summaryrefslogtreecommitdiff
path: root/stage3/cheese3d.c
diff options
context:
space:
mode:
authorLizzy Fleckenstein <lizzy@vlhl.dev>2023-12-22 23:26:21 +0100
committerLizzy Fleckenstein <lizzy@vlhl.dev>2023-12-22 23:26:21 +0100
commit8ed1362368dc064fa35bf879c1f905165b990de8 (patch)
treef8369b0332b760d5c5b20a8b919be155c5b9464c /stage3/cheese3d.c
parent13293ec3238b62c66d323b82e595e860e193b6ed (diff)
downloadcuddles-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.c148
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);
+}