#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); } 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); }