summaryrefslogtreecommitdiff
path: root/src/scene.c
diff options
context:
space:
mode:
authorLizzy Fleckenstein <lizzy@vlhl.dev>2026-04-12 20:57:06 +0200
committerLizzy Fleckenstein <lizzy@vlhl.dev>2026-04-12 20:59:39 +0200
commite5af28536bfb0f4c9131df56d2009ba5196f5e3a (patch)
tree3ab928f961a1ccd8440b070d7b57f79146457e8c /src/scene.c
downloadanimtool-e5af28536bfb0f4c9131df56d2009ba5196f5e3a.tar.xz
init
Diffstat (limited to 'src/scene.c')
-rw-r--r--src/scene.c197
1 files changed, 197 insertions, 0 deletions
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 <stdlib.h>
+#include <stdio.h>
+#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(&reg->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(&reg->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(&reg->default_camera->target, src, reg);
+ for (size_t i = 0; i < reg->cameras.len; i++)
+ bind_pos(&reg->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);
+}