From e5af28536bfb0f4c9131df56d2009ba5196f5e3a Mon Sep 17 00:00:00 2001 From: Lizzy Fleckenstein Date: Sun, 12 Apr 2026 20:57:06 +0200 Subject: init --- src/scene.c | 197 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100644 src/scene.c (limited to 'src/scene.c') diff --git a/src/scene.c b/src/scene.c new file mode 100644 index 0000000..645c30e --- /dev/null +++ b/src/scene.c @@ -0,0 +1,197 @@ +#include +#include +#include "util/err.h" +#include "scene.h" + +void proj_default(struct projection *proj, enum projection_type type) +{ + proj->type = type; + switch (type) { + case PROJ_PERSPECTIVE: + proj->perspective.fov.type = EXPR_NUMBER; + proj->perspective.fov.number = 45.0; + proj->perspective.planes[0] = 0.1f; + proj->perspective.planes[1] = 100.0f; + break; + case PROJ_ORTHO: { + float planes[6] = { -1.f, +1.f, -1.f, 1.f, 1.f, -1.f }; + memcpy(proj->ortho.planes, planes, sizeof planes); + break; + } + } +} + +void proj_free(struct projection *proj) +{ + if (proj->type == PROJ_PERSPECTIVE) + expr_free(&proj->perspective.fov); +} + +void surface_init(struct surface *surf) +{ + surf->texture.present = false; + surf->color.type = EXPR_NUMBER; + surf->color.number = 0xffffff; +} + +void registry_free(struct registry *reg) +{ + free(reg->raw_vars.ptr); + free(reg->vars.ptr); + free(reg->cameras.ptr); + free(reg->bones.ptr); +} + + +// - transform, - camera (pos) - surface (color) - projection fov +void scene_init(struct scene *scene) +{ + *scene = (struct scene) { + .fps = 25, + .size = { 100, 100 }, + .root = { .type = NODE_TRANSFORM }, + }; + proj_default(&scene->proj, PROJ_PERSPECTIVE); +} + +static void free_seq(size_t n_inst, struct seq_inst inst[n_inst]) +{ + for (size_t i = 0; i < n_inst; i++) + if (inst[i].type == SEQ_REP) + free_seq(inst[i].rep.children.len, inst[i].rep.children.ptr); + free(inst); +} + +static void free_surface(struct surface *surf) +{ + expr_free(&surf->color); +} + +static void free_pos(struct pos *pos) +{ + if (pos->type == POS_ABSOLUTE) + for (size_t i = 0; i < 3; i++) + expr_free(&pos->absolute[i]); +} + +static void free_node(struct node *node) +{ + switch (node->type) { + case NODE_TRANSFORM: + for (enum transform_op op = 0; op < TRANSFORM_OPS_N; op++) + for (size_t i = 0; i < 3; i++) + if (node->transform.has_op[op][i]) + expr_free(&node->transform.op[op][i]); + for (size_t i = 0; i < node->transform.children.len; i++) + free_node(&node->transform.children.ptr[i]); + free(node->transform.children.ptr); + break; + case NODE_CAMERA: + free_pos(&node->camera.target); + break; + case NODE_OBJECT: + free_surface(&node->object.surface); + break; + case NODE_LIGHT: + case NODE_BONE: + break; + } +} + +void scene_free(struct scene *scene) +{ + free_seq(scene->seq.len, scene->seq.ptr); + free_node(&scene->root); + proj_free(&scene->proj); + if (scene->bg.present) + free_surface(&scene->bg.data); +} + +static void bind_pos(struct pos *pos, struct source *src, struct registry *reg) +{ + if (pos->type != POS_ATTACHED) + return; + struct bone **bone = nullptr; + map_find(®->bones, pos->attach_name.str, &bone); + if (!bone) + source_error(src, pos->attach_name.loc, "bone not found"); + pos->attach = *bone; +} + +static void bind_seq(size_t n_inst, struct seq_inst inst[n_inst], struct source *src, struct registry *reg) +{ + for (size_t i = 0; i < n_inst; i++) { + switch (inst[i].type) { + case SEQ_POV: + struct camera **camera = nullptr; + map_find(®->cameras, inst[i].pov_name.str, &camera); + if (!camera) + source_error(src, inst[i].pov_name.loc, "camera not found"); + inst[i].pov = *camera; + break; + case SEQ_REP: + bind_seq(inst[i].rep.children.len, inst[i].rep.children.ptr, src, reg); + break; + default: + break; + } + } +} + +static bool seq_begins_pov(size_t n_inst, struct seq_inst inst[n_inst]) +{ + if (n_inst < 1) return false; + switch (inst[0].type) { + case SEQ_TIME: return false; + case SEQ_POV: return true; + case SEQ_REP: return inst[0].rep.times > 0 + && seq_begins_pov(inst[0].rep.children.len, inst[0].rep.children.ptr); + } + return false; // unreachable +} + +void scene_bind(struct scene *scene, struct source *src, struct registry *reg) +{ + if (reg->default_camera) + bind_pos(®->default_camera->target, src, reg); + for (size_t i = 0; i < reg->cameras.len; i++) + bind_pos(®->cameras.ptr[i].val->target, src, reg); + + bind_seq(scene->seq.len, scene->seq.ptr, src, reg); + + if (reg->default_camera) + scene->camera = reg->default_camera; + else if (!seq_begins_pov(scene->seq.len, scene->seq.ptr)) + eprintf("sequence does not begin with a pov command and no unnamed camera found\n"); +} + +static void load_surface(struct surface *surf, struct source *src, struct draw_backend *draw, struct cache *cache) +{ + if (surf->texture.present) + texture_load(&surf->texture.data, src, draw, cache); +} + +static void load_node(struct node *node, struct source *src, struct draw_backend *draw, struct cache *cache) +{ + switch (node->type) { + case NODE_TRANSFORM: + for (size_t i = 0; i < node->transform.children.len; i++) + load_node(&node->transform.children.ptr[i], src, draw, cache); + break; + case NODE_OBJECT: + load_surface(&node->object.surface, src, draw, cache); + mesh_load(&node->object.mesh, src, draw, cache); + break; + default: + break; + } +} + +void scene_load(struct scene *scene, struct source *src, struct draw_backend *draw) +{ + struct cache cache = {}; + load_node(&scene->root, src, draw, &cache); + if (scene->bg.present) + load_surface(&scene->bg.data, src, draw, &cache); + cache_free(&cache); +} -- cgit v1.2.3