commit dab7136

uint  ·  2026-07-30 00:25:02 +0000 UTC
parent ba23b8e
dynamic textures with MGTexture
4 files changed,  +140, -67
+11, -2
 1@@ -8,6 +8,9 @@
 2 typedef u32 MGMesh;
 3 #define MGMESH_INVALID ((MGMesh) 0)
 4 
 5+typedef u32 MGTexture;
 6+#define MGTEXTURE_INVALID ((MGTexture) 0)
 7+
 8 typedef struct {
 9 	float x;
10 	float y;
11@@ -42,11 +45,17 @@ void renderer_destroy(void);
12 /* create mesh from descriptor */
13 MGMesh renderer_mesh_create(const MGMeshDesc* desc);
14 
15-/* draws mesh using specified mvp mat */
16-void renderer_mesh_draw(MGMesh id, const MGMat4* mvp);
17+/* draws mesh using specified texture and mat */
18+void renderer_mesh_draw(MGMesh mesh, MGTexture texture, const MGMat4* mvp);
19 
20 /* destroy mesh */
21 void renderer_mesh_destroy(MGMesh id);
22 
23+/* load texture from file */
24+MGTexture renderer_texture_load(const char* path);
25+
26+/* destroy texture */
27+void renderer_texture_destroy(MGTexture id);
28+
29 #endif /* RENDERER_H */
30 
+8, -3
 1@@ -8,14 +8,18 @@
 2 #include "renderer/test_block.h"
 3 
 4 static MGMesh block = MGMESH_INVALID;
 5+static MGTexture block_texture = MGTEXTURE_INVALID;
 6 static MGCamera cam;
 7 
 8 void test_scene_create(void)
 9 {
10 	block = block_mesh_create();
11-
12 	if (block == MGMESH_INVALID)
13-		mg_die(MG_ERR_REN_CREATE, "Failed to create test block mesh");
14+		mg_die(MG_ERR_MESH_CREATE, "Failed to create test block mesh");
15+
16+	block_texture = renderer_texture_load("assets/resourcepacks/default/blocks/brick.png");
17+	if (block_texture == MGTEXTURE_INVALID)
18+		mg_die(MG_ERR_TEXTURE_LOAD, "Failed to load test block texture");
19 
20 	camera_init(&cam, MG_V3(3.0f, 3.0f, 3.0f));
21 	cam.yaw = MG_AngleDeg(-140.0f);
22@@ -45,12 +49,13 @@ void test_scene_draw(MGContext* ctx)
23 
24 	mvp = MG_MulM4(proj, MG_MulM4(view, model));
25 
26-	renderer_mesh_draw(block, &mvp);
27+	renderer_mesh_draw(block, block_texture, &mvp);
28 }
29 
30 void test_scene_destroy(void)
31 {
32 	renderer_mesh_destroy(block);
33+	renderer_texture_destroy(block_texture);
34 	block = MGMESH_INVALID;
35 }
36 
+2, -0
1@@ -15,6 +15,8 @@ typedef enum { /* TODO: rename to MG_EC_... */
2 
3 	MG_ERR_PIPELINE_CREATE,
4 
5+	MG_ERR_MESH_CREATE,
6+
7 	MG_ERR_TEXTURE_LOAD,
8 	MG_ERR_TEXTURE_CREATE,
9 	MG_ERR_SAMPLER_CREATE,
+119, -62
  1@@ -7,6 +7,7 @@
  2 #include "renderer/renderer.h"
  3 
  4 #define MAX_MESHES (512) /* TODO; random value ig */
  5+#define MAX_TEXTURES (512) /* TODO; random value ig */
  6 
  7 typedef struct {
  8 	sg_buffer vb; /* vertex buffer */
  9@@ -15,6 +16,12 @@ typedef struct {
 10 	i8        used;
 11 } RendererMesh;
 12 
 13+typedef struct {
 14+	sg_image image;
 15+	sg_view  view;
 16+	i8       used;
 17+} RendererTexture;
 18+
 19 typedef struct {
 20 	MGContext* ctx;
 21 	i8         pass; /* basically a bool; in
 22@@ -22,18 +29,17 @@ typedef struct {
 23 
 24 	sg_shader   shader;
 25 	sg_pipeline pipeline;
 26+	sg_sampler  sampler;
 27 
 28-	sg_image   texture;
 29-	sg_view    texture_view;
 30-	sg_sampler sampler;
 31-
 32-	RendererMesh meshes[MAX_MESHES];
 33+	RendererMesh    meshes[MAX_MESHES];
 34+	RendererTexture textures[MAX_MESHES];
 35 } RendererState;
 36 
 37 /* create the shader and render pipeline */
 38 static void create_pipelines(void);
 39 
 40-static void create_texture(void);
 41+/* create texture sampler */
 42+static void create_sampler(void);
 43 
 44 /* logging function for passing to sokol  */
 45 static void sokol_log(const char* tag, u32 level, u32 item, const char* msg, u32 ln, const char* file, void* user);
 46@@ -120,54 +126,19 @@ static void create_pipelines(void)
 47 		mg_die(MG_ERR_PIPELINE_CREATE, "Failed to create pipeline");
 48 }
 49 
 50-static void create_texture(void)
 51+static void create_sampler(void)
 52 {
 53-	sg_image_desc image_desc = {0};
 54-	sg_sampler_desc sampler_desc = {0};
 55-	sg_view_desc view_desc = {0};
 56-	stbi_uc* pixels;
 57-	int width;
 58-	int height;
 59-	int chanells;
 60-
 61-	pixels = stbi_load(
 62-		/* "assets/resourcepacks/default/blocks/brick.png", */
 63-		/* "assets/resourcepacks/default/blocks/dirt.png", */
 64-		"assets/smile_test.png",
 65-		&width, &height, &chanells, 4
 66-	);
 67-
 68-	if (!pixels)
 69-		mg_die(MG_ERR_TEXTURE_LOAD, "failed to load texture");
 70-
 71-	/* image */
 72-	image_desc.width = width;
 73-	image_desc.height = height;
 74-	image_desc.pixel_format = SG_PIXELFORMAT_RGBA8;
 75-	image_desc.data.mip_levels[0].ptr = pixels;
 76-	image_desc.data.mip_levels[0].size = width * height * 4;
 77-	ren.texture = sg_make_image(&image_desc);
 78-	stbi_image_free(pixels);
 79+	sg_sampler_desc desc = {0};
 80 
 81-	if (sg_query_image_state(ren.texture) != SG_RESOURCESTATE_VALID)
 82-		mg_die(MG_ERR_TEXTURE_CREATE, "failed to create texture");
 83+	desc.min_filter = SG_FILTER_NEAREST;
 84+	desc.mag_filter = SG_FILTER_NEAREST;
 85+	desc.wrap_u = SG_WRAP_REPEAT;
 86+	desc.wrap_v = SG_WRAP_REPEAT;
 87 
 88-	/* texture view */
 89-	view_desc.texture.image = ren.texture;
 90-	ren.texture_view = sg_make_view(&view_desc);
 91-
 92-	if (sg_query_view_state(ren.texture_view) != SG_RESOURCESTATE_VALID)
 93-		mg_die(MG_ERR_VIEW_CREATE, "failed to texture view");
 94-
 95-	/* sampler */
 96-	sampler_desc.min_filter = SG_FILTER_NEAREST;
 97-	sampler_desc.mag_filter = SG_FILTER_NEAREST;
 98-	sampler_desc.wrap_u = SG_WRAP_REPEAT;
 99-	sampler_desc.wrap_v = SG_WRAP_REPEAT;
100-	ren.sampler = sg_make_sampler(&sampler_desc);
101+	ren.sampler = sg_make_sampler(&desc);
102 
103 	if (sg_query_sampler_state(ren.sampler) != SG_RESOURCESTATE_VALID)
104-		mg_die(MG_ERR_SAMPLER_CREATE, "failed to create sampler");
105+		mg_die(MG_ERR_SAMPLER_CREATE, "Failed to create sampler");
106 }
107 
108 static void sokol_log(const char* tag, u32 level, u32 item, const char* msg, u32 ln, const char* file, void* user)
109@@ -205,7 +176,7 @@ void renderer_create(MGContext* ctx)
110 		mg_die(MG_ERR_REN_CREATE, "Failed to initialise renderer");
111 
112 	create_pipelines();
113-	create_texture();
114+	create_sampler();
115 }
116 
117 void renderer_begin(void)
118@@ -257,13 +228,15 @@ void renderer_end(void)
119 void renderer_destroy(void)
120 {
121 	u32 id;
122+
123+	/* the values could be different in future so
124+	   probably should keep them separate */
125 	for (id = 1; id < MAX_MESHES; id++)
126 		renderer_mesh_destroy(id);
127+	for (id = 1; id < MAX_TEXTURES; id++)
128+		renderer_texture_destroy(id);
129 
130-	sg_destroy_view(ren.texture_view);
131 	sg_destroy_sampler(ren.sampler);
132-	sg_destroy_image(ren.texture);
133-
134 	sg_destroy_pipeline(ren.pipeline);
135 	sg_destroy_shader(ren.shader);
136 
137@@ -327,25 +300,30 @@ MGMesh renderer_mesh_create(const MGMeshDesc* desc)
138 	return id;
139 }
140 
141-void renderer_mesh_draw(MGMesh id, const MGMat4* mvp)
142+void renderer_mesh_draw(MGMesh mesh, MGTexture texture, const MGMat4* mvp)
143 {
144-	RendererMesh* mesh;
145+	RendererMesh* rmesh;
146+	RendererTexture* rtexture;
147 	sg_bindings bindings = {0};
148 	sg_range uniforms;
149 
150 	if (!ren.pass || !mvp)
151 		return;
152 
153-	if (id == MGMESH_INVALID || id >= MAX_MESHES)
154+	if (mesh == MGMESH_INVALID || mesh >= MAX_MESHES)
155 		return;
156 
157-	mesh = &ren.meshes[id];
158-	if (!mesh->used)
159+	if (texture == MGTEXTURE_INVALID || texture >= MAX_TEXTURES)
160 		return;
161 
162-	bindings.vertex_buffers[0] = mesh->vb;
163-	bindings.index_buffer = mesh->ib;
164-	bindings.views[0] = ren.texture_view;
165+	rmesh = &ren.meshes[mesh];
166+	rtexture = &ren.textures[texture];
167+	if (!rmesh->used || !rtexture->used)
168+		return;
169+
170+	bindings.vertex_buffers[0] = rmesh->vb;
171+	bindings.index_buffer = rmesh->ib;
172+	bindings.views[0] = rtexture->view;
173 	bindings.samplers[0] = ren.sampler;
174 
175 	uniforms.ptr = &mvp->Elements[0][0];
176@@ -355,7 +333,7 @@ void renderer_mesh_draw(MGMesh id, const MGMat4* mvp)
177 	sg_apply_bindings(&bindings);
178 	sg_apply_uniforms(0, &uniforms);
179 
180-	sg_draw(0, mesh->ic, 1);
181+	sg_draw(0, rmesh->ic, 1);
182 }
183 
184 void renderer_mesh_destroy(MGMesh id)
185@@ -375,3 +353,82 @@ void renderer_mesh_destroy(MGMesh id)
186 	*mesh = (RendererMesh){0};
187 }
188 
189+MGTexture renderer_texture_load(const char* path)
190+{
191+	sg_image_desc image_desc = {0};
192+	sg_view_desc view_desc = {0};
193+	RendererTexture* texture;
194+	stbi_uc* pixels;
195+	int width;
196+	int height;
197+	int channels;
198+	u32 id;
199+
200+	if (!path)
201+		return MGTEXTURE_INVALID;
202+
203+	/* find free texture slot */
204+	for (id = 1; id < MAX_TEXTURES; id++) {
205+		if (!ren.textures[id].used)
206+			break;
207+	}
208+
209+	if (id == MAX_TEXTURES) {
210+		mg_log(LOG_ERR, "Maximum texture limit reached");
211+		return MGTEXTURE_INVALID;
212+	}
213+
214+	texture = &ren.textures[id];
215+	pixels = stbi_load(path, &width, &height, &channels, 4);
216+	if (!pixels) {
217+		mg_log(LOG_ERR, "Failed to load texture: %s", path);
218+		return MGTEXTURE_INVALID;
219+	}
220+
221+	image_desc.width = width;
222+	image_desc.height = height;
223+	image_desc.pixel_format = SG_PIXELFORMAT_RGBA8;
224+	image_desc.data.mip_levels[0].ptr = pixels;
225+	image_desc.data.mip_levels[0].size =width * height * 4;
226+
227+	texture->image = sg_make_image(&image_desc);
228+	stbi_image_free(pixels);
229+	if (sg_query_image_state(texture->image) != SG_RESOURCESTATE_VALID) {
230+		*texture = (RendererTexture){0};
231+		mg_log(LOG_ERR, "Failed to create texture: %s", path);
232+		return MGTEXTURE_INVALID;
233+	}
234+
235+	view_desc.texture.image = texture->image;
236+	texture->view = sg_make_view(&view_desc);
237+
238+	if (sg_query_view_state(texture->view) != SG_RESOURCESTATE_VALID) {
239+		sg_destroy_image(texture->image);
240+		*texture = (RendererTexture){0};
241+		mg_log(LOG_ERR, "Failed to create texture view: %s", path);
242+		return MGTEXTURE_INVALID;
243+	}
244+
245+	texture->used = 1;
246+
247+	return id;
248+}
249+
250+void renderer_texture_destroy(MGTexture id)
251+{
252+	RendererTexture* texture;
253+
254+	if (id == MGTEXTURE_INVALID || id >= MAX_TEXTURES)
255+		return;
256+
257+	texture = &ren.textures[id];
258+
259+	if (!texture->used)
260+		return;
261+
262+	sg_destroy_view(texture->view);
263+	sg_destroy_image(texture->image);
264+
265+	*texture = (RendererTexture){0};
266+}
267+