2017-09-20 08:42:57 -07:00
|
|
|
// Copyright © 2017 Project Golan, all rights reserved.
|
|
|
|
#include "g_object.h"
|
|
|
|
#include "m_token.h"
|
|
|
|
#include "m_str.h"
|
|
|
|
#include "m_darray.h"
|
|
|
|
|
|
|
|
#include <Doominati.h>
|
|
|
|
#include <GDCC/HashMap.h>
|
|
|
|
|
|
|
|
#include <setjmp.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
#define G_dodTokBeg (4)
|
|
|
|
#define G_dodTokEnd (10)
|
|
|
|
|
|
|
|
#define G_ofmap_GetKey(o) ( (o)->name)
|
|
|
|
#define G_ofmap_GetNext(o) (&(o)->next)
|
|
|
|
#define G_ofmap_GetPrev(o) (&(o)->prev)
|
|
|
|
#define G_ofmap_HashObj(o) ( (o)->keyhash)
|
|
|
|
#define G_ofmap_HashKey(k) (M_StrHash(k))
|
|
|
|
#define G_ofmap_KeyCmp(l, r) (strcmp(l, r))
|
|
|
|
|
|
|
|
#define G_etmap_GetKey(o) ( (o)->name)
|
|
|
|
#define G_etmap_GetNext(o) (&(o)->next)
|
|
|
|
#define G_etmap_GetPrev(o) (&(o)->prev)
|
|
|
|
#define G_etmap_HashObj(o) ( (o)->keyhash)
|
|
|
|
#define G_etmap_HashKey(k) (M_StrHash(k))
|
|
|
|
#define G_etmap_KeyCmp(l, r) (strcmp(l, r))
|
|
|
|
|
|
|
|
#define G_frmap_GetKey(o) ( (o)->name)
|
|
|
|
#define G_frmap_GetNext(o) (&(o)->next)
|
|
|
|
#define G_frmap_GetPrev(o) (&(o)->prev)
|
|
|
|
#define G_frmap_HashObj(o) ( (o)->keyhash)
|
|
|
|
#define G_frmap_HashKey(k) (M_StrHash(k))
|
|
|
|
#define G_frmap_KeyCmp(l, r) (strcmp(l, r))
|
|
|
|
|
|
|
|
#define G_anmap_GetKey(o) ( (o)->name)
|
|
|
|
#define G_anmap_GetNext(o) (&(o)->next)
|
|
|
|
#define G_anmap_GetPrev(o) (&(o)->prev)
|
|
|
|
#define G_anmap_HashObj(o) ( (o)->keyhash)
|
|
|
|
#define G_anmap_HashKey(k) (M_StrHash(k))
|
|
|
|
#define G_anmap_KeyCmp(l, r) (strcmp(l, r))
|
|
|
|
|
|
|
|
#define G_anims_GetKey(o) ( (o)->name)
|
|
|
|
#define G_anims_GetNext(o) (&(o)->next)
|
|
|
|
#define G_anims_GetPrev(o) (&(o)->prev)
|
|
|
|
#define G_anims_HashObj(o) ( (o)->keyhash)
|
|
|
|
#define G_anims_HashKey(k) (M_StrHash(k))
|
|
|
|
#define G_anims_KeyCmp(l, r) (strcmp(l, r))
|
|
|
|
|
|
|
|
// Static Functions ----------------------------------------------------------|
|
|
|
|
|
|
|
|
_Noreturn static void G_ObjDef_throw (struct G_dodst *st, char const *emsg);
|
|
|
|
static M_token *G_ObjDef_getToken(struct G_dodst *st);
|
|
|
|
static M_token *G_ObjDef_unget (struct G_dodst *st);
|
|
|
|
static M_token *G_ObjDef_reget (struct G_dodst *st);
|
|
|
|
static bool G_ObjDef_drop (struct G_dodst *st, M_tokty t);
|
|
|
|
[[__optional_args(1)]]
|
|
|
|
static M_token *G_ObjDef_expect (struct G_dodst *st, M_tokty t, char const *exp);
|
|
|
|
[[__optional_args(1)]]
|
|
|
|
static struct G_odarg G_ObjDef_getArgs (struct G_dodst *st, char const *arg);
|
|
|
|
|
|
|
|
// Types ---------------------------------------------------------------------|
|
|
|
|
|
|
|
|
GDCC_HashMap_Decl(G_ofmap, char const *, struct G_ofdcl)
|
|
|
|
GDCC_HashMap_Decl(G_etmap, char const *, struct G_etdcl)
|
|
|
|
GDCC_HashMap_Decl(G_frmap, char const *, struct G_frdcl)
|
|
|
|
GDCC_HashMap_Decl(G_anmap, char const *, struct G_andcl)
|
|
|
|
GDCC_HashMap_Decl(G_anims, char const *, struct G_manim)
|
|
|
|
|
|
|
|
typedef struct G_dodst
|
|
|
|
{
|
|
|
|
__prop throw {call: G_ObjDef_throw (this)}
|
|
|
|
__prop getToken {call: G_ObjDef_getToken(this)}
|
|
|
|
__prop unget {call: G_ObjDef_unget (this)}
|
|
|
|
__prop drop {call: G_ObjDef_drop (this)}
|
|
|
|
__prop expect {call: G_ObjDef_expect (this)}
|
|
|
|
__prop getArgs {call: G_ObjDef_getArgs (this)}
|
|
|
|
__prop reget {call: G_ObjDef_reget (this)}
|
|
|
|
|
|
|
|
jmp_buf ejmp;
|
|
|
|
int lines;
|
|
|
|
char const *fname;
|
|
|
|
FILE *fp;
|
|
|
|
int tpos, tend;
|
|
|
|
M_token toks[G_dodTokEnd];
|
|
|
|
} G_dodst;
|
|
|
|
|
|
|
|
typedef union G_odprm
|
|
|
|
{
|
|
|
|
mword u;
|
|
|
|
integ i;
|
|
|
|
fixed k;
|
|
|
|
lfrac r;
|
|
|
|
} G_odprm;
|
|
|
|
|
|
|
|
typedef struct G_odarg
|
|
|
|
{
|
|
|
|
G_odprm argv[8];
|
|
|
|
int argc;
|
|
|
|
} G_odarg;
|
|
|
|
|
|
|
|
typedef struct G_ofdcl
|
|
|
|
{
|
|
|
|
DGE_CallbackType fptr;
|
|
|
|
char const *name;
|
|
|
|
size_t keyhash;
|
|
|
|
struct G_ofdcl *next, **prev;
|
|
|
|
} G_ofdcl;
|
|
|
|
|
|
|
|
typedef struct G_etdcl
|
|
|
|
{
|
|
|
|
G_entty type;
|
|
|
|
G_anims anim;
|
|
|
|
M_Vec_decl(struct G_manim, anims);
|
|
|
|
|
|
|
|
char name[32];
|
|
|
|
size_t keyhash;
|
|
|
|
struct G_etdcl *next, **prev;
|
|
|
|
} G_etdcl;
|
|
|
|
|
|
|
|
typedef struct G_frdcl
|
|
|
|
{
|
|
|
|
M_texid sprite;
|
|
|
|
char name[32];
|
|
|
|
size_t keyhash;
|
|
|
|
struct G_frdcl *next, **prev;
|
|
|
|
} G_frdcl;
|
|
|
|
|
|
|
|
typedef struct G_andcl
|
|
|
|
{
|
|
|
|
M_Vec_decl(G_frame, frame);
|
|
|
|
char name[32];
|
|
|
|
size_t keyhash;
|
|
|
|
struct G_andcl *next, **prev;
|
|
|
|
} G_andcl;
|
|
|
|
|
|
|
|
typedef struct G_manim
|
|
|
|
{
|
|
|
|
G_anima anim;
|
|
|
|
char name[32];
|
|
|
|
size_t keyhash;
|
|
|
|
struct G_manim *next, **prev;
|
|
|
|
} G_manim;
|
|
|
|
|
|
|
|
// Static Objects ------------------------------------------------------------|
|
|
|
|
|
|
|
|
static G_ofmap G_objfuncs;
|
|
|
|
static G_etmap G_enttypes;
|
|
|
|
static G_frmap G_frametab;
|
|
|
|
static G_anmap G_animsmap;
|
|
|
|
|
|
|
|
M_Vec_defn(G_ofdcl, G_ofvec, static);
|
|
|
|
M_Vec_defn(G_etdcl, G_etvec, static);
|
|
|
|
M_Vec_defn(G_frdcl, G_frvec, static);
|
|
|
|
M_Vec_defn(G_andcl, G_anvec, static);
|
|
|
|
|
|
|
|
// Static Functions ----------------------------------------------------------|
|
|
|
|
|
|
|
|
GDCC_HashMap_Defn(G_ofmap, char const *, G_ofdcl)
|
|
|
|
GDCC_HashMap_Defn(G_etmap, char const *, G_etdcl)
|
|
|
|
GDCC_HashMap_Defn(G_frmap, char const *, G_frdcl)
|
|
|
|
GDCC_HashMap_Defn(G_anmap, char const *, G_andcl)
|
|
|
|
GDCC_HashMap_Defn(G_anims, char const *, G_manim)
|
|
|
|
|
|
|
|
//
|
|
|
|
// G_ObjDef_throw
|
|
|
|
//
|
|
|
|
_Noreturn static void G_ObjDef_throw(G_dodst *st, char const *emsg)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "ObjDef (%s:%i): %s\n", st->fname, st->reget()->line, emsg);
|
|
|
|
longjmp(st->ejmp, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// G_ObjDef_getToken
|
|
|
|
//
|
|
|
|
static M_token *G_ObjDef_getToken(G_dodst *st)
|
|
|
|
{
|
|
|
|
if(++st->tpos < st->tend)
|
|
|
|
return &st->toks[st->tpos];
|
|
|
|
|
|
|
|
memmove(&st->toks[0], &st->toks[st->tend - G_dodTokBeg],
|
|
|
|
sizeof(M_token) * G_dodTokBeg);
|
|
|
|
|
|
|
|
for(st->tpos = st->tend = G_dodTokBeg; st->tend < G_dodTokEnd; st->tend++)
|
|
|
|
{
|
|
|
|
skip:
|
|
|
|
M_Tk_Parse(st->fp, &st->toks[st->tend]);
|
|
|
|
st->toks[st->tend].line = st->lines;
|
|
|
|
|
|
|
|
switch(st->toks[st->tend].type) {
|
|
|
|
default: break;
|
|
|
|
case tok_eof: goto done;
|
|
|
|
case tok_lnend: st->lines++;
|
|
|
|
case tok_cmtlin: goto skip;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
for(int i = 0; i < st->tend; i++)
|
|
|
|
printf("%i: %s%s\n", st->toks[i].type, st->toks[i].text, i == st->tpos ? " <-- cursor is here" : "");
|
|
|
|
*/
|
|
|
|
|
|
|
|
done:
|
|
|
|
return &st->toks[st->tpos];
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// G_ObjDef_unget
|
|
|
|
//
|
|
|
|
static M_token *G_ObjDef_unget(G_dodst *st)
|
|
|
|
{
|
|
|
|
return &st->toks[st->tpos--];
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// G_ObjDef_reget
|
|
|
|
//
|
|
|
|
static M_token *G_ObjDef_reget(G_dodst *st)
|
|
|
|
{
|
|
|
|
return &st->toks[st->tpos];
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// G_ObjDef_drop
|
|
|
|
//
|
|
|
|
static bool G_ObjDef_drop(G_dodst *st, M_tokty t)
|
|
|
|
{
|
|
|
|
if(st->getToken()->type != t) {
|
|
|
|
st->unget();
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// G_ObjDef_expect
|
|
|
|
//
|
|
|
|
static M_token *G_ObjDef_expect(G_dodst *st, M_tokty t, char const *exp)
|
|
|
|
{
|
|
|
|
M_token *tok;
|
|
|
|
if((tok = st->getToken())->type != t) {
|
|
|
|
if(exp) st->throw(M_StrFmt("expected %s", exp));
|
|
|
|
else st->throw("unexpected token");
|
|
|
|
}
|
|
|
|
return tok;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// G_ObjDef_getArgs
|
|
|
|
//
|
|
|
|
[[__optional_args(1)]]
|
|
|
|
static G_odarg G_ObjDef_getArgs(G_dodst *st, char const *arg)
|
|
|
|
{
|
|
|
|
G_odarg a = {};
|
|
|
|
bool done = false;
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
for(;;)
|
|
|
|
{
|
|
|
|
char ch = arg[i++];
|
|
|
|
|
|
|
|
if(!done && (arg[i] == '\0' || arg[i] == '|'))
|
|
|
|
done = true;
|
|
|
|
|
|
|
|
switch(ch)
|
|
|
|
{
|
|
|
|
#define CaseN(c, t, f, ...) \
|
|
|
|
case c: \
|
|
|
|
a.argv[a.argc++].t = \
|
|
|
|
f(st->expect(tok_number, "number")->text, __VA_ARGS__); \
|
|
|
|
break
|
|
|
|
CaseN('u', u, strtoui, NULL, 0);
|
|
|
|
CaseN('i', i, strtoi, NULL, 0);
|
|
|
|
CaseN('k', k, strtofxhk, NULL);
|
|
|
|
CaseN('r', r, strtofxk, NULL);
|
|
|
|
// TODO: get david to implement fracts
|
|
|
|
//CaseN('r', r, strtofxlr, NULL);
|
|
|
|
#undef CaseN
|
|
|
|
case '|': done = true; continue;
|
|
|
|
case '\0': st->throw("too many arguments");
|
|
|
|
default: st->throw("unexpected argument type");
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!st->drop(tok_comma)) break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!done)
|
|
|
|
st->throw("not enough arguments");
|
|
|
|
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// G_ObjDef_getEntAnim
|
|
|
|
//
|
|
|
|
static void G_ObjDef_getEntAnim(G_dodst *st, G_etdcl *decl)
|
|
|
|
{
|
|
|
|
char alias[M_countof(decl->name)];
|
|
|
|
|
|
|
|
M_strbufcpy(alias, st->expect(tok_identi, "alias name")->text);
|
|
|
|
st->expect(tok_eq, "'='");
|
|
|
|
|
|
|
|
G_andcl *an = G_animsmap.find(st->expect(tok_identi, "anim name")->text);
|
|
|
|
if(an == NULL) st->throw("anim not defined");
|
|
|
|
if(decl->anim.find(alias)) st->throw("alias redefinition");
|
|
|
|
|
|
|
|
M_Vec_grow(decl->anims, 1);
|
|
|
|
G_manim *anim = &decl->animsV[decl->animsC++];
|
|
|
|
M_strbufcpy(anim->name, alias);
|
|
|
|
anim->keyhash = M_StrHash(anim->name);
|
|
|
|
anim->anim = (G_anima){an->frameV, an->frameC};
|
|
|
|
decl->anim.insert(anim);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// G_ObjDef_getEntProp
|
|
|
|
//
|
|
|
|
static void G_ObjDef_getEntProp(G_dodst *st, G_entty *type, char const *id)
|
|
|
|
{
|
|
|
|
if(strcmp(id, "task") == 0)
|
|
|
|
{
|
|
|
|
G_ofdcl *fn = G_objfuncs.find(st->expect(tok_identi, "function")->text);
|
|
|
|
if(!fn) st->throw("invalid function name");
|
|
|
|
type->task = fn->fptr;
|
|
|
|
}
|
|
|
|
else if(strcmp(id, "size") == 0)
|
|
|
|
{
|
|
|
|
G_odarg a = st->getArgs("k|kk");
|
|
|
|
if(a.argc == 1) {
|
|
|
|
type->sx = type->sy = a.argv[0].k;
|
|
|
|
} else {
|
|
|
|
type->sx = a.argv[0].k;
|
|
|
|
type->sy = a.argv[1].k;
|
|
|
|
if(a.argc > 2) type->sz = a.argv[2].k;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(strcmp(id, "drawsize") == 0)
|
|
|
|
{
|
|
|
|
G_odarg a = st->getArgs("k|k");
|
|
|
|
if(a.argc == 1) {
|
|
|
|
type->rsx = type->rsy = a.argv[0].k;
|
|
|
|
} else {
|
|
|
|
type->rsx = a.argv[0].k;
|
|
|
|
type->rsy = a.argv[1].k;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(strcmp(id, "sprite") == 0)
|
|
|
|
{
|
2017-09-20 19:35:19 -07:00
|
|
|
type->sprite = DGE_Texture_Get(
|
2017-09-20 08:42:57 -07:00
|
|
|
M_StrCreate(st->expect(tok_string, "sprite name")->text));
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: change this when access through rvalues is fixed
|
|
|
|
#define Prop(name, t) \
|
|
|
|
else if(strcmp(id, #name) == 0) \
|
|
|
|
__with(G_odarg a = st->getArgs(#t);) type->name = a.argv[0].t
|
|
|
|
Prop(health, i);
|
|
|
|
Prop(friction, k);
|
|
|
|
Prop(mass, k);
|
|
|
|
#undef Prop
|
|
|
|
|
|
|
|
else
|
|
|
|
st->throw("unknown identifier in entity definition");
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// G_ObjDef_getFrameSprite
|
|
|
|
//
|
|
|
|
static M_texid G_ObjDef_getFrameSprite(char const *fmt, char frame, int i)
|
|
|
|
{
|
|
|
|
M_Vec_defn(char, buf);
|
|
|
|
|
|
|
|
for(; *fmt; fmt++)
|
|
|
|
{
|
|
|
|
if(*fmt != '%') {M_Vec_grow(buf, 1); bufV[bufC++] = *fmt; continue;}
|
|
|
|
|
|
|
|
switch(*++fmt)
|
|
|
|
{
|
|
|
|
default:
|
|
|
|
case '%': M_Vec_grow(buf, 1); bufV[bufC++] = *fmt; break;
|
|
|
|
case 'c': M_Vec_grow(buf, 1); bufV[bufC++] = frame; break;
|
|
|
|
case 'i':
|
|
|
|
M_Vec_grow(buf, 20);
|
|
|
|
bufC += snprintf(&bufV[bufC], 20, "%i", i);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!bufV) return 0;
|
|
|
|
|
2017-09-20 19:35:19 -07:00
|
|
|
M_texid id = DGE_Texture_Get(DGE_String_Create(bufV, bufC));
|
2017-09-20 08:42:57 -07:00
|
|
|
free(bufV);
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// G_ObjDef_parseFrameDef
|
|
|
|
//
|
|
|
|
static void G_ObjDef_parseFrameDef(G_dodst *st)
|
|
|
|
{
|
|
|
|
char name[32], frame[32], fmt[32];
|
|
|
|
M_strbufcpy(name, st->expect(tok_identi, "name")->text);
|
|
|
|
M_strbufcpy(frame, st->expect(tok_identi, "frames")->text);
|
|
|
|
M_strbufcpy(fmt, st->expect(tok_string, "format")->text);
|
|
|
|
|
|
|
|
for(int i = 0; frame[i]; i++)
|
|
|
|
{
|
|
|
|
if(frame[i] < 'A' || frame[i] > 'Z')
|
|
|
|
st->throw("invalid frame");
|
|
|
|
|
|
|
|
char const *key = M_StrFmt("%s%c", name, frame[i]);
|
|
|
|
G_frdcl *decl = G_frametab.find(key);
|
|
|
|
|
|
|
|
if(!decl)
|
|
|
|
{
|
|
|
|
M_Vec_grow(G_frvec, 1);
|
|
|
|
*(decl = &G_frvecV[G_frvecC++]) = (G_frdcl){};
|
|
|
|
M_strbufcpy(decl->name, key);
|
|
|
|
decl->keyhash = M_StrHash(decl->name);
|
|
|
|
G_frametab.insert(decl);
|
|
|
|
}
|
|
|
|
|
|
|
|
decl->sprite = G_ObjDef_getFrameSprite(fmt, 'A' + i, i + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// G_ObjDef_parseAnim
|
|
|
|
//
|
|
|
|
static void G_ObjDef_parseAnim(G_dodst *st, G_andcl *decl)
|
|
|
|
{
|
|
|
|
char name[32], frames[32];
|
|
|
|
M_strbufcpy(name, st->expect(tok_identi, "name")->text);
|
|
|
|
M_strbufcpy(frames, st->expect(tok_identi, "frame")->text);
|
|
|
|
int time = strtoi(st->expect(tok_number, "time")->text, NULL, 0);
|
|
|
|
|
|
|
|
M_Vec_growN(decl->frame, strlen(frames), 0);
|
|
|
|
for(char const *frame = frames; *frame; frame++) {
|
|
|
|
char *key = M_StrFmt("%s%c", name, *frame);
|
|
|
|
G_frdcl *fr = G_frametab.find(key);
|
|
|
|
if(!fr) st->throw(M_StrFmt("undefined frame '%s'", key));
|
|
|
|
decl->frameV[decl->frameC++] = (G_frame){time, fr->sprite};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// G_ObjDef_parseAnimDef
|
|
|
|
//
|
|
|
|
static void G_ObjDef_parseAnimDef(G_dodst *st)
|
|
|
|
{
|
|
|
|
bool ins = true;
|
|
|
|
G_andcl *decl;
|
|
|
|
|
|
|
|
__with(char const *name = st->expect(tok_identi, "anim name")->text;)
|
|
|
|
{
|
|
|
|
if((decl = G_animsmap.find(name)) == NULL) {
|
|
|
|
M_Vec_grow(G_anvec, 1);
|
|
|
|
*(decl = &G_anvecV[G_anvecC++]) = (G_andcl){};
|
|
|
|
M_strbufcpy(decl->name, name);
|
|
|
|
} else {
|
|
|
|
ins = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
st->expect(tok_braceo, "'{'");
|
|
|
|
|
|
|
|
while(!st->drop(tok_bracec))
|
|
|
|
G_ObjDef_parseAnim(st, decl);
|
|
|
|
|
|
|
|
if(ins) {
|
|
|
|
decl->keyhash = M_StrHash(decl->name);
|
|
|
|
G_animsmap.insert(decl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// G_ObjDef_parseEntDef
|
|
|
|
//
|
|
|
|
static void G_ObjDef_parseEntDef(G_dodst *st)
|
|
|
|
{
|
|
|
|
bool ins = true;
|
|
|
|
G_etdcl *decl;
|
|
|
|
|
|
|
|
__with(char const *name = st->expect(tok_identi, "entity name")->text;)
|
|
|
|
{
|
|
|
|
if((decl = G_enttypes.find(name)) == NULL) {
|
|
|
|
M_Vec_grow(G_etvec, 1);
|
|
|
|
*(decl = &G_etvecV[G_etvecC++]) = (G_etdcl){};
|
|
|
|
M_strbufcpy(decl->name, name);
|
|
|
|
G_anims_ctor(&decl->anim, 8, 8);
|
|
|
|
} else {
|
|
|
|
ins = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(st->drop(tok_lt)) {
|
|
|
|
G_etdcl *base =
|
|
|
|
G_enttypes.find(st->expect(tok_identi, "base entity name")->text);
|
|
|
|
if(!base) st->throw("base type not found");
|
|
|
|
decl->type = base->type;
|
|
|
|
}
|
|
|
|
|
|
|
|
st->expect(tok_braceo, "'{'");
|
|
|
|
|
|
|
|
for(M_token *tok; (tok = st->getToken())->type != tok_bracec;)
|
|
|
|
switch(tok->type)
|
|
|
|
{
|
|
|
|
case tok_identi:
|
|
|
|
if(strcmp(tok->text, "anim") == 0)
|
|
|
|
G_ObjDef_getEntAnim(st, decl);
|
|
|
|
else
|
|
|
|
G_ObjDef_getEntProp(st, &decl->type, tok->text);
|
|
|
|
break;
|
|
|
|
case tok_semico:
|
|
|
|
continue;
|
|
|
|
default:
|
|
|
|
st->throw("expected '}'");
|
|
|
|
}
|
|
|
|
|
|
|
|
if(ins) {
|
|
|
|
decl->keyhash = M_StrHash(decl->name);
|
|
|
|
G_enttypes.insert(decl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Extern Functions ----------------------------------------------------------|
|
|
|
|
|
|
|
|
//
|
|
|
|
// G_ObjDef_Init
|
|
|
|
//
|
|
|
|
void G_ObjDef_Init(void)
|
|
|
|
{
|
|
|
|
G_ofmap_ctor(&G_objfuncs, 16, 16);
|
|
|
|
G_etmap_ctor(&G_enttypes, 16, 16);
|
|
|
|
G_frmap_ctor(&G_frametab, 16, 16);
|
|
|
|
G_anmap_ctor(&G_animsmap, 16, 16);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// G_ObjDef_Load
|
|
|
|
//
|
|
|
|
void G_ObjDef_Load(char const *fname)
|
|
|
|
{
|
|
|
|
G_dodst st = {.fp = fopen(fname, "r"), .fname = fname, .lines = 1};
|
|
|
|
|
|
|
|
if(!st.fp) {
|
|
|
|
fprintf(stderr, "ObjDef: couldn't open file '%s'\n", fname);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(setjmp(st.ejmp) == 1)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
for(M_token *tok; (tok = st.getToken())->type != tok_eof;)
|
|
|
|
switch(tok->type)
|
|
|
|
{
|
|
|
|
case tok_identi:
|
|
|
|
if(strcmp(tok->text, "entity") == 0)
|
|
|
|
G_ObjDef_parseEntDef(&st);
|
|
|
|
else if(strcmp(tok->text, "anim") == 0)
|
|
|
|
G_ObjDef_parseAnimDef(&st);
|
|
|
|
else if(strcmp(tok->text, "frame") == 0)
|
|
|
|
G_ObjDef_parseFrameDef(&st);
|
|
|
|
else if(strcmp(tok->text, "include") == 0)
|
|
|
|
G_ObjDef_Load(st.expect(tok_string, "string")->text);
|
|
|
|
else
|
|
|
|
st.throw("unknown identifier in toplevel");
|
|
|
|
continue;
|
|
|
|
default:
|
|
|
|
st.throw("expected toplevel definition");
|
|
|
|
}
|
|
|
|
|
|
|
|
printf("ObjDef: '%s' loaded.\n", fname);
|
|
|
|
|
|
|
|
done:
|
|
|
|
fclose(st.fp);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// G_ObjDef_LoadFunc
|
|
|
|
//
|
|
|
|
void G_ObjDef_LoadFunc(char const *name, DGE_CallbackType fptr)
|
|
|
|
{
|
|
|
|
M_Vec_grow(G_ofvec, 1);
|
|
|
|
G_ofvecV[G_ofvecC] = (G_ofdcl){fptr, name, M_StrHash(name)};
|
|
|
|
G_objfuncs.insert(&G_ofvecV[G_ofvecC++]);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// G_ObjDef_GetType
|
|
|
|
//
|
|
|
|
G_entty const *G_ObjDef_GetType(char const *name)
|
|
|
|
{
|
|
|
|
G_etdcl const *decl = G_enttypes.find(name);
|
|
|
|
return decl ? &decl->type : NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// G_ObjDef_GetAnim
|
|
|
|
//
|
|
|
|
G_anima const *G_ObjDef_GetAnim(G_entty const *type, char const *name)
|
|
|
|
{
|
|
|
|
G_manim *anim = ((G_etdcl *)type)->anim.find(name);
|
|
|
|
return anim ? &anim->anim : NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// EOF
|