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;