ObjectivelyMVC
Object oriented MVC framework for SDL3 and GNU C
Loading...
Searching...
No Matches
Renderer.c File Reference
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <Objectively/Vector.h>
#include <ObjectivelyGPU/CopyPass.h>
#include <ObjectivelyGPU/Mathlib.h>
#include <ObjectivelyGPU/RenderPass.h>
#include "Renderer.h"
#include "View.h"
#include "Window.h"
#include "../Assets/Renderer.vert.metal.h"
#include "../Assets/Renderer.frag.metal.h"
#include "../Assets/Renderer.vert.spv.h"
#include "../Assets/Renderer.frag.spv.h"

Go to the source code of this file.

Macros

#define _Class   _Renderer
 

Functions

Class * _Renderer (void)
 
static void beginFrame (Renderer *self)
 
static void beginFrameWith (Renderer *self, CommandBuffer *commands, Framebuffer *framebuffer)
 
static void dealloc (Object *self)
 
static void drawLine (const Renderer *self, const SDL_Point *points, const SDL_Color *color)
 
static void drawLines (const Renderer *self, const SDL_Point *points, size_t count, const SDL_Color *color)
 
static void drawRect (const Renderer *self, const SDL_Rect *rect, const SDL_Color *color)
 
static void drawRectFilled (const Renderer *self, const SDL_Rect *rect, const SDL_Color *color)
 
static void drawTexture (const Renderer *self, Texture *texture, const SDL_Rect *rect, const SDL_Color *color)
 
static void drawView (Renderer *self, View *view)
 
static void endFrame (Renderer *self)
 
static void initialize (Class *clazz)
 
static RendererinitWithDevice (Renderer *self, RenderDevice *device)
 
static void pushDrawArrays (const Renderer *self, const MVC_Vertex *verts, size_t count, Texture *texture, const SDL_Color *color)
 
static void renderDeviceDidReset (Renderer *self)
 
static void renderDeviceWillReset (Renderer *self)
 
static void setClippingFrame (Renderer *self, const SDL_Rect *clippingFrame)
 
static Data * shaderResourceProvider (const char *name)
 ResourceProvider for loading shaders from xxd headers.
 

Macro Definition Documentation

◆ _Class

#define _Class   _Renderer

Definition at line 62 of file Renderer.c.

Function Documentation

◆ _Renderer()

Class * _Renderer ( void  )

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 Renderer.c:496
Renderer extends Object with ObjectivelyMVC's UI rendering layer.
Definition Renderer.h:70

◆ beginFrame()

static void beginFrame ( Renderer self)
static

Definition at line 88 of file Renderer.c.

88 {
89 $(self, beginFrameWith, self->device->commands, self->device->framebuffer);
90}
static void beginFrameWith(Renderer *self, CommandBuffer *commands, Framebuffer *framebuffer)
Definition Renderer.c:96
RenderDevice * device
The backing RenderDevice.
Definition Renderer.h:92

◆ beginFrameWith()

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

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}

◆ dealloc()

static void dealloc ( Object *  self)
static
See also
Object::dealloc(Object *)

Definition at line 69 of file Renderer.c.

69 {
70
71 Renderer *this = (Renderer *) self;
72
73 this->commands = NULL;
74
75 release(this->vertices);
76 release(this->drawArrays);
77 release(this->device);
78
79 super(Object, self, dealloc);
80}
static void dealloc(Object *self)
Definition Renderer.c:69

◆ drawLine()

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

Definition at line 114 of file Renderer.c.

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

◆ drawLines()

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

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}
static void pushDrawArrays(const Renderer *self, const MVC_Vertex *verts, size_t count, Texture *texture, const SDL_Color *color)
Definition Renderer.c:334
Interleaved position + texcoord + color vertex for GPU upload.
Definition Renderer.h:48

◆ drawRect()

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

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()

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

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()

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

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()

static void drawView ( Renderer self,
View view 
)
static

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 void setClippingFrame(Renderer *self, const SDL_Rect *clippingFrame)
Definition Renderer.c:482
static SDL_Rect clippingFrame(const View *self)
Definition View.c:546

◆ endFrame()

static void endFrame ( Renderer self)
static

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

◆ initialize()

static void initialize ( Class *  clazz)
static
See also
Class::initialize(Class *)

Definition at line 496 of file Renderer.c.

496 {
497
498 ((ObjectInterface *) clazz->interface)->dealloc = dealloc;
499
500 ((RendererInterface *) clazz->interface)->beginFrame = beginFrame;
501 ((RendererInterface *) clazz->interface)->beginFrameWith = beginFrameWith;
502 ((RendererInterface *) clazz->interface)->drawLine = drawLine;
503 ((RendererInterface *) clazz->interface)->drawLines = drawLines;
504 ((RendererInterface *) clazz->interface)->drawRect = drawRect;
505 ((RendererInterface *) clazz->interface)->drawRectFilled = drawRectFilled;
506 ((RendererInterface *) clazz->interface)->drawTexture = drawTexture;
507 ((RendererInterface *) clazz->interface)->drawView = drawView;
508 ((RendererInterface *) clazz->interface)->endFrame = endFrame;
509 ((RendererInterface *) clazz->interface)->initWithDevice = initWithDevice;
510 ((RendererInterface *) clazz->interface)->pushDrawArrays = pushDrawArrays;
511 ((RendererInterface *) clazz->interface)->renderDeviceDidReset = renderDeviceDidReset;
512 ((RendererInterface *) clazz->interface)->renderDeviceWillReset = renderDeviceWillReset;
513 ((RendererInterface *) clazz->interface)->setClippingFrame = setClippingFrame;
514
515 $$(Resource, addResourceProvider, shaderResourceProvider);
516}
static void drawView(Renderer *self, View *view)
Definition Renderer.c:234
static Data * shaderResourceProvider(const char *name)
ResourceProvider for loading shaders from xxd headers.
Definition Renderer.c:45
static void beginFrame(Renderer *self)
Definition Renderer.c:88
static void drawRectFilled(const Renderer *self, const SDL_Rect *rect, const SDL_Color *color)
Definition Renderer.c:188
static void drawRect(const Renderer *self, const SDL_Rect *rect, const SDL_Color *color)
Definition Renderer.c:169
static Renderer * initWithDevice(Renderer *self, RenderDevice *device)
Definition Renderer.c:313
static void drawTexture(const Renderer *self, Texture *texture, const SDL_Rect *rect, const SDL_Color *color)
Definition Renderer.c:211
static void drawLine(const Renderer *self, const SDL_Point *points, const SDL_Color *color)
Definition Renderer.c:114
static void endFrame(Renderer *self)
Definition Renderer.c:249
static void renderDeviceDidReset(Renderer *self)
Definition Renderer.c:359
static void renderDeviceWillReset(Renderer *self)
Definition Renderer.c:462
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

◆ initWithDevice()

static Renderer * initWithDevice ( Renderer self,
RenderDevice *  device 
)
static

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()

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

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()

static void renderDeviceDidReset ( Renderer self)
static

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()

static void renderDeviceWillReset ( Renderer self)
static

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()

static void setClippingFrame ( Renderer self,
const SDL_Rect *  clippingFrame 
)
static

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

◆ shaderResourceProvider()

static Data * shaderResourceProvider ( const char *  name)
static

ResourceProvider for loading shaders from xxd headers.

Definition at line 45 of file Renderer.c.

45 {
46
47 Data *data = NULL;
48
49 if (!strcmp("Renderer.vert.metal", name)) {
50 data = $(alloc(Data), initWithConstMemory, Renderer_vert_metal, Renderer_vert_metal_len);
51 } else if (!strcmp("Renderer.frag.metal", name)) {
52 data = $(alloc(Data), initWithConstMemory, Renderer_frag_metal, Renderer_frag_metal_len);
53 } else if (!strcmp("Renderer.vert.spv", name)) {
54 data = $(alloc(Data), initWithConstMemory, Renderer_vert_spv, Renderer_vert_spv_len);
55 } else if (!strcmp("Renderer.frag.spv", name)) {
56 data = $(alloc(Data), initWithConstMemory, Renderer_frag_spv, Renderer_frag_spv_len);
57 }
58
59 return data;
60}