summaryrefslogtreecommitdiff
path: root/sponge.h
diff options
context:
space:
mode:
Diffstat (limited to 'sponge.h')
-rw-r--r--sponge.h379
1 files changed, 220 insertions, 159 deletions
diff --git a/sponge.h b/sponge.h
index 02f1bcd..ce27f31 100644
--- a/sponge.h
+++ b/sponge.h
@@ -1,30 +1,92 @@
#include <stdint.h>
+typedef union {
+ // do not rely on byte order of this field (unless you only support one platform)
+ uint32_t value;
+ struct {
+ uint8_t b;
+ uint8_t g;
+ uint8_t r;
+ uint8_t a;
+ };
+} sponge_Color32;
+sponge_Color32 sponge_color32_make(uint32_t value);
+
typedef struct {
- uint32_t *pixels; // AARRGGBB
- uint32_t width;
- uint32_t height;
- uint32_t stride;
+ sponge_Color32 *pixels;
+ uint32_t width;
+ uint32_t height;
+ size_t stride_pixels;
} sponge_Texture;
typedef struct {
float x;
float y;
} sponge_Vec2;
+sponge_Vec2 sponge_vec2_make(float x, float y);
-sponge_Vec2 sponge_add2(sponge_Vec2 v0, sponge_Vec2 v1);
-sponge_Vec2 sponge_sub2(sponge_Vec2 v0, sponge_Vec2 v1);
-float sponge_dot2(sponge_Vec2 v0, sponge_Vec2 v1);
+typedef struct {
+ float x;
+ float y;
+ float z;
+} sponge_Vec3;
+sponge_Vec3 sponge_vec3_make(float x, float y, float z);
-int sponge_canvas_valid (sponge_Texture c);
-void sponge_clear (sponge_Texture c, uint32_t color);
-void sponge_draw_rect (sponge_Texture c, uint32_t x0, uint32_t y0, uint32_t x1, uint32_t y1, uint32_t color);
-void sponge_draw_line (sponge_Texture c, int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t color);
-void sponge_draw_texture (sponge_Texture c, uint32_t x0, uint32_t y0, sponge_Texture tex);
-void sponge_draw_triangle_col (sponge_Texture c, int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_t x2, int32_t y2, uint32_t color);
-void sponge_draw_triangle_col3(
- sponge_Texture c, int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_t x2, int32_t y2,
- uint32_t color0, uint32_t color1, uint32_t color2);
+typedef union {
+ struct {
+ float x;
+ float y;
+ float z;
+ float w;
+ };
+ struct {
+ float a;
+ float r;
+ float g;
+ float b;
+ };
+} sponge_Vec4;
+sponge_Vec4 sponge_vec4_make(float x, float y, float z, float w);
+
+// in sponge apis components expected to be between 0.0 and 255.0
+#define sponge_ColorF sponge_Vec4
+
+typedef struct {
+ int32_t x;
+ int32_t y;
+} sponge_Vec2I;
+sponge_Vec2I sponge_vec2i_make(int32_t x, int32_t y);
+
+sponge_Vec2 sponge_vec2_add(sponge_Vec2 v0, sponge_Vec2 v1);
+sponge_Vec2 sponge_vec2_sub(sponge_Vec2 v0, sponge_Vec2 v1);
+float sponge_vec2_dot(sponge_Vec2 v0, sponge_Vec2 v1);
+
+sponge_Vec4 sponge_vec4_add(sponge_Vec4 v0, sponge_Vec4 v1);
+sponge_Vec4 sponge_vec4_mul(sponge_Vec4 v0, float f);
+
+sponge_ColorF sponge_color32_to_colorf(sponge_Color32 col);
+sponge_Color32 sponge_colorf_to_color32(sponge_ColorF col);
+
+// checks if tex.width or tex.height is equal to 0
+// calling sponge functions with invalid textures is not supported
+int sponge_texture_valid(sponge_Texture tex);
+
+// first argument is always rendering target (canvas)
+void sponge_clear (sponge_Texture c, sponge_Color32 col);
+
+void sponge_draw_rect (sponge_Texture c, sponge_Vec2I v0, sponge_Vec2I v1, sponge_Color32 col);
+void sponge_draw_line (sponge_Texture c, sponge_Vec2I v0, sponge_Vec2I v1, sponge_Color32 col);
+void sponge_draw_texture(sponge_Texture c, sponge_Vec2I offset, sponge_Texture tex);
+
+//void sponge_draw_triangle_col (sponge_Texture c, sponge_Vec2I v0, sponge_Vec2I v1, sponge_Vec2I v2, sponge_Color32 col);
+//void sponge_draw_triangle_col3(sponge_Texture c,
+// sponge_Vec2I v0, sponge_Vec2I v1, sponge_Vec2I v2,
+// sponge_ColorF col0, sponge_ColorF col1, sponge_ColorF col2);
+
+#define SPONGE_CLAMP(val, min, max) ((val) < (min) ? (min) : ((val) > (max) ? (max) : (val)))
+#define SPONGE_MIN(x, y) ((x) < (y) ? (x) : (y))
+#define SPONGE_MAX(x, y) ((x) > (y) ? (x) : (y))
+#define SPONGE_ABS(x) ((x) >= 0 ? (x) : -(x))
// TODO(kard): prefix stripping
@@ -36,199 +98,193 @@ void sponge_draw_triangle_col3(
#define SPONGE_ASSERT(x) assert(x)
#endif // SPONGE_ASSERT
-#define SPONGE__CLAMP(val, min, max) ((val) < (min) ? (min) : ((val) > (max) ? (max) : (val)))
-#define SPONGE__MIN(x, y) ((x) < (y) ? (x) : (y))
-#define SPONGE__MAX(x, y) ((x) > (y) ? (x) : (y))
-#define SPONGE__ABS(x) ((x) >= 0 ? (x) : -(x))
-
-typedef struct {
- float a;
- float r;
- float g;
- float b;
-} sponge__ColorF;
-
-sponge__ColorF sponge__colf_unpack(uint32_t col) {
- uint32_t b = col & 0xFF;
- col = col >> 8;
- uint32_t g = col & 0xFF;
- col = col >> 8;
- uint32_t r = col & 0xFF;
- col = col >> 8;
- uint32_t a = col & 0xFF;
- sponge__ColorF result = { .a = (float)a, .r = (float)r, .g = (float)g, .b = (float)b };
+// TODO(kard): msvc does not inline this for some reason, explore if it's a concern
+sponge_Color32 sponge_color32_make(uint32_t value) {
+ sponge_Color32 result;
+ result.a = (value & 0xFF000000) >> 24;
+ result.r = (value & 0x00FF0000) >> 16;
+ result.g = (value & 0x0000FF00) >> 8;
+ result.b = (value & 0x000000FF);
return result;
}
-
-uint32_t sponge__colf_pack(sponge__ColorF color) {
- uint32_t result = 0;
- result |= SPONGE__CLAMP((uint32_t)color.a, 0x00, 0xFF);
- result = result << 8;
- result |= SPONGE__CLAMP((uint32_t)color.r, 0x00, 0xFF);
- result = result << 8;
- result |= SPONGE__CLAMP((uint32_t)color.g, 0x00, 0xFF);
- result = result << 8;
- result |= SPONGE__CLAMP((uint32_t)color.b, 0x00, 0xFF);
+sponge_Vec2 sponge_vec2_make(float x, float y) {
+ sponge_Vec2 result;
+ result.x = x;
+ result.y = y;
return result;
}
-
-sponge__ColorF sponge__colf_mul(sponge__ColorF color, float f) {
- color.a *= f;
- color.r *= f;
- color.g *= f;
- color.b *= f;
- return color;
+sponge_Vec3 sponge_vec3_make(float x, float y, float z) {
+ sponge_Vec3 result;
+ result.x = x;
+ result.y = y;
+ result.z = z;
+ return result;
}
-
-sponge__ColorF sponge__colf_add(sponge__ColorF color0, sponge__ColorF color1) {
- sponge__ColorF result;
- result.a = color0.a + color1.a;
- result.r = color0.r + color1.r;
- result.g = color0.g + color1.g;
- result.b = color0.b + color1.b;
+sponge_Vec4 sponge_vec4_make(float x, float y, float z, float w) {
+ sponge_Vec4 result;
+ result.x = x;
+ result.y = y;
+ result.z = z;
+ result.w = w;
return result;
}
-
-
-typedef struct {
- sponge_Vec2 v0;
- sponge_Vec2 v1;
- float d00;
- float d01;
- float d11;
- float denom;
-} sponge__BarycentricContext;
-
-// TODO(kard): measure if caching this makes sense
-sponge__BarycentricContext sponge__barycentric_init(sponge_Vec2 t0, sponge_Vec2 t1, sponge_Vec2 t2) {
- sponge__BarycentricContext result;
- result.v0 = sponge_sub2(t1, t0);
- result.v1 = sponge_sub2(t2, t0);
- result.d00 = sponge_dot2(result.v0, result.v0);
- result.d01 = sponge_dot2(result.v0, result.v1);
- result.d11 = sponge_dot2(result.v1, result.v1);
- result.denom = (result.d00 * result.d11) - (result.d01 * result.d01);
+sponge_Vec2I sponge_vec2i_make(int32_t x, int32_t y) {
+ sponge_Vec2I result;
+ result.x = x;
+ result.y = y;
return result;
}
-void sponge__barycentric(
- sponge__BarycentricContext ctx, sponge_Vec2 p,
- sponge_Vec2 t0,
- sponge_Vec2 t1,
- sponge_Vec2 t2,
- float *u, float *v, float *w
-) {
- sponge_Vec2 v2 = sponge_sub2(p, t0);
- float d20 = sponge_dot2(v2, ctx.v0);
- float d21 = sponge_dot2(v2, ctx.v1);
- float vr = (ctx.d11 * d20 - ctx.d01 * d21) / ctx.denom;
- float wr = (ctx.d00 * d21 - ctx.d01 * d20) / ctx.denom;
- float ur = 1.0f - vr - wr;
- *u = ur;
- *v = vr;
- *w = wr;
+sponge_Vec2 sponge_vec2_add(sponge_Vec2 v0, sponge_Vec2 v1) {
+ return (sponge_Vec2){ .x = v0.x + v1.x, .y = v0.y + v1.y };
}
-
-
-sponge_Vec2 sponge_add2(sponge_Vec2 v0, sponge_Vec2 v1) {
- sponge_Vec2 result;
- result.x = v0.x + v1.x;
- result.y = v0.y + v1.y;
- return result;
+sponge_Vec2 sponge_vec2_sub(sponge_Vec2 v0, sponge_Vec2 v1) {
+ return (sponge_Vec2){ .x = v0.x - v1.x, .y = v0.y - v1.y };
+}
+float sponge_vec2_dot(sponge_Vec2 v0, sponge_Vec2 v1) {
+ return (v0.x * v1.x) + (v0.y * v1.y);
}
-sponge_Vec2 sponge_sub2(sponge_Vec2 v0, sponge_Vec2 v1) {
- sponge_Vec2 result;
- result.x = v0.x - v1.x;
- result.y = v0.y - v1.y;
- return result;
+sponge_ColorF sponge_color32_to_colorf(sponge_Color32 col) {
+ return (sponge_ColorF){ .a = (float)col.a, .r = (float)col.r, .g = (float)col.g, .b = (float)col.b };
+}
+sponge_Color32 sponge_colorf_to_color32(sponge_ColorF col) {
+ return (sponge_Color32){ .a = (uint8_t)col.a, .r = (uint8_t)col.r, .g = (uint8_t)col.g, .b = (uint8_t)col.b };
}
-float sponge_dot2(sponge_Vec2 v0, sponge_Vec2 v1) {
- return (v0.x * v1.x) + (v0.y * v1.y);
+sponge_Vec4 sponge_vec4_add(sponge_Vec4 v0, sponge_Vec4 v1) {
+ v0.a += v1.a;
+ v0.r += v1.r;
+ v0.g += v1.g;
+ v0.b += v1.b;
+ return v0;
+}
+sponge_Vec4 sponge_vec4_mul(sponge_Vec4 v0, float f) {
+ v0.a *= f;
+ v0.r *= f;
+ v0.g *= f;
+ v0.b *= f;
+ return v0;
}
-int sponge_canvas_valid(sponge_Texture c) {
- return c.width != 0 && c.height != 0;
+// sponge__BarycentricContext sponge__barycentric_init(sponge_Vec2 t0, sponge_Vec2 t1, sponge_Vec2 t2) {
+ // sponge__BarycentricContext result;
+ // result.v0 = sponge_sub2(t1, t0);
+ // result.v1 = sponge_sub2(t2, t0);
+ // result.d00 = sponge_dot2(result.v0, result.v0);
+ // result.d01 = sponge_dot2(result.v0, result.v1);
+ // result.d11 = sponge_dot2(result.v1, result.v1);
+ // result.denom = (result.d00 * result.d11) - (result.d01 * result.d01);
+ // return result;
+// }
+//
+// void sponge__barycentric(
+ // sponge__BarycentricContext ctx, sponge_Vec2 p,
+ // sponge_Vec2 t0,
+ // sponge_Vec2 t1,
+ // sponge_Vec2 t2,
+ // float *u, float *v, float *w
+// ) {
+ // sponge_Vec2 v2 = sponge_sub2(p, t0);
+ // float d20 = sponge_dot2(v2, ctx.v0);
+ // float d21 = sponge_dot2(v2, ctx.v1);
+ // float vr = (ctx.d11 * d20 - ctx.d01 * d21) / ctx.denom;
+ // float wr = (ctx.d00 * d21 - ctx.d01 * d20) / ctx.denom;
+ // float ur = 1.0f - vr - wr;
+ // *u = ur;
+ // *v = vr;
+ // *w = wr;
+// }
+
+
+int sponge_texture_valid(sponge_Texture tex) {
+ return tex.width != 0 && tex.height != 0 && tex.stride_pixels != 0;
}
-void sponge_clear(sponge_Texture c, uint32_t color) {
- SPONGE_ASSERT(sponge_canvas_valid(c));
+void sponge_clear(sponge_Texture c, sponge_Color32 col) {
+ SPONGE_ASSERT(sponge_texture_valid(c));
+ sponge_Color32 *row = c.pixels;
- sponge_draw_rect(c, 0, 0, c.width - 1, c.height - 1, color);
+ for (uint32_t y = 0; y < c.height; y++, row += c.stride_pixels) {
+ for (uint32_t x = 0; x < c.width; x++) {
+ row[x] = col;
+ }
+ }
}
-// TODO(kard): probably bounds checking
-// TODO(kard): alpha blending maybe
-void sponge_draw_rect(sponge_Texture c, uint32_t x0, uint32_t y0, uint32_t x1, uint32_t y1, uint32_t color) {
- SPONGE_ASSERT(sponge_canvas_valid(c));
+void sponge_draw_rect(sponge_Texture c, sponge_Vec2I v0, sponge_Vec2I v1, sponge_Color32 col) {
+ SPONGE_ASSERT(sponge_texture_valid(c));
+ sponge_Vec2I min, max;
+ min.x = SPONGE_MIN(v0.x, v1.x);
+ min.y = SPONGE_MIN(v0.y, v1.y);
+ max.x = SPONGE_MAX(v0.x, v1.x);
+ max.y = SPONGE_MAX(v0.y, v1.y);
+ if (min.x >= (int32_t)c.width || min.y >= (int32_t)c.height || max.x < 0 || max.y < 0)
+ return;
+ min.x = SPONGE_MAX(min.x, 0);
+ min.y = SPONGE_MAX(min.y, 0);
+ max.x = SPONGE_MIN(max.x, (int32_t)c.width - 1);
+ max.y = SPONGE_MIN(max.y, (int32_t)c.height - 1);
- uint32_t *row = c.pixels + (y0 * c.stride);
+ sponge_Color32 *row = c.pixels + (min.y * c.stride_pixels);
- for (uint32_t y = y0; y <= y1; y++, row += c.stride) {
- for (uint32_t x = x0; x <= x1; x++) {
- row[x] = color;
+ for (int32_t y = min.y; y <= max.y; y++, row += c.stride_pixels) {
+ for (int32_t x = min.x; x <= max.x; x++) {
+ row[x] = col;
}
}
}
-void sponge_draw_line(sponge_Texture c, int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t color) {
- SPONGE_ASSERT(sponge_canvas_valid(c));
+void sponge_draw_line(sponge_Texture c, sponge_Vec2I v0, sponge_Vec2I v1, sponge_Color32 col) {
+ SPONGE_ASSERT(sponge_texture_valid(c));
- int32_t dx = x1 - x0;
- dx = SPONGE__ABS(dx);
- int32_t dy = y1 - y0;
- dy = SPONGE__ABS(dy);
+ int32_t dx = SPONGE_ABS(v1.x - v0.x);
+ int32_t dy = SPONGE_ABS(v1.y - v0.y);
int32_t d = (2 * dy) - dx;
- int32_t sx = (x0 < x1) ? 1 : -1;
- int32_t sy = (y0 < y1) ? 1 : -1;
+ int32_t sx = (v0.x < v1.x) ? 1 : -1;
+ int32_t sy = (v0.y < v1.y) ? 1 : -1;
int32_t err = dx - dy;
while (1) {
- if (x0 >= 0 && x0 < (int32_t)c.width && y0 >= 0 && y0 < (int32_t)c.height)
- c.pixels[(y0 * c.stride) + x0] = color;
+ if (v0.x >= 0 && v0.x < (int32_t)c.width && v0.y >= 0 && v0.y < (int32_t)c.height)
+ c.pixels[(v0.y * c.stride_pixels) + v0.x] = col;
- if (x0 == x1 && y0 == y1) break;
+ if (v0.x == v1.x && v0.y == v1.y) break;
int32_t e2 = 2 * err;
- if (e2 > -dy) { err -= dy; x0 += sx; }
- if (e2 < dx) { err += dx; y0 += sy; }
+ if (e2 > -dy) { err -= dy; v0.x += sx; }
+ if (e2 < dx) { err += dx; v0.y += sy; }
}
}
-void sponge_draw_texture(sponge_Texture c, uint32_t x0, uint32_t y0, sponge_Texture tex) {
- SPONGE_ASSERT(sponge_canvas_valid(c));
-
- uint32_t *row_dst = c.pixels + (y0 * c.stride);
- uint32_t *row_src = tex.pixels;
- uint32_t x1 = x0 + tex.width;
- uint32_t y1 = y0 + tex.height;
+void sponge_draw_texture(sponge_Texture c, sponge_Vec2I offset, sponge_Texture tex) {
+ SPONGE_ASSERT(sponge_texture_valid(c));
+ SPONGE_ASSERT(sponge_texture_valid(tex));
- if (x1 >= c.width)
- x1 = c.width - 1;
- if (y1 >= c.height)
- y1 = c.height - 1;
+ sponge_Vec2I min, max;
+ min.x = SPONGE_MAX(offset.x, 0);
+ min.y = SPONGE_MAX(offset.y, 0);
+ max.x = SPONGE_MIN(offset.x + tex.width - 1, c.width - 1);
+ max.y = SPONGE_MIN(offset.y + tex.height - 1, c.height - 1);
+ sponge_Color32 *row_dst = c.pixels + (min.y * c.stride_pixels);
+ sponge_Color32 *row_src = (tex.pixels - (offset.y * c.stride_pixels)) + (min.y * c.stride_pixels);
+ uint32_t src_offset = min.x - offset.x;
- for (uint32_t y = y0; y <= y1; y++, row_src += tex.stride, row_dst += c.stride) {
- // TODO(kard): memcpy?
- for (uint32_t x = x0, x_src = 0; x <= x1; x++, x_src++) {
+ for (int32_t y = min.y; y <= max.y; y++, row_src += tex.stride_pixels, row_dst += c.stride_pixels) {
+ for (int32_t x = min.x, x_src = src_offset; x <= max.x; x++, x_src++) {
row_dst[x] = row_src[x_src];
}
}
}
+/*
void sponge_draw_triangle_col(sponge_Texture c, int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_t x2, int32_t y2, uint32_t color) {
sponge_draw_triangle_col3(c, x0, y0, x1, y1, x2, y2, color, color, color);
}
// NOTE(kard):
// this does not accept floats on purpose.
-// there are more efficient algorithms for producing triangle pixels other than
-// checking every one of them in rectangle with barycentric coords (e.g. using Brehensam algorithm)
-// and they can work with integer coordinates.
-// TODO(kard): this should be explored in the future
-// TODO(kard): backface culling?
void sponge_draw_triangle_col3(
sponge_Texture c, int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_t x2, int32_t y2,
uint32_t color0, uint32_t color1, uint32_t color2) {
@@ -248,7 +304,6 @@ void sponge_draw_triangle_col3(
uint32_t min_y = (uint32_t)SPONGE__CLAMP(smin_y, 0, (int32_t)(c.height - 1));
uint32_t max_y = (uint32_t)SPONGE__CLAMP(smax_y, 0, (int32_t)(c.height - 1));
- sponge__BarycentricContext ctx = sponge__barycentric_init(t0, t1, t2);
uint32_t *row = c.pixels + (min_y * c.stride);
@@ -260,10 +315,10 @@ void sponge_draw_triangle_col3(
for (uint32_t x = x0; x <= max_x; x++) {
float u, v, w;
sponge_Vec2 p = { .x = (float)x, .y = (float)y };
+ sponge__BarycentricContext ctx = sponge__barycentric_init(t0, t1, t2);
sponge__barycentric(ctx, p, t0, t1, t2, &u, &v, &w);
if (u > 0.0f && v > 0.0f && w > 0.0f)
{
- // TODO(kard): make more robust, this probably has a lot of off by 1 errors
sponge__ColorF c0 = sponge__colf_mul(color0f, u);
sponge__ColorF c1 = sponge__colf_mul(color1f, v);
sponge__ColorF c2 = sponge__colf_mul(color2f, w);
@@ -274,5 +329,11 @@ void sponge_draw_triangle_col3(
}
}
-#endif // SPONGE_IMPLEMENTATION
+void sponge_draw_triangle_uv(
+ sponge_Texture c, int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_t x2, int32_t y2,
+ uint32_t color0, uint32_t color1, uint32_t color2,
+ sponge_Vec2 uv0, sponge_Vec2 uv1, sponge_Vec2 uv2, sponge_Texture tex) {
+}
+*/
+#endif // SPONGE_IMPLEMENTATION