diff options
| author | 3gg <3gg@shellblade.net> | 2026-02-13 14:21:37 -0800 |
|---|---|---|
| committer | 3gg <3gg@shellblade.net> | 2026-02-13 14:21:37 -0800 |
| commit | b0544549c551dfa0b52e7c685580f954861240ba (patch) | |
| tree | 707de822e484eb14ebc0b3fad23e1d79ce26e305 | |
| parent | 77f9dbee1721518e09f0beed10b3dbb78d893b08 (diff) | |
Emit normals
| -rw-r--r-- | include/swgfx.h | 12 | ||||
| -rw-r--r-- | src/swgfx.c | 100 |
2 files changed, 83 insertions, 29 deletions
diff --git a/include/swgfx.h b/include/swgfx.h index b3f9150..452847c 100644 --- a/include/swgfx.h +++ b/include/swgfx.h | |||
| @@ -37,8 +37,8 @@ typedef sgVec3 sgNormal; | |||
| 37 | 37 | ||
| 38 | typedef struct sgVert2i { sgVec2i pos; sgVec2 uv; } sgVert2i; | 38 | typedef struct sgVert2i { sgVec2i pos; sgVec2 uv; } sgVert2i; |
| 39 | typedef struct sgVert2 { sgVec2 pos; sgVec2 uv; } sgVert2; | 39 | typedef struct sgVert2 { sgVec2 pos; sgVec2 uv; } sgVert2; |
| 40 | typedef struct sgVert3 { sgVec3 pos; sgVec2 uv; } sgVert3; | 40 | typedef struct sgVert3 { sgVec3 pos; sgVec2 uv; sgVec3 normal; } sgVert3; |
| 41 | typedef struct sgVert4 { sgVec4 pos; sgVec2 uv; } sgVert4; | 41 | typedef struct sgVert4 { sgVec4 pos; sgVec2 uv; sgVec3 normal; } sgVert4; |
| 42 | 42 | ||
| 43 | typedef struct sgQuadi { sgVert2i p0, p1; } sgQuadi; | 43 | typedef struct sgQuadi { sgVert2i p0, p1; } sgQuadi; |
| 44 | typedef struct sgQuad { sgVert2 p0, p1; } sgQuad; | 44 | typedef struct sgQuad { sgVert2 p0, p1; } sgQuad; |
| @@ -108,11 +108,15 @@ void sgTriangles2 (swgfx*, size_t count, const sgTri2*); | |||
| 108 | void sgTriangleStrip2(swgfx*, size_t count, const sgVec2*); | 108 | void sgTriangleStrip2(swgfx*, size_t count, const sgVec2*); |
| 109 | void sgTriangles (swgfx*, size_t count, const sgTri3*, const sgNormal*); | 109 | void sgTriangles (swgfx*, size_t count, const sgTri3*, const sgNormal*); |
| 110 | void sgTriangleStrip (swgfx*, size_t count, const sgVec3*, const sgNormal*); | 110 | void sgTriangleStrip (swgfx*, size_t count, const sgVec3*, const sgNormal*); |
| 111 | void sgTrianglesIndexed(swgfx*, size_t numIndices, const sgIdx* indices, const sgVec3* positions, const sgVec2* texcoords); | 111 | void sgTrianglesIndexed(swgfx*, size_t numIndices, const sgIdx* indices, const sgVec3* positions, const sgVec2* texcoords, const sgVec3* normals); |
| 112 | void sgTrianglesIndexedNonUniform(swgfx*, size_t numTris, const sgTriIdx* tris, const sgVec3* positions, const sgVec2* texcoords); | 112 | void sgTrianglesIndexedNonUniform(swgfx*, size_t numTris, const sgTriIdx* tris, const sgVec3* positions, const sgVec2* texcoords, const sgVec3* normals); |
| 113 | 113 | ||
| 114 | void sgLighting(swgfx*); | 114 | void sgLighting(swgfx*); |
| 115 | void sgAmbient(swgfx*, sgVec3 ambient); | 115 | void sgAmbient(swgfx*, sgVec3 ambient); |
| 116 | // TODO: Implement directional lights. | ||
| 117 | |||
| 118 | void sgDepth(swgfx*); | ||
| 119 | void sgNormals(swgfx*); | ||
| 116 | 120 | ||
| 117 | void sgGamma (swgfx*, sgPixel*, int width, int height); | 121 | void sgGamma (swgfx*, sgPixel*, int width, int height); |
| 118 | void sgGammaInv(swgfx*, sgPixel*, int width, int height); | 122 | void sgGammaInv(swgfx*, sgPixel*, int width, int height); |
diff --git a/src/swgfx.c b/src/swgfx.c index ddd64f7..6074eac 100644 --- a/src/swgfx.c +++ b/src/swgfx.c | |||
| @@ -24,7 +24,8 @@ static constexpr size_t SWGFX_TEXTURE_REGISTER_SIZE = SWGFX_MAX_TEXTURES + 1; | |||
| 24 | 24 | ||
| 25 | static constexpr R DepthClearValue = 1.0f; | 25 | static constexpr R DepthClearValue = 1.0f; |
| 26 | 26 | ||
| 27 | static constexpr sgVec3 Up3 = (sgVec3){0,1,0}; | 27 | static constexpr sgVec3 Up3 = (sgVec3){0,1,0}; |
| 28 | static constexpr sgVec3 Zero3 = (sgVec3){0,0,0}; | ||
| 28 | 29 | ||
| 29 | typedef struct sgViewport_t { int x0, y0, width, height; } sgViewport_t; | 30 | typedef struct sgViewport_t { int x0, y0, width, height; } sgViewport_t; |
| 30 | typedef struct sgAABB2 { sgVec2 pmin, pmax; } sgAABB2; | 31 | typedef struct sgAABB2 { sgVec2 pmin, pmax; } sgAABB2; |
| @@ -46,6 +47,7 @@ typedef struct swgfx { | |||
| 46 | sgTextureId* texture; // Texture ID buffer. | 47 | sgTextureId* texture; // Texture ID buffer. |
| 47 | sgVec2* texcoords; // Texture coords buffer. | 48 | sgVec2* texcoords; // Texture coords buffer. |
| 48 | sgPixel* albedo; // Albedo buffer. | 49 | sgPixel* albedo; // Albedo buffer. |
| 50 | sgVec3* normals; // Normals buffer. | ||
| 49 | sgViewport_t viewport; | 51 | sgViewport_t viewport; |
| 50 | sgMat4 model; // Model matrix. | 52 | sgMat4 model; // Model matrix. |
| 51 | sgMat4 view; // View matrix. | 53 | sgMat4 view; // View matrix. |
| @@ -87,12 +89,14 @@ static inline sgVec2 frac2(sgVec2 v) { return (sgVec2){frac(v.x), frac(v.y)}; } | |||
| 87 | static inline sgVec2 lerp2(sgVec2 a, sgVec2 b, R t) { return add2(a, scale2(sub2(b,a), t)); } | 89 | static inline sgVec2 lerp2(sgVec2 a, sgVec2 b, R t) { return add2(a, scale2(sub2(b,a), t)); } |
| 88 | static inline sgVec2 mod2(sgVec2 v, R m) { return (sgVec2){mod1(v.x, m), mod1(v.y, m)}; } | 90 | static inline sgVec2 mod2(sgVec2 v, R m) { return (sgVec2){mod1(v.x, m), mod1(v.y, m)}; } |
| 89 | 91 | ||
| 92 | static inline sgVec3 max3(sgVec3 a, sgVec3 b) { return (sgVec3){fmaxf(a.x, b.x), fmaxf(a.y, b.y), fmaxf(a.z, b.z)}; } | ||
| 90 | static inline sgVec3 add3(sgVec3 a, sgVec3 b) { return (sgVec3){a.x + b.x, a.y + b.y, a.z + b.z}; } | 93 | static inline sgVec3 add3(sgVec3 a, sgVec3 b) { return (sgVec3){a.x + b.x, a.y + b.y, a.z + b.z}; } |
| 91 | static inline sgVec3 neg3(sgVec3 v) { return (sgVec3){-v.x, -v.y, -v.z}; } | 94 | static inline sgVec3 neg3(sgVec3 v) { return (sgVec3){-v.x, -v.y, -v.z}; } |
| 92 | static inline sgVec3 sub3(sgVec3 a, sgVec3 b) { return (sgVec3){a.x - b.x, a.y - b.y, a.z - b.z}; } | 95 | static inline sgVec3 sub3(sgVec3 a, sgVec3 b) { return (sgVec3){a.x - b.x, a.y - b.y, a.z - b.z}; } |
| 93 | static inline sgVec3 mul3(sgVec3 a, sgVec3 b) { return (sgVec3){a.x * b.x, a.y * b.y, a.z * b.z}; } | 96 | static inline sgVec3 mul3(sgVec3 a, sgVec3 b) { return (sgVec3){a.x * b.x, a.y * b.y, a.z * b.z}; } |
| 94 | static inline sgVec3 div3(sgVec3 a, sgVec3 b) { return (sgVec3){a.x / b.x, a.y / b.y, a.z / b.z}; } | 97 | static inline sgVec3 div3(sgVec3 a, sgVec3 b) { return (sgVec3){a.x / b.x, a.y / b.y, a.z / b.z}; } |
| 95 | static inline sgVec3 scale3(sgVec3 v, R s) { return (sgVec3){v.x * s, v.y * s, v.z * s}; } | 98 | static inline sgVec3 scale3(sgVec3 v, R s) { return (sgVec3){v.x * s, v.y * s, v.z * s}; } |
| 99 | static inline sgVec3 lerp3(sgVec3 a, sgVec3 b, R t) { return add3(a, scale3(sub3(b,a), t)); } | ||
| 96 | static inline sgVec3 exp3(sgVec3 v, R exp) { return (sgVec3){powf(v.x, exp), powf(v.y, exp), powf(v.z, exp)};} | 100 | static inline sgVec3 exp3(sgVec3 v, R exp) { return (sgVec3){powf(v.x, exp), powf(v.y, exp), powf(v.z, exp)};} |
| 97 | static inline R dot3(sgVec3 a, sgVec3 b) { return a.x * b.x + a.y * b.y + a.z * b.z; } | 101 | static inline R dot3(sgVec3 a, sgVec3 b) { return a.x * b.x + a.y * b.y + a.z * b.z; } |
| 98 | static inline R normsq3(sgVec3 v) { return v.x * v.x + v.y * v.y + v.z * v.z; } | 102 | static inline R normsq3(sgVec3 v) { return v.x * v.x + v.y * v.y + v.z * v.z; } |
| @@ -326,11 +330,13 @@ static inline void SetPixelColour(swgfx* gfx, const sgVec2i p, sgPixel colour) { | |||
| 326 | #endif // SWGFX_PROFILING | 330 | #endif // SWGFX_PROFILING |
| 327 | } | 331 | } |
| 328 | 332 | ||
| 329 | static inline void SetPixelDeferred(swgfx* gfx, const sgVec2i p, R depth, sgTextureId texid, sgVec2 uv) { | 333 | static inline void SetPixelDeferred(swgfx* gfx, const sgVec2i p, R depth, sgTextureId texid, sgVec2 uv, sgVec3 normal) { |
| 330 | assert(gfx); | 334 | assert(gfx); |
| 331 | gfx->depth[(p.y * gfx->dims.x) + p.x] = depth; | 335 | const int i = (p.y * gfx->dims.x) + p.x; |
| 332 | gfx->texture[(p.y * gfx->dims.x) + p.x] = texid; | 336 | gfx->depth[i] = depth; |
| 333 | gfx->texcoords[(p.y * gfx->dims.x) + p.x] = uv; | 337 | gfx->texture[i] = texid; |
| 338 | gfx->texcoords[i] = uv; | ||
| 339 | gfx->normals[i] = normalize3(normal); // Non-unit after interpolation. | ||
| 334 | #if SWGFX_PROFILING | 340 | #if SWGFX_PROFILING |
| 335 | gfx->counters.pixels++; | 341 | gfx->counters.pixels++; |
| 336 | #endif // SWGFX_PROFILING | 342 | #endif // SWGFX_PROFILING |
| @@ -514,7 +520,7 @@ static inline R IntersectSegmentPlane(R near, const sgVec3* const a, const sgVec | |||
| 514 | return t; | 520 | return t; |
| 515 | } | 521 | } |
| 516 | 522 | ||
| 517 | /// Interpolate depth and vertex attributes at the in/out vertex 'out'. | 523 | /// Interpolate vertex attributes at the in/out vertex 'out'. |
| 518 | static void InterpolateAttributes(const sgVert4* const a, const sgVert4* const b, R t, sgVert4* out) { | 524 | static void InterpolateAttributes(const sgVert4* const a, const sgVert4* const b, R t, sgVert4* out) { |
| 519 | assert(a); | 525 | assert(a); |
| 520 | assert(b); | 526 | assert(b); |
| @@ -522,8 +528,9 @@ static void InterpolateAttributes(const sgVert4* const a, const sgVert4* const b | |||
| 522 | assert(t >= 0.f); | 528 | assert(t >= 0.f); |
| 523 | assert(t <= 1.f); | 529 | assert(t <= 1.f); |
| 524 | const sgVec4 d = sub4(b->pos, a->pos); // Line direction. | 530 | const sgVec4 d = sub4(b->pos, a->pos); // Line direction. |
| 525 | out->pos = add4(a->pos, scale4(d, t)); | 531 | out->pos = add4(a->pos, scale4(d, t)); |
| 526 | out->uv = lerp2(a->uv, b->uv, t); | 532 | out->uv = lerp2(a->uv, b->uv, t); |
| 533 | out->normal = lerp3(a->normal, b->normal, t); | ||
| 527 | } | 534 | } |
| 528 | 535 | ||
| 529 | /// Clip a triangle, vertices in clip space. Return the number of output | 536 | /// Clip a triangle, vertices in clip space. Return the number of output |
| @@ -597,10 +604,18 @@ static inline int TransformTri(const swgfx* gfx, const sgTri3* const tri, sgTri4 | |||
| 597 | const sgVec4 p0_clip = Mat4MulVec4(gfx->mvp, Vec4FromVec3(tri->p0.pos, 1)); | 604 | const sgVec4 p0_clip = Mat4MulVec4(gfx->mvp, Vec4FromVec3(tri->p0.pos, 1)); |
| 598 | const sgVec4 p1_clip = Mat4MulVec4(gfx->mvp, Vec4FromVec3(tri->p1.pos, 1)); | 605 | const sgVec4 p1_clip = Mat4MulVec4(gfx->mvp, Vec4FromVec3(tri->p1.pos, 1)); |
| 599 | const sgVec4 p2_clip = Mat4MulVec4(gfx->mvp, Vec4FromVec3(tri->p2.pos, 1)); | 606 | const sgVec4 p2_clip = Mat4MulVec4(gfx->mvp, Vec4FromVec3(tri->p2.pos, 1)); |
| 607 | // Model to world space for normals. | ||
| 608 | // This assumes the model matrix does not have non-uniform scaling. | ||
| 609 | // It seems more convenient to put the normals in world space instead of view | ||
| 610 | // space right now so that we don't have to transform lights to view space | ||
| 611 | // when lighting. But we might want to revisit this later. | ||
| 612 | const sgVec3 n0_view = Mat4MulVec3(gfx->model, tri->p0.normal, 0.f); | ||
| 613 | const sgVec3 n1_view = Mat4MulVec3(gfx->model, tri->p1.normal, 0.f); | ||
| 614 | const sgVec3 n2_view = Mat4MulVec3(gfx->model, tri->p2.normal, 0.f); | ||
| 600 | const sgTri4 tri_clip = { | 615 | const sgTri4 tri_clip = { |
| 601 | (sgVert4){ p0_clip, tri->p0.uv }, | 616 | (sgVert4){ p0_clip, tri->p0.uv, n0_view }, |
| 602 | (sgVert4){ p1_clip, tri->p1.uv }, | 617 | (sgVert4){ p1_clip, tri->p1.uv, n1_view }, |
| 603 | (sgVert4){ p2_clip, tri->p2.uv }}; | 618 | (sgVert4){ p2_clip, tri->p2.uv, n2_view }}; |
| 604 | // Clip. | 619 | // Clip. |
| 605 | // Our perspective matrix maps the near plane to z=-1 in clip space. | 620 | // Our perspective matrix maps the near plane to z=-1 in clip space. |
| 606 | constexpr R near_clip = -1.f; | 621 | constexpr R near_clip = -1.f; |
| @@ -673,20 +688,22 @@ static void DrawTriangle3PostClip(swgfx* gfx, const sgTri4* const tri) { | |||
| 673 | if ((bar.x >= 0) && (bar.y >= 0) && (bar.z >= 0)) { | 688 | if ((bar.x >= 0) && (bar.y >= 0) && (bar.z >= 0)) { |
| 674 | assert((bar.x + bar.y + bar.z - 1e7) <= 1.f); | 689 | assert((bar.x + bar.y + bar.z - 1e7) <= 1.f); |
| 675 | const R p_one_over_z = dot3(bar, one_over_zs); | 690 | const R p_one_over_z = dot3(bar, one_over_zs); |
| 676 | const R p_u_over_z = dot3(bar, u_over_zs); | ||
| 677 | const R p_v_over_z = dot3(bar, v_over_zs); | ||
| 678 | const R p_depth = dot3(bar, depths); | 691 | const R p_depth = dot3(bar, depths); |
| 679 | const R z = 1.f / p_one_over_z; | 692 | const R z = 1.f / p_one_over_z; |
| 680 | const sgVec2 uv = (sgVec2){p_u_over_z * z, p_v_over_z * z}; | ||
| 681 | const R* depth = Depth(gfx, x, y); | 693 | const R* depth = Depth(gfx, x, y); |
| 682 | if ((0.f <= p_depth) && (p_depth <= 1.f) && (p_depth <= *depth)) { | 694 | if ((0.f <= p_depth) && (p_depth <= 1.f) && (p_depth <= *depth)) { |
| 683 | // TODO: When doing lighting, need to tone-map here and apply inverse | 695 | const R p_u_over_z = dot3(bar, u_over_zs); |
| 684 | // gamma here. | 696 | const R p_v_over_z = dot3(bar, v_over_zs); |
| 697 | const sgVec2 uv = (sgVec2){p_u_over_z * z, p_v_over_z * z}; | ||
| 698 | const sgVec3 n0 = scale3(tri->p0.normal, bar.x * one_over_zs.x); | ||
| 699 | const sgVec3 n1 = scale3(tri->p1.normal, bar.y * one_over_zs.y); | ||
| 700 | const sgVec3 n2 = scale3(tri->p2.normal, bar.z * one_over_zs.z); | ||
| 701 | const sgVec3 normal = add3(add3(n0,n1),n2); | ||
| 685 | //const sgPixel colour = {(uint8_t)(bar.x*255.f), (uint8_t)(bar.y*255.f), (uint8_t)(bar.z*255.f), 255}; | 702 | //const sgPixel colour = {(uint8_t)(bar.x*255.f), (uint8_t)(bar.y*255.f), (uint8_t)(bar.z*255.f), 255}; |
| 686 | //const sgPixel colour = {(int)(z*255.f), (int)(z*255.f), (int)(z*255.f), 255}; | 703 | //const sgPixel colour = {(int)(z*255.f), (int)(z*255.f), (int)(z*255.f), 255}; |
| 687 | //const sgPixel colour = {255, 0, 255, 255}; | 704 | //const sgPixel colour = {255, 0, 255, 255}; |
| 688 | //const sgPixel colour = {(int)(uv.x * 255.f), (int)(uv.y * 255.f), 255, 255}; | 705 | //const sgPixel colour = {(int)(uv.x * 255.f), (int)(uv.y * 255.f), 255, 255}; |
| 689 | SetPixelDeferred(gfx, (sgVec2i){x,y}, p_depth, gfx->activeTexture, uv); | 706 | SetPixelDeferred(gfx, (sgVec2i){x,y}, p_depth, gfx->activeTexture, uv, normal); |
| 690 | } | 707 | } |
| 691 | } | 708 | } |
| 692 | } | 709 | } |
| @@ -742,6 +759,7 @@ size_t sgMem(int width, int height) { | |||
| 742 | Align(N * sizeof(sgTextureId)) + // Texture ID buffer. | 759 | Align(N * sizeof(sgTextureId)) + // Texture ID buffer. |
| 743 | Align(N * sizeof(sgVec2)) + // Texture coords buffer. | 760 | Align(N * sizeof(sgVec2)) + // Texture coords buffer. |
| 744 | Align(N * sizeof(sgPixel)) + // Albedo buffer. | 761 | Align(N * sizeof(sgPixel)) + // Albedo buffer. |
| 762 | Align(N * sizeof(sgVec3)) + // Normals buffer. | ||
| 745 | Align(SWGFX_TEXTURE_REGISTER_SIZE * sizeof(sgTexture)) + // Texture register. | 763 | Align(SWGFX_TEXTURE_REGISTER_SIZE * sizeof(sgTexture)) + // Texture register. |
| 746 | (SG_ALIGN - 1); // To make room to align allocations within the buffer. | 764 | (SG_ALIGN - 1); // To make room to align allocations within the buffer. |
| 747 | } | 765 | } |
| @@ -756,6 +774,7 @@ swgfx* sgNew(int width, int height, void* mem) { | |||
| 756 | gfx->texture = SG_ALLOC(&aligned, N, sgTextureId); | 774 | gfx->texture = SG_ALLOC(&aligned, N, sgTextureId); |
| 757 | gfx->texcoords = SG_ALLOC(&aligned, N, sgVec2); | 775 | gfx->texcoords = SG_ALLOC(&aligned, N, sgVec2); |
| 758 | gfx->albedo = SG_ALLOC(&aligned, N, sgPixel); | 776 | gfx->albedo = SG_ALLOC(&aligned, N, sgPixel); |
| 777 | gfx->normals = SG_ALLOC(&aligned, N, sgVec3); | ||
| 759 | gfx->textureRegister = SG_ALLOC(&aligned, SWGFX_TEXTURE_REGISTER_SIZE, sgTexture); | 778 | gfx->textureRegister = SG_ALLOC(&aligned, SWGFX_TEXTURE_REGISTER_SIZE, sgTexture); |
| 760 | gfx->activeTexture = DefaultTextureId; | 779 | gfx->activeTexture = DefaultTextureId; |
| 761 | gfx->defaultPixel = (sgPixel){255, 255, 255, 255}; | 780 | gfx->defaultPixel = (sgPixel){255, 255, 255, 255}; |
| @@ -922,11 +941,12 @@ void sgTriangles(swgfx* gfx, size_t count, const sgTri3* tris, const sgNormal*) | |||
| 922 | } | 941 | } |
| 923 | } | 942 | } |
| 924 | 943 | ||
| 925 | void sgTrianglesIndexed(swgfx* gfx, size_t numIndices, const sgIdx* indices, const sgVec3* positions, const sgVec2* texcoords) { | 944 | void sgTrianglesIndexed(swgfx* gfx, size_t numIndices, const sgIdx* indices, const sgVec3* positions, const sgVec2* texcoords, const sgVec3* normals) { |
| 926 | assert(gfx); | 945 | assert(gfx); |
| 927 | assert(indices); | 946 | assert(indices); |
| 928 | assert(positions); | 947 | assert(positions); |
| 929 | assert(texcoords); | 948 | assert(texcoords); |
| 949 | assert(normals); | ||
| 930 | for (size_t i = 0; i < numIndices; i+=3) { | 950 | for (size_t i = 0; i < numIndices; i+=3) { |
| 931 | const sgIdx i0 = indices[i]; | 951 | const sgIdx i0 = indices[i]; |
| 932 | const sgIdx i1 = indices[i+1]; | 952 | const sgIdx i1 = indices[i+1]; |
| @@ -937,25 +957,29 @@ void sgTrianglesIndexed(swgfx* gfx, size_t numIndices, const sgIdx* indices, con | |||
| 937 | const sgVec2 uv0 = texcoords[i0]; | 957 | const sgVec2 uv0 = texcoords[i0]; |
| 938 | const sgVec2 uv1 = texcoords[i1]; | 958 | const sgVec2 uv1 = texcoords[i1]; |
| 939 | const sgVec2 uv2 = texcoords[i2]; | 959 | const sgVec2 uv2 = texcoords[i2]; |
| 960 | const sgVec3 n0 = normals[i0]; | ||
| 961 | const sgVec3 n1 = normals[i1]; | ||
| 962 | const sgVec3 n2 = normals[i2]; | ||
| 940 | const sgTri3 tri = (sgTri3){ | 963 | const sgTri3 tri = (sgTri3){ |
| 941 | (sgVert3){p0, uv0}, | 964 | (sgVert3){p0, uv0, n0}, |
| 942 | (sgVert3){p1, uv1}, | 965 | (sgVert3){p1, uv1, n1}, |
| 943 | (sgVert3){p2, uv2}}; | 966 | (sgVert3){p2, uv2, n2}}; |
| 944 | DrawTriangle3(gfx, &tri); | 967 | DrawTriangle3(gfx, &tri); |
| 945 | } | 968 | } |
| 946 | } | 969 | } |
| 947 | 970 | ||
| 948 | void sgTrianglesIndexedNonUniform(swgfx* gfx, size_t numTris, const sgTriIdx* tris, const sgVec3* positions, const sgVec2* texcoords) { | 971 | void sgTrianglesIndexedNonUniform(swgfx* gfx, size_t numTris, const sgTriIdx* tris, const sgVec3* positions, const sgVec2* texcoords, const sgVec3* normals) { |
| 949 | assert(gfx); | 972 | assert(gfx); |
| 950 | assert(tris); | 973 | assert(tris); |
| 951 | assert(positions); | 974 | assert(positions); |
| 952 | assert(texcoords); | 975 | assert(texcoords); |
| 976 | assert(normals); | ||
| 953 | for (size_t t = 0; t < numTris; ++t) { | 977 | for (size_t t = 0; t < numTris; ++t) { |
| 954 | const sgTriIdx* triIdx = &tris[t]; | 978 | const sgTriIdx* triIdx = &tris[t]; |
| 955 | const sgTri3 tri = (sgTri3){ | 979 | const sgTri3 tri = (sgTri3){ |
| 956 | (sgVert3){positions[triIdx->v0.pos], texcoords[triIdx->v0.uv]}, | 980 | (sgVert3){positions[triIdx->v0.pos], texcoords[triIdx->v0.uv], normals[triIdx->v0.normal]}, |
| 957 | (sgVert3){positions[triIdx->v1.pos], texcoords[triIdx->v1.uv]}, | 981 | (sgVert3){positions[triIdx->v1.pos], texcoords[triIdx->v1.uv], normals[triIdx->v1.normal]}, |
| 958 | (sgVert3){positions[triIdx->v2.pos], texcoords[triIdx->v2.uv]}}; | 982 | (sgVert3){positions[triIdx->v2.pos], texcoords[triIdx->v2.uv], normals[triIdx->v2.normal]}}; |
| 959 | DrawTriangle3(gfx, &tri); | 983 | DrawTriangle3(gfx, &tri); |
| 960 | } | 984 | } |
| 961 | } | 985 | } |
| @@ -996,6 +1020,32 @@ void sgAmbient(swgfx* gfx, sgVec3 ambient) { | |||
| 996 | } | 1020 | } |
| 997 | } | 1021 | } |
| 998 | 1022 | ||
| 1023 | void sgDepth(swgfx* gfx) { | ||
| 1024 | assert(gfx); | ||
| 1025 | const int N = gfx->dims.x * gfx->dims.y; | ||
| 1026 | for (int i = 0; i < N; ++i) { | ||
| 1027 | const R depth = gfx->depth[i]; | ||
| 1028 | if (depth != DepthClearValue) { | ||
| 1029 | sgPixel* colour = &gfx->colour[i]; | ||
| 1030 | const R d = gfx->depth[i]; | ||
| 1031 | *colour = Vec3ToPixel((sgVec3){d,d,d}, 1.f); | ||
| 1032 | } | ||
| 1033 | } | ||
| 1034 | } | ||
| 1035 | |||
| 1036 | void sgNormals(swgfx* gfx) { | ||
| 1037 | assert(gfx); | ||
| 1038 | const int N = gfx->dims.x * gfx->dims.y; | ||
| 1039 | for (int i = 0; i < N; ++i) { | ||
| 1040 | const R depth = gfx->depth[i]; | ||
| 1041 | if (depth != DepthClearValue) { | ||
| 1042 | sgPixel* colour = &gfx->colour[i]; | ||
| 1043 | const sgVec3* normal = &gfx->normals[i]; | ||
| 1044 | *colour = Vec3ToPixel(max3(Zero3, *normal), 1.f); | ||
| 1045 | } | ||
| 1046 | } | ||
| 1047 | } | ||
| 1048 | |||
| 999 | void sgGamma(swgfx* gfx, sgPixel* pixels, int width, int height) { | 1049 | void sgGamma(swgfx* gfx, sgPixel* pixels, int width, int height) { |
| 1000 | assert(gfx); | 1050 | assert(gfx); |
| 1001 | assert(pixels); | 1051 | assert(pixels); |
