polyadvent

A game engine from scratch in C
git clone git://jb55.com/polyadvent
Log | Files | Refs | README

node.c (5645B)


      1 
      2 
      3 #include "node.h"
      4 #include "mat_util.h"
      5 #include "debug.h"
      6 #include "static_resources.h"
      7 #include <string.h>
      8 #include <stdio.h>
      9 #include <assert.h>
     10 #include <stdint.h>
     11 
     12 struct resource_manager node_manager = {0};
     13 
     14 static inline struct node *new_uninitialized_node(node_id *id)
     15 {
     16     return new_resource(&node_manager, id);
     17 }
     18 
     19 struct node *new_node(node_id *id)
     20 {
     21     struct node *n = node_init(new_uninitialized_node(id));
     22     assert((int64_t)id->uuid != -1);
     23     /* debug("new node %llu\n", id->uuid); */
     24     return n;
     25 }
     26 
     27 struct node *get_node(node_id *id)
     28 {
     29     return get_resource(&node_manager, id);
     30 }
     31 
     32 void destroy_node(node_id *id)
     33 {
     34 #ifdef DEBUG
     35     struct node *node = get_node(id);
     36     debug("destroying node %llu %s\n", id->uuid, node->label);
     37 #endif
     38 
     39     destroy_resource(&node_manager, id);
     40 }
     41 
     42 void init_node_manager()
     43 {
     44     init_resource_manager(&node_manager, sizeof(struct node), 4096,
     45                           0xFFFF, "node", N_STATIC_NODES);
     46 
     47     for (int i = 0; i < N_STATIC_NODES; i++)
     48         node_init(&static_nodes()[i]);
     49 }
     50 
     51 struct node *node_init(struct node *node) {
     52   mat4_id(node->mat);
     53   vec3_all(node->pos, 0);
     54   vec3_all(node->rot, 0);
     55   vec3_all(node->scale, 1.0);
     56   quat_id(node->orientation);
     57   node->n_children = 0;
     58   for (int i = 0; i < MAX_NODE_CHILDREN; ++i)
     59       init_id(&node->children_ids[i]);
     60   node->flags = 0;
     61   null_id(&node->parent_id);
     62   node_set_label(node, "unknown");
     63   node->needs_recalc = 0;
     64   node->custom_update = 0;
     65   node_mark_for_recalc(node);
     66 
     67   return node;
     68 }
     69 
     70 int node_set_label(struct node *node, const char *label)
     71 {
     72     strncpy(node->label, label, sizeof(node->label)-1);
     73     // return 0 if the string is too big and that we've truncated it
     74     int ok = node->label[sizeof(node->label)-1] == '\0';
     75     // strncpy won't write this for large strings =/
     76     node->label[sizeof(node->label)-1] = '\0';
     77     return ok;
     78 }
     79 
     80 void node_scale(struct node *node, float val) {
     81     vec3_scale(node->scale, val, node->scale);
     82 }
     83 
     84 void node_translate(struct node *node, vec3 *p) {
     85   if (vec3_isall(p, 0))
     86       return;
     87 
     88   /* printf("translating %f %f %f\n", p[0], p[1], p[2]); */
     89   vec3_add(node->pos, p, node->pos);
     90   node_mark_for_recalc(node);
     91 }
     92 
     93 void node_rotate(struct node *node, vec3 *axis_angles) {
     94   if (vec3_isall(axis_angles, 0))
     95     return;
     96 
     97   for (int i = 0; i < 3; ++i) {
     98     float axis[3] = {0};
     99     float quat[4];
    100     axis[i] = 1;
    101     quat_axis_angle(axis, axis_angles[i], quat);
    102     quat_multiply(node->orientation, quat, node->orientation);
    103   }
    104 
    105   /* printf("translating %f %f %f\n", p[0], p[1], p[2]); */
    106   node_mark_for_recalc(node);
    107 }
    108 
    109 int node_needs_recalc(struct node *node)
    110 {
    111     struct node *parent = get_node(&node->parent_id);
    112     return (parent && parent->needs_recalc) || node->needs_recalc;
    113 }
    114 
    115 vec3 *node_world(struct node *node) {
    116 
    117     return &node->mat[M_X];
    118 }
    119 
    120 void node_mark_for_recalc(struct node *node) {
    121   static int j = 0;
    122 
    123   if (node->needs_recalc)
    124     return;
    125 
    126   node->needs_recalc = 1;
    127 
    128   for (int i = 0; i < node->n_children; ++i) {
    129       struct node *child = get_node(&node->children_ids[i]);
    130       if (child)
    131           node_mark_for_recalc(child);
    132   }
    133 }
    134 
    135 static void node_recalc_children(struct node *node) {
    136   for (int i = 0; i < node->n_children; ++i) {
    137       struct node *child = get_node(&node->children_ids[i]);
    138       if (child)
    139           node_recalc(child);
    140   }
    141 }
    142 
    143 int node_recalc(struct node *node) {
    144   assert(node);
    145   float rot[9] = {1.0};
    146 
    147   struct node *parent = get_node(&node->parent_id);
    148   if (parent && node_needs_recalc(parent)) {
    149       node_recalc(parent);
    150   }
    151 
    152   if (!node_needs_recalc(node)) {
    153     node_recalc_children(node);
    154     return 0;
    155   }
    156 
    157   node->needs_recalc = 0;
    158 
    159   if (!node->custom_update) {
    160       quat_to_mat3(node->orientation, rot);
    161       mat4_create_transform(node->pos, node->scale, rot, node->mat);
    162 
    163       if (parent) {
    164           assert(!parent->needs_recalc);
    165           mat4_multiply(parent->mat, node->mat, node->mat);
    166       }
    167 
    168   }
    169   else {
    170       debug("custom updating %s\n", node->label);
    171       node->custom_update(node);
    172   }
    173 
    174   node_recalc_children(node);
    175 
    176   return 1;
    177 }
    178 
    179 int node_detach(struct node *node, struct node *from) {
    180     for (int i = 0; i < from->n_children; i++) {
    181         node_id *child_id = &from->children_ids[i];
    182         struct node *child = get_node(&from->children_ids[i]);
    183         if (child && child == node) {
    184             destroy_node(child_id);
    185             memmove(&from->children_ids[i], &from->children_ids[i+1],
    186                     sizeof(*from->children_ids) * (from->n_children - i - 1));
    187             // TODO: test node_detach
    188             from->n_children--;
    189             return 1;
    190         }
    191     }
    192     return 0;
    193 }
    194 
    195 void node_detach_from_parent(struct node *node)
    196 {
    197     struct node *parent = get_node(&node->parent_id);
    198 
    199     if (parent)
    200         node_detach(node, parent);
    201 }
    202 
    203 // count the total number of nodes
    204 int node_count(struct node *node)
    205 {
    206     int c = 1;
    207     for (int i = 0; i < node->n_children; i++) {
    208         struct node *child = get_node(&node->children_ids[i]);
    209         assert(child);
    210         if (child)
    211             c += node_count(child);
    212     }
    213     return c;
    214 }
    215 
    216 void node_attach(struct resource_id *node_id, struct resource_id *to_id)
    217 {
    218     struct node *node = get_node(node_id);
    219     struct node *to   = get_node(to_id);
    220 
    221     assert(node);
    222     assert(to && to->n_children <= MAX_NODE_CHILDREN);
    223 
    224     node->parent_id = *to_id;
    225     assert(node->parent_id.uuid == to_id->uuid);
    226     to->children_ids[to->n_children++] = *node_id;
    227 }
    228 
    229 void node_forward(struct node *node, float *dir) {
    230     vec3_forward(node->pos, node->orientation, dir, node->pos);
    231     node_mark_for_recalc(node);
    232 }