diff options
| -rw-r--r-- | include/swgfx.h | 7 | ||||
| -rw-r--r-- | src/swgfx.c | 28 |
2 files changed, 22 insertions, 13 deletions
diff --git a/include/swgfx.h b/include/swgfx.h index cdeefe8..e9e69b8 100644 --- a/include/swgfx.h +++ b/include/swgfx.h | |||
| @@ -53,6 +53,11 @@ typedef sgRgba sgPixel; | |||
| 53 | // TODO: Expose a macro to control the desired surface format. | 53 | // TODO: Expose a macro to control the desired surface format. |
| 54 | typedef sgBgra sgScreenPixel; | 54 | typedef sgBgra sgScreenPixel; |
| 55 | 55 | ||
| 56 | typedef enum sgTextureFilter { | ||
| 57 | sgNearest, | ||
| 58 | sgBilinear | ||
| 59 | } sgTextureFilter; | ||
| 60 | |||
| 56 | typedef struct sgImage { | 61 | typedef struct sgImage { |
| 57 | int width; | 62 | int width; |
| 58 | int height; | 63 | int height; |
| @@ -76,7 +81,7 @@ void sgOrtho (swgfx*, R left, R right, R top, R bottom, R near, R far); | |||
| 76 | void sgPerspective(swgfx*, R fovy, R aspect, R near, R far); | 81 | void sgPerspective(swgfx*, R fovy, R aspect, R near, R far); |
| 77 | void sgViewport (swgfx*, int x0, int y0, int width, int height); | 82 | void sgViewport (swgfx*, int x0, int y0, int width, int height); |
| 78 | 83 | ||
| 79 | void sgTexture(swgfx*, const sgImage*); | 84 | void sgTexture(swgfx*, const sgImage*, sgTextureFilter); |
| 80 | 85 | ||
| 81 | void sgClear(swgfx*); | 86 | void sgClear(swgfx*); |
| 82 | void sgPixels(swgfx*, size_t count, const sgVec2i* positions, sgPixel colour); | 87 | void sgPixels(swgfx*, size_t count, const sgVec2i* positions, sgPixel colour); |
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) { |
