From ef35a088cb3ab1900acdbd5285465cd845368e79 Mon Sep 17 00:00:00 2001 From: havoc Date: Thu, 31 Jul 2003 00:26:34 +0000 Subject: [PATCH] corrected a few LittleLongs to LittleFloat in md3 loading (EEP those were bad) .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 --- cl_parse.c | 60 +++++++++++++++------------ client.h | 1 + cmd.c | 2 +- common.c | 32 +++++++++----- common.h | 2 +- host_cmd.c | 4 +- model_alias.c | 41 ++++++++---------- model_brush.c | 12 +++--- model_shared.c | 110 ++++++++++++++++++++++++++++++++++++++----------- model_shared.h | 16 +++++++ pr_cmds.c | 8 +++- pr_edict.c | 10 ++--- protocol.c | 3 ++ r_shadow.c | 6 +-- 14 files changed, 203 insertions(+), 104 deletions(-) diff --git a/cl_parse.c b/cl_parse.c index c51570b9..f0beef03 100644 --- a/cl_parse.c +++ b/cl_parse.c @@ -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; + } } } } diff --git a/client.h b/client.h index 7682a957..4713f19d 100644 --- 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 169f9efa..79f9137b 100644 --- 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) diff --git a/common.c b/common.c index 9520cb3f..c4461231 100644 --- 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); diff --git a/common.h b/common.h index 9ba0ff96..f3e7be34 100644 --- 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; diff --git a/host_cmd.c b/host_cmd.c index 201efa52..000e43a9 100644 --- a/host_cmd.c +++ b/host_cmd.c @@ -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 # diff --git a/model_alias.c b/model_alias.c index f327e0db..aacae600 100644 --- a/model_alias.c +++ b/model_alias.c @@ -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); diff --git a/model_brush.c b/model_brush.c index 2a466fcd..df7b4dce 100644 --- a/model_brush.c +++ b/model_brush.c @@ -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)) diff --git a/model_shared.c b/model_shared.c index 7b0a8581..d993fe8f 100644 --- a/model_shared.c +++ b/model_shared.c @@ -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; } diff --git a/model_shared.h b/model_shared.h index 29e4fc56..0d22a501 100644 --- a/model_shared.h +++ b/model_shared.h @@ -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; diff --git a/pr_cmds.c b/pr_cmds.c index 1eeefc2d..72c72335 100644 --- 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; diff --git a/pr_edict.c b/pr_edict.c index 324ad388..9f22b1e4 100644 --- a/pr_edict.c +++ b/pr_edict.c @@ -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); diff --git a/protocol.c b/protocol.c index bd8b4f90..32624a4f 100644 --- a/protocol.c +++ b/protocol.c @@ -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); } diff --git a/r_shadow.c b/r_shadow.c index 6e8ad302..1e3f3ec5 100644 --- a/r_shadow.c +++ b/r_shadow.c @@ -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); -- 2.39.2