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);
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++)
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++)
{
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);
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;
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++)
{
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);
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])
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++)
{
// 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++)
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);
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");
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;
// 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);
}
}
}
}
- // 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
//
// 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);
}
}
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)
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)
{
lastEntry = entry;
entry = entry->chain;
}
+ while (entry != NULL);
if (entry == NULL)
{
if (lastEntry->shader.name[0] != 0)
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;
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
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;
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.specularscalemod = 1;
- shader.specularpowermod = 1;
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, "{"))
{
// multilayer terrain shader or similar
shader.textureblendalpha = true;
+ if (mod_q3shader_force_terrain_alphaflag.integer)
+ shader.layers[0].dptexflags |= TEXF_ALPHA;
}
}
if(layer->blendfunc[0] == GL_ONE && layer->blendfunc[1] == GL_ONE)
layer->blendfunc[0] = GL_SRC_ALPHA;
}
-
- layer->texflags = 0;
+
+ layer->dptexflags = 0;
if (layer->alphatest)
- layer->texflags |= TEXF_ALPHA;
+ layer->dptexflags |= TEXF_ALPHA;
switch(layer->blendfunc[0])
{
case GL_SRC_ALPHA:
case GL_ONE_MINUS_SRC_ALPHA:
- layer->texflags |= TEXF_ALPHA;
+ layer->dptexflags |= TEXF_ALPHA;
break;
}
switch(layer->blendfunc[1])
{
case GL_SRC_ALPHA:
case GL_ONE_MINUS_SRC_ALPHA:
- layer->texflags |= TEXF_ALPHA;
+ layer->dptexflags |= TEXF_ALPHA;
break;
}
if (!(shader.surfaceparms & Q3SURFACEPARM_NOMIPMAPS))
- layer->texflags |= TEXF_MIPMAP;
+ layer->dptexflags |= TEXF_MIPMAP;
if (!(shader.textureflags & Q3TEXTUREFLAG_NOPICMIP))
- layer->texflags |= TEXF_PICMIP | TEXF_COMPRESS;
+ layer->dptexflags |= TEXF_PICMIP | TEXF_COMPRESS;
if (layer->clampmap)
- layer->texflags |= TEXF_CLAMP;
+ layer->dptexflags |= TEXF_CLAMP;
continue;
}
numparameters = 0;
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;
// 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);
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;
+ // allow disabling of picmip or compression by defaulttexflags
texflagsmask = ~0;
if(!(defaulttexflags & TEXF_PICMIP))
texflagsmask &= ~TEXF_PICMIP;
texture->specularscalemod = 1;
texture->specularpowermod = 1;
texture->rtlightambient = 0;
- // WHEN ADDING DEFAULTS HERE, REMEMBER TO SYNC TO SHADER LOADING ABOVE
- // HERE, AND Q1BSP LOADING
+ 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);
- // allow disabling of picmip or compression by defaulttexflags
- texture->textureflags = (shader->textureflags & texflagsmask) | texflagsor;
-
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
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];
}
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].dptexflags & 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].dptexflags & 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].dptexflags & 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].dptexflags & texflagsmask) | texflagsor, texture->name);
+ texture->startpostshaderpass = shaderpassindex;
}
+
if (shader->dpshadow)
texture->basematerialflags &= ~MATERIALFLAG_NOSHADOW;
if (shader->dpnoshadow)
}
else if (texture->surfaceflags & Q3SURFACEFLAG_SKY)
{
- texture->basematerialflags |= MATERIALFLAG_SKY | MATERIALFLAG_NOSHADOW;
+ texture->basematerialflags |= MATERIALFLAG_SKY;
texture->supercontents = SUPERCONTENTS_SKY;
}
else
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;
}
// 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;
}
+void Mod_LoadCustomMaterial(texture_t *texture, const char *name, int supercontents, int materialflags, skinframe_t *skinframe)
+{
+ if (!(materialflags & (MATERIALFLAG_WALL | MATERIALFLAG_SKY)))
+ Con_DPrintf("^1%s:^7 Custom texture ^3\"%s\" does not have MATERIALFLAG_WALL set\n", loadmodel->name, texture->name);
+ strlcpy(texture->name, name, sizeof(texture->name));
+ texture->basealpha = 1.0f;
+ texture->basematerialflags = texture->currentmaterialflags = materialflags;
+ texture->supercontents = supercontents;
+
+ 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 (developer_extra.integer)
+ Con_DPrintf("^1%s:^7 Custom texture ^3\"%s\"\n", loadmodel->name, texture->name);
+ texture->materialshaderpass = texture->shaderpasses[0] = Mod_CreateShaderPass(skinframe);
+
+ // init the animation variables
+ texture->currentframe = texture;
+ 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;
+}
+
skinfile_t *Mod_LoadSkinFiles(void)
{
int i, words, line, wordsoverflow;
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;
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);
// 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);
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 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
// 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]);
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]));
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_vertexbuffer = R_Mesh_CreateMeshBuffer(mem, size, loadmodel->name, false, false, false);
+ 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);
}
}
{
// 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] == '_')
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] == '_')
}
}
-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;
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;
}
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);
}
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;
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++)
{
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
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;
}
Mod_GenerateLightmaps(cl.worldmodel);
}
+
+void Mod_Mesh_Create(dp_model_t *mod, const char *name)
+{
+ memset(mod, 0, sizeof(*mod));
+ strlcpy(mod->name, name, sizeof(mod->name));
+ mod->mempool = Mem_AllocPool(name, 0, NULL);
+ mod->texturepool = R_AllocTexturePool();
+ mod->Draw = R_Q1BSP_Draw;
+ mod->DrawDepth = R_Q1BSP_DrawDepth;
+ mod->DrawDebug = R_Q1BSP_DrawDebug;
+ mod->DrawPrepass = R_Q1BSP_DrawPrepass;
+ mod->GetLightInfo = R_Q1BSP_GetLightInfo;
+ mod->DrawShadowMap = R_Q1BSP_DrawShadowMap;
+ mod->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
+ mod->DrawLight = R_Q1BSP_DrawLight;
+}
+
+void Mod_Mesh_Destroy(dp_model_t *mod)
+{
+ Mod_UnloadModel(mod);
+}
+
+// resets the mesh model to have no geometry to render, ready for a new frame -
+// the mesh will be prepared for rendering later using Mod_Mesh_Finalize
+void Mod_Mesh_Reset(dp_model_t *mod)
+{
+ mod->num_surfaces = 0;
+ mod->surfmesh.num_vertices = 0;
+ mod->surfmesh.num_triangles = 0;
+ memset(mod->surfmesh.data_vertexhash, -1, mod->surfmesh.num_vertexhashsize * sizeof(*mod->surfmesh.data_vertexhash));
+ mod->DrawSky = NULL; // will be set if a texture needs it
+ mod->DrawAddWaterPlanes = NULL; // will be set if a texture needs it
+}
+
+texture_t *Mod_Mesh_GetTexture(dp_model_t *mod, const char *name)
+{
+ int i;
+ texture_t *t;
+ for (i = 0; i < mod->num_textures; i++)
+ if (!strcmp(mod->data_textures[i].name, name))
+ return mod->data_textures + i;
+ if (mod->max_textures <= mod->num_textures)
+ {
+ texture_t *oldtextures = mod->data_textures;
+ mod->max_textures = max(mod->max_textures * 2, 1024);
+ mod->data_textures = (texture_t *)Mem_Realloc(mod->mempool, mod->data_textures, mod->max_textures * sizeof(*mod->data_textures));
+ // update the pointers
+ for (i = 0; i < mod->num_surfaces; i++)
+ mod->data_surfaces[i].texture = mod->data_textures + (mod->data_surfaces[i].texture - oldtextures);
+ }
+ t = &mod->data_textures[mod->num_textures++];
+ Mod_LoadTextureFromQ3Shader(t, name, false, true, 0);
+ return t;
+}
+
+msurface_t *Mod_Mesh_AddSurface(dp_model_t *mod, texture_t *tex)
+{
+ msurface_t *surf;
+ // check if the proposed surface matches the last one we created
+ if (mod->num_surfaces == 0 || mod->data_surfaces[mod->num_surfaces - 1].texture != tex)
+ {
+ if (mod->max_surfaces == mod->num_surfaces)
+ {
+ mod->max_surfaces = 2 * max(mod->num_surfaces, 64);
+ mod->data_surfaces = (msurface_t *)Mem_Realloc(mod->mempool, mod->data_surfaces, mod->max_surfaces * sizeof(*mod->data_surfaces));
+ mod->sortedmodelsurfaces = (int *)Mem_Realloc(mod->mempool, mod->sortedmodelsurfaces, mod->max_surfaces * sizeof(*mod->sortedmodelsurfaces));
+ }
+ surf = mod->data_surfaces + mod->num_surfaces;
+ mod->num_surfaces++;
+ memset(surf, 0, sizeof(*surf));
+ surf->texture = tex;
+ surf->num_firsttriangle = mod->surfmesh.num_triangles;
+ surf->num_firstvertex = mod->surfmesh.num_vertices;
+ if (tex->basematerialflags & (MATERIALFLAG_SKY))
+ mod->DrawSky = R_Q1BSP_DrawSky;
+ if (tex->basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
+ mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
+ return surf;
+ }
+ return mod->data_surfaces + mod->num_surfaces - 1;
+}
+
+int Mod_Mesh_IndexForVertex(dp_model_t *mod, msurface_t *surf, float x, float y, float z, float nx, float ny, float nz, float s, float t, float u, float v, float r, float g, float b, float a)
+{
+ int hashindex, h, vnum, mask;
+ surfmesh_t *mesh = &mod->surfmesh;
+ if (mesh->max_vertices == mesh->num_vertices)
+ {
+ mesh->max_vertices = max(mesh->num_vertices * 2, 256);
+ mesh->data_vertex3f = (float *)Mem_Realloc(mod->mempool, mesh->data_vertex3f, mesh->max_vertices * sizeof(float[3]));
+ mesh->data_svector3f = (float *)Mem_Realloc(mod->mempool, mesh->data_svector3f, mesh->max_vertices * sizeof(float[3]));
+ mesh->data_tvector3f = (float *)Mem_Realloc(mod->mempool, mesh->data_tvector3f, mesh->max_vertices * sizeof(float[3]));
+ mesh->data_normal3f = (float *)Mem_Realloc(mod->mempool, mesh->data_normal3f, mesh->max_vertices * sizeof(float[3]));
+ mesh->data_texcoordtexture2f = (float *)Mem_Realloc(mod->mempool, mesh->data_texcoordtexture2f, mesh->max_vertices * sizeof(float[2]));
+ mesh->data_texcoordlightmap2f = (float *)Mem_Realloc(mod->mempool, mesh->data_texcoordlightmap2f, mesh->max_vertices * sizeof(float[2]));
+ mesh->data_lightmapcolor4f = (float *)Mem_Realloc(mod->mempool, mesh->data_lightmapcolor4f, mesh->max_vertices * sizeof(float[4]));
+ // rebuild the hash table
+ mesh->num_vertexhashsize = 4 * mesh->max_vertices;
+ mesh->num_vertexhashsize &= ~(mesh->num_vertexhashsize - 1); // round down to pow2
+ mesh->data_vertexhash = (int *)Mem_Realloc(mod->mempool, mesh->data_vertexhash, mesh->num_vertexhashsize * sizeof(*mesh->data_vertexhash));
+ memset(mesh->data_vertexhash, -1, mesh->num_vertexhashsize * sizeof(*mesh->data_vertexhash));
+ mask = mod->surfmesh.num_vertexhashsize - 1;
+ // no need to hash the vertices for the entire model, the latest surface will suffice.
+ for (vnum = surf ? surf->num_firstvertex : 0; vnum < mesh->num_vertices; vnum++)
+ {
+ // this uses prime numbers intentionally for computing the hash
+ hashindex = (unsigned int)(mesh->data_vertex3f[vnum * 3 + 0] * 2003 + mesh->data_vertex3f[vnum * 3 + 1] * 4001 + mesh->data_vertex3f[vnum * 3 + 2] * 7919 + mesh->data_normal3f[vnum * 3 + 0] * 4097 + mesh->data_normal3f[vnum * 3 + 1] * 257 + mesh->data_normal3f[vnum * 3 + 2] * 17) & mask;
+ for (h = hashindex; mesh->data_vertexhash[h] >= 0; h = (h + 1) & mask)
+ ; // just iterate until we find the terminator
+ mesh->data_vertexhash[h] = vnum;
+ }
+ }
+ mask = mod->surfmesh.num_vertexhashsize - 1;
+ // this uses prime numbers intentionally for computing the hash
+ hashindex = (unsigned int)(x * 2003 + y * 4001 + z * 7919 + nx * 4097 + ny * 257 + nz * 17) & mask;
+ // when possible find an identical vertex within the same surface and return it
+ for(h = hashindex;(vnum = mesh->data_vertexhash[h]) >= 0;h = (h + 1) & mask)
+ {
+ if (vnum >= surf->num_firstvertex
+ && mesh->data_vertex3f[vnum * 3 + 0] == x && mesh->data_vertex3f[vnum * 3 + 1] == y && mesh->data_vertex3f[vnum * 3 + 2] == z
+ && mesh->data_normal3f[vnum * 3 + 0] == nx && mesh->data_normal3f[vnum * 3 + 1] == ny && mesh->data_normal3f[vnum * 3 + 2] == nz
+ && mesh->data_texcoordtexture2f[vnum * 2 + 0] == s && mesh->data_texcoordtexture2f[vnum * 2 + 1] == t
+ && mesh->data_texcoordlightmap2f[vnum * 2 + 0] == u && mesh->data_texcoordlightmap2f[vnum * 2 + 1] == v
+ && mesh->data_lightmapcolor4f[vnum * 4 + 0] == r && mesh->data_lightmapcolor4f[vnum * 4 + 1] == g && mesh->data_lightmapcolor4f[vnum * 4 + 2] == b && mesh->data_lightmapcolor4f[vnum * 4 + 3] == a)
+ return vnum;
+ }
+ // add the new vertex
+ vnum = mesh->num_vertices++;
+ if (surf->num_vertices > 0)
+ {
+ if (surf->mins[0] > x) surf->mins[0] = x;
+ if (surf->mins[1] > y) surf->mins[1] = y;
+ if (surf->mins[2] > z) surf->mins[2] = z;
+ if (surf->maxs[0] < x) surf->maxs[0] = x;
+ if (surf->maxs[1] < y) surf->maxs[1] = y;
+ if (surf->maxs[2] < z) surf->maxs[2] = z;
+ }
+ else
+ {
+ VectorSet(surf->mins, x, y, z);
+ VectorSet(surf->maxs, x, y, z);
+ }
+ surf->num_vertices = mesh->num_vertices - surf->num_firstvertex;
+ mesh->data_vertexhash[h] = vnum;
+ mesh->data_vertex3f[vnum * 3 + 0] = x;
+ mesh->data_vertex3f[vnum * 3 + 1] = y;
+ mesh->data_vertex3f[vnum * 3 + 2] = z;
+ mesh->data_normal3f[vnum * 3 + 0] = nx;
+ mesh->data_normal3f[vnum * 3 + 1] = ny;
+ mesh->data_normal3f[vnum * 3 + 2] = nz;
+ mesh->data_texcoordtexture2f[vnum * 2 + 0] = s;
+ mesh->data_texcoordtexture2f[vnum * 2 + 1] = t;
+ mesh->data_texcoordlightmap2f[vnum * 2 + 0] = u;
+ mesh->data_texcoordlightmap2f[vnum * 2 + 1] = v;
+ mesh->data_lightmapcolor4f[vnum * 4 + 0] = r;
+ mesh->data_lightmapcolor4f[vnum * 4 + 1] = g;
+ mesh->data_lightmapcolor4f[vnum * 4 + 2] = b;
+ mesh->data_lightmapcolor4f[vnum * 4 + 3] = a;
+ return vnum;
+}
+
+void Mod_Mesh_AddTriangle(dp_model_t *mod, msurface_t *surf, int e0, int e1, int e2)
+{
+ surfmesh_t *mesh = &mod->surfmesh;
+ if (mesh->max_triangles == mesh->num_triangles)
+ {
+ mesh->max_triangles = 2 * max(mesh->num_triangles, 128);
+ mesh->data_element3s = (unsigned short *)Mem_Realloc(mod->mempool, mesh->data_element3s, mesh->max_triangles * sizeof(unsigned short[3]));
+ mesh->data_element3i = (int *)Mem_Realloc(mod->mempool, mesh->data_element3i, mesh->max_triangles * sizeof(int[3]));
+ }
+ mesh->data_element3s[mesh->num_triangles * 3 + 0] = e0;
+ mesh->data_element3s[mesh->num_triangles * 3 + 1] = e1;
+ mesh->data_element3s[mesh->num_triangles * 3 + 2] = e2;
+ mesh->data_element3i[mesh->num_triangles * 3 + 0] = e0;
+ mesh->data_element3i[mesh->num_triangles * 3 + 1] = e1;
+ mesh->data_element3i[mesh->num_triangles * 3 + 2] = e2;
+ mesh->num_triangles++;
+ surf->num_triangles++;
+}
+
+static void Mod_Mesh_MakeSortedSurfaces(dp_model_t *mod)
+{
+ int i, j;
+ texture_t *tex;
+ msurface_t *surf, *surf2;
+
+ // build the sorted surfaces list properly to reduce material setup
+ // this is easy because we're just sorting on texture and don't care about the order of textures
+ mod->nummodelsurfaces = 0;
+ for (i = 0; i < mod->num_surfaces; i++)
+ mod->data_surfaces[i].included = false;
+ for (i = 0; i < mod->num_surfaces; i++)
+ {
+ surf = mod->data_surfaces + i;
+ if (surf->included)
+ continue;
+ tex = surf->texture;
+ // j = i is intentional
+ for (j = i; j < mod->num_surfaces; j++)
+ {
+ surf2 = mod->data_surfaces + j;
+ if (surf2->included)
+ continue;
+ if (surf2->texture == tex)
+ {
+ surf2->included = true;
+ mod->sortedmodelsurfaces[mod->nummodelsurfaces++] = j;
+ }
+ }
+ }
+}
+
+void Mod_Mesh_ComputeBounds(dp_model_t *mod)
+{
+ int i;
+ vec_t x2a, x2b, y2a, y2b, z2a, z2b, x2, y2, z2, yawradius, rotatedradius;
+
+ if (mod->surfmesh.num_vertices > 0)
+ {
+ // calculate normalmins/normalmaxs
+ VectorCopy(mod->surfmesh.data_vertex3f, mod->normalmins);
+ VectorCopy(mod->surfmesh.data_vertex3f, mod->normalmaxs);
+ for (i = 1; i < mod->surfmesh.num_vertices; i++)
+ {
+ float x = mod->surfmesh.data_vertex3f[i * 3 + 0];
+ float y = mod->surfmesh.data_vertex3f[i * 3 + 1];
+ float z = mod->surfmesh.data_vertex3f[i * 3 + 2];
+ // expand bounds to include this vertex
+ if (mod->normalmins[0] > x) mod->normalmins[0] = x;
+ if (mod->normalmins[1] > y) mod->normalmins[1] = y;
+ if (mod->normalmins[2] > z) mod->normalmins[2] = z;
+ if (mod->normalmaxs[0] < x) mod->normalmaxs[0] = x;
+ if (mod->normalmaxs[1] < y) mod->normalmaxs[1] = y;
+ if (mod->normalmaxs[2] < z) mod->normalmaxs[2] = z;
+ }
+ // calculate yawmins/yawmaxs, rotatedmins/maxs from normalmins/maxs
+ // (fast but less accurate than doing it per vertex)
+ x2a = mod->normalmins[0] * mod->normalmins[0];
+ x2b = mod->normalmaxs[0] * mod->normalmaxs[0];
+ y2a = mod->normalmins[1] * mod->normalmins[1];
+ y2b = mod->normalmaxs[1] * mod->normalmaxs[1];
+ z2a = mod->normalmins[2] * mod->normalmins[2];
+ z2b = mod->normalmaxs[2] * mod->normalmaxs[2];
+ x2 = max(x2a, x2b);
+ y2 = max(y2a, y2b);
+ z2 = max(z2a, z2b);
+ yawradius = sqrt(x2 + y2);
+ rotatedradius = sqrt(x2 + y2 + z2);
+ VectorSet(mod->yawmins, -yawradius, -yawradius, mod->normalmins[2]);
+ VectorSet(mod->yawmaxs, yawradius, yawradius, mod->normalmaxs[2]);
+ VectorSet(mod->rotatedmins, -rotatedradius, -rotatedradius, -rotatedradius);
+ VectorSet(mod->rotatedmaxs, rotatedradius, rotatedradius, rotatedradius);
+ mod->radius = rotatedradius;
+ mod->radius2 = x2 + y2 + z2;
+ }
+ else
+ {
+ VectorClear(mod->normalmins);
+ VectorClear(mod->normalmaxs);
+ VectorClear(mod->yawmins);
+ VectorClear(mod->yawmaxs);
+ VectorClear(mod->rotatedmins);
+ VectorClear(mod->rotatedmaxs);
+ mod->radius = 0;
+ mod->radius2 = 0;
+ }
+}
+
+void Mod_Mesh_Finalize(dp_model_t *mod)
+{
+ Mod_Mesh_ComputeBounds(mod);
+ Mod_Mesh_MakeSortedSurfaces(mod);
+ Mod_BuildTextureVectorsFromNormals(0, mod->surfmesh.num_vertices, mod->surfmesh.num_triangles, mod->surfmesh.data_vertex3f, mod->surfmesh.data_texcoordtexture2f, mod->surfmesh.data_normal3f, mod->surfmesh.data_element3i, mod->surfmesh.data_svector3f, mod->surfmesh.data_tvector3f, true);
+}