summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/swgfx.h16
-rw-r--r--src/swgfx.c61
2 files changed, 63 insertions, 14 deletions
diff --git a/include/swgfx.h b/include/swgfx.h
index 970e3fa..4a98116 100644
--- a/include/swgfx.h
+++ b/include/swgfx.h
@@ -38,8 +38,18 @@ typedef uint16_t sgIdx;
38typedef struct sgVertIdx { sgIdx pos, uv, normal; } sgVertIdx; 38typedef struct sgVertIdx { sgIdx pos, uv, normal; } sgVertIdx;
39typedef struct sgTriIdx { sgVertIdx v0, v1, v2; } sgTriIdx; 39typedef struct sgTriIdx { sgVertIdx v0, v1, v2; } sgTriIdx;
40 40
41typedef struct sgBgra { uint8_t b, g, r, a; } sgBgra;
42typedef struct sgRgba { uint8_t r, g, b, a; } sgRgba;
41// TODO: Should we use real-valued colours? 43// TODO: Should we use real-valued colours?
42typedef struct sgPixel { uint8_t r, g, b, a; } sgPixel; 44typedef sgRgba sgPixel;
45// TODO: Expose a macro to control the desired surface format.
46typedef sgBgra sgScreenPixel;
47
48typedef struct sgTexture_t {
49 int width;
50 int height;
51 sgPixel* pixels;
52} sgTexture_t;
43 53
44typedef struct swgfx swgfx; 54typedef struct swgfx swgfx;
45 55
@@ -49,7 +59,7 @@ void sgDel(swgfx**);
49 59
50// TODO: Write client app first, then implement the functions below in the C file. 60// TODO: Write client app first, then implement the functions below in the C file.
51 61
52void sgPresent(swgfx*, sgVec2i dimensions, sgPixel* screen); 62void sgPresent(swgfx*, sgVec2i dimensions, sgScreenPixel* screen);
53 63
54void sgModelId (swgfx*); 64void sgModelId (swgfx*);
55void sgModel (swgfx*, sgVec3 position, sgVec3 right, sgVec3 up, sgVec3 forward); 65void sgModel (swgfx*, sgVec3 position, sgVec3 right, sgVec3 up, sgVec3 forward);
@@ -58,6 +68,8 @@ void sgOrtho (swgfx*, R left, R right, R top, R bottom, R near, R far);
58void sgPerspective(swgfx*, R fovy, R aspect, R near, R far); 68void sgPerspective(swgfx*, R fovy, R aspect, R near, R far);
59void sgViewport (swgfx*, int x0, int y0, int width, int height); 69void sgViewport (swgfx*, int x0, int y0, int width, int height);
60 70
71void sgTexture(swgfx*, const sgTexture_t*);
72
61void sgClear(swgfx*); 73void sgClear(swgfx*);
62void sgPixels(swgfx*, size_t count, const sgVec2i* positions, sgPixel colour); 74void sgPixels(swgfx*, size_t count, const sgVec2i* positions, sgPixel colour);
63void sgQuads (swgfx*, size_t count, const sgQuad*); 75void sgQuads (swgfx*, size_t count, const sgQuad*);
diff --git a/src/swgfx.c b/src/swgfx.c
index c298fb4..612f82d 100644
--- a/src/swgfx.c
+++ b/src/swgfx.c
@@ -46,6 +46,9 @@ typedef struct swgfx {
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 sgTexture_t* texture;// User-specified texture.
50 sgTexture_t defaultTexture; // A default for when no texture is provided.
51 sgPixel defaultPixel; // The single-pixel of the default texture.
49} swgfx; 52} swgfx;
50 53
51static inline R rmin(R a, R b) { return (a <= b) ? a : b; } 54static inline R rmin(R a, R b) { return (a <= b) ? a : b; }
@@ -265,6 +268,22 @@ void SetDepth(swgfx* gfx, const sgVec2i p, R depth) {
265 *Depth(gfx, p.x, p.y) = depth; 268 *Depth(gfx, p.x, p.y) = depth;
266} 269}
267 270
271// TODO: Mipmapping.
272sgPixel Sample(const sgTexture_t* texture, sgVec2 uv) {
273 assert(texture);
274 assert(texture->pixels);
275 // TODO: (1/2, 1/2) is the center of the pixel. Do we need to do something
276 // about it here?
277#define INDEX(X,Y) texture->pixels[(Y) * texture->width + (X)]
278 // Doing a nearest sample for now. TODO: Other sampling strategies.
279 const int x = (int)(uv.x * (R)texture->width);
280 const int y = (int)(uv.y * (R)texture->height);
281 // Repeat for now. TODO: Clamping and other strategies.
282 const int xx = x % texture->width;
283 const int yy = y % texture->height;
284 return INDEX(xx,yy);
285}
286
268static inline sgAABB2 TriangleAabb2(sgVec2 p0, sgVec2 p1, sgVec2 p2) { 287static inline sgAABB2 TriangleAabb2(sgVec2 p0, sgVec2 p1, sgVec2 p2) {
269 return (sgAABB2){.pmin = min2(min2(p0, p1), p2), 288 return (sgAABB2){.pmin = min2(min2(p0, p1), p2),
270 .pmax = max2(max2(p0, p1), p2)}; 289 .pmax = max2(max2(p0, p1), p2)};
@@ -340,12 +359,16 @@ static void DrawTriangle2(swgfx* gfx, const sgTri3* const tri) {
340 R* depth = Depth(gfx, x, y); 359 R* depth = Depth(gfx, x, y);
341 if ((0.f <= z) && (z <= 1.f) && (z <= *depth)) { 360 if ((0.f <= z) && (z <= 1.f) && (z <= *depth)) {
342 *depth = z; 361 *depth = z;
343 const sgVec3 depths = (sgVec3){tri->p0.pos.z, tri->p1.pos.z, tri->p2.pos.z}; 362 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); 363 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); 364 const sgPixel colour = Sample(gfx->texture, uv);
365 //const sgPixel colour = (sgPixel){255, 0, 255, 255};
366 // TODO: When doing lighting, need to tone-map here.
367 /*const int r = (int)(uv.x * 255.f);
346 const int g = (int)(uv.y * 255.f); 368 const int g = (int)(uv.y * 255.f);
347 const sgVec2i pix = (sgVec2i){(int)x, (int)y}; 369 const sgPixel colour = (sgPixel){r, g, 255, 255};*/
348 SetPixel(gfx, pix, (sgPixel){r, g, 255, 255}); 370 const sgVec2i pix = (sgVec2i){x,y};
371 SetPixel(gfx, pix, colour);
349 } 372 }
350 } 373 }
351 } 374 }
@@ -436,6 +459,12 @@ swgfx* sgNew(int width, int height, void* mem) {
436 gfx->dims = (sgVec2i){width, height}; 459 gfx->dims = (sgVec2i){width, height};
437 gfx->colour = SG_ALLOC(&aligned, width * height, sgPixel); 460 gfx->colour = SG_ALLOC(&aligned, width * height, sgPixel);
438 gfx->depth = SG_ALLOC(&aligned, width * height, R); 461 gfx->depth = SG_ALLOC(&aligned, width * height, R);
462 gfx->defaultPixel = (sgPixel){255, 255, 255, 255};
463 gfx->defaultTexture = (sgTexture_t){
464 .width = 1,
465 .height = 1,
466 .pixels = &gfx->defaultPixel,
467 };
439 return gfx; 468 return gfx;
440} 469}
441 470
@@ -446,7 +475,7 @@ void sgDel(swgfx** ppSwgfx) {
446 } 475 }
447} 476}
448 477
449void sgPresent(swgfx* gfx, sgVec2i dimensions, sgPixel* screen) { 478void sgPresent(swgfx* gfx, sgVec2i dimensions, sgScreenPixel* screen) {
450 assert(gfx); 479 assert(gfx);
451 assert(screen); 480 assert(screen);
452 // Integer scaling only. 481 // Integer scaling only.
@@ -457,16 +486,18 @@ void sgPresent(swgfx* gfx, sgVec2i dimensions, sgPixel* screen) {
457 const int sy = dimensions.y / gfx->dims.y; 486 const int sy = dimensions.y / gfx->dims.y;
458 487
459 const sgPixel* src = gfx->colour; 488 const sgPixel* src = gfx->colour;
460 sgPixel* dst = screen;
461 489
462 // Replicate each row 'sy' times.
463 for (int y = 0; y < gfx->dims.y; ++y, src += gfx->dims.x) { 490 for (int y = 0; y < gfx->dims.y; ++y, src += gfx->dims.x) {
464 for (int yy = y*sy; yy < (y+1)*sy; ++yy) { 491 // Replicate each row 'sy' times.
465 // Replicate each column 'sx' times. 492 for (int yy = 0; yy < sy; ++yy) {
466 const sgPixel* src_col = src; 493 const sgPixel* src_col = src;
467 for (int x = 0; x < gfx->dims.x; ++x, ++src_col) { 494 for (int x = 0; x < gfx->dims.x; ++x, ++src_col) {
468 for (int xx = x*sx; xx < (x+1)*sx; ++xx, ++dst) { 495 // Replicate each column 'sx' times.
469 *dst = *src_col; 496 for (int xx = 0; xx < sx; ++xx, ++screen) {
497 screen->r = src_col->r;
498 screen->g = src_col->g;
499 screen->b = src_col->b;
500 screen->a = src_col->a;
470 } 501 }
471 } 502 }
472 } 503 }
@@ -518,6 +549,12 @@ void sgViewport(swgfx* gfx, int x0, int y0, int width, int height) {
518 gfx->viewport = (sgViewport_t){x0, y0, width, height}; 549 gfx->viewport = (sgViewport_t){x0, y0, width, height};
519} 550}
520 551
552void sgTexture(swgfx* gfx, const sgTexture_t* texture) {
553 assert(gfx);
554 assert(texture);
555 gfx->texture = texture;
556}
557
521void sgClear(swgfx* gfx) { 558void sgClear(swgfx* gfx) {
522 assert(gfx); 559 assert(gfx);
523 const int N = gfx->dims.x * gfx->dims.y; 560 const int N = gfx->dims.x * gfx->dims.y;