summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/swgfx.c38
1 files changed, 21 insertions, 17 deletions
diff --git a/src/swgfx.c b/src/swgfx.c
index 2262dd8..85844e0 100644
--- a/src/swgfx.c
+++ b/src/swgfx.c
@@ -53,12 +53,13 @@ typedef struct swgfx {
53 53
54static inline int mod(int a, int m) { return (m + (a % m)) % m; } 54static inline int mod(int a, int m) { return (m + (a % m)) % m; }
55static inline R frac(R a) { return a - (R)((int)a); } 55static inline R frac(R a) { return a - (R)((int)a); }
56
57static inline int imin(int a, int b) { return (a <= b) ? a : b; } 56static inline int imin(int a, int b) { return (a <= b) ? a : b; }
58static inline int imax(int a, int b) { return (a >= b) ? a : b; } 57static inline int imax(int a, int b) { return (a >= b) ? a : b; }
59static inline R rmin(R a, R b) { return (a <= b) ? a : b; } 58
60static inline R rmax(R a, R b) { return (a >= b) ? a : b; } 59static inline R rmin(R a, R b) { return (a <= b) ? a : b; }
61static inline R lerp(R a, R b, R t) { return a + t*(b-a); } 60static inline R rmax(R a, R b) { return (a >= b) ? a : b; }
61static inline R lerp(R a, R b, R t) { return a + t*(b-a); }
62static inline R mod1(R a, R m) { return fmodf(1.f + fmodf(a, m), 1.f); }
62 63
63static inline sgVec2i min2i(sgVec2i a, sgVec2i b) { return (sgVec2i){.x = imin(a.x, b.x), .y = imin(a.y, b.y) }; } 64static inline sgVec2i min2i(sgVec2i a, sgVec2i b) { return (sgVec2i){.x = imin(a.x, b.x), .y = imin(a.y, b.y) }; }
64static inline sgVec2i max2i(sgVec2i a, sgVec2i b) { return (sgVec2i){.x = imax(a.x, b.x), .y = imax(a.y, b.y) }; } 65static inline sgVec2i max2i(sgVec2i a, sgVec2i b) { return (sgVec2i){.x = imax(a.x, b.x), .y = imax(a.y, b.y) }; }
@@ -69,6 +70,7 @@ static inline sgVec2 sub2(sgVec2 a, sgVec2 b) { return (sgVec2){a.x - b.x, a.y
69static inline sgVec2 scale2(sgVec2 v, R s) { return (sgVec2){v.x * s, v.y * s}; } 70static inline sgVec2 scale2(sgVec2 v, R s) { return (sgVec2){v.x * s, v.y * s}; }
70static inline sgVec2 frac2(sgVec2 v) { return (sgVec2){frac(v.x), frac(v.y)}; } 71static inline sgVec2 frac2(sgVec2 v) { return (sgVec2){frac(v.x), frac(v.y)}; }
71static inline sgVec2 lerp2(sgVec2 a, sgVec2 b, R t) { return add2(a, scale2(sub2(b,a), t)); } 72static inline sgVec2 lerp2(sgVec2 a, sgVec2 b, R t) { return add2(a, scale2(sub2(b,a), t)); }
73static inline sgVec2 mod2(sgVec2 v, R m) { return (sgVec2){mod1(v.x, m), mod1(v.y, m)}; }
72 74
73static inline sgVec3 add3(sgVec3 a, sgVec3 b) { return (sgVec3){a.x + b.x, a.y + b.y, a.z + b.z}; } 75static inline sgVec3 add3(sgVec3 a, sgVec3 b) { return (sgVec3){a.x + b.x, a.y + b.y, a.z + b.z}; }
74static inline sgVec3 neg3(sgVec3 v) { return (sgVec3){-v.x, -v.y, -v.z}; } 76static inline sgVec3 neg3(sgVec3 v) { return (sgVec3){-v.x, -v.y, -v.z}; }
@@ -314,33 +316,37 @@ static inline sgVec4 ReadTextureFloat(const sgImage* texture, sgVec2i xy) {
314 return PixelToVec4(ReadTexture(texture, xy)); 316 return PixelToVec4(ReadTexture(texture, xy));
315} 317}
316 318
319static inline sgVec2i UvToIndex(const sgImage* texture, sgVec2 uv) {
320 assert(texture);
321 return (sgVec2i){
322 (int)(uv.x * (R)(texture->width - 1)),
323 (int)(uv.y * (R)(texture->height - 1))};
324}
325
317static inline sgVec2i TextureRepeat(const sgImage* texture, sgVec2i p) { 326static inline sgVec2i TextureRepeat(const sgImage* texture, sgVec2i p) {
318 return (sgVec2i){mod(p.x, texture->width), mod(p.y, texture->height)}; 327 return (sgVec2i){mod(p.x, texture->width), mod(p.y, texture->height)};
319} 328}
320 329
321static inline sgPixel SampleNearest(const sgImage* texture, sgVec2 uv) { 330static inline sgPixel FilterNearest(const sgImage* texture, sgVec2 uv) {
322 assert(texture); 331 assert(texture);
323 assert(texture->pixels); 332 assert(texture->pixels);
324 const sgVec2i xy = { 333 const sgVec2i xy = UvToIndex(texture, uv);
325 (int)(uv.x * (R)texture->width),
326 (int)(uv.y * (R)texture->height)};
327 const sgVec2i xy2 = TextureRepeat(texture, xy); 334 const sgVec2i xy2 = TextureRepeat(texture, xy);
328 return ReadTexture(texture, xy2); 335 return ReadTexture(texture, xy2);
329} 336}
330 337
331static inline sgPixel SampleBilinear(const sgImage* texture, sgVec2 uv) { 338static inline sgPixel FilterBilinear(const sgImage* texture, sgVec2 uv) {
332 assert(texture); 339 assert(texture);
333 assert(texture->pixels); 340 assert(texture->pixels);
334#define ADDR(x,y) TextureRepeat(texture, (sgVec2i){x,y}) 341#define ADDR(x,y) TextureRepeat(texture, (sgVec2i){x,y})
342 const sgVec2 uv01 = mod2(uv, 1.f);
335 // Find the closest grid vertex, then interpolate the 4 neighbouring pixel 343 // Find the closest grid vertex, then interpolate the 4 neighbouring pixel
336 // centers. 344 // centers.
337 const sgVec2i tl = ADDR( 345 const sgVec2i tl = UvToIndex(texture, uv01);
338 (int)(uv.x * (R)(texture->width - 1)),
339 (int)(uv.y * (R)(texture->height - 1)));
340 const sgVec2i tr = ADDR(tl.x+1, tl.y); 346 const sgVec2i tr = ADDR(tl.x+1, tl.y);
341 const sgVec2i bl = ADDR(tl.x, tl.y+1); 347 const sgVec2i bl = ADDR(tl.x, tl.y+1);
342 const sgVec2i br = ADDR(tl.x+1, tl.y+1); 348 const sgVec2i br = ADDR(tl.x+1, tl.y+1);
343 const sgVec2 t = frac2(uv); 349 const sgVec2 t = frac2(uv01);
344 const sgVec4 tl_pix = ReadTextureFloat(texture, tl); 350 const sgVec4 tl_pix = ReadTextureFloat(texture, tl);
345 const sgVec4 tr_pix = ReadTextureFloat(texture, tr); 351 const sgVec4 tr_pix = ReadTextureFloat(texture, tr);
346 const sgVec4 bl_pix = ReadTextureFloat(texture, bl); 352 const sgVec4 bl_pix = ReadTextureFloat(texture, bl);
@@ -355,10 +361,8 @@ static inline sgPixel SampleBilinear(const sgImage* texture, sgVec2 uv) {
355// TODO: Clamping and other addressing strategies. 361// TODO: Clamping and other addressing strategies.
356static inline sgPixel Sample(const sgImage* texture, sgVec2 uv) { 362static inline sgPixel Sample(const sgImage* texture, sgVec2 uv) {
357 // TODO: Add a member to sgImage that determines how it should be filtered. 363 // TODO: Add a member to sgImage that determines how it should be filtered.
358 return SampleNearest(texture, uv); 364 //return FilterNearest(texture, uv);
359 // TODO: Debug bilinear. It's producing random colours on the ground, likely 365 return FilterBilinear(texture, uv);
360 // out-of-bounds memory accesses.
361 //return SampleBilinear(texture, uv);
362} 366}
363 367
364static inline sgAABB2 TriangleAabb2(sgVec2 p0, sgVec2 p1, sgVec2 p2) { 368static inline sgAABB2 TriangleAabb2(sgVec2 p0, sgVec2 p1, sgVec2 p2) {