X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=model_shared.c;h=2be02ff9b017610520bbc8189bb624096b7284e3;hp=9d44b9c822093a44297dc4dc9bc8d61c95c108e0;hb=220d6cb7e084a11a1c8f99b0fd57c522e17d6cef;hpb=636c2207a7feebbc93dacfbe1e4626df48c0269b diff --git a/model_shared.c b/model_shared.c index 9d44b9c8..2be02ff9 100644 --- a/model_shared.c +++ b/model_shared.c @@ -27,7 +27,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "r_shadow.h" #include "polygon.h" +cvar_t r_enableshadowvolumes = {CVAR_SAVE, "r_enableshadowvolumes", "1", "Enables use of Stencil Shadow Volume shadowing methods, saves some memory if turned off"}; cvar_t r_mipskins = {CVAR_SAVE, "r_mipskins", "0", "mipmaps model skins so they render faster in the distance and do not display noise artifacts, can cause discoloration of skins if they contain undesirable border colors"}; +cvar_t r_mipnormalmaps = {CVAR_SAVE, "r_mipnormalmaps", "1", "mipmaps normalmaps (turning it off looks sharper but may have aliasing)"}; cvar_t mod_generatelightmaps_unitspersample = {CVAR_SAVE, "mod_generatelightmaps_unitspersample", "8", "lightmap resolution"}; cvar_t mod_generatelightmaps_borderpixels = {CVAR_SAVE, "mod_generatelightmaps_borderpixels", "2", "extra space around polygons to prevent sampling artifacts"}; cvar_t mod_generatelightmaps_texturesize = {CVAR_SAVE, "mod_generatelightmaps_texturesize", "1024", "size of lightmap textures"}; @@ -61,7 +63,7 @@ static q3shader_data_t* q3shader_data; static void mod_start(void) { int i, count; - int nummodels = Mem_ExpandableArray_IndexRange(&models); + int nummodels = (int)Mem_ExpandableArray_IndexRange(&models); dp_model_t *mod; SCR_PushLoadingScreen(false, "Loading models", 1.0); @@ -84,7 +86,7 @@ static void mod_start(void) static void mod_shutdown(void) { int i; - int nummodels = Mem_ExpandableArray_IndexRange(&models); + int nummodels = (int)Mem_ExpandableArray_IndexRange(&models); dp_model_t *mod; for (i = 0;i < nummodels;i++) @@ -92,13 +94,14 @@ static void mod_shutdown(void) Mod_UnloadModel(mod); Mod_FreeQ3Shaders(); + Mod_Skeletal_FreeBuffers(); } static void mod_newmap(void) { msurface_t *surface; - int i, j, k, surfacenum, ssize, tsize; - int nummodels = Mem_ExpandableArray_IndexRange(&models); + int i, j, k, l, surfacenum, ssize, tsize; + int nummodels = (int)Mem_ExpandableArray_IndexRange(&models); dp_model_t *mod; for (i = 0;i < nummodels;i++) @@ -107,10 +110,11 @@ static void mod_newmap(void) { for (j = 0;j < mod->num_textures && mod->data_textures;j++) { - for (k = 0;k < mod->data_textures[j].numskinframes;k++) - R_SkinFrame_MarkUsed(mod->data_textures[j].skinframes[k]); - for (k = 0;k < mod->data_textures[j].backgroundnumskinframes;k++) - R_SkinFrame_MarkUsed(mod->data_textures[j].backgroundskinframes[k]); + // note that materialshaderpass and backgroundshaderpass point to shaderpasses[] and so do the pre/post shader ranges, so this catches all of them... + for (l = 0; l < Q3SHADER_MAXLAYERS; l++) + if (mod->data_textures[j].shaderpasses[l]) + for (k = 0; k < mod->data_textures[j].shaderpasses[l]->numframes; k++) + R_SkinFrame_MarkUsed(mod->data_textures[j].shaderpasses[l]->skinframes[k]); } if (mod->brush.solidskyskinframe) R_SkinFrame_MarkUsed(mod->brush.solidskyskinframe); @@ -148,7 +152,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) { @@ -159,7 +162,9 @@ void Mod_Init (void) Mod_AliasInit(); Mod_SpriteInit(); + Cvar_RegisterVariable(&r_enableshadowvolumes); Cvar_RegisterVariable(&r_mipskins); + Cvar_RegisterVariable(&r_mipnormalmaps); Cvar_RegisterVariable(&mod_generatelightmaps_unitspersample); Cvar_RegisterVariable(&mod_generatelightmaps_borderpixels); Cvar_RegisterVariable(&mod_generatelightmaps_texturesize); @@ -179,7 +184,7 @@ void Mod_Init (void) void Mod_RenderInit(void) { - R_RegisterModule("Models", mod_start, mod_shutdown, mod_newmap); + R_RegisterModule("Models", mod_start, mod_shutdown, mod_newmap, NULL, NULL); } void Mod_UnloadModel (dp_model_t *mod) @@ -194,12 +199,18 @@ 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.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); @@ -212,78 +223,95 @@ void Mod_UnloadModel (dp_model_t *mod) mod->loaded = false; } -void R_Model_Null_Draw(entity_render_t *ent) +static void R_Model_Null_Draw(entity_render_t *ent) { return; } -typedef void (*mod_framegroupify_parsegroups_t) (unsigned int i, int start, int len, float fps, qboolean loop, void *pass); +typedef void (*mod_framegroupify_parsegroups_t) (unsigned int i, int start, int len, float fps, qboolean loop, const char *name, void *pass); -int Mod_FrameGroupify_ParseGroups(const char *buf, mod_framegroupify_parsegroups_t cb, void *pass) +static int Mod_FrameGroupify_ParseGroups(const char *buf, mod_framegroupify_parsegroups_t cb, void *pass) { const char *bufptr; int start, len; float fps; unsigned int i; qboolean loop; + char name[64]; bufptr = buf; i = 0; - for(;;) + while(bufptr) { // an anim scene! - if (!COM_ParseToken_Simple(&bufptr, true, false)) - break; + + // REQUIRED: fetch start + COM_ParseToken_Simple(&bufptr, true, false, true); + if (!bufptr) + break; // end of file if (!strcmp(com_token, "\n")) continue; // empty line start = atoi(com_token); - if (!COM_ParseToken_Simple(&bufptr, true, false)) - break; - if (!strcmp(com_token, "\n")) + + // REQUIRED: fetch length + COM_ParseToken_Simple(&bufptr, true, false, true); + if (!bufptr || !strcmp(com_token, "\n")) { Con_Printf("framegroups file: missing number of frames\n"); continue; } len = atoi(com_token); - if (!COM_ParseToken_Simple(&bufptr, true, false)) - break; - // we default to looping as it's usually wanted, so to NOT loop you append a 0 - if (strcmp(com_token, "\n")) + + // OPTIONAL args start + COM_ParseToken_Simple(&bufptr, true, false, true); + + // OPTIONAL: fetch fps + fps = 20; + if (bufptr && strcmp(com_token, "\n")) { fps = atof(com_token); - if (!COM_ParseToken_Simple(&bufptr, true, false)) - break; - if (strcmp(com_token, "\n")) - loop = atoi(com_token) != 0; - else - loop = true; + COM_ParseToken_Simple(&bufptr, true, false, true); } - else + + // OPTIONAL: fetch loopflag + loop = true; + if (bufptr && strcmp(com_token, "\n")) + { + loop = (atoi(com_token) != 0); + COM_ParseToken_Simple(&bufptr, true, false, true); + } + + // OPTIONAL: fetch name + name[0] = 0; + if (bufptr && strcmp(com_token, "\n")) { - fps = 20; - loop = true; + strlcpy(name, com_token, sizeof(name)); + COM_ParseToken_Simple(&bufptr, true, false, true); } + // OPTIONAL: remaining unsupported tokens (eat them) + while (bufptr && strcmp(com_token, "\n")) + COM_ParseToken_Simple(&bufptr, true, false, true); + + //Con_Printf("data: %d %d %d %f %d (%s)\n", i, start, len, fps, loop, name); + if(cb) - cb(i, start, len, fps, loop, pass); + cb(i, start, len, fps, loop, (name[0] ? name : NULL), pass); ++i; } return i; } -void Mod_FrameGroupify_ParseGroups_Count (unsigned int i, int start, int len, float fps, qboolean loop, void *pass) -{ - unsigned int *cnt = (unsigned int *) pass; - ++*cnt; -} - -void Mod_FrameGroupify_ParseGroups_Store (unsigned int i, int start, int len, float fps, qboolean loop, void *pass) +static void Mod_FrameGroupify_ParseGroups_Store (unsigned int i, int start, int len, float fps, qboolean loop, const char *name, void *pass) { dp_model_t *mod = (dp_model_t *) pass; animscene_t *anim = &mod->animscenes[i]; - dpsnprintf(anim->name, sizeof(anim[i].name), "groupified_%d", i); + if(name) + strlcpy(anim->name, name, sizeof(anim[i].name)); + else + 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); @@ -291,7 +319,7 @@ void Mod_FrameGroupify_ParseGroups_Store (unsigned int i, int start, int len, fl //Con_Printf("frame group %d is %d %d %f %d\n", i, start, len, fps, loop); } -void Mod_FrameGroupify(dp_model_t *mod, const char *buf) +static void Mod_FrameGroupify(dp_model_t *mod, const char *buf) { unsigned int cnt; @@ -312,6 +340,33 @@ void Mod_FrameGroupify(dp_model_t *mod, const char *buf) Mod_FrameGroupify_ParseGroups(buf, Mod_FrameGroupify_ParseGroups_Store, mod); } +static 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->materialshaderpass && texture->materialshaderpass->tcgen.tcgen == Q3TCGEN_ENVIRONMENT) + mod->wantnormals = true; + if (texture->materialshaderpass && texture->materialshaderpass->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 @@ -324,7 +379,8 @@ dp_model_t *Mod_LoadModel(dp_model_t *mod, qboolean crash, qboolean checkdisk) int num; unsigned int crc; void *buf; - fs_offset_t filesize; + fs_offset_t filesize = 0; + char vabuf[1024]; mod->used = true; @@ -408,6 +464,9 @@ dp_model_t *Mod_LoadModel(dp_model_t *mod, qboolean crash, qboolean checkdisk) // errors can prevent the corresponding mod->loaded = true; mod->loaded = false; + // default lightmap scale + mod->lightmapscale = 1; + // default model radius and bounding box (mainly for missing models) mod->radius = 16; VectorSet(mod->normalmins, -mod->radius, -mod->radius, -mod->radius); @@ -433,7 +492,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,12 +502,15 @@ 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 if (num == BSPVERSION || num == 30 || !memcmp(buf, "BSP2", 4) || !memcmp(buf, "2PSB", 4)) Mod_Q1BSP_Load(mod, buf, bufend); else Con_Printf("Mod_LoadModel: model \"%s\" is of unknown/unsupported type\n", mod->name); Mem_Free(buf); - buf = FS_LoadFile (va("%s.framegroups", mod->name), tempmempool, false, &filesize); + Mod_FindPotentialDeforms(mod); + + buf = FS_LoadFile(va(vabuf, sizeof(vabuf), "%s.framegroups", mod->name), tempmempool, false, &filesize); if(buf) { Mod_FrameGroupify(mod, (const char *)buf); @@ -474,7 +536,7 @@ dp_model_t *Mod_LoadModel(dp_model_t *mod, qboolean crash, qboolean checkdisk) void Mod_ClearUsed(void) { int i; - int nummodels = Mem_ExpandableArray_IndexRange(&models); + int nummodels = (int)Mem_ExpandableArray_IndexRange(&models); dp_model_t *mod; for (i = 0;i < nummodels;i++) if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0]) @@ -484,7 +546,7 @@ void Mod_ClearUsed(void) void Mod_PurgeUnused(void) { int i; - int nummodels = Mem_ExpandableArray_IndexRange(&models); + int nummodels = (int)Mem_ExpandableArray_IndexRange(&models); dp_model_t *mod; for (i = 0;i < nummodels;i++) { @@ -514,10 +576,10 @@ dp_model_t *Mod_FindName(const char *name, const char *parentname) // if we're not dedicatd, the renderer calls will crash without video Host_StartVideo(); - nummodels = Mem_ExpandableArray_IndexRange(&models); + nummodels = (int)Mem_ExpandableArray_IndexRange(&models); if (!name[0]) - Host_Error ("Mod_ForName: NULL name"); + Host_Error ("Mod_ForName: empty name"); // search the currently loaded models for (i = 0;i < nummodels;i++) @@ -567,7 +629,7 @@ Reloads all models if they have changed void Mod_Reload(void) { int i, count; - int nummodels = Mem_ExpandableArray_IndexRange(&models); + int nummodels = (int)Mem_ExpandableArray_IndexRange(&models); dp_model_t *mod; SCR_PushLoadingScreen(false, "Reloading models", 1.0); @@ -598,7 +660,7 @@ Mod_Print static void Mod_Print(void) { int i; - int nummodels = Mem_ExpandableArray_IndexRange(&models); + int nummodels = (int)Mem_ExpandableArray_IndexRange(&models); dp_model_t *mod; Con_Print("Loaded models:\n"); @@ -659,7 +721,7 @@ void Mod_BuildTriangleNeighbors(int *neighbors, const int *elements, int numtria edgehashentry_t *edgehashentries, *hash; if (!numtriangles) return; - edgehash = Mem_Alloc(tempmempool, TRIANGLEEDGEHASH * sizeof(*edgehash)); + edgehash = (edgehashentry_t **)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 @@ -812,7 +874,8 @@ void Mod_BuildNormals(int firstvertex, int numvertices, int numtriangles, const VectorNormalize(vectorNormal); } -void Mod_BuildBumpVectors(const float *v0, const float *v1, const float *v2, const float *tc0, const float *tc1, const float *tc2, float *svector3f, float *tvector3f, float *normal3f) +#if 0 +static void Mod_BuildBumpVectors(const float *v0, const float *v1, const float *v2, const float *tc0, const float *tc1, const float *tc2, float *svector3f, float *tvector3f, float *normal3f) { float f, tangentcross[3], v10[3], v20[3], tc10[2], tc20[2]; // 79 add/sub/negate/multiply (1 cycle), 1 compare (3 cycle?), total cycles not counting load/store/exchange roughly 82 cycles @@ -855,12 +918,13 @@ void Mod_BuildBumpVectors(const float *v0, const float *v1, const float *v2, con VectorNegate(tvector3f, tvector3f); } } +#endif // warning: this is a very expensive function! void Mod_BuildTextureVectorsFromNormals(int firstvertex, int numvertices, int numtriangles, const float *vertex3f, const float *texcoord2f, const float *normal3f, const int *elements, float *svector3f, float *tvector3f, qboolean areaweighting) { int i, tnum; - float sdir[3], tdir[3], normal[3], *sv, *tv; + float sdir[3], tdir[3], normal[3], *svec, *tvec; const float *v0, *v1, *v2, *tc0, *tc1, *tc2, *n; float f, tangentcross[3], v10[3], v20[3], tc10[2], tc20[2]; const int *e; @@ -926,14 +990,14 @@ void Mod_BuildTextureVectorsFromNormals(int firstvertex, int numvertices, int nu // make the tangents completely perpendicular to the surface normal, and // then normalize them // 16 assignments, 2 divide, 2 sqrt, 2 negates, 14 adds, 24 multiplies - for (i = 0, sv = svector3f + 3 * firstvertex, tv = tvector3f + 3 * firstvertex, n = normal3f + 3 * firstvertex;i < numvertices;i++, sv += 3, tv += 3, n += 3) + for (i = 0, svec = svector3f + 3 * firstvertex, tvec = tvector3f + 3 * firstvertex, n = normal3f + 3 * firstvertex;i < numvertices;i++, svec += 3, tvec += 3, n += 3) { - f = -DotProduct(sv, n); - VectorMA(sv, f, n, sv); - VectorNormalize(sv); - f = -DotProduct(tv, n); - VectorMA(tv, f, n, tv); - VectorNormalize(tv); + f = -DotProduct(svec, n); + VectorMA(svec, f, n, svec); + VectorNormalize(svec); + f = -DotProduct(tvec, n); + VectorMA(tvec, f, n, tvec); + VectorNormalize(tvec); } } @@ -1145,42 +1209,61 @@ shadowmesh_t *Mod_ShadowMesh_Begin(mempool_t *mempool, int maxverts, int maxtria return Mod_ShadowMesh_Alloc(mempool, maxverts, maxtriangles, map_diffuse, map_specular, map_normal, light, neighbors, expandable); } -static void Mod_ShadowMesh_CreateVBOs(shadowmesh_t *mesh) +static void Mod_ShadowMesh_CreateVBOs(shadowmesh_t *mesh, mempool_t *mempool) { - 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 D3D) + if (!mesh->vertexmesh && mesh->texcoord2f && vid.useinterleavedarrays) { - 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(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); + } } + // 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, false, true); + + // 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, false, 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 && !vid.useinterleavedarrays) { - size_t size; + int size; unsigned char *mem; size = 0; + mesh->vbooffset_vertexmesh = size;if (mesh->vertexmesh ) size += mesh->numverts * sizeof(r_vertexmesh_t); mesh->vbooffset_vertex3f = size;if (mesh->vertex3f ) size += mesh->numverts * sizeof(float[3]); mesh->vbooffset_svector3f = size;if (mesh->svector3f ) size += mesh->numverts * sizeof(float[3]); mesh->vbooffset_tvector3f = size;if (mesh->tvector3f ) size += mesh->numverts * sizeof(float[3]); mesh->vbooffset_normal3f = size;if (mesh->normal3f ) size += mesh->numverts * sizeof(float[3]); mesh->vbooffset_texcoord2f = size;if (mesh->texcoord2f ) size += mesh->numverts * sizeof(float[2]); mem = (unsigned char *)Mem_Alloc(tempmempool, size); + if (mesh->vertexmesh ) memcpy(mem + mesh->vbooffset_vertexmesh , mesh->vertexmesh , mesh->numverts * sizeof(r_vertexmesh_t)); if (mesh->vertex3f ) memcpy(mem + mesh->vbooffset_vertex3f , mesh->vertex3f , mesh->numverts * sizeof(float[3])); if (mesh->svector3f ) memcpy(mem + mesh->vbooffset_svector3f , mesh->svector3f , mesh->numverts * sizeof(float[3])); 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, false, false); Mem_Free(mem); } } @@ -1204,7 +1287,7 @@ shadowmesh_t *Mod_ShadowMesh_Finish(mempool_t *mempool, shadowmesh_t *firstmesh, newmesh->element3s[i] = newmesh->element3i[i]; } if (createvbo) - Mod_ShadowMesh_CreateVBOs(newmesh); + Mod_ShadowMesh_CreateVBOs(newmesh, mempool); } Mem_Free(mesh); } @@ -1269,12 +1352,12 @@ 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->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); } @@ -1282,9 +1365,10 @@ void Mod_ShadowMesh_Free(shadowmesh_t *mesh) void Mod_CreateCollisionMesh(dp_model_t *mod) { - int k; - int numcollisionmeshtriangles; - const msurface_t *surface; + int k, numcollisionmeshtriangles; + qboolean usesinglecollisionmesh = false; + const msurface_t *surface = NULL; + mempool_t *mempool = mod->mempool; if (!mempool && mod->brush.parentmodel) mempool = mod->brush.parentmodel->mempool; @@ -1294,22 +1378,34 @@ void Mod_CreateCollisionMesh(dp_model_t *mod) for (k = 0;k < mod->nummodelsurfaces;k++) { surface = mod->data_surfaces + mod->firstmodelsurface + k; + if (!strcmp(surface->texture->name, "collision") || !strcmp(surface->texture->name, "collisionconvex")) // found collision mesh + { + usesinglecollisionmesh = true; + numcollisionmeshtriangles = surface->num_triangles; + break; + } if (!(surface->texture->supercontents & SUPERCONTENTS_SOLID)) continue; numcollisionmeshtriangles += surface->num_triangles; } mod->brush.collisionmesh = Mod_ShadowMesh_Begin(mempool, numcollisionmeshtriangles * 3, numcollisionmeshtriangles, NULL, NULL, NULL, false, false, true); - for (k = 0;k < mod->nummodelsurfaces;k++) - { - surface = mod->data_surfaces + mod->firstmodelsurface + k; - if (!(surface->texture->supercontents & SUPERCONTENTS_SOLID)) - continue; + if (usesinglecollisionmesh) Mod_ShadowMesh_AddMesh(mempool, mod->brush.collisionmesh, NULL, NULL, NULL, mod->surfmesh.data_vertex3f, NULL, NULL, NULL, NULL, surface->num_triangles, (mod->surfmesh.data_element3i + 3 * surface->num_firsttriangle)); + else + { + for (k = 0;k < mod->nummodelsurfaces;k++) + { + surface = mod->data_surfaces + mod->firstmodelsurface + k; + if (!(surface->texture->supercontents & SUPERCONTENTS_SOLID)) + continue; + Mod_ShadowMesh_AddMesh(mempool, mod->brush.collisionmesh, NULL, NULL, NULL, mod->surfmesh.data_vertex3f, NULL, NULL, NULL, NULL, surface->num_triangles, (mod->surfmesh.data_element3i + 3 * surface->num_firsttriangle)); + } } - mod->brush.collisionmesh = Mod_ShadowMesh_Finish(mempool, mod->brush.collisionmesh, false, true, false); + mod->brush.collisionmesh = Mod_ShadowMesh_Finish(mempool, mod->brush.collisionmesh, false, false, false); } -void Mod_GetTerrainVertex3fTexCoord2fFromBGRA(const unsigned char *imagepixels, int imagewidth, int imageheight, int ix, int iy, float *vertex3f, float *texcoord2f, matrix4x4_t *pixelstepmatrix, matrix4x4_t *pixeltexturestepmatrix) +#if 0 +static void Mod_GetTerrainVertex3fTexCoord2fFromBGRA(const unsigned char *imagepixels, int imagewidth, int imageheight, int ix, int iy, float *vertex3f, float *texcoord2f, matrix4x4_t *pixelstepmatrix, matrix4x4_t *pixeltexturestepmatrix) { float v[3], tc[3]; v[0] = ix; @@ -1324,7 +1420,7 @@ void Mod_GetTerrainVertex3fTexCoord2fFromBGRA(const unsigned char *imagepixels, texcoord2f[1] = tc[1]; } -void Mod_GetTerrainVertexFromBGRA(const unsigned char *imagepixels, int imagewidth, int imageheight, int ix, int iy, float *vertex3f, float *svector3f, float *tvector3f, float *normal3f, float *texcoord2f, matrix4x4_t *pixelstepmatrix, matrix4x4_t *pixeltexturestepmatrix) +static void Mod_GetTerrainVertexFromBGRA(const unsigned char *imagepixels, int imagewidth, int imageheight, int ix, int iy, float *vertex3f, float *svector3f, float *tvector3f, float *normal3f, float *texcoord2f, matrix4x4_t *pixelstepmatrix, matrix4x4_t *pixeltexturestepmatrix) { float vup[3], vdown[3], vleft[3], vright[3]; float tcup[3], tcdown[3], tcleft[3], tcright[3]; @@ -1349,7 +1445,7 @@ void Mod_GetTerrainVertexFromBGRA(const unsigned char *imagepixels, int imagewid VectorAdd(normal3f, nl, normal3f); } -void Mod_ConstructTerrainPatchFromBGRA(const unsigned char *imagepixels, int imagewidth, int imageheight, int x1, int y1, int width, int height, int *element3i, int *neighbor3i, float *vertex3f, float *svector3f, float *tvector3f, float *normal3f, float *texcoord2f, matrix4x4_t *pixelstepmatrix, matrix4x4_t *pixeltexturestepmatrix) +static void Mod_ConstructTerrainPatchFromBGRA(const unsigned char *imagepixels, int imagewidth, int imageheight, int x1, int y1, int width, int height, int *element3i, int *neighbor3i, float *vertex3f, float *svector3f, float *tvector3f, float *normal3f, float *texcoord2f, matrix4x4_t *pixelstepmatrix, matrix4x4_t *pixeltexturestepmatrix) { int x, y, ix, iy, *e; e = element3i; @@ -1371,6 +1467,7 @@ void Mod_ConstructTerrainPatchFromBGRA(const unsigned char *imagepixels, int ima for (x = 0, ix = x1;x < width + 1;x++, ix++, vertex3f += 3, texcoord2f += 2, svector3f += 3, tvector3f += 3, normal3f += 3) Mod_GetTerrainVertexFromBGRA(imagepixels, imagewidth, imageheight, ix, iy, vertex3f, texcoord2f, svector3f, tvector3f, normal3f, pixelstepmatrix, pixeltexturestepmatrix); } +#endif #if 0 void Mod_Terrain_SurfaceRecurseChunk(dp_model_t *model, int stepsize, int x, int y) @@ -1452,16 +1549,26 @@ void Mod_Terrain_UpdateSurfacesForViewOrigin(dp_model_t *model) } #endif -q3wavefunc_t Mod_LoadQ3Shaders_EnumerateWaveFunc(const char *s) +static 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) @@ -1474,23 +1581,40 @@ static void Q3Shader_AddToHash (q3shaderinfo_t* shader) unsigned short hash = CRC_Block_CaseInsensitive ((const unsigned char *)shader->name, strlen (shader->name)); q3shader_hash_entry_t* entry = q3shader_data->hash + (hash % Q3SHADER_HASH_SIZE); q3shader_hash_entry_t* lastEntry = NULL; - while (entry != NULL) + do { if (strcasecmp (entry->shader.name, shader->name) == 0) { - unsigned char *start, *end, *start2; - start = (unsigned char *) (&shader->Q3SHADERINFO_COMPARE_START); - 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_DPrintf("Shader '%s' already defined, ignoring mismatching redeclaration\n", shader->name); + // redeclaration + if(shader->dpshaderkill) + { + // killed shader is a redeclarion? we can safely ignore it + return; + } + else if(entry->shader.dpshaderkill) + { + // replace the old shader! + // this will skip the entry allocating part + // below and just replace the shader + break; + } else - Con_DPrintf("Shader '%s' already defined\n", shader->name); - return; + { + unsigned char *start, *end, *start2; + start = (unsigned char *) (&shader->Q3SHADERINFO_COMPARE_START); + 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_DPrintf("Shader '%s' already defined, ignoring mismatching redeclaration\n", shader->name); + else + Con_DPrintf("Shader '%s' already defined\n", shader->name); + return; + } } lastEntry = entry; entry = entry->chain; } + while (entry != NULL); if (entry == NULL) { if (lastEntry->shader.name[0] != 0) @@ -1510,7 +1634,14 @@ static void Q3Shader_AddToHash (q3shaderinfo_t* shader) memcpy (&entry->shader, shader, sizeof (q3shaderinfo_t)); } -extern cvar_t r_picmipworld; +extern cvar_t mod_noshader_default_offsetmapping; +extern cvar_t mod_q3shader_default_offsetmapping; +extern cvar_t mod_q3shader_default_offsetmapping_scale; +extern cvar_t mod_q3shader_default_offsetmapping_bias; +extern cvar_t mod_q3shader_default_polygonoffset; +extern cvar_t mod_q3shader_default_polygonfactor; +extern cvar_t mod_q3shader_force_addalpha; +extern cvar_t mod_q3shader_force_terrain_alphaflag; void Mod_LoadQ3Shaders(void) { int j; @@ -1522,6 +1653,10 @@ 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 custsurfaceflags[256]; + int numcustsurfaceflags; + qboolean dpshaderkill; Mod_FreeQ3Shaders(); @@ -1533,6 +1668,49 @@ void Mod_LoadQ3Shaders(void) Mem_ExpandableArray_NewArray (&q3shader_data->char_ptrs, q3shaders_mem, sizeof (char**), 256); + // parse custinfoparms.txt + numcustsurfaceflags = 0; + if ((text = f = (char *)FS_LoadFile("scripts/custinfoparms.txt", tempmempool, false, NULL)) != 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 (numcustsurfaceflags >= 256) + { + Con_Printf("scripts/custinfoparms.txt: surfaceflags section parsing error - max 256 surfaceflags exceeded\n"); + break; + } + // name + j = (int)strlen(com_token)+1; + custsurfaceparmnames[numcustsurfaceflags] = (char *)Mem_Alloc(tempmempool, j); + strlcpy(custsurfaceparmnames[numcustsurfaceflags], com_token, j+1); + // value + if (COM_ParseToken_QuakeC(&text, false)) + custsurfaceflags[numcustsurfaceflags] = strtol(com_token, NULL, 0); + else + custsurfaceflags[numcustsurfaceflags] = 0; + numcustsurfaceflags++; + } + } + } + Mem_Free(f); + } + + // parse shaders search = FS_Search("scripts/*.shader", true, false); if (!search) return; @@ -1544,6 +1722,22 @@ void Mod_LoadQ3Shaders(void) while (COM_ParseToken_QuakeC(&text, false)) { memset (&shader, 0, sizeof(shader)); + shader.name[0] = 0; + shader.surfaceparms = 0; + shader.surfaceflags = 0; + shader.textureflags = 0; + shader.numlayers = 0; + shader.lighting = false; + shader.vertexalpha = false; + shader.textureblendalpha = false; + shader.skyboxname[0] = 0; + shader.deforms[0].deform = Q3DEFORM_NONE; + shader.dpnortlight = false; + shader.dpshadow = false; + shader.dpnoshadow = false; + shader.dpmeshcollisions = false; + shader.dpshaderkill = false; + shader.dpreflectcube[0] = 0; shader.reflectmin = 0; shader.reflectmax = 1; shader.refractfactor = 1; @@ -1551,8 +1745,19 @@ void Mod_LoadQ3Shaders(void) shader.reflectfactor = 1; Vector4Set(shader.reflectcolor4f, 1, 1, 1, 1); shader.r_water_wateralpha = 1; + shader.r_water_waterscroll[0] = 0; + shader.r_water_waterscroll[1] = 0; + shader.offsetmapping = (mod_q3shader_default_offsetmapping.value) ? OFFSETMAPPING_DEFAULT : OFFSETMAPPING_OFF; + shader.offsetscale = mod_q3shader_default_offsetmapping_scale.value; + shader.offsetbias = mod_q3shader_default_offsetmapping_bias.value; + shader.biaspolygonoffset = mod_q3shader_default_polygonoffset.value; + shader.biaspolygonfactor = mod_q3shader_default_polygonfactor.value; + shader.transparentsort = TRANSPARENTSORT_DISTANCE; shader.specularscalemod = 1; shader.specularpowermod = 1; + shader.rtlightambient = 0; + // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS + // JUST GREP FOR "specularscalemod = 1". strlcpy(shader.name, com_token, sizeof(shader.name)); if (!COM_ParseToken_QuakeC(&text, false) || strcasecmp(com_token, "{")) @@ -1593,7 +1798,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)) @@ -1617,6 +1826,11 @@ void Mod_LoadQ3Shaders(void) layer->blendfunc[0] = GL_ONE; layer->blendfunc[1] = GL_ONE; } + else if (!strcasecmp(parameter[1], "addalpha")) + { + layer->blendfunc[0] = GL_SRC_ALPHA; + layer->blendfunc[1] = GL_ONE; + } else if (!strcasecmp(parameter[1], "filter")) { layer->blendfunc[0] = GL_DST_COLOR; @@ -1644,7 +1858,7 @@ void Mod_LoadQ3Shaders(void) else if (!strcasecmp(parameter[k+1], "GL_DST_COLOR")) layer->blendfunc[k] = GL_DST_COLOR; else if (!strcasecmp(parameter[k+1], "GL_DST_ALPHA")) - layer->blendfunc[k] = GL_ONE_MINUS_DST_ALPHA; + layer->blendfunc[k] = GL_DST_ALPHA; else if (!strcasecmp(parameter[k+1], "GL_ONE_MINUS_SRC_COLOR")) layer->blendfunc[k] = GL_ONE_MINUS_SRC_COLOR; else if (!strcasecmp(parameter[k+1], "GL_ONE_MINUS_SRC_ALPHA")) @@ -1796,9 +2010,36 @@ void Mod_LoadQ3Shaders(void) { // multilayer terrain shader or similar shader.textureblendalpha = true; + if (mod_q3shader_force_terrain_alphaflag.integer) + shader.layers[0].texflags |= TEXF_ALPHA; } } - layer->texflags = TEXF_ALPHA; + + if(mod_q3shader_force_addalpha.integer) + { + // for a long while, DP treated GL_ONE GL_ONE as GL_SRC_ALPHA GL_ONE + // this cvar brings back this behaviour + if(layer->blendfunc[0] == GL_ONE && layer->blendfunc[1] == GL_ONE) + layer->blendfunc[0] = GL_SRC_ALPHA; + } + + layer->texflags = 0; + if (layer->alphatest) + layer->texflags |= TEXF_ALPHA; + switch(layer->blendfunc[0]) + { + case GL_SRC_ALPHA: + case GL_ONE_MINUS_SRC_ALPHA: + layer->texflags |= TEXF_ALPHA; + break; + } + switch(layer->blendfunc[1]) + { + case GL_SRC_ALPHA: + case GL_ONE_MINUS_SRC_ALPHA: + layer->texflags |= TEXF_ALPHA; + break; + } if (!(shader.surfaceparms & Q3SURFACEPARM_NOMIPMAPS)) layer->texflags |= TEXF_MIPMAP; if (!(shader.textureflags & Q3TEXTUREFLAG_NOPICMIP)) @@ -1812,7 +2053,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,13 +2142,86 @@ void Mod_LoadQ3Shaders(void) shader.surfaceparms |= Q3SURFACEPARM_POINTLIGHT; else if (!strcasecmp(parameter[1], "antiportal")) shader.surfaceparms |= Q3SURFACEPARM_ANTIPORTAL; + else if (!strcasecmp(parameter[1], "skip")) + ; // shader.surfaceparms |= Q3SURFACEPARM_SKIP; FIXME we don't have enough #defines for this any more, and the engine doesn't need this one anyway else - Con_DPrintf("%s parsing warning: unknown surfaceparm \"%s\"\n", search->filenames[fileindex], parameter[1]); + { + // try custom surfaceparms + for (j = 0; j < numcustsurfaceflags; j++) + { + if (!strcasecmp(custsurfaceparmnames[j], parameter[1])) + { + shader.surfaceflags |= custsurfaceflags[j]; + break; + } + } + // failed all + if (j == numcustsurfaceflags) + 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], "dpnortlight")) + shader.dpnortlight = true; + else if (!strcasecmp(parameter[0], "dpreflectcube")) + strlcpy(shader.dpreflectcube, parameter[1], sizeof(shader.dpreflectcube)); + else if (!strcasecmp(parameter[0], "dpmeshcollisions")) + shader.dpmeshcollisions = true; + // this sets dpshaderkill to true if dpshaderkillifcvarzero was used, and to false if dpnoshaderkillifcvarzero was used + else if (((dpshaderkill = !strcasecmp(parameter[0], "dpshaderkillifcvarzero")) || !strcasecmp(parameter[0], "dpnoshaderkillifcvarzero")) && numparameters >= 2) + { + if (Cvar_VariableValue(parameter[1]) == 0.0f) + shader.dpshaderkill = dpshaderkill; + } + // this sets dpshaderkill to true if dpshaderkillifcvar was used, and to false if dpnoshaderkillifcvar was used + else if (((dpshaderkill = !strcasecmp(parameter[0], "dpshaderkillifcvar")) || !strcasecmp(parameter[0], "dpnoshaderkillifcvar")) && numparameters >= 2) + { + const char *op = NULL; + if (numparameters >= 3) + op = parameter[2]; + if(!op) + { + if (Cvar_VariableValue(parameter[1]) != 0.0f) + shader.dpshaderkill = dpshaderkill; + } + else if (numparameters >= 4 && !strcmp(op, "==")) + { + if (Cvar_VariableValue(parameter[1]) == atof(parameter[3])) + shader.dpshaderkill = dpshaderkill; + } + else if (numparameters >= 4 && !strcmp(op, "!=")) + { + if (Cvar_VariableValue(parameter[1]) != atof(parameter[3])) + shader.dpshaderkill = dpshaderkill; + } + else if (numparameters >= 4 && !strcmp(op, ">")) + { + if (Cvar_VariableValue(parameter[1]) > atof(parameter[3])) + shader.dpshaderkill = dpshaderkill; + } + else if (numparameters >= 4 && !strcmp(op, "<")) + { + if (Cvar_VariableValue(parameter[1]) < atof(parameter[3])) + shader.dpshaderkill = dpshaderkill; + } + else if (numparameters >= 4 && !strcmp(op, ">=")) + { + if (Cvar_VariableValue(parameter[1]) >= atof(parameter[3])) + shader.dpshaderkill = dpshaderkill; + } + else if (numparameters >= 4 && !strcmp(op, "<=")) + { + if (Cvar_VariableValue(parameter[1]) <= atof(parameter[3])) + shader.dpshaderkill = dpshaderkill; + } + else + { + Con_DPrintf("%s parsing warning: unknown dpshaderkillifcvar op \"%s\", or not enough arguments\n", search->filenames[fileindex], op); + } + } else if (!strcasecmp(parameter[0], "sky") && numparameters >= 2) { // some q3 skies don't have the sky parm set @@ -1928,19 +2246,47 @@ 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], "dppolygonoffset")) + { + shader.textureflags |= Q3TEXTUREFLAG_POLYGONOFFSET; + if(numparameters >= 2) + { + shader.biaspolygonfactor = atof(parameter[1]); + if(numparameters >= 3) + shader.biaspolygonoffset = atof(parameter[2]); + else + shader.biaspolygonoffset = 0; + } + } + else if (!strcasecmp(parameter[0], "dptransparentsort") && numparameters >= 2) + { + shader.textureflags |= Q3TEXTUREFLAG_TRANSPARENTSORT; + if (!strcasecmp(parameter[1], "sky")) + shader.transparentsort = TRANSPARENTSORT_SKY; + else if (!strcasecmp(parameter[1], "distance")) + shader.transparentsort = TRANSPARENTSORT_DISTANCE; + else if (!strcasecmp(parameter[1], "hud")) + shader.transparentsort = TRANSPARENTSORT_HUD; + else + Con_DPrintf("%s parsing warning: unknown dptransparentsort category \"%s\", or not enough arguments\n", search->filenames[fileindex], parameter[1]); + } + 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]); @@ -1951,14 +2297,47 @@ 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], "dpwaterscroll") && numparameters >= 3) + { + shader.r_water_waterscroll[0] = 1/atof(parameter[1]); + shader.r_water_waterscroll[1] = 1/atof(parameter[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], "dprtlightambient") && numparameters >= 2) + { + shader.rtlightambient = atof(parameter[1]); + } + else if (!strcasecmp(parameter[0], "dpoffsetmapping") && numparameters >= 2) + { + if (!strcasecmp(parameter[1], "disable") || !strcasecmp(parameter[1], "none") || !strcasecmp(parameter[1], "off")) + shader.offsetmapping = OFFSETMAPPING_OFF; + else if (!strcasecmp(parameter[1], "default") || !strcasecmp(parameter[1], "normal")) + shader.offsetmapping = OFFSETMAPPING_DEFAULT; + else if (!strcasecmp(parameter[1], "linear")) + shader.offsetmapping = OFFSETMAPPING_LINEAR; + else if (!strcasecmp(parameter[1], "relief")) + shader.offsetmapping = OFFSETMAPPING_RELIEF; + if (numparameters >= 3) + shader.offsetscale = atof(parameter[2]); + if (numparameters >= 5) + { + if(!strcasecmp(parameter[3], "bias")) + shader.offsetbias = atof(parameter[4]); + else if(!strcasecmp(parameter[3], "match")) + shader.offsetbias = 1.0f - atof(parameter[4]); + else if(!strcasecmp(parameter[3], "match8")) + shader.offsetbias = 1.0f - atof(parameter[4]) / 255.0f; + else if(!strcasecmp(parameter[3], "match16")) + shader.offsetbias = 1.0f - atof(parameter[4]) / 65535.0f; + } + } else if (!strcasecmp(parameter[0], "deformvertexes") && numparameters >= 2) { int i, deformindex; @@ -1999,39 +2378,21 @@ void Mod_LoadQ3Shaders(void) } } } - // pick the primary layer to render with - if (shader.numlayers) - { - shader.backgroundlayer = -1; - shader.primarylayer = 0; - // if lightmap comes first this is definitely an ordinary texture - // if the first two layers have the correct blendfuncs and use vertex alpha, it is a blended terrain shader - if ((shader.layers[shader.primarylayer].texturename != NULL) - && !strcasecmp(shader.layers[shader.primarylayer].texturename[0], "$lightmap")) - { - shader.backgroundlayer = -1; - shader.primarylayer = 1; - } - else if (shader.numlayers >= 2 - && shader.layers[1].alphagen.alphagen == Q3ALPHAGEN_VERTEX - && (shader.layers[0].blendfunc[0] == GL_ONE && shader.layers[0].blendfunc[1] == GL_ZERO && !shader.layers[0].alphatest) - && ((shader.layers[1].blendfunc[0] == GL_SRC_ALPHA && shader.layers[1].blendfunc[1] == GL_ONE_MINUS_SRC_ALPHA) - || (shader.layers[1].blendfunc[0] == GL_ONE && shader.layers[1].blendfunc[1] == GL_ZERO && shader.layers[1].alphatest))) - { - // terrain blending or other effects - shader.backgroundlayer = 0; - shader.primarylayer = 1; - } - } + // hide this shader if a cvar said it should be killed + if (shader.dpshaderkill) + shader.numlayers = 0; // 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 < numcustsurfaceflags; j++) + Mem_Free(custsurfaceparmnames[j]); } q3shaderinfo_t *Mod_LookupQ3Shader(const char *name) @@ -2051,15 +2412,59 @@ q3shaderinfo_t *Mod_LookupQ3Shader(const char *name) return NULL; } -qboolean Mod_LoadTextureFromQ3Shader(texture_t *texture, const char *name, qboolean warnmissing, qboolean fallback, int defaulttexflags) +texture_shaderpass_t *Mod_CreateShaderPass(skinframe_t *skinframe) +{ + texture_shaderpass_t *shaderpass = (texture_shaderpass_t *)Mem_Alloc(loadmodel->mempool, sizeof(*shaderpass)); + shaderpass->framerate = 0.0f; + shaderpass->numframes = 1; + shaderpass->blendfunc[0] = GL_ONE; + shaderpass->blendfunc[1] = GL_ZERO; + shaderpass->rgbgen.rgbgen = Q3RGBGEN_IDENTITY; + shaderpass->alphagen.alphagen = Q3ALPHAGEN_IDENTITY; + shaderpass->alphatest = false; + shaderpass->tcgen.tcgen = Q3TCGEN_TEXTURE; + shaderpass->skinframes[0] = skinframe; + return shaderpass; +} + +texture_shaderpass_t *Mod_CreateShaderPassFromQ3ShaderLayer(q3shaderinfo_layer_t *layer, int layerindex, int texflags, const char *texturename) { int j; - int texflagsmask; + texture_shaderpass_t *shaderpass = (texture_shaderpass_t *)Mem_Alloc(loadmodel->mempool, sizeof(*shaderpass)); + shaderpass->alphatest = layer->alphatest != 0; + shaderpass->framerate = layer->framerate; + shaderpass->numframes = layer->numframes; + shaderpass->blendfunc[0] = layer->blendfunc[0]; + shaderpass->blendfunc[1] = layer->blendfunc[1]; + shaderpass->rgbgen = layer->rgbgen; + shaderpass->alphagen = layer->alphagen; + shaderpass->tcgen = layer->tcgen; + for (j = 0; j < Q3MAXTCMODS && layer->tcmods[j].tcmod != Q3TCMOD_NONE; j++) + shaderpass->tcmods[j] = layer->tcmods[j]; + for (j = 0; j < layer->numframes; j++) + { + if (cls.state == ca_dedicated) + { + shaderpass->skinframes[j] = NULL; + } + else if (!(shaderpass->skinframes[j] = R_SkinFrame_LoadExternal(layer->texturename[j], texflags, false))) + { + Con_Printf("^1%s:^7 could not load texture ^3\"%s\"^7 (frame %i) for layer %i of shader ^2\"%s\"\n", loadmodel->name, layer->texturename[j], j, layerindex, texturename); + shaderpass->skinframes[j] = R_SkinFrame_LoadMissing(); + } + } + return shaderpass; +} + +qboolean Mod_LoadTextureFromQ3Shader(texture_t *texture, const char *name, qboolean warnmissing, qboolean fallback, int defaulttexflags) +{ + int texflagsmask, texflagsor; qboolean success = true; q3shaderinfo_t *shader; if (!name) name = ""; strlcpy(texture->name, name, sizeof(texture->name)); + texture->basealpha = 1.0f; shader = name[0] ? Mod_LookupQ3Shader(name) : NULL; texflagsmask = ~0; @@ -2067,20 +2472,29 @@ 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 - // WHEN ADDING DEFAULTS HERE, REMEMBER TO SYNC TO SHADER LOADING ABOVE - // HERE, AND Q1BSP LOADING + texflagsor = 0; + if(defaulttexflags & TEXF_ISWORLD) + texflagsor |= TEXF_ISWORLD; + if(defaulttexflags & TEXF_ISSPRITE) + texflagsor |= TEXF_ISSPRITE; + // unless later loaded from the shader + texture->offsetmapping = (mod_noshader_default_offsetmapping.value) ? OFFSETMAPPING_DEFAULT : OFFSETMAPPING_OFF; + texture->offsetscale = 1; + texture->offsetbias = 0; + texture->specularscalemod = 1; + texture->specularpowermod = 1; + texture->rtlightambient = 0; + texture->transparentsort = TRANSPARENTSORT_DISTANCE; + // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS // JUST GREP FOR "specularscalemod = 1". if (shader) { if (developer_loading.integer) Con_Printf("%s: loaded shader for %s\n", loadmodel->name, name); - texture->surfaceparms = shader->surfaceparms; // allow disabling of picmip or compression by defaulttexflags - texture->textureflags = shader->textureflags & texflagsmask; + texture->textureflags = (shader->textureflags & texflagsmask) | texflagsor; if (shader->surfaceparms & Q3SURFACEPARM_SKY) { @@ -2101,15 +2515,21 @@ qboolean Mod_LoadTextureFromQ3Shader(texture_t *texture, const char *name, qbool if (shader->textureflags & Q3TEXTUREFLAG_TWOSIDED) texture->basematerialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE; if (shader->textureflags & Q3TEXTUREFLAG_POLYGONOFFSET) - texture->biaspolygonoffset -= 2; + { + texture->biaspolygonoffset += shader->biaspolygonoffset; + texture->biaspolygonfactor += shader->biaspolygonfactor; + } if (shader->textureflags & Q3TEXTUREFLAG_REFRACTION) texture->basematerialflags |= MATERIALFLAG_REFRACTION; if (shader->textureflags & Q3TEXTUREFLAG_REFLECTION) 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; + texture->transparentsort = shader->transparentsort; if (shader->numlayers > 0) { texture->customblendfunc[0] = shader->layers[0].blendfunc[0]; @@ -2149,55 +2569,107 @@ nothing GL_ZERO GL_ONE } if (!shader->lighting) texture->basematerialflags |= MATERIALFLAG_FULLBRIGHT; - if (shader->primarylayer >= 0) - { - q3shaderinfo_layer_t* primarylayer = shader->layers + shader->primarylayer; - // copy over many primarylayer parameters - texture->rgbgen = primarylayer->rgbgen; - texture->alphagen = primarylayer->alphagen; - texture->tcgen = primarylayer->tcgen; - memcpy(texture->tcmods, primarylayer->tcmods, sizeof(texture->tcmods)); - // load the textures - texture->numskinframes = primarylayer->numframes; - texture->skinframerate = primarylayer->framerate; - for (j = 0;j < primarylayer->numframes;j++) + + // here be dragons: convert quake3 shaders to material + if (shader->numlayers > 0) + { + int i; + int terrainbackgroundlayer = -1; + int lightmaplayer = -1; + int alphagenspecularlayer = -1; + int rgbgenvertexlayer = -1; + int rgbgendiffuselayer = -1; + int materiallayer = -1; + int endofprelayers = 0; + int firstpostlayer = 0; + int shaderpassindex = 0; + for (i = 0; i < shader->numlayers; i++) { - if(cls.state == ca_dedicated) - { - texture->skinframes[j] = NULL; - } - else if (!(texture->skinframes[j] = R_SkinFrame_LoadExternal(primarylayer->texturename[j], primarylayer->texflags & texflagsmask, false))) - { - Con_Printf("^1%s:^7 could not load texture ^3\"%s\"^7 (frame %i) for shader ^2\"%s\"\n", loadmodel->name, primarylayer->texturename[j], j, texture->name); - texture->skinframes[j] = R_SkinFrame_LoadMissing(); - } + if (shader->layers[i].texturename != NULL && !strcasecmp(shader->layers[i].texturename[0], "$lightmap")) + lightmaplayer = i; + if (shader->layers[i].rgbgen.rgbgen == Q3RGBGEN_VERTEX) + rgbgenvertexlayer = i; + if (shader->layers[i].rgbgen.rgbgen == Q3RGBGEN_LIGHTINGDIFFUSE) + rgbgendiffuselayer = i; + if (shader->layers[i].alphagen.alphagen == Q3ALPHAGEN_LIGHTINGSPECULAR) + alphagenspecularlayer = i; } - } - if (shader->backgroundlayer >= 0) - { - q3shaderinfo_layer_t* backgroundlayer = shader->layers + shader->backgroundlayer; - // copy over one secondarylayer parameter - memcpy(texture->backgroundtcmods, backgroundlayer->tcmods, sizeof(texture->backgroundtcmods)); - // load the textures - texture->backgroundnumskinframes = backgroundlayer->numframes; - texture->backgroundskinframerate = backgroundlayer->framerate; - for (j = 0;j < backgroundlayer->numframes;j++) + if (shader->numlayers >= 2 + && shader->layers[1].alphagen.alphagen == Q3ALPHAGEN_VERTEX + && (shader->layers[0].blendfunc[0] == GL_ONE && shader->layers[0].blendfunc[1] == GL_ZERO && !shader->layers[0].alphatest) + && ((shader->layers[1].blendfunc[0] == GL_SRC_ALPHA && shader->layers[1].blendfunc[1] == GL_ONE_MINUS_SRC_ALPHA) + || (shader->layers[1].blendfunc[0] == GL_ONE && shader->layers[1].blendfunc[1] == GL_ZERO && shader->layers[1].alphatest))) { - if(cls.state == ca_dedicated) - { - texture->skinframes[j] = NULL; - } - else if (!(texture->backgroundskinframes[j] = R_SkinFrame_LoadExternal(backgroundlayer->texturename[j], backgroundlayer->texflags & texflagsmask, false))) - { - Con_Printf("^1%s:^7 could not load texture ^3\"%s\"^7 (background frame %i) for shader ^2\"%s\"\n", loadmodel->name, backgroundlayer->texturename[j], j, texture->name); - texture->backgroundskinframes[j] = R_SkinFrame_LoadMissing(); - } + // terrain blend or certain other effects involving alphatest over a regular layer + terrainbackgroundlayer = 0; + materiallayer = 1; + // terrain may be vertex lit (in which case both layers are rgbGen vertex) or lightmapped (in which ase the third layer is lightmap) + firstpostlayer = lightmaplayer >= 0 ? lightmaplayer + 1 : materiallayer + 1; + } + else if (lightmaplayer == 0) + { + // ordinary texture but with $lightmap before diffuse + materiallayer = 1; + firstpostlayer = lightmaplayer + 2; + } + else if (lightmaplayer >= 1) + { + // ordinary texture - we don't properly apply lighting to the prelayers, but oh well... + endofprelayers = lightmaplayer - 1; + materiallayer = lightmaplayer - 1; + firstpostlayer = lightmaplayer + 1; + } + else if (rgbgenvertexlayer >= 0) + { + // map models with baked lighting + materiallayer = rgbgenvertexlayer; + endofprelayers = rgbgenvertexlayer; + firstpostlayer = rgbgenvertexlayer + 1; + } + else if (rgbgendiffuselayer >= 0) + { + // entity models with dynamic lighting + materiallayer = rgbgendiffuselayer; + endofprelayers = rgbgendiffuselayer; + firstpostlayer = rgbgendiffuselayer + 1; + // player models often have specular as a pass after diffuse - we don't currently make use of that specular texture (would need to meld it into the skinframe)... + if (alphagenspecularlayer >= 0) + firstpostlayer = alphagenspecularlayer + 1; + } + else + { + // special effects shaders - treat first as primary layer and do everything else as post + endofprelayers = 0; + materiallayer = 0; + firstpostlayer = 1; } + // convert the main material layer + // FIXME: if alphagenspecularlayer is used, we should pass a specular texture name to R_SkinFrame_LoadExternal and have it load that texture instead of the assumed name for _gloss texture + if (materiallayer >= 0) + texture->materialshaderpass = texture->shaderpasses[shaderpassindex++] = Mod_CreateShaderPassFromQ3ShaderLayer(&shader->layers[materiallayer], materiallayer, (shader->layers[materiallayer].texflags & texflagsmask) | texflagsor, texture->name); + // convert the terrain background blend layer (if any) + if (terrainbackgroundlayer >= 0) + texture->backgroundshaderpass = texture->shaderpasses[shaderpassindex++] = Mod_CreateShaderPassFromQ3ShaderLayer(&shader->layers[terrainbackgroundlayer], terrainbackgroundlayer, (shader->layers[terrainbackgroundlayer].texflags & texflagsmask) | texflagsor, texture->name); + // convert the prepass layers (if any) + texture->startpreshaderpass = shaderpassindex; + for (i = 0; i < endofprelayers; i++) + texture->shaderpasses[shaderpassindex++] = Mod_CreateShaderPassFromQ3ShaderLayer(&shader->layers[i], i, (shader->layers[i].texflags & texflagsmask) | texflagsor, texture->name); + texture->endpreshaderpass = shaderpassindex; + texture->startpostshaderpass = shaderpassindex; + // convert the postpass layers (if any) + for (i = firstpostlayer; i < shader->numlayers; i++) + texture->shaderpasses[shaderpassindex++] = Mod_CreateShaderPassFromQ3ShaderLayer(&shader->layers[i], i, (shader->layers[i].texflags & texflagsmask) | texflagsor, texture->name); + texture->startpostshaderpass = shaderpassindex; } + if (shader->dpshadow) texture->basematerialflags &= ~MATERIALFLAG_NOSHADOW; if (shader->dpnoshadow) texture->basematerialflags |= MATERIALFLAG_NOSHADOW; + if (shader->dpnortlight) + texture->basematerialflags |= MATERIALFLAG_NORTLIGHT; + if (shader->vertexalpha) + texture->basematerialflags |= MATERIALFLAG_ALPHAGEN_VERTEX; memcpy(texture->deforms, shader->deforms, sizeof(texture->deforms)); texture->reflectmin = shader->reflectmin; texture->reflectmax = shader->reflectmax; @@ -2206,46 +2678,146 @@ nothing GL_ZERO GL_ONE texture->reflectfactor = shader->reflectfactor; Vector4Copy(shader->reflectcolor4f, texture->reflectcolor4f); texture->r_water_wateralpha = shader->r_water_wateralpha; + Vector2Copy(shader->r_water_waterscroll, texture->r_water_waterscroll); + texture->offsetmapping = shader->offsetmapping; + texture->offsetscale = shader->offsetscale; + texture->offsetbias = shader->offsetbias; texture->specularscalemod = shader->specularscalemod; texture->specularpowermod = shader->specularpowermod; + texture->rtlightambient = shader->rtlightambient; + 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 ; + + texture->surfaceflags = shader->surfaceflags; + if (shader->surfaceparms & Q3SURFACEPARM_ALPHASHADOW ) texture->surfaceflags |= Q3SURFACEFLAG_ALPHASHADOW ; + // if (shader->surfaceparms & Q3SURFACEPARM_AREAPORTAL ) texture->surfaceflags |= Q3SURFACEFLAG_AREAPORTAL ; + // if (shader->surfaceparms & Q3SURFACEPARM_CLUSTERPORTAL) texture->surfaceflags |= Q3SURFACEFLAG_CLUSTERPORTAL; + // if (shader->surfaceparms & Q3SURFACEPARM_DETAIL ) texture->surfaceflags |= Q3SURFACEFLAG_DETAIL ; + // if (shader->surfaceparms & Q3SURFACEPARM_DONOTENTER ) texture->surfaceflags |= Q3SURFACEFLAG_DONOTENTER ; + // if (shader->surfaceparms & Q3SURFACEPARM_FOG ) texture->surfaceflags |= Q3SURFACEFLAG_FOG ; + // if (shader->surfaceparms & Q3SURFACEPARM_LAVA ) texture->surfaceflags |= Q3SURFACEFLAG_LAVA ; + if (shader->surfaceparms & Q3SURFACEPARM_LIGHTFILTER ) texture->surfaceflags |= Q3SURFACEFLAG_LIGHTFILTER ; + if (shader->surfaceparms & Q3SURFACEPARM_METALSTEPS ) texture->surfaceflags |= Q3SURFACEFLAG_METALSTEPS ; + if (shader->surfaceparms & Q3SURFACEPARM_NODAMAGE ) texture->surfaceflags |= Q3SURFACEFLAG_NODAMAGE ; + if (shader->surfaceparms & Q3SURFACEPARM_NODLIGHT ) texture->surfaceflags |= Q3SURFACEFLAG_NODLIGHT ; + if (shader->surfaceparms & Q3SURFACEPARM_NODRAW ) texture->surfaceflags |= Q3SURFACEFLAG_NODRAW ; + // if (shader->surfaceparms & Q3SURFACEPARM_NODROP ) texture->surfaceflags |= Q3SURFACEFLAG_NODROP ; + if (shader->surfaceparms & Q3SURFACEPARM_NOIMPACT ) texture->surfaceflags |= Q3SURFACEFLAG_NOIMPACT ; + if (shader->surfaceparms & Q3SURFACEPARM_NOLIGHTMAP ) texture->surfaceflags |= Q3SURFACEFLAG_NOLIGHTMAP ; + if (shader->surfaceparms & Q3SURFACEPARM_NOMARKS ) texture->surfaceflags |= Q3SURFACEFLAG_NOMARKS ; + // if (shader->surfaceparms & Q3SURFACEPARM_NOMIPMAPS ) texture->surfaceflags |= Q3SURFACEFLAG_NOMIPMAPS ; + if (shader->surfaceparms & Q3SURFACEPARM_NONSOLID ) texture->surfaceflags |= Q3SURFACEFLAG_NONSOLID ; + // if (shader->surfaceparms & Q3SURFACEPARM_ORIGIN ) texture->surfaceflags |= Q3SURFACEFLAG_ORIGIN ; + // if (shader->surfaceparms & Q3SURFACEPARM_PLAYERCLIP ) texture->surfaceflags |= Q3SURFACEFLAG_PLAYERCLIP ; + if (shader->surfaceparms & Q3SURFACEPARM_SKY ) texture->surfaceflags |= Q3SURFACEFLAG_SKY ; + if (shader->surfaceparms & Q3SURFACEPARM_SLICK ) texture->surfaceflags |= Q3SURFACEFLAG_SLICK ; + // if (shader->surfaceparms & Q3SURFACEPARM_SLIME ) texture->surfaceflags |= Q3SURFACEFLAG_SLIME ; + // if (shader->surfaceparms & Q3SURFACEPARM_STRUCTURAL ) texture->surfaceflags |= Q3SURFACEFLAG_STRUCTURAL ; + // if (shader->surfaceparms & Q3SURFACEPARM_TRANS ) texture->surfaceflags |= Q3SURFACEFLAG_TRANS ; + // if (shader->surfaceparms & Q3SURFACEPARM_WATER ) texture->surfaceflags |= Q3SURFACEFLAG_WATER ; + if (shader->surfaceparms & Q3SURFACEPARM_POINTLIGHT ) texture->surfaceflags |= Q3SURFACEFLAG_POINTLIGHT ; + if (shader->surfaceparms & Q3SURFACEPARM_HINT ) texture->surfaceflags |= Q3SURFACEFLAG_HINT ; + if (shader->surfaceparms & Q3SURFACEPARM_DUST ) texture->surfaceflags |= Q3SURFACEFLAG_DUST ; + // if (shader->surfaceparms & Q3SURFACEPARM_BOTCLIP ) texture->surfaceflags |= Q3SURFACEFLAG_BOTCLIP ; + // if (shader->surfaceparms & Q3SURFACEPARM_LIGHTGRID ) texture->surfaceflags |= Q3SURFACEFLAG_LIGHTGRID ; + // if (shader->surfaceparms & Q3SURFACEPARM_ANTIPORTAL ) texture->surfaceflags |= Q3SURFACEFLAG_ANTIPORTAL ; + + if (shader->dpmeshcollisions) + texture->basematerialflags |= MATERIALFLAG_MESHCOLLISIONS; + if (shader->dpshaderkill && developer_extra.integer) + Con_DPrintf("^1%s:^7 killing shader ^3\"%s\" because of cvar\n", loadmodel->name, name); } 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")) { if (developer_extra.integer) 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 { if (developer_extra.integer) 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->numskinframes = 1; + texture->supercontents = SUPERCONTENTS_SOLID | SUPERCONTENTS_OPAQUE; + } if(cls.state == ca_dedicated) { - texture->skinframes[0] = NULL; + texture->materialshaderpass = NULL; + success = false; } else { if (fallback) { - if ((texture->skinframes[0] = R_SkinFrame_LoadExternal(texture->name, defaulttexflags, false))) + texture->materialshaderpass = texture->shaderpasses[0] = Mod_CreateShaderPass(R_SkinFrame_LoadExternal(texture->name, defaulttexflags, false)); + if (texture->materialshaderpass->skinframes[0]) { - if(texture->skinframes[0]->hasalpha) + if (texture->materialshaderpass->skinframes[0]->hasalpha) texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; + if (texture->q2contents) + texture->supercontents = Mod_Q2BSP_SuperContentsFromNativeContents(loadmodel, texture->q2contents); } else success = false; @@ -2258,12 +2830,12 @@ nothing GL_ZERO GL_ONE } // init the animation variables texture->currentframe = texture; - if (texture->numskinframes < 1) - texture->numskinframes = 1; - if (!texture->skinframes[0]) - texture->skinframes[0] = R_SkinFrame_LoadMissing(); - texture->currentskinframe = texture->skinframes[0]; - texture->backgroundcurrentskinframe = texture->backgroundskinframes[0]; + if (!texture->materialshaderpass) + texture->materialshaderpass = texture->shaderpasses[0] = Mod_CreateShaderPass(R_SkinFrame_LoadMissing()); + if (!texture->materialshaderpass->skinframes[0]) + texture->materialshaderpass->skinframes[0] = R_SkinFrame_LoadMissing(); + texture->currentskinframe = texture->materialshaderpass ? texture->materialshaderpass->skinframes[0] : NULL; + texture->backgroundcurrentskinframe = texture->backgroundshaderpass ? texture->backgroundshaderpass->skinframes[0] : NULL; return success; } @@ -2275,6 +2847,7 @@ skinfile_t *Mod_LoadSkinFiles(void) skinfile_t *skinfile = NULL, *first = NULL; skinfileitem_t *skinfileitem; char word[10][MAX_QPATH]; + char vabuf[1024]; /* sample file: @@ -2292,7 +2865,7 @@ tag_weapon, tag_torso, */ memset(word, 0, sizeof(word)); - for (i = 0;i < 256 && (data = text = (char *)FS_LoadFile(va("%s_%i.skin", loadmodel->name, i), tempmempool, true, NULL));i++) + for (i = 0;i < 256 && (data = text = (char *)FS_LoadFile(va(vabuf, sizeof(vabuf), "%s_%i.skin", loadmodel->name, i), tempmempool, true, NULL));i++) { // If it's the first file we parse if (skinfile == NULL) @@ -2462,7 +3035,7 @@ void Mod_MakeSortedSurfaces(dp_model_t *mod) for (j = 0;j < mod->nummodelsurfaces;j++) { const msurface_t *surface = mod->data_surfaces + j + mod->firstmodelsurface; - int t = (int)(surface->texture - mod->data_textures); + t = (int)(surface->texture - mod->data_textures); numsurfacesfortexture[t]++; } j = 0; @@ -2474,15 +3047,18 @@ void Mod_MakeSortedSurfaces(dp_model_t *mod) for (j = 0;j < mod->nummodelsurfaces;j++) { const msurface_t *surface = mod->data_surfaces + j + mod->firstmodelsurface; - int t = (int)(surface->texture - mod->data_textures); + t = (int)(surface->texture - mod->data_textures); mod->sortedmodelsurfaces[firstsurfacefortexture[t]++] = j + mod->firstmodelsurface; } Mem_Free(firstsurfacefortexture); 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; @@ -2496,28 +3072,52 @@ static void Mod_BuildVBOs(void) } } - if (!vid.support.arb_vertex_buffer_object) - return; - - // element buffer is easy because it's just one array - if (loadmodel->surfmesh.num_triangles) + // build r_vertexmesh_t array + // (compressed interleaved array for D3D) + if (!loadmodel->surfmesh.data_vertexmesh && vid.useinterleavedarrays) { - 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_vertexmesh_t *vertexmesh; + loadmodel->surfmesh.data_vertexmesh = vertexmesh = (r_vertexmesh_t*)Mem_Alloc(loadmodel->mempool, numvertices * sizeof(r_vertexmesh_t)); + 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) + Vector4Copy(loadmodel->surfmesh.data_lightmapcolor4f + 4*vertexindex, vertexmesh->color4f); + 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); + if (loadmodel->surfmesh.data_skeletalindex4ub) + Vector4Copy(loadmodel->surfmesh.data_skeletalindex4ub + 4*vertexindex, vertexmesh->skeletalindex4ub); + if (loadmodel->surfmesh.data_skeletalweight4ub) + Vector4Copy(loadmodel->surfmesh.data_skeletalweight4ub + 4*vertexindex, vertexmesh->skeletalweight4ub); + } } + // 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, false, true); + + // 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, false, 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 && !vid.useinterleavedarrays) { - size_t size; + int size; unsigned char *mem; size = 0; + loadmodel->surfmesh.vbooffset_vertexmesh = size;if (loadmodel->surfmesh.data_vertexmesh ) size += loadmodel->surfmesh.num_vertices * sizeof(r_vertexmesh_t); loadmodel->surfmesh.vbooffset_vertex3f = size;if (loadmodel->surfmesh.data_vertex3f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]); loadmodel->surfmesh.vbooffset_svector3f = size;if (loadmodel->surfmesh.data_svector3f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]); loadmodel->surfmesh.vbooffset_tvector3f = size;if (loadmodel->surfmesh.data_tvector3f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]); @@ -2525,7 +3125,10 @@ static void Mod_BuildVBOs(void) loadmodel->surfmesh.vbooffset_texcoordtexture2f = size;if (loadmodel->surfmesh.data_texcoordtexture2f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[2]); loadmodel->surfmesh.vbooffset_texcoordlightmap2f = size;if (loadmodel->surfmesh.data_texcoordlightmap2f) size += loadmodel->surfmesh.num_vertices * sizeof(float[2]); loadmodel->surfmesh.vbooffset_lightmapcolor4f = size;if (loadmodel->surfmesh.data_lightmapcolor4f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[4]); + loadmodel->surfmesh.vbooffset_skeletalindex4ub = size;if (loadmodel->surfmesh.data_skeletalindex4ub ) size += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]); + loadmodel->surfmesh.vbooffset_skeletalweight4ub = size;if (loadmodel->surfmesh.data_skeletalweight4ub ) size += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]); mem = (unsigned char *)Mem_Alloc(tempmempool, size); + if (loadmodel->surfmesh.data_vertexmesh ) memcpy(mem + loadmodel->surfmesh.vbooffset_vertexmesh , loadmodel->surfmesh.data_vertexmesh , loadmodel->surfmesh.num_vertices * sizeof(r_vertexmesh_t)); if (loadmodel->surfmesh.data_vertex3f ) memcpy(mem + loadmodel->surfmesh.vbooffset_vertex3f , loadmodel->surfmesh.data_vertex3f , loadmodel->surfmesh.num_vertices * sizeof(float[3])); if (loadmodel->surfmesh.data_svector3f ) memcpy(mem + loadmodel->surfmesh.vbooffset_svector3f , loadmodel->surfmesh.data_svector3f , loadmodel->surfmesh.num_vertices * sizeof(float[3])); if (loadmodel->surfmesh.data_tvector3f ) memcpy(mem + loadmodel->surfmesh.vbooffset_tvector3f , loadmodel->surfmesh.data_tvector3f , loadmodel->surfmesh.num_vertices * sizeof(float[3])); @@ -2533,14 +3136,17 @@ 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); + if (loadmodel->surfmesh.data_skeletalindex4ub ) memcpy(mem + loadmodel->surfmesh.vbooffset_skeletalindex4ub , loadmodel->surfmesh.data_skeletalindex4ub , loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4])); + if (loadmodel->surfmesh.data_skeletalweight4ub ) memcpy(mem + loadmodel->surfmesh.vbooffset_skeletalweight4ub , loadmodel->surfmesh.data_skeletalweight4ub , loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4])); + loadmodel->surfmesh.vbo_vertexbuffer = R_Mesh_CreateMeshBuffer(mem, size, loadmodel->name, false, false, false, false); Mem_Free(mem); } } +extern cvar_t mod_obj_orientation; static void Mod_Decompile_OBJ(dp_model_t *model, const char *filename, const char *mtlfilename, const char *originalfilename) { - int vertexindex, surfaceindex, triangleindex, textureindex, countvertices = 0, countsurfaces = 0, countfaces = 0, counttextures = 0; + int submodelindex, vertexindex, surfaceindex, triangleindex, textureindex, countvertices = 0, countsurfaces = 0, countfaces = 0, counttextures = 0; int a, b, c; const char *texname; const int *e; @@ -2552,6 +3158,7 @@ static void Mod_Decompile_OBJ(dp_model_t *model, const char *filename, const cha const msurface_t *surface; const int maxtextures = 256; char *texturenames = (char *) Z_Malloc(maxtextures * MAX_QPATH); + dp_model_t *submodel; // construct the mtllib file l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "# mtllib for %s exported by darkplaces engine\n", originalfilename); @@ -2587,12 +3194,13 @@ static void Mod_Decompile_OBJ(dp_model_t *model, const char *filename, const cha // write the mtllib file FS_WriteFile(mtlfilename, outbuffer, outbufferpos); - outbufferpos = 0; // construct the obj file + outbufferpos = 0; l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "# model exported from %s by darkplaces engine\n# %i vertices, %i faces, %i surfaces\nmtllib %s\n", originalfilename, countvertices, countfaces, countsurfaces, mtlfilename); if (l > 0) outbufferpos += l; + for (vertexindex = 0, v = model->surfmesh.data_vertex3f, vn = model->surfmesh.data_normal3f, vt = model->surfmesh.data_texcoordtexture2f;vertexindex < model->surfmesh.num_vertices;vertexindex++, v += 3, vn += 3, vt += 2) { if (outbufferpos >= outbuffermax >> 1) @@ -2603,31 +3211,46 @@ static void Mod_Decompile_OBJ(dp_model_t *model, const char *filename, const cha memcpy(outbuffer, oldbuffer, outbufferpos); Z_Free(oldbuffer); } - l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "v %f %f %f\nvn %f %f %f\nvt %f %f\n", v[0], v[2], -v[1], vn[0], vn[2], -vn[1], vt[0], 1-vt[1]); + if(mod_obj_orientation.integer) + l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "v %f %f %f\nvn %f %f %f\nvt %f %f\n", v[0], v[2], v[1], vn[0], vn[2], vn[1], vt[0], 1-vt[1]); + else + l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "v %f %f %f\nvn %f %f %f\nvt %f %f\n", v[0], v[1], v[2], vn[0], vn[1], vn[2], vt[0], 1-vt[1]); if (l > 0) outbufferpos += l; } - for (surfaceindex = 0, surface = model->data_surfaces;surfaceindex < model->num_surfaces;surfaceindex++, surface++) + + for (submodelindex = 0;submodelindex < max(1, model->brush.numsubmodels);submodelindex++) { - l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "usemtl %s\n", (surface->texture && surface->texture->name[0]) ? surface->texture->name : "default"); + l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "o %i\n", submodelindex); if (l > 0) outbufferpos += l; - for (triangleindex = 0, e = model->surfmesh.data_element3i + surface->num_firsttriangle * 3;triangleindex < surface->num_triangles;triangleindex++, e += 3) + submodel = model->brush.numsubmodels ? model->brush.submodels[submodelindex] : model; + for (surfaceindex = 0;surfaceindex < submodel->nummodelsurfaces;surfaceindex++) { - if (outbufferpos >= outbuffermax >> 1) - { - outbuffermax *= 2; - oldbuffer = outbuffer; - outbuffer = (char *) Z_Malloc(outbuffermax); - memcpy(outbuffer, oldbuffer, outbufferpos); - Z_Free(oldbuffer); - } - a = e[0]+1; - b = e[2]+1; - c = e[1]+1; - l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "f %i/%i/%i %i/%i/%i %i/%i/%i\n", a,a,a,b,b,b,c,c,c); + surface = model->data_surfaces + submodel->sortedmodelsurfaces[surfaceindex]; + l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "usemtl %s\n", (surface->texture && surface->texture->name[0]) ? surface->texture->name : "default"); if (l > 0) outbufferpos += l; + for (triangleindex = 0, e = model->surfmesh.data_element3i + surface->num_firsttriangle * 3;triangleindex < surface->num_triangles;triangleindex++, e += 3) + { + if (outbufferpos >= outbuffermax >> 1) + { + outbuffermax *= 2; + oldbuffer = outbuffer; + outbuffer = (char *) Z_Malloc(outbuffermax); + memcpy(outbuffer, oldbuffer, outbufferpos); + Z_Free(oldbuffer); + } + a = e[0]+1; + b = e[1]+1; + c = e[2]+1; + if(mod_obj_orientation.integer) + l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "f %i/%i/%i %i/%i/%i %i/%i/%i\n", a,a,a,b,b,b,c,c,c); + else + l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "f %i/%i/%i %i/%i/%i %i/%i/%i\n", a,a,a,c,c,c,b,b,b); + if (l > 0) + outbufferpos += l; + } } } @@ -2651,7 +3274,6 @@ static void Mod_Decompile_SMD(dp_model_t *model, const char *filename, int first int poseindex; int cornerindex; const int *e; - const float *pose; size_t l; size_t outbufferpos = 0; size_t outbuffermax = 0x100000; @@ -2684,9 +3306,8 @@ static void Mod_Decompile_SMD(dp_model_t *model, const char *filename, int first 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[4][3]; matrix4x4_t posematrix; @@ -2701,19 +3322,18 @@ 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... - Matrix4x4_FromBonePose6s(&posematrix, model->num_posescale, model->data_poses6s + 6*(model->num_bones * poseindex + transformindex)); + Matrix4x4_FromBonePose7s(&posematrix, model->num_posescale, model->data_poses7s + 7*(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[4][3]; // smd matrix construction, for comparing @@ -2773,12 +3393,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; } @@ -2814,8 +3441,11 @@ 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; + char vabuf[1024]; if (Cmd_Argc() != 2) { @@ -2827,6 +3457,11 @@ static void Mod_Decompile_f(void) FS_StripExtension(inname, basename, sizeof(basename)); mod = Mod_ForName(inname, false, true, inname[0] == '*' ? cl.model_name[1] : NULL); + if (!mod) + { + Con_Print("No such model\n"); + return; + } if (mod->brush.submodel) { // if we're decompiling a submodel, be sure to give it a proper name based on its parent @@ -2834,11 +3469,6 @@ static void Mod_Decompile_f(void) dpsnprintf(basename, sizeof(basename), "%s/%s", outname, mod->name); outname[0] = 0; } - if (!mod) - { - Con_Print("No such model\n"); - return; - } if (!mod->surfmesh.num_triangles) { Con_Print("Empty model (or sprite)\n"); @@ -2876,17 +3506,21 @@ 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] != '_') + for (l = 0, k = (int)strlen(animname);animname[l];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] != '_') + for (l = 0, k = (int)strlen(animname2);animname2[l];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) { @@ -2903,30 +3537,37 @@ 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); + FS_WriteFile(va(vabuf, sizeof(vabuf), "%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); + FS_WriteFile(va(vabuf, sizeof(vabuf), "%s_decompiled/out_dpm.txt", basename), dpmtextbuffer, (fs_offset_t)dpmtextsize); + if (framegroupstextsize) + FS_WriteFile(va(vabuf, sizeof(vabuf), "%s_decompiled.framegroups", basename), framegroupstextbuffer, (fs_offset_t)framegroupstextsize); } } -void Mod_AllocLightmap_Init(mod_alloclightmap_state_t *state, int width, int height) +void Mod_AllocLightmap_Init(mod_alloclightmap_state_t *state, mempool_t *mempool, int width, int height) { int y; memset(state, 0, sizeof(*state)); state->width = width; state->height = height; state->currentY = 0; - state->rows = Mem_Alloc(loadmodel->mempool, state->height * sizeof(*state->rows)); + state->rows = (mod_alloclightmap_row_t *)Mem_Alloc(mempool, state->height * sizeof(*state->rows)); for (y = 0;y < state->height;y++) { state->rows[y].currentX = 0; @@ -3049,6 +3690,78 @@ static float mod_generatelightmaps_offsets[3][MAX_LIGHTMAPSAMPLES][3]; static int mod_generatelightmaps_numlights; static lightmaplight_t *mod_generatelightmaps_lightinfo; +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 = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist); + if (intensity <= 0.0f) + continue; + if (model && model->TraceLine) + { + model->TraceLine(model, NULL, NULL, &trace, pos, lightorigin, SUPERCONTENTS_VISBLOCKERMASK, SUPERCONTENTS_SKY); + 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; @@ -3062,7 +3775,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) { @@ -3085,35 +3798,34 @@ static void Mod_GenerateLightmaps_CreateLights_ComputeSVBSP(dp_model_t *model, l VectorSet(mins, lightinfo->origin[0] - lightinfo->radius, lightinfo->origin[1] - lightinfo->radius, lightinfo->origin[2] - lightinfo->radius); VectorSet(maxs, lightinfo->origin[0] + lightinfo->radius, lightinfo->origin[1] + lightinfo->radius, lightinfo->origin[2] + lightinfo->radius); VectorCopy(lightinfo->origin, origin); - nodes = Mem_Alloc(tempmempool, maxnodes * sizeof(*nodes)); + nodes = (svbsp_node_t *)Mem_Alloc(tempmempool, maxnodes * sizeof(*nodes)); for (;;) { SVBSP_Init(&svbsp, origin, maxnodes, nodes); Mod_GenerateLightmaps_CreateLights_ComputeSVBSP_InsertSurfaces(model, &svbsp, mins, maxs); if (svbsp.ranoutofnodes) { - maxnodes *= 2; - if (maxnodes >= 1<<22) + maxnodes *= 16; + if (maxnodes > 1<<22) { Mem_Free(nodes); return; } Mem_Free(nodes); - nodes = Mem_Alloc(tempmempool, maxnodes * sizeof(*nodes)); + nodes = (svbsp_node_t *)Mem_Alloc(tempmempool, maxnodes * sizeof(*nodes)); } else break; } if (svbsp.numnodes > 0) { - svbsp.nodes = Mem_Alloc(tempmempool, svbsp.numnodes * sizeof(*nodes)); + svbsp.nodes = (svbsp_node_t *)Mem_Alloc(tempmempool, svbsp.numnodes * sizeof(*nodes)); memcpy(svbsp.nodes, nodes, svbsp.numnodes * sizeof(*nodes)); lightinfo->svbsp = svbsp; } 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; @@ -3133,7 +3845,7 @@ static void Mod_GenerateLightmaps_CreateLights(dp_model_t *model) } if (mod_generatelightmaps_numlights > 0) { - mod_generatelightmaps_lightinfo = Mem_Alloc(tempmempool, mod_generatelightmaps_numlights * sizeof(*mod_generatelightmaps_lightinfo)); + mod_generatelightmaps_lightinfo = (lightmaplight_t *)Mem_Alloc(tempmempool, mod_generatelightmaps_numlights * sizeof(*mod_generatelightmaps_lightinfo)); lightinfo = mod_generatelightmaps_lightinfo; for (index = 0;;index++) { @@ -3180,8 +3892,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; @@ -3224,7 +3934,7 @@ static void Mod_GenerateLightmaps_SamplePoint(const float *pos, const float *nor if (!normal) { // for light grid we'd better check visibility of the offset point - cl.worldmodel->TraceLine(cl.worldmodel, NULL, NULL, &trace, pos, offsetpos, SUPERCONTENTS_VISBLOCKERMASK); + cl.worldmodel->TraceLine(cl.worldmodel, NULL, NULL, &trace, pos, offsetpos, SUPERCONTENTS_VISBLOCKERMASK, SUPERCONTENTS_SKY); if (trace.fraction < 1) VectorLerp(pos, trace.fraction, offsetpos, offsetpos); } @@ -3354,14 +4064,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; } @@ -3400,15 +4112,15 @@ 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.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; @@ -3435,12 +4147,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++; } @@ -3464,7 +4184,7 @@ static void Mod_GenerateLightmaps_CreateTriangleInformation(dp_model_t *model) const int *e; lightmaptriangle_t *triangle; // generate lightmap triangle structs - mod_generatelightmaps_lightmaptriangles = Mem_Alloc(model->mempool, model->surfmesh.num_triangles * sizeof(lightmaptriangle_t)); + mod_generatelightmaps_lightmaptriangles = (lightmaptriangle_t *)Mem_Alloc(model->mempool, model->surfmesh.num_triangles * sizeof(lightmaptriangle_t)); for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++) { surface = model->data_surfaces + surfaceindex; @@ -3535,12 +4255,13 @@ 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; unsigned char *deluxemappixels; mod_alloclightmap_state_t lmstate; + char vabuf[1024]; // generate lightmap projection information for all triangles if (model->texturepool == NULL) @@ -3548,8 +4269,8 @@ 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); - Mod_AllocLightmap_Init(&lmstate, lm_texturesize, lm_texturesize); + //lm_maxpixels = lm_texturesize-(lm_borderpixels*2+1); + Mod_AllocLightmap_Init(&lmstate, loadmodel->mempool, lm_texturesize, lm_texturesize); lightmapnumber = 0; for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++) { @@ -3597,7 +4318,7 @@ static void Mod_GenerateLightmaps_CreateLightmaps(dp_model_t *model) surfaceindex = -1; lightmapnumber = 0; Mod_AllocLightmap_Free(&lmstate); - Mod_AllocLightmap_Init(&lmstate, lm_texturesize, lm_texturesize); + Mod_AllocLightmap_Init(&lmstate, loadmodel->mempool, lm_texturesize, lm_texturesize); break; } // if we have maxed out the lightmap size, and this triangle does @@ -3613,14 +4334,16 @@ 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; - model->brushq3.data_lightmaps = Mem_Alloc(model->mempool, model->brushq3.num_mergedlightmaps * sizeof(rtexture_t *)); - model->brushq3.data_deluxemaps = Mem_Alloc(model->mempool, model->brushq3.num_mergedlightmaps * sizeof(rtexture_t *)); - lightmappixels = Mem_Alloc(tempmempool, model->brushq3.num_mergedlightmaps * lm_texturesize * lm_texturesize * 4); - deluxemappixels = Mem_Alloc(tempmempool, model->brushq3.num_mergedlightmaps * lm_texturesize * lm_texturesize * 4); + model->brushq3.data_lightmaps = (rtexture_t **)Mem_Alloc(model->mempool, model->brushq3.num_mergedlightmaps * sizeof(rtexture_t *)); + model->brushq3.data_deluxemaps = (rtexture_t **)Mem_Alloc(model->mempool, model->brushq3.num_mergedlightmaps * sizeof(rtexture_t *)); + lightmappixels = (unsigned char *)Mem_Alloc(tempmempool, model->brushq3.num_mergedlightmaps * lm_texturesize * lm_texturesize * 4); + deluxemappixels = (unsigned char *)Mem_Alloc(tempmempool, model->brushq3.num_mergedlightmaps * lm_texturesize * lm_texturesize * 4); for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++) { surface = model->data_surfaces + surfaceindex; @@ -3721,8 +4444,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(vabuf, sizeof(vabuf), "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(vabuf, sizeof(vabuf), "deluxemap%i", lightmapindex), lm_texturesize, lm_texturesize, deluxemappixels + lightmapindex * lm_texturesize * lm_texturesize * 4, TEXTYPE_BGRA, TEXF_FORCELINEAR, -1, NULL); } if (lightmappixels) @@ -3733,12 +4456,26 @@ static void Mod_GenerateLightmaps_CreateLightmaps(dp_model_t *model) for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++) { surface = model->data_surfaces + surfaceindex; - e = model->surfmesh.data_element3i + surface->num_firsttriangle*3; if (!surface->num_triangles) continue; 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; } }