X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=model_shared.c;h=dd5e06e0a43b575458a956d023143dcdc42e1748;hb=f7750d34bc095248efb2aec0cefb2e3db367ab3b;hp=0c4fe1759c63359576b002e563e67072cc1599fc;hpb=c2e80277d20d64e0da8ea14523eed5af1f3120dd;p=xonotic%2Fdarkplaces.git diff --git a/model_shared.c b/model_shared.c index 0c4fe175..dd5e06e0 100644 --- a/model_shared.c +++ b/model_shared.c @@ -63,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); @@ -86,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++) @@ -100,8 +100,8 @@ static void mod_shutdown(void) 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++) @@ -110,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); @@ -200,12 +201,6 @@ void Mod_UnloadModel (dp_model_t *mod) used = mod->used; if (mod->mempool) { - if (mod->surfmesh.vertex3fbuffer) - R_Mesh_DestroyMeshBuffer(mod->surfmesh.vertex3fbuffer); - mod->surfmesh.vertex3fbuffer = NULL; - if (mod->surfmesh.vertexmeshbuffer) - R_Mesh_DestroyMeshBuffer(mod->surfmesh.vertexmeshbuffer); - mod->surfmesh.vertexmeshbuffer = NULL; if (mod->surfmesh.data_element3i_indexbuffer) R_Mesh_DestroyMeshBuffer(mod->surfmesh.data_element3i_indexbuffer); mod->surfmesh.data_element3i_indexbuffer = NULL; @@ -354,7 +349,9 @@ static void Mod_FindPotentialDeforms(dp_model_t *mod) for (i = 0;i < mod->num_textures;i++) { texture = mod->data_textures + i; - if (texture->tcgen.tcgen == Q3TCGEN_ENVIRONMENT) + 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++) { @@ -507,7 +504,7 @@ dp_model_t *Mod_LoadModel(dp_model_t *mod, qboolean crash, qboolean checkdisk) 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 || !memcmp(buf, "BSP2", 4)) 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); @@ -539,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]) @@ -549,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++) { @@ -579,7 +576,7 @@ 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: empty name"); @@ -632,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); @@ -663,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"); @@ -927,7 +924,7 @@ static void Mod_BuildBumpVectors(const float *v0, const float *v1, const float * 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; @@ -993,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); } } @@ -1235,21 +1232,13 @@ static void Mod_ShadowMesh_CreateVBOs(shadowmesh_t *mesh, mempool_t *mempool) } } - // upload r_vertexmesh_t array as a buffer - if (mesh->vertexmesh && !mesh->vertexmeshbuffer) - mesh->vertexmeshbuffer = R_Mesh_CreateMeshBuffer(mesh->vertexmesh, mesh->numverts * sizeof(*mesh->vertexmesh), loadmodel->name, false, false, false); - - // upload vertex3f array as a buffer - if (mesh->vertex3f && !mesh->vertex3fbuffer) - mesh->vertex3fbuffer = R_Mesh_CreateMeshBuffer(mesh->vertex3f, mesh->numverts * sizeof(float[3]), loadmodel->name, false, false, false); - // upload short indices as a buffer if (mesh->element3s && !mesh->element3s_indexbuffer) - mesh->element3s_indexbuffer = R_Mesh_CreateMeshBuffer(mesh->element3s, mesh->numtriangles * sizeof(short[3]), loadmodel->name, true, false, true); + 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); + 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 // @@ -1258,21 +1247,23 @@ static void Mod_ShadowMesh_CreateVBOs(shadowmesh_t *mesh, mempool_t *mempool) // other hand animated models don't use a lot of vertices anyway... 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_vertexbuffer = R_Mesh_CreateMeshBuffer(mem, size, "shadowmesh", false, false, false); + mesh->vbo_vertexbuffer = R_Mesh_CreateMeshBuffer(mem, size, "shadowmesh", false, false, false, false); Mem_Free(mem); } } @@ -1361,10 +1352,6 @@ void Mod_ShadowMesh_Free(shadowmesh_t *mesh) shadowmesh_t *nextmesh; for (;mesh;mesh = nextmesh) { - if (mesh->vertex3fbuffer) - R_Mesh_DestroyMeshBuffer(mesh->vertex3fbuffer); - if (mesh->vertexmeshbuffer) - R_Mesh_DestroyMeshBuffer(mesh->vertexmeshbuffer); if (mesh->element3i_indexbuffer) R_Mesh_DestroyMeshBuffer(mesh->element3i_indexbuffer); if (mesh->element3s_indexbuffer) @@ -1594,7 +1581,7 @@ 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) { @@ -1627,6 +1614,7 @@ static void Q3Shader_AddToHash (q3shaderinfo_t* shader) lastEntry = entry; entry = entry->chain; } + while (entry != NULL); if (entry == NULL) { if (lastEntry->shader.name[0] != 0) @@ -1707,7 +1695,7 @@ void Mod_LoadQ3Shaders(void) break; } // name - j = strlen(com_token)+1; + j = (int)strlen(com_token)+1; custsurfaceparmnames[numcustsurfaceflags] = (char *)Mem_Alloc(tempmempool, j); strlcpy(custsurfaceparmnames[numcustsurfaceflags], com_token, j+1); // value @@ -1742,8 +1730,6 @@ void Mod_LoadQ3Shaders(void) shader.lighting = false; shader.vertexalpha = false; shader.textureblendalpha = false; - shader.primarylayer = 0; - shader.backgroundlayer = 0; shader.skyboxname[0] = 0; shader.deforms[0].deform = Q3DEFORM_NONE; shader.dpnortlight = false; @@ -2395,30 +2381,6 @@ void Mod_LoadQ3Shaders(void) // hide this shader if a cvar said it should be killed if (shader.dpshaderkill) shader.numlayers = 0; - // 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; - } - } // fix up multiple reflection types if(shader.textureflags & Q3TEXTUREFLAG_WATERSHADER) shader.textureflags &= ~(Q3TEXTUREFLAG_REFRACTION | Q3TEXTUREFLAG_REFLECTION | Q3TEXTUREFLAG_CAMERA); @@ -2450,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; + 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; @@ -2492,7 +2498,7 @@ qboolean Mod_LoadTextureFromQ3Shader(texture_t *texture, const char *name, qbool if (shader->surfaceparms & Q3SURFACEPARM_SKY) { - texture->basematerialflags = MATERIALFLAG_SKY | MATERIALFLAG_NOSHADOW; + texture->basematerialflags = MATERIALFLAG_SKY; if (shader->skyboxname[0]) { // quake3 seems to append a _ to the skybox name, so this must do so as well @@ -2563,51 +2569,99 @@ nothing GL_ZERO GL_ONE } if (!shader->lighting) texture->basematerialflags |= MATERIALFLAG_FULLBRIGHT; - if (shader->primarylayer >= 0) + + // here be dragons: convert quake3 shaders to material + if (shader->numlayers > 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++) + 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) | texflagsor, 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) | texflagsor, 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) @@ -2740,7 +2794,7 @@ nothing GL_ZERO GL_ONE } else if (texture->surfaceflags & Q3SURFACEFLAG_SKY) { - texture->basematerialflags |= MATERIALFLAG_SKY | MATERIALFLAG_NOSHADOW; + texture->basematerialflags |= MATERIALFLAG_SKY; texture->supercontents = SUPERCONTENTS_SKY; } else @@ -2748,20 +2802,22 @@ nothing GL_ZERO GL_ONE texture->basematerialflags |= MATERIALFLAG_WALL; texture->supercontents = SUPERCONTENTS_SOLID | SUPERCONTENTS_OPAQUE; } - texture->numskinframes = 1; 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; @@ -2774,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; } @@ -2979,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; @@ -2991,7 +3047,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); mod->sortedmodelsurfaces[firstsurfacefortexture[t]++] = j + mod->firstmodelsurface; } Mem_Free(firstsurfacefortexture); @@ -3018,12 +3074,12 @@ void Mod_BuildVBOs(void) // build r_vertexmesh_t array // (compressed interleaved array for D3D) - if (!loadmodel->surfmesh.vertexmesh && vid.useinterleavedarrays) + if (!loadmodel->surfmesh.data_vertexmesh && vid.useinterleavedarrays) { int vertexindex; int numvertices = loadmodel->surfmesh.num_vertices; r_vertexmesh_t *vertexmesh; - loadmodel->surfmesh.vertexmesh = vertexmesh = (r_vertexmesh_t*)Mem_Alloc(loadmodel->mempool, numvertices * sizeof(*loadmodel->surfmesh.vertexmesh)); + 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); @@ -3042,21 +3098,13 @@ void Mod_BuildVBOs(void) } } - // upload r_vertexmesh_t array as a buffer - if (loadmodel->surfmesh.vertexmesh && !loadmodel->surfmesh.vertexmeshbuffer) - loadmodel->surfmesh.vertexmeshbuffer = R_Mesh_CreateMeshBuffer(loadmodel->surfmesh.vertexmesh, loadmodel->surfmesh.num_vertices * sizeof(*loadmodel->surfmesh.vertexmesh), loadmodel->name, false, false, false); - - // upload vertex3f array as a buffer - if (loadmodel->surfmesh.data_vertex3f && !loadmodel->surfmesh.vertex3fbuffer) - loadmodel->surfmesh.vertex3fbuffer = R_Mesh_CreateMeshBuffer(loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.num_vertices * sizeof(float[3]), loadmodel->name, false, false, false); - // upload short indices as a buffer if (loadmodel->surfmesh.data_element3s && !loadmodel->surfmesh.data_element3s_indexbuffer) - loadmodel->surfmesh.data_element3s_indexbuffer = R_Mesh_CreateMeshBuffer(loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles * sizeof(short[3]), loadmodel->name, true, false, true); + 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); + 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 @@ -3066,9 +3114,10 @@ void Mod_BuildVBOs(void) // other hand animated models don't use a lot of vertices anyway... 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]); @@ -3079,6 +3128,7 @@ void Mod_BuildVBOs(void) 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])); @@ -3088,7 +3138,7 @@ void Mod_BuildVBOs(void) if (loadmodel->surfmesh.data_lightmapcolor4f ) memcpy(mem + loadmodel->surfmesh.vbooffset_lightmapcolor4f , loadmodel->surfmesh.data_lightmapcolor4f , loadmodel->surfmesh.num_vertices * sizeof(float[4])); 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); + loadmodel->surfmesh.vbo_vertexbuffer = R_Mesh_CreateMeshBuffer(mem, size, loadmodel->name, false, false, false, false); Mem_Free(mem); } } @@ -3456,7 +3506,7 @@ static void Mod_Decompile_f(void) { // individual frame // check for additional frames with same name - for (l = 0, k = strlen(animname);animname[l];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] == '_') @@ -3466,7 +3516,7 @@ static void Mod_Decompile_f(void) 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++) + 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] == '_') @@ -3510,14 +3560,14 @@ static void Mod_Decompile_f(void) } } -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 = (mod_alloclightmap_row_t *)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; @@ -3682,7 +3732,7 @@ static void Mod_GenerateLightmaps_LightPoint(dp_model_t *model, const vec3_t pos continue; if (model && model->TraceLine) { - model->TraceLine(model, NULL, NULL, &trace, pos, lightorigin, SUPERCONTENTS_VISBLOCKERMASK); + model->TraceLine(model, NULL, NULL, &trace, pos, lightorigin, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT | MATERIALFLAG_NOSHADOW); if (trace.fraction < 1) continue; } @@ -3884,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_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT | MATERIALFLAG_NOSHADOW); if (trace.fraction < 1) VectorLerp(pos, trace.fraction, offsetpos, offsetpos); } @@ -4062,15 +4112,6 @@ static void Mod_GenerateLightmaps_UnweldTriangles(dp_model_t *model) if (model->surfmesh.num_vertices > 65536) model->surfmesh.data_element3s = NULL; - if (model->surfmesh.vertexmesh) - Mem_Free(model->surfmesh.vertexmesh); - model->surfmesh.vertexmesh = NULL; - if (model->surfmesh.vertex3fbuffer) - R_Mesh_DestroyMeshBuffer(model->surfmesh.vertex3fbuffer); - model->surfmesh.vertex3fbuffer = NULL; - if (model->surfmesh.vertexmeshbuffer) - R_Mesh_DestroyMeshBuffer(model->surfmesh.vertexmeshbuffer); - model->surfmesh.vertexmeshbuffer = NULL; if (model->surfmesh.data_element3i_indexbuffer) R_Mesh_DestroyMeshBuffer(model->surfmesh.data_element3i_indexbuffer); model->surfmesh.data_element3i_indexbuffer = NULL; @@ -4229,7 +4270,7 @@ static void Mod_GenerateLightmaps_CreateLightmaps(dp_model_t *model) 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); + Mod_AllocLightmap_Init(&lmstate, loadmodel->mempool, lm_texturesize, lm_texturesize); lightmapnumber = 0; for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++) { @@ -4277,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