commit 489391e
uint
·
2026-07-23 12:56:23 +0000 UTC
parent 4b3b38c
add sokol rendering and mesh setup Also compiling with C99 for now but thats only to get maths library to work
7 files changed,
+361,
-10
+32,
-1
1@@ -1,7 +1,29 @@
2 #ifndef RENDERER_H
3 #define RENDERER_H
4
5-#include <platform/platform.h>
6+#include "types.h"
7+#include "platform/platform.h"
8+
9+typedef u32 MGMesh;
10+#define MGMESH_INVALID ((MGMesh) 0)
11+
12+typedef struct {
13+ float x;
14+ float y;
15+ float z;
16+
17+ float u;
18+ float v;
19+
20+ u32 col;
21+} MGVertex;
22+
23+typedef struct {
24+ const MGVertex* vtc; /* vertices */
25+ u32 vtcc; /* vertices count */
26+ const u16* idc; /* indecies */
27+ u32 idcc; /* indecies count */
28+} MGMeshDesc;
29
30 /* create renderer with chosen context
31 (just GL for now) */
32@@ -16,5 +38,14 @@ void renderer_end(void);
33 /* destroy renderer resources */
34 void renderer_destroy(void);
35
36+/* create mesh from descriptor */
37+MGMesh renderer_mesh_create(const MGMeshDesc* desc);
38+
39+/* draws mesh using specified mvp mat */
40+void renderer_mesh_draw(MGMesh id, const float mvp[16]); /* TODO: use MGMat4 or wtv itll be called */
41+
42+/* destroy mesh */
43+void renderer_mesh_destroy(MGMesh id);
44+
45 #endif /* RENDERER_H */
46
+69,
-0
1@@ -0,0 +1,69 @@
2+#ifndef TEST_BLOCK_H
3+#define TEST_BLOCK_H
4+
5+#include "renderer/renderer.h"
6+
7+#define RGBA(r, g, b, a) ( \
8+ ((u32)(r) ) | \
9+ ((u32)(g) << 8) | \
10+ ((u32)(b) << 16) | \
11+ ((u32)(a) << 24) \
12+)
13+
14+MGMesh block_mesh_create(void);
15+
16+static const MGVertex vtc[24] = {
17+ /* north: -z */
18+ {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, RGBA(255, 0, 0, 255)},
19+ {0.0f, 1.0f, 0.0f, 0.0f, 0.0f, RGBA(255, 0, 0, 255)},
20+ {1.0f, 1.0f, 0.0f, 0.0f, 0.0f, RGBA(255, 0, 0, 255)},
21+ {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, RGBA(255, 0, 0, 255)},
22+
23+ /* south: +z */
24+ {1.0f, 0.0f, 1.0f, 0.0f, 0.0f, RGBA(0, 255, 0, 255)},
25+ {1.0f, 1.0f, 1.0f, 0.0f, 0.0f, RGBA(0, 255, 0, 255)},
26+ {0.0f, 1.0f, 1.0f, 0.0f, 0.0f, RGBA(0, 255, 0, 255)},
27+ {0.0f, 0.0f, 1.0f, 0.0f, 0.0f, RGBA(0, 255, 0, 255)},
28+
29+ /* west: -x */
30+ {0.0f, 0.0f, 1.0f, 0.0f, 0.0f, RGBA(0, 0, 255, 255)},
31+ {0.0f, 1.0f, 1.0f, 0.0f, 0.0f, RGBA(0, 0, 255, 255)},
32+ {0.0f, 1.0f, 0.0f, 0.0f, 0.0f, RGBA(0, 0, 255, 255)},
33+ {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, RGBA(0, 0, 255, 255)},
34+
35+ /* east: +x */
36+ {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, RGBA(255, 255, 0, 255)},
37+ {1.0f, 1.0f, 0.0f, 0.0f, 0.0f, RGBA(255, 255, 0, 255)},
38+ {1.0f, 1.0f, 1.0f, 0.0f, 0.0f, RGBA(255, 255, 0, 255)},
39+ {1.0f, 0.0f, 1.0f, 0.0f, 0.0f, RGBA(255, 255, 0, 255)},
40+
41+ /* bottom: -y */
42+ {0.0f, 0.0f, 1.0f, 0.0f, 0.0f, RGBA(255, 0, 255, 255)},
43+ {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, RGBA(255, 0, 255, 255)},
44+ {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, RGBA(255, 0, 255, 255)},
45+ {1.0f, 0.0f, 1.0f, 0.0f, 0.0f, RGBA(255, 0, 255, 255)},
46+
47+ /* top: +y */
48+ {0.0f, 1.0f, 0.0f, 0.0f, 0.0f, RGBA(0, 255, 255, 255)},
49+ {0.0f, 1.0f, 1.0f, 0.0f, 0.0f, RGBA(0, 255, 255, 255)},
50+ {1.0f, 1.0f, 1.0f, 0.0f, 0.0f, RGBA(0, 255, 255, 255)},
51+ {1.0f, 1.0f, 0.0f, 0.0f, 0.0f, RGBA(0, 255, 255, 255)}
52+};
53+
54+static const u16 idc[36] = {
55+ 0, 1, 2, 0, 2, 3,
56+ 4, 5, 6, 4, 6, 7,
57+ 8, 9, 10, 8, 10, 11,
58+ 12, 13, 14, 12, 14, 15,
59+ 16, 17, 18, 16, 18, 19,
60+ 20, 21, 22, 20, 22, 23,
61+};
62+
63+MGMesh block_mesh_create(void)
64+{
65+ MGMeshDesc desc = { vtc, 24, idc, 36 };
66+ return renderer_mesh_create(&desc);
67+}
68+
69+#endif /* TEST_BLOCK_H */
70+
+59,
-0
1@@ -0,0 +1,59 @@
2+#ifndef TEST_SCENE_H
3+#define TEST_SCENE_H
4+
5+#include <HandmadeMath.h>
6+
7+#include "util.h"
8+#include "renderer/renderer.h"
9+#include "renderer/test_block.h"
10+
11+static MGMesh block = MGMESH_INVALID;
12+
13+void test_scene_create(void)
14+{
15+ block = block_mesh_create();
16+
17+ if (block == MGMESH_INVALID)
18+ mg_die(MG_ERR_REN_CREATE, "Failed to create test block mesh");
19+}
20+
21+void test_scene_draw(MGContext* ctx)
22+{
23+ HMM_Mat4 proj;
24+ HMM_Mat4 view;
25+ HMM_Mat4 model;
26+ HMM_Mat4 view_model;
27+ HMM_Mat4 mvp;
28+ i32 width;
29+ i32 height;
30+ float aspect;
31+
32+ platform_get_drawable_size(ctx, &width, &height);
33+
34+ if (width <= 0 || height <= 0)
35+ return;
36+
37+ aspect = (float)width / (float)height;
38+
39+ proj = HMM_Perspective_RH_NO(HMM_AngleDeg(70.0f), aspect, 0.1f, 100.0f);
40+ view = HMM_LookAt_RH(
41+ HMM_V3(2.5f, 2.0f, 3.0f),
42+ HMM_V3(0.5f, 0.5f, 0.5f),
43+ HMM_V3(0.0f, 1.0f, 0.0f)
44+ );
45+
46+ model = HMM_M4D(1.0f);
47+ view_model = HMM_MulM4(view, model);
48+ mvp = HMM_MulM4(proj, view_model);
49+
50+ renderer_mesh_draw(block, &mvp.Elements[0][0]);
51+}
52+
53+void test_scene_destroy(void)
54+{
55+ renderer_mesh_destroy(block);
56+ block = MGMESH_INVALID;
57+}
58+
59+#endif /* TEST_SCENE_H */
60+
+4,
-2
1@@ -1,8 +1,6 @@
2 #ifndef UTIL_H
3 #define UTIL_H
4
5-#include <stdio.h>
6-
7 typedef enum { /* TODO: rename to MG_EC_... */
8 MG_ERR_EXIT_SUCCESS,
9 MG_ERR_EXIT_FAILURE,
10@@ -13,6 +11,10 @@ typedef enum { /* TODO: rename to MG_EC_... */
11 MG_ERR_GL_CTX_CREATE,
12 MG_ERR_GL_CTX_ACTIVATE,
13
14+ MG_ERR_SHADER_CREATE,
15+
16+ MG_ERR_PIPELINE_CREATE,
17+
18 MG_ERR_REN_CREATE,
19
20 MG_ERR_LAST
+1,
-1
1@@ -2,7 +2,7 @@ project(
2 'Magnolia',
3 'c',
4 default_options: [
5- 'c_std=c89',
6+ 'c_std=c99',
7 'warning_level=3',
8 ],
9 )
+4,
-6
1@@ -1,8 +1,7 @@
2-#include <stdlib.h>
3-
4 #include "util.h"
5 #include "platform/platform.h"
6 #include "renderer/renderer.h"
7+#include "renderer/test_scene.h"
8
9 int main(void)
10 {
11@@ -14,24 +13,23 @@ int main(void)
12 1024, 768, /* w, h */
13 };
14
15- mg_log(LOG_INF, "test log info");
16- mg_log(LOG_ERR, "test log error");
17- mg_log(LOG_DBG, "test log debug");
18-
19 platform_init(&ctx);
20 platform_window_create(&ctx);
21 renderer_create(&ctx);
22+ test_scene_create();
23
24 while (platform_poll(&ctx)) {
25 renderer_begin();
26
27 /* ... */
28+ test_scene_draw(&ctx);
29
30 renderer_end();
31 platform_present(&ctx);
32 SDL_Delay(1); /* TODO: replace with target fps */
33 }
34
35+ test_scene_destroy();
36 renderer_destroy();
37 platform_shutdown(&ctx);
38 return MG_ERR_EXIT_SUCCESS;
+192,
-0
1@@ -5,16 +5,100 @@
2 #include "platform/platform.h"
3 #include "renderer/renderer.h"
4
5+#define MAX_MESHES (512) /* TODO; random value ig */
6+
7+typedef struct {
8+ sg_buffer vb; /* vertex buffer */
9+ sg_buffer ib; /* index buffer */
10+ u32 ic; /* index count */
11+ i8 used;
12+} RendererMesh;
13+
14 typedef struct {
15 MGContext* ctx;
16 i8 pass; /* basically a bool; in
17 render pass or not */
18+
19+ sg_shader shader;
20+ sg_pipeline pipeline;
21+
22+ RendererMesh meshes[MAX_MESHES];
23 } RendererState;
24
25+/* create the shader and render pipeline */
26+static void create_pipelines(void);
27+
28 /* logging function for passing to sokol */
29 static void sokol_log(const char* tag, u32 level, u32 item, const char* msg, u32 ln, const char* file, void* user);
30
31 static RendererState ren;
32+/* TODO: textures */
33+static const char* vsdr =
34+"#version 410\n"
35+"layout(location=0) in vec3 position;\n"
36+"layout(location=1) in vec2 texcoord0;\n"
37+"layout(location=2) in vec4 color0;\n"
38+"\n"
39+"uniform mat4 mvp;\n"
40+"\n"
41+"out vec2 uv;\n"
42+"out vec4 colour;\n"
43+"\n"
44+"void main(void)\n"
45+"{\n"
46+" gl_Position = mvp * vec4(position, 1.0);\n"
47+" uv = texcoord0;\n"
48+" colour = color0;\n"
49+"}\n";
50+static const char* fsdr =
51+"#version 410\n"
52+"in vec2 uv;\n"
53+"in vec4 colour;\n"
54+"\n"
55+"out vec4 frag_colour;\n"
56+"\n"
57+"void main(void)\n"
58+"{\n"
59+" frag_colour = colour;\n"
60+"}\n";
61+
62+static void create_pipelines(void)
63+{
64+ sg_shader_desc shader_desc = {0};
65+ sg_pipeline_desc pipeline_desc = {0};
66+
67+ /* shader descriptor */
68+ shader_desc.vertex_func.source = vsdr;
69+ shader_desc.fragment_func.source = fsdr;
70+ shader_desc.attrs[0].glsl_name = "position";
71+ shader_desc.attrs[1].glsl_name = "texcoord0";
72+ shader_desc.attrs[2].glsl_name = "color0";
73+ shader_desc.uniform_blocks[0].stage = SG_SHADERSTAGE_VERTEX;
74+ shader_desc.uniform_blocks[0].size = sizeof(float) * 16; /* size of mvp matrix */
75+ shader_desc.uniform_blocks[0].layout = SG_UNIFORMLAYOUT_STD140;
76+ shader_desc.uniform_blocks[0] .glsl_uniforms[0].glsl_name = "mvp";
77+ shader_desc.uniform_blocks[0] .glsl_uniforms[0].type = SG_UNIFORMTYPE_MAT4;
78+
79+ ren.shader = sg_make_shader(&shader_desc);
80+ if (sg_query_shader_state(ren.shader) != SG_RESOURCESTATE_VALID)
81+ mg_die(MG_ERR_SHADER_CREATE, "Failed to create shader");
82+
83+ /* pipeline descriptor */
84+ pipeline_desc.shader = ren.shader;
85+ pipeline_desc.layout.buffers[0].stride = sizeof(MGVertex);
86+ pipeline_desc.layout.attrs[0].format = SG_VERTEXFORMAT_FLOAT3;
87+ pipeline_desc.layout.attrs[1].format = SG_VERTEXFORMAT_FLOAT2;
88+ pipeline_desc.layout.attrs[2].format = SG_VERTEXFORMAT_UBYTE4N;
89+ pipeline_desc.index_type = SG_INDEXTYPE_UINT16;
90+ pipeline_desc.depth.compare = SG_COMPAREFUNC_LESS_EQUAL;
91+ pipeline_desc.depth.write_enabled = true;
92+ pipeline_desc.cull_mode = SG_CULLMODE_BACK;
93+ pipeline_desc.face_winding = SG_FACEWINDING_CCW;
94+
95+ ren.pipeline = sg_make_pipeline(&pipeline_desc);
96+ if (sg_query_pipeline_state(ren.pipeline) != SG_RESOURCESTATE_VALID)
97+ mg_die(MG_ERR_PIPELINE_CREATE, "Failed to create pipeline");
98+}
99
100 static void sokol_log(const char* tag, u32 level, u32 item, const char* msg, u32 ln, const char* file, void* user)
101 {
102@@ -49,6 +133,8 @@ void renderer_create(MGContext* ctx)
103
104 if (!sg_isvalid())
105 mg_die(MG_ERR_REN_CREATE, "Failed to initialise renderer");
106+
107+ create_pipelines();
108 }
109
110 void renderer_begin(void)
111@@ -99,9 +185,115 @@ void renderer_end(void)
112
113 void renderer_destroy(void)
114 {
115+ u32 id;
116+ for (id = 1; id < MAX_MESHES; id++)
117+ renderer_mesh_destroy(id);
118+
119+ sg_destroy_pipeline(ren.pipeline);
120+ sg_destroy_shader(ren.shader);
121+
122 if (sg_isvalid())
123 sg_shutdown();
124 ren.ctx = NULL;
125 ren.pass = 0;
126 }
127
128+MGMesh renderer_mesh_create(const MGMeshDesc* desc)
129+{
130+ sg_buffer_desc buffer_desc = {0};
131+ RendererMesh* mesh;
132+ u32 id;
133+
134+ if (!desc || !desc->vtc || !desc->idc || desc->vtcc == 0 || desc->idcc == 0)
135+ return MGMESH_INVALID;
136+
137+ /* find free mesh slot */
138+ for (id = 1; id < MAX_MESHES; id++) {
139+ if (!ren.meshes[id].used)
140+ break;
141+ }
142+
143+ if (id == MAX_MESHES) {
144+ mg_log(LOG_ERR, "Maximum mesh limit reached");
145+ return MGMESH_INVALID;
146+ }
147+
148+ /* vertex buffer */
149+ mesh = &ren.meshes[id];
150+ buffer_desc.data.ptr = desc->vtc;
151+ buffer_desc.data.size = desc->vtcc * sizeof(MGVertex);
152+ mesh->vb = sg_make_buffer(&buffer_desc);
153+
154+ /* index buffer */
155+ buffer_desc = (sg_buffer_desc){0};
156+ buffer_desc.usage.vertex_buffer = false;
157+ buffer_desc.usage.index_buffer = true;
158+ buffer_desc.usage.immutable = true;
159+ buffer_desc.data.ptr = desc->idc;
160+ buffer_desc.data.size = desc->idcc * sizeof(u16);
161+ mesh->ib = sg_make_buffer(&buffer_desc);
162+
163+ i8 valid = sg_query_buffer_state(mesh->vb) == SG_RESOURCESTATE_VALID &&
164+ sg_query_buffer_state(mesh->ib) == SG_RESOURCESTATE_VALID;
165+ if (!valid) {
166+ if (sg_query_buffer_state(mesh->vb) == SG_RESOURCESTATE_VALID)
167+ sg_destroy_buffer(mesh->vb);
168+ if (sg_query_buffer_state(mesh->ib) == SG_RESOURCESTATE_VALID)
169+ sg_destroy_buffer(mesh->ib);
170+
171+ *mesh = (RendererMesh){0};
172+ mg_log(LOG_ERR, "Failed to create mesh buffers");
173+ return MGMESH_INVALID;
174+ }
175+
176+ mesh->ic = desc->idcc;
177+ mesh->used = 1;
178+ return id;
179+}
180+
181+void renderer_mesh_draw(MGMesh id, const float mvp[16])
182+{
183+ RendererMesh* mesh;
184+ sg_bindings bindings = {0};
185+ sg_range uniforms;
186+
187+ if (!ren.pass || !mvp)
188+ return;
189+
190+ if (id == MGMESH_INVALID || id >= MAX_MESHES)
191+ return;
192+
193+ mesh = &ren.meshes[id];
194+ if (!mesh->used)
195+ return;
196+
197+ bindings.vertex_buffers[0] = mesh->vb;
198+ bindings.index_buffer = mesh->ib;
199+
200+ uniforms.ptr = mvp;
201+ uniforms.size = sizeof(float) * 16;
202+
203+ sg_apply_pipeline(ren.pipeline);
204+ sg_apply_bindings(&bindings);
205+ sg_apply_uniforms(0, &uniforms);
206+
207+ sg_draw(0, mesh->ic, 1);
208+}
209+
210+void renderer_mesh_destroy(MGMesh id)
211+{
212+ RendererMesh* mesh;
213+
214+ if (id == MGMESH_INVALID || id >= MAX_MESHES)
215+ return;
216+
217+ mesh = &ren.meshes[id];
218+ if (!mesh->used)
219+ return;
220+
221+ sg_destroy_buffer(mesh->ib);
222+ sg_destroy_buffer(mesh->vb);
223+
224+ *mesh = (RendererMesh){0};
225+}
226+