summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2025-12-30 17:24:42 -0800
committer3gg <3gg@shellblade.net>2025-12-30 17:24:42 -0800
commit57c6cf991b498aa19cc1cb3d736fec08d3643490 (patch)
treef50d652ffde35c13a024ee87a4429ef9c32c5ef5
parent75ee45cc65b35d40355178f48ef0c2d90040b863 (diff)
Depth buffering and texture coords
-rw-r--r--include/swgfx.h20
-rw-r--r--src/swgfx.c202
2 files changed, 140 insertions, 82 deletions
diff --git a/include/swgfx.h b/include/swgfx.h
index 005359b..970e3fa 100644
--- a/include/swgfx.h
+++ b/include/swgfx.h
@@ -25,14 +25,18 @@ typedef struct sgVec4 { R x, y, z, w; } sgVec4;
25 25
26typedef sgVec3 sgNormal; 26typedef sgVec3 sgNormal;
27 27
28typedef struct sgQuadi { sgVec2i p0, p1; } sgQuadi; 28typedef struct sgVert2i { sgVec2i pos; sgVec2 uv; } sgVert2i;
29typedef struct sgQuad { sgVec2 p0, p1; } sgQuad; 29typedef struct sgVert2 { sgVec2 pos; sgVec2 uv; } sgVert2;
30typedef struct sgTri2 { sgVec2 p0, p1, p2; } sgTri2; 30typedef struct sgVert3 { sgVec3 pos; sgVec2 uv; } sgVert3;
31typedef struct sgTri3 { sgVec3 p0, p1, p2; } sgTri3; 31
32typedef struct sgQuadi { sgVert2i p0, p1; } sgQuadi;
33typedef struct sgQuad { sgVert2 p0, p1; } sgQuad;
34typedef struct sgTri2 { sgVert2 p0, p1, p2; } sgTri2;
35typedef struct sgTri3 { sgVert3 p0, p1, p2; } sgTri3;
32 36
33typedef uint16_t sgIdx; 37typedef uint16_t sgIdx;
34typedef struct sgVert { sgIdx position, normal, texcoord; } sgVert; 38typedef struct sgVertIdx { sgIdx pos, uv, normal; } sgVertIdx;
35typedef struct sgTriIdx { sgVert v0, v1, v2; } sgTriIdx; 39typedef struct sgTriIdx { sgVertIdx v0, v1, v2; } sgTriIdx;
36 40
37// TODO: Should we use real-valued colours? 41// TODO: Should we use real-valued colours?
38typedef struct sgPixel { uint8_t r, g, b, a; } sgPixel; 42typedef struct sgPixel { uint8_t r, g, b, a; } sgPixel;
@@ -62,7 +66,7 @@ void sgTriangles2 (swgfx*, size_t count, const sgTri2*);
62void sgTriangleStrip2(swgfx*, size_t count, const sgVec2*); 66void sgTriangleStrip2(swgfx*, size_t count, const sgVec2*);
63void sgTriangles (swgfx*, size_t count, const sgTri3*, const sgNormal*); 67void sgTriangles (swgfx*, size_t count, const sgTri3*, const sgNormal*);
64void sgTriangleStrip (swgfx*, size_t count, const sgVec3*, const sgNormal*); 68void sgTriangleStrip (swgfx*, size_t count, const sgVec3*, const sgNormal*);
65void sgTrianglesIndexed(swgfx*, size_t numIndices, const sgIdx* indices, const sgVec3* positions); 69void sgTrianglesIndexed(swgfx*, size_t numIndices, const sgIdx* indices, const sgVec3* positions, const sgVec2* texcoords);
66void sgTrianglesIndexedNonUniform(swgfx*, size_t numTris, const sgTriIdx* tris, const sgVec3* positions); 70void sgTrianglesIndexedNonUniform(swgfx*, size_t numTris, const sgTriIdx* tris, const sgVec3* positions, const sgVec2* texcoords);
67 71
68void sgCheck(swgfx*); 72void sgCheck(swgfx*);
diff --git a/src/swgfx.c b/src/swgfx.c
index 54f7432..c298fb4 100644
--- a/src/swgfx.c
+++ b/src/swgfx.c
@@ -22,7 +22,6 @@ Coordinate systems:
22static constexpr sgVec3 Up3 = (sgVec3){0,1,0}; 22static constexpr sgVec3 Up3 = (sgVec3){0,1,0};
23 23
24typedef struct sgViewport_t { int x0, y0, width, height; } sgViewport_t; 24typedef struct sgViewport_t { int x0, y0, width, height; } sgViewport_t;
25typedef struct sgTri2 { sgVec2 p0, p1, p2; } sgTri2;
26typedef struct sgAABB2 { sgVec2 pmin, pmax; } sgAABB2; 25typedef struct sgAABB2 { sgVec2 pmin, pmax; } sgAABB2;
27 26
28// Column-major math, column-major storage. 27// Column-major math, column-major storage.
@@ -33,6 +32,7 @@ typedef struct sgMat4 {
33typedef struct swgfx { 32typedef struct swgfx {
34 sgVec2i dims; // Colour buffer dimensions. 33 sgVec2i dims; // Colour buffer dimensions.
35 sgPixel* colour; // Colour buffer. 34 sgPixel* colour; // Colour buffer.
35 R* depth; // Depth buffer.
36 sgViewport_t viewport; 36 sgViewport_t viewport;
37 sgMat4 model; // Model matrix. 37 sgMat4 model; // Model matrix.
38 sgMat4 view; // View matrix. 38 sgMat4 view; // View matrix.
@@ -48,15 +48,25 @@ typedef struct swgfx {
48 sgMat4 mvp; // Model-view-projection matrix. 48 sgMat4 mvp; // Model-view-projection matrix.
49} swgfx; 49} swgfx;
50 50
51static inline sgVec3 neg3(sgVec3 v) { return (sgVec3){-v.x, -v.y, -v.z}; } 51static inline R rmin(R a, R b) { return (a <= b) ? a : b; }
52static inline R rmax(R a, R b) { return (a >= b) ? a : b; }
53static inline int imin(int a, int b) { return (a <= b) ? a : b; }
54static inline int imax(int a, int b) { return (a >= b) ? a : b; }
52 55
53static inline sgVec3 sub3(sgVec3 a, sgVec3 b) { 56static inline sgVec2 min2(sgVec2 a, sgVec2 b) { return (sgVec2){.x = rmin(a.x, b.x), .y = rmin(a.y, b.y) }; }
54 return (sgVec3){a.x - b.x, a.y - b.y, a.z - b.z}; 57static inline sgVec2 max2(sgVec2 a, sgVec2 b) { return (sgVec2){.x = rmax(a.x, b.x), .y = rmax(a.y, b.y) }; }
55} 58static inline sgVec2i min2i(sgVec2i a, sgVec2i b) { return (sgVec2i){.x = imin(a.x, b.x), .y = imin(a.y, b.y) }; }
59static inline sgVec2i max2i(sgVec2i a, sgVec2i b) { return (sgVec2i){.x = imax(a.x, b.x), .y = imax(a.y, b.y) }; }
56 60
57static inline R dot3(sgVec3 a, sgVec3 b) { 61static inline sgVec2 add2(sgVec2 a, sgVec2 b) { return (sgVec2){a.x + b.x, a.y + b.y}; }
58 return a.x * b.x + a.y * b.y + a.z * b.z; 62static inline sgVec2 scale2(sgVec2 v, R s) { return (sgVec2){v.x * s, v.y * s}; }
59} 63
64static inline sgVec3 neg3(sgVec3 v) { return (sgVec3){-v.x, -v.y, -v.z}; }
65static inline sgVec3 sub3(sgVec3 a, sgVec3 b) { return (sgVec3){a.x - b.x, a.y - b.y, a.z - b.z}; }
66static inline sgVec3 div3(sgVec3 a, sgVec3 b) { return (sgVec3){a.x / b.x, a.y / b.y, a.z / b.z}; }
67static inline R dot3(sgVec3 a, sgVec3 b) { return a.x * b.x + a.y * b.y + a.z * b.z; }
68static inline R normsq3(sgVec3 v) { return v.x * v.x + v.y * v.y + v.z * v.z; }
69static inline R norm3 (sgVec3 v) { return (R)sqrt(normsq3(v)); }
60 70
61static inline sgVec3 cross3(sgVec3 a, sgVec3 b) { 71static inline sgVec3 cross3(sgVec3 a, sgVec3 b) {
62 return (sgVec3) { 72 return (sgVec3) {
@@ -65,18 +75,12 @@ static inline sgVec3 cross3(sgVec3 a, sgVec3 b) {
65 a.x * b.y - a.y * b.x}; 75 a.x * b.y - a.y * b.x};
66} 76}
67 77
68static inline R normsq3(sgVec3 v) { return v.x * v.x + v.y * v.y + v.z * v.z; }
69static inline R norm3 (sgVec3 v) { return (R)sqrt(normsq3(v)); }
70
71static inline sgVec3 normalize3(sgVec3 v) { 78static inline sgVec3 normalize3(sgVec3 v) {
72 const R n = norm3(v); 79 const R n = norm3(v);
73 assert(n > 0); 80 return (n > 0) ? (sgVec3){v.x / n, v.y / n, v.z / n} : (sgVec3){0, 0, 0};
74 return (sgVec3){v.x / n, v.y / n, v.z / n};
75} 81}
76 82
77static inline sgVec4 Vec4FromVec3(sgVec3 v, R w) { 83static inline sgVec4 Vec4FromVec3(sgVec3 v, R w) { return (sgVec4){v.x, v.y, v.z, w}; }
78 return (sgVec4){v.x, v.y, v.z, w};
79}
80 84
81static inline sgMat4 Mat4( 85static inline sgMat4 Mat4(
82 R m00, R m01, R m02, R m03, // v0.x v1.x v2.x v3.x 86 R m00, R m01, R m02, R m03, // v0.x v1.x v2.x v3.x
@@ -231,37 +235,39 @@ static inline sgMat4 Mat4Perspective(R fovy, R aspect, R near, R far) {
231} 235}
232 236
233#ifndef _NDEBUG 237#ifndef _NDEBUG
234static bool InBounds(int width, int height, sgVec2i p) { 238static bool InBounds(int width, int height, int x, int y) {
235 return (0 <= p.x) && (p.x < width) && 239 return (0 <= x) && (x < width) &&
236 (0 <= p.y) && (p.y < height); 240 (0 <= y) && (y < height);
237} 241}
238#endif // _NDEBUG 242#endif // _NDEBUG
239 243
240static inline sgPixel* Pixel(sgPixel* image, int width, int height, int x, int y) { 244static inline sgPixel* Pixel(swgfx* gfx, int x, int y) {
241 assert(InBounds(width, height, (sgVec2i){x,y})); 245 assert(gfx);
242 return image + (y * width) + x; 246 assert(gfx->colour);
247 assert(InBounds(gfx->dims.x, gfx->dims.y, x, y));
248 return gfx->colour + (y * gfx->dims.x) + x;
243} 249}
244 250
245static inline R rmin(R a, R b) { return (a <= b) ? a : b; } 251static inline R* Depth(swgfx* gfx, int x, int y) {
246static inline R rmax(R a, R b) { return (a >= b) ? a : b; } 252 assert(gfx);
247static inline int imin(int a, int b) { return (a <= b) ? a : b; } 253 assert(gfx->depth);
248static inline int imax(int a, int b) { return (a >= b) ? a : b; } 254 assert(InBounds(gfx->dims.x, gfx->dims.y, x, y));
249static inline sgVec2 min2(sgVec2 a, sgVec2 b) { 255 return gfx->depth + (y * gfx->dims.x) + x;
250 return (sgVec2){.x = rmin(a.x, b.x), .y = rmin(a.y, b.y) };
251}
252static inline sgVec2 max2(sgVec2 a, sgVec2 b) {
253 return (sgVec2){.x = rmax(a.x, b.x), .y = rmax(a.y, b.y) };
254} 256}
255static inline sgVec2i min2i(sgVec2i a, sgVec2i b) { 257
256 return (sgVec2i){.x = imin(a.x, b.x), .y = imin(a.y, b.y) }; 258void SetPixel(swgfx* gfx, const sgVec2i p, sgPixel colour) {
259 assert(gfx);
260 *Pixel(gfx, p.x, p.y) = colour;
257} 261}
258static inline sgVec2i max2i(sgVec2i a, sgVec2i b) { 262
259 return (sgVec2i){.x = imax(a.x, b.x), .y = imax(a.y, b.y) }; 263void SetDepth(swgfx* gfx, const sgVec2i p, R depth) {
264 assert(gfx);
265 *Depth(gfx, p.x, p.y) = depth;
260} 266}
261 267
262static inline sgAABB2 TriangleAabb2(const sgTri2 tri) { 268static inline sgAABB2 TriangleAabb2(sgVec2 p0, sgVec2 p1, sgVec2 p2) {
263 return (sgAABB2){.pmin = min2(min2(tri.p0, tri.p1), tri.p2), 269 return (sgAABB2){.pmin = min2(min2(p0, p1), p2),
264 .pmax = max2(max2(tri.p0, tri.p1), tri.p2)}; 270 .pmax = max2(max2(p0, p1), p2)};
265} 271}
266 272
267static inline sgVec2i Clip(const swgfx* gfx, const sgVec2i p) { 273static inline sgVec2i Clip(const swgfx* gfx, const sgVec2i p) {
@@ -272,30 +278,45 @@ static inline sgVec2i Clip(const swgfx* gfx, const sgVec2i p) {
272 return max2i(lower, min2i(upper, p)); 278 return max2i(lower, min2i(upper, p));
273} 279}
274 280
281static inline R BarycentricInterp1(sgVec3 bar, R a, R b, R c) {
282 return bar.x*a + bar.y*b + bar.z*c;
283}
284static inline sgVec2 BarycentricInterp2(sgVec3 bar, sgVec2 a, sgVec2 b, sgVec2 c) {
285 return add2(add2(scale2(a, bar.x), scale2(b, bar.y)), scale2(c, bar.z));
286}
287static inline sgVec2 PerspectiveInterp2(sgVec3 bar, sgVec3 depths, R z, sgVec2 a, sgVec2 b, sgVec2 c) {
288 return scale2(BarycentricInterp2(div3(bar, depths), a, b, c), z);
289}
290
275static inline R f(sgVec2 a, sgVec2 b, sgVec2 p) { 291static inline R f(sgVec2 a, sgVec2 b, sgVec2 p) {
276 return (a.y - b.y)*p.x + (b.x - a.x)*p.y + a.x*b.y - b.x*a.y; 292 return (a.y - b.y)*p.x + (b.x - a.x)*p.y + a.x*b.y - b.x*a.y;
277} 293}
278 294
279static inline sgVec3 Barycentric(const sgTri2 tri, sgVec2 p) { 295static inline sgVec3 Barycentric(sgVec2 p0, sgVec2 p1, sgVec2 p2, sgVec2 p) {
280 // There is no need to compute the third coordinate explicitly: a + b + c = 1. 296 // There is no need to compute the third coordinate explicitly: a + b + c = 1.
281 // But this results in a worse rasterization of the triangle along one of the edges. 297 // But this results in a worse rasterization of the triangle along one of the edges.
282 // It seems we can patch it with a small epsilon, though. 298 // It seems we can patch it with a small epsilon, though.
283 // --- 299 // ---
284 // Division by zero is only possible if the triangle has zero area. 300 // Division by zero is only possible if the triangle has zero area.
285 /*return (sgVec3){ 301 /*return (sgVec3){
286 f(tri.p1, tri.p2, p) / f(tri.p1, tri.p2, tri.p0), 302 f(p1, p2, p) / f(p1, p2, p0),
287 f(tri.p2, tri.p0, p) / f(tri.p2, tri.p0, tri.p1), 303 f(p2, p0, p) / f(p2, p0, p1),
288 f(tri.p0, tri.p1, p) / f(tri.p0, tri.p1, tri.p2)};*/ 304 f(p0, p1, p) / f(p0, p1, p2)};*/
289 const R b = f(tri.p0, tri.p2, p) / f(tri.p0, tri.p2, tri.p1); 305 const R b = f(p0, p2, p) / f(p0, p2, p1);
290 const R c = f(tri.p0, tri.p1, p) / f(tri.p0, tri.p1, tri.p2); 306 const R c = f(p0, p1, p) / f(p0, p1, p2);
291 const R a = /*f(tri.p1, tri.p2, p) / f(tri.p1, tri.p2, tri.p0);*/1.f - b - c - (R)1e-7; 307 const R a = /*f(p1, p2, p) / f(p1, p2, p0);*/1.f - b - c - (R)1e-7;
292 return (sgVec3){a,b,c}; 308 return (sgVec3){a,b,c};
293} 309}
294 310
295static void DrawTriangle2(swgfx* gfx, const sgTri2* tri) { 311// Input triangle in screen space. Retains Z for depth testing and vertex
312// attribute interpolation.
313static void DrawTriangle2(swgfx* gfx, const sgTri3* const tri) {
296 assert(gfx); 314 assert(gfx);
297 assert(tri); 315 assert(tri);
298 const sgAABB2 bbox = TriangleAabb2(*tri); 316 const sgVec2 p0 = (sgVec2){tri->p0.pos.x, tri->p0.pos.y};
317 const sgVec2 p1 = (sgVec2){tri->p1.pos.x, tri->p1.pos.y};
318 const sgVec2 p2 = (sgVec2){tri->p2.pos.x, tri->p2.pos.y};
319 const sgAABB2 bbox = TriangleAabb2(p0, p1, p2);
299 // We consider (x,y) to be the pixel center. 320 // We consider (x,y) to be the pixel center.
300 // Draw all pixels touched by the bounding box. TODO: Multi-sampling. 321 // Draw all pixels touched by the bounding box. TODO: Multi-sampling.
301 sgVec2i pmin = (sgVec2i){(int)bbox.pmin.x, (int)bbox.pmin.y}; 322 sgVec2i pmin = (sgVec2i){(int)bbox.pmin.x, (int)bbox.pmin.y};
@@ -309,14 +330,23 @@ static void DrawTriangle2(swgfx* gfx, const sgTri2* tri) {
309 const sgVec2 p = (sgVec2){(R)x, (R)y}; 330 const sgVec2 p = (sgVec2){(R)x, (R)y};
310 // TODO: there is an incremental optimization to computing barycentric coordinates; 331 // TODO: there is an incremental optimization to computing barycentric coordinates;
311 // read more about it. 332 // read more about it.
312 const sgVec3 bar = Barycentric(*tri, p); 333 const sgVec3 bar = Barycentric(p0, p1, p2, p);
313 // We need to check the third coordinate. 334 // We need to check the third coordinate.
314 // a + b + c = 1 335 // a + b + c = 1
315 // So, e.g., if a >= 0 and b >= 0, then we have c <= 1, but we could also have c <= 0. 336 // So, e.g., if a >= 0 and b >= 0, then we have c <= 1, but we could also have c <= 0.
316 // In the case c <= 0, then point is outside the triangle. 337 // In the case c <= 0, then point is outside the triangle.
317 if ((bar.x >= 0) && (bar.y >= 0) && (bar.z >= 0)) { 338 if ((bar.x >= 0) && (bar.y >= 0) && (bar.z >= 0)) {
318 const sgVec2i pi = (sgVec2i){(int)x, (int)y}; 339 const R z = BarycentricInterp1(bar, tri->p0.pos.z, tri->p1.pos.z, tri->p2.pos.z);
319 sgPixels(gfx, 1, &pi, (sgPixel){255, 255, 255, 255}); 340 R* depth = Depth(gfx, x, y);
341 if ((0.f <= z) && (z <= 1.f) && (z <= *depth)) {
342 *depth = z;
343 const sgVec3 depths = (sgVec3){tri->p0.pos.z, tri->p1.pos.z, tri->p2.pos.z};
344 const sgVec2 uv = PerspectiveInterp2(bar, depths, z, tri->p0.uv, tri->p1.uv, tri->p2.uv);
345 const int r = (int)(uv.x * 255.f);
346 const int g = (int)(uv.y * 255.f);
347 const sgVec2i pix = (sgVec2i){(int)x, (int)y};
348 SetPixel(gfx, pix, (sgPixel){r, g, 255, 255});
349 }
320 } 350 }
321 } 351 }
322 } 352 }
@@ -327,17 +357,18 @@ static inline sgVec3 PerspDivide(sgVec4 v) {
327} 357}
328 358
329// TODO: Compute a viewport matrix in sgViewport() instead. 359// TODO: Compute a viewport matrix in sgViewport() instead.
330static inline sgVec2 ViewportTransform(sgViewport_t vp, sgVec3 ndc) { 360static inline sgVec3 ViewportTransform(sgViewport_t vp, sgVec3 ndc) {
331 return (sgVec2){ 361 return (sgVec3){
332 .x = (ndc.x+1.f) * ((R)vp.width/2.f) + (R)vp.x0, 362 .x = (ndc.x+1.f) * ((R)vp.width/2.f) + (R)vp.x0,
333 .y = (ndc.y+1.f) * ((R)vp.height/2.f) + (R)vp.y0}; 363 .y = (ndc.y+1.f) * ((R)vp.height/2.f) + (R)vp.y0,
364 .z = ndc.z};
334} 365}
335 366
336static inline sgVec2 ViewportToWindow(sgViewport_t vp, sgVec2 p) { 367static inline sgVec3 ViewportToWindow(sgViewport_t vp, sgVec3 p) {
337 return (sgVec2){p.x, (R)vp.height - p.y}; 368 return (sgVec3){p.x, (R)vp.height - p.y, p.z};
338} 369}
339 370
340static inline sgVec2 TransformPosition(const swgfx* gfx, sgVec3 p) { 371static inline sgVec3 TransformPosition(const swgfx* gfx, sgVec3 p) {
341 assert(gfx); 372 assert(gfx);
342 // Model to clip space. 373 // Model to clip space.
343 const sgVec4 p_clip = Mat4MulVec4(gfx->mvp, Vec4FromVec3(p, 1)); 374 const sgVec4 p_clip = Mat4MulVec4(gfx->mvp, Vec4FromVec3(p, 1));
@@ -345,18 +376,24 @@ static inline sgVec2 TransformPosition(const swgfx* gfx, sgVec3 p) {
345 // Perspective divide. 376 // Perspective divide.
346 const sgVec3 p_ndc = PerspDivide(p_clip); 377 const sgVec3 p_ndc = PerspDivide(p_clip);
347 // TODO: Clip. 378 // TODO: Clip.
348 const sgVec2 p_vp = ViewportTransform(gfx->viewport, p_ndc); 379 const sgVec3 p_vp = ViewportTransform(gfx->viewport, p_ndc);
349 return ViewportToWindow(gfx->viewport, p_vp); 380 return ViewportToWindow(gfx->viewport, p_vp);
350} 381}
351 382
352static void DrawTriangle3(swgfx* gfx, const sgTri3* tri) { 383static void DrawTriangle3(swgfx* gfx, const sgTri3* const tri) {
353 assert(gfx); 384 assert(gfx);
354 assert(tri); 385 assert(tri);
355 const sgVec2 p0 = TransformPosition(gfx, tri->p0); 386 const sgVec3 p0 = TransformPosition(gfx, tri->p0.pos);
356 const sgVec2 p1 = TransformPosition(gfx, tri->p1); 387 const sgVec3 p1 = TransformPosition(gfx, tri->p1.pos);
357 const sgVec2 p2 = TransformPosition(gfx, tri->p2); 388 const sgVec3 p2 = TransformPosition(gfx, tri->p2.pos);
358 const sgTri2 tri2 = (sgTri2){p0, p1, p2}; 389 const sgVec2 uv0 = tri->p0.uv;
359 DrawTriangle2(gfx, &tri2); 390 const sgVec2 uv1 = tri->p1.uv;
391 const sgVec2 uv2 = tri->p2.uv;
392 const sgTri3 tri_screen = (sgTri3){
393 (sgVert3){p0, uv0},
394 (sgVert3){p1, uv1},
395 (sgVert3){p2, uv2}};
396 DrawTriangle2(gfx, &tri_screen);
360} 397}
361 398
362#define is_pow2_or_0(X) ((X & (X - 1)) == 0) 399#define is_pow2_or_0(X) ((X & (X - 1)) == 0)
@@ -389,6 +426,7 @@ static void* Alloc(void** ppMem, size_t count, size_t size) {
389size_t sgMem(int width, int height) { 426size_t sgMem(int width, int height) {
390 return Align(sizeof(swgfx)) + 427 return Align(sizeof(swgfx)) +
391 Align(width * height * sizeof(sgPixel)) + 428 Align(width * height * sizeof(sgPixel)) +
429 Align(width * height * sizeof(R)) +
392 (SG_ALIGN - 1); // To make room to align allocations within the buffer. 430 (SG_ALIGN - 1); // To make room to align allocations within the buffer.
393} 431}
394 432
@@ -397,6 +435,7 @@ swgfx* sgNew(int width, int height, void* mem) {
397 swgfx* gfx = SG_ALLOC(&aligned, 1, swgfx); 435 swgfx* gfx = SG_ALLOC(&aligned, 1, swgfx);
398 gfx->dims = (sgVec2i){width, height}; 436 gfx->dims = (sgVec2i){width, height};
399 gfx->colour = SG_ALLOC(&aligned, width * height, sgPixel); 437 gfx->colour = SG_ALLOC(&aligned, width * height, sgPixel);
438 gfx->depth = SG_ALLOC(&aligned, width * height, R);
400 return gfx; 439 return gfx;
401} 440}
402 441
@@ -481,15 +520,17 @@ void sgViewport(swgfx* gfx, int x0, int y0, int width, int height) {
481 520
482void sgClear(swgfx* gfx) { 521void sgClear(swgfx* gfx) {
483 assert(gfx); 522 assert(gfx);
484 memset(gfx->colour, 0, gfx->dims.x * gfx->dims.y * sizeof(sgPixel)); 523 const int N = gfx->dims.x * gfx->dims.y;
524 memset(gfx->colour, 0, N * sizeof(*gfx->colour));
525 for (int i = 0; i < N; ++i) {
526 gfx->depth[i] = 1.0f;
527 }
485} 528}
486 529
487void sgPixels(swgfx* gfx, size_t count, const sgVec2i* positions, sgPixel colour) { 530void sgPixels(swgfx* gfx, size_t count, const sgVec2i* positions, sgPixel colour) {
488 assert(gfx); 531 assert(gfx);
489#define XY(X,Y) Pixel(gfx->colour, gfx->dims.x, gfx->dims.y, X, Y)
490 for (size_t i = 0; i < count; ++i) { 532 for (size_t i = 0; i < count; ++i) {
491 const sgVec2i p = positions[i]; 533 SetPixel(gfx, positions[i], colour);
492 *XY(p.x, p.y) = colour;
493 } 534 }
494} 535}
495 536
@@ -507,7 +548,12 @@ void sgPixels(swgfx* gfx, size_t count, const sgVec2i* positions, sgPixel colour
507void sgTriangles2(swgfx* gfx, size_t count, const sgTri2* tris) { 548void sgTriangles2(swgfx* gfx, size_t count, const sgTri2* tris) {
508 assert(gfx); 549 assert(gfx);
509 for (size_t i = 0; i < count; ++i) { 550 for (size_t i = 0; i < count; ++i) {
510 DrawTriangle2(gfx, &tris[i]); 551 const sgTri3 tri3 = (sgTri3) {
552 .p0 = (sgVert3){.pos = (sgVec3){tris[i].p0.pos.x, tris[i].p0.pos.y, 0}, .uv = tris[i].p0.uv},
553 .p1 = (sgVert3){.pos = (sgVec3){tris[i].p1.pos.x, tris[i].p1.pos.y, 0}, .uv = tris[i].p1.uv},
554 .p2 = (sgVert3){.pos = (sgVec3){tris[i].p2.pos.x, tris[i].p2.pos.y, 0}, .uv = tris[i].p2.uv},
555 };
556 DrawTriangle2(gfx, &tri3);
511 } 557 }
512} 558}
513 559
@@ -520,10 +566,11 @@ void sgTriangles(swgfx* gfx, size_t count, const sgTri3* tris, const sgNormal*)
520 } 566 }
521} 567}
522 568
523void sgTrianglesIndexed(swgfx* gfx, size_t numIndices, const sgIdx* indices, const sgVec3* positions) { 569void sgTrianglesIndexed(swgfx* gfx, size_t numIndices, const sgIdx* indices, const sgVec3* positions, const sgVec2* texcoords) {
524 assert(gfx); 570 assert(gfx);
525 assert(indices); 571 assert(indices);
526 assert(positions); 572 assert(positions);
573 assert(texcoords);
527 for (size_t i = 0; i < numIndices; i+=3) { 574 for (size_t i = 0; i < numIndices; i+=3) {
528 const sgIdx i0 = indices[i]; 575 const sgIdx i0 = indices[i];
529 const sgIdx i1 = indices[i+1]; 576 const sgIdx i1 = indices[i+1];
@@ -531,21 +578,28 @@ void sgTrianglesIndexed(swgfx* gfx, size_t numIndices, const sgIdx* indices, con
531 const sgVec3 p0 = positions[i0]; 578 const sgVec3 p0 = positions[i0];
532 const sgVec3 p1 = positions[i1]; 579 const sgVec3 p1 = positions[i1];
533 const sgVec3 p2 = positions[i2]; 580 const sgVec3 p2 = positions[i2];
534 const sgTri3 tri = (sgTri3){p0, p1, p2}; 581 const sgVec2 uv0 = texcoords[i0];
582 const sgVec2 uv1 = texcoords[i1];
583 const sgVec2 uv2 = texcoords[i2];
584 const sgTri3 tri = (sgTri3){
585 (sgVert3){p0, uv0},
586 (sgVert3){p1, uv1},
587 (sgVert3){p2, uv2}};
535 DrawTriangle3(gfx, &tri); 588 DrawTriangle3(gfx, &tri);
536 } 589 }
537} 590}
538 591
539void sgTrianglesIndexedNonUniform(swgfx* gfx, size_t numTris, const sgTriIdx* tris, const sgVec3* positions) { 592void sgTrianglesIndexedNonUniform(swgfx* gfx, size_t numTris, const sgTriIdx* tris, const sgVec3* positions, const sgVec2* texcoords) {
540 assert(gfx); 593 assert(gfx);
541 assert(tris); 594 assert(tris);
542 assert(positions); 595 assert(positions);
596 assert(texcoords);
543 for (size_t t = 0; t < numTris; ++t) { 597 for (size_t t = 0; t < numTris; ++t) {
544 const sgTriIdx* triIdx = &tris[t]; 598 const sgTriIdx* triIdx = &tris[t];
545 const sgTri3 tri = (sgTri3){ 599 const sgTri3 tri = (sgTri3){
546 positions[triIdx->v0.position], 600 (sgVert3){positions[triIdx->v0.pos], texcoords[triIdx->v0.uv]},
547 positions[triIdx->v1.position], 601 (sgVert3){positions[triIdx->v1.pos], texcoords[triIdx->v1.uv]},
548 positions[triIdx->v2.position]}; 602 (sgVert3){positions[triIdx->v2.pos], texcoords[triIdx->v2.uv]}};
549 DrawTriangle3(gfx, &tri); 603 DrawTriangle3(gfx, &tri);
550 } 604 }
551} 605}