From 2bdcaf319b1d74ffbaccf08a58336f804761beab Mon Sep 17 00:00:00 2001 From: LLLL Colonq Date: Thu, 9 Jul 2026 23:51:55 -0400 Subject: Refactor into monorepo --- gastro/src/gastro.c | 311 ++++++++++++++++++++++++++++++++++++++++++++++++++++ gastro/src/main.c | 242 ++++++++++++++++++++++++++++++++++++++++ gastro/src/trig.c | 268 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 821 insertions(+) create mode 100644 gastro/src/gastro.c create mode 100644 gastro/src/main.c create mode 100644 gastro/src/trig.c (limited to 'gastro/src') diff --git a/gastro/src/gastro.c b/gastro/src/gastro.c new file mode 100644 index 0000000..2b175fe --- /dev/null +++ b/gastro/src/gastro.c @@ -0,0 +1,311 @@ +#include +#include +#include + +#include + +#define MAX_ATTRS 16 + +static i64 min2(i64 x, i64 y) { return x < y ? x : y; } +static i64 min3(i64 x, i64 y, i64 z) { return min2(min2(x, y), z); } +static i64 max2(i64 x, i64 y) { return x > y ? x : y; } +static i64 max3(i64 x, i64 y, i64 z) { return max2(max2(x, y), z); } + +gastro_fix gastro_fix_new(i64 x) { + assert(x < ((i64) 1 << (sizeof(gastro_fix) * 8 - GASTRO_FIXED_POINT))); + return x << GASTRO_FIXED_POINT; +} +i64 gastro_fix_to_i64(gastro_fix x) { + return x >> GASTRO_FIXED_POINT; +} +gastro_fix gastro_fix_from_double(double x) { + double shift = (double) (1 << GASTRO_FIXED_POINT); + return (gastro_fix) (x * shift); +} +double gastro_fix_to_double(gastro_fix x) { + double shift = (double) (1 << GASTRO_FIXED_POINT); + return (double) x / shift; +} +gastro_fix gastro_fix_mul(gastro_fix x, gastro_fix y) { + return (gastro_fix) (x * y) >> GASTRO_FIXED_POINT; +} +gastro_fix gastro_fix_div(gastro_fix x, gastro_fix y) { + return (x * (1 << GASTRO_FIXED_POINT)) / y; +} +gastro_fix gastro_fix_sqrt(gastro_fix s) { + gastro_fix x = GASTRO_FIX_ONE; + i64 i; + for (i = 0; i < 5; ++i) { + x = gastro_fix_mul(GASTRO_FIX_HALF, x + gastro_fix_div(s, x)); + } + return x; +} + +gastro_vec2 gastro_vec2_new(gastro_fix x, gastro_fix y) { + gastro_vec2 ret; + ret.x = x; ret.y = y; + return ret; +} +gastro_vec2 gastro_vec2_add(gastro_vec2 x, gastro_vec2 y) { + return gastro_vec2_new(x.x + y.x, x.y + y.y); +} +gastro_vec2 gastro_vec2_sub(gastro_vec2 x, gastro_vec2 y) { + return gastro_vec2_new(x.x - y.x, x.y - y.y); +} +gastro_fix gastro_vec2_length(gastro_vec2 v) { + gastro_fix sq = gastro_fix_mul(v.x, v.x) + gastro_fix_mul(v.y, v.y); + return gastro_fix_sqrt((gastro_fix) sq); +} +gastro_fix gastro_vec2_cross(gastro_vec2 v, gastro_vec2 u) { + return gastro_fix_mul(v.x, u.y) - gastro_fix_mul(u.x, v.y); +} +gastro_vec3 gastro_vec3_new(gastro_fix x, gastro_fix y, gastro_fix z) { + gastro_vec3 ret; + ret.x = x; ret.y = y; ret.z = z; + return ret; +} +void gastro_vec3_print(gastro_vec3 v) { + printf("<%f, %f, %f>\n", gastro_fix_to_double(v.x), gastro_fix_to_double(v.y), gastro_fix_to_double(v.z)); +} +gastro_vec2 gastro_vec3_xy(gastro_vec3 v) { return gastro_vec2_new(v.x, v.y); } +gastro_vec3 gastro_vec3_perspective(gastro_fix nearz, gastro_vec3 p) { + gastro_vec3 ret; + ret.x = gastro_fix_mul(gastro_fix_div(nearz, p.z), p.x); + ret.y = gastro_fix_mul(gastro_fix_div(nearz, p.z), p.y); + ret.z = p.z; + return ret; +} +gastro_fix gastro_vec3_bary_interpolate(gastro_vec3 bary, gastro_fix x, gastro_fix y, gastro_fix z) { + return gastro_fix_mul(bary.x, x) + gastro_fix_mul(bary.y, y) + gastro_fix_mul(bary.z, z); +} +gastro_fix gastro_vec3_bary_interpolate_inv(gastro_vec3 bary, gastro_fix x, gastro_fix y, gastro_fix z) { + return gastro_fix_div(GASTRO_FIX_ONE, + gastro_vec3_bary_interpolate(bary, + gastro_fix_div(GASTRO_FIX_ONE, x), + gastro_fix_div(GASTRO_FIX_ONE, y), + gastro_fix_div(GASTRO_FIX_ONE, z) + ) + ); +} + +gastro_vec4 gastro_vec4_new(gastro_fix x, gastro_fix y, gastro_fix z, gastro_fix w) { + gastro_vec4 ret; + ret.x = x; ret.y = y; ret.z = z; ret.w = w; + return ret; +} +void gastro_vec4_print(gastro_vec4 v) { + printf("<%f, %f, %f, %f>\n", gastro_fix_to_double(v.x), gastro_fix_to_double(v.y), gastro_fix_to_double(v.z), gastro_fix_to_double(v.w)); +} +gastro_vec3 gastro_vec4_xyz(gastro_vec4 v) { return gastro_vec3_new(v.x, v.y, v.z); } +gastro_fix gastro_vec4_idx(gastro_vec4 v, i64 idx) { + assert(idx >= 0 && idx < 4); + switch (idx) { + case 0: return v.x; + case 1: return v.y; + case 2: return v.z; + case 3: return v.w; + default: return 0; + } +} +gastro_fix gastro_vec4_dot(gastro_vec4 a, gastro_vec4 b) { + return gastro_fix_mul(a.x, b.x) + + gastro_fix_mul(a.y, b.y) + + gastro_fix_mul(a.z, b.z) + + gastro_fix_mul(a.w, b.w); +} + +gastro_mat4x4 gastro_mat4x4_new( + gastro_fix e0, gastro_fix e1, gastro_fix e2, gastro_fix e3, + gastro_fix e4, gastro_fix e5, gastro_fix e6, gastro_fix e7, + gastro_fix e8, gastro_fix e9, gastro_fix e10, gastro_fix e11, + gastro_fix e12, gastro_fix e13, gastro_fix e14, gastro_fix e15) { + gastro_mat4x4 ret; + ret.rows[0] = gastro_vec4_new( e0, e1, e2, e3); + ret.rows[1] = gastro_vec4_new( e4, e5, e6, e7); + ret.rows[2] = gastro_vec4_new( e8, e9, e10, e11); + ret.rows[3] = gastro_vec4_new(e12, e13, e14, e15); + return ret; +} +void gastro_mat4x4_print(gastro_mat4x4 m) { + i64 row; + for (row = 0; row < 4; ++row) { + printf("%c %14f, %14f, %14f, %14f, %c\n", + row == 0 ? '[' : ' ', + gastro_fix_to_double(m.rows[row].x), + gastro_fix_to_double(m.rows[row].y), + gastro_fix_to_double(m.rows[row].z), + gastro_fix_to_double(m.rows[row].w), + row == 3 ? ']' : ' '); + } +} +gastro_vec4 gastro_mat4x4_mul_vec4(gastro_mat4x4 m, gastro_vec4 v) { + return gastro_vec4_new( + gastro_vec4_dot(m.rows[0], v), + gastro_vec4_dot(m.rows[1], v), + gastro_vec4_dot(m.rows[2], v), + gastro_vec4_dot(m.rows[3], v)); +} +gastro_mat4x4 gastro_mat4x4_mul_mat4x4(gastro_mat4x4 n, gastro_mat4x4 m) { + gastro_mat4x4 ret; + i64 row, col; + for (row = 0; row < 4; ++row) { + gastro_fix comps[4]; + for (col = 0; col < 4; ++col) { + comps[col] = gastro_vec4_dot( + gastro_vec4_new( + gastro_vec4_idx(m.rows[0], col), + gastro_vec4_idx(m.rows[1], col), + gastro_vec4_idx(m.rows[2], col), + gastro_vec4_idx(m.rows[3], col)), + n.rows[row]); + } + ret.rows[row] = gastro_vec4_new(comps[0], comps[1], comps[2], comps[3]); + } + return ret; +} + +gastro_color gastro_color_new(u8 r, u8 g, u8 b, u8 a) { + gastro_color ret; + ret.r = r; ret.g = g; ret.b = b; ret.a = a; + return ret; +} + +void gastro_ctx_init(gastro_ctx *ret, u32 width, u32 height, gastro_color *pixels, gastro_fix *depth) { + ret->width = width; + ret->height = height; + ret->pixels = pixels; + ret->depth = depth; +} + +gastro_vec3 gastro_vec3_denormalize(gastro_ctx *ctx, gastro_vec3 p) { + gastro_vec3 ret; + ret.x = gastro_fix_mul(p.x + GASTRO_FIX_ONE, gastro_fix_new(ctx->width / 2)); + ret.y = gastro_fix_mul(p.y + GASTRO_FIX_ONE, gastro_fix_new(ctx->height / 2)); + ret.z = p.z; + return ret; +} + +void gastro_draw_pixel(gastro_ctx *ctx, gastro_color col, gastro_fix z, i64 x, i64 y) { + i64 idx = y * ctx->width + x; + if (x < 0 || x >= ctx->width || y < 0 || y >= ctx->height) return; + if (z > ctx->depth[idx]) return; + ctx->pixels[idx] = col; + ctx->depth[idx] = z; +} + +void gastro_draw_clear(gastro_ctx *ctx, gastro_color col) { + i64 x, y; + for (x = 0; x < ctx->width; ++x) { + for (y = 0; y < ctx->height; ++y) { + i64 idx = y * ctx->width + x; + ctx->pixels[idx] = col; + ctx->depth[idx] = INT64_MAX; + } + } +} + +gastro_vertex gastro_program_vertex(gastro_ctx *ctx, gastro_program *p, gastro_vec3 v, gastro_fix *attrs, i64 attrs_len) { + gastro_vertex ret; + gastro_vec4 res = p->vertex(ctx, v, attrs, attrs_len); + res.x = gastro_fix_div(res.x, res.w); + res.y = gastro_fix_div(res.y, res.w); + /* res.z = gastro_fix_div(res.z, res.w); */ + ret.v = gastro_vec4_xyz(res); + ret.attrs = attrs; + return ret; +} +gastro_color gastro_program_fragment(gastro_ctx *ctx, gastro_program *p, gastro_vec3 v, gastro_fix *attrs, i64 attrs_len) { + gastro_color ret; + ret = p->fragment(ctx, v, attrs, attrs_len); + return ret; +} + +/* return negative if x is to the right of the line from p0 to p1 */ +static gastro_fix compare_edge(gastro_vec2 x, gastro_vec2 p0, gastro_vec2 p1) { + gastro_vec2 pd = gastro_vec2_sub(p1, p0); + gastro_vec2 xd = gastro_vec2_sub(x, p0); + gastro_fix cross = gastro_vec2_cross(xd, pd); + return cross; +} +static bool triangle_contains(gastro_vec3 *bary, gastro_vec2 x, gastro_vec2 p0, gastro_vec2 p1, gastro_vec2 p2) { + gastro_fix p0p1 = compare_edge(x, p0, p1); + gastro_fix p1p2 = compare_edge(x, p1, p2); + gastro_fix p2p0 = compare_edge(x, p2, p0); + gastro_fix area = compare_edge(p2, p0, p1); + if (area == 0) return false; + bary->x = gastro_fix_div(p1p2, area); + bary->y = gastro_fix_div(p2p0, area); + bary->z = gastro_fix_div(p0p1, area); + return p0p1 <= 0 && p1p2 <= 0 && p2p0 <= 0; +} +void gastro_render_triangle(gastro_ctx *ctx, gastro_program *p, gastro_vertex n0, gastro_vertex n1, gastro_vertex n2, i64 attrs_len) { + /* assume clockwise winding order of points */ + /* p0 -> p1, p1 -> p2, p2 -> p0 */ + i64 x, y, minx, miny, maxx, maxy; + gastro_fix attrs[MAX_ATTRS]; + /* convert all points from -1 to 1 range (normalized) into pixels */ + gastro_vec3 p0 = gastro_vec3_denormalize(ctx, n0.v); gastro_vec2 v0 = gastro_vec3_xy(p0); + gastro_vec3 p1 = gastro_vec3_denormalize(ctx, n1.v); gastro_vec2 v1 = gastro_vec3_xy(p1); + gastro_vec3 p2 = gastro_vec3_denormalize(ctx, n2.v); gastro_vec2 v2 = gastro_vec3_xy(p2); + /* compute a bounding box for the triangle - we know only these pixels could possible be drawn */ + minx = min3(gastro_fix_to_i64(p0.x), gastro_fix_to_i64(p1.x), gastro_fix_to_i64(p2.x)); + maxx = max3(gastro_fix_to_i64(p0.x), gastro_fix_to_i64(p1.x), gastro_fix_to_i64(p2.x)); + miny = min3(gastro_fix_to_i64(p0.y), gastro_fix_to_i64(p1.y), gastro_fix_to_i64(p2.y)); + maxy = max3(gastro_fix_to_i64(p0.y), gastro_fix_to_i64(p1.y), gastro_fix_to_i64(p2.y)); + for (x = minx; x <= maxx; ++x) { /* for each pixel in the bounding box: */ + for (y = miny; y <= maxy; ++y) { + i64 idx = y * ctx->width + x; + /* consider the center of the pixel, not the top left corner */ + gastro_vec2 centered = gastro_vec2_new( + gastro_fix_new(x) + GASTRO_FIX_HALF, + gastro_fix_new(y) + GASTRO_FIX_HALF + ); + gastro_vec3 bary; + /* if the center of the pixel is in the triangle */ + if (triangle_contains(&bary, centered, v0, v1, v2)) { + i64 a; + gastro_color col; + /* find the depth of this pixel by using the barycentric coordinates */ + /* we must interpolate the reciprocals to be perspective-correct, since p0 etc. are already projected */ + /* i don't understand why this works very well yet */ + gastro_fix z = gastro_vec3_bary_interpolate_inv(bary, p0.z, p1.z, p2.z); + if (z > ctx->depth[idx]) continue; + gastro_vec3 interp_v = gastro_vec3_new( + gastro_vec3_bary_interpolate(bary, p0.x, p1.x, p2.x), + gastro_vec3_bary_interpolate(bary, p0.y, p1.y, p2.y), + z + ); + /* interpolate all of the attributes as well */ + /* again, to be perspective correct, we do some funny math */ + for (a = 0; a < attrs_len; ++a) { + gastro_fix n0z = gastro_fix_div(n0.attrs[a], p0.z); + gastro_fix n1z = gastro_fix_div(n1.attrs[a], p1.z); + gastro_fix n2z = gastro_fix_div(n2.attrs[a], p2.z); + attrs[a] = gastro_fix_mul( + z, + gastro_vec3_bary_interpolate(bary, n0z, n1z, n2z) + ); + } + /* actually compute the color for and write the pixel */ + col = gastro_program_fragment(ctx, p, interp_v, attrs, attrs_len); + gastro_draw_pixel(ctx, col, z, x, y); + ctx->pixels[idx] = col; + ctx->depth[idx] = z; + } + } + } +} + +static gastro_vertex get_vertex(gastro_ctx *ctx, gastro_program *p, gastro_fix *vs, i64 elem_size, i64 idx) { + i64 i = idx * elem_size; + return gastro_program_vertex(ctx, p, gastro_vec3_new(vs[i], vs[i+1], vs[i+2]), &vs[i+3], elem_size - 3); +} +void gastro_render_triangles(gastro_ctx *ctx, gastro_program *p, gastro_fix *vs, i64 elem_size, i64 *idxs, i64 num_triangles) { + i64 i; + for (i = 0; i < 3 * num_triangles; i += 3) { + gastro_vertex v0 = get_vertex(ctx, p, vs, elem_size, idxs[i]); + gastro_vertex v1 = get_vertex(ctx, p, vs, elem_size, idxs[i + 1]); + gastro_vertex v2 = get_vertex(ctx, p, vs, elem_size, idxs[i + 2]); + gastro_render_triangle(ctx, p, v0, v1, v2, elem_size - 3); + } +} diff --git a/gastro/src/main.c b/gastro/src/main.c new file mode 100644 index 0000000..af2e3aa --- /dev/null +++ b/gastro/src/main.c @@ -0,0 +1,242 @@ +#include +#include +#include +#include + +#include + +#include + +/* #include "../converted_model.h" */ + +i64 off = 0; +qoi_color *TEXTURE; +i64 TEXTURE_WIDTH; +i64 TEXTURE_HEIGHT; + +#define QUADIDX(p0, p1, p2, p3) p0, p1, p2, p2, p3, p0 +#define COLOR(r, g, b) gastro_fix_new(r), gastro_fix_new(g), gastro_fix_new(b) +static void draw_quad(gastro_ctx *ctx, gastro_program *p) { + gastro_fix sz = GASTRO_FIX_HALF; + gastro_fix verts[] = { + /* front */ + -sz, -sz, -sz, 0, 0, + +sz, -sz, -sz, GASTRO_FIX_ONE, 0, + +sz, +sz, -sz, GASTRO_FIX_ONE, GASTRO_FIX_ONE, + -sz, +sz, -sz, 0, GASTRO_FIX_ONE + }; + i64 idxs[] = { + QUADIDX(0, 1, 2, 3), /* front */ + }; + gastro_render_triangles(ctx, p, verts, 5, idxs, 2); +} +static void draw_cube(gastro_ctx *ctx, gastro_program *p) { + static gastro_fix verts[] = { + /* front */ + -GASTRO_FIX_HALF, -GASTRO_FIX_HALF, -GASTRO_FIX_HALF, 0, 0, + +GASTRO_FIX_HALF, -GASTRO_FIX_HALF, -GASTRO_FIX_HALF, GASTRO_FIX_ONE, 0, + +GASTRO_FIX_HALF, +GASTRO_FIX_HALF, -GASTRO_FIX_HALF, GASTRO_FIX_ONE, GASTRO_FIX_ONE, + -GASTRO_FIX_HALF, +GASTRO_FIX_HALF, -GASTRO_FIX_HALF, 0, GASTRO_FIX_ONE, + /* right */ + +GASTRO_FIX_HALF, -GASTRO_FIX_HALF, -GASTRO_FIX_HALF, 0, 0, + +GASTRO_FIX_HALF, -GASTRO_FIX_HALF, +GASTRO_FIX_HALF, GASTRO_FIX_ONE, 0, + +GASTRO_FIX_HALF, +GASTRO_FIX_HALF, +GASTRO_FIX_HALF, GASTRO_FIX_ONE, GASTRO_FIX_ONE, + +GASTRO_FIX_HALF, +GASTRO_FIX_HALF, -GASTRO_FIX_HALF, 0, GASTRO_FIX_ONE, + /* left */ + -GASTRO_FIX_HALF, -GASTRO_FIX_HALF, +GASTRO_FIX_HALF, 0, 0, + -GASTRO_FIX_HALF, -GASTRO_FIX_HALF, -GASTRO_FIX_HALF, GASTRO_FIX_ONE, 0, + -GASTRO_FIX_HALF, +GASTRO_FIX_HALF, -GASTRO_FIX_HALF, GASTRO_FIX_ONE, GASTRO_FIX_ONE, + -GASTRO_FIX_HALF, +GASTRO_FIX_HALF, +GASTRO_FIX_HALF, 0, GASTRO_FIX_ONE, + /* top */ + -GASTRO_FIX_HALF, -GASTRO_FIX_HALF, +GASTRO_FIX_HALF, 0, 0, + +GASTRO_FIX_HALF, -GASTRO_FIX_HALF, +GASTRO_FIX_HALF, GASTRO_FIX_ONE, 0, + +GASTRO_FIX_HALF, -GASTRO_FIX_HALF, -GASTRO_FIX_HALF, GASTRO_FIX_ONE, GASTRO_FIX_ONE, + -GASTRO_FIX_HALF, -GASTRO_FIX_HALF, -GASTRO_FIX_HALF, 0, GASTRO_FIX_ONE, + /* bottom */ + -GASTRO_FIX_HALF, +GASTRO_FIX_HALF, -GASTRO_FIX_HALF, 0, 0, + +GASTRO_FIX_HALF, +GASTRO_FIX_HALF, -GASTRO_FIX_HALF, GASTRO_FIX_ONE, 0, + +GASTRO_FIX_HALF, +GASTRO_FIX_HALF, +GASTRO_FIX_HALF, GASTRO_FIX_ONE, GASTRO_FIX_ONE, + -GASTRO_FIX_HALF, +GASTRO_FIX_HALF, +GASTRO_FIX_HALF, 0, GASTRO_FIX_ONE, + /* back */ + +GASTRO_FIX_HALF, -GASTRO_FIX_HALF, +GASTRO_FIX_HALF, 0, 0, + -GASTRO_FIX_HALF, -GASTRO_FIX_HALF, +GASTRO_FIX_HALF, GASTRO_FIX_ONE, 0, + -GASTRO_FIX_HALF, +GASTRO_FIX_HALF, +GASTRO_FIX_HALF, GASTRO_FIX_ONE, GASTRO_FIX_ONE, + +GASTRO_FIX_HALF, +GASTRO_FIX_HALF, +GASTRO_FIX_HALF, 0, GASTRO_FIX_ONE + }; + static i64 idxs[] = { + QUADIDX(0, 1, 2, 3), /* front */ + QUADIDX(4, 5, 6, 7), /* right */ + QUADIDX(8, 9, 10, 11), /* left */ + QUADIDX(12, 13, 14, 15), /* top */ + QUADIDX(16, 17, 18, 19), /* bottom */ + QUADIDX(20, 21, 22, 23) /* back */ + }; + gastro_render_triangles(ctx, p, verts, 5, idxs, 12); +} +static void draw_pyramid(gastro_ctx *ctx, gastro_program *p) { + static gastro_fix verts[] = { + /* front */ + 0, +GASTRO_FIX_HALF, 0, 0, 0, + +GASTRO_FIX_HALF, -GASTRO_FIX_HALF, -GASTRO_FIX_HALF, GASTRO_FIX_ONE, 0, + -GASTRO_FIX_HALF, -GASTRO_FIX_HALF, -GASTRO_FIX_HALF, GASTRO_FIX_ONE, GASTRO_FIX_ONE, + /* right */ + 0, +GASTRO_FIX_HALF, 0, 0, 0, + +GASTRO_FIX_HALF, -GASTRO_FIX_HALF, +GASTRO_FIX_HALF, GASTRO_FIX_ONE, 0, + +GASTRO_FIX_HALF, -GASTRO_FIX_HALF, -GASTRO_FIX_HALF, GASTRO_FIX_ONE, GASTRO_FIX_ONE, + /* left */ + 0, +GASTRO_FIX_HALF, 0, 0, 0, + -GASTRO_FIX_HALF, -GASTRO_FIX_HALF, -GASTRO_FIX_HALF, GASTRO_FIX_ONE, 0, + -GASTRO_FIX_HALF, -GASTRO_FIX_HALF, +GASTRO_FIX_HALF, GASTRO_FIX_ONE, GASTRO_FIX_ONE, + /* back */ + 0, +GASTRO_FIX_HALF, 0, 0, 0, + -GASTRO_FIX_HALF, -GASTRO_FIX_HALF, +GASTRO_FIX_HALF, GASTRO_FIX_ONE, 0, + +GASTRO_FIX_HALF, -GASTRO_FIX_HALF, +GASTRO_FIX_HALF, GASTRO_FIX_ONE, GASTRO_FIX_ONE, + /* bottom */ + -GASTRO_FIX_HALF, -GASTRO_FIX_HALF, -GASTRO_FIX_HALF, 0, 0, + +GASTRO_FIX_HALF, -GASTRO_FIX_HALF, -GASTRO_FIX_HALF, GASTRO_FIX_ONE, 0, + +GASTRO_FIX_HALF, -GASTRO_FIX_HALF, +GASTRO_FIX_HALF, GASTRO_FIX_ONE, GASTRO_FIX_ONE, + -GASTRO_FIX_HALF, -GASTRO_FIX_HALF, +GASTRO_FIX_HALF, 0, GASTRO_FIX_ONE, + }; + static i64 idxs[] = { + 0, 1, 2, + 3, 4, 5, + 6, 7, 8, + 9, 10, 11, + QUADIDX(12, 13, 14, 15), + }; + gastro_render_triangles(ctx, p, verts, 5, idxs, 6); +} + +static gastro_vec4 vertex_shader(gastro_ctx *ctx, gastro_vec3 in, gastro_fix *attrs, i64 attrs_len) { + gastro_fix x = gastro_fix_from_double((double) off / 1000.0); + gastro_vec4 v = gastro_vec4_new(in.x, in.y, in.z, GASTRO_FIX_ONE); + gastro_mat4x4 scale = gastro_mat4x4_new( + gastro_fix_from_double(1.0), 0, 0, 0, + 0, gastro_fix_from_double(1.0), 0, 0, + 0, 0, gastro_fix_from_double(1.0), 0, + 0, 0, 0, GASTRO_FIX_ONE + ); + u8 theta = (u8) (off / 4); + /* u8 theta = 13; */ + gastro_mat4x4 rot = gastro_mat4x4_new( + GASTRO_FIX_ONE, 0, 0, 0, + 0, gastro_cos(theta), -gastro_sin(theta), 0, + 0, gastro_sin(theta), gastro_cos(theta), 0, + 0, 0, 0, GASTRO_FIX_ONE + ); + gastro_mat4x4 trans = gastro_mat4x4_new( + GASTRO_FIX_ONE, 0, 0, gastro_fix_new(0), /* x,*/ + 0, GASTRO_FIX_ONE, 0, gastro_fix_new(1), + 0, 0, GASTRO_FIX_ONE, gastro_fix_new(-3), + 0, 0, 0, GASTRO_FIX_ONE + ); + gastro_mat4x4 proj = gastro_mat4x4_new( + GASTRO_FIX_ONE, 0, 0, 0, + 0, GASTRO_FIX_ONE, 0, 0, + 0, 0, GASTRO_FIX_ONE, 0, + 0, 0, GASTRO_FIX_ONE, 0 + ); + v = gastro_mat4x4_mul_vec4(scale, v); + v = gastro_mat4x4_mul_vec4(rot, v); + v = gastro_mat4x4_mul_vec4(trans, v); + v = gastro_mat4x4_mul_vec4(proj, v); + return v; +} + +static gastro_color fragment_shader_texture(gastro_ctx *ctx, gastro_vec3 in, gastro_fix *attrs, i64 attrs_len) { + gastro_fix u = attrs[0]; + gastro_fix v = attrs[1]; + i64 x = gastro_fix_to_i64(gastro_fix_mul(gastro_fix_new(TEXTURE_WIDTH), u)); + i64 y = gastro_fix_to_i64(gastro_fix_mul(gastro_fix_new(TEXTURE_HEIGHT), v)); + qoi_color c = TEXTURE[y * TEXTURE_WIDTH + x]; + return gastro_color_new(c.r, c.g, c.b, c.a); +} + +static gastro_color fragment_shader_teapot(gastro_ctx *ctx, gastro_vec3 in, gastro_fix *attrs, i64 attrs_len) { + u8 col = (u8) gastro_fix_to_i64( + gastro_fix_mul( + gastro_fix_new(0xff), + gastro_fix_div(in.z, gastro_fix_new(8)) + ) + ); + return gastro_color_new(0xff - col, 0xff - col, 0xff - col, 0xff); +} + +void load_image(char *path) { + FILE *f; + u8 *buf; + i64 len; + qoi_decoder q; + qoi_header h; + qoi_color *pixels; + if (!(f = fopen(path, "r"))) { + fprintf(stderr, "failed to open file: %s\n", path); + return; + } + fseek(f, 0, SEEK_END); + len = ftell(f); + fseek(f, 0, SEEK_SET); + buf = calloc((size_t) len, sizeof(u8)); + fread(buf, sizeof(u8), (size_t) len, f); + qoi_decoder_new(&q, buf, len); + if (!qoi_decode_header(&q, &h)) { + fprintf(stderr, "failed to decode header\n"); + return; + } + pixels = calloc(h.width * h.height, sizeof(qoi_color)); + qoi_decode(&q, &h, pixels); + TEXTURE = pixels; + TEXTURE_WIDTH = h.width; + TEXTURE_HEIGHT = h.height; +} + +int main(int argc, char **argv) { + gastro_ctx ctx; + u32 width = 256, height = 256; + gastro_color *pixels = calloc(width * height, sizeof(gastro_color)); + gastro_fix *depth = calloc(width * height, sizeof(gastro_fix)); + gastro_program p; + gastro_ctx_init(&ctx, width, height, pixels, depth); + p.vertex = vertex_shader; + p.fragment = fragment_shader_texture; + + load_image("mark2.qoi"); + + /* gastro_draw_clear(&ctx, gastro_color_new(0, 0, 0, 0xff)); */ + /* draw_model(&ctx, &p); */ + + InitWindow(800, 600, "test"); + { + Image im; + Texture2D tex; + im.data = ctx.pixels; + im.width = (int) ctx.width; + im.height = (int) ctx.height; + im.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; + im.mipmaps = 1; + tex = LoadTextureFromImage(im); + SetTargetFPS(300); + while (!WindowShouldClose()) { + i64 i; + Vector2 pos; + pos.x = 10; pos.y = 10; + gastro_draw_clear(&ctx, gastro_color_new(0, 0, 0, 0xff)); + for (i = 0; i < 1; ++i) { + draw_pyramid(&ctx, &p); + } + /* draw_quad(&ctx, &p); */ + /* draw_model(&ctx, &p); */ + off += 1; + off %= 256 * 64; + BeginDrawing(); + ClearBackground(RED); + UpdateTexture(tex, ctx.pixels); + DrawTextureEx(tex, pos, 0.0, 4.0, WHITE); + DrawFPS(10, 10); + EndDrawing(); + } + } + CloseWindow(); + (void) argc; (void) argv; + return 0; +} diff --git a/gastro/src/trig.c b/gastro/src/trig.c new file mode 100644 index 0000000..7f838c1 --- /dev/null +++ b/gastro/src/trig.c @@ -0,0 +1,268 @@ +#include + +static gastro_fix SIN_TABLE[256] = { + 0x0, + 0x648, + 0xc8f, + 0x12d5, + 0x1917, + 0x1f56, + 0x2590, + 0x2bc4, + 0x31f1, + 0x3817, + 0x3e33, + 0x4447, + 0x4a50, + 0x504d, + 0x563e, + 0x5c22, + 0x61f7, + 0x67bd, + 0x6d74, + 0x7319, + 0x78ad, + 0x7e2e, + 0x839c, + 0x88f5, + 0x8e39, + 0x9368, + 0x987f, + 0x9d7f, + 0xa267, + 0xa736, + 0xabeb, + 0xb085, + 0xb504, + 0xb968, + 0xbdae, + 0xc1d8, + 0xc5e4, + 0xc9d1, + 0xcd9f, + 0xd14d, + 0xd4db, + 0xd848, + 0xdb94, + 0xdebe, + 0xe1c5, + 0xe4aa, + 0xe76b, + 0xea09, + 0xec83, + 0xeed8, + 0xf109, + 0xf314, + 0xf4fa, + 0xf6ba, + 0xf853, + 0xf9c7, + 0xfb14, + 0xfc3b, + 0xfd3a, + 0xfe13, + 0xfec4, + 0xff4e, + 0xffb1, + 0xffec, + 0xffff, + 0xffec, + 0xffb1, + 0xff4e, + 0xfec4, + 0xfe13, + 0xfd3a, + 0xfc3b, + 0xfb14, + 0xf9c7, + 0xf853, + 0xf6ba, + 0xf4fa, + 0xf314, + 0xf109, + 0xeed8, + 0xec83, + 0xea09, + 0xe76b, + 0xe4aa, + 0xe1c5, + 0xdebe, + 0xdb94, + 0xd848, + 0xd4db, + 0xd14d, + 0xcd9f, + 0xc9d1, + 0xc5e4, + 0xc1d8, + 0xbdae, + 0xb968, + 0xb504, + 0xb085, + 0xabeb, + 0xa736, + 0xa267, + 0x9d7f, + 0x987f, + 0x9368, + 0x8e39, + 0x88f5, + 0x839c, + 0x7e2e, + 0x78ad, + 0x7319, + 0x6d74, + 0x67bd, + 0x61f7, + 0x5c22, + 0x563e, + 0x504d, + 0x4a50, + 0x4447, + 0x3e33, + 0x3817, + 0x31f1, + 0x2bc4, + 0x2590, + 0x1f56, + 0x1917, + 0x12d5, + 0xc8f, + 0x648, + 0x0, + (i64) 0xfffffffffffff9b8, + (i64) 0xfffffffffffff371, + (i64) 0xffffffffffffed2b, + (i64) 0xffffffffffffe6e9, + (i64) 0xffffffffffffe0aa, + (i64) 0xffffffffffffda70, + (i64) 0xffffffffffffd43c, + (i64) 0xffffffffffffce0f, + (i64) 0xffffffffffffc7e9, + (i64) 0xffffffffffffc1cd, + (i64) 0xffffffffffffbbb9, + (i64) 0xffffffffffffb5b0, + (i64) 0xffffffffffffafb3, + (i64) 0xffffffffffffa9c2, + (i64) 0xffffffffffffa3de, + (i64) 0xffffffffffff9e09, + (i64) 0xffffffffffff9843, + (i64) 0xffffffffffff928c, + (i64) 0xffffffffffff8ce7, + (i64) 0xffffffffffff8753, + (i64) 0xffffffffffff81d2, + (i64) 0xffffffffffff7c64, + (i64) 0xffffffffffff770b, + (i64) 0xffffffffffff71c7, + (i64) 0xffffffffffff6c98, + (i64) 0xffffffffffff6781, + (i64) 0xffffffffffff6281, + (i64) 0xffffffffffff5d99, + (i64) 0xffffffffffff58ca, + (i64) 0xffffffffffff5415, + (i64) 0xffffffffffff4f7b, + (i64) 0xffffffffffff4afc, + (i64) 0xffffffffffff4698, + (i64) 0xffffffffffff4252, + (i64) 0xffffffffffff3e28, + (i64) 0xffffffffffff3a1c, + (i64) 0xffffffffffff362f, + (i64) 0xffffffffffff3261, + (i64) 0xffffffffffff2eb3, + (i64) 0xffffffffffff2b25, + (i64) 0xffffffffffff27b8, + (i64) 0xffffffffffff246c, + (i64) 0xffffffffffff2142, + (i64) 0xffffffffffff1e3b, + (i64) 0xffffffffffff1b56, + (i64) 0xffffffffffff1895, + (i64) 0xffffffffffff15f7, + (i64) 0xffffffffffff137d, + (i64) 0xffffffffffff1128, + (i64) 0xffffffffffff0ef7, + (i64) 0xffffffffffff0cec, + (i64) 0xffffffffffff0b06, + (i64) 0xffffffffffff0946, + (i64) 0xffffffffffff07ad, + (i64) 0xffffffffffff0639, + (i64) 0xffffffffffff04ec, + (i64) 0xffffffffffff03c5, + (i64) 0xffffffffffff02c6, + (i64) 0xffffffffffff01ed, + (i64) 0xffffffffffff013c, + (i64) 0xffffffffffff00b2, + (i64) 0xffffffffffff004f, + (i64) 0xffffffffffff0014, + (i64) 0xffffffffffff0001, + (i64) 0xffffffffffff0014, + (i64) 0xffffffffffff004f, + (i64) 0xffffffffffff00b2, + (i64) 0xffffffffffff013c, + (i64) 0xffffffffffff01ed, + (i64) 0xffffffffffff02c6, + (i64) 0xffffffffffff03c5, + (i64) 0xffffffffffff04ec, + (i64) 0xffffffffffff0639, + (i64) 0xffffffffffff07ad, + (i64) 0xffffffffffff0946, + (i64) 0xffffffffffff0b06, + (i64) 0xffffffffffff0cec, + (i64) 0xffffffffffff0ef7, + (i64) 0xffffffffffff1128, + (i64) 0xffffffffffff137d, + (i64) 0xffffffffffff15f7, + (i64) 0xffffffffffff1895, + (i64) 0xffffffffffff1b56, + (i64) 0xffffffffffff1e3b, + (i64) 0xffffffffffff2142, + (i64) 0xffffffffffff246c, + (i64) 0xffffffffffff27b8, + (i64) 0xffffffffffff2b25, + (i64) 0xffffffffffff2eb3, + (i64) 0xffffffffffff3261, + (i64) 0xffffffffffff362f, + (i64) 0xffffffffffff3a1c, + (i64) 0xffffffffffff3e28, + (i64) 0xffffffffffff4252, + (i64) 0xffffffffffff4698, + (i64) 0xffffffffffff4afc, + (i64) 0xffffffffffff4f7b, + (i64) 0xffffffffffff5415, + (i64) 0xffffffffffff58ca, + (i64) 0xffffffffffff5d99, + (i64) 0xffffffffffff6281, + (i64) 0xffffffffffff6781, + (i64) 0xffffffffffff6c98, + (i64) 0xffffffffffff71c7, + (i64) 0xffffffffffff770b, + (i64) 0xffffffffffff7c64, + (i64) 0xffffffffffff81d2, + (i64) 0xffffffffffff8753, + (i64) 0xffffffffffff8ce7, + (i64) 0xffffffffffff928c, + (i64) 0xffffffffffff9843, + (i64) 0xffffffffffff9e09, + (i64) 0xffffffffffffa3de, + (i64) 0xffffffffffffa9c2, + (i64) 0xffffffffffffafb3, + (i64) 0xffffffffffffb5b0, + (i64) 0xffffffffffffbbb9, + (i64) 0xffffffffffffc1cd, + (i64) 0xffffffffffffc7e9, + (i64) 0xffffffffffffce0f, + (i64) 0xffffffffffffd43c, + (i64) 0xffffffffffffda70, + (i64) 0xffffffffffffe0aa, + (i64) 0xffffffffffffe6e9, + (i64) 0xffffffffffffed2b, + (i64) 0xfffffffffffff371, + (i64) 0xfffffffffffff9b8 +}; + +gastro_fix gastro_sin(u8 turns) { + return SIN_TABLE[turns]; +} + +gastro_fix gastro_cos(u8 turns) { + return SIN_TABLE[(u8) (turns + 64)]; +} -- cgit v1.3.1