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 drawBevel (const Renderer *self, const SDL_Rect *rect, int radius, int width, const SDL_Color *topLeft, const SDL_Color *bottomRight)
 Records a rounded rectangle outline split diagonally into two colors.
 
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 drawPolygon (const Renderer *self, const SDL_Point *points, size_t count, int width, const SDL_Color *color)
 Records a closed polygon outline of the given width.
 
void drawPolygonFilled (const Renderer *self, const SDL_Point *points, size_t count, int angle, const SDL_Color *from, const SDL_Color *to)
 Records a filled convex polygon, optionally with a linear gradient.
 
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 drawRoundedRect (const Renderer *self, const SDL_Rect *rect, int radius, int width, const SDL_Color *color)
 Records a rounded rectangle outline of the given width, drawn inside rect.
 
void drawRoundedRectFilled (const Renderer *self, const SDL_Rect *rect, int radius, const SDL_Color *color)
 Records a filled rounded rectangle.
 
void drawRoundedRectGradientFilled (const Renderer *self, const SDL_Rect *rect, int radius, int angle, const SDL_Color *from, const SDL_Color *to)
 Records a rounded rectangle filled with a linear gradient.
 
void drawRoundedTexture (const Renderer *self, Texture *texture, const SDL_FRect *dest, int radius, const SDL_Color *color)
 Records a textured quad clipped to a rounded rectangle.
 
void drawRoundedTextureRegion (const Renderer *self, Texture *texture, const SDL_Rect *src, const SDL_FRect *dest, int radius, const SDL_Color *color)
 Records a region of a texture as a quad clipped to a rounded rectangle.
 
void drawTexture (const Renderer *self, Texture *texture, const SDL_FRect *dest, const SDL_Color *color)
 Records a textured quad in the given destination rectangle.
 
void drawTextureRegion (const Renderer *self, Texture *texture, const SDL_Rect *src, const SDL_FRect *dest, const SDL_Color *color)
 Records a region of a texture as a 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).
 
Renderer * initWithDevice (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 [0]
 The interface type.
 

Detailed Description

Renderer extends Object with ObjectivelyMVC's UI rendering layer.

Create a WindowController to instantiate a default Renderer.

Definition at line 75 of file Renderer.h.

Member Function Documentation

◆ _Renderer()

Class * _Renderer ( void  )

The Renderer archetype.

Returns
The Renderer Class.

Definition at line 890 of file Renderer.c.

890 {
891 static Class *clazz;
892 static Once once;
893
894 do_once(&once, {
895 clazz = _initialize(&(const ClassDef) {
896 .name = "Renderer",
897 .superclass = _Object(),
898 .instanceSize = sizeof(Renderer),
899 .interfaceSize = sizeof(RendererInterface),
900 .initialize = initialize,
901 });
902 });
903
904 return clazz;
905}
static void initialize(Class *clazz)
Definition AtlasImage.c:74
Renderer extends Object with ObjectivelyMVC's UI rendering layer.
Definition Renderer.h:75

◆ 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 101 of file Renderer.c.

101 {
102 $(self, beginFrameWith, self->device->commands, self->device->framebuffer);
103}
RenderDevice * device
The backing RenderDevice.
Definition Renderer.h:97
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:109

◆ 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 109 of file Renderer.c.

109 {
110
111 assert(commands);
112 assert(framebuffer);
113
114 self->commands = commands;
115 self->framebuffer = framebuffer;
116
117 $(self->vertices, removeAll);
118 $(self->drawArrays, removeAll);
119
120 self->scissor = MakeRect(0, 0, framebuffer->size.w, framebuffer->size.h);
121}

◆ drawBevel()

void drawBevel ( const Renderer *  self,
const SDL_Rect *  rect,
int  radius,
int  width,
const SDL_Color *  topLeft,
const SDL_Color *  bottomRight 
)

Records a rounded rectangle outline split diagonally into two colors.

The outline is drawn inside rect. The half above the bottom-left to top-right diagonal takes topLeft; the other half takes bottomRight.

Parameters
selfThe Renderer.
rectThe rectangle.
radiusThe corner radius.
widthThe outline width.
topLeftThe color of the top and left edges.
bottomRightThe color of the bottom and right edges.

Definition at line 247 of file Renderer.c.

248 {
249
250 assert(rect);
251
252 SDL_FRect frect;
253 SDL_RectToFRect(rect, &frect);
254
255 MVC_Vertex verts[6];
256 roundedRectVertices(verts, &frect, radius, width, NULL);
257
258 $(self, pushDrawArrays, verts, 3, NULL, topLeft);
259 $(self, pushDrawArrays, verts + 3, 3, NULL, bottomRight);
260}
static void roundedRectVertices(MVC_Vertex *verts, const SDL_FRect *rect, int radius, int stroke, const SDL_FRect *uv)
Fills six vertices covering rect as two triangles, tagged so the fragment shader shades them as a rou...
Definition Renderer.c:128
Interleaved position + texcoord + color + rounded rect shape vertex for GPU upload.
Definition Renderer.h:51
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:660

◆ 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 266 of file Renderer.c.

266 {
267
268 assert(points);
269
270 $(self, drawLines, points, 2, color);
271}
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:277

◆ 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 277 of file Renderer.c.

277 {
278
279 assert(points);
280 assert(color);
281
282 if (count < 2) {
283 return;
284 }
285
286 strokePolyline(self, points, count, false, 1.f, color);
287}
static void strokePolyline(const Renderer *self, const SDL_Point *points, size_t count, bool closed, float width, const SDL_Color *color)
Appends the quads stroking points, of width, optionally closing the loop.
Definition Renderer.c:202

◆ drawPolygon()

void drawPolygon ( const Renderer *  self,
const SDL_Point *  points,
size_t  count,
int  width,
const SDL_Color *  color 
)

Records a closed polygon outline of the given width.

The stroke is centered on each edge. Joints are not mitered, so a width well above the one or two pixels a border uses will notch at sharp corners.

Parameters
selfThe Renderer.
pointsThe points, in order; the last is joined back to the first.
countThe number of points; fewer than three draws nothing.
widthThe stroke width.
colorThe outline color.

Definition at line 293 of file Renderer.c.

294 {
295
296 assert(points);
297 assert(color);
298
299 if (count < 3 || width < 1) {
300 return;
301 }
302
303 strokePolyline(self, points, count, true, (float) width, color);
304}

◆ drawPolygonFilled()

void drawPolygonFilled ( const Renderer *  self,
const SDL_Point *  points,
size_t  count,
int  angle,
const SDL_Color *  from,
const SDL_Color *  to 
)

Records a filled convex polygon, optionally with a linear gradient.

The polygon is triangulated as a fan from its first vertex, so it MUST be convex. It is drawn without the rounded rectangle shader, and so without its anti-aliasing: diagonal edges are hard.

Parameters
selfThe Renderer.
pointsThe points, in order.
countThe number of points; fewer than three draws nothing.
angleThe gradient angle in degrees, clockwise from south. Ignored when to is NULL.
fromThe fill color, and the near color of the gradient.
toThe far color of the gradient, or NULL to fill flat with from.

Definition at line 310 of file Renderer.c.

311 {
312
313 assert(points);
314 assert(from);
315
316 if (count < 3) {
317 return;
318 }
319
320 SDL_FRect bounds = { (float) points[0].x, (float) points[0].y, 0.f, 0.f };
321 float x2 = bounds.x, y2 = bounds.y;
322
323 for (size_t i = 1; i < count; i++) {
324 bounds.x = min(bounds.x, (float) points[i].x);
325 bounds.y = min(bounds.y, (float) points[i].y);
326 x2 = max(x2, (float) points[i].x);
327 y2 = max(y2, (float) points[i].y);
328 }
329
330 bounds.w = x2 - bounds.x;
331 bounds.h = y2 - bounds.y;
332
333 // a convex polygon triangulates as a fan from its first vertex
334 const size_t triangles = count - 2;
335
336 MVC_Vertex verts[16 * 3];
337 const size_t batchSize = lengthof(verts) / 3;
338
339 for (size_t t = 0; t < triangles; ) {
340
341 const size_t batch = min(triangles - t, batchSize);
342
343 for (size_t i = 0; i < batch; i++, t++) {
344
345 const SDL_Point *p[3] = { &points[0], &points[t + 1], &points[t + 2] };
346
347 for (size_t j = 0; j < 3; j++) {
348
349 const float x = (float) p[j]->x, y = (float) p[j]->y;
350
351 verts[i * 3 + j] = (MVC_Vertex) { { { x, y } }, { { 0.f, 0.f } },
352 to ? gradientColor(x, y, &bounds, angle, from, to) : *from
353 };
354 }
355 }
356
357 $(self, pushDrawArrays, verts, batch * 3, NULL, NULL);
358 }
359}
static SDL_Color gradientColor(float x, float y, const SDL_FRect *bounds, int angle, const SDL_Color *from, const SDL_Color *to)
The color at x, y for a gradient of angle degrees across bounds.
Definition Renderer.c:170
static SDL_Rect bounds(const View *self)
Definition View.c:552

◆ 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 365 of file Renderer.c.

365 {
366
367 assert(rect);
368
369 const SDL_Point points[5] = {
370 { rect->x, rect->y },
371 { rect->x + rect->w, rect->y },
372 { rect->x + rect->w, rect->y + rect->h },
373 { rect->x, rect->y + rect->h },
374 { rect->x, rect->y },
375 };
376
377 $(self, drawLines, points, 5, color);
378}

◆ 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 384 of file Renderer.c.

384 {
385
386 assert(rect);
387
388 const float x1 = (float) rect->x, y1 = (float) rect->y;
389 const float x2 = (float) rect->x + rect->w, y2 = (float) rect->y + rect->h;
390
391 const MVC_Vertex verts[6] = {
392 { { { x1, y1 } }, { { 0.0f, 0.0f } }, { 0 } },
393 { { { x2, y1 } }, { { 0.0f, 0.0f } }, { 0 } },
394 { { { x1, y2 } }, { { 0.0f, 0.0f } }, { 0 } },
395 { { { x2, y1 } }, { { 0.0f, 0.0f } }, { 0 } },
396 { { { x2, y2 } }, { { 0.0f, 0.0f } }, { 0 } },
397 { { { x1, y2 } }, { { 0.0f, 0.0f } }, { 0 } },
398 };
399
400 $(self, pushDrawArrays, verts, 6, NULL, color);
401}

◆ drawRoundedRect()

void drawRoundedRect ( const Renderer *  self,
const SDL_Rect *  rect,
int  radius,
int  width,
const SDL_Color *  color 
)

Records a rounded rectangle outline of the given width, drawn inside rect.

Parameters
selfThe Renderer.
rectThe rectangle.
radiusThe corner radius.
widthThe outline width.
colorThe outline color.

Definition at line 407 of file Renderer.c.

407 {
408
409 assert(rect);
410
411 SDL_FRect frect;
412 SDL_RectToFRect(rect, &frect);
413
414 MVC_Vertex verts[6];
415 roundedRectVertices(verts, &frect, radius, width, NULL);
416
417 $(self, pushDrawArrays, verts, 6, NULL, color);
418}

◆ drawRoundedRectFilled()

void drawRoundedRectFilled ( const Renderer *  self,
const SDL_Rect *  rect,
int  radius,
const SDL_Color *  color 
)

Records a filled rounded rectangle.

Parameters
selfThe Renderer.
rectThe rectangle.
radiusThe corner radius.
colorThe fill color.

Definition at line 424 of file Renderer.c.

424 {
425
426 assert(rect);
427
428 SDL_FRect frect;
429 SDL_RectToFRect(rect, &frect);
430
431 MVC_Vertex verts[6];
432 roundedRectVertices(verts, &frect, radius, 0, NULL);
433
434 $(self, pushDrawArrays, verts, 6, NULL, color);
435}

◆ drawRoundedRectGradientFilled()

void drawRoundedRectGradientFilled ( const Renderer *  self,
const SDL_Rect *  rect,
int  radius,
int  angle,
const SDL_Color *  from,
const SDL_Color *  to 
)

Records a rounded rectangle filled with a linear gradient.

Parameters
selfThe Renderer.
rectThe rectangle.
radiusThe corner radius.
angleThe gradient angle in degrees, clockwise from south: 0 fills downwards, 90 to the right, 180 upwards.
fromThe near color of the gradient.
toThe far color of the gradient.

Definition at line 441 of file Renderer.c.

442 {
443
444 assert(rect);
445 assert(from);
446 assert(to);
447
448 SDL_FRect frect;
449 SDL_RectToFRect(rect, &frect);
450
451 MVC_Vertex verts[6];
452 roundedRectVertices(verts, &frect, radius, 0, NULL);
453
454 for (size_t i = 0; i < lengthof(verts); i++) {
455 verts[i].color = gradientColor(verts[i].position.x, verts[i].position.y, &frect, angle, from, to);
456 }
457
458 $(self, pushDrawArrays, verts, lengthof(verts), NULL, NULL);
459}
SDL_Color color
Definition Renderer.h:54

◆ drawRoundedTexture()

void drawRoundedTexture ( const Renderer *  self,
Texture *  texture,
const SDL_FRect *  dest,
int  radius,
const SDL_Color *  color 
)

Records a textured quad clipped to a rounded rectangle.

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

Definition at line 465 of file Renderer.c.

465 {
466 $(self, drawRoundedTextureRegion, texture, NULL, dest, radius, color);
467}
static Texture * texture(ImageAtlas *self, RenderDevice *device)
Definition ImageAtlas.c:289
void drawRoundedTextureRegion(const Renderer *self, Texture *texture, const SDL_Rect *src, const SDL_FRect *dest, int radius, const SDL_Color *color)
Records a region of a texture as a quad clipped to a rounded rectangle.
Definition Renderer.c:473

◆ drawRoundedTextureRegion()

void drawRoundedTextureRegion ( const Renderer *  self,
Texture *  texture,
const SDL_Rect *  src,
const SDL_FRect *  dest,
int  radius,
const SDL_Color *  color 
)

Records a region of a texture as a quad clipped to a rounded rectangle.

Parameters
selfThe Renderer.
textureThe Texture to sample.
srcThe region of texture to sample, in texels, or NULL for all of it.
destThe destination rectangle in logical screen coordinates.
radiusThe corner radius.
colorThe color multiplier (use &Colors.White for no tint).

Definition at line 473 of file Renderer.c.

473 {
474
475 assert(dest);
476
477 const SDL_FRect uv = textureRegion(texture, src);
478
479 MVC_Vertex verts[6];
480 roundedRectVertices(verts, dest, radius, 0, &uv);
481
482 $(self, pushDrawArrays, verts, 6, texture, color);
483}
static SDL_FRect textureRegion(const Texture *texture, const SDL_Rect *src)
Resolves the normalized texture coordinates of src within texture, or of the whole texture when src i...
Definition Renderer.c:151

◆ drawTexture()

void drawTexture ( const Renderer *  self,
Texture *  texture,
const SDL_FRect *  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.
Remarks
dest is a sub-pixel-precise SDL_FRect, not SDL_Rect: a caller that needs the texture drawn at its exact native resolution (e.g. Text, to avoid a fractional stretch that shifts every glyph as the string's pixel width changes) must pass an unrounded size here, since rounding it to the nearest integer logical unit first is precisely what reintroduces that stretch.
Parameters
colorThe color multiplier (use &Colors.White for no tint).

Definition at line 489 of file Renderer.c.

489 {
490 $(self, drawTextureRegion, texture, NULL, dest, color);
491}
void drawTextureRegion(const Renderer *self, Texture *texture, const SDL_Rect *src, const SDL_FRect *dest, const SDL_Color *color)
Records a region of a texture as a quad in the given destination rectangle.
Definition Renderer.c:497

◆ drawTextureRegion()

void drawTextureRegion ( const Renderer *  self,
Texture *  texture,
const SDL_Rect *  src,
const SDL_FRect *  dest,
const SDL_Color *  color 
)

Records a region of a texture as a quad in the given destination rectangle.

This is how an AtlasImage is drawn: src is its rect within the atlas sheet.

Parameters
selfThe Renderer.
textureThe Texture to sample.
srcThe region of texture to sample, in texels, or NULL for all of it.
destThe destination rectangle in logical screen coordinates.
colorThe color multiplier (use &Colors.White for no tint).

Definition at line 497 of file Renderer.c.

497 {
498
499 assert(dest);
500
501 const float x1 = dest->x, y1 = dest->y;
502 const float x2 = dest->x + dest->w, y2 = dest->y + dest->h;
503
504 const SDL_FRect uv = textureRegion(texture, src);
505
506 const float u1 = uv.x, v1 = uv.y;
507 const float u2 = uv.x + uv.w, v2 = uv.y + uv.h;
508
509 const MVC_Vertex verts[6] = {
510 { { { x1, y1 } }, { { u1, v1 } }, { 0 } },
511 { { { x2, y1 } }, { { u2, v1 } }, { 0 } },
512 { { { x1, y2 } }, { { u1, v2 } }, { 0 } },
513 { { { x2, y1 } }, { { u2, v1 } }, { 0 } },
514 { { { x2, y2 } }, { { u2, v2 } }, { 0 } },
515 { { { x1, y2 } }, { { u1, v2 } }, { 0 } },
516 };
517
518 $(self, pushDrawArrays, verts, 6, texture, color);
519}

◆ drawView()

void drawView ( Renderer *  self,
View *  view 
)

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

A View whose View::clippingFrame is empty is culled. Otherwise the scissor is set to the View::clippingFrame of the nearest ancestor with clipsSubviews set, or to the full framebuffer when there is none. A View is therefore NOT clipped to its own frame: one that draws outside its bounds does so visibly, and a container that wants to clip its contents MUST set clipsSubviews.

Parameters
selfThe Renderer.
viewThe View to render.

Definition at line 525 of file Renderer.c.

525 {
526
527 assert(view);
528
529 const SDL_Rect clippingFrame = $(view, clippingFrame);
530 if (clippingFrame.w && clippingFrame.h) {
531
532 // The scissor enforces clipsSubviews, so it comes from the nearest clipping ancestor
533 // rather than from this View's own frame: siblings then share a scissor, which is one of
534 // the two conditions under which pushDrawArrays merges their draw calls.
535 const View *superview = view->superview;
536 while (superview && !superview->clipsSubviews) {
537 superview = superview->superview;
538 }
539
540 if (superview) {
541 const SDL_Rect scissor = $(superview, clippingFrame);
542 $(self, setClippingFrame, &scissor);
543 } else {
544 $(self, setClippingFrame, NULL);
545 }
546
547 $(view, render, self);
548 }
549}
static void render(View *self, Renderer *renderer)
Definition Control.c:181
static SDL_Rect clippingFrame(const View *self)
Definition View.c:606
void setClippingFrame(Renderer *self, const SDL_Rect *clippingFrame)
Sets the scissor rectangle for subsequent draw calls.
Definition Renderer.c:841
Views are the fundamental building blocks of ObjectivelyMVC user interfaces.
Definition View.h:225
bool clipsSubviews
If true, subviews will be clipped to this View's frame.
Definition View.h:309
View * superview
The super View.
Definition View.h:454

◆ 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 555 of file Renderer.c.

555 {
556
557 Framebuffer *framebuffer = self->framebuffer;
558 assert(framebuffer);
559
560 const SDL_GPUColorTargetInfo colorTarget = $(framebuffer, colorTargetInfo, 0, SDL_GPU_LOADOP_LOAD, SDL_GPU_STOREOP_STORE);
561
562 const size_t vertexCount = self->vertices->count;
563
564 CopyPass *copyPass = $(self->commands, beginCopyPass);
565
566 if (vertexCount > 0) {
567 const Uint32 vertexSize = (Uint32) (vertexCount * sizeof(MVC_Vertex));
568
569 if (vertexCount > self->vertexBufferCapacity) {
570 release(self->vertexBuffer);
571 self->vertexBuffer = $(self->device, createBuffer, &(SDL_GPUBufferCreateInfo) {
572 .usage = SDL_GPU_BUFFERUSAGE_VERTEX,
573 .size = vertexSize
574 });
575
576 release(self->transferBuffer);
577 self->transferBuffer = $(self->device, createTransferBuffer, &(SDL_GPUTransferBufferCreateInfo) {
578 .usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD,
579 .size = vertexSize,
580 });
581
582 self->vertexBufferCapacity = (Uint32) vertexCount;
583 }
584
585 $(self->transferBuffer, write, self->vertices->elements, vertexSize, true);
586
587 $(copyPass, uploadBuffer,
588 &(SDL_GPUTransferBufferLocation) { .transfer_buffer = self->transferBuffer->buffer },
589 &(SDL_GPUBufferRegion) { .buffer = self->vertexBuffer->buffer, .size = vertexSize },
590 true);
591 }
592
593 release(copyPass);
594
595 RenderPass *renderPass = $(self->commands, beginRenderPass, &colorTarget, 1, NULL);
596
597 $(renderPass, setViewport, &(SDL_GPUViewport){
598 .x = 0.0f, .y = 0.0f,
599 .w = (float) framebuffer->size.w, .h = (float) framebuffer->size.h,
600 .min_depth = 0.0f, .max_depth = 1.0f,
601 });
602
603 int winW, winH;
604 SDL_GetWindowSize(self->device->window, &winW, &winH);
605 const mat4 projection = mat4_ortho(0.f, (float) winW, (float) winH, 0.f, -1.f, 1.f);
606 $(self->commands, pushVertexUniformData, 0, projection.f, sizeof(projection));
607
608 $(renderPass, bindPipeline, self->pipeline);
609
610 // the vertex buffer is created only once something has been drawn into the frame, so a
611 // frame that drew nothing has none to bind
612 if (vertexCount) {
613
614 $(renderPass, bindVertexBuffers, 0, &(SDL_GPUBufferBinding) { .buffer = self->vertexBuffer->buffer }, 1);
615
616 for (size_t i = 0; i < self->drawArrays->count; i++) {
617 const MVC_DrawArrays *draw = VectorElement(self->drawArrays, MVC_DrawArrays, i);
618
619 $(renderPass, setScissor, &draw->scissor);
620
621 $(renderPass, bindFragmentSamplers, 0, &(SDL_GPUTextureSamplerBinding) {
622 .texture = draw->texture->texture, .sampler = self->sampler->sampler,
623 }, 1);
624
625 $(renderPass, drawPrimitives, draw->vertexCount, 1, draw->firstVertex, 0);
626 }
627 }
628
629 release(renderPass);
630
631 self->commands = NULL;
632 self->framebuffer = NULL;
633}
static void draw(View *self, Renderer *renderer)
Definition View.c:778

◆ 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 639 of file Renderer.c.

639 {
640
641 self = (Renderer *) super(Object, self, init);
642 if (self) {
643 self->device = retain(device);
644 assert(self->device);
645
646 self->vertices = $(alloc(Vector), initWithSize, sizeof(MVC_Vertex));
647 assert(self->vertices);
648
649 self->drawArrays = $(alloc(Vector), initWithSize, sizeof(MVC_DrawArrays));
650 assert(self->drawArrays);
651 }
652
653 return self;
654}
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. Consecutive calls that share both texture and the current scissor are merged into one draw call. Only the immediately preceding record is considered, so draw order matters: a quad from another texture between two same-texture quads breaks the run.

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 to apply to every vertex, or NULL to keep the colors the vertices already carry. MVC_Vertex::color is interpolated across the triangle, so NULL is how a caller draws a gradient.

Definition at line 660 of file Renderer.c.

660 {
661
662 assert(verts);
663
664 const MVC_DrawArrays draw = {
665 .firstVertex = (Uint32) self->vertices->count,
666 .vertexCount = (Uint32) count,
667 .texture = texture ? texture : self->white,
668 .scissor = self->scissor,
669 };
670
671 Vector *vertices = self->vertices;
672
673 if (vertices->count + count > vertices->capacity) {
674 $(vertices, resize, max(vertices->capacity * 2, vertices->count + count));
675 }
676
677 MVC_Vertex *out = VectorElement(vertices, MVC_Vertex, vertices->count);
678 for (size_t i = 0; i < count; i++) {
679 out[i] = verts[i];
680 if (color) {
681 out[i].color = *color;
682 }
683 }
684
685 vertices->count += count;
686
687 // If this drawArrays is contiguous with the last one, combine them into a single call
688
689 if (self->drawArrays->count) {
690 MVC_DrawArrays *last = VectorElement(self->drawArrays, MVC_DrawArrays, self->drawArrays->count - 1);
691 if (last->texture == draw.texture && SDL_RectsEqual(&last->scissor, &draw.scissor)) {
692 last->vertexCount += draw.vertexCount;
693 } else {
694 $(self->drawArrays, add, (MVC_DrawArrays *) &draw);
695 }
696 } else {
697 $(self->drawArrays, add, (MVC_DrawArrays *) &draw);
698 }
699}
static void resize(View *self, const SDL_Size *size)
Definition View.c:1708

◆ renderDeviceDidReset()

void renderDeviceDidReset ( Renderer *  self)

Recreates MVC GPU resources after the backing RenderDevice resets.

Parameters
selfThe Renderer.

Definition at line 705 of file Renderer.c.

705 {
706
707 Shader *vertexShader = $(self->device, loadShader, "Renderer.vert", &(SDL_GPUShaderCreateInfo) {
708 .stage = SDL_GPU_SHADERSTAGE_VERTEX,
709 .num_uniform_buffers = 1,
710 });
711
712 Shader *fragmentShader = $(self->device, loadShader, "Renderer.frag", &(SDL_GPUShaderCreateInfo) {
713 .stage = SDL_GPU_SHADERSTAGE_FRAGMENT,
714 .num_samplers = 1,
715 });
716
717 const SDL_GPUVertexBufferDescription vertexBufferInfo = {
718 .slot = 0,
719 .pitch = sizeof(MVC_Vertex),
720 .input_rate = SDL_GPU_VERTEXINPUTRATE_VERTEX,
721 .instance_step_rate = 0,
722 };
723
724 const SDL_GPUColorTargetDescription colorTarget = {
725 .format = $(self->device, getSwapchainTextureFormat),
726 .blend_state = {
727 .enable_blend = true,
728 .color_blend_op = SDL_GPU_BLENDOP_ADD,
729 .alpha_blend_op = SDL_GPU_BLENDOP_ADD,
730 .src_color_blendfactor = SDL_GPU_BLENDFACTOR_SRC_ALPHA,
731 .dst_color_blendfactor = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA,
732 .src_alpha_blendfactor = SDL_GPU_BLENDFACTOR_ONE,
733 .dst_alpha_blendfactor = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA,
734 },
735 };
736
737 const SDL_GPUGraphicsPipelineCreateInfo pipelineInfo = {
738 .vertex_shader = vertexShader->shader,
739 .fragment_shader = fragmentShader->shader,
740 .vertex_input_state = {
741 .vertex_buffer_descriptions = &vertexBufferInfo,
742 .num_vertex_buffers = 1,
743 .vertex_attributes = (SDL_GPUVertexAttribute[]) {
744 {
745 .location = 0,
746 .buffer_slot = 0,
747 .format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2,
748 .offset = offsetof(MVC_Vertex, position)
749 },
750 {
751 .location = 1,
752 .buffer_slot = 0,
753 .format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2,
754 .offset = offsetof(MVC_Vertex, uv)
755 },
756 {
757 .location = 2,
758 .buffer_slot = 0,
759 .format = SDL_GPU_VERTEXELEMENTFORMAT_UBYTE4_NORM,
760 .offset = offsetof(MVC_Vertex, color)
761 },
762 {
763 .location = 3,
764 .buffer_slot = 0,
765 .format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT4,
766 .offset = offsetof(MVC_Vertex, rect)
767 },
768 {
769 .location = 4,
770 .buffer_slot = 0,
771 .format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2,
772 .offset = offsetof(MVC_Vertex, shape)
773 },
774 },
775 .num_vertex_attributes = 5,
776 },
777 .primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST,
778 .rasterizer_state = {
779 .fill_mode = SDL_GPU_FILLMODE_FILL,
780 .cull_mode = SDL_GPU_CULLMODE_NONE,
781 .front_face = SDL_GPU_FRONTFACE_COUNTER_CLOCKWISE,
782 },
783 .target_info = {
784 .color_target_descriptions = &colorTarget,
785 .num_color_targets = 1,
786 },
787 };
788
789 self->pipeline = $(self->device, createGraphicsPipeline, &pipelineInfo);
790
791 release(vertexShader);
792 release(fragmentShader);
793
794 self->sampler = $(self->device, createSampler, &(const SDL_GPUSamplerCreateInfo) {
795 .min_filter = SDL_GPU_FILTER_LINEAR,
796 .mag_filter = SDL_GPU_FILTER_LINEAR,
797 .mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_LINEAR,
798 .address_mode_u = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE,
799 .address_mode_v = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE,
800 .address_mode_w = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE,
801 });
802
803 const Uint8 white[4] = { 255, 255, 255, 255 };
804
805 self->white = $(self->device, createTexture, &(const SDL_GPUTextureCreateInfo) {
806 .type = SDL_GPU_TEXTURETYPE_2D,
807 .format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM,
808 .usage = SDL_GPU_TEXTUREUSAGE_SAMPLER,
809 .width = 1,
810 .height = 1,
811 .layer_count_or_depth = 1,
812 .num_levels = 1,
813 }, white);
814}

◆ renderDeviceWillReset()

void renderDeviceWillReset ( Renderer *  self)

Releases MVC GPU resources before the backing RenderDevice resets.

Parameters
selfThe Renderer.

Definition at line 820 of file Renderer.c.

820 {
821
822 self->commands = NULL;
823
824 self->white = release(self->white);
825 self->sampler = release(self->sampler);
826
827 self->vertexBuffer = release(self->vertexBuffer);
828 self->transferBuffer = release(self->transferBuffer);
829 self->vertexBufferCapacity = 0;
830
831 self->pipeline = release(self->pipeline);
832
833 $(self->vertices, removeAll);
834 $(self->drawArrays, removeAll);
835}

◆ 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 841 of file Renderer.c.

841 {
842
843 if (clippingFrame) {
844 self->scissor = MVC_TransformToWindow(self->device->window, clippingFrame);
845 } else {
846 self->scissor = MakeRect(0, 0, self->framebuffer->size.w, self->framebuffer->size.h);
847 }
848}
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 97 of file Renderer.h.

◆ interface

RendererInterface* Renderer::interface[0]
protected

The interface type.

Definition at line 86 of file Renderer.h.

◆ object

Object Renderer::object

The superclass.

Definition at line 80 of file Renderer.h.


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