corrected a few LittleLongs to LittleFloat in md3 loading (EEP those were bad)
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Thu, 31 Jul 2003 00:26:34 +0000 (00:26 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Thu, 31 Jul 2003 00:26:34 +0000 (00:26 +0000)
.skin loading is now able to parse the quake3 format, and uses "common/nodraw" or "textures/common/nodraw" for the invisible parts, this also meant supporting replacement tag names in the .skin files...  so that's implemented as well (quite difficult)
COM_ParseToken upgraded to be able to parse .skin files (now identifies more single character tokens, and can return newlines if desired - this required patching lots of code to pass false to it)
added beginnings of support for DPPROTOCOL_VERSION4 in client (I.E. does nothing right now because the server speaks DPPROTOCOL_VERSION3)

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@3352 d7cf8633-e32d-0410-b094-e92efae38249

14 files changed:
cl_parse.c
client.h
cmd.c
common.c
common.h
host_cmd.c
model_alias.c
model_brush.c
model_shared.c
model_shared.h
pr_cmds.c
pr_edict.c
protocol.c
r_shadow.c

index c51570b..f0beef0 100644 (file)
@@ -221,13 +221,13 @@ void CL_ParseEntityLump(char *entdata)
        data = entdata;
        if (!data)
                return;
-       if (!COM_ParseToken(&data))
+       if (!COM_ParseToken(&data, false))
                return; // error
        if (com_token[0] != '{')
                return; // error
        while (1)
        {
-               if (!COM_ParseToken(&data))
+               if (!COM_ParseToken(&data, false))
                        return; // error
                if (com_token[0] == '}')
                        break; // end of worldspawn
@@ -237,7 +237,7 @@ void CL_ParseEntityLump(char *entdata)
                        strcpy(key, com_token);
                while (key[strlen(key)-1] == ' ') // remove trailing spaces
                        key[strlen(key)-1] = 0;
-               if (!COM_ParseToken(&data))
+               if (!COM_ParseToken(&data, false))
                        return; // error
                strcpy(value, com_token);
                if (!strcmp("sky", key))
@@ -655,21 +655,26 @@ void CL_ParseUpdate (int bits)
 static entity_frame_t entityframe;
 void CL_ReadEntityFrame(void)
 {
-       entity_t *ent;
-       int i;
-       EntityFrame_Read(&cl.entitydatabase);
-       EntityFrame_FetchFrame(&cl.entitydatabase, EntityFrame_MostRecentlyRecievedFrameNum(&cl.entitydatabase), &entityframe);
-       for (i = 0;i < entityframe.numentities;i++)
+       if (dpprotocol == DPPROTOCOL_VERSION3)
        {
-               // copy the states
-               ent = &cl_entities[entityframe.entitydata[i].number];
-               ent->state_previous = ent->state_current;
-               ent->state_current = entityframe.entitydata[i];
-               CL_MoveLerpEntityStates(ent);
-               // the entity lives again...
-               entlife[ent->state_current.number] = 2;
-               cl_entities_active[ent->state_current.number] = true;
+               int i;
+               entity_t *ent;
+               EntityFrame_Read(&cl.entitydatabase);
+               EntityFrame_FetchFrame(&cl.entitydatabase, EntityFrame_MostRecentlyRecievedFrameNum(&cl.entitydatabase), &entityframe);
+               for (i = 0;i < entityframe.numentities;i++)
+               {
+                       // copy the states
+                       ent = &cl_entities[entityframe.entitydata[i].number];
+                       ent->state_previous = ent->state_current;
+                       ent->state_current = entityframe.entitydata[i];
+                       CL_MoveLerpEntityStates(ent);
+                       // the entity lives again...
+                       entlife[ent->state_current.number] = 2;
+                       cl_entities_active[ent->state_current.number] = true;
+               }
        }
+       else
+               EntityFrame4_CL_ReadFrame(&cl.entitydatabase4);
 }
 
 void CL_EntityUpdateSetup(void)
@@ -678,18 +683,21 @@ void CL_EntityUpdateSetup(void)
 
 void CL_EntityUpdateEnd(void)
 {
-       int i;
-       // disable entities that disappeared this frame
-       for (i = 1;i < MAX_EDICTS;i++)
+       if (dpprotocol != DPPROTOCOL_VERSION4)
        {
-               // clear only the entities that were active last frame but not this
-               // frame, don't waste time clearing all entities (which would cause
-               // cache misses)
-               if (entlife[i])
+               int i;
+               // disable entities that disappeared this frame
+               for (i = 1;i < MAX_EDICTS;i++)
                {
-                       entlife[i]--;
-                       if (!entlife[i])
-                               cl_entities[i].state_previous.active = cl_entities[i].state_current.active = 0;
+                       // clear only the entities that were active last frame but not this
+                       // frame, don't waste time clearing all entities (which would cause
+                       // cache misses)
+                       if (entlife[i])
+                       {
+                               entlife[i]--;
+                               if (!entlife[i])
+                                       cl_entities[i].state_previous.active = cl_entities[i].state_current.active = 0;
+                       }
                }
        }
 }
index 7682a95..4713f19 100644 (file)
--- a/client.h
+++ b/client.h
@@ -424,6 +424,7 @@ typedef struct
 
        // entity database stuff
        entity_database_t entitydatabase;
+       entity_database4_t entitydatabase4;
 }
 client_state_t;
 
diff --git a/cmd.c b/cmd.c
index 169f9ef..79f9137 100644 (file)
--- a/cmd.c
+++ b/cmd.c
@@ -552,7 +552,7 @@ static void Cmd_TokenizeString (const char *text)
                if (cmd_argc == 1)
                         cmd_args = text;
 
-               if (!COM_ParseToken (&text))
+               if (!COM_ParseToken(&text, false))
                        return;
 
                if (cmd_argc < MAX_ARGS)
index 9520cb3..c446123 100644 (file)
--- a/common.c
+++ b/common.c
@@ -506,7 +506,7 @@ COM_ParseToken
 Parse a token out of a string
 ==============
 */
-int COM_ParseToken (const char **datapointer)
+int COM_ParseToken(const char **datapointer, int returnnewline)
 {
        int c;
        int len;
@@ -523,7 +523,7 @@ int COM_ParseToken (const char **datapointer)
 
 // skip whitespace
 skipwhite:
-       while ((c = *data) <= ' ')
+       while ((c = *data) <= ' ' && (c != '\n' || !returnnewline))
        {
                if (c == 0)
                {
@@ -534,15 +534,25 @@ skipwhite:
                data++;
        }
 
-// skip // comments
-       if (c=='/' && data[1] == '/')
+       // check if it's a comment
+       if (c == '/')
        {
-               while (*data && *data != '\n')
-                       data++;
-               goto skipwhite;
+               // skip // comments
+               if (data[1] == '/')
+               {
+                       while (*data && *data != '\n')
+                               data++;
+                       goto skipwhite;
+               }
+               // skip /* comments
+               if (data[1] == '*')
+               {
+                       while (*data && *data != '*' && data[1] != '/')
+                               data++;
+                       goto skipwhite;
+               }
        }
 
-
 // handle quoted strings specially
        if (c == '\"')
        {
@@ -550,7 +560,7 @@ skipwhite:
                while (1)
                {
                        c = *data++;
-                       if (c=='\"' || !c)
+                       if (c == '\"' || !c)
                        {
                                com_token[len] = 0;
                                *datapointer = data;
@@ -562,7 +572,7 @@ skipwhite:
        }
 
 // parse single characters
-       if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
+       if (c == '{' || c == '}' || c == ')' || c == '(' || c == ']' || c == '[' || c == '\'' || c == ':' || c == ',' || c == ';' || c == '\n')
        {
                com_token[len] = c;
                len++;
@@ -578,7 +588,7 @@ skipwhite:
                data++;
                len++;
                c = *data;
-               if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
+               if (c == '{' || c == '}' || c == ')' || c == '(' || c == ']' || c == '[' || c == '\'' || c == ':' || c == ',' || c == ';')
                        break;
        } while (c>32);
 
index 9ba0ff9..f3e7be3 100644 (file)
--- a/common.h
+++ b/common.h
@@ -144,7 +144,7 @@ extern int dpprotocol;
 
 extern char com_token[1024];
 
-int COM_ParseToken (const char **data);
+int COM_ParseToken(const char **datapointer, int returnnewline);
 
 extern int com_argc;
 extern const char **com_argv;
index 201efa5..000e43a 100644 (file)
@@ -574,7 +574,7 @@ void Host_PerformLoadGame(char *name)
                        Host_Error ("Loadgame buffer overflow");
                buf[i] = 0;
                start = buf;
-               if (!COM_ParseToken(&start))
+               if (!COM_ParseToken(&start, false))
                {
                        // end of file
                        break;
@@ -1226,7 +1226,7 @@ void Host_Kick_f (void)
                if (Cmd_Argc() > 2)
                {
                        message = Cmd_Args();
-                       COM_ParseToken(&message);
+                       COM_ParseToken(&message, false);
                        if (byNumber)
                        {
                                message++;                                                      // skip the #
index f327e0d..aacae60 100644 (file)
@@ -230,26 +230,21 @@ void Mod_BuildAliasSkinsFromSkinFiles(aliasskin_t *skin, skinfile_t *skinfile, c
                        memset(skin, 0, sizeof(*skin));
                        for (skinfileitem = skinfile->items;skinfileitem;skinfileitem = skinfileitem->next)
                        {
-                               if (!strcmp(skinfileitem->name, meshname))
+                               // leave the skin unitialized (nodraw) if the replacement is "common/nodraw" or "textures/common/nodraw"
+                               if (!strcmp(skinfileitem->name, meshname) && strcmp(skinfileitem->replacement, "common/nodraw") && strcmp(skinfileitem->replacement, "textures/common/nodraw"))
                                {
-                                       if (!strcmp(skinfileitem->replacement, "common/nodraw"))
-                                       {
-                                       }
+                                       memset(&tempskinframe, 0, sizeof(tempskinframe));
+                                       if (Mod_LoadSkinFrame(&tempskinframe, skinfileitem->replacement, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_CLAMP | TEXF_PRECACHE, true, false, true))
+                                               Mod_BuildAliasSkinFromSkinFrame(skin, &tempskinframe);
                                        else
                                        {
-                                               memset(&tempskinframe, 0, sizeof(tempskinframe));
-                                               if (Mod_LoadSkinFrame(&tempskinframe, skinfileitem->replacement, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_CLAMP | TEXF_PRECACHE, true, false, true))
+                                               Con_Printf("mesh \"%s\": failed to load skin #%i \"%s\", falling back to mesh's internal shader name \"%s\"\n", meshname, i, skinfileitem->replacement, shadername);
+                                               if (Mod_LoadSkinFrame(&tempskinframe, shadername, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_CLAMP | TEXF_PRECACHE, true, false, true))
                                                        Mod_BuildAliasSkinFromSkinFrame(skin, &tempskinframe);
                                                else
                                                {
-                                                       Con_Printf("mesh \"%s\": failed to load skin #%i \"%s\", falling back to mesh's internal shader name \"%s\"\n", meshname, i, skinfileitem->replacement, shadername);
-                                                       if (Mod_LoadSkinFrame(&tempskinframe, shadername, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_CLAMP | TEXF_PRECACHE, true, false, true))
-                                                               Mod_BuildAliasSkinFromSkinFrame(skin, &tempskinframe);
-                                                       else
-                                                       {
-                                                               Con_Printf("failed to load skin \"%s\"\n", shadername);
-                                                               Mod_BuildAliasSkinFromSkinFrame(skin, NULL);
-                                                       }
+                                                       Con_Printf("failed to load skin \"%s\"\n", shadername);
+                                                       Mod_BuildAliasSkinFromSkinFrame(skin, NULL);
                                                }
                                        }
                                }
@@ -472,7 +467,7 @@ void Mod_IDP0_Load(model_t *mod, void *buffer)
        // load the skins
        if ((skinfiles = Mod_LoadSkinFiles()))
        {
-               loadmodel->alias.aliasdata_meshes->num_skins = totalskins = loadmodel->numskins = Mod_CountSkinFiles(skinfiles);
+               loadmodel->alias.aliasdata_meshes->num_skins = totalskins = loadmodel->numskins;
                loadmodel->alias.aliasdata_meshes->data_skins = Mem_Alloc(loadmodel->mempool, loadmodel->alias.aliasdata_meshes->num_skins * sizeof(aliasskin_t));
                Mod_BuildAliasSkinsFromSkinFiles(loadmodel->alias.aliasdata_meshes->data_skins, skinfiles, "default", "");
                Mod_FreeSkinFiles(skinfiles);
@@ -655,7 +650,7 @@ void Mod_IDP2_Load(model_t *mod, void *buffer)
        inskin = (void*)(base + LittleLong(pinmodel->ofs_skins));
        if ((skinfiles = Mod_LoadSkinFiles()))
        {
-               loadmodel->alias.aliasdata_meshes->num_skins = loadmodel->numskins = Mod_CountSkinFiles(skinfiles);
+               loadmodel->alias.aliasdata_meshes->num_skins = loadmodel->numskins;
                loadmodel->alias.aliasdata_meshes->data_skins = Mem_Alloc(loadmodel->mempool, loadmodel->alias.aliasdata_meshes->num_skins * sizeof(aliasskin_t));
                Mod_BuildAliasSkinsFromSkinFiles(loadmodel->alias.aliasdata_meshes->data_skins, skinfiles, "default", "");
                Mod_FreeSkinFiles(skinfiles);
@@ -826,7 +821,6 @@ void Mod_IDP3_Load(model_t *mod, void *buffer)
                        loadmodel->name, version, MD3VERSION);
 
        skinfiles = Mod_LoadSkinFiles();
-       loadmodel->numskins = Mod_CountSkinFiles(skinfiles);
        if (loadmodel->numskins < 1)
                loadmodel->numskins = 1;
 
@@ -869,16 +863,17 @@ void Mod_IDP3_Load(model_t *mod, void *buffer)
        loadmodel->alias.aliasnum_tagframes = loadmodel->numframes;
        loadmodel->alias.aliasnum_tags = LittleLong(pinmodel->num_tags);
        loadmodel->alias.aliasdata_tags = Mem_Alloc(loadmodel->mempool, loadmodel->alias.aliasnum_tagframes * loadmodel->alias.aliasnum_tags * sizeof(aliastag_t));
-       for (i = 0, pintag = (md3tag_t *)((qbyte *)pinmodel + LittleLong(pinmodel->lump_tags));i < loadmodel->alias.aliasnum_tagframes * loadmodel->alias.aliasnum_tags;i++, pinframe++)
+       for (i = 0, pintag = (md3tag_t *)((qbyte *)pinmodel + LittleLong(pinmodel->lump_tags));i < loadmodel->alias.aliasnum_tagframes * loadmodel->alias.aliasnum_tags;i++, pintag++)
        {
                strcpy(loadmodel->alias.aliasdata_tags[i].name, pintag->name);
                Matrix4x4_CreateIdentity(&loadmodel->alias.aliasdata_tags[i].matrix);
                for (j = 0;j < 3;j++)
                {
                        for (k = 0;k < 3;k++)
-                               loadmodel->alias.aliasdata_tags[i].matrix.m[j][k] = LittleLong(pintag->rotationmatrix[j * 3 + k]);
-                       loadmodel->alias.aliasdata_tags[i].matrix.m[j][3] = LittleLong(pintag->origin[j]);
+                               loadmodel->alias.aliasdata_tags[i].matrix.m[j][k] = LittleFloat(pintag->rotationmatrix[j * 3 + k]);
+                       loadmodel->alias.aliasdata_tags[i].matrix.m[j][3] = LittleFloat(pintag->origin[j]);
                }
+               //Con_Printf("model \"%s\" frame #%i tag #%i \"%s\"\n", loadmodel->name, i / loadmodel->alias.aliasnum_tags, i % loadmodel->alias.aliasnum_tags, loadmodel->alias.aliasdata_tags[i].name);
        }
 
        // load meshes
@@ -904,8 +899,8 @@ void Mod_IDP3_Load(model_t *mod, void *buffer)
                        mesh->data_element3i[j] = LittleLong(((int *)((qbyte *)pinmesh + pinmesh->lump_elements))[j]);
                for (j = 0;j < mesh->num_vertices;j++)
                {
-                       mesh->data_texcoord2f[j * 2 + 0] = LittleLong(((float *)((qbyte *)pinmesh + pinmesh->lump_texcoords))[j * 2 + 0]);
-                       mesh->data_texcoord2f[j * 2 + 1] = LittleLong(((float *)((qbyte *)pinmesh + pinmesh->lump_texcoords))[j * 2 + 1]);
+                       mesh->data_texcoord2f[j * 2 + 0] = LittleFloat(((float *)((qbyte *)pinmesh + pinmesh->lump_texcoords))[j * 2 + 0]);
+                       mesh->data_texcoord2f[j * 2 + 1] = LittleFloat(((float *)((qbyte *)pinmesh + pinmesh->lump_texcoords))[j * 2 + 1]);
                }
                for (j = 0;j < mesh->num_vertices * mesh->num_frames;j++)
                {
@@ -922,10 +917,8 @@ void Mod_IDP3_Load(model_t *mod, void *buffer)
                if (LittleLong(pinmesh->num_shaders) >= 1 && ((md3shader_t *)((qbyte *) pinmesh + pinmesh->lump_shaders))->name[0])
                        Mod_BuildAliasSkinsFromSkinFiles(mesh->data_skins, skinfiles, pinmesh->name, ((md3shader_t *)((qbyte *) pinmesh + pinmesh->lump_shaders))->name);
                else
-               {
                        for (j = 0;j < mesh->num_skins;j++)
                                Mod_BuildAliasSkinFromSkinFrame(mesh->data_skins + j, NULL);
-               }
        }
        Mod_CalcAliasModelBBoxes();
        Mod_FreeSkinFiles(skinfiles);
index 2a466fc..df7b4dc 100644 (file)
@@ -1195,13 +1195,13 @@ static void Mod_Q1BSP_ParseWadsFromEntityLump(const char *data)
        int i, j, k;
        if (!data)
                return;
-       if (!COM_ParseToken(&data))
+       if (!COM_ParseToken(&data, false))
                return; // error
        if (com_token[0] != '{')
                return; // error
        while (1)
        {
-               if (!COM_ParseToken(&data))
+               if (!COM_ParseToken(&data, false))
                        return; // error
                if (com_token[0] == '}')
                        break; // end of worldspawn
@@ -1211,7 +1211,7 @@ static void Mod_Q1BSP_ParseWadsFromEntityLump(const char *data)
                        strcpy(key, com_token);
                while (key[strlen(key)-1] == ' ') // remove trailing spaces
                        key[strlen(key)-1] = 0;
-               if (!COM_ParseToken(&data))
+               if (!COM_ParseToken(&data, false))
                        return; // error
                strcpy(value, com_token);
                if (!strcmp("wad", key)) // for HalfLife maps
@@ -3478,11 +3478,11 @@ static void Mod_Q3BSP_LoadEntities(lump_t *l)
        memcpy(loadmodel->brush.entities, mod_base + l->fileofs, l->filelen);
        data = loadmodel->brush.entities;
        // some Q3 maps override the lightgrid_cellsize with a worldspawn key
-       if (data && COM_ParseToken(&data) && com_token[0] == '{')
+       if (data && COM_ParseToken(&data, false) && com_token[0] == '{')
        {
                while (1)
                {
-                       if (!COM_ParseToken(&data))
+                       if (!COM_ParseToken(&data, false))
                                break; // error
                        if (com_token[0] == '}')
                                break; // end of worldspawn
@@ -3492,7 +3492,7 @@ static void Mod_Q3BSP_LoadEntities(lump_t *l)
                                strcpy(key, com_token);
                        while (key[strlen(key)-1] == ' ') // remove trailing spaces
                                key[strlen(key)-1] = 0;
-                       if (!COM_ParseToken(&data))
+                       if (!COM_ParseToken(&data, false))
                                break; // error
                        strcpy(value, com_token);
                        if (!strcmp("gridsize", key))
index 7b0a858..d993fe8 100644 (file)
@@ -904,50 +904,114 @@ void Mod_ConstructTerrainPatchFromRGBA(const qbyte *imagepixels, int imagewidth,
 
 skinfile_t *Mod_LoadSkinFiles(void)
 {
-       int i;
+       int i, words, numtags, line, tagsetsused = false, wordsoverflow;
        char *text;
        const char *data;
        skinfile_t *skinfile, *first = NULL;
        skinfileitem_t *skinfileitem;
-       char command[MAX_QPATH], name[MAX_QPATH], replacement[MAX_QPATH];
-       for (i = 0;(data = text = FS_LoadFile(va("%s_%i.skin", loadmodel->name, i), true));i++)
+       char word[10][MAX_QPATH];
+       overridetagnameset_t tagsets[MAX_SKINS];
+       overridetagname_t tags[256];
+
+/*
+sample file:
+U_bodyBox,models/players/Legoman/BikerA2.tga
+U_RArm,models/players/Legoman/BikerA1.tga
+U_LArm,models/players/Legoman/BikerA1.tga
+U_armor,common/nodraw
+U_sword,common/nodraw
+U_shield,common/nodraw
+U_homb,common/nodraw
+U_backpack,common/nodraw
+U_colcha,common/nodraw
+tag_head,
+tag_weapon,
+tag_torso,
+*/
+       memset(tagsets, 0, sizeof(tagsets));
+       memset(word, 0, sizeof(word));
+       for (i = 0;i < MAX_SKINS && (data = text = FS_LoadFile(va("%s_%i.skin", loadmodel->name, i), true));i++)
        {
+               numtags = 0;
                skinfile = Mem_Alloc(tempmempool, sizeof(skinfile_t));
                skinfile->next = first;
                first = skinfile;
-               for(;;)
+               for(line = 0;;line++)
                {
-                       if (!COM_ParseToken(&data))
+                       // parse line
+                       if (!COM_ParseToken(&data, true))
                                break;
-                       strncpy(command, com_token, sizeof(command) - 1);
-                       command[sizeof(command) - 1] = 0;
-                       if (!strcmp(command, "replace"))
+                       if (!strcmp(com_token, "\n"))
+                               continue;
+                       words = 0;
+                       wordsoverflow = false;
+                       do
                        {
-                               if (!COM_ParseToken(&data))
-                               {
-                                       Con_Printf("Mod_LoadSkinFiles: parsing error (insufficient parameters to command \"%s\" in file \"%s_%i.skin\")\n", command, loadmodel->name, i);
-                                       break;
-                               }
-                               strncpy(name, com_token, sizeof(name) - 1);
-                               name[sizeof(name) - 1] = 0;
-                               if (!COM_ParseToken(&data))
+                               if (words < 10)
+                                       strncpy(word[words++], com_token, MAX_QPATH - 1);
+                               else
+                                       wordsoverflow = true;
+                       }
+                       while (COM_ParseToken(&data, true) && strcmp(com_token, "\n"));
+                       if (wordsoverflow)
+                       {
+                               Con_Printf("Mod_LoadSkinFiles: parsing error in file \"%s_%i.skin\" on line #%i: line with too many statements, skipping\n", loadmodel->name, i, line);
+                               continue;
+                       }
+                       // words is always >= 1
+                       if (!strcmp(word[0], "replace"))
+                       {
+                               if (words == 3)
                                {
-                                       Con_Printf("Mod_LoadSkinFiles: parsing error (insufficient parameters to command \"%s\" in file \"%s_%i.skin\")\n", command, loadmodel->name, i);
-                                       break;
+                                       Con_DPrintf("Mod_LoadSkinFiles: parsed mesh \"%s\" shader replacement \"%s\"\n", word[1], word[2]);
+                                       skinfileitem = Mem_Alloc(tempmempool, sizeof(skinfileitem_t));
+                                       skinfileitem->next = skinfile->items;
+                                       skinfile->items = skinfileitem;
+                                       strncpy(skinfileitem->name, word[1], sizeof(skinfileitem->name) - 1);
+                                       strncpy(skinfileitem->replacement, word[2], sizeof(skinfileitem->replacement) - 1);
                                }
-                               strncpy(replacement, com_token, sizeof(replacement) - 1);
-                               replacement[sizeof(replacement) - 1] = 0;
+                               else
+                                       Con_Printf("Mod_LoadSkinFiles: parsing error in file \"%s_%i.skin\" on line #%i: wrong number of parameters to command \"%s\", see documentation in DP_GFX_SKINFILES extension in dpextensions.qc\n", loadmodel->name, i, line, word[0]);
+                       }
+                       else if (words == 2 && !strcmp(word[1], ","))
+                       {
+                               // tag name, like "tag_weapon,"
+                               Con_DPrintf("Mod_LoadSkinFiles: parsed tag #%i \"%s\"\n", numtags, word[0]);
+                               memset(tags + numtags, 0, sizeof(tags[numtags]));
+                               strncpy(tags[numtags].name, word[0], sizeof(tags[numtags].name) - 1);
+                               numtags++;
+                       }
+                       else if (words == 3 && !strcmp(word[1], ","))
+                       {
+                               // mesh shader name, like "U_RArm,models/players/Legoman/BikerA1.tga"
+                               Con_DPrintf("Mod_LoadSkinFiles: parsed mesh \"%s\" shader replacement \"%s\"\n", word[0], word[2]);
                                skinfileitem = Mem_Alloc(tempmempool, sizeof(skinfileitem_t));
                                skinfileitem->next = skinfile->items;
                                skinfile->items = skinfileitem;
-                               strncpy(skinfileitem->name, name, sizeof(skinfileitem->name) - 1);
-                               strncpy(skinfileitem->replacement, replacement, sizeof(skinfileitem->replacement) - 1);
+                               strncpy(skinfileitem->name, word[0], sizeof(skinfileitem->name) - 1);
+                               strncpy(skinfileitem->replacement, word[2], sizeof(skinfileitem->replacement) - 1);
                        }
                        else
-                               Con_Printf("Mod_LoadSkinFiles: parsing error (unknown command \"%s\" in file \"%s_%i.skin\")\n", command, loadmodel->name, i);
+                               Con_Printf("Mod_LoadSkinFiles: parsing error in file \"%s_%i.skin\" on line #%i: does not look like tag or mesh specification, or replace command, see documentation in DP_GFX_SKINFILES extension in dpextensions.qc\n", loadmodel->name, i, line);
                }
                Mem_Free(text);
+
+               if (numtags)
+               {
+                       overridetagnameset_t *t;
+                       t = tagsets + i;
+                       t->num_overridetagnames = numtags;
+                       t->data_overridetagnames = Mem_Alloc(loadmodel->mempool, t->num_overridetagnames * sizeof(overridetagname_t));
+                       memcpy(t->data_overridetagnames, tags, t->num_overridetagnames * sizeof(overridetagname_t));
+                       tagsetsused = true;
+               }
+       }
+       if (tagsetsused)
+       {
+               loadmodel->data_overridetagnamesforskin = Mem_Alloc(loadmodel->mempool, i * sizeof(overridetagnameset_t));
+               memcpy(loadmodel->data_overridetagnamesforskin, tagsets, i * sizeof(overridetagnameset_t));
        }
+       loadmodel->numskins = i;
        return first;
 }
 
index 29e4fc5..0d22a50 100644 (file)
@@ -61,6 +61,20 @@ skinframe_t;
 
 #define MAX_SKINS 256
 
+typedef struct overridetagname_s
+{
+       char name[MAX_QPATH];
+}
+overridetagname_t;
+
+// a replacement set of tag names, per skin
+typedef struct overridetagnameset_s
+{
+       int num_overridetagnames;
+       overridetagname_t *data_overridetagnames;
+}
+overridetagnameset_t;
+
 #define SHADOWMESHVERTEXHASH 1024
 typedef struct shadowmeshvertexhash_s
 {
@@ -474,6 +488,8 @@ typedef struct model_s
        model_brushq2_t brushq2;
        */
        model_brushq3_t brushq3;
+       // skin files can have different tags for each skin
+       overridetagnameset_t    *data_overridetagnamesforskin;
 }
 model_t;
 
index 1eeefc2..72c7233 100644 (file)
--- a/pr_cmds.c
+++ b/pr_cmds.c
@@ -2931,7 +2931,7 @@ void PF_tokenize (void)
        tokens = Z_Malloc(strlen(str) * sizeof(char *));
        max_tokens = strlen(str);
 
-       for (p = str;COM_ParseToken(&p) && num_tokens < max_tokens;num_tokens++)
+       for (p = str;COM_ParseToken(&p, false) && num_tokens < max_tokens;num_tokens++)
        {
                tokens[num_tokens] = Z_Malloc(strlen(com_token) + 1);
                strcpy(tokens[num_tokens], com_token);
@@ -2977,7 +2977,11 @@ void PF_setattachment (void)
                if (modelindex >= 0 && modelindex < MAX_MODELS)
                {
                        model = sv.models[modelindex];
-                       if (model->alias.aliasnum_tags)
+                       if (model->data_overridetagnamesforskin && (unsigned int)tagentity->v->skin < model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames)
+                               for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames;i++)
+                                       if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].data_overridetagnames[i].name))
+                                               v->_float = i + 1;
+                       if (v->_float == 0 && model->alias.aliasnum_tags)
                                for (i = 0;i < model->alias.aliasnum_tags;i++)
                                        if (!strcmp(tagname, model->alias.aliasdata_tags[i].name))
                                                v->_float = i + 1;
index 324ad38..9f22b1e 100644 (file)
@@ -814,7 +814,7 @@ void ED_ParseGlobals (const char *data)
        while (1)
        {
                // parse key
-               if (!COM_ParseToken (&data))
+               if (!COM_ParseToken(&data, false))
                        Host_Error ("ED_ParseEntity: EOF without closing brace");
                if (com_token[0] == '}')
                        break;
@@ -822,7 +822,7 @@ void ED_ParseGlobals (const char *data)
                strcpy (keyname, com_token);
 
                // parse value
-               if (!COM_ParseToken (&data))
+               if (!COM_ParseToken(&data, false))
                        Host_Error ("ED_ParseEntity: EOF without closing brace");
 
                if (com_token[0] == '}')
@@ -982,7 +982,7 @@ const char *ED_ParseEdict (const char *data, edict_t *ent)
        while (1)
        {
        // parse key
-               if (!COM_ParseToken (&data))
+               if (!COM_ParseToken(&data, false))
                        Host_Error ("ED_ParseEntity: EOF without closing brace");
                if (com_token[0] == '}')
                        break;
@@ -1012,7 +1012,7 @@ const char *ED_ParseEdict (const char *data, edict_t *ent)
                }
 
        // parse value
-               if (!COM_ParseToken (&data))
+               if (!COM_ParseToken(&data, false))
                        Host_Error ("ED_ParseEntity: EOF without closing brace");
 
                if (com_token[0] == '}')
@@ -1082,7 +1082,7 @@ void ED_LoadFromFile (const char *data)
        while (1)
        {
 // parse the opening brace
-               if (!COM_ParseToken (&data))
+               if (!COM_ParseToken(&data, false))
                        break;
                if (com_token[0] != '{')
                        Host_Error ("ED_LoadFromFile: found %s when expecting {",com_token);
index bd8b4f9..32624a4 100644 (file)
@@ -699,6 +699,7 @@ void EntityFrame4_SV_WriteFrame_End(entity_database4_t *d, sizebuf_t *msg)
        d->currentcommit = NULL;
 }
 
+extern void CL_MoveLerpEntityStates(entity_t *ent);
 void EntityFrame4_CL_ReadFrame(entity_database4_t *d)
 {
        int i, n, number, referenceframenum, framenum;
@@ -732,6 +733,8 @@ void EntityFrame4_CL_ReadFrame(entity_database4_t *d)
                }
                else
                        EntityState_Read(&cl_entities[number].state_current, EntityFrame4_GetReferenceEntity(d, number), number);
+               CL_MoveLerpEntityStates(&cl_entities[number]);
+               cl_entities_active[number] = true;
                if (d->currentcommit)
                        EntityFrame4_AddCommitEntity(d, &cl_entities[number].state_current);
        }
index 6e8ad30..1e3f3ec 100644 (file)
@@ -2282,7 +2282,7 @@ void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
        data = cl.worldmodel->brush.entities;
        if (!data)
                return;
-       for (entnum = 0;COM_ParseToken(&data) && com_token[0] == '{';entnum++)
+       for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
        {
                light = 0;
                origin[0] = origin[1] = origin[2] = 0;
@@ -2294,7 +2294,7 @@ void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
                islight = false;
                while (1)
                {
-                       if (!COM_ParseToken(&data))
+                       if (!COM_ParseToken(&data, false))
                                break; // error
                        if (com_token[0] == '}')
                                break; // end of entity
@@ -2304,7 +2304,7 @@ void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
                                strcpy(key, com_token);
                        while (key[strlen(key)-1] == ' ') // remove trailing spaces
                                key[strlen(key)-1] = 0;
-                       if (!COM_ParseToken(&data))
+                       if (!COM_ParseToken(&data, false))
                                break; // error
                        strcpy(value, com_token);