cvar_t r_novis = {0, "r_novis", "0"};
cvar_t r_miplightmaps = {CVAR_SAVE, "r_miplightmaps", "0"};
cvar_t r_lightmaprgba = {0, "r_lightmaprgba", "1"};
-cvar_t r_vertexsurfacesthreshold = {CVAR_SAVE, "r_vertexsurfacesthreshold", "0"};
cvar_t r_nosurftextures = {0, "r_nosurftextures", "0"};
cvar_t r_sortsurfaces = {0, "r_sortsurfaces", "0"};
Cvar_RegisterVariable(&r_novis);
Cvar_RegisterVariable(&r_miplightmaps);
Cvar_RegisterVariable(&r_lightmaprgba);
- Cvar_RegisterVariable(&r_vertexsurfacesthreshold);
Cvar_RegisterVariable(&r_nosurftextures);
Cvar_RegisterVariable(&r_sortsurfaces);
memset(mod_novis, 0xff, sizeof(mod_novis));
// add two slots for notexture walls and notexture liquids
loadmodel->numtextures = m->nummiptex + 2;
- loadmodel->textures = Mem_Alloc(loadmodel->mempool, loadmodel->numtextures * sizeof(*loadmodel->textures));
+ loadmodel->textures = Mem_Alloc(loadmodel->mempool, loadmodel->numtextures * sizeof(texture_t));
// fill out all slots with notexture
- for (i = 0;i < loadmodel->numtextures;i++)
+ for (i = 0, tx = loadmodel->textures;i < loadmodel->numtextures;i++, tx++)
{
- loadmodel->textures[i] = tx = Mem_Alloc(loadmodel->mempool, sizeof(texture_t));
tx->width = 16;
tx->height = 16;
tx->texture = r_notexture;
+ tx->shader = &Cshader_wall_lightmap;
if (i == loadmodel->numtextures - 1)
- tx->flags = SURF_DRAWTURB | SURF_DRAWFULLBRIGHT | SURF_DRAWNOALPHA | SURF_CLIPSOLID;
+ {
+ tx->flags = SURF_DRAWTURB | SURF_LIGHTBOTHSIDES;
+ tx->shader = &Cshader_water;
+ }
}
// just to work around bounds checking when debugging with it (array index out of bounds error thing)
if (name[j] >= 'A' && name[j] <= 'Z')
name[j] += 'a' - 'A';
- tx = loadmodel->textures[i];
+ tx = loadmodel->textures + i;
strcpy(tx->name, name);
tx->width = mtwidth;
tx->height = mtheight;
- tx->texture = NULL;
- tx->glowtexture = NULL;
- tx->fogtexture = NULL;
if (!tx->name[0])
{
if (tx->name[0] == '*')
{
- tx->flags |= (SURF_DRAWTURB | SURF_LIGHTBOTHSIDES);
+ tx->flags |= SURF_DRAWTURB | SURF_LIGHTBOTHSIDES;
// LordHavoc: some turbulent textures should be fullbright and solid
if (!strncmp(tx->name,"*lava",5)
|| !strncmp(tx->name,"*teleport",9)
|| !strncmp(tx->name,"*rift",5)) // Scourge of Armagon texture
- tx->flags |= (SURF_DRAWFULLBRIGHT | SURF_DRAWNOALPHA | SURF_CLIPSOLID);
+ tx->flags |= SURF_DRAWFULLBRIGHT | SURF_DRAWNOALPHA;
+ tx->shader = &Cshader_water;
}
else if (tx->name[0] == 's' && tx->name[1] == 'k' && tx->name[2] == 'y')
- tx->flags |= (SURF_DRAWSKY | SURF_CLIPSOLID);
+ {
+ tx->flags |= SURF_DRAWSKY;
+ tx->shader = &Cshader_sky;
+ }
else
{
tx->flags |= SURF_LIGHTMAP;
- if (!R_TextureHasAlpha(tx->texture))
- tx->flags |= SURF_CLIPSOLID;
+ tx->shader = &Cshader_wall_lightmap;
}
tx->detailtexture = detailtextures[i % NUM_DETAILTEXTURES];
// sequence the animations
for (i = 0;i < m->nummiptex;i++)
{
- tx = loadmodel->textures[i];
+ tx = loadmodel->textures + i;
if (!tx || tx->name[0] != '+' || tx->name[1] == 0 || tx->name[2] == 0)
continue;
if (tx->anim_total[0] || tx->anim_total[1])
for (j = i;j < m->nummiptex;j++)
{
- tx2 = loadmodel->textures[j];
+ tx2 = loadmodel->textures + j;
if (!tx2 || tx2->name[0] != '+' || strcmp (tx2->name+2, tx->name+2))
continue;
if (a != 14)
{
Mem_Free(lightsstring);
- Host_Error("invalid lights file, found %d parameters on line %i, should be 13 parameters (origin[0] origin[1] origin[2] falloff light[0] light[1] light[2] subtract spotdir[0] spotdir[1] spotdir[2] spotcone style)\n", a, n + 1);
+ Host_Error("invalid lights file, found %d parameters on line %i, should be 14 parameters (origin[0] origin[1] origin[2] falloff light[0] light[1] light[2] subtract spotdir[0] spotdir[1] spotdir[2] spotcone distancebias style)\n", a, n + 1);
}
s++;
n++;
}
}
+void Mod_ProcessLightList(void)
+{
+ int i, j, k, *mark;
+ mlight_t *e;
+ msurface_t *surf;
+ float dist;
+ mleaf_t *l;
+ qbyte *pvs;
+ for (i = 0, e = loadmodel->lights;i < loadmodel->numlights;i++, e++)
+ {
+ e->cullradius2 = DotProduct(e->light, e->light) * (1.0f / (8192.0f * 8192.0f)) / (e->falloff * e->falloff) + 4096.0f;
+ if (e->cullradius2 > 4096.0f * 4096.0f)
+ e->cullradius2 = 4096.0f * 4096.0f;
+ e->cullradius = sqrt(e->cullradius2);
+ l = Mod_PointInLeaf(e->origin, loadmodel);
+ if (l->compressed_vis)
+ pvs = Mod_DecompressVis (l->compressed_vis, loadmodel);
+ else
+ pvs = mod_novis;
+ for (j = 0, l = loadmodel->leafs + 1;j < loadmodel->numleafs - 1;j++)
+ {
+ if (pvs[j >> 3] & (1 << (j & 7)))
+ {
+ for (k = 0, mark = l->firstmarksurface;k < l->nummarksurfaces;k++, mark++)
+ {
+ surf = loadmodel->surfaces + *mark;
+ dist = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist;
+ if (surf->flags & SURF_PLANEBACK)
+ dist = -dist;
+ if (dist > 0 && dist < e->cullradius)
+ loadmodel->surfacevisframes[j] = i - 1000000;
+ }
+ }
+ }
+ e->numsurfaces = 0;
+ for (j = 0;j < loadmodel->nummodelsurfaces;j++)
+ if (loadmodel->surfacevisframes[j] == i - 1000000)
+ e->numsurfaces++;
+ e->surfaces = NULL;
+ if (e->numsurfaces > 0)
+ {
+ e->surfaces = Mem_Alloc(loadmodel->mempool, sizeof(msurface_t *) * e->numsurfaces);
+ e->numsurfaces = 0;
+ for (j = 0;j < loadmodel->nummodelsurfaces;j++)
+ if (loadmodel->surfacevisframes[j] == i - 1000000)
+ e->surfaces[e->numsurfaces++] = loadmodel->surfaces + loadmodel->firstmodelsurface + j;
+ }
+ }
+}
+
/*
=================
}
// used only for HalfLife maps
-void Mod_ParseWadsFromEntityLump(char *data)
+void Mod_ParseWadsFromEntityLump(const char *data)
{
char key[128], value[4096];
char wadname[128];
int i, j, k;
if (!data)
return;
- data = COM_Parse(data);
- if (!data)
+ if (!COM_ParseToken(&data))
return; // error
if (com_token[0] != '{')
return; // error
while (1)
{
- data = COM_Parse(data);
- if (!data)
+ if (!COM_ParseToken(&data))
return; // error
if (com_token[0] == '}')
break; // end of worldspawn
strcpy(key, com_token);
while (key[strlen(key)-1] == ' ') // remove trailing spaces
key[strlen(key)-1] = 0;
- data = COM_Parse(data);
- if (!data)
+ if (!COM_ParseToken(&data))
return; // error
strcpy(value, com_token);
if (!strcmp("wad", key)) // for HalfLife maps
if ((unsigned int) miptex >= (unsigned int) loadmodel->numtextures)
Con_Printf ("error in model \"%s\": invalid miptex index %i (of %i)\n", loadmodel->name, miptex, loadmodel->numtextures);
else
- out->texture = loadmodel->textures[miptex];
+ out->texture = loadmodel->textures + miptex;
}
- if (out->texture == NULL)
+ if (out->flags & TEX_SPECIAL)
{
- // choose either the liquid notexture, or the normal notexture
- if (out->flags & TEX_SPECIAL)
- out->texture = loadmodel->textures[loadmodel->numtextures - 1];
- else
- out->texture = loadmodel->textures[loadmodel->numtextures - 2];
+ // if texture chosen is NULL or the shader needs a lightmap,
+ // force to notexture water shader
+ if (out->texture == NULL || out->texture->shader->flags & SHADERFLAGS_NEEDLIGHTMAP)
+ out->texture = loadmodel->textures + (loadmodel->numtextures - 1);
+ }
+ else
+ {
+ // if texture chosen is NULL, force to notexture
+ if (out->texture == NULL)
+ out->texture = loadmodel->textures + (loadmodel->numtextures - 2);
}
}
}
void Mod_GenerateWallMesh (msurface_t *surf, int vertexonly)
{
- int i, iu, iv, *index, smax, tmax;
- float *in, s, t, u, v, ubase, vbase, uscale, vscale;
+ int i, iu, iv, *index, *n, smax, tmax;
+ float *in, s, t, u, v, ubase, vbase, uscale, vscale, normal[3];
surfmesh_t *mesh;
smax = surf->extents[0] >> 4;
vscale = (vscale - vbase) * 16.0 / ((surf->extents[1] & ~15) + 16);
}
- surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + (surf->poly_numverts - 2) * sizeof(int[3]) + surf->poly_numverts * (4 + 2 + 2 + 2 + 1) * sizeof(float));
+ surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + (surf->poly_numverts - 2) * sizeof(int[6]) + surf->poly_numverts * (4 + 2 + 2 + 2 + 1 + 3) * sizeof(float));
mesh->numverts = surf->poly_numverts;
mesh->numtriangles = surf->poly_numverts - 2;
mesh->verts = (float *)(mesh + 1);
mesh->ab = mesh->uv + mesh->numverts * 2;
mesh->lightmapoffsets = (int *)(mesh->ab + mesh->numverts * 2);
mesh->index = mesh->lightmapoffsets + mesh->numverts;
+ mesh->triangleneighbors = mesh->index + mesh->numtriangles * 3;
+ mesh->normals = (float *)(mesh->triangleneighbors + mesh->numtriangles * 3);
index = mesh->index;
+ n = mesh->triangleneighbors;
for (i = 0;i < mesh->numtriangles;i++)
{
*index++ = 0;
*index++ = i + 1;
*index++ = i + 2;
+ *n++ = i - 1;
+ *n++ = -1;
+ *n++ = i + 1;
}
+ VectorCopy(surf->plane->normal, normal);
+ if (surf->flags & SURF_PLANEBACK)
+ VectorNegate(normal, normal);
for (i = 0, in = surf->poly_verts;i < mesh->numverts;i++, in += 3)
{
s = DotProduct (in, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3];
t = DotProduct (in, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3];
- u = (s + 8 - surf->texturemins[0]) * (1.0 / 16.0) * uscale + ubase;
- v = (t + 8 - surf->texturemins[1]) * (1.0 / 16.0) * vscale + vbase;
+ u = (s + 8 - surf->texturemins[0]) * (1.0 / 16.0);
+ v = (t + 8 - surf->texturemins[1]) * (1.0 / 16.0);
// LordHavoc: calc lightmap data offset for vertex lighting to use
iu = (int) u;
iv = (int) v;
iu = bound(0, iu, smax);
iv = bound(0, iv, tmax);
+ u = u * uscale + ubase;
+ v = v * vscale + vbase;
mesh->verts[i * 4 + 0] = in[0];
mesh->verts[i * 4 + 1] = in[1];
mesh->ab[i * 2 + 0] = s * (1.0f / 16.0f);
mesh->ab[i * 2 + 1] = t * (1.0f / 16.0f);
mesh->lightmapoffsets[i] = ((iv * (smax+1) + iu) * 3);
+ mesh->normals[i * 3 + 0] = normal[0];
+ mesh->normals[i * 3 + 1] = normal[1];
+ mesh->normals[i * 3 + 2] = normal[2];
}
}
void Mod_GenerateVertexMesh (msurface_t *surf)
{
- int i, *index;
- float *in, s, t;
+ int i, *index, *n;
+ float *in, s, t, normal[3];
surfmesh_t *mesh;
surf->lightmaptexturestride = 0;
surf->lightmaptexture = NULL;
- surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + (surf->poly_numverts - 2) * sizeof(int[3]) + surf->poly_numverts * (4 + 2 + 2) * sizeof(float));
+ surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + (surf->poly_numverts - 2) * sizeof(int[6]) + surf->poly_numverts * (4 + 2 + 2 + 3) * sizeof(float));
mesh->numverts = surf->poly_numverts;
mesh->numtriangles = surf->poly_numverts - 2;
mesh->verts = (float *)(mesh + 1);
mesh->st = mesh->verts + mesh->numverts * 4;
mesh->ab = mesh->st + mesh->numverts * 2;
mesh->index = (int *)(mesh->ab + mesh->numverts * 2);
+ mesh->triangleneighbors = mesh->index + mesh->numtriangles * 3;
+ mesh->normals = (float *)(mesh->triangleneighbors + mesh->numtriangles * 3);
index = mesh->index;
+ n = mesh->triangleneighbors;
for (i = 0;i < mesh->numtriangles;i++)
{
*index++ = 0;
*index++ = i + 1;
*index++ = i + 2;
+ *n++ = -1;
+ *n++ = -1;
+ *n++ = i + 1;
}
+ VectorCopy(surf->plane->normal, normal);
+ if (surf->flags & SURF_PLANEBACK)
+ VectorNegate(normal, normal);
for (i = 0, in = surf->poly_verts;i < mesh->numverts;i++, in += 3)
{
s = (DotProduct (in, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]);
mesh->st[i * 2 + 1] = t / surf->texinfo->texture->height;
mesh->ab[i * 2 + 0] = s * (1.0f / 16.0f);
mesh->ab[i * 2 + 1] = t * (1.0f / 16.0f);
+ mesh->normals[i * 3 + 0] = normal[0];
+ mesh->normals[i * 3 + 1] = normal[1];
+ mesh->normals[i * 3 + 2] = normal[2];
}
}
void Mod_GenerateSurfacePolygon (msurface_t *surf)
{
int i, lindex;
- float *vec, *vert, mins[3], maxs[3];
+ float *vec, *vert, mins[3], maxs[3], temp[3], dist;
// convert edges back to a normal polygon
surf->poly_numverts = surf->numedges;
surf->poly_center[0] = (mins[0] + maxs[0]) * 0.5f;
surf->poly_center[1] = (mins[1] + maxs[1]) * 0.5f;
surf->poly_center[2] = (mins[2] + maxs[2]) * 0.5f;
+ surf->poly_radius2 = 0;
+ vert = surf->poly_verts;
+ for (i = 0;i < surf->poly_numverts;i++)
+ {
+ VectorSubtract(vert, surf->poly_center, temp);
+ dist = DotProduct(temp, temp);
+ if (surf->poly_radius2 < dist)
+ surf->poly_radius2 = dist;
+ vert += 3;
+ }
+ surf->poly_radius = sqrt(surf->poly_radius2);
}
/*
loadmodel->surfaces = out;
loadmodel->numsurfaces = count;
+ loadmodel->surfacevisframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
+ loadmodel->surfacepvsframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
for (surfnum = 0;surfnum < count;surfnum++, in++, out++)
{
+ out->number = surfnum;
// FIXME: validate edges, texinfo, etc?
out->firstedge = LittleLong(in->firstedge);
out->numedges = LittleShort(in->numedges);
// force lightmap upload on first time seeing the surface
out->cached_dlight = true;
- out->cached_ambient = -1000;
- out->cached_lightscalebit = -1000;
CalcSurfaceExtents (out);
out->samples = loadmodel->lightdata + (i * 3);
Mod_GenerateSurfacePolygon(out);
-
- if (out->texinfo->texture->flags & SURF_DRAWSKY)
+ if (out->texinfo->texture->shader == &Cshader_wall_lightmap)
{
- out->shader = &Cshader_sky;
- out->samples = NULL;
- Mod_GenerateVertexMesh (out);
- }
- else if (out->texinfo->texture->flags & SURF_DRAWTURB)
- {
- out->shader = &Cshader_water;
- out->samples = NULL;
- Mod_GenerateVertexMesh (out);
+ if ((out->extents[0] >> 4) + 1 > (256) || (out->extents[1] >> 4) + 1 > (256))
+ Host_Error ("Bad surface extents");
+ Mod_GenerateWallMesh (out, false);
+ // stainmap for permanent marks on walls
+ out->stainsamples = Mem_Alloc(loadmodel->mempool, ssize * tsize * 3);
+ // clear to white
+ memset(out->stainsamples, 255, ssize * tsize * 3);
}
else
- {
- if (!R_TextureHasAlpha(out->texinfo->texture->texture))
- out->flags |= SURF_CLIPSOLID;
- if (out->texinfo->flags & TEX_SPECIAL)
- {
- // qbsp couldn't find the texture for this surface, but it was either turb or sky... assume turb
- out->shader = &Cshader_water;
- out->shader = &Cshader_water;
- out->samples = NULL;
- Mod_GenerateVertexMesh (out);
- }
- else if ((out->extents[0] >> 4) + 1 > (256) || (out->extents[1] >> 4) + 1 > (256))
- {
- Con_Printf ("Bad surface extents, converting to fullbright polygon");
- out->shader = &Cshader_wall_fullbright;
- out->samples = NULL;
- Mod_GenerateVertexMesh(out);
- }
- else
- {
- // stainmap for permanent marks on walls
- out->stainsamples = Mem_Alloc(loadmodel->mempool, ssize * tsize * 3);
- // clear to white
- memset(out->stainsamples, 255, ssize * tsize * 3);
- if (out->extents[0] < r_vertexsurfacesthreshold.integer && out->extents[1] < r_vertexsurfacesthreshold.integer)
- {
- out->shader = &Cshader_wall_vertex;
- Mod_GenerateWallMesh (out, true);
- }
- else
- {
- out->shader = &Cshader_wall_lightmap;
- Mod_GenerateWallMesh (out, false);
- }
- }
- }
+ Mod_GenerateVertexMesh (out);
}
}
*/
static void Mod_LoadMarksurfaces (lump_t *l)
{
- int i, j;
- short *in;
+ int i, j;
+ short *in;
in = (void *)(mod_base + l->fileofs);
if (l->filelen % sizeof(*in))
Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
loadmodel->nummarksurfaces = l->filelen / sizeof(*in);
- loadmodel->marksurfaces = Mem_Alloc(loadmodel->mempool, loadmodel->nummarksurfaces * sizeof(msurface_t *));
+ loadmodel->marksurfaces = Mem_Alloc(loadmodel->mempool, loadmodel->nummarksurfaces * sizeof(int));
for (i = 0;i < loadmodel->nummarksurfaces;i++)
{
j = (unsigned) LittleShort(in[i]);
if (j >= loadmodel->numsurfaces)
Host_Error ("Mod_ParseMarksurfaces: bad surface number");
- loadmodel->marksurfaces[i] = loadmodel->surfaces + j;
+ loadmodel->marksurfaces[i] = j;
}
}
Mod_LoadBrushModel
=================
*/
+extern void R_DrawBrushModelFakeShadow (entity_render_t *ent);
void Mod_LoadBrushModel (model_t *mod, void *buffer)
{
int i, j;
dmodel_t *bm;
mempool_t *mainmempool;
char *loadname;
+ model_t *originalloadmodel;
mod->type = mod_brush;
loadname = mod->name;
Mod_LoadLightList ();
+ originalloadmodel = loadmodel;
//
// set up the submodels (FIXME: this is confusing)
for (j = 0, surf = &mod->surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surf++)
{
// we only need to have a drawsky function if it is used (usually only on world model)
- if (surf->shader == &Cshader_sky)
+ if (surf->texinfo->texture->shader == &Cshader_sky)
mod->DrawSky = R_DrawBrushModelSky;
for (k = 0;k < surf->numedges;k++)
{
mod->yawmaxs[2] = mod->normalmaxs[2];
mod->rotatedmins[0] = mod->rotatedmins[1] = mod->rotatedmins[2] = -modelradius;
mod->rotatedmaxs[0] = mod->rotatedmaxs[1] = mod->rotatedmaxs[2] = modelradius;
+ mod->radius = modelradius;
+ mod->radius2 = modelradius * modelradius;
// LordHavoc: check for empty submodels (lacrima.bsp has such a glitch)
if (mod->normalmins[0] > mod->normalmaxs[0] || mod->normalmins[1] > mod->normalmaxs[1] || mod->normalmins[2] > mod->normalmaxs[2])
{
VectorClear(mod->yawmaxs);
VectorClear(mod->rotatedmins);
VectorClear(mod->rotatedmaxs);
+ mod->radius = 0;
+ mod->radius2 = 0;
}
mod->numleafs = bm->visleafs;
mod->Draw = R_DrawBrushModelNormal;
- mod->DrawShadow = NULL;
+ mod->DrawFakeShadow = R_DrawBrushModelFakeShadow;
// LordHavoc: only register submodels if it is the world
// (prevents bsp models from replacing world submodels)
mod = loadmodel;
}
}
+
+ loadmodel = originalloadmodel;
+ Mod_ProcessLightList ();
}