X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=model_shared.c;h=840f8b7fb3cbebeb453da5b6d72b74193e5ca7af;hp=8aec8ba87daaee4fbfc3347ef9681a612ba0c8d6;hb=bf54dd6e7fb965287073b669235a7b30c7f96923;hpb=d39861bfe72a5a9ec8cfbcc83457db58a74b75d9 diff --git a/model_shared.c b/model_shared.c index 8aec8ba8..840f8b7f 100644 --- a/model_shared.c +++ b/model_shared.c @@ -92,6 +92,7 @@ static void mod_shutdown(void) Mod_UnloadModel(mod); Mod_FreeQ3Shaders(); + Mod_Skeletal_FreeBuffers(); } static void mod_newmap(void) @@ -148,7 +149,6 @@ Mod_Init static void Mod_Print(void); static void Mod_Precache (void); static void Mod_Decompile_f(void); -static void Mod_BuildVBOs(void); static void Mod_GenerateLightmaps_f(void); void Mod_Init (void) { @@ -194,12 +194,24 @@ void Mod_UnloadModel (dp_model_t *mod) strlcpy(name, mod->name, sizeof(name)); parentmodel = mod->brush.parentmodel; used = mod->used; - if (mod->surfmesh.ebo3i) - R_Mesh_DestroyBufferObject(mod->surfmesh.ebo3i); - if (mod->surfmesh.ebo3s) - R_Mesh_DestroyBufferObject(mod->surfmesh.ebo3s); - if (mod->surfmesh.vbo) - R_Mesh_DestroyBufferObject(mod->surfmesh.vbo); + if (mod->mempool) + { + if (mod->surfmesh.vertexpositionbuffer) + R_Mesh_DestroyMeshBuffer(mod->surfmesh.vertexpositionbuffer); + mod->surfmesh.vertexpositionbuffer = NULL; + if (mod->surfmesh.vertexmeshbuffer) + R_Mesh_DestroyMeshBuffer(mod->surfmesh.vertexmeshbuffer); + mod->surfmesh.vertexmeshbuffer = NULL; + if (mod->surfmesh.data_element3i_indexbuffer) + R_Mesh_DestroyMeshBuffer(mod->surfmesh.data_element3i_indexbuffer); + mod->surfmesh.data_element3i_indexbuffer = NULL; + if (mod->surfmesh.data_element3s_indexbuffer) + R_Mesh_DestroyMeshBuffer(mod->surfmesh.data_element3s_indexbuffer); + mod->surfmesh.data_element3s_indexbuffer = NULL; + if (mod->surfmesh.vbo_vertexbuffer) + R_Mesh_DestroyMeshBuffer(mod->surfmesh.vbo_vertexbuffer); + mod->surfmesh.vbo_vertexbuffer = NULL; + } // free textures/memory attached to the model R_FreeTexturePool(&mod->texturepool); Mem_FreePool(&mod->mempool); @@ -283,7 +295,7 @@ void Mod_FrameGroupify_ParseGroups_Store (unsigned int i, int start, int len, fl { dp_model_t *mod = (dp_model_t *) pass; animscene_t *anim = &mod->animscenes[i]; - dpsnprintf(anim->name, sizeof(anim[i].name), "groupified_%d", i); + dpsnprintf(anim->name, sizeof(anim[i].name), "groupified_%d_anim", i); anim->firstframe = bound(0, start, mod->num_poses - 1); anim->framecount = bound(1, len, mod->num_poses - anim->firstframe); anim->framerate = max(1, fps); @@ -312,6 +324,31 @@ void Mod_FrameGroupify(dp_model_t *mod, const char *buf) Mod_FrameGroupify_ParseGroups(buf, Mod_FrameGroupify_ParseGroups_Store, mod); } +void Mod_FindPotentialDeforms(dp_model_t *mod) +{ + int i, j; + texture_t *texture; + mod->wantnormals = false; + mod->wanttangents = false; + for (i = 0;i < mod->num_textures;i++) + { + texture = mod->data_textures + i; + if (texture->tcgen.tcgen == Q3TCGEN_ENVIRONMENT) + mod->wantnormals = true; + for (j = 0;j < Q3MAXDEFORMS;j++) + { + if (texture->deforms[j].deform == Q3DEFORM_AUTOSPRITE) + { + mod->wanttangents = true; + mod->wantnormals = true; + break; + } + if (texture->deforms[j].deform != Q3DEFORM_NONE) + mod->wantnormals = true; + } + } +} + /* ================== Mod_LoadModel @@ -433,7 +470,7 @@ dp_model_t *Mod_LoadModel(dp_model_t *mod, qboolean crash, qboolean checkdisk) num = LittleLong(*((int *)buf)); // call the apropriate loader loadmodel = mod; - if (!strcasecmp(FS_FileExtension(mod->name), "obj")) Mod_OBJ_Load(mod, buf, bufend); + if (!strcasecmp(FS_FileExtension(mod->name), "obj")) Mod_OBJ_Load(mod, buf, bufend); else if (!memcmp(buf, "IDPO", 4)) Mod_IDP0_Load(mod, buf, bufend); else if (!memcmp(buf, "IDP2", 4)) Mod_IDP2_Load(mod, buf, bufend); else if (!memcmp(buf, "IDP3", 4)) Mod_IDP3_Load(mod, buf, bufend); @@ -443,11 +480,14 @@ dp_model_t *Mod_LoadModel(dp_model_t *mod, qboolean crash, qboolean checkdisk) else if (!memcmp(buf, "ZYMOTICMODEL", 12)) Mod_ZYMOTICMODEL_Load(mod, buf, bufend); else if (!memcmp(buf, "DARKPLACESMODEL", 16)) Mod_DARKPLACESMODEL_Load(mod, buf, bufend); else if (!memcmp(buf, "ACTRHEAD", 8)) Mod_PSKMODEL_Load(mod, buf, bufend); + else if (!memcmp(buf, "INTERQUAKEMODEL", 16)) Mod_INTERQUAKEMODEL_Load(mod, buf, bufend); else if (strlen(mod->name) >= 4 && !strcmp(mod->name + strlen(mod->name) - 4, ".map")) Mod_MAP_Load(mod, buf, bufend); else if (num == BSPVERSION || num == 30) Mod_Q1BSP_Load(mod, buf, bufend); else Con_Printf("Mod_LoadModel: model \"%s\" is of unknown/unsupported type\n", mod->name); Mem_Free(buf); + Mod_FindPotentialDeforms(mod); + buf = FS_LoadFile (va("%s.framegroups", mod->name), tempmempool, false, &filesize); if(buf) { @@ -655,11 +695,11 @@ void Mod_BuildTriangleNeighbors(int *neighbors, const int *elements, int numtria int element[2]; } edgehashentry_t; - static edgehashentry_t *edgehash[TRIANGLEEDGEHASH]; + static edgehashentry_t **edgehash; edgehashentry_t *edgehashentries, *hash; if (!numtriangles) return; - memset(edgehash, 0, sizeof(edgehash)); + edgehash = Mem_Alloc(tempmempool, TRIANGLEEDGEHASH * sizeof(*edgehash)); // if there are too many triangles for the stack array, allocate larger buffer edgehashentries = (edgehashentry_t *)Mem_Alloc(tempmempool, numtriangles * 3 * sizeof(edgehashentry_t)); // find neighboring triangles @@ -711,6 +751,7 @@ void Mod_BuildTriangleNeighbors(int *neighbors, const int *elements, int numtria } // free the allocated buffer Mem_Free(edgehashentries); + Mem_Free(edgehash); } #else // very slow but simple way @@ -1146,24 +1187,60 @@ shadowmesh_t *Mod_ShadowMesh_Begin(mempool_t *mempool, int maxverts, int maxtria static void Mod_ShadowMesh_CreateVBOs(shadowmesh_t *mesh) { - if (!vid.support.arb_vertex_buffer_object) + if (!mesh->numverts) return; - // element buffer is easy because it's just one array - if (mesh->numtriangles) + // build r_vertexmesh_t array + // (compressed interleaved array for faster rendering) + if (!mesh->vertexmesh && mesh->texcoord2f) { - if (mesh->element3s) - mesh->ebo3s = R_Mesh_CreateStaticBufferObject(GL_ELEMENT_ARRAY_BUFFER_ARB, mesh->element3s, mesh->numtriangles * sizeof(unsigned short[3]), "shadowmesh"); - else - mesh->ebo3i = R_Mesh_CreateStaticBufferObject(GL_ELEMENT_ARRAY_BUFFER_ARB, mesh->element3i, mesh->numtriangles * sizeof(unsigned int[3]), "shadowmesh"); + int vertexindex; + int numvertices = mesh->numverts; + r_vertexmesh_t *vertexmesh; + mesh->vertexmesh = vertexmesh = (r_vertexmesh_t*)Mem_Alloc(loadmodel->mempool, numvertices * sizeof(*mesh->vertexmesh)); + for (vertexindex = 0;vertexindex < numvertices;vertexindex++, vertexmesh++) + { + VectorCopy(mesh->vertex3f + 3*vertexindex, vertexmesh->vertex3f); + VectorScale(mesh->svector3f + 3*vertexindex, 1.0f, vertexmesh->svector3f); + VectorScale(mesh->tvector3f + 3*vertexindex, 1.0f, vertexmesh->tvector3f); + VectorScale(mesh->normal3f + 3*vertexindex, 1.0f, vertexmesh->normal3f); + Vector2Copy(mesh->texcoord2f + 2*vertexindex, vertexmesh->texcoordtexture2f); + } + } + + // build r_vertexposition_t array + if (!mesh->vertexposition) + { + int vertexindex; + int numvertices = mesh->numverts; + r_vertexposition_t *vertexposition; + mesh->vertexposition = vertexposition = (r_vertexposition_t*)Mem_Alloc(loadmodel->mempool, numvertices * sizeof(*mesh->vertexposition)); + for (vertexindex = 0;vertexindex < numvertices;vertexindex++, vertexposition++) + VectorCopy(mesh->vertex3f + 3*vertexindex, vertexposition->vertex3f); } + // upload r_vertexmesh_t array as a buffer + if (mesh->vertexmesh && !mesh->vertexmeshbuffer) + mesh->vertexmeshbuffer = R_Mesh_CreateMeshBuffer(mesh->vertexmesh, mesh->numverts * sizeof(*mesh->vertexmesh), loadmodel->name, false, false); + + // upload r_vertexposition_t array as a buffer + if (mesh->vertexposition && !mesh->vertexpositionbuffer) + mesh->vertexpositionbuffer = R_Mesh_CreateMeshBuffer(mesh->vertexposition, mesh->numverts * sizeof(*mesh->vertexposition), loadmodel->name, false, false); + + // upload short indices as a buffer + if (mesh->element3s && !mesh->element3s_indexbuffer) + mesh->element3s_indexbuffer = R_Mesh_CreateMeshBuffer(mesh->element3s, mesh->numtriangles * sizeof(short[3]), loadmodel->name, true, false); + + // upload int indices as a buffer + if (mesh->element3i && !mesh->element3i_indexbuffer && !mesh->element3s) + mesh->element3i_indexbuffer = R_Mesh_CreateMeshBuffer(mesh->element3i, mesh->numtriangles * sizeof(int[3]), loadmodel->name, true, false); + // vertex buffer is several arrays and we put them in the same buffer // // is this wise? the texcoordtexture2f array is used with dynamic // vertex/svector/tvector/normal when rendering animated models, on the // other hand animated models don't use a lot of vertices anyway... - if (mesh->numverts) + if (!mesh->vbo_vertexbuffer) { size_t size; unsigned char *mem; @@ -1179,7 +1256,7 @@ static void Mod_ShadowMesh_CreateVBOs(shadowmesh_t *mesh) if (mesh->tvector3f ) memcpy(mem + mesh->vbooffset_tvector3f , mesh->tvector3f , mesh->numverts * sizeof(float[3])); if (mesh->normal3f ) memcpy(mem + mesh->vbooffset_normal3f , mesh->normal3f , mesh->numverts * sizeof(float[3])); if (mesh->texcoord2f ) memcpy(mem + mesh->vbooffset_texcoord2f , mesh->texcoord2f , mesh->numverts * sizeof(float[2])); - mesh->vbo = R_Mesh_CreateStaticBufferObject(GL_ARRAY_BUFFER_ARB, mem, size, "shadowmesh"); + mesh->vbo_vertexbuffer = R_Mesh_CreateMeshBuffer(mem, size, "shadowmesh", false, false); Mem_Free(mem); } } @@ -1268,12 +1345,16 @@ void Mod_ShadowMesh_Free(shadowmesh_t *mesh) shadowmesh_t *nextmesh; for (;mesh;mesh = nextmesh) { - if (mesh->ebo3i) - R_Mesh_DestroyBufferObject(mesh->ebo3i); - if (mesh->ebo3s) - R_Mesh_DestroyBufferObject(mesh->ebo3s); - if (mesh->vbo) - R_Mesh_DestroyBufferObject(mesh->vbo); + if (mesh->vertexpositionbuffer) + R_Mesh_DestroyMeshBuffer(mesh->vertexpositionbuffer); + if (mesh->vertexmeshbuffer) + R_Mesh_DestroyMeshBuffer(mesh->vertexmeshbuffer); + if (mesh->element3i_indexbuffer) + R_Mesh_DestroyMeshBuffer(mesh->element3i_indexbuffer); + if (mesh->element3s_indexbuffer) + R_Mesh_DestroyMeshBuffer(mesh->element3s_indexbuffer); + if (mesh->vbo_vertexbuffer) + R_Mesh_DestroyMeshBuffer(mesh->vbo_vertexbuffer); nextmesh = mesh->next; Mem_Free(mesh); } @@ -1451,16 +1532,26 @@ void Mod_Terrain_UpdateSurfacesForViewOrigin(dp_model_t *model) } #endif -q3wavefunc_t Mod_LoadQ3Shaders_EnumerateWaveFunc(const char *s) +int Mod_LoadQ3Shaders_EnumerateWaveFunc(const char *s) { - if (!strcasecmp(s, "sin")) return Q3WAVEFUNC_SIN; - if (!strcasecmp(s, "square")) return Q3WAVEFUNC_SQUARE; - if (!strcasecmp(s, "triangle")) return Q3WAVEFUNC_TRIANGLE; - if (!strcasecmp(s, "sawtooth")) return Q3WAVEFUNC_SAWTOOTH; - if (!strcasecmp(s, "inversesawtooth")) return Q3WAVEFUNC_INVERSESAWTOOTH; - if (!strcasecmp(s, "noise")) return Q3WAVEFUNC_NOISE; + int offset = 0; + if (!strncasecmp(s, "user", 4)) // parse stuff like "user1sin", always userfunc + { + offset = bound(0, s[4] - '0', 9); + offset = (offset + 1) << Q3WAVEFUNC_USER_SHIFT; + s += 4; + if(*s) + ++s; + } + if (!strcasecmp(s, "sin")) return offset | Q3WAVEFUNC_SIN; + if (!strcasecmp(s, "square")) return offset | Q3WAVEFUNC_SQUARE; + if (!strcasecmp(s, "triangle")) return offset | Q3WAVEFUNC_TRIANGLE; + if (!strcasecmp(s, "sawtooth")) return offset | Q3WAVEFUNC_SAWTOOTH; + if (!strcasecmp(s, "inversesawtooth")) return offset | Q3WAVEFUNC_INVERSESAWTOOTH; + if (!strcasecmp(s, "noise")) return offset | Q3WAVEFUNC_NOISE; + if (!strcasecmp(s, "none")) return offset | Q3WAVEFUNC_NONE; Con_DPrintf("Mod_LoadQ3Shaders: unknown wavefunc %s\n", s); - return Q3WAVEFUNC_NONE; + return offset | Q3WAVEFUNC_NONE; } void Mod_FreeQ3Shaders(void) @@ -1482,7 +1573,7 @@ static void Q3Shader_AddToHash (q3shaderinfo_t* shader) end = ((unsigned char *) (&shader->Q3SHADERINFO_COMPARE_END)) + sizeof(shader->Q3SHADERINFO_COMPARE_END); start2 = (unsigned char *) (&entry->shader.Q3SHADERINFO_COMPARE_START); if(memcmp(start, start2, end - start)) - Con_Printf("Shader '%s' already defined, ignoring mismatching redeclaration\n", shader->name); + Con_DPrintf("Shader '%s' already defined, ignoring mismatching redeclaration\n", shader->name); else Con_DPrintf("Shader '%s' already defined\n", shader->name); return; @@ -1509,7 +1600,7 @@ static void Q3Shader_AddToHash (q3shaderinfo_t* shader) memcpy (&entry->shader, shader, sizeof (q3shaderinfo_t)); } -extern cvar_t r_picmipworld; +extern cvar_t mod_q3shader_default_offsetmapping; void Mod_LoadQ3Shaders(void) { int j; @@ -1521,6 +1612,9 @@ void Mod_LoadQ3Shaders(void) q3shaderinfo_layer_t *layer; int numparameters; char parameter[TEXTURE_MAXFRAMES + 4][Q3PATHLENGTH]; + char *custsurfaceparmnames[256]; // VorteX: q3map2 has 64 but well, someone will need more + unsigned long custsurfaceparms[256]; + int numcustsurfaceparms; Mod_FreeQ3Shaders(); @@ -1532,6 +1626,49 @@ void Mod_LoadQ3Shaders(void) Mem_ExpandableArray_NewArray (&q3shader_data->char_ptrs, q3shaders_mem, sizeof (char**), 256); + // parse custinfoparms.txt + numcustsurfaceparms = 0; + if (text = f = (char *)FS_LoadFile("scripts/custinfoparms.txt", tempmempool, false, NULL)) + { + if (!COM_ParseToken_QuakeC(&text, false) || strcasecmp(com_token, "{")) + Con_DPrintf("scripts/custinfoparms.txt: contentflags section parsing error - expected \"{\", found \"%s\"\n", com_token); + else + { + while (COM_ParseToken_QuakeC(&text, false)) + if (!strcasecmp(com_token, "}")) + break; + // custom surfaceflags section + if (!COM_ParseToken_QuakeC(&text, false) || strcasecmp(com_token, "{")) + Con_DPrintf("scripts/custinfoparms.txt: surfaceflags section parsing error - expected \"{\", found \"%s\"\n", com_token); + else + { + while(COM_ParseToken_QuakeC(&text, false)) + { + if (!strcasecmp(com_token, "}")) + break; + // register surfaceflag + if (numcustsurfaceparms >= 256) + { + Con_Printf("scripts/custinfoparms.txt: surfaceflags section parsing error - max 256 surfaceflags exceeded\n"); + break; + } + // name + j = strlen(com_token)+1; + custsurfaceparmnames[numcustsurfaceparms] = (char *)Mem_Alloc(tempmempool, j); + strlcpy(custsurfaceparmnames[numcustsurfaceparms], com_token, j+1); + // value + if (COM_ParseToken_QuakeC(&text, false)) + custsurfaceparms[numcustsurfaceparms] = strtol(com_token, NULL, 0); + else + custsurfaceparms[numcustsurfaceparms] = 0; + numcustsurfaceparms++; + } + } + } + Mem_Free(f); + } + + // parse shaders search = FS_Search("scripts/*.shader", true, false); if (!search) return; @@ -1550,13 +1687,15 @@ void Mod_LoadQ3Shaders(void) shader.reflectfactor = 1; Vector4Set(shader.reflectcolor4f, 1, 1, 1, 1); shader.r_water_wateralpha = 1; + shader.offsetmapping = (mod_q3shader_default_offsetmapping.value) ? OFFSETMAPPING_DEFAULT : OFFSETMAPPING_OFF; + shader.offsetscale = 1; shader.specularscalemod = 1; shader.specularpowermod = 1; strlcpy(shader.name, com_token, sizeof(shader.name)); if (!COM_ParseToken_QuakeC(&text, false) || strcasecmp(com_token, "{")) { - Con_Printf("%s parsing error - expected \"{\", found \"%s\"\n", search->filenames[fileindex], com_token); + Con_DPrintf("%s parsing error - expected \"{\", found \"%s\"\n", search->filenames[fileindex], com_token); break; } while (COM_ParseToken_QuakeC(&text, false)) @@ -1592,7 +1731,11 @@ void Mod_LoadQ3Shaders(void) { if (j < TEXTURE_MAXFRAMES + 4) { - strlcpy(parameter[j], com_token, sizeof(parameter[j])); + // remap dp_water to dpwater, dp_reflect to dpreflect, etc. + if(j == 0 && !strncasecmp(com_token, "dp_", 3)) + dpsnprintf(parameter[j], sizeof(parameter[j]), "dp%s", &com_token[3]); + else + strlcpy(parameter[j], com_token, sizeof(parameter[j])); numparameters = j + 1; } if (!COM_ParseToken_QuakeC(&text, true)) @@ -1811,7 +1954,11 @@ void Mod_LoadQ3Shaders(void) { if (j < TEXTURE_MAXFRAMES + 4) { - strlcpy(parameter[j], com_token, sizeof(parameter[j])); + // remap dp_water to dpwater, dp_reflect to dpreflect, etc. + if(j == 0 && !strncasecmp(com_token, "dp_", 3)) + dpsnprintf(parameter[j], sizeof(parameter[j]), "dp%s", &com_token[3]); + else + strlcpy(parameter[j], com_token, sizeof(parameter[j])); numparameters = j + 1; } if (!COM_ParseToken_QuakeC(&text, true)) @@ -1897,12 +2044,29 @@ void Mod_LoadQ3Shaders(void) else if (!strcasecmp(parameter[1], "antiportal")) shader.surfaceparms |= Q3SURFACEPARM_ANTIPORTAL; else - Con_DPrintf("%s parsing warning: unknown surfaceparm \"%s\"\n", search->filenames[fileindex], parameter[1]); + { + // try custom surfaceparms + for (j = 0; j < numcustsurfaceparms; j++) + { + if (!strcasecmp(custsurfaceparmnames[j], parameter[1])) + { + shader.surfaceparms |= custsurfaceparms[j]; + break; + } + } + // failed all + if (j == numcustsurfaceparms) + Con_DPrintf("%s parsing warning: unknown surfaceparm \"%s\"\n", search->filenames[fileindex], parameter[1]); + } } else if (!strcasecmp(parameter[0], "dpshadow")) shader.dpshadow = true; else if (!strcasecmp(parameter[0], "dpnoshadow")) shader.dpnoshadow = true; + else if (!strcasecmp(parameter[0], "dpreflectcube")) + strlcpy(shader.dpreflectcube, parameter[1], sizeof(shader.dpreflectcube)); + else if (!strcasecmp(parameter[0], "dpmeshcollisions")) + shader.dpmeshcollisions = true; else if (!strcasecmp(parameter[0], "sky") && numparameters >= 2) { // some q3 skies don't have the sky parm set @@ -1927,19 +2091,23 @@ void Mod_LoadQ3Shaders(void) shader.textureflags |= Q3TEXTUREFLAG_NOPICMIP; else if (!strcasecmp(parameter[0], "polygonoffset")) shader.textureflags |= Q3TEXTUREFLAG_POLYGONOFFSET; - else if (!strcasecmp(parameter[0], "dp_refract") && numparameters >= 5) + else if (!strcasecmp(parameter[0], "dprefract") && numparameters >= 5) { shader.textureflags |= Q3TEXTUREFLAG_REFRACTION; shader.refractfactor = atof(parameter[1]); Vector4Set(shader.refractcolor4f, atof(parameter[2]), atof(parameter[3]), atof(parameter[4]), 1); } - else if (!strcasecmp(parameter[0], "dp_reflect") && numparameters >= 6) + else if (!strcasecmp(parameter[0], "dpreflect") && numparameters >= 6) { shader.textureflags |= Q3TEXTUREFLAG_REFLECTION; shader.reflectfactor = atof(parameter[1]); Vector4Set(shader.reflectcolor4f, atof(parameter[2]), atof(parameter[3]), atof(parameter[4]), atof(parameter[5])); } - else if (!strcasecmp(parameter[0], "dp_water") && numparameters >= 12) + else if (!strcasecmp(parameter[0], "dpcamera")) + { + shader.textureflags |= Q3TEXTUREFLAG_CAMERA; + } + else if (!strcasecmp(parameter[0], "dpwater") && numparameters >= 12) { shader.textureflags |= Q3TEXTUREFLAG_WATERSHADER; shader.reflectmin = atof(parameter[1]); @@ -1950,14 +2118,26 @@ void Mod_LoadQ3Shaders(void) Vector4Set(shader.reflectcolor4f, atof(parameter[8]), atof(parameter[9]), atof(parameter[10]), 1); shader.r_water_wateralpha = atof(parameter[11]); } - else if (!strcasecmp(parameter[0], "dp_glossintensitymod") && numparameters >= 2) + else if (!strcasecmp(parameter[0], "dpglossintensitymod") && numparameters >= 2) { shader.specularscalemod = atof(parameter[1]); } - else if (!strcasecmp(parameter[0], "dp_glossexponentmod") && numparameters >= 2) + else if (!strcasecmp(parameter[0], "dpglossexponentmod") && numparameters >= 2) { shader.specularpowermod = atof(parameter[1]); } + else if (!strcasecmp(parameter[0], "dpoffsetmapping") && numparameters >= 3) + { + if (!strcasecmp(parameter[1], "disable") || !strcasecmp(parameter[1], "none") || !strcasecmp(parameter[1], "off")) + shader.offsetmapping = OFFSETMAPPING_OFF; + else if (!strcasecmp(parameter[1], "default")) + shader.offsetmapping = OFFSETMAPPING_DEFAULT; + else if (!strcasecmp(parameter[1], "linear")) + shader.offsetmapping = OFFSETMAPPING_LINEAR; + else if (!strcasecmp(parameter[1], "relief")) + shader.offsetmapping = OFFSETMAPPING_RELIEF; + shader.offsetscale = atof(parameter[2]); + } else if (!strcasecmp(parameter[0], "deformvertexes") && numparameters >= 2) { int i, deformindex; @@ -2024,13 +2204,16 @@ void Mod_LoadQ3Shaders(void) } // fix up multiple reflection types if(shader.textureflags & Q3TEXTUREFLAG_WATERSHADER) - shader.textureflags &= ~(Q3TEXTUREFLAG_REFRACTION | Q3TEXTUREFLAG_REFLECTION); + shader.textureflags &= ~(Q3TEXTUREFLAG_REFRACTION | Q3TEXTUREFLAG_REFLECTION | Q3TEXTUREFLAG_CAMERA); Q3Shader_AddToHash (&shader); } Mem_Free(f); } FS_FreeSearch(search); + // free custinfoparm values + for (j = 0; j < numcustsurfaceparms; j++) + Mem_Free(custsurfaceparmnames[j]); } q3shaderinfo_t *Mod_LookupQ3Shader(const char *name) @@ -2066,8 +2249,11 @@ qboolean Mod_LoadTextureFromQ3Shader(texture_t *texture, const char *name, qbool texflagsmask &= ~TEXF_PICMIP; if(!(defaulttexflags & TEXF_COMPRESS)) texflagsmask &= ~TEXF_COMPRESS; - texture->specularscalemod = 1; // unless later loaded from the shader - texture->specularpowermod = 1; // unless later loaded from the shader + // unless later loaded from the shader + texture->offsetmapping = (mod_q3shader_default_offsetmapping.value) ? OFFSETMAPPING_DEFAULT : OFFSETMAPPING_OFF; + texture->offsetscale = 1; + texture->specularscalemod = 1; + texture->specularpowermod = 1; // WHEN ADDING DEFAULTS HERE, REMEMBER TO SYNC TO SHADER LOADING ABOVE // HERE, AND Q1BSP LOADING // JUST GREP FOR "specularscalemod = 1". @@ -2107,6 +2293,8 @@ qboolean Mod_LoadTextureFromQ3Shader(texture_t *texture, const char *name, qbool texture->basematerialflags |= MATERIALFLAG_REFLECTION; if (shader->textureflags & Q3TEXTUREFLAG_WATERSHADER) texture->basematerialflags |= MATERIALFLAG_WATERSHADER; + if (shader->textureflags & Q3TEXTUREFLAG_CAMERA) + texture->basematerialflags |= MATERIALFLAG_CAMERA; texture->customblendfunc[0] = GL_ONE; texture->customblendfunc[1] = GL_ZERO; if (shader->numlayers > 0) @@ -2205,14 +2393,65 @@ nothing GL_ZERO GL_ONE texture->reflectfactor = shader->reflectfactor; Vector4Copy(shader->reflectcolor4f, texture->reflectcolor4f); texture->r_water_wateralpha = shader->r_water_wateralpha; + texture->offsetmapping = shader->offsetmapping; + texture->offsetscale = shader->offsetscale; texture->specularscalemod = shader->specularscalemod; texture->specularpowermod = shader->specularpowermod; + if (shader->dpreflectcube[0]) + texture->reflectcubetexture = R_GetCubemap(shader->dpreflectcube); + + // set up default supercontents (on q3bsp this is overridden by the q3bsp loader) + texture->supercontents = SUPERCONTENTS_SOLID | SUPERCONTENTS_OPAQUE; + if (shader->surfaceparms & Q3SURFACEPARM_LAVA ) texture->supercontents = SUPERCONTENTS_LAVA ; + if (shader->surfaceparms & Q3SURFACEPARM_SLIME ) texture->supercontents = SUPERCONTENTS_SLIME ; + if (shader->surfaceparms & Q3SURFACEPARM_WATER ) texture->supercontents = SUPERCONTENTS_WATER ; + if (shader->surfaceparms & Q3SURFACEPARM_NONSOLID ) texture->supercontents = 0 ; + if (shader->surfaceparms & Q3SURFACEPARM_PLAYERCLIP ) texture->supercontents = SUPERCONTENTS_PLAYERCLIP ; + if (shader->surfaceparms & Q3SURFACEPARM_BOTCLIP ) texture->supercontents = SUPERCONTENTS_MONSTERCLIP ; + if (shader->surfaceparms & Q3SURFACEPARM_SKY ) texture->supercontents = SUPERCONTENTS_SKY ; + + // if (shader->surfaceparms & Q3SURFACEPARM_ALPHASHADOW ) texture->supercontents |= SUPERCONTENTS_ALPHASHADOW ; + // if (shader->surfaceparms & Q3SURFACEPARM_AREAPORTAL ) texture->supercontents |= SUPERCONTENTS_AREAPORTAL ; + // if (shader->surfaceparms & Q3SURFACEPARM_CLUSTERPORTAL) texture->supercontents |= SUPERCONTENTS_CLUSTERPORTAL; + // if (shader->surfaceparms & Q3SURFACEPARM_DETAIL ) texture->supercontents |= SUPERCONTENTS_DETAIL ; + if (shader->surfaceparms & Q3SURFACEPARM_DONOTENTER ) texture->supercontents |= SUPERCONTENTS_DONOTENTER ; + // if (shader->surfaceparms & Q3SURFACEPARM_FOG ) texture->supercontents |= SUPERCONTENTS_FOG ; + if (shader->surfaceparms & Q3SURFACEPARM_LAVA ) texture->supercontents |= SUPERCONTENTS_LAVA ; + // if (shader->surfaceparms & Q3SURFACEPARM_LIGHTFILTER ) texture->supercontents |= SUPERCONTENTS_LIGHTFILTER ; + // if (shader->surfaceparms & Q3SURFACEPARM_METALSTEPS ) texture->supercontents |= SUPERCONTENTS_METALSTEPS ; + // if (shader->surfaceparms & Q3SURFACEPARM_NODAMAGE ) texture->supercontents |= SUPERCONTENTS_NODAMAGE ; + // if (shader->surfaceparms & Q3SURFACEPARM_NODLIGHT ) texture->supercontents |= SUPERCONTENTS_NODLIGHT ; + // if (shader->surfaceparms & Q3SURFACEPARM_NODRAW ) texture->supercontents |= SUPERCONTENTS_NODRAW ; + if (shader->surfaceparms & Q3SURFACEPARM_NODROP ) texture->supercontents |= SUPERCONTENTS_NODROP ; + // if (shader->surfaceparms & Q3SURFACEPARM_NOIMPACT ) texture->supercontents |= SUPERCONTENTS_NOIMPACT ; + // if (shader->surfaceparms & Q3SURFACEPARM_NOLIGHTMAP ) texture->supercontents |= SUPERCONTENTS_NOLIGHTMAP ; + // if (shader->surfaceparms & Q3SURFACEPARM_NOMARKS ) texture->supercontents |= SUPERCONTENTS_NOMARKS ; + // if (shader->surfaceparms & Q3SURFACEPARM_NOMIPMAPS ) texture->supercontents |= SUPERCONTENTS_NOMIPMAPS ; + if (shader->surfaceparms & Q3SURFACEPARM_NONSOLID ) texture->supercontents &=~SUPERCONTENTS_SOLID ; + // if (shader->surfaceparms & Q3SURFACEPARM_ORIGIN ) texture->supercontents |= SUPERCONTENTS_ORIGIN ; + if (shader->surfaceparms & Q3SURFACEPARM_PLAYERCLIP ) texture->supercontents |= SUPERCONTENTS_PLAYERCLIP ; + if (shader->surfaceparms & Q3SURFACEPARM_SKY ) texture->supercontents |= SUPERCONTENTS_SKY ; + // if (shader->surfaceparms & Q3SURFACEPARM_SLICK ) texture->supercontents |= SUPERCONTENTS_SLICK ; + if (shader->surfaceparms & Q3SURFACEPARM_SLIME ) texture->supercontents |= SUPERCONTENTS_SLIME ; + // if (shader->surfaceparms & Q3SURFACEPARM_STRUCTURAL ) texture->supercontents |= SUPERCONTENTS_STRUCTURAL ; + // if (shader->surfaceparms & Q3SURFACEPARM_TRANS ) texture->supercontents |= SUPERCONTENTS_TRANS ; + if (shader->surfaceparms & Q3SURFACEPARM_WATER ) texture->supercontents |= SUPERCONTENTS_WATER ; + // if (shader->surfaceparms & Q3SURFACEPARM_POINTLIGHT ) texture->supercontents |= SUPERCONTENTS_POINTLIGHT ; + // if (shader->surfaceparms & Q3SURFACEPARM_HINT ) texture->supercontents |= SUPERCONTENTS_HINT ; + // if (shader->surfaceparms & Q3SURFACEPARM_DUST ) texture->supercontents |= SUPERCONTENTS_DUST ; + if (shader->surfaceparms & Q3SURFACEPARM_BOTCLIP ) texture->supercontents |= SUPERCONTENTS_BOTCLIP | SUPERCONTENTS_MONSTERCLIP; + // if (shader->surfaceparms & Q3SURFACEPARM_LIGHTGRID ) texture->supercontents |= SUPERCONTENTS_LIGHTGRID ; + // if (shader->surfaceparms & Q3SURFACEPARM_ANTIPORTAL ) texture->supercontents |= SUPERCONTENTS_ANTIPORTAL ; + + if (shader->dpmeshcollisions) + texture->basematerialflags |= MATERIALFLAG_MESHCOLLISIONS; } else if (!strcmp(texture->name, "noshader") || !texture->name[0]) { if (developer_extra.integer) Con_DPrintf("^1%s:^7 using fallback noshader material for ^3\"%s\"\n", loadmodel->name, name); texture->surfaceparms = 0; + texture->supercontents = SUPERCONTENTS_SOLID | SUPERCONTENTS_OPAQUE; } else if (!strcmp(texture->name, "common/nodraw") || !strcmp(texture->name, "textures/common/nodraw")) { @@ -2220,6 +2459,7 @@ nothing GL_ZERO GL_ONE Con_DPrintf("^1%s:^7 using fallback nodraw material for ^3\"%s\"\n", loadmodel->name, name); texture->surfaceparms = 0; texture->basematerialflags = MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW; + texture->supercontents = SUPERCONTENTS_SOLID; } else { @@ -2227,11 +2467,20 @@ nothing GL_ZERO GL_ONE Con_DPrintf("^1%s:^7 No shader found for texture ^3\"%s\"\n", loadmodel->name, texture->name); texture->surfaceparms = 0; if (texture->surfaceflags & Q3SURFACEFLAG_NODRAW) + { texture->basematerialflags |= MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW; + texture->supercontents = SUPERCONTENTS_SOLID; + } else if (texture->surfaceflags & Q3SURFACEFLAG_SKY) + { texture->basematerialflags |= MATERIALFLAG_SKY | MATERIALFLAG_NOSHADOW; + texture->supercontents = SUPERCONTENTS_SKY; + } else + { texture->basematerialflags |= MATERIALFLAG_WALL; + texture->supercontents = SUPERCONTENTS_SOLID | SUPERCONTENTS_OPAQUE; + } texture->numskinframes = 1; if(cls.state == ca_dedicated) { @@ -2480,8 +2729,11 @@ void Mod_MakeSortedSurfaces(dp_model_t *mod) Mem_Free(numsurfacesfortexture); } -static void Mod_BuildVBOs(void) +void Mod_BuildVBOs(void) { + if (!loadmodel->surfmesh.num_vertices) + return; + if (gl_paranoid.integer && loadmodel->surfmesh.data_element3s && loadmodel->surfmesh.data_element3i) { int i; @@ -2495,24 +2747,62 @@ static void Mod_BuildVBOs(void) } } - if (!vid.support.arb_vertex_buffer_object) - return; + // build r_vertexmesh_t array + // (compressed interleaved array for faster rendering) + if (!loadmodel->surfmesh.vertexmesh) + { + int vertexindex; + int numvertices = loadmodel->surfmesh.num_vertices; + r_vertexmesh_t *vertexmesh; + loadmodel->surfmesh.vertexmesh = vertexmesh = (r_vertexmesh_t*)Mem_Alloc(loadmodel->mempool, numvertices * sizeof(*loadmodel->surfmesh.vertexmesh)); + for (vertexindex = 0;vertexindex < numvertices;vertexindex++, vertexmesh++) + { + VectorCopy(loadmodel->surfmesh.data_vertex3f + 3*vertexindex, vertexmesh->vertex3f); + VectorScale(loadmodel->surfmesh.data_svector3f + 3*vertexindex, 1.0f, vertexmesh->svector3f); + VectorScale(loadmodel->surfmesh.data_tvector3f + 3*vertexindex, 1.0f, vertexmesh->tvector3f); + VectorScale(loadmodel->surfmesh.data_normal3f + 3*vertexindex, 1.0f, vertexmesh->normal3f); + if (loadmodel->surfmesh.data_lightmapcolor4f) + Vector4Scale(loadmodel->surfmesh.data_lightmapcolor4f + 4*vertexindex, 255.0f, vertexmesh->color4ub); + Vector2Copy(loadmodel->surfmesh.data_texcoordtexture2f + 2*vertexindex, vertexmesh->texcoordtexture2f); + if (loadmodel->surfmesh.data_texcoordlightmap2f) + Vector2Scale(loadmodel->surfmesh.data_texcoordlightmap2f + 2*vertexindex, 1.0f, vertexmesh->texcoordlightmap2f); + } + } - // element buffer is easy because it's just one array - if (loadmodel->surfmesh.num_triangles) + // build r_vertexposition_t array + if (!loadmodel->surfmesh.vertexposition) { - if (loadmodel->surfmesh.data_element3s) - loadmodel->surfmesh.ebo3s = R_Mesh_CreateStaticBufferObject(GL_ELEMENT_ARRAY_BUFFER_ARB, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]), loadmodel->name); - else - loadmodel->surfmesh.ebo3i = R_Mesh_CreateStaticBufferObject(GL_ELEMENT_ARRAY_BUFFER_ARB, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles * sizeof(unsigned int[3]), loadmodel->name); + int vertexindex; + int numvertices = loadmodel->surfmesh.num_vertices; + r_vertexposition_t *vertexposition; + loadmodel->surfmesh.vertexposition = vertexposition = (r_vertexposition_t*)Mem_Alloc(loadmodel->mempool, numvertices * sizeof(*loadmodel->surfmesh.vertexposition)); + for (vertexindex = 0;vertexindex < numvertices;vertexindex++, vertexposition++) + VectorCopy(loadmodel->surfmesh.data_vertex3f + 3*vertexindex, vertexposition->vertex3f); } + // upload r_vertexmesh_t array as a buffer + if (loadmodel->surfmesh.vertexmesh && !loadmodel->surfmesh.vertexmeshbuffer) + loadmodel->surfmesh.vertexmeshbuffer = R_Mesh_CreateMeshBuffer(loadmodel->surfmesh.vertexmesh, loadmodel->surfmesh.num_vertices * sizeof(*loadmodel->surfmesh.vertexmesh), loadmodel->name, false, false); + + // upload r_vertexposition_t array as a buffer + if (loadmodel->surfmesh.vertexposition && !loadmodel->surfmesh.vertexpositionbuffer) + loadmodel->surfmesh.vertexpositionbuffer = R_Mesh_CreateMeshBuffer(loadmodel->surfmesh.vertexposition, loadmodel->surfmesh.num_vertices * sizeof(*loadmodel->surfmesh.vertexposition), loadmodel->name, false, false); + + // upload short indices as a buffer + if (loadmodel->surfmesh.data_element3s && !loadmodel->surfmesh.data_element3s_indexbuffer) + loadmodel->surfmesh.data_element3s_indexbuffer = R_Mesh_CreateMeshBuffer(loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles * sizeof(short[3]), loadmodel->name, true, false); + + // upload int indices as a buffer + if (loadmodel->surfmesh.data_element3i && !loadmodel->surfmesh.data_element3i_indexbuffer && !loadmodel->surfmesh.data_element3s) + loadmodel->surfmesh.data_element3i_indexbuffer = R_Mesh_CreateMeshBuffer(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles * sizeof(int[3]), loadmodel->name, true, false); + + // only build a vbo if one has not already been created (this is important for brush models which load specially) // vertex buffer is several arrays and we put them in the same buffer // // is this wise? the texcoordtexture2f array is used with dynamic // vertex/svector/tvector/normal when rendering animated models, on the // other hand animated models don't use a lot of vertices anyway... - if (loadmodel->surfmesh.num_vertices) + if (!loadmodel->surfmesh.vbo_vertexbuffer) { size_t size; unsigned char *mem; @@ -2532,7 +2822,7 @@ static void Mod_BuildVBOs(void) if (loadmodel->surfmesh.data_texcoordtexture2f ) memcpy(mem + loadmodel->surfmesh.vbooffset_texcoordtexture2f , loadmodel->surfmesh.data_texcoordtexture2f , loadmodel->surfmesh.num_vertices * sizeof(float[2])); if (loadmodel->surfmesh.data_texcoordlightmap2f) memcpy(mem + loadmodel->surfmesh.vbooffset_texcoordlightmap2f, loadmodel->surfmesh.data_texcoordlightmap2f, loadmodel->surfmesh.num_vertices * sizeof(float[2])); if (loadmodel->surfmesh.data_lightmapcolor4f ) memcpy(mem + loadmodel->surfmesh.vbooffset_lightmapcolor4f , loadmodel->surfmesh.data_lightmapcolor4f , loadmodel->surfmesh.num_vertices * sizeof(float[4])); - loadmodel->surfmesh.vbo = R_Mesh_CreateStaticBufferObject(GL_ARRAY_BUFFER_ARB, mem, size, loadmodel->name); + loadmodel->surfmesh.vbo_vertexbuffer = R_Mesh_CreateMeshBuffer(mem, size, loadmodel->name, false, false); Mem_Free(mem); } } @@ -2649,9 +2939,7 @@ static void Mod_Decompile_SMD(dp_model_t *model, const char *filename, int first int transformindex; int poseindex; int cornerindex; - float modelscale; const int *e; - const float *pose; size_t l; size_t outbufferpos = 0; size_t outbuffermax = 0x100000; @@ -2660,16 +2948,6 @@ static void Mod_Decompile_SMD(dp_model_t *model, const char *filename, int first l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "version 1\nnodes\n"); if (l > 0) outbufferpos += l; - modelscale = 1; - if(model->num_poses >= 0) - modelscale = sqrt(model->data_poses[0] * model->data_poses[0] + model->data_poses[1] * model->data_poses[1] + model->data_poses[2] * model->data_poses[2]); - if(fabs(modelscale - 1) > 1e-4) - { - if(firstpose == 0) // only print the when writing the reference pose - Con_Printf("The model has an old-style model scale of %f\n", modelscale); - } - else - modelscale = 1; for (transformindex = 0;transformindex < model->num_bones;transformindex++) { if (outbufferpos >= outbuffermax >> 1) @@ -2688,17 +2966,17 @@ static void Mod_Decompile_SMD(dp_model_t *model, const char *filename, int first l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "end\nskeleton\n"); if (l > 0) outbufferpos += l; - for (poseindex = 0, pose = model->data_poses + model->num_bones * 12 * firstpose;poseindex < numposes;poseindex++) + for (poseindex = 0;poseindex < numposes;poseindex++) { countframes++; l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "time %i\n", poseindex); if (l > 0) outbufferpos += l; - for (transformindex = 0;transformindex < model->num_bones;transformindex++, pose += 12) + for (transformindex = 0;transformindex < model->num_bones;transformindex++) { - float a, b, c; float angles[3]; - float mtest[3][4]; + float mtest[4][3]; + matrix4x4_t posematrix; if (outbufferpos >= outbuffermax >> 1) { outbuffermax *= 2; @@ -2710,32 +2988,21 @@ static void Mod_Decompile_SMD(dp_model_t *model, const char *filename, int first // strangely the smd angles are for a transposed matrix, so we // have to generate a transposed matrix, then convert that... - mtest[0][0] = pose[ 0]; - mtest[0][1] = pose[ 4]; - mtest[0][2] = pose[ 8]; - mtest[0][3] = pose[ 3]; - mtest[1][0] = pose[ 1]; - mtest[1][1] = pose[ 5]; - mtest[1][2] = pose[ 9]; - mtest[1][3] = pose[ 7]; - mtest[2][0] = pose[ 2]; - mtest[2][1] = pose[ 6]; - mtest[2][2] = pose[10]; - mtest[2][3] = pose[11]; + Matrix4x4_FromBonePose6s(&posematrix, model->num_posescale, model->data_poses6s + 6*(model->num_bones * poseindex + transformindex)); + Matrix4x4_ToArray12FloatGL(&posematrix, mtest[0]); AnglesFromVectors(angles, mtest[0], mtest[2], false); if (angles[0] >= 180) angles[0] -= 360; if (angles[1] >= 180) angles[1] -= 360; if (angles[2] >= 180) angles[2] -= 360; - a = DEG2RAD(angles[ROLL]); - b = DEG2RAD(angles[PITCH]); - c = DEG2RAD(angles[YAW]); - #if 0 { + float a = DEG2RAD(angles[ROLL]); + float b = DEG2RAD(angles[PITCH]); + float c = DEG2RAD(angles[YAW]); float cy, sy, cp, sp, cr, sr; - float test[3][4]; - // smd matrix construction, for comparing to non-transposed m + float test[4][3]; + // smd matrix construction, for comparing sy = sin(c); cy = cos(c); sp = sin(b); @@ -2744,20 +3011,20 @@ static void Mod_Decompile_SMD(dp_model_t *model, const char *filename, int first cr = cos(a); test[0][0] = cp*cy; - test[1][0] = cp*sy; - test[2][0] = -sp; - test[0][1] = sr*sp*cy+cr*-sy; + test[0][1] = cp*sy; + test[0][2] = -sp; + test[1][0] = sr*sp*cy+cr*-sy; test[1][1] = sr*sp*sy+cr*cy; - test[2][1] = sr*cp; - test[0][2] = (cr*sp*cy+-sr*-sy); - test[1][2] = (cr*sp*sy+-sr*cy); + test[1][2] = sr*cp; + test[2][0] = (cr*sp*cy+-sr*-sy); + test[2][1] = (cr*sp*sy+-sr*cy); test[2][2] = cr*cp; - test[0][3] = pose[3]; - test[1][3] = pose[7]; - test[2][3] = pose[11]; + test[3][0] = pose[9]; + test[3][1] = pose[10]; + test[3][2] = pose[11]; } #endif - l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i %f %f %f %f %f %f\n", transformindex, pose[3] * modelscale, pose[7] * modelscale, pose[11] * modelscale, DEG2RAD(angles[ROLL]), DEG2RAD(angles[PITCH]), DEG2RAD(angles[YAW])); + l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i %f %f %f %f %f %f\n", transformindex, mtest[3][0], mtest[3][1], mtest[3][2], DEG2RAD(angles[ROLL]), DEG2RAD(angles[PITCH]), DEG2RAD(angles[YAW])); if (l > 0) outbufferpos += l; } @@ -2792,12 +3059,19 @@ static void Mod_Decompile_SMD(dp_model_t *model, const char *filename, int first const float *v = model->surfmesh.data_vertex3f + index * 3; const float *vn = model->surfmesh.data_normal3f + index * 3; const float *vt = model->surfmesh.data_texcoordtexture2f + index * 2; - const int *wi = model->surfmesh.data_vertexweightindex4i + index * 4; - const float *wf = model->surfmesh.data_vertexweightinfluence4f + index * 4; - if (wf[3]) l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i %f %f %f %f %f %f %f %f 4 %i %f %i %f %i %f %i %f\n", wi[0], v[0], v[1], v[2], vn[0], vn[1], vn[2], vt[0], 1 - vt[1], wi[0], wf[0], wi[1], wf[1], wi[2], wf[2], wi[3], wf[3]); - else if (wf[2]) l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i %f %f %f %f %f %f %f %f 3 %i %f %i %f %i %f\n" , wi[0], v[0], v[1], v[2], vn[0], vn[1], vn[2], vt[0], 1 - vt[1], wi[0], wf[0], wi[1], wf[1], wi[2], wf[2]); - else if (wf[1]) l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i %f %f %f %f %f %f %f %f 2 %i %f %i %f\n" , wi[0], v[0], v[1], v[2], vn[0], vn[1], vn[2], vt[0], 1 - vt[1], wi[0], wf[0], wi[1], wf[1]); - else l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i %f %f %f %f %f %f %f %f\n" , wi[0], v[0], v[1], v[2], vn[0], vn[1], vn[2], vt[0], 1 - vt[1]); + const int b = model->surfmesh.blends[index]; + if (b < model->num_bones) + l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i %f %f %f %f %f %f %f %f\n" , b, v[0], v[1], v[2], vn[0], vn[1], vn[2], vt[0], 1 - vt[1]); + else + { + const blendweights_t *w = model->surfmesh.data_blendweights + b - model->num_bones; + const unsigned char *wi = w->index; + const unsigned char *wf = w->influence; + if (wf[3]) l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i %f %f %f %f %f %f %f %f 4 %i %f %i %f %i %f %i %f\n", wi[0], v[0], v[1], v[2], vn[0], vn[1], vn[2], vt[0], 1 - vt[1], wi[0], wf[0]/255.0f, wi[1], wf[1]/255.0f, wi[2], wf[2]/255.0f, wi[3], wf[3]/255.0f); + else if (wf[2]) l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i %f %f %f %f %f %f %f %f 3 %i %f %i %f %i %f\n" , wi[0], v[0], v[1], v[2], vn[0], vn[1], vn[2], vt[0], 1 - vt[1], wi[0], wf[0]/255.0f, wi[1], wf[1]/255.0f, wi[2], wf[2]/255.0f); + else if (wf[1]) l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i %f %f %f %f %f %f %f %f 2 %i %f %i %f\n" , wi[0], v[0], v[1], v[2], vn[0], vn[1], vn[2], vt[0], 1 - vt[1], wi[0], wf[0]/255.0f, wi[1], wf[1]/255.0f); + else l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i %f %f %f %f %f %f %f %f\n" , wi[0], v[0], v[1], v[2], vn[0], vn[1], vn[2], vt[0], 1 - vt[1]); + } if (l > 0) outbufferpos += l; } @@ -2833,8 +3107,10 @@ static void Mod_Decompile_f(void) char animname2[MAX_QPATH]; char zymtextbuffer[16384]; char dpmtextbuffer[16384]; + char framegroupstextbuffer[16384]; int zymtextsize = 0; int dpmtextsize = 0; + int framegroupstextsize = 0; if (Cmd_Argc() != 2) { @@ -2896,16 +3172,20 @@ static void Mod_Decompile_f(void) // individual frame // check for additional frames with same name for (l = 0, k = strlen(animname);animname[l];l++) - if ((animname[l] < '0' || animname[l] > '9') && animname[l] != '_') + if(animname[l] < '0' || animname[l] > '9') k = l + 1; + if(k > 0 && animname[k-1] == '_') + --k; animname[k] = 0; count = mod->num_poses - first; for (j = i + 1;j < mod->numframes;j++) { strlcpy(animname2, mod->animscenes[j].name, sizeof(animname2)); for (l = 0, k = strlen(animname2);animname2[l];l++) - if ((animname2[l] < '0' || animname2[l] > '9') && animname2[l] != '_') + if(animname2[l] < '0' || animname2[l] > '9') k = l + 1; + if(k > 0 && animname[k-1] == '_') + --k; animname2[k] = 0; if (strcmp(animname2, animname) || mod->animscenes[j].framecount > 1) { @@ -2922,19 +3202,26 @@ static void Mod_Decompile_f(void) Mod_Decompile_SMD(mod, outname, first, count, false); if (zymtextsize < (int)sizeof(zymtextbuffer) - 100) { - l = dpsnprintf(zymtextbuffer + zymtextsize, sizeof(zymtextbuffer) - zymtextsize, "scene %s.smd fps %g\n", animname, mod->animscenes[i].framerate); + l = dpsnprintf(zymtextbuffer + zymtextsize, sizeof(zymtextbuffer) - zymtextsize, "scene %s.smd fps %g %s\n", animname, mod->animscenes[i].framerate, mod->animscenes[i].loop ? "" : " noloop"); if (l > 0) zymtextsize += l; } if (dpmtextsize < (int)sizeof(dpmtextbuffer) - 100) { - l = dpsnprintf(dpmtextbuffer + dpmtextsize, sizeof(dpmtextbuffer) - dpmtextsize, "scene %s.smd\n", animname); + l = dpsnprintf(dpmtextbuffer + dpmtextsize, sizeof(dpmtextbuffer) - dpmtextsize, "scene %s.smd fps %g %s\n", animname, mod->animscenes[i].framerate, mod->animscenes[i].loop ? "" : " noloop"); if (l > 0) dpmtextsize += l; } + if (framegroupstextsize < (int)sizeof(framegroupstextbuffer) - 100) + { + l = dpsnprintf(framegroupstextbuffer + framegroupstextsize, sizeof(framegroupstextbuffer) - framegroupstextsize, "%d %d %f %d // %s\n", first, count, mod->animscenes[i].framerate, mod->animscenes[i].loop, animname); + if (l > 0) framegroupstextsize += l; + } } if (zymtextsize) FS_WriteFile(va("%s_decompiled/out_zym.txt", basename), zymtextbuffer, (fs_offset_t)zymtextsize); if (dpmtextsize) FS_WriteFile(va("%s_decompiled/out_dpm.txt", basename), dpmtextbuffer, (fs_offset_t)dpmtextsize); + if (framegroupstextsize) + FS_WriteFile(va("%s_decompiled.framegroups", basename), framegroupstextbuffer, (fs_offset_t)framegroupstextsize); } } @@ -3068,6 +3355,79 @@ static float mod_generatelightmaps_offsets[3][MAX_LIGHTMAPSAMPLES][3]; static int mod_generatelightmaps_numlights; static lightmaplight_t *mod_generatelightmaps_lightinfo; +extern int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color); +extern cvar_t r_shadow_lightattenuationdividebias; +extern cvar_t r_shadow_lightattenuationlinearscale; + +static void Mod_GenerateLightmaps_LightPoint(dp_model_t *model, const vec3_t pos, vec3_t ambient, vec3_t diffuse, vec3_t lightdir) +{ + int i; + int index; + int result; + float relativepoint[3]; + float color[3]; + float dir[3]; + float dist; + float dist2; + float intensity; + float sample[5*3]; + float lightorigin[3]; + float lightradius; + float lightradius2; + float lightiradius; + float lightcolor[3]; + trace_t trace; + for (i = 0;i < 5*3;i++) + sample[i] = 0.0f; + for (index = 0;;index++) + { + result = R_Shadow_GetRTLightInfo(index, lightorigin, &lightradius, lightcolor); + if (result < 0) + break; + if (result == 0) + continue; + lightradius2 = lightradius * lightradius; + VectorSubtract(lightorigin, pos, relativepoint); + dist2 = VectorLength2(relativepoint); + if (dist2 >= lightradius2) + continue; + lightiradius = 1.0f / lightradius; + dist = sqrt(dist2) * lightiradius; + intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0; + if (intensity <= 0) + continue; + if (model && model->TraceLine) + { + model->TraceLine(model, NULL, NULL, &trace, pos, lightorigin, SUPERCONTENTS_VISBLOCKERMASK); + if (trace.fraction < 1) + continue; + } + // scale down intensity to add to both ambient and diffuse + //intensity *= 0.5f; + VectorNormalize(relativepoint); + VectorScale(lightcolor, intensity, color); + VectorMA(sample , 0.5f , color, sample ); + VectorMA(sample + 3, relativepoint[0], color, sample + 3); + VectorMA(sample + 6, relativepoint[1], color, sample + 6); + VectorMA(sample + 9, relativepoint[2], color, sample + 9); + // calculate a weighted average light direction as well + intensity *= VectorLength(color); + VectorMA(sample + 12, intensity, relativepoint, sample + 12); + } + // calculate the direction we'll use to reduce the sample to a directional light source + VectorCopy(sample + 12, dir); + //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]); + VectorNormalize(dir); + // extract the diffuse color along the chosen direction and scale it + diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]); + diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]); + diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]); + // subtract some of diffuse from ambient + VectorMA(sample, -0.333f, diffuse, ambient); + // store the normalized lightdir + VectorCopy(dir, lightdir); +} + static void Mod_GenerateLightmaps_CreateLights_ComputeSVBSP_InsertSurfaces(const dp_model_t *model, svbsp_t *svbsp, const float *mins, const float *maxs) { int surfaceindex; @@ -3081,7 +3441,7 @@ static void Mod_GenerateLightmaps_CreateLights_ComputeSVBSP_InsertSurfaces(const { if (!BoxesOverlap(surface->mins, surface->maxs, mins, maxs)) continue; - if (R_GetCurrentTexture(surface->texture)->currentmaterialflags & MATERIALFLAG_NOSHADOW) + if (surface->texture->basematerialflags & MATERIALFLAG_NOSHADOW) continue; for (triangleindex = 0, e = element3i + 3*surface->num_firsttriangle;triangleindex < surface->num_triangles;triangleindex++, e += 3) { @@ -3132,7 +3492,6 @@ static void Mod_GenerateLightmaps_CreateLights_ComputeSVBSP(dp_model_t *model, l Mem_Free(nodes); } -extern int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color); static void Mod_GenerateLightmaps_CreateLights(dp_model_t *model) { int index; @@ -3199,8 +3558,6 @@ static qboolean Mod_GenerateLightmaps_SamplePoint_SVBSP(const svbsp_t *svbsp, co return num == -1; // true if empty, false if solid (shadowed) } -extern cvar_t r_shadow_lightattenuationdividebias; -extern cvar_t r_shadow_lightattenuationlinearscale; static void Mod_GenerateLightmaps_SamplePoint(const float *pos, const float *normal, float *sample, int numoffsets, const float *offsets) { int i; @@ -3373,14 +3730,16 @@ static void Mod_GenerateLightmaps_DestroyLightmaps(dp_model_t *model) if (model->brushq3.data_lightmaps) { for (i = 0;i < model->brushq3.num_mergedlightmaps;i++) - R_FreeTexture(model->brushq3.data_lightmaps[i]); + if (model->brushq3.data_lightmaps[i]) + R_FreeTexture(model->brushq3.data_lightmaps[i]); Mem_Free(model->brushq3.data_lightmaps); model->brushq3.data_lightmaps = NULL; } if (model->brushq3.data_deluxemaps) { for (i = 0;i < model->brushq3.num_mergedlightmaps;i++) - R_FreeTexture(model->brushq3.data_deluxemaps[i]); + if (model->brushq3.data_deluxemaps[i]) + R_FreeTexture(model->brushq3.data_deluxemaps[i]); Mem_Free(model->brushq3.data_deluxemaps); model->brushq3.data_deluxemaps = NULL; } @@ -3419,15 +3778,27 @@ static void Mod_GenerateLightmaps_UnweldTriangles(dp_model_t *model) if (model->surfmesh.num_vertices > 65536) model->surfmesh.data_element3s = NULL; - if (model->surfmesh.vbo) - R_Mesh_DestroyBufferObject(model->surfmesh.vbo); - model->surfmesh.vbo = 0; - if (model->surfmesh.ebo3i) - R_Mesh_DestroyBufferObject(model->surfmesh.ebo3i); - model->surfmesh.ebo3i = 0; - if (model->surfmesh.ebo3s) - R_Mesh_DestroyBufferObject(model->surfmesh.ebo3s); - model->surfmesh.ebo3s = 0; + if (model->surfmesh.vertexposition) + Mem_Free(model->surfmesh.vertexposition); + model->surfmesh.vertexposition = NULL; + if (model->surfmesh.vertexmesh) + Mem_Free(model->surfmesh.vertexmesh); + model->surfmesh.vertexmesh = NULL; + if (model->surfmesh.vertexpositionbuffer) + R_Mesh_DestroyMeshBuffer(model->surfmesh.vertexpositionbuffer); + model->surfmesh.vertexpositionbuffer = NULL; + if (model->surfmesh.vertexmeshbuffer) + R_Mesh_DestroyMeshBuffer(model->surfmesh.vertexmeshbuffer); + model->surfmesh.vertexmeshbuffer = NULL; + if (model->surfmesh.data_element3i_indexbuffer) + R_Mesh_DestroyMeshBuffer(model->surfmesh.data_element3i_indexbuffer); + model->surfmesh.data_element3i_indexbuffer = NULL; + if (model->surfmesh.data_element3s_indexbuffer) + R_Mesh_DestroyMeshBuffer(model->surfmesh.data_element3s_indexbuffer); + model->surfmesh.data_element3s_indexbuffer = NULL; + if (model->surfmesh.vbo_vertexbuffer) + R_Mesh_DestroyMeshBuffer(model->surfmesh.vbo_vertexbuffer); + model->surfmesh.vbo_vertexbuffer = 0; // convert all triangles to unique vertex data outvertexindex = 0; @@ -3454,12 +3825,20 @@ static void Mod_GenerateLightmaps_UnweldTriangles(dp_model_t *model) model->surfmesh.data_tvector3f[outvertexindex*3+2] = oldsurfmesh.data_tvector3f[vertexindex*3+2]; model->surfmesh.data_texcoordtexture2f[outvertexindex*2+0] = oldsurfmesh.data_texcoordtexture2f[vertexindex*2+0]; model->surfmesh.data_texcoordtexture2f[outvertexindex*2+1] = oldsurfmesh.data_texcoordtexture2f[vertexindex*2+1]; - model->surfmesh.data_texcoordlightmap2f[outvertexindex*2+0] = oldsurfmesh.data_texcoordlightmap2f[vertexindex*2+0]; - model->surfmesh.data_texcoordlightmap2f[outvertexindex*2+1] = oldsurfmesh.data_texcoordlightmap2f[vertexindex*2+1]; - model->surfmesh.data_lightmapcolor4f[outvertexindex*4+0] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+0]; - model->surfmesh.data_lightmapcolor4f[outvertexindex*4+1] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+1]; - model->surfmesh.data_lightmapcolor4f[outvertexindex*4+2] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+2]; - model->surfmesh.data_lightmapcolor4f[outvertexindex*4+3] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+3]; + if (oldsurfmesh.data_texcoordlightmap2f) + { + model->surfmesh.data_texcoordlightmap2f[outvertexindex*2+0] = oldsurfmesh.data_texcoordlightmap2f[vertexindex*2+0]; + model->surfmesh.data_texcoordlightmap2f[outvertexindex*2+1] = oldsurfmesh.data_texcoordlightmap2f[vertexindex*2+1]; + } + if (oldsurfmesh.data_lightmapcolor4f) + { + model->surfmesh.data_lightmapcolor4f[outvertexindex*4+0] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+0]; + model->surfmesh.data_lightmapcolor4f[outvertexindex*4+1] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+1]; + model->surfmesh.data_lightmapcolor4f[outvertexindex*4+2] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+2]; + model->surfmesh.data_lightmapcolor4f[outvertexindex*4+3] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+3]; + } + else + Vector4Set(model->surfmesh.data_lightmapcolor4f + 4*outvertexindex, 1, 1, 1, 1); model->surfmesh.data_element3i[surface->num_firsttriangle*3+i] = outvertexindex; outvertexindex++; } @@ -3554,7 +3933,7 @@ static void Mod_GenerateLightmaps_CreateLightmaps(dp_model_t *model) float lm_basescalepixels; int lm_borderpixels; int lm_texturesize; - int lm_maxpixels; + //int lm_maxpixels; const int *e; lightmaptriangle_t *triangle; unsigned char *lightmappixels; @@ -3567,7 +3946,7 @@ static void Mod_GenerateLightmaps_CreateLightmaps(dp_model_t *model) lm_basescalepixels = 1.0f / max(0.0001f, mod_generatelightmaps_unitspersample.value); lm_borderpixels = mod_generatelightmaps_borderpixels.integer; lm_texturesize = bound(lm_borderpixels*2+1, 64, (int)vid.maxtexturesize_2d); - lm_maxpixels = lm_texturesize-(lm_borderpixels*2+1); + //lm_maxpixels = lm_texturesize-(lm_borderpixels*2+1); Mod_AllocLightmap_Init(&lmstate, lm_texturesize, lm_texturesize); lightmapnumber = 0; for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++) @@ -3632,7 +4011,9 @@ static void Mod_GenerateLightmaps_CreateLightmaps(dp_model_t *model) lightmapnumber++; Mod_AllocLightmap_Free(&lmstate); - // now together lightmap textures + // now put triangles together into lightmap textures, and do not allow + // triangles of a surface to go into different textures (as that would + // require rewriting the surface list) model->brushq3.deluxemapping_modelspace = true; model->brushq3.deluxemapping = true; model->brushq3.num_mergedlightmaps = lightmapnumber; @@ -3740,8 +4121,8 @@ static void Mod_GenerateLightmaps_CreateLightmaps(dp_model_t *model) for (lightmapindex = 0;lightmapindex < model->brushq3.num_mergedlightmaps;lightmapindex++) { - model->brushq3.data_lightmaps[lightmapindex] = R_LoadTexture2D(model->texturepool, va("lightmap%i", lightmapindex), lm_texturesize, lm_texturesize, lightmappixels + lightmapindex * lm_texturesize * lm_texturesize * 4, TEXTYPE_BGRA, TEXF_FORCELINEAR, NULL); - model->brushq3.data_deluxemaps[lightmapindex] = R_LoadTexture2D(model->texturepool, va("deluxemap%i", lightmapindex), lm_texturesize, lm_texturesize, deluxemappixels + lightmapindex * lm_texturesize * lm_texturesize * 4, TEXTYPE_BGRA, TEXF_FORCELINEAR, NULL); + model->brushq3.data_lightmaps[lightmapindex] = R_LoadTexture2D(model->texturepool, va("lightmap%i", lightmapindex), lm_texturesize, lm_texturesize, lightmappixels + lightmapindex * lm_texturesize * lm_texturesize * 4, TEXTYPE_BGRA, TEXF_FORCELINEAR, -1, NULL); + model->brushq3.data_deluxemaps[lightmapindex] = R_LoadTexture2D(model->texturepool, va("deluxemap%i", lightmapindex), lm_texturesize, lm_texturesize, deluxemappixels + lightmapindex * lm_texturesize * lm_texturesize * 4, TEXTYPE_BGRA, TEXF_FORCELINEAR, -1, NULL); } if (lightmappixels) @@ -3758,6 +4139,21 @@ static void Mod_GenerateLightmaps_CreateLightmaps(dp_model_t *model) lightmapindex = mod_generatelightmaps_lightmaptriangles[surface->num_firsttriangle].lightmapindex; surface->lightmaptexture = model->brushq3.data_lightmaps[lightmapindex]; surface->deluxemaptexture = model->brushq3.data_deluxemaps[lightmapindex]; + surface->lightmapinfo = NULL; + } + + model->brush.LightPoint = Mod_GenerateLightmaps_LightPoint; + model->brushq1.lightdata = NULL; + model->brushq1.lightmapupdateflags = NULL; + model->brushq1.firstrender = false; + model->brushq1.num_lightstyles = 0; + model->brushq1.data_lightstyleinfo = NULL; + for (i = 0;i < model->brush.numsubmodels;i++) + { + model->brush.submodels[i]->brushq1.lightmapupdateflags = NULL; + model->brush.submodels[i]->brushq1.firstrender = false; + model->brush.submodels[i]->brushq1.num_lightstyles = 0; + model->brush.submodels[i]->brushq1.data_lightstyleinfo = NULL; } }