Sepehr Taghdisian avatar Sepehr Taghdisian committed 88f5721

anim-mech init

Comments (0)

Files changed (2)

include/engine/anim.h

     struct allocator* alloc;
 };
 
+/*************************************************************************************************/
+struct anim_mech_data;
+typedef struct anim_mech_data* anim_mech;
+
+anim_mech anim_mech_load(struct allocator* alloc, const char* janim_filepath, uint32 thread_id);
+void anim_mech_unload(anim_mech mech);
 
 /*************************************************************************************************/
 /* animation clip: keyframe bank */

src/engine/anim.c

 #include "components/cmp-xform.h"
 
 /*************************************************************************************************
+ * types
+ */
+enum anim_mech_paramtype
+{
+    ANIM_MECH_PARAM_UNKNOWN = 0,
+    ANIM_MECH_PARAM_INT,
+    ANIM_MECH_PARAM_FLOAT,
+    ANIM_MECH_PARAM_BOOLEAN
+};
+
+enum anim_mech_sequencetype
+{
+    ANIM_MECH_SEQUENCE_UNKNOWN = 0,
+    ANIM_MECH_SEQUENCE_CLIP,
+    ANIM_MECH_SEQUENCE_BLENDTREE
+};
+
+struct anim_mech_param
+{
+    char name[32];
+    enum anim_mech_paramtype type;
+
+    union   {
+        fl32 f;
+        int32 i;
+        bool_t b;
+    } value;
+};
+
+struct anim_mech_layer
+{
+    char name[32];
+    uint32 state_cnt;
+    uint32* states; /* index to states in anim_mech */
+    uint32 default_state_idx;
+};
+
+struct anim_mech_sequence
+{
+    enum anum_mech_sequencetype type;
+    uint32 idx;
+};
+
+struct anim_mech_state
+{
+    char name[32];
+    fl32 speed;
+    uint32 transition_cnt;
+    uint32* transitions;
+    struct anim_mech_sequence seq;
+};
+
+struct anim_mech_blendtree
+{
+    char name[32];
+    uint32 param_idx;
+    uint32 child_seq_cnt;
+    struct anim_mech_sequence* child_seqs;
+};
+
+struct anim_mech_clip
+{
+    char name[32];
+    uint32 name_hash;
+};
+
+enum anim_predicate
+{
+    ANIM_PREDICATE_UNKNOWN = 0,
+    ANIM_PREDICATE_EQUAL,
+    ANIM_PREDICATE_NOT,
+    ANIM_PREDICATE_GREATER,
+    ANIM_PREDICATE_LESS
+};
+
+enum anim_mech_tgrouptype
+{
+    ANIM_MECH_TGROUP_EXIT = 0,
+    ANIM_MECH_TGROUP_PARAM
+};
+
+struct anim_mech_transition
+{
+    fl32 duration;
+    uint32 parent_state_idx;
+    uint32 target_state_idx;
+    uint32 group_cnt;
+
+    struct anim_mech_transition_group
+    {
+        enum anim_mech_tgrouptype type;
+        enum anim_predicate predicate; 
+        uint32 param_idx;
+        fl32 value;                
+    } *groups;
+};
+
+struct anim_mech_data
+{
+    struct allocator* alloc;
+    uint32 transition_cnt;
+    uint32 clip_cnt;
+    uint32 blendtree_cnt;
+    uint32 state_cnt;
+    uint32 param_cnt;
+    uint32 layer_cnt;
+
+    struct anim_mech_transition* transitions;
+    struct anim_mech_clip* clips;
+    struct anim_mech_blendtree* blendtrees;
+    struct anim_mech_state* states;
+    struct anim_mech_param* params;
+    struct anim_mech_layer* layers;
+};
+
+/*************************************************************************************************
  * fwd declarations
  */
 void anim_loadchannel(file_t f, struct anim_clip* clip, struct vec4f* tmp_pos_scale, 
     struct quat4f* tmp_rot, uint32 pose_idx, uint32 frame_cnt);
+bool_t anim_mech_load_params(anim_mech mech, json_t jparams);
+bool_t anim_mech_load_layers(anim_mech mech, json_t jlayers);
+bool_t anim_mech_load_states(anim_mech mech, json_t jstates);
+bool_t anim_mech_load_blendtrees(anim_mech mech, json_t jblendtrees);
+bool_t anim_mech_load_clips(anim_mech mech, json_t jclips);
+bool_t anim_mech_load_transitions(anim_mech mech, json_t jtransitions);
+
 
 /*************************************************************************************************
  * inlines
     struct allocator* tmp_alloc = eng_get_framealloc();
     eng_save_framealloc();
 
-
     file_t f = io_file_openmem(alloc, h3da_filepath, FALSE, MID_ANIM);
     if (f == NULL)  {
         err_printf(__FILE__, __LINE__, "load anim '%s' failed: could not open file", h3da_filepath);
         return item->value;
     return INVALID_INDEX;
 }
+
+bool_t anim_mech_load_params(anim_mech mech, json_t jparams)
+{
+    if (jparams == NULL)
+        return TRUE;
+
+    uint32 cnt = json_getarr_count(jparams);
+    if (cnt == 0)
+        return TRUE;
+    mech->params = A_ALLOC(mech->alloc, sizeof(struct anim_mech_param)*cnt, MID_ANIM);
+    if (mech->params == NULL)
+        return FALSE;
+    
+    for (uint32 i = 0; i < cnt; i++)    {
+        json_t jparam = json_getarr_item(jparams, i);
+        struct anim_mech_param* param = &mech->params[i];
+        
+        strcpy(param->name, json_gets_child(jparam, "name", ""));
+
+        char type[32];
+        strcpy(type, json_gets_child(jparam, "type", "float"));
+        if (str_isequal(type, "float")) {
+            param->type = ANIM_MECH_PARAM_FLOAT;
+            param->value.f = json_getf_child(jparam, "value", 0.0f);
+        }   else if (str_isequal(type, "int"))  {
+            param->type = ANIM_MECH_PARAM_INT;
+            param->value.i = json_geti_child(jparam, "value", 0);
+        }   else if (str_isequal(type, "bool")) {
+            param->type = ANIM_MECH_PARAM_BOOLEAN;
+            param->value.b = json_getb_child(jparam, "value", FALSE);
+        }   else    {
+            param->type = ANIM_MECH_PARAM_FLOAT;
+            param->value.f = 0.0f;
+        }
+    }   
+
+    mech->param_cnt = cnt;
+    return TRUE;
+}
+
+bool_t anim_mech_load_layers(anim_mech mech, json_t jlayers)
+{
+    if (jlayers == NULL)
+        return TRUE;
+
+    uint32 cnt = json_getarr_count(jlayers);
+    if (cnt == 0)
+        return TRUE;
+    mech->layers = A_ALLOC(mech->alloc, sizeof(struct anim_mech_layer)*cnt, MID_ANIM);
+    if (mech->layers == NULL)
+        return FALSE;
+
+    for (uint32 i = 0; i < cnt; i++)    {
+        json_t jlayer = json_getarr_item(jlayers, i);
+        struct anim_mech_layer* layer = &mech->layers[i];
+
+        strcpy(layer->name, json_gets_child(jlayer, "name", ""));
+        layer->default_state_idx = json_geti_child(jlayer, "default", INVALID_INDEX);
+
+        /* states */
+        json_t jstates = json_getitem(jlayer, "states");
+        if (jstates != NULL)    {
+            layer->state_cnt = json_getarr_count(jstates);
+            if (layer->state_cnt != 0)  {
+                layer->states = A_ALLOC(mech->alloc, sizeof(uint32)*layer->state_cnt, MID_ANIM);
+                if (layer->states == NULL)
+                    return FALSE;
+                for (uint32 k = 0; k < layer->state_cnt; k++) 
+                    layer->states[k] = json_geti(json_getarr_item(jstates, k));
+            }
+        }
+    }
+
+    mech->layer_cnt = cnt;
+    return TRUE;
+}
+
+INLINE enum anim_mech_sequencetype anim_mech_parse_seqtype(json_t jseq)
+{
+    char seq_type_s[32];
+    strcpy(seq_type_s, json_gets_child(jseq, "type", ""));
+    if (str_isequal(seq_type_s, "clip"))
+        return ANIM_MECH_SEQUENCE_CLIP;
+    else if (str_isequal(seq_type_s, "blendtree"))
+        return ANIM_MECH_SEQUENCE_BLENDTREE;
+    else
+        return ANIM_MECH_SEQUENCE_UNKNOWN;
+}
+
+bool_t anim_mech_load_states(anim_mech mech, json_t jstates)
+{
+    if (jstates == NULL)
+        return TRUE;
+
+    uint32 cnt = json_getarr_count(jstates);
+    if (cnt == 0)
+        return TRUE;
+    mech->states = A_ALLOC(mech->alloc, sizeof(struct anim_mech_state)*cnt, MID_ANIM);
+    if (mech->states == NULL)  
+        return FALSE;
+
+    for (uint32 i = 0; i < cnt; i++)    {
+        json_t jstate = json_getarr_item(jstates, i);
+        struct anim_mech_state* state = &mech->states[i];
+
+        strcpy(state->name, json_gets_child(jstate, "name", ""));
+        state->speed = json_getf_child(jstate, "speed", 1.0f);
+        
+        /* sequence */
+        json_t jseq = json_getitem(jstate, "sequence");
+        if (jseq != NULL)   {
+            state->seq.type = anim_mech_parse_seqtype(jseq);
+            state->seq.idx = json_geti_child(jseq, "id", INVALID_INDEX);
+        }
+
+        /* transitions */
+        json_t jtrans = json_getitem(jstate, "transitions");
+        if (jtrans != NULL) {
+             state->transition_cnt = json_getarr_count(jtrans);
+             if (state->transition_cnt > 0) {
+                 state->transitions = A_ALLOC(mech->alloc, sizeof(uint32)*state->transition_cnt, 
+                     MID_ANIM);
+                 if (state->transitions != NULL)
+                     return FALSE;
+
+                 for (uint32 k = 0; k < state->transition_cnt; k++) 
+                     state->transitions[k] = json_geti(json_getarr_item(jtrans, k));
+             }
+        }
+    }
+
+    mech->state_cnt = cnt;
+    return TRUE;
+}
+
+bool_t anim_mech_load_blendtrees(anim_mech mech, json_t jblendtrees)
+{
+    if (jblendtrees == NULL)
+        return TRUE;
+
+    uint32 cnt = json_getarr_count(jblendtrees);
+    if (cnt == 0)
+        return TRUE;
+
+    mech->blendtrees = A_ALLOC(mech->alloc, sizeof(struct anim_mech_blendtree)*cnt, MID_ANIM);
+    if (mech->blendtrees == NULL)
+        return FALSE;
+
+    for (uint32 i = 0; i < cnt; i++)    {
+        json_t jbt = json_getarr_item(jblendtrees, i);
+        struct anim_mech_blendtree* bt = &mech->blendtrees[i];
+        strcpy(bt->name, json_gets_child(jbt, "name", ""));
+        
+        bt->param_idx = json_geti_child(jbt, "param", INVALID_INDEX);
+
+        /* childs */
+        json_t jchilds = json_getitem(jbt, "childs");
+        if (jchilds != NULL)    {
+            uint32 child_cnt = json_getarr_count(jchilds);
+            if (child_cnt > 0)  {
+                bt->child_seqs = A_ALLOC(mech->alloc, sizeof(struct anim_mech_sequence)*child_cnt,
+                    MID_ANIM);
+                if (bt->child_seqs == NULL)
+                    return FALSE;
+
+                for (uint32 k = 0; k < child_cnt; k++)  {
+                    json_t jseq = json_getarr_item(jchilds, k);
+                    struct anim_mech_sequence* seq = &bt->child_seqs[k];
+                    seq->idx = json_geti_child(jseq, "id", INVALID_INDEX);
+                    seq->type = anim_mech_parse_seqtype(jseq);
+                }
+                
+                bt->child_seq_cnt = child_cnt;
+            }
+        }
+    }
+
+    mech->blendtree_cnt = cnt;
+    return TRUE;
+}
+
+bool_t anim_mech_load_clips(anim_mech mech, json_t jclips)
+{
+    if (jclips == NULL)
+        return TRUE;
+
+    uint32 cnt = json_getarr_count(jclips);
+    if (cnt == 0)
+        return TRUE;
+
+    mech->clips = A_ALLOC(mech->alloc, sizeof(struct anim_mech_clip)*cnt, MID_ANIM);
+    if (mech->clips == NULL)
+        return FALSE;
+
+    for (uint32 i = 0; i < cnt; i++)    {
+        json_t jclip = json_getarr_item(jclips, i);
+        struct anim_mech_clip* clip = &mech->clips[i];
+        strcpy(clip->name, json_gets_child(jclip, "name", ""));
+        clip->name_hash = hashtable_str(clip->name);
+    }
+
+    mech->clip_cnt = cnt;
+    return TRUE;
+}
+
+INLINE enum anim_mech_tgrouptype anim_mech_parse_grptype(json_t jgrp)
+{
+    char type_s[32];
+    strcpy(type_s, json_gets_child(jgrp, "type", ""));
+
+    if (str_isequal(type_s, "exit"))
+        return ANIM_MECH_TGROUP_EXIT;
+    else if (str_isequal(type_s, "parameter"))
+        return ANIM_MECH_TGROUP_PARAM;
+    else
+        return ANIM_MECH_TGROUP_EXIT;
+}
+
+INLINE enum anim_predicate anim_mech_parse_grppred(json_t jgrp)
+{
+    char pred_s[32];
+    strcpy(pred_s, json_gets_child(jgrp, "predicate", ""));
+
+    if (str_isequal(pred_s, "eq"))
+        return ANIM_PREDICATE_EQUAL;
+    else if (str_isequal(pred_s, "not"))
+        return ANIM_PREDICATE_NOT;
+    else if (str_isequal(pred_s, "gt"))
+        return ANIM_PREDICATE_GREATER;
+    else if (str_isequal(pred_s, "lt"))
+        return ANIM_PREDICATE_LESS;
+    else
+        return ANIM_PREDICATE_UNKNOWN;
+}
+
+bool_t anim_mech_load_transitions(anim_mech mech, json_t jtransitions)
+{
+    if (jtransitions == NULL)
+        return TRUE;
+
+    uint32 cnt = json_getarr_count(jtransitions);
+    if (cnt == 0)
+        return TRUE;
+
+    mech->transitions = A_ALLOC(mech->alloc, sizeof(struct anim_mech_transition)*cnt, MID_ANIM);
+    if (mech->transitions == NULL)
+        return FALSE;
+
+    for (uint32 i = 0; i < cnt; i++)    {
+        json_t jtrans = json_getarr_item(jtransitions, i);
+        struct anim_mech_transition* trans = &mech->transitions[i];
+        
+        trans->duration = json_getf_child(jtrans, "duration", 0.0f);
+        trans->parent_state_idx = json_geti_child(jtrans, "src", INVALID_INDEX);
+        trans->target_state_idx = json_geti_child(jtrans, "target", INVALID_INDEX);
+
+        /* groups */
+        json_t jgroups = json_getitem(jtrans, "groups");
+        if (jgroups != NULL)    {
+            uint32 group_cnt = json_getarr_count(jgroups);
+            if (group_cnt > 0)  {
+                trans->groups = A_ALLOC(mech->alloc, 
+                    sizeof(struct anim_mech_transition_group)*group_cnt, MID_GFX);
+                if (trans->groups == NULL)
+                    return FALSE;
+
+                for (uint32 k = 0; k < group_cnt; k++)  {
+                    json_t jgrp = json_getarr_item(jgroups, k);
+                    struct anim_mech_transition_group* grp = &trans->groups[k];
+                    grp->type = anim_mech_parse_grptype(jgrp);
+                    grp->param_idx = json_geti_child(jgrp, "param", INVALID_INDEX);
+                    grp->predicate = anim_mech_parse_grppred(jgrp);
+                    grp->value = json_getf_child(jgrp, "value", 0.9f);
+                }
+            }
+
+            trans->group_cnt = group_cnt;
+        }
+    }
+
+    mech->transition_cnt = cnt;
+    return TRUE;
+}
+
+anim_mech anim_mech_load(struct allocator* alloc, const char* janim_filepath, uint32 thread_id)
+{
+    /* TODO: get temp alloc from current thread */
+    struct allocator* tmp_alloc = eng_get_framealloc();
+    eng_save_framealloc();
+    
+    /* load JSON mech file */
+    file_t f = io_file_openmem(tmp_alloc, janim_filepath, FALSE, MID_ANIM);
+    if (f == FILE_NULL) {
+        err_printf(__FILE__, __LINE__, "Loading mech-anim failed: Could not open file '%s'", 
+            janim_filepath);
+        return NULL;
+    }
+
+    json_t jroot = json_parsefile(f, tmp_alloc);
+    io_file_close(f);
+    if (jroot == NULL)  {
+        err_printf(__FILE__, __LINE__, "Loading mech-anim failed: Invalid json '%s'", 
+            janim_filepath);
+        return NULL;
+    }
+
+    /* create mech structure and zero memory */
+    anim_mech mech = A_ALLOC(alloc, sizeof(struct anim_mech_data), MID_ANIM);
+    if (mech == NULL)   {
+        err_printn(__FILE__, __LINE__, RET_OUTOFMEMORY);
+        return NULL;
+    }
+    memset(mech, 0x00, sizeof(struct anim_mech_data));
+    mech->alloc = alloc;
+
+    if (!anim_mech_load_params(mech, json_getitem(jroot, "params")))    {
+        err_print(__FILE__, __LINE__, "Loading mech-anim failed: unable to load params");
+        anim_mech_unload(mech);
+        return NULL;
+    }    
+
+    if (!anim_mech_load_clips(mech, json_getitem(jroot, "clips")))    {
+        err_print(__FILE__, __LINE__, "Loading mech-anim failed: unable to load clips");
+        anim_mech_unload(mech);
+        return NULL;
+    }
+
+    if (!anim_mech_load_transitions(mech, json_getitem(jroot, "transitions")))    {
+        err_print(__FILE__, __LINE__, "Loading mech-anim failed: unable to load transitions");
+        anim_mech_unload(mech);
+        return NULL;
+    }
+
+    if (!anim_mech_load_blendtrees(mech, json_getitem(jroot, "blendtrees")))    {
+        err_print(__FILE__, __LINE__, "Loading mech-anim failed: unable to load blendtrees");
+        anim_mech_unload(mech);
+        return NULL;
+    }
+
+    if (!anim_mech_load_states(mech, json_getitem(jroot, "states")))    {
+        err_print(__FILE__, __LINE__, "Loading mech-anim failed: unable to load states");
+        anim_mech_unload(mech);
+        return NULL;
+    }
+
+    if (!anim_mech_load_layers(mech, json_getitem(jroot, "layers")))    {
+        err_print(__FILE__, __LINE__, "Loading mech-anim failed: unable to load layers");
+        anim_mech_unload(mech);
+        return NULL;
+    }
+
+    json_destroy(jroot);
+    eng_load_framealloc();
+    return mech;
+}
+
+void anim_mech_unload(anim_mech mech)
+{
+    struct allocator* alloc = mech->alloc;
+    ASSERT(alloc);
+
+    if (mech->layers != NULL)   {
+        for (uint32 i = 0; i < mech->layer_cnt; i++)    {
+            struct anim_mech_layer* l = &mech->layers[i];
+            if (l->states != NULL)
+                A_FREE(alloc, l->states);
+        }
+        A_FREE(alloc, mech->layers);
+    }
+
+    if (mech->states != NULL)   {
+        for (uint32 i = 0; i < mech->state_cnt; i++)    {
+            struct anim_mech_state* s = &mech->states[i];
+            if (s->transitions != NULL)
+                A_FREE(alloc, s->transitions);
+        }
+        A_FREE(alloc, mech->states);
+    }
+
+    if (mech->blendtrees != NULL)   {
+        for (uint32 i = 0; i < mech->blendtree_cnt; i++)    {
+            struct anim_mech_blendtree* b = &mech->blendtrees[i];
+            if (b->child_seqs != NULL)
+                A_FREE(alloc, b->child_seqs);
+        }
+        A_FREE(alloc, mech->blendtrees);
+    }
+
+    if (mech->params != NULL)
+        A_FREE(alloc, mech->params);
+
+    if (mech->clips != NULL)
+        A_FREE(alloc, mech->clips);
+
+    if (mech->transitions != NULL)  {
+        for (uint32 i = 0; i < mech->transition_cnt; i++)   {
+            struct anim_mech_transition* t = &mech->transitions[i];
+            if (t->groups != NULL)
+                A_FREE(alloc, t->groups);
+        }
+        A_FREE(alloc, mech->transitions);
+    }
+
+    A_FREE(alloc, mech);
+}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.