commit 42d3dc4

shrub  ·  2026-07-30 21:34:59 +0000 UTC
parent 62f0f04
make it worse
1 files changed,  +148, -73
+148, -73
  1@@ -9,27 +9,39 @@
  2 #include "renderer/renderer.h"
  3 #include "renderer_backend.h"
  4 
  5-#define MAX_MESHES (512)
  6+#define MAX_MESHES (1024)
  7 #define MAX_TEXTURES (512)
  8 #define S3L_MAX_WIDTH (4096)
  9 #define S3L_MAX_HEIGHT (4096)
 10+#define SOFTWARE_MAX_WIDTH (800)
 11+#define SOFTWARE_MAX_HEIGHT (600)
 12+#define TEXTURE_SAMPLE_PERIOD (4)
 13 
 14 #define S3L_MAX_PIXELS (S3L_MAX_WIDTH * S3L_MAX_HEIGHT)
 15 #define S3L_PERSPECTIVE_CORRECTION 2
 16+#define S3L_PC_APPROX_LENGTH 32
 17 #define S3L_NEAR_CROSS_STRATEGY 1
 18 #define S3L_Z_BUFFER 1
 19 #define S3L_PIXEL_FUNCTION small3dlib_pixel
 20 #include <small3dlib.h>
 21 
 22+typedef struct {
 23+	float x;
 24+	float y;
 25+	float z;
 26+	float w;
 27+} ClipVertex;
 28+
 29 typedef struct {
 30 	MGVertex* vtc; /* vertices */
 31 	u16* idc; /* indices */
 32+	u32 vc; /* vertex count */
 33 	u32 ic; /* index count */
 34 	i8 used;
 35 } RendererMesh;
 36 
 37 typedef struct {
 38-	u8* pixels;
 39+	u32* pixels;
 40 	i32 width;
 41 	i32 height;
 42 	i8 used;
 43@@ -41,7 +53,7 @@ typedef struct {
 44 	            render pass or not */
 45 
 46 	SDL_Texture* screen_texture;
 47-	u32* framebuffer;
 48+	u16* framebuffer;
 49 	i32 width;
 50 	i32 height;
 51 
 52@@ -52,14 +64,13 @@ typedef struct {
 53 	RendererTexture* active_texture;
 54 	u32 active_triangle;
 55 	i32 tri_uvs[6];
 56-} RendererState;
 57+	u32 sampled_colour;
 58+	u8 texture_sample_count;
 59 
 60-typedef struct {
 61-	float x;
 62-	float y;
 63-	float z;
 64-	float w;
 65-} ClipVertex;
 66+	ClipVertex* clip_vertices;
 67+	S3L_Vec4* screen_vertices;
 68+	u32 scratch_capacity;
 69+} RendererState;
 70 
 71 static RendererState ren;
 72 
 73@@ -74,23 +85,40 @@ static i8 triangle_outside(const ClipVertex* a, const ClipVertex* b, const ClipV
 74 static i8 triangle_front_facing(const ClipVertex* a, const ClipVertex* b, const ClipVertex* c);
 75 static S3L_Vec4 clip_to_screen(const ClipVertex* v);
 76 static u32 sample_texture(const RendererMesh* mesh, const RendererTexture* texture, const S3L_PixelInfo* pixel);
 77-static u32 rgba_to_sdl(u32 rgba);
 78+static u16 rgba_to_rgb565(u32 rgba);
 79+static u32 pack_texture_pixel(u32 rgba);
 80 
 81 static inline void small3dlib_pixel(S3L_PixelInfo* pixel)
 82 {
 83 	u32 index;
 84+	u32 sampled;
 85 
 86 	if (!ren.active_mesh || !ren.active_texture || !ren.framebuffer)
 87 		return;
 88 
 89+	if (ren.active_triangle != (u32)pixel->triangleIndex)
 90+		ren.texture_sample_count = 0;
 91+	if (ren.texture_sample_count == 0) {
 92+		ren.sampled_colour =
 93+		    sample_texture(ren.active_mesh, ren.active_texture, pixel);
 94+		if ((ren.sampled_colour >> 24) == 0xff)
 95+			ren.texture_sample_count = TEXTURE_SAMPLE_PERIOD;
 96+	}
 97+	sampled = ren.sampled_colour;
 98+	if (ren.texture_sample_count)
 99+		--ren.texture_sample_count;
100+	if ((sampled >> 24) < 128) {
101+		S3L_zBufferWrite(pixel->x, pixel->y, pixel->previousZ);
102+		return;
103+	}
104 	index = (u32)pixel->y * (u32)ren.width + (u32)pixel->x;
105-	ren.framebuffer[index] = rgba_to_sdl(sample_texture(ren.active_mesh, ren.active_texture, pixel));
106+	ren.framebuffer[index] = (u16)sampled;
107 }
108 
109 static void create_screen_texture(i32 width, i32 height)
110 {
111 	u64 pixel_count;
112-	u32* framebuffer;
113+	u16* framebuffer;
114 
115 	if (width == ren.width && height == ren.height && ren.framebuffer && ren.screen_texture)
116 		return;
117@@ -111,7 +139,7 @@ static void create_screen_texture(i32 width, i32 height)
118 
119 	ren.screen_texture = SDL_CreateTexture(
120 	    ren.ctx->vbe.renderer,
121-	    SDL_PIXELFORMAT_RGBA8888,
122+	    SDL_PIXELFORMAT_RGB565,
123 	    SDL_TEXTUREACCESS_STREAMING,
124 	    width,
125 	    height);
126@@ -200,7 +228,11 @@ static S3L_Vec4 clip_to_screen(const ClipVertex* v)
127 
128 	r.x = (S3L_Unit)((ndc_x * 0.5f + 0.5f) * (float)(ren.width - 1));
129 	r.y = (S3L_Unit)((0.5f - ndc_y * 0.5f) * (float)(ren.height - 1));
130-	r.z = (S3L_Unit)(v->w * (float)S3L_F);
131+	/*
132+	 * keep enough reciprocal depth precision for a 
133+	 * useful amount of perspective correction 
134+	 */
135+	r.z = (S3L_Unit)(v->w * 16.0f);
136 	if (r.z < 1)
137 		r.z = 1;
138 	r.w = S3L_F;
139@@ -212,10 +244,10 @@ static u32 sample_texture(const RendererMesh* mesh, const RendererTexture* textu
140 {
141 	u32 tri;
142 	const MGVertex* v[3];
143-	int barycentric[3];
144 	i32 x;
145 	i32 y;
146-	u8* texel;
147+	i32 weighted_x;
148+	i32 weighted_y;
149 
150 	if (!texture || !texture->pixels)
151 		return 0xffffffff;
152@@ -235,43 +267,37 @@ static u32 sample_texture(const RendererMesh* mesh, const RendererTexture* textu
153 		ren.tri_uvs[5] = (i32)(v[2]->v * (float)texture->height);
154 	}
155 
156-	/*licar taught me*/
157-	/*https://en.wikipedia.org/wiki/Barycentric_coordinate_system*/
158-	barycentric[0] = pixel->barycentric[0] / 8;
159-	barycentric[1] = pixel->barycentric[1] / 8;
160-	barycentric[2] = pixel->barycentric[2] / 8;
161-
162-	x = (barycentric[0] * ren.tri_uvs[0] +
163-	     barycentric[1] * ren.tri_uvs[2] +
164-	     barycentric[2] * ren.tri_uvs[4]) /
165-	    (S3L_F / 8);
166-	y = (barycentric[0] * ren.tri_uvs[1] +
167-	     barycentric[1] * ren.tri_uvs[3] +
168-	     barycentric[2] * ren.tri_uvs[5]) /
169-	    (S3L_F / 8);
170-
171-	x %= texture->width;
172-	y %= texture->height;
173+	weighted_x = pixel->barycentric[0] * ren.tri_uvs[0] +
174+	             pixel->barycentric[1] * ren.tri_uvs[2] +
175+	             pixel->barycentric[2] * ren.tri_uvs[4];
176+	weighted_y = pixel->barycentric[0] * ren.tri_uvs[1] +
177+	             pixel->barycentric[1] * ren.tri_uvs[3] +
178+	             pixel->barycentric[2] * ren.tri_uvs[5];
179+	x = weighted_x >> 9;
180+	y = weighted_y >> 9;
181 	if (x < 0)
182-		x += texture->width;
183+		x = 0;
184+	else if (x >= texture->width)
185+		x = texture->width - 1;
186 	if (y < 0)
187-		y += texture->height;
188-
189-	texel = texture->pixels + ((y * texture->width + x) * 4);
190-	return ((u32)texel[0]) |
191-	       ((u32)texel[1] << 8) |
192-	       ((u32)texel[2] << 16) |
193-	       ((u32)texel[3] << 24);
194+		y = 0;
195+	else if (y >= texture->height)
196+		y = texture->height - 1;
197+	return texture->pixels[y * texture->width + x];
198 }
199 
200-static u32 rgba_to_sdl(u32 rgba)
201+static u16 rgba_to_rgb565(u32 rgba)
202 {
203 	u32 r = (rgba >> 0) & 0xff;
204 	u32 g = (rgba >> 8) & 0xff;
205 	u32 b = (rgba >> 16) & 0xff;
206-	u32 a = (rgba >> 24) & 0xff;
207 
208-	return (r << 24) | (g << 16) | (b << 8) | a;
209+	return (u16)(((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3));
210+}
211+
212+static u32 pack_texture_pixel(u32 rgba)
213+{
214+	return ((rgba >> 24) << 24) | rgba_to_rgb565(rgba);
215 }
216 
217 void renderer_backend_create(MGContext* ctx)
218@@ -287,16 +313,30 @@ void renderer_backend_begin(void)
219 {
220 	i32 width;
221 	i32 height;
222+	i32 scaled_width;
223+	i32 scaled_height;
224 	u64 i;
225 	u64 pixel_count;
226-	u32 clear_colour = rgba_to_sdl(0xffb3cce6);
227+	u16 clear_colour = rgba_to_rgb565(0xffb3cce6);
228 
229 	ren.pass = 0;
230 	platform_get_drawable_size(ren.ctx, &width, &height);
231 	if (width <= 0 || height <= 0)
232 		return;
233 
234-	create_screen_texture(width, height);
235+	scaled_width = width;
236+	scaled_height = height;
237+	if (scaled_width > SOFTWARE_MAX_WIDTH) {
238+		scaled_height =
239+		    (i32)(((i64)scaled_height * SOFTWARE_MAX_WIDTH) / scaled_width);
240+		scaled_width = SOFTWARE_MAX_WIDTH;
241+	}
242+	if (scaled_height > SOFTWARE_MAX_HEIGHT) {
243+		scaled_width =
244+		    (i32)(((i64)scaled_width * SOFTWARE_MAX_HEIGHT) / scaled_height);
245+		scaled_height = SOFTWARE_MAX_HEIGHT;
246+	}
247+	create_screen_texture(scaled_width, scaled_height);
248 
249 	pixel_count = (u64)ren.width * (u64)ren.height;
250 	for (i = 0; i < pixel_count; i++)
251@@ -329,8 +369,13 @@ void renderer_backend_destroy(void)
252 		renderer_backend_texture_destroy(id);
253 
254 	destroy_screen_texture();
255+	free(ren.clip_vertices);
256+	free(ren.screen_vertices);
257 
258 	ren.ctx = NULL;
259+	ren.clip_vertices = NULL;
260+	ren.screen_vertices = NULL;
261+	ren.scratch_capacity = 0;
262 	ren.active_mesh = NULL;
263 	ren.active_texture = NULL;
264 	ren.active_triangle = (u32)-1;
265@@ -373,6 +418,7 @@ MGMesh renderer_backend_mesh_create(const MGMeshDesc* desc)
266 
267 	memcpy(mesh->vtc, desc->vtc, desc->vtcc * sizeof(*mesh->vtc));
268 	memcpy(mesh->idc, desc->idc, desc->idcc * sizeof(*mesh->idc));
269+	mesh->vc = desc->vtcc;
270 	mesh->ic = desc->idcc;
271 	mesh->used = 1;
272 
273@@ -383,6 +429,7 @@ void renderer_backend_mesh_draw(MGMesh mesh, MGTexture texture, const MGMat4* mv
274 {
275 	RendererMesh* rmesh;
276 	RendererTexture* rtexture;
277+	u32 vertex;
278 	u32 tri;
279 
280 	if (!ren.pass || !mvp)
281@@ -399,32 +446,52 @@ void renderer_backend_mesh_draw(MGMesh mesh, MGTexture texture, const MGMat4* mv
282 	if (!rmesh->used || !rtexture->used)
283 		return;
284 
285+	if (rmesh->vc > ren.scratch_capacity) {
286+		ClipVertex* clip_vertices;
287+		S3L_Vec4* screen_vertices;
288+		clip_vertices = (ClipVertex*)realloc(ren.clip_vertices,
289+		    rmesh->vc * sizeof(*clip_vertices));
290+		if (!clip_vertices)
291+			return;
292+		ren.clip_vertices = clip_vertices;
293+		screen_vertices = (S3L_Vec4*)realloc(ren.screen_vertices,
294+		    rmesh->vc * sizeof(*screen_vertices));
295+		if (!screen_vertices)
296+			return;
297+		ren.screen_vertices = screen_vertices;
298+		ren.scratch_capacity = rmesh->vc;
299+	}
300+	for (vertex = 0; vertex < rmesh->vc; ++vertex) {
301+		ren.clip_vertices[vertex] =
302+		    transform_vertex(mvp, &rmesh->vtc[vertex]);
303+		if (ren.clip_vertices[vertex].w > 0.0001f)
304+			ren.screen_vertices[vertex] =
305+			    clip_to_screen(&ren.clip_vertices[vertex]);
306+	}
307+
308 	ren.active_mesh = rmesh;
309 	ren.active_texture = rtexture;
310 	ren.active_triangle = (u32)-1;
311+	ren.texture_sample_count = 0;
312 
313 	for (tri = 0; tri < rmesh->ic; tri += 3) {
314-		ClipVertex ca;
315-		ClipVertex cb;
316-		ClipVertex cc;
317-		S3L_Vec4 sa;
318-		S3L_Vec4 sb;
319-		S3L_Vec4 sc;
320-
321-		ca = transform_vertex(mvp, &rmesh->vtc[rmesh->idc[tri + 0]]);
322-		cb = transform_vertex(mvp, &rmesh->vtc[rmesh->idc[tri + 1]]);
323-		cc = transform_vertex(mvp, &rmesh->vtc[rmesh->idc[tri + 2]]);
324-
325-		if (triangle_outside(&ca, &cb, &cc))
326+		u16 ia = rmesh->idc[tri + 0];
327+		u16 ib = rmesh->idc[tri + 1];
328+		u16 ic = rmesh->idc[tri + 2];
329+		ClipVertex* ca = &ren.clip_vertices[ia];
330+		ClipVertex* cb = &ren.clip_vertices[ib];
331+		ClipVertex* cc = &ren.clip_vertices[ic];
332+
333+		if (triangle_outside(ca, cb, cc))
334 			continue;
335-		if (!triangle_front_facing(&ca, &cb, &cc))
336+		if (!triangle_front_facing(ca, cb, cc))
337 			continue;
338 
339-		sa = clip_to_screen(&ca);
340-		sb = clip_to_screen(&cb);
341-		sc = clip_to_screen(&cc);
342-
343-		S3L_drawTriangle(sa, sb, sc, 0, (S3L_Index)(tri / 3));
344+		S3L_drawTriangle(
345+		    ren.screen_vertices[ia],
346+		    ren.screen_vertices[ib],
347+		    ren.screen_vertices[ic],
348+		    0, (S3L_Index)(tri / 3));
349 	}
350 
351 	ren.active_mesh = NULL;
352@@ -476,13 +543,15 @@ MGTexture renderer_backend_texture_create(const MGTextureDesc* desc)
353 {
354 	RendererTexture* texture;
355 	size_t size;
356+	size_t pixel_count;
357+	size_t i;
358 	u32 id;
359 
360-	/* find free texture slot */
361-	for (id = 1; id < MAX_TEXTURES; id++) {
362+	if (!desc || !desc->pixels || desc->width <= 0 || desc->height <= 0)
363+		return MGTEXTURE_INVALID;
364+	for (id = 1; id < MAX_TEXTURES; id++)
365 		if (!ren.textures[id].used)
366 			break;
367-	}
368 
369 	if (id == MAX_TEXTURES) {
370 		mg_log(LOG_ERR, "Maximum texture limit reached");
371@@ -490,16 +559,22 @@ MGTexture renderer_backend_texture_create(const MGTextureDesc* desc)
372 	}
373 
374 	texture = &ren.textures[id];
375-	if (!desc || !desc->pixels || desc->width <= 0 || desc->height <= 0)
376-		return MGTEXTURE_INVALID;
377-	size = (size_t)desc->width * (size_t)desc->height * 4;
378-	texture->pixels = (u8*)malloc(size);
379+	pixel_count = (size_t)desc->width * (size_t)desc->height;
380+	size = pixel_count * sizeof(*texture->pixels);
381+	texture->pixels = (u32*)malloc(size);
382 	if (!texture->pixels) {
383 		mg_log(LOG_ERR, "Failed to create texture");
384 		return MGTEXTURE_INVALID;
385 	}
386 
387-	memcpy(texture->pixels, desc->pixels, size);
388+	for (i = 0; i < pixel_count; ++i) {
389+		const u8* source = desc->pixels + i * 4;
390+		u32 rgba = (u32)source[0] |
391+		           ((u32)source[1] << 8) |
392+		           ((u32)source[2] << 16) |
393+		           ((u32)source[3] << 24);
394+		texture->pixels[i] = pack_texture_pixel(rgba);
395+	}
396 	texture->width = desc->width;
397 	texture->height = desc->height;
398 	texture->used = 1;