summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2026-02-12 18:24:14 -0800
committer3gg <3gg@shellblade.net>2026-02-12 18:24:14 -0800
commit5f7855b6aa0e3338625eb7d30e8ccc5b74050bbf (patch)
treefc6ae60f612de4193a96768250997487a524881e /src
parent2ce59d54aa110a2c1fc1105855f628c5512f8dac (diff)
Deferred pipeline
Diffstat (limited to 'src')
-rw-r--r--src/swgfx.c65
1 files changed, 39 insertions, 26 deletions
diff --git a/src/swgfx.c b/src/swgfx.c
index 8663b62..d41b69d 100644
--- a/src/swgfx.c
+++ b/src/swgfx.c
@@ -22,6 +22,8 @@ Coordinate systems:
22static constexpr sgTextureId DefaultTextureId = SWGFX_MAX_TEXTURES; 22static constexpr sgTextureId DefaultTextureId = SWGFX_MAX_TEXTURES;
23static constexpr size_t SWGFX_TEXTURE_REGISTER_SIZE = SWGFX_MAX_TEXTURES + 1; 23static constexpr size_t SWGFX_TEXTURE_REGISTER_SIZE = SWGFX_MAX_TEXTURES + 1;
24 24
25static constexpr R DepthClearValue = 1.0f;
26
25static constexpr sgVec3 Up3 = (sgVec3){0,1,0}; 27static constexpr sgVec3 Up3 = (sgVec3){0,1,0};
26 28
27typedef struct sgViewport_t { int x0, y0, width, height; } sgViewport_t; 29typedef struct sgViewport_t { int x0, y0, width, height; } sgViewport_t;
@@ -41,7 +43,7 @@ typedef struct swgfx {
41 sgVec2i dims; // Colour buffer dimensions. 43 sgVec2i dims; // Colour buffer dimensions.
42 sgPixel* colour; // Colour buffer. 44 sgPixel* colour; // Colour buffer.
43 R* depth; // Depth buffer. 45 R* depth; // Depth buffer.
44 sgTextureId* textureId; // Texture ID buffer. 46 sgTextureId* texture; // Texture ID buffer.
45 sgVec2* texcoords; // Texture coords buffer. 47 sgVec2* texcoords; // Texture coords buffer.
46 sgViewport_t viewport; 48 sgViewport_t viewport;
47 sgMat4 model; // Model matrix. 49 sgMat4 model; // Model matrix.
@@ -307,14 +309,14 @@ static inline sgPixel* Pixel(swgfx* gfx, int x, int y) {
307 return gfx->colour + (y * gfx->dims.x) + x; 309 return gfx->colour + (y * gfx->dims.x) + x;
308} 310}
309 311
310static inline R* Depth(swgfx* gfx, int x, int y) { 312static inline const R* Depth(swgfx* gfx, int x, int y) {
311 assert(gfx); 313 assert(gfx);
312 assert(gfx->depth); 314 assert(gfx->depth);
313 assert(InBounds(gfx->dims.x, gfx->dims.y, x, y)); 315 assert(InBounds(gfx->dims.x, gfx->dims.y, x, y));
314 return gfx->depth + (y * gfx->dims.x) + x; 316 return gfx->depth + (y * gfx->dims.x) + x;
315} 317}
316 318
317static inline void SetPixel(swgfx* gfx, const sgVec2i p, sgPixel colour) { 319static inline void SetPixelColour(swgfx* gfx, const sgVec2i p, sgPixel colour) {
318 assert(gfx); 320 assert(gfx);
319 *Pixel(gfx, p.x, p.y) = colour; 321 *Pixel(gfx, p.x, p.y) = colour;
320#if SWGFX_PROFILING 322#if SWGFX_PROFILING
@@ -322,9 +324,14 @@ static inline void SetPixel(swgfx* gfx, const sgVec2i p, sgPixel colour) {
322#endif // SWGFX_PROFILING 324#endif // SWGFX_PROFILING
323} 325}
324 326
325static inline void SetDepth(swgfx* gfx, const sgVec2i p, R depth) { 327static inline void SetPixelDeferred(swgfx* gfx, const sgVec2i p, R depth, sgTextureId texid, sgVec2 uv) {
326 assert(gfx); 328 assert(gfx);
327 *Depth(gfx, p.x, p.y) = depth; 329 gfx->depth[(p.y * gfx->dims.x) + p.x] = depth;
330 gfx->texture[(p.y * gfx->dims.x) + p.x] = texid;
331 gfx->texcoords[(p.y * gfx->dims.x) + p.x] = uv;
332#if SWGFX_PROFILING
333 gfx->counters.pixels++;
334#endif // SWGFX_PROFILING
328} 335}
329 336
330static inline sgPixel ReadTexture(const sgImage* texture, sgVec2i xy) { 337static inline sgPixel ReadTexture(const sgImage* texture, sgVec2i xy) {
@@ -459,7 +466,7 @@ static void DrawTriangle2(swgfx* gfx, const sgTri2* const tri) {
459 assert((bar.x + bar.y + bar.z - 1e7) <= 1.f); 466 assert((bar.x + bar.y + bar.z - 1e7) <= 1.f);
460 const sgVec2 uv = BarycentricInterp2(bar, tri->p0.uv, tri->p1.uv, tri->p2.uv); 467 const sgVec2 uv = BarycentricInterp2(bar, tri->p0.uv, tri->p1.uv, tri->p2.uv);
461 const sgPixel colour = Sample(texture->image, texture->filter, uv); 468 const sgPixel colour = Sample(texture->image, texture->filter, uv);
462 SetPixel(gfx, (sgVec2i){x,y}, colour); 469 SetPixelColour(gfx, (sgVec2i){x,y}, colour);
463 } 470 }
464 } 471 }
465 } 472 }
@@ -650,7 +657,6 @@ static void DrawTriangle3PostClip(swgfx* gfx, const sgTri4* const tri) {
650 const sgVec3 one_over_zs = (sgVec3){1.f / p0.w, 1.f / p1.w, 1.f/ p2.w}; 657 const sgVec3 one_over_zs = (sgVec3){1.f / p0.w, 1.f / p1.w, 1.f/ p2.w};
651 const sgVec3 u_over_zs = (sgVec3){tri->p0.uv.x / p0.w, tri->p1.uv.x / p1.w, tri->p2.uv.x / p2.w}; 658 const sgVec3 u_over_zs = (sgVec3){tri->p0.uv.x / p0.w, tri->p1.uv.x / p1.w, tri->p2.uv.x / p2.w};
652 const sgVec3 v_over_zs = (sgVec3){tri->p0.uv.y / p0.w, tri->p1.uv.y / p1.w, tri->p2.uv.y / p2.w}; 659 const sgVec3 v_over_zs = (sgVec3){tri->p0.uv.y / p0.w, tri->p1.uv.y / p1.w, tri->p2.uv.y / p2.w};
653 const sgTexture* texture = &gfx->textureRegister[gfx->activeTexture];
654 // Draw. 660 // Draw.
655 for (int y = pmin.y; y <= pmax.y; ++y) { 661 for (int y = pmin.y; y <= pmax.y; ++y) {
656 for (int x = pmin.x; x <= pmax.x; ++x) { 662 for (int x = pmin.x; x <= pmax.x; ++x) {
@@ -670,17 +676,15 @@ static void DrawTriangle3PostClip(swgfx* gfx, const sgTri4* const tri) {
670 const R p_depth = dot3(bar, depths); 676 const R p_depth = dot3(bar, depths);
671 const R z = 1.f / p_one_over_z; 677 const R z = 1.f / p_one_over_z;
672 const sgVec2 uv = (sgVec2){p_u_over_z * z, p_v_over_z * z}; 678 const sgVec2 uv = (sgVec2){p_u_over_z * z, p_v_over_z * z};
673 R* depth = Depth(gfx, x, y); 679 const R* depth = Depth(gfx, x, y);
674 if ((0.f <= p_depth) && (p_depth <= 1.f) && (p_depth <= *depth)) { 680 if ((0.f <= p_depth) && (p_depth <= 1.f) && (p_depth <= *depth)) {
675 *depth = p_depth;
676 const sgPixel colour = Sample(texture->image, texture->filter, uv);
677 // TODO: When doing lighting, need to tone-map here and apply inverse 681 // TODO: When doing lighting, need to tone-map here and apply inverse
678 // gamma here. 682 // gamma here.
679 //const sgPixel colour = {(uint8_t)(bar.x*255.f), (uint8_t)(bar.y*255.f), (uint8_t)(bar.z*255.f), 255}; 683 //const sgPixel colour = {(uint8_t)(bar.x*255.f), (uint8_t)(bar.y*255.f), (uint8_t)(bar.z*255.f), 255};
680 //const sgPixel colour = {(int)(z*255.f), (int)(z*255.f), (int)(z*255.f), 255}; 684 //const sgPixel colour = {(int)(z*255.f), (int)(z*255.f), (int)(z*255.f), 255};
681 //const sgPixel colour = {255, 0, 255, 255}; 685 //const sgPixel colour = {255, 0, 255, 255};
682 //const sgPixel colour = {(int)(uv.x * 255.f), (int)(uv.y * 255.f), 255, 255}; 686 //const sgPixel colour = {(int)(uv.x * 255.f), (int)(uv.y * 255.f), 255, 255};
683 SetPixel(gfx, (sgVec2i){x,y}, colour); 687 SetPixelDeferred(gfx, (sgVec2i){x,y}, p_depth, gfx->activeTexture, uv);
684 } 688 }
685 } 689 }
686 } 690 }
@@ -746,7 +750,7 @@ swgfx* sgNew(int width, int height, void* mem) {
746 gfx->dims = (sgVec2i){width, height}; 750 gfx->dims = (sgVec2i){width, height};
747 gfx->colour = SG_ALLOC(&aligned, N, sgPixel); 751 gfx->colour = SG_ALLOC(&aligned, N, sgPixel);
748 gfx->depth = SG_ALLOC(&aligned, N, R); 752 gfx->depth = SG_ALLOC(&aligned, N, R);
749 gfx->textureId = SG_ALLOC(&aligned, N, sgTextureId); 753 gfx->texture = SG_ALLOC(&aligned, N, sgTextureId);
750 gfx->texcoords = SG_ALLOC(&aligned, N, sgVec2); 754 gfx->texcoords = SG_ALLOC(&aligned, N, sgVec2);
751 gfx->textureRegister = SG_ALLOC(&aligned, SWGFX_TEXTURE_REGISTER_SIZE, sgTexture); 755 gfx->textureRegister = SG_ALLOC(&aligned, SWGFX_TEXTURE_REGISTER_SIZE, sgTexture);
752 gfx->activeTexture = DefaultTextureId; 756 gfx->activeTexture = DefaultTextureId;
@@ -850,6 +854,10 @@ void sgPerspective(swgfx* gfx, R fovy, R aspect, R near, R far) {
850 854
851void sgViewport(swgfx* gfx, int x0, int y0, int width, int height) { 855void sgViewport(swgfx* gfx, int x0, int y0, int width, int height) {
852 assert(gfx); 856 assert(gfx);
857 assert(x0 >= 0);
858 assert(y0 >= 0);
859 assert((x0 + width) <= gfx->dims.x);
860 assert((y0 + height) <= gfx->dims.y);
853 gfx->viewport = (sgViewport_t){x0, y0, width, height}; 861 gfx->viewport = (sgViewport_t){x0, y0, width, height};
854} 862}
855 863
@@ -872,14 +880,14 @@ void sgClear(swgfx* gfx) {
872 const int N = gfx->dims.x * gfx->dims.y; 880 const int N = gfx->dims.x * gfx->dims.y;
873 memset(gfx->colour, 0, N * sizeof(*gfx->colour)); 881 memset(gfx->colour, 0, N * sizeof(*gfx->colour));
874 for (int i = 0; i < N; ++i) { 882 for (int i = 0; i < N; ++i) {
875 gfx->depth[i] = 1.0f; 883 gfx->depth[i] = DepthClearValue;
876 } 884 }
877} 885}
878 886
879void sgPixels(swgfx* gfx, size_t count, const sgVec2i* positions, sgPixel colour) { 887void sgPixels(swgfx* gfx, size_t count, const sgVec2i* positions, sgPixel colour) {
880 assert(gfx); 888 assert(gfx);
881 for (size_t i = 0; i < count; ++i) { 889 for (size_t i = 0; i < count; ++i) {
882 SetPixel(gfx, positions[i], colour); 890 SetPixelColour(gfx, positions[i], colour);
883 } 891 }
884} 892}
885 893
@@ -956,6 +964,23 @@ static void ImageExp(sgPixel* pixels, int width, int height, R exp) {
956 } 964 }
957} 965}
958 966
967void sgLighting(swgfx* gfx) {
968 assert(gfx);
969 const int N = gfx->dims.x * gfx->dims.y;
970 for (int i = 0; i < N; ++i) {
971 const R depth = gfx->depth[i];
972 if (depth != DepthClearValue) {
973 const sgTextureId texid = gfx->texture[i];
974 const sgTexture* texture = &gfx->textureRegister[texid];
975 const sgVec2 uv = gfx->texcoords[i];
976 sgPixel* colour = &gfx->colour[i];
977 // TODO: Actual lighting.
978 const sgPixel albedo = Sample(texture->image, texture->filter, uv);
979 *colour = albedo;
980 }
981 }
982}
983
959void sgGamma(swgfx* gfx, sgPixel* pixels, int width, int height) { 984void sgGamma(swgfx* gfx, sgPixel* pixels, int width, int height) {
960 assert(gfx); 985 assert(gfx);
961 assert(pixels); 986 assert(pixels);
@@ -968,19 +993,7 @@ void sgGammaInv(swgfx* gfx, sgPixel* pixels, int width, int height) {
968 ImageExp(pixels, width, height, 1.0f/2.2f); 993 ImageExp(pixels, width, height, 1.0f/2.2f);
969} 994}
970 995
971static bool ViewportWithinBuffer(swgfx* gfx) {
972 assert(gfx);
973 const sgViewport_t vp = gfx->viewport;
974 return ((vp.x0 + vp.width) <= gfx->dims.x) &&
975 ((vp.y0 + vp.height) <= gfx->dims.y);
976}
977
978sgCounters sgGetCounters(const swgfx* gfx) { 996sgCounters sgGetCounters(const swgfx* gfx) {
979 assert(gfx); 997 assert(gfx);
980 return gfx->counters; 998 return gfx->counters;
981} 999}
982
983void sgCheck(swgfx* gfx) {
984 assert(gfx);
985 assert(ViewportWithinBuffer(gfx));
986}