ObjectivelyMVC
Object oriented MVC framework for SDL3 and GNU C
Loading...
Searching...
No Matches
Renderer Struct Reference

Renderer extends Object with ObjectivelyMVC's UI rendering layer. More...

#include <Renderer.h>

Inheritance diagram for Renderer:

Public Member Functions

Class * _Renderer (void)
 The Renderer archetype.
 
void beginFrame (Renderer *self)
 Prepares this Renderer for a new frame using self->device's current command buffer and framebuffer.
 
void beginFrameWith (Renderer *self, CommandBuffer *commands, Framebuffer *framebuffer)
 Prepares this Renderer for a new frame using the given command buffer and framebuffer.
 
void drawLine (const Renderer *self, const SDL_Point *points, const SDL_Color *color)
 Records a line segment between two points.
 
void drawLines (const Renderer *self, const SDL_Point *points, size_t count, const SDL_Color *color)
 Records a polyline through the given points.
 
void drawRect (const Renderer *self, const SDL_Rect *rect, const SDL_Color *color)
 Records a rectangle outline.
 
void drawRectFilled (const Renderer *self, const SDL_Rect *rect, const SDL_Color *color)
 Records a filled rectangle.
 
void drawTexture (const Renderer *self, Texture *texture, const SDL_Rect *dest, const SDL_Color *color)
 Records a textured quad in the given destination rectangle.
 
void drawView (Renderer *self, View *view)
 Sets the clipping frame and invokes View::render for the given View.
 
void endFrame (Renderer *self)
 Uploads MVC vertices and executes the UI render pass into the Framebuffer given to beginFrame/beginFrameWith (LOAD_OP_LOAD).
 
RendererinitWithDevice (Renderer *self, RenderDevice *device)
 Initializes this Renderer with the given RenderDevice.
 
void pushDrawArrays (const Renderer *self, const MVC_Vertex *verts, size_t count, Texture *texture, const SDL_Color *color)
 Appends raw vertices and a draw call record to the frame queue.
 
void renderDeviceDidReset (Renderer *self)
 Recreates MVC GPU resources after the backing RenderDevice resets.
 
void renderDeviceWillReset (Renderer *self)
 Releases MVC GPU resources before the backing RenderDevice resets.
 
void setClippingFrame (Renderer *self, const SDL_Rect *clippingFrame)
 Sets the scissor rectangle for subsequent draw calls.
 

Data Fields

RenderDevice * device
 The backing RenderDevice.
 
Object object
 The superclass.
 

Protected Attributes

RendererInterface * interface
 The interface.
 

Detailed Description

Renderer extends Object with ObjectivelyMVC's UI rendering layer.

Create a WindowController to instantiate a default Renderer.

Definition at line 70 of file Renderer.h.

Member Function Documentation

◆ _Renderer()

Class * _Renderer ( void  )

The Renderer archetype.

Returns
The Renderer Class.

Definition at line 522 of file Renderer.c.

522 {
523 static Class *clazz;
524 static Once once;
525
526 do_once(&once, {
527 clazz = _initialize(&(const ClassDef) {
528 .name = "Renderer",
529 .superclass = _Object(),
530 .instanceSize = sizeof(Renderer),
531 .interfaceOffset = offsetof(Renderer, interface),
532 .interfaceSize = sizeof(RendererInterface),
534 });
535 });
536
537 return clazz;
538}
static void initialize(Class *clazz)
Definition Box.c:123
Renderer extends Object with ObjectivelyMVC's UI rendering layer.
Definition Renderer.h:70
RendererInterface * interface
The interface.
Definition Renderer.h:81

◆ beginFrame()

void beginFrame ( Renderer self)

Prepares this Renderer for a new frame using self->device's current command buffer and framebuffer.

Convenience over beginFrameWith for the common case of rendering the UI into the device's own current frame. Equivalent to $(self, beginFrameWith, self->device->commands, self->device->framebuffer).

Parameters
selfThe Renderer.

Definition at line 88 of file Renderer.c.

88 {
89 $(self, beginFrameWith, self->device->commands, self->device->framebuffer);
90}
RenderDevice * device
The backing RenderDevice.
Definition Renderer.h:92
void beginFrameWith(Renderer *self, CommandBuffer *commands, Framebuffer *framebuffer)
Prepares this Renderer for a new frame using the given command buffer and framebuffer.
Definition Renderer.c:96

◆ beginFrameWith()

void beginFrameWith ( Renderer self,
CommandBuffer *  commands,
Framebuffer *  framebuffer 
)

Prepares this Renderer for a new frame using the given command buffer and framebuffer.

Parameters
selfThe Renderer.
commandsThe frame's CommandBuffer. The caller retains ownership and must submit and release it.
framebufferThe target Framebuffer for this frame. Borrowed for the duration of the frame.

Definition at line 96 of file Renderer.c.

96 {
97
98 assert(commands);
99 assert(framebuffer);
100
101 self->commands = commands;
102 self->framebuffer = framebuffer;
103
104 $(self->vertices, removeAll);
105 $(self->drawArrays, removeAll);
106
107 self->scissor = MakeRect(0, 0, framebuffer->size.w, framebuffer->size.h);
108}

◆ drawLine()

void drawLine ( const Renderer self,
const SDL_Point *  points,
const SDL_Color *  color 
)

Records a line segment between two points.

Parameters
selfThe Renderer.
pointsTwo points defining the line segment.
colorThe line color.

Definition at line 114 of file Renderer.c.

114 {
115
116 assert(points);
117
118 $(self, drawLines, points, 2, color);
119}
void drawLines(const Renderer *self, const SDL_Point *points, size_t count, const SDL_Color *color)
Records a polyline through the given points.
Definition Renderer.c:125

◆ drawLines()

void drawLines ( const Renderer self,
const SDL_Point *  points,
size_t  count,
const SDL_Color *  color 
)

Records a polyline through the given points.

Parameters
selfThe Renderer.
pointsThe points.
countThe number of points.
colorThe line color.

Definition at line 125 of file Renderer.c.

125 {
126
127 assert(points);
128 assert(color);
129
130 if (count < 2) {
131 return;
132 }
133
134 const size_t segCount = count - 1;
135 MVC_Vertex *verts = malloc(segCount * 6 * sizeof(MVC_Vertex));
136 assert(verts);
137
138 for (size_t i = 0; i < segCount; i++) {
139 const float ax = (float) points[i].x, ay = (float) points[i].y;
140 const float bx = (float) points[i+1].x, by = (float) points[i+1].y;
141
142 const float dx = bx - ax, dy = by - ay;
143 const float len = sqrtf(dx * dx + dy * dy);
144
145 float nx = 0.0f, ny = 0.0f;
146 if (len > 0.001f) {
147 nx = (-dy / len) * 0.5f;
148 ny = ( dx / len) * 0.5f;
149 }
150
151 MVC_Vertex *v = &verts[i * 6];
152 v[0] = (MVC_Vertex) { { { ax - nx, ay - ny } }, { { 0.0f, 0.0f } }, { 0 } };
153 v[1] = (MVC_Vertex) { { { ax + nx, ay + ny } }, { { 0.0f, 0.0f } }, { 0 } };
154 v[2] = (MVC_Vertex) { { { bx - nx, by - ny } }, { { 0.0f, 0.0f } }, { 0 } };
155 v[3] = (MVC_Vertex) { { { ax + nx, ay + ny } }, { { 0.0f, 0.0f } }, { 0 } };
156 v[4] = (MVC_Vertex) { { { bx + nx, by + ny } }, { { 0.0f, 0.0f } }, { 0 } };
157 v[5] = (MVC_Vertex) { { { bx - nx, by - ny } }, { { 0.0f, 0.0f } }, { 0 } };
158 }
159
160 $(self, pushDrawArrays, verts, segCount * 6, NULL, color);
161
162 free(verts);
163}
Interleaved position + texcoord + color vertex for GPU upload.
Definition Renderer.h:48
void pushDrawArrays(const Renderer *self, const MVC_Vertex *verts, size_t count, Texture *texture, const SDL_Color *color)
Appends raw vertices and a draw call record to the frame queue.
Definition Renderer.c:334

◆ drawRect()

void drawRect ( const Renderer self,
const SDL_Rect *  rect,
const SDL_Color *  color 
)

Records a rectangle outline.

Parameters
selfThe Renderer.
rectThe rectangle.
colorThe outline color.

Definition at line 169 of file Renderer.c.

169 {
170
171 assert(rect);
172
173 const SDL_Point points[5] = {
174 { rect->x, rect->y },
175 { rect->x + rect->w, rect->y },
176 { rect->x + rect->w, rect->y + rect->h },
177 { rect->x, rect->y + rect->h },
178 { rect->x, rect->y },
179 };
180
181 $(self, drawLines, points, 5, color);
182}

◆ drawRectFilled()

void drawRectFilled ( const Renderer self,
const SDL_Rect *  rect,
const SDL_Color *  color 
)

Records a filled rectangle.

Parameters
selfThe Renderer.
rectThe rectangle.
colorThe fill color.

Definition at line 188 of file Renderer.c.

188 {
189
190 assert(rect);
191
192 const float x1 = (float) rect->x, y1 = (float) rect->y;
193 const float x2 = (float) rect->x + rect->w, y2 = (float) rect->y + rect->h;
194
195 const MVC_Vertex verts[6] = {
196 { { { x1, y1 } }, { { 0.0f, 0.0f } }, { 0 } },
197 { { { x2, y1 } }, { { 0.0f, 0.0f } }, { 0 } },
198 { { { x1, y2 } }, { { 0.0f, 0.0f } }, { 0 } },
199 { { { x2, y1 } }, { { 0.0f, 0.0f } }, { 0 } },
200 { { { x2, y2 } }, { { 0.0f, 0.0f } }, { 0 } },
201 { { { x1, y2 } }, { { 0.0f, 0.0f } }, { 0 } },
202 };
203
204 $(self, pushDrawArrays, verts, 6, NULL, color);
205}

◆ drawTexture()

void drawTexture ( const Renderer self,
Texture *  texture,
const SDL_Rect *  dest,
const SDL_Color *  color 
)

Records a textured quad in the given destination rectangle.

Parameters
selfThe Renderer.
textureThe Texture to sample.
destThe destination rectangle in logical screen coordinates.
colorThe color multiplier (use &Colors.White for no tint).

Definition at line 211 of file Renderer.c.

211 {
212
213 assert(rect);
214
215 const float x1 = (float) rect->x, y1 = (float) rect->y;
216 const float x2 = (float) rect->x + rect->w, y2 = (float) rect->y + rect->h;
217
218 const MVC_Vertex verts[6] = {
219 { { { x1, y1 } }, { { 0.0f, 0.0f } }, { 0 } },
220 { { { x2, y1 } }, { { 1.0f, 0.0f } }, { 0 } },
221 { { { x1, y2 } }, { { 0.0f, 1.0f } }, { 0 } },
222 { { { x2, y1 } }, { { 1.0f, 0.0f } }, { 0 } },
223 { { { x2, y2 } }, { { 1.0f, 1.0f } }, { 0 } },
224 { { { x1, y2 } }, { { 0.0f, 1.0f } }, { 0 } },
225 };
226
227 $(self, pushDrawArrays, verts, 6, texture, color);
228}

◆ drawView()

void drawView ( Renderer self,
View view 
)

Sets the clipping frame and invokes View::render for the given View.

Parameters
selfThe Renderer.
viewThe View to render.

Definition at line 234 of file Renderer.c.

234 {
235
236 assert(view);
237
238 const SDL_Rect clippingFrame = $(view, clippingFrame);
239 if (clippingFrame.w && clippingFrame.h) {
241 $(view, render, self);
242 }
243}
static void render(View *self, Renderer *renderer)
Definition Control.c:179
static SDL_Rect clippingFrame(const View *self)
Definition View.c:546
void setClippingFrame(Renderer *self, const SDL_Rect *clippingFrame)
Sets the scissor rectangle for subsequent draw calls.
Definition Renderer.c:482

◆ endFrame()

void endFrame ( Renderer self)

Uploads MVC vertices and executes the UI render pass into the Framebuffer given to beginFrame/beginFrameWith (LOAD_OP_LOAD).

The caller is responsible for submitting the command buffer after this returns.

Parameters
selfThe Renderer.

Definition at line 249 of file Renderer.c.

249 {
250
251 Framebuffer *framebuffer = self->framebuffer;
252 assert(framebuffer);
253
254 const SDL_GPUColorTargetInfo colorTarget = $(framebuffer, colorTargetInfo, 0, SDL_GPU_LOADOP_LOAD, SDL_GPU_STOREOP_STORE, NULL);
255
256 const size_t vtxCount = self->vertices->count;
257
258 CopyPass *copyPass = $(self->commands, beginCopyPass);
259
260 if (vtxCount > 0) {
261 const Uint32 vtxSize = (Uint32) (vtxCount * sizeof(MVC_Vertex));
262
263 if (vtxCount > self->vertexBufferCapacity) {
264 release(self->vertexBuffer);
265 const SDL_GPUBufferCreateInfo info = { .usage = SDL_GPU_BUFFERUSAGE_VERTEX, .size = vtxSize };
266 self->vertexBuffer = $(self->device, createBuffer, &info);
267 self->vertexBufferCapacity = (Uint32) vtxCount;
268 }
269
270 $(copyPass, uploadData, self->vertexBuffer->buffer, self->vertices->elements, vtxSize, 0, true);
271 }
272
273 release(copyPass);
274
275 RenderPass *renderPass = $(self->commands, beginRenderPass, &colorTarget, 1, NULL);
276
277 $(renderPass, setViewport, &(SDL_GPUViewport){
278 .x = 0.0f, .y = 0.0f,
279 .w = (float) framebuffer->size.w, .h = (float) framebuffer->size.h,
280 .min_depth = 0.0f, .max_depth = 1.0f,
281 });
282
283 int winW, winH;
284 SDL_GetWindowSize(self->device->window, &winW, &winH);
285 const mat4 projection = mat4_ortho(0.f, (float) winW, (float) winH, 0.f, -1.f, 1.f);
286 $(self->commands, pushVertexUniformData, 0, projection.f, sizeof(projection));
287
288 $(renderPass, bindPipeline, self->pipeline);
289 $(renderPass, bindVertexBuffers, 0, &(SDL_GPUBufferBinding) { .buffer = self->vertexBuffer->buffer }, 1);
290
291 for (size_t i = 0; i < self->drawArrays->count; i++) {
292 const MVC_DrawArrays *draw = VectorElement(self->drawArrays, MVC_DrawArrays, i);
293
294 $(renderPass, setScissor, &draw->scissor);
295
296 $(renderPass, bindFragmentSamplers, 0, &(SDL_GPUTextureSamplerBinding) {
297 .texture = draw->texture->texture, .sampler = self->sampler->sampler,
298 }, 1);
299
300 $(renderPass, drawPrimitives, draw->vertexCount, 1, draw->firstVertex, 0);
301 }
302
303 release(renderPass);
304
305 self->commands = NULL;
306 self->framebuffer = NULL;
307}
static void draw(View *self, Renderer *renderer)
Definition View.c:720

◆ initWithDevice()

Renderer * initWithDevice ( Renderer self,
RenderDevice *  device 
)

Initializes this Renderer with the given RenderDevice.

Parameters
selfThe Renderer.
deviceThe RenderDevice.
Returns
The initialized Renderer, or NULL on error.

Definition at line 313 of file Renderer.c.

313 {
314
315 self = (Renderer *) super(Object, self, init);
316 if (self) {
317 self->device = retain(device);
318 assert(self->device);
319
320 self->vertices = $(alloc(Vector), initWithSize, sizeof(MVC_Vertex));
321 assert(self->vertices);
322
323 self->drawArrays = $(alloc(Vector), initWithSize, sizeof(MVC_DrawArrays));
324 assert(self->drawArrays);
325 }
326
327 return self;
328}
static View * init(View *self)
Definition Box.c:67

◆ pushDrawArrays()

void pushDrawArrays ( const Renderer self,
const MVC_Vertex verts,
size_t  count,
Texture *  texture,
const SDL_Color *  color 
)

Appends raw vertices and a draw call record to the frame queue.

Views that need full draw-call control can call this directly instead of going through the drawLine/drawRect/drawTexture helpers.

Parameters
selfThe Renderer.
vertsThe vertices to append (in logical screen coordinates).
countThe number of vertices.
textureThe texture to bind, or NULL to use the 1×1 white fallback.
colorThe color multiplier applied in the fragment shader.

Definition at line 334 of file Renderer.c.

334 {
335
336 assert(verts);
337 assert(color);
338
339 const MVC_DrawArrays draw = {
340 .firstVertex = (Uint32) self->vertices->count,
341 .vertexCount = (Uint32) count,
342 .texture = texture ? texture : self->white,
343 .scissor = self->scissor,
344 };
345
346 for (size_t i = 0; i < count; i++) {
347 MVC_Vertex v = verts[i];
348 v.color = *color;
349 $(self->vertices, add, &v);
350 }
351
352 $(self->drawArrays, add, (MVC_DrawArrays *) &draw);
353}
SDL_Color color
Definition Renderer.h:51

◆ renderDeviceDidReset()

void renderDeviceDidReset ( Renderer self)

Recreates MVC GPU resources after the backing RenderDevice resets.

Parameters
selfThe Renderer.

Definition at line 359 of file Renderer.c.

359 {
360
361 Shader *vertexShader = $(self->device, loadShader, "Renderer.vert", &(SDL_GPUShaderCreateInfo) {
362 .stage = SDL_GPU_SHADERSTAGE_VERTEX,
363 .num_uniform_buffers = 1,
364 });
365
366 Shader *fragmentShader = $(self->device, loadShader, "Renderer.frag", &(SDL_GPUShaderCreateInfo) {
367 .stage = SDL_GPU_SHADERSTAGE_FRAGMENT,
368 .num_samplers = 1,
369 });
370
371 const SDL_GPUVertexBufferDescription vertexBufferInfo = {
372 .slot = 0,
373 .pitch = sizeof(MVC_Vertex),
374 .input_rate = SDL_GPU_VERTEXINPUTRATE_VERTEX,
375 .instance_step_rate = 0,
376 };
377
378 const SDL_GPUColorTargetDescription colorTarget = {
379 .format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM,
380 .blend_state = {
381 .enable_blend = true,
382 .color_blend_op = SDL_GPU_BLENDOP_ADD,
383 .alpha_blend_op = SDL_GPU_BLENDOP_ADD,
384 .src_color_blendfactor = SDL_GPU_BLENDFACTOR_SRC_ALPHA,
385 .dst_color_blendfactor = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA,
386 .src_alpha_blendfactor = SDL_GPU_BLENDFACTOR_ONE,
387 .dst_alpha_blendfactor = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA,
388 },
389 };
390
391 const SDL_GPUGraphicsPipelineCreateInfo pipelineInfo = {
392 .vertex_shader = vertexShader->shader,
393 .fragment_shader = fragmentShader->shader,
394 .vertex_input_state = {
395 .vertex_buffer_descriptions = &vertexBufferInfo,
396 .num_vertex_buffers = 1,
397 .vertex_attributes = (SDL_GPUVertexAttribute[]) {
398 {
399 .location = 0,
400 .buffer_slot = 0,
401 .format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2,
402 .offset = offsetof(MVC_Vertex, position)
403 },
404 {
405 .location = 1,
406 .buffer_slot = 0,
407 .format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2,
408 .offset = offsetof(MVC_Vertex, uv)
409 },
410 {
411 .location = 2,
412 .buffer_slot = 0,
413 .format = SDL_GPU_VERTEXELEMENTFORMAT_UBYTE4_NORM,
414 .offset = offsetof(MVC_Vertex, color)
415 },
416 },
417 .num_vertex_attributes = 3,
418 },
419 .primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST,
420 .rasterizer_state = {
421 .fill_mode = SDL_GPU_FILLMODE_FILL,
422 .cull_mode = SDL_GPU_CULLMODE_NONE,
423 .front_face = SDL_GPU_FRONTFACE_COUNTER_CLOCKWISE,
424 },
425 .target_info = {
426 .color_target_descriptions = &colorTarget,
427 .num_color_targets = 1,
428 },
429 };
430
431 self->pipeline = $(self->device, createGraphicsPipeline, &pipelineInfo);
432
433 release(vertexShader);
434 release(fragmentShader);
435
436 self->sampler = $(self->device, createSampler, &(const SDL_GPUSamplerCreateInfo) {
437 .min_filter = SDL_GPU_FILTER_LINEAR,
438 .mag_filter = SDL_GPU_FILTER_LINEAR,
439 .mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_LINEAR,
440 .address_mode_u = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE,
441 .address_mode_v = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE,
442 .address_mode_w = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE,
443 });
444
445 const Uint8 white[4] = { 255, 255, 255, 255 };
446
447 self->white = $(self->device, createTexture, &(const SDL_GPUTextureCreateInfo) {
448 .type = SDL_GPU_TEXTURETYPE_2D,
449 .format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM,
450 .usage = SDL_GPU_TEXTUREUSAGE_SAMPLER,
451 .width = 1,
452 .height = 1,
453 .layer_count_or_depth = 1,
454 .num_levels = 1,
455 }, white);
456}

◆ renderDeviceWillReset()

void renderDeviceWillReset ( Renderer self)

Releases MVC GPU resources before the backing RenderDevice resets.

Parameters
selfThe Renderer.

Definition at line 462 of file Renderer.c.

462 {
463
464 self->commands = NULL;
465
466 self->white = release(self->white);
467 self->sampler = release(self->sampler);
468
469 self->vertexBuffer = release(self->vertexBuffer);
470 self->vertexBufferCapacity = 0;
471
472 self->pipeline = release(self->pipeline);
473
474 $(self->vertices, removeAll);
475 $(self->drawArrays, removeAll);
476}

◆ setClippingFrame()

void setClippingFrame ( Renderer self,
const SDL_Rect *  clippingFrame 
)

Sets the scissor rectangle for subsequent draw calls.

Parameters
selfThe Renderer.
clippingFrameThe clipping rectangle in logical screen coordinates, or NULL to disable clipping (full window scissor).

Definition at line 482 of file Renderer.c.

482 {
483
484 if (clippingFrame) {
485 self->scissor = MVC_TransformToWindow(self->device->window, clippingFrame);
486 } else {
487 self->scissor = MakeRect(0, 0, self->framebuffer->size.w, self->framebuffer->size.h);
488 }
489}
SDL_Rect MVC_TransformToWindow(SDL_Window *window, const SDL_Rect *rect)
Transforms the specified rectangle to normalized device coordinates in window.
Definition Window.c:29

Field Documentation

◆ device

RenderDevice* Renderer::device

The backing RenderDevice.

Definition at line 92 of file Renderer.h.

◆ interface

RendererInterface* Renderer::interface
protected

The interface.

Definition at line 81 of file Renderer.h.

◆ object

Object Renderer::object

The superclass.

Definition at line 75 of file Renderer.h.


The documentation for this struct was generated from the following files: