diff options
| author | 3gg <3gg@shellblade.net> | 2026-02-05 17:16:39 -0800 |
|---|---|---|
| committer | 3gg <3gg@shellblade.net> | 2026-02-05 17:16:39 -0800 |
| commit | d44df852bbdcb58d634413d69eaa288a7b4573f3 (patch) | |
| tree | cdf00d21aea252d379129e957cc29e5b48ac76b1 /src | |
| parent | 9e5db7c33df67d80f49f4efd7b8ace5f27e2e7cb (diff) | |
Expose texture filter.
Diffstat (limited to 'src')
| -rw-r--r-- | src/swgfx.c | 28 |
1 files changed, 16 insertions, 12 deletions
diff --git a/src/swgfx.c b/src/swgfx.c index 85844e0..153a5f4 100644 --- a/src/swgfx.c +++ b/src/swgfx.c | |||
| @@ -44,11 +44,12 @@ typedef struct swgfx { | |||
| 44 | // Make it so that changing the model matrix only requires one matrix | 44 | // Make it so that changing the model matrix only requires one matrix |
| 45 | // multiplication (mvp = model * viewProj) and not two (mvp = model * view * projection) | 45 | // multiplication (mvp = model * viewProj) and not two (mvp = model * view * projection) |
| 46 | // before rendering the model's triangles. | 46 | // before rendering the model's triangles. |
| 47 | sgMat4 viewProj; // View-projection matrix. | 47 | sgMat4 viewProj; // View-projection matrix. |
| 48 | sgMat4 mvp; // Model-view-projection matrix. | 48 | sgMat4 mvp; // Model-view-projection matrix. |
| 49 | const sgImage* texture; // User-specified texture. | 49 | const sgImage* texture; // User-specified texture. |
| 50 | sgImage defaultTexture; // A default for when no texture is provided. | 50 | sgTextureFilter textureFilter; // Filter method for the texture. |
| 51 | sgPixel defaultPixel; // The single-pixel of the default texture. | 51 | sgImage defaultTexture; // A default for when no texture is provided. |
| 52 | sgPixel defaultPixel; // The single-pixel of the default texture. | ||
| 52 | } swgfx; | 53 | } swgfx; |
| 53 | 54 | ||
| 54 | static inline int mod(int a, int m) { return (m + (a % m)) % m; } | 55 | static inline int mod(int a, int m) { return (m + (a % m)) % m; } |
| @@ -359,10 +360,12 @@ static inline sgPixel FilterBilinear(const sgImage* texture, sgVec2 uv) { | |||
| 359 | 360 | ||
| 360 | // TODO: Mipmapping. | 361 | // TODO: Mipmapping. |
| 361 | // TODO: Clamping and other addressing strategies. | 362 | // TODO: Clamping and other addressing strategies. |
| 362 | static inline sgPixel Sample(const sgImage* texture, sgVec2 uv) { | 363 | static inline sgPixel Sample(const sgImage* texture, sgTextureFilter filter, sgVec2 uv) { |
| 363 | // TODO: Add a member to sgImage that determines how it should be filtered. | 364 | switch (filter) { |
| 364 | //return FilterNearest(texture, uv); | 365 | case sgNearest: return FilterNearest(texture, uv); |
| 365 | return FilterBilinear(texture, uv); | 366 | case sgBilinear: return FilterBilinear(texture, uv); |
| 367 | default: assert(false); return (sgPixel){0}; | ||
| 368 | } | ||
| 366 | } | 369 | } |
| 367 | 370 | ||
| 368 | static inline sgAABB2 TriangleAabb2(sgVec2 p0, sgVec2 p1, sgVec2 p2) { | 371 | static inline sgAABB2 TriangleAabb2(sgVec2 p0, sgVec2 p1, sgVec2 p2) { |
| @@ -433,7 +436,7 @@ static void DrawTriangle2(swgfx* gfx, const sgTri2* const tri) { | |||
| 433 | if ((bar.x >= 0) && (bar.y >= 0) && (bar.z >= 0)) { | 436 | if ((bar.x >= 0) && (bar.y >= 0) && (bar.z >= 0)) { |
| 434 | assert((bar.x + bar.y + bar.z - 1e7) <= 1.f); | 437 | assert((bar.x + bar.y + bar.z - 1e7) <= 1.f); |
| 435 | const sgVec2 uv = BarycentricInterp2(bar, tri->p0.uv, tri->p1.uv, tri->p2.uv); | 438 | const sgVec2 uv = BarycentricInterp2(bar, tri->p0.uv, tri->p1.uv, tri->p2.uv); |
| 436 | const sgPixel colour = Sample(gfx->texture, uv); | 439 | const sgPixel colour = Sample(gfx->texture, gfx->textureFilter, uv); |
| 437 | SetPixel(gfx, (sgVec2i){x,y}, colour); | 440 | SetPixel(gfx, (sgVec2i){x,y}, colour); |
| 438 | } | 441 | } |
| 439 | } | 442 | } |
| @@ -644,7 +647,7 @@ static void DrawTriangle3PostClip(swgfx* gfx, const sgTri4* const tri) { | |||
| 644 | R* depth = Depth(gfx, x, y); | 647 | R* depth = Depth(gfx, x, y); |
| 645 | if ((0.f <= p_depth) && (p_depth <= 1.f) && (p_depth <= *depth)) { | 648 | if ((0.f <= p_depth) && (p_depth <= 1.f) && (p_depth <= *depth)) { |
| 646 | *depth = p_depth; | 649 | *depth = p_depth; |
| 647 | const sgPixel colour = Sample(gfx->texture, uv); | 650 | const sgPixel colour = Sample(gfx->texture, gfx->textureFilter, uv); |
| 648 | // TODO: When doing lighting, need to tone-map here and apply inverse | 651 | // TODO: When doing lighting, need to tone-map here and apply inverse |
| 649 | // gamma here. | 652 | // gamma here. |
| 650 | //const sgPixel colour = {(uint8_t)(bar.x*255.f), (uint8_t)(bar.y*255.f), (uint8_t)(bar.z*255.f), 255}; | 653 | //const sgPixel colour = {(uint8_t)(bar.x*255.f), (uint8_t)(bar.y*255.f), (uint8_t)(bar.z*255.f), 255}; |
| @@ -800,10 +803,11 @@ void sgViewport(swgfx* gfx, int x0, int y0, int width, int height) { | |||
| 800 | gfx->viewport = (sgViewport_t){x0, y0, width, height}; | 803 | gfx->viewport = (sgViewport_t){x0, y0, width, height}; |
| 801 | } | 804 | } |
| 802 | 805 | ||
| 803 | void sgTexture(swgfx* gfx, const sgImage* texture) { | 806 | void sgTexture(swgfx* gfx, const sgImage* texture, sgTextureFilter filter) { |
| 804 | assert(gfx); | 807 | assert(gfx); |
| 805 | assert(texture); | 808 | assert(texture); |
| 806 | gfx->texture = texture; | 809 | gfx->texture = texture; |
| 810 | gfx->textureFilter = filter; | ||
| 807 | } | 811 | } |
| 808 | 812 | ||
| 809 | void sgClear(swgfx* gfx) { | 813 | void sgClear(swgfx* gfx) { |
