#include "image.h"
#include "r_shadow.h"
-cvar_t r_mipskins = {CVAR_SAVE, "r_mipskins", "0"};
+cvar_t r_mipskins = {CVAR_SAVE, "r_mipskins", "0", "mipmaps skins (so they become blurrier in the distance), disabled by default because it tends to blur with strange border colors from the skin"};
model_t *loadmodel;
+#if 0
+// LordHavoc: was 512
+static int mod_numknown = 0;
+static int mod_maxknown = 0;
+static model_t *mod_known = NULL;
+#else
// LordHavoc: was 512
#define MAX_MOD_KNOWN (MAX_MODELS + 256)
+static int mod_numknown = 0;
+static int mod_maxknown = MAX_MOD_KNOWN;
static model_t mod_known[MAX_MOD_KNOWN];
+#endif
static void mod_start(void)
{
int i;
model_t *mod;
- for (i = 0, mod = mod_known;i < MAX_MOD_KNOWN;i++, mod++)
+ for (i = 0, mod = mod_known;i < mod_numknown;i++, mod++)
if (mod->name[0])
if (mod->used)
Mod_LoadModel(mod, true, false, mod->isworldmodel);
int i;
model_t *mod;
- for (i = 0, mod = mod_known;i < MAX_MOD_KNOWN;i++, mod++)
+ for (i = 0, mod = mod_known;i < mod_numknown;i++, mod++)
if (mod->loaded)
Mod_UnloadModel(mod);
}
if (!cl_stainmaps_clearonload.integer)
return;
- for (i = 0;i < MAX_MOD_KNOWN;i++)
+ for (i = 0;i < mod_numknown;i++)
{
if (mod_known[i].mempool && mod_known[i].data_surfaces)
{
Mod_SpriteInit();
Cvar_RegisterVariable(&r_mipskins);
- Cmd_AddCommand ("modellist", Mod_Print);
- Cmd_AddCommand ("modelprecache", Mod_Precache);
+ Cmd_AddCommand ("modellist", Mod_Print, "prints a list of loaded models");
+ Cmd_AddCommand ("modelprecache", Mod_Precache, "load a model");
}
void Mod_RenderInit(void)
}
}
if (mod->loaded)
- return mod; // already loaded
+ {
+ // already loaded
+ if (buf)
+ Mem_Free(buf);
+ return mod;
+ }
Con_DPrintf("loading model %s\n", mod->name);
// LordHavoc: unload the existing model in this slot (if there is one)
return mod;
}
-/*
-===================
-Mod_ClearAll
-===================
-*/
-void Mod_ClearAll(void)
-{
-}
-
void Mod_ClearUsed(void)
{
#if 0
int i;
model_t *mod;
- for (i = 0, mod = mod_known;i < MAX_MOD_KNOWN;i++, mod++)
+ for (i = 0, mod = mod_known;i < mod_numknown;i++, mod++)
if (mod->name[0])
mod->used = false;
#endif
int i;
model_t *mod;
- for (i = 0, mod = mod_known;i < MAX_MOD_KNOWN;i++, mod++)
+ for (i = 0, mod = mod_known;i < mod_numknown;i++, mod++)
if (mod->name[0])
if (!mod->used)
Mod_UnloadModel(mod);
int i;
model_t *mod;
- for (i = 0, mod = mod_known;i < MAX_MOD_KNOWN;i++, mod++)
+ for (i = 0, mod = mod_known;i < mod_numknown;i++, mod++)
{
if (mod->isworldmodel && mod->loaded && skip != mod)
{
model_t *Mod_FindName(const char *name)
{
int i;
- model_t *mod, *freemod;
+ model_t *mod;
if (!name[0])
Host_Error ("Mod_ForName: NULL name");
// search the currently loaded models
- freemod = NULL;
- for (i = 0, mod = mod_known;i < MAX_MOD_KNOWN;i++, mod++)
+ for (i = 0, mod = mod_known;i < mod_numknown;i++, mod++)
{
- if (mod->name[0])
+ if (mod->name[0] && !strcmp(mod->name, name))
{
- if (!strcmp (mod->name, name))
- {
- mod->used = true;
- return mod;
- }
+ mod->used = true;
+ return mod;
}
- else if (freemod == NULL)
- freemod = mod;
}
- if (freemod)
+ // no match found, find room for a new one
+ for (i = 0;i < mod_numknown;i++)
+ if (!mod_known[i].name[0])
+ break;
+
+ if (mod_maxknown == i)
{
- mod = freemod;
- strcpy (mod->name, name);
- mod->loaded = false;
- mod->used = true;
- return mod;
+#if 0
+ model_t *old;
+ mod_maxknown += 256;
+ old = mod_known;
+ mod_known = Mem_Alloc(mod_mempool, mod_maxknown * sizeof(model_t));
+ if (old)
+ {
+ memcpy(mod_known, old, mod_numknown * sizeof(model_t));
+ Mem_Free(old);
+ }
+#else
+ Host_Error ("Mod_FindName: ran out of models");
+#endif
}
-
- Host_Error ("Mod_FindName: ran out of models");
- return NULL;
+ if (mod_numknown == i)
+ mod_numknown++;
+ mod = mod_known + i;
+ strcpy (mod->name, name);
+ mod->loaded = false;
+ mod->used = true;
+ return mod;
}
/*
model_t *mod;
Con_Print("Loaded models:\n");
- for (i = 0, mod = mod_known;i < MAX_MOD_KNOWN;i++, mod++)
+ for (i = 0, mod = mod_known;i < mod_numknown;i++, mod++)
if (mod->name[0])
Con_Printf("%4iK %s\n", mod->mempool ? (mod->mempool->totalsize + 1023) / 1024 : 0, mod->name);
}
}
#endif
-void Mod_ValidateElements(int *elements, int numtriangles, int numverts, const char *filename, int fileline)
+void Mod_ValidateElements(int *elements, int numtriangles, int firstvertex, int numverts, const char *filename, int fileline)
{
- int i, warned = false;
+ int i, warned = false, endvertex = firstvertex + numverts;
for (i = 0;i < numtriangles * 3;i++)
{
- if ((unsigned int)elements[i] >= (unsigned int)numverts)
+ if (elements[i] < firstvertex || elements[i] >= endvertex)
{
if (!warned)
{
warned = true;
Con_Printf("Mod_ValidateElements: out of bounds elements detected at %s:%d\n", filename, fileline);
}
- elements[i] = 0;
+ elements[i] = firstvertex;
}
}
}
{
int i, tnum;
float sdir[3], tdir[3], normal[3], *v;
+ const float *v0, *v1, *v2, *tc0, *tc1, *tc2;
+ float f, tangentcross[3], v10[3], v20[3], tc10[2], tc20[2];
const int *e;
// clear the vectors
if (svector3f)
// process each vertex of each triangle and accumulate the results
for (tnum = 0, e = elements;tnum < numtriangles;tnum++, e += 3)
{
- Mod_BuildBumpVectors(vertex3f + e[0] * 3, vertex3f + e[1] * 3, vertex3f + e[2] * 3, texcoord2f + e[0] * 2, texcoord2f + e[1] * 2, texcoord2f + e[2] * 2, sdir, tdir, normal);
+ v0 = vertex3f + e[0] * 3;
+ v1 = vertex3f + e[1] * 3;
+ v2 = vertex3f + e[2] * 3;
+ tc0 = texcoord2f + e[0] * 2;
+ tc1 = texcoord2f + e[1] * 2;
+ tc2 = texcoord2f + e[2] * 2;
+
+ // 79 add/sub/negate/multiply (1 cycle), 1 compare (3 cycle?), total cycles not counting load/store/exchange roughly 82 cycles
+ // 6 add, 28 subtract, 39 multiply, 1 compare, 50% chance of 6 negates
+
+ // calculate the edge directions and surface normal
+ // 6 multiply, 9 subtract
+ VectorSubtract(v1, v0, v10);
+ VectorSubtract(v2, v0, v20);
+ normal[0] = v20[1] * v10[2] - v20[2] * v10[1];
+ normal[1] = v20[2] * v10[0] - v20[0] * v10[2];
+ normal[2] = v20[0] * v10[1] - v20[1] * v10[0];
+
+ // calculate the tangents
+ // 12 multiply, 10 subtract
+ tc10[1] = tc1[1] - tc0[1];
+ tc20[1] = tc2[1] - tc0[1];
+ sdir[0] = tc10[1] * v20[0] - tc20[1] * v10[0];
+ sdir[1] = tc10[1] * v20[1] - tc20[1] * v10[1];
+ sdir[2] = tc10[1] * v20[2] - tc20[1] * v10[2];
+ tc10[0] = tc1[0] - tc0[0];
+ tc20[0] = tc2[0] - tc0[0];
+ tdir[0] = tc10[0] * v20[0] - tc20[0] * v10[0];
+ tdir[1] = tc10[0] * v20[1] - tc20[0] * v10[1];
+ tdir[2] = tc10[0] * v20[2] - tc20[0] * v10[2];
+
+ // make the tangents completely perpendicular to the surface normal
+ // 12 multiply, 4 add, 6 subtract
+ f = DotProduct(sdir, normal);
+ sdir[0] -= f * normal[0];
+ sdir[1] -= f * normal[1];
+ sdir[2] -= f * normal[2];
+ f = DotProduct(tdir, normal);
+ tdir[0] -= f * normal[0];
+ tdir[1] -= f * normal[1];
+ tdir[2] -= f * normal[2];
+
+ // if texture is mapped the wrong way (counterclockwise), the tangents
+ // have to be flipped, this is detected by calculating a normal from the
+ // two tangents, and seeing if it is opposite the surface normal
+ // 9 multiply, 2 add, 3 subtract, 1 compare, 50% chance of: 6 negates
+ CrossProduct(tdir, sdir, tangentcross);
+ if (DotProduct(tangentcross, normal) < 0)
+ {
+ VectorNegate(sdir, sdir);
+ VectorNegate(tdir, tdir);
+ }
+
if (!areaweighting)
{
VectorNormalize(sdir);
VectorNormalize(v);
}
-surfmesh_t *Mod_AllocSurfMesh(mempool_t *mempool, int numvertices, int numtriangles, qboolean lightmapoffsets, qboolean vertexcolors, qboolean neighbors)
+void Mod_AllocSurfMesh(mempool_t *mempool, int numvertices, int numtriangles, qboolean lightmapoffsets, qboolean vertexcolors, qboolean neighbors)
{
- surfmesh_t *mesh;
unsigned char *data;
- mesh = (surfmesh_t *)Mem_Alloc(mempool, sizeof(surfmesh_t) + numvertices * (3 + 3 + 3 + 3 + 2 + 2 + (vertexcolors ? 4 : 0)) * sizeof(float) + numvertices * (lightmapoffsets ? 1 : 0) * sizeof(int) + numtriangles * (3 + (neighbors ? 3 : 0)) * sizeof(int));
- mesh->num_vertices = numvertices;
- mesh->num_triangles = numtriangles;
- data = (unsigned char *)(mesh + 1);
- if (mesh->num_vertices)
+ data = (unsigned char *)Mem_Alloc(mempool, numvertices * (3 + 3 + 3 + 3 + 2 + 2 + (vertexcolors ? 4 : 0)) * sizeof(float) + numvertices * (lightmapoffsets ? 1 : 0) * sizeof(int) + numtriangles * (3 + (neighbors ? 3 : 0)) * sizeof(int));
+ loadmodel->surfmesh.num_vertices = numvertices;
+ loadmodel->surfmesh.num_triangles = numtriangles;
+ if (loadmodel->surfmesh.num_vertices)
{
- mesh->data_vertex3f = (float *)data, data += sizeof(float[3]) * mesh->num_vertices;
- mesh->data_svector3f = (float *)data, data += sizeof(float[3]) * mesh->num_vertices;
- mesh->data_tvector3f = (float *)data, data += sizeof(float[3]) * mesh->num_vertices;
- mesh->data_normal3f = (float *)data, data += sizeof(float[3]) * mesh->num_vertices;
- mesh->data_texcoordtexture2f = (float *)data, data += sizeof(float[2]) * mesh->num_vertices;
- mesh->data_texcoordlightmap2f = (float *)data, data += sizeof(float[2]) * mesh->num_vertices;
+ loadmodel->surfmesh.data_vertex3f = (float *)data, data += sizeof(float[3]) * loadmodel->surfmesh.num_vertices;
+ loadmodel->surfmesh.data_svector3f = (float *)data, data += sizeof(float[3]) * loadmodel->surfmesh.num_vertices;
+ loadmodel->surfmesh.data_tvector3f = (float *)data, data += sizeof(float[3]) * loadmodel->surfmesh.num_vertices;
+ loadmodel->surfmesh.data_normal3f = (float *)data, data += sizeof(float[3]) * loadmodel->surfmesh.num_vertices;
+ loadmodel->surfmesh.data_texcoordtexture2f = (float *)data, data += sizeof(float[2]) * loadmodel->surfmesh.num_vertices;
+ loadmodel->surfmesh.data_texcoordlightmap2f = (float *)data, data += sizeof(float[2]) * loadmodel->surfmesh.num_vertices;
if (vertexcolors)
- mesh->data_lightmapcolor4f = (float *)data, data += sizeof(float[4]) * mesh->num_vertices;
+ loadmodel->surfmesh.data_lightmapcolor4f = (float *)data, data += sizeof(float[4]) * loadmodel->surfmesh.num_vertices;
if (lightmapoffsets)
- mesh->data_lightmapoffsets = (int *)data, data += sizeof(int) * mesh->num_vertices;
+ loadmodel->surfmesh.data_lightmapoffsets = (int *)data, data += sizeof(int) * loadmodel->surfmesh.num_vertices;
}
- if (mesh->num_triangles)
+ if (loadmodel->surfmesh.num_triangles)
{
- mesh->data_element3i = (int *)data, data += sizeof(int[3]) * mesh->num_triangles;
+ loadmodel->surfmesh.data_element3i = (int *)data, data += sizeof(int[3]) * loadmodel->surfmesh.num_triangles;
if (neighbors)
- mesh->data_neighbor3i = (int *)data, data += sizeof(int[3]) * mesh->num_triangles;
+ loadmodel->surfmesh.data_neighbor3i = (int *)data, data += sizeof(int[3]) * loadmodel->surfmesh.num_triangles;
}
- return mesh;
}
shadowmesh_t *Mod_ShadowMesh_Alloc(mempool_t *mempool, int maxverts, int maxtriangles, rtexture_t *map_diffuse, rtexture_t *map_specular, rtexture_t *map_normal, int light, int neighbors, int expandable)
break;
if (i < width * height * 4)
{
- unsigned char *fogpixels = Mem_Alloc(loadmodel->mempool, width * height * 4);
+ unsigned char *fogpixels = (unsigned char *)Mem_Alloc(loadmodel->mempool, width * height * 4);
memcpy(fogpixels, skindata, width * height * 4);
for (i = 0;i < width * height * 4;i += 4)
fogpixels[i] = fogpixels[i+1] = fogpixels[i+2] = 255;
// If it's the first file we parse
if (skinfile == NULL)
{
- skinfile = (skinfile_t *)Mem_Alloc(tempmempool, sizeof(skinfile_t));
+ skinfile = (skinfile_t *)Mem_Alloc(loadmodel->mempool, sizeof(skinfile_t));
first = skinfile;
}
else
{
- skinfile->next = (skinfile_t *)Mem_Alloc(tempmempool, sizeof(skinfile_t));
+ skinfile->next = (skinfile_t *)Mem_Alloc(loadmodel->mempool, sizeof(skinfile_t));
skinfile = skinfile->next;
}
skinfile->next = NULL;
if (words == 3)
{
Con_DPrintf("Mod_LoadSkinFiles: parsed mesh \"%s\" shader replacement \"%s\"\n", word[1], word[2]);
- skinfileitem = (skinfileitem_t *)Mem_Alloc(tempmempool, sizeof(skinfileitem_t));
+ skinfileitem = (skinfileitem_t *)Mem_Alloc(loadmodel->mempool, sizeof(skinfileitem_t));
skinfileitem->next = skinfile->items;
skinfile->items = skinfileitem;
strlcpy (skinfileitem->name, word[1], sizeof (skinfileitem->name));
{
// mesh shader name, like "U_RArm,models/players/Legoman/BikerA1.tga"
Con_DPrintf("Mod_LoadSkinFiles: parsed mesh \"%s\" shader replacement \"%s\"\n", word[0], word[2]);
- skinfileitem = (skinfileitem_t *)Mem_Alloc(tempmempool, sizeof(skinfileitem_t));
+ skinfileitem = (skinfileitem_t *)Mem_Alloc(loadmodel->mempool, sizeof(skinfileitem_t));
skinfileitem->next = skinfile->items;
skinfile->items = skinfileitem;
strlcpy (skinfileitem->name, word[0], sizeof (skinfileitem->name));