polyadvent

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

node.c (5015B)


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