diff options
author | Lizzy Fleckenstein <lizzy@vlhl.dev> | 2023-12-22 23:26:21 +0100 |
---|---|---|
committer | Lizzy Fleckenstein <lizzy@vlhl.dev> | 2023-12-22 23:26:21 +0100 |
commit | 8ed1362368dc064fa35bf879c1f905165b990de8 (patch) | |
tree | f8369b0332b760d5c5b20a8b919be155c5b9464c /stage3/cheese3d.c | |
parent | 13293ec3238b62c66d323b82e595e860e193b6ed (diff) | |
download | cuddles-8ed1362368dc064fa35bf879c1f905165b990de8.tar.xz |
add rotating cheese
This adds the Cheese3D graphics api and makes the cheese command display a cheese rotating in 3d as a demo
Diffstat (limited to 'stage3/cheese3d.c')
-rw-r--r-- | stage3/cheese3d.c | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/stage3/cheese3d.c b/stage3/cheese3d.c new file mode 100644 index 0000000..154ce58 --- /dev/null +++ b/stage3/cheese3d.c @@ -0,0 +1,148 @@ +#include "heap.h" +#include "math3d.h" +#include "cheese3d.h" +#include "gfx.h" +#include "memory.h" + +cheese3d_ctx cheese3d_create(u32 width, u32 height, u32 pitch, u32 bgcolor) +{ + return (cheese3d_ctx) { + .width = width, + .height = height, + .pitch = pitch, + .bgcolor = bgcolor, + .depth_buffer = malloc(gfx_info->width * gfx_info->height * sizeof(u32)), + .color_buffer = malloc(gfx_info->pitch * gfx_info->height), + }; +} + +cheese3d_ctx cheese3d_create_default(u32 bgcolor) +{ + return cheese3d_create(gfx_info->width, gfx_info->height, gfx_info->pitch, bgcolor); +} + +void cheese3d_destroy(cheese3d_ctx ctx) +{ + free(ctx.depth_buffer); + free(ctx.color_buffer); +} + +void cheese3d_clear(cheese3d_ctx ctx, bool color, bool depth) +{ + for (u32 x = 0; x < gfx_info->width; x++) + for (u32 y = 0; y < gfx_info->height; y++) { + if (color) ctx.depth_buffer[y * ctx.width + x] = 0.0; + if (depth) *(u32 *) (ctx.color_buffer + y * ctx.pitch + x * sizeof(u32)) = ctx.bgcolor; + } +} + +void cheese3d_render(cheese3d_ctx ctx, usize num, vertex *vertices, texture *textures, float transform[4][4]) +{ + for (usize i = 0; i < num; i += 3) { + float verts[3][4]; + float min[2]; + float max[2]; + + for (usize j = 0; j < 3; j++) { + float coord[4]; + for (int k = 0; k < 3; k++) + coord[k] = vertices[i+j].pos[k]; + coord[3] = 1.0; + + mat_mul_vec(transform, coord); + + verts[j][3] = 1/coord[3]; + for (int k = 0; k < 3; k++) + verts[j][k] = coord[k] * verts[j][3]; + + for (int k = 0; k < 2; k++) { + if (j == 0 || verts[j][k] > max[k]) + max[k] = verts[j][k]; + if (j == 0 || verts[j][k] < min[k]) + min[k] = verts[j][k]; + } + } + + // cull clockwise faces + float area = tri_area(verts[0], verts[1], verts[2]); + if (area < 0) + continue; + + i32 i_min[2]; + i32 i_max[2]; + for (int k = 0; k < 2; k++) { + i32 size = k ? gfx_info->height : gfx_info->width; + + i_min[k] = (0.5 + 0.5 * min[k]) * size; + i_max[k] = (0.5 + 0.5 * max[k]) * size; + + if (i_max[k] >= size) + i_max[k] = size-1; + if (i_min[k] < 0) + i_min[k] = 0; + } + + for (i32 y = i_min[1]; y <= i_max[1]; y++) { + float point[2] = { + 0.0, + (float) y / gfx_info->height * 2.0 - 1.0 + }; + for (i32 x = i_min[0]; x <= i_max[0]; x++) { + point[0] = (float) x / gfx_info->width * 2.0 - 1.0; + + float weights[3]; + if ((weights[0] = tri_area(point, verts[1], verts[2])) < 0) + continue; + if ((weights[1] = tri_area(verts[0], point, verts[2])) < 0) + continue; + if ((weights[2] = tri_area(verts[0], verts[1], point)) < 0) + continue; + + float depth = 0.0; + float w = 0.0; + float tex[2] = { 0.0, 0.0 }; + + for (int j = 0; j < 3; j++) { + weights[j] /= area; + + depth += weights[j] * verts[j][2]; + w += weights[j] * verts[j][3]; + tex[0] += weights[j] * verts[j][3] * vertices[i+j].tex[0]; + tex[1] += weights[j] * verts[j][3] * vertices[i+j].tex[1]; + } + + tex[0] /= w; + tex[1] /= w; + + float *d = &ctx.depth_buffer[y * ctx.width + x]; + if (*d > depth) + continue; + *d = depth; + + texture *t = &textures[i]; + + i32 i_tex[2]; + for (int k = 0; k < 2; k++) { + i32 size = k ? t->h : t->w; + + i_tex[k] = tex[k] * size; + + if (i_tex[k] >= size) + i_tex[k] = size-1; + if (i_tex[k] < 0) + i_tex[k] = 0; + } + + *(u32 *) (ctx.color_buffer + y * ctx.pitch + x * sizeof(u32)) = + t->data[i_tex[1]*t->w+i_tex[0]]; + } + } + + } + +} + +void cheese3d_display(cheese3d_ctx ctx) +{ + memcpy((void *) (u64) gfx_info->framebuffer, ctx.color_buffer, gfx_info->pitch * gfx_info->height); +} |