diff --git a/dat/spfx.xml b/dat/spfx.xml new file mode 100644 index 0000000..c3ae373 --- /dev/null +++ b/dat/spfx.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="UTF-8"?> +<spfxs> + <spfx name="ExpS"> + <gfx x="6" y="5">exps</gfx> + <anim>400</anim> + </spfx> + <spfx name="ExpM"> + <gfx x="6" y="5">expm</gfx> + <anim>450</anim> + </spfx> + <spfx name="ExpL"> + <gfx x="6" y="5">expl</gfx> + <anim>500</anim> + </spfx> + <spfx name="cargo"> + <gfx x="6" y="6">cargo</gfx> + <ttl>15000</ttl> + <anim>5000</anim> + </spfx> + <spfx name="EmpS"> + <gfx x="6" y="5">emps</gfx> + <anim>400</anim> + </spfx> + <spfx name="EmpM"> + <gfx x="6" y="5">empm</gfx> + <anim>450</anim> + </spfx> + <spfx name="ShiS"> + <gfx x="6" y="5">shis</gfx> + <anim>400</anim> + </spfx> + <spfx name="ShiM"> + <gfx x="6" y="5">shim</gfx> + <anim>450</anim> + </spfx> + <spfx name="PlaS"> + <gfx x="6" y="5">plas</gfx> + <anim>400</anim> + </spfx> + <spfx name="PlaM"> + <gfx x="6" y="5">plam</gfx> + <anim>450</anim> + </spfx> +</spfxs> diff --git a/src/spfx.c b/src/spfx.c index 6f0a492..d1006bb 100644 --- a/src/spfx.c +++ b/src/spfx.c @@ -16,13 +16,22 @@ #include "opengl.h" #include "pause.h" #include "rng.h" +#include "ldata.h" +#include "lxml.h" #include "spfx.h" -#define SPFX_GFX "../gfx/spfx/" /**< Graphics location. */ -#define SPFX_CHUNK 32 /**< Chunk to allocate when needed. */ -#define SHAKE_VEL_MOD 0.0008 /**< Shake modifier. */ +#define SPFX_XML_ID "spfxs" /**< XML Document tag. */ +#define SPFX_XML_TAG "spfx" /**< SPFX XML node tag. */ -#define HAPTIC_UPDATE_INTERVAL 0.1 /**< Time between haptic updates. */ +#define SPFX_DATA "../dat/spfx.xml" /**< Location of the spfx datafile. */ +#define SPFX_GFX_PRE "../gfx/spfx/" /**< Location of the graphic. */ +#define SPFX_GFX_SUF ".png" /**< Suffix of graphics. */ + +#define CHUNK_SIZE 32 /**< Chunk size to allocate spfx bases. */ +#define SPFX_CHUNK 32 /**< Chunk to allocate when needed. */ +#define SHAKE_VEL_MOD 0.0008 /**< Shake modifier. */ + +#define HAPTIC_UPDATE_INTERVAL 0.1 /**< Time between haptic updates. */ /* Special hardcoded effects.. */ @@ -81,7 +90,7 @@ static int spfx_nstack_back = 0; /**< Number of special effects in the static int spfx_mstack_back = 0; /**< Memory allocated for special effects in back. */ /* General. */ -static int spfx_base_load(char* name, int ttl, int anim, char* gfx, int sx, int sy); +static int spfx_base_parse(SPFX_Base* tmp, const xmlNodePtr parent); static void spfx_base_free(SPFX_Base* effect); static void spfx_destroy(SPFX* layer, int* nlayer, int spfx); static void spfx_update_layer(SPFX* layer, int* nlayer, const double dt); @@ -90,28 +99,42 @@ static int spfx_hapticInit(void); static void spfx_hapticRumble(double mod); /** - * @brief Load an SPFX_Base into the stack based on some params. - * @param name Name of the spfx. - * @param ttl Time to live of the spfx. - * @param gfx Name of the graphic effect to use. - * @param sx Number of x sprites in the graphic. - * @param sy Number of y sprites in the graphic. + * @brief Parse an xml node containing an spfx. + * @param tmp Address to load sfx into. + * @param parent XML node containing the spfx data. * @return 0 on success. */ -static int spfx_base_load(char* name, int ttl, int anim, char* gfx, int sx, int sy) { - SPFX_Base* cur; - char buf[PATH_MAX]; +static int spfx_base_parse(SPFX_Base* tmp, const xmlNodePtr parent) { + xmlNodePtr node; - /* Create new effect. */ - spfx_effects = realloc(spfx_effects, ++spfx_neffects*sizeof(SPFX_Base)); - cur = &spfx_effects[spfx_neffects-1]; + /* Clear data. */ + memset(tmp, 0, sizeof(SPFX_Base)); - /* Fill it with the data. */ - cur->name = strdup(name); - cur->anim = (double)anim / 1000.; - cur->ttl = (double)ttl / 1000.; - snprintf(buf, PATH_MAX, SPFX_GFX"%s", gfx); - cur->gfx = gl_newSprite(buf, sx, sy, 0); + /* Get the name (mallocs). */ + tmp->name = xml_nodeProp(parent, "name"); + + /* Extract the data. */ + node = parent->xmlChildrenNode; + do { + xmlr_float(node, "anim", tmp->anim); + xmlr_float(node, "ttl", tmp->ttl); + if(xml_isNode(node, "gfx")) + tmp->gfx = xml_parseTexture(node, + SPFX_GFX_PRE"%s"SPFX_GFX_SUF, 6, 5, 0); + } while(xml_nextNode(node)); + + /* Convert from ms to s. */ + tmp->anim /= 1000.; + tmp->ttl /= 1000.; + if(tmp->ttl == 0.) + tmp->ttl = tmp->anim; + +#define MELEMENT(o,s) \ + if(o) WARN("SPFX '%s' missing/invalid '"s"' element", tmp->name) /**< Define to help check for data errors. */ + MELEMENT(tmp->anim == 0., "anim"); + MELEMENT(tmp->ttl == 0., "ttl"); + MELEMENT(tmp->gfx == NULL, "gfx"); +#undef ELEMENT return 0; } @@ -121,8 +144,14 @@ static int spfx_base_load(char* name, int ttl, int anim, char* gfx, int sx, int * @param effect SPFX_Base to free. */ static void spfx_base_free(SPFX_Base* effect) { - if(effect->name != NULL) free(effect->name); - if(effect->gfx != NULL) gl_freeTexture(effect->gfx); + if(effect->name != NULL) { + free(effect->name); + effect->name = NULL; + } + if(effect->gfx != NULL) { + gl_freeTexture(effect->gfx); + effect->gfx = NULL; + } } /** @@ -146,22 +175,47 @@ int spfx_get(char* name) { * @todo Make spfx not hardcoded. */ int spfx_load(void) { - /* Standard explosion effects. */ - spfx_base_load("ExpS", 400, 400, "exps.png", 6, 5); - spfx_base_load("ExpM", 450, 450, "expm.png", 6, 5); - spfx_base_load("ExpL", 500, 500, "expl.png", 6, 5); - /* Cargo Rotation. */ - spfx_base_load("cargo", 15000, 5000, "cargo.png", 6, 6); - /* EMP Blasts. */ - spfx_base_load("EmpS", 400, 400, "emps.png", 6, 5); - spfx_base_load("EmpM", 450, 450, "empm.png", 6, 5); - /* Shield hits. */ - spfx_base_load("ShiS", 400, 400, "shis.png", 6, 5); - spfx_base_load("ShiM", 450, 450, "shim.png", 6, 5); - /* Plasma hits. */ - spfx_base_load("PlaS", 400, 400, "plas.png", 6, 5); - spfx_base_load("PlaM", 450, 450, "plam.png", 6, 5); + int mem; + uint32_t bufsize; + char* buf; + xmlNodePtr node; + xmlDocPtr doc; + /* Load and read the data. */ + buf = ldata_read(SPFX_DATA, &bufsize); + doc = xmlParseMemory(buf, bufsize); + + /* Check to see if document exists. */ + node = doc->xmlChildrenNode; + if(!xml_isNode(node, SPFX_XML_ID)) { + ERR("Malformed '"SPFX_DATA"' file: missing root element '"SPFX_XML_ID"'"); + return -1; + } + + /* Check to see if it's populated. */ + node = node->xmlChildrenNode; /* First system node. */ + if(node == NULL) { + ERR("Malformed '"SPFX_DATA"' file: does not contain elements"); + return -1; + } + + /* First pass, loads up ammunition. */ + mem = 0; + do { + if(xml_isNode(node, SPFX_XML_TAG)) { + spfx_neffects++; + if(spfx_neffects > mem) { + mem += CHUNK_SIZE; + spfx_effects = realloc(spfx_effects, sizeof(SPFX_Base)*mem); + } + spfx_base_parse(&spfx_effects[spfx_neffects-1], node); + } + } while(xml_nextNode(node)); + + /* Shrink back to minimum - shouldn't change ever. */ + spfx_effects = realloc(spfx_effects, sizeof(SPFX_Base) * spfx_neffects); + + /* Now initialize force feedback. */ spfx_hapticInit(); return 0;