double t1, t2;
// variables that need to be stored on the stack when recursing
- dclipnode_t *node;
+ mclipnode_t *node;
int side;
double midf, mid[3];
rhc.hull = &model->brushq1.hulls[0]; // 0x0x0
else if (model->brush.ismcbsp)
{
- if (boxsize[2] < 48) // pick the nearest of 40 or 56
- rhc.hull = &model->brushq1.hulls[2]; // 16x16x40
- else
- rhc.hull = &model->brushq1.hulls[1]; // 16x16x56
+ int i;
+ float vdist, dist;
+ int vdisti = 0;
+
+ vdist = 0; // shut up compiler warning
+
+ // find the closest hull size (this algorithm probably sucks, a qc field to override it might be in order...)
+ for (i = 1; i < model->brushq1.numhulls; i++)
+ {
+ dist = fabs(model->brushq1.hulls[i].clip_size[0] - boxsize[0]) +
+ fabs(model->brushq1.hulls[i].clip_size[1] - boxsize[1]) +
+ fabs(model->brushq1.hulls[i].clip_size[2] - boxsize[2]) * 0.25;
+
+ if (!vdisti || dist < vdist)
+ {
+ vdisti = i;
+ vdist = dist;
+ }
+ }
+ rhc.hull = &model->brushq1.hulls[vdisti];
}
else if (model->brush.ishlbsp)
{
#else
RecursiveHullCheckTraceInfo_t rhc;
static hull_t box_hull;
- static dclipnode_t box_clipnodes[6];
+ static mclipnode_t box_clipnodes[6];
static mplane_t box_planes[6];
// fill in a default trace
memset(&rhc, 0, sizeof(rhc));
// if sky isn't the right size, just use it as a solid layer
if (width != 256 || height != 128)
{
- loadmodel->brush.solidskytexture = R_LoadTexture2D(loadmodel->texturepool, "sky_solidtexture", width, height, src, bytesperpixel == 4 ? TEXTYPE_RGBA : TEXTYPE_PALETTE, TEXF_PRECACHE | (gl_texturecompression_sky.integer ? TEXF_COMPRESS : 0), bytesperpixel == 1 ? palette_complete : NULL);
+ loadmodel->brush.solidskytexture = R_LoadTexture2D(loadmodel->texturepool, "sky_solidtexture", width, height, src, bytesperpixel == 4 ? TEXTYPE_RGBA : TEXTYPE_PALETTE, TEXF_PRECACHE, bytesperpixel == 1 ? palette_complete : NULL);
loadmodel->brush.alphaskytexture = NULL;
return;
}
}
}
- loadmodel->brush.solidskytexture = R_LoadTexture2D(loadmodel->texturepool, "sky_solidtexture", 128, 128, (unsigned char *) solidpixels, TEXTYPE_RGBA, TEXF_PRECACHE | (gl_texturecompression_sky.integer ? TEXF_COMPRESS : 0), NULL);
- loadmodel->brush.alphaskytexture = R_LoadTexture2D(loadmodel->texturepool, "sky_alphatexture", 128, 128, (unsigned char *) alphapixels, TEXTYPE_RGBA, TEXF_ALPHA | TEXF_PRECACHE | (gl_texturecompression_sky.integer ? TEXF_COMPRESS : 0), NULL);
+ loadmodel->brush.solidskytexture = R_LoadTexture2D(loadmodel->texturepool, "sky_solidtexture", 128, 128, (unsigned char *) solidpixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
+ loadmodel->brush.alphaskytexture = R_LoadTexture2D(loadmodel->texturepool, "sky_alphatexture", 128, 128, (unsigned char *) alphapixels, TEXTYPE_RGBA, TEXF_ALPHA | TEXF_PRECACHE, NULL);
}
static void Mod_Q1BSP_LoadTextures(lump_t *l)
{
tx->width = image_width;
tx->height = image_height;
- skinframe = R_SkinFrame_LoadInternal(tx->name, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE | (r_picmipworld.integer ? TEXF_PICMIP : 0) | TEXF_COMPRESS, false, false, pixels, image_width, image_height, 32, NULL, NULL);
+ skinframe = R_SkinFrame_LoadInternal(tx->name, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE | (r_picmipworld.integer ? TEXF_PICMIP : 0), false, false, pixels, image_width, image_height, 32, NULL, NULL);
}
if (freepixels)
Mem_Free(freepixels);
}
else if (mtdata) // texture included
- skinframe = R_SkinFrame_LoadInternal(tx->name, TEXF_MIPMAP | TEXF_PRECACHE | (r_picmipworld.integer ? TEXF_PICMIP : 0) | TEXF_COMPRESS, false, r_fullbrights.integer, mtdata, tx->width, tx->height, 8, NULL, NULL);
+ skinframe = R_SkinFrame_LoadInternal(tx->name, TEXF_MIPMAP | TEXF_PRECACHE | (r_picmipworld.integer ? TEXF_PICMIP : 0), false, r_fullbrights.integer, mtdata, tx->width, tx->height, 8, NULL, NULL);
}
// if skinframe is still NULL the "missing" texture will be used
if (skinframe)
if (strncmp(tx->name,"*lava",5)
&& strncmp(tx->name,"*teleport",9)
&& strncmp(tx->name,"*rift",5)) // Scourge of Armagon texture
- tx->basematerialflags |= MATERIALFLAG_WATERALPHA | MATERIALFLAG_NOSHADOW;
+ {
+ tx->basematerialflags |= MATERIALFLAG_WATERALPHA | MATERIALFLAG_NOSHADOW | MATERIALFLAG_WATERSHADER;
+ VectorSet(tx->reflectcolor, 1, 1, 1);
+ VectorSet(tx->refractcolor, 1, 1, 1);
+ tx->refractmin = 0;
+ tx->refractmax = 1;
+ tx->refractfactor = 1;
+ }
tx->basematerialflags |= MATERIALFLAG_WATER | MATERIALFLAG_LIGHTBOTHSIDES | MATERIALFLAG_NOSHADOW;
}
else if (!strncmp(tx->name, "sky", 3))
int i, j, k;
if (!data)
return;
- if (!COM_ParseToken_Simple(&data, false))
+ if (!COM_ParseToken_Simple(&data, false, false))
return; // error
if (com_token[0] != '{')
return; // error
while (1)
{
- if (!COM_ParseToken_Simple(&data, false))
+ if (!COM_ParseToken_Simple(&data, false, false))
return; // error
if (com_token[0] == '}')
break; // end of worldspawn
strlcpy(key, com_token, sizeof(key));
while (key[strlen(key)-1] == ' ') // remove trailing spaces
key[strlen(key)-1] = 0;
- if (!COM_ParseToken_Simple(&data, false))
+ if (!COM_ParseToken_Simple(&data, false, false))
return; // error
dpsnprintf(value, sizeof(value), "%s", com_token);
if (!strcmp("wad", key)) // for HalfLife maps
totaltris = 0;
for (surfacenum = 0, in = (dface_t *)(mod_base + l->fileofs);surfacenum < count;surfacenum++, in++)
{
- numedges = LittleShort(in->numedges);
+ numedges = (unsigned short)LittleShort(in->numedges);
totalverts += numedges;
totaltris += numedges - 2;
}
// FIXME: validate edges, texinfo, etc?
firstedge = LittleLong(in->firstedge);
- numedges = LittleShort(in->numedges);
+ numedges = (unsigned short)LittleShort(in->numedges);
if ((unsigned int) firstedge > (unsigned int) loadmodel->brushq1.numsurfedges || (unsigned int) numedges > (unsigned int) loadmodel->brushq1.numsurfedges || (unsigned int) firstedge + (unsigned int) numedges > (unsigned int) loadmodel->brushq1.numsurfedges)
Host_Error("Mod_Q1BSP_LoadFaces: invalid edge range (firstedge %i, numedges %i, model edges %i)", firstedge, numedges, loadmodel->brushq1.numsurfedges);
- i = LittleShort(in->texinfo);
+ i = (unsigned short)LittleShort(in->texinfo);
if ((unsigned int) i >= (unsigned int) loadmodel->brushq1.numtexinfo)
Host_Error("Mod_Q1BSP_LoadFaces: invalid texinfo index %i(model has %i texinfos)", i, loadmodel->brushq1.numtexinfo);
surface->lightmapinfo->texinfo = loadmodel->brushq1.texinfo + i;
surface->texture = surface->lightmapinfo->texinfo->texture;
- planenum = LittleShort(in->planenum);
+ planenum = (unsigned short)LittleShort(in->planenum);
if ((unsigned int) planenum >= (unsigned int) loadmodel->brush.num_planes)
Host_Error("Mod_Q1BSP_LoadFaces: invalid plane index %i (model has %i planes)", planenum, loadmodel->brush.num_planes);
p = LittleLong(in->planenum);
out->plane = loadmodel->brush.data_planes + p;
- out->firstsurface = LittleShort(in->firstface);
- out->numsurfaces = LittleShort(in->numfaces);
+ out->firstsurface = (unsigned short)LittleShort(in->firstface);
+ out->numsurfaces = (unsigned short)LittleShort(in->numfaces);
for (j=0 ; j<2 ; j++)
{
- p = LittleShort(in->children[j]);
- if (p >= 0)
- out->children[j] = loadmodel->brush.data_nodes + p;
+ // LordHavoc: this code supports broken bsp files produced by
+ // arguire qbsp which can produce more than 32768 nodes, any value
+ // below count is assumed to be a node number, any other value is
+ // assumed to be a leaf number
+ p = (unsigned short)LittleShort(in->children[j]);
+ if (p < count)
+ {
+ if (p < loadmodel->brush.num_nodes)
+ out->children[j] = loadmodel->brush.data_nodes + p;
+ else
+ {
+ Con_Printf("Mod_Q1BSP_LoadNodes: invalid node index %i (file has only %i nodes)\n", p, loadmodel->brush.num_nodes);
+ // map it to the solid leaf
+ out->children[j] = (mnode_t *)loadmodel->brush.data_leafs;
+ }
+ }
else
- out->children[j] = (mnode_t *)(loadmodel->brush.data_leafs + (-1 - p));
+ {
+ // note this uses 65535 intentionally, -1 is leaf 0
+ p = 65535 - p;
+ if (p < loadmodel->brush.num_leafs)
+ out->children[j] = (mnode_t *)(loadmodel->brush.data_leafs + p);
+ else
+ {
+ Con_Printf("Mod_Q1BSP_LoadNodes: invalid leaf index %i (file has only %i leafs)\n", p, loadmodel->brush.num_leafs);
+ // map it to the solid leaf
+ out->children[j] = (mnode_t *)loadmodel->brush.data_leafs;
+ }
+ }
}
}
out->contents = LittleLong(in->contents);
- out->firstleafsurface = loadmodel->brush.data_leafsurfaces + LittleShort(in->firstmarksurface);
- out->numleafsurfaces = LittleShort(in->nummarksurfaces);
- if (out->firstleafsurface < 0 || LittleShort(in->firstmarksurface) + out->numleafsurfaces > loadmodel->brush.num_leafsurfaces)
+ out->firstleafsurface = loadmodel->brush.data_leafsurfaces + (unsigned short)LittleShort(in->firstmarksurface);
+ out->numleafsurfaces = (unsigned short)LittleShort(in->nummarksurfaces);
+ if (out->firstleafsurface < 0 || (unsigned short)LittleShort(in->firstmarksurface) + out->numleafsurfaces > loadmodel->brush.num_leafsurfaces)
{
Con_Printf("Mod_Q1BSP_LoadLeafs: invalid leafsurface range %i:%i outside range %i:%i\n", (int)(out->firstleafsurface - loadmodel->brush.data_leafsurfaces), (int)(out->firstleafsurface + out->numleafsurfaces - loadmodel->brush.data_leafsurfaces), 0, loadmodel->brush.num_leafsurfaces);
out->firstleafsurface = NULL;
static void Mod_Q1BSP_LoadClipnodes(lump_t *l, hullinfo_t *hullinfo)
{
- dclipnode_t *in, *out;
+ dclipnode_t *in;
+ mclipnode_t *out;
int i, count;
hull_t *hull;
if (l->filelen % sizeof(*in))
Host_Error("Mod_Q1BSP_LoadClipnodes: funny lump size in %s",loadmodel->name);
count = l->filelen / sizeof(*in);
- out = (dclipnode_t *)Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
+ out = (mclipnode_t *)Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
loadmodel->brushq1.clipnodes = out;
loadmodel->brushq1.numclipnodes = count;
for (i=0 ; i<count ; i++, out++, in++)
{
out->planenum = LittleLong(in->planenum);
- out->children[0] = LittleShort(in->children[0]);
- out->children[1] = LittleShort(in->children[1]);
+ // LordHavoc: this code supports arguire qbsp's broken clipnodes indices (more than 32768 clipnodes), values above count are assumed to be contents values
+ out->children[0] = (unsigned short)LittleShort(in->children[0]);
+ out->children[1] = (unsigned short)LittleShort(in->children[1]);
+ if (out->children[0] >= count)
+ out->children[0] -= 65536;
+ if (out->children[1] >= count)
+ out->children[1] -= 65536;
if (out->planenum < 0 || out->planenum >= loadmodel->brush.num_planes)
Host_Error("Corrupt clipping hull(out of range planenum)");
- if (out->children[0] >= count || out->children[1] >= count)
- Host_Error("Corrupt clipping hull(out of range child)");
}
}
static void Mod_Q1BSP_MakeHull0(void)
{
mnode_t *in;
- dclipnode_t *out;
+ mclipnode_t *out;
int i;
hull_t *hull;
hull = &loadmodel->brushq1.hulls[0];
in = loadmodel->brush.data_nodes;
- out = (dclipnode_t *)Mem_Alloc(loadmodel->mempool, loadmodel->brush.num_nodes * sizeof(dclipnode_t));
+ out = (mclipnode_t *)Mem_Alloc(loadmodel->mempool, loadmodel->brush.num_nodes * sizeof(*out));
hull->clipnodes = out;
hull->firstclipnode = 0;
for (i = 0;i < loadmodel->brush.num_leafsurfaces;i++)
{
- j = (unsigned) LittleShort(in[i]);
+ j = (unsigned short) LittleShort(in[i]);
if (j >= loadmodel->num_surfaces)
Host_Error("Mod_Q1BSP_LoadLeaffaces: bad surface number");
loadmodel->brush.data_leafsurfaces[i] = j;
if (!maptext)
return;
text = maptext;
- if (!COM_ParseToken_Simple(&data, false))
+ if (!COM_ParseToken_Simple(&data, false, false))
return; // error
submodel = 0;
for (;;)
{
- if (!COM_ParseToken_Simple(&data, false))
+ if (!COM_ParseToken_Simple(&data, false, false))
break;
if (com_token[0] != '{')
return; // error
brushes = Mem_Alloc(loadmodel->mempool, maxbrushes * sizeof(mbrush_t));
for (;;)
{
- if (!COM_ParseToken_Simple(&data, false))
+ if (!COM_ParseToken_Simple(&data, false, false))
return; // error
if (com_token[0] == '}')
break; // end of entity
}
for (;;)
{
- if (!COM_ParseToken_Simple(&data, false))
+ if (!COM_ParseToken_Simple(&data, false, false))
return; // error
if (com_token[0] == '}')
break; // end of brush
// FIXME: support hl .map format
for (pointnum = 0;pointnum < 3;pointnum++)
{
- COM_ParseToken_Simple(&data, false);
+ COM_ParseToken_Simple(&data, false, false);
for (componentnum = 0;componentnum < 3;componentnum++)
{
- COM_ParseToken_Simple(&data, false);
+ COM_ParseToken_Simple(&data, false, false);
point[pointnum][componentnum] = atof(com_token);
}
- COM_ParseToken_Simple(&data, false);
+ COM_ParseToken_Simple(&data, false, false);
}
- COM_ParseToken_Simple(&data, false);
+ COM_ParseToken_Simple(&data, false, false);
strlcpy(facetexture, com_token, sizeof(facetexture));
- COM_ParseToken_Simple(&data, false);
+ COM_ParseToken_Simple(&data, false, false);
//scroll_s = atof(com_token);
- COM_ParseToken_Simple(&data, false);
+ COM_ParseToken_Simple(&data, false, false);
//scroll_t = atof(com_token);
- COM_ParseToken_Simple(&data, false);
+ COM_ParseToken_Simple(&data, false, false);
//rotate = atof(com_token);
- COM_ParseToken_Simple(&data, false);
+ COM_ParseToken_Simple(&data, false, false);
//scale_s = atof(com_token);
- COM_ParseToken_Simple(&data, false);
+ COM_ParseToken_Simple(&data, false, false);
//scale_t = atof(com_token);
TriangleNormal(point[0], point[1], point[2], planenormal);
VectorNormalizeDouble(planenormal);
//Calculates a PVS that is the inclusive or of all leafs within radius pixels
//of the given point.
-static int Mod_Q1BSP_FatPVS(model_t *model, const vec3_t org, vec_t radius, unsigned char *pvsbuffer, int pvsbufferlength)
+static int Mod_Q1BSP_FatPVS(model_t *model, const vec3_t org, vec_t radius, unsigned char *pvsbuffer, int pvsbufferlength, qboolean merge)
{
int bytes = model->brush.num_pvsclusterbytes;
bytes = min(bytes, pvsbufferlength);
memset(pvsbuffer, 0xFF, bytes);
return bytes;
}
- memset(pvsbuffer, 0, bytes);
+ if (!merge)
+ memset(pvsbuffer, 0, bytes);
Mod_Q1BSP_FatPVS_RecursiveBSPNode(model, org, radius, pvsbuffer, bytes, model->brush.data_nodes);
return bytes;
}
Host_Error("Mod_Q1BSP_Load: %s has wrong version number(%i should be %i)", mod->name, i, MCBSPVERSION);
// read hull info
- hullinfo.numhulls = LittleLong(*(int*)index); index += 4;
+ hullinfo.numhulls = SB_ReadInt (&index);
hullinfo.filehulls = hullinfo.numhulls;
+ mod->brushq1.numhulls = hullinfo.numhulls;
+
VectorClear (hullinfo.hullsizes[0][0]);
VectorClear (hullinfo.hullsizes[0][1]);
for (i = 1; i < hullinfo.numhulls; i++)
hullinfo.numhulls = 4;
hullinfo.filehulls = 4;
+ mod->brushq1.numhulls = 4;
VectorSet (hullinfo.hullsizes[1][0], -16, -16, -36);
VectorSet (hullinfo.hullsizes[1][1], 16, 16, 36);
VectorSet (hullinfo.hullsizes[2][0], -32, -32, -32);
{
hullinfo.numhulls = 3;
hullinfo.filehulls = 4;
+ mod->brushq1.numhulls = 3;
VectorSet (hullinfo.hullsizes[1][0], -16, -16, -24);
VectorSet (hullinfo.hullsizes[1][1], 16, 16, 32);
VectorSet (hullinfo.hullsizes[2][0], -32, -32, -24);
for (j = 0;j < mod->nummodelsurfaces;j++)
mod->surfacelist[j] = mod->firstmodelsurface + j;
- // this gets altered below if sky is used
+ // this gets altered below if sky or water is used
mod->DrawSky = NULL;
+ mod->DrawAddWaterPlanes = NULL;
mod->Draw = R_Q1BSP_Draw;
mod->DrawDepth = R_Q1BSP_DrawDepth;
+ mod->DrawDebug = R_Q1BSP_DrawDebug;
mod->GetLightInfo = R_Q1BSP_GetLightInfo;
mod->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
mod->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
// we only need to have a drawsky function if it is used(usually only on world model)
if (surface->texture->basematerialflags & MATERIALFLAG_SKY)
mod->DrawSky = R_Q1BSP_DrawSky;
+ if (surface->texture->basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
+ mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
// calculate bounding shapes
for (k = 0, vec = (loadmodel->surfmesh.data_vertex3f + 3 * surface->num_firstvertex);k < surface->num_vertices;k++, vec += 3)
{
memcpy(loadmodel->brush.entities, mod_base + l->fileofs, l->filelen);
data = loadmodel->brush.entities;
// some Q3 maps override the lightgrid_cellsize with a worldspawn key
- if (data && COM_ParseToken_Simple(&data, false) && com_token[0] == '{')
+ if (data && COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{')
{
while (1)
{
- if (!COM_ParseToken_Simple(&data, false))
+ if (!COM_ParseToken_Simple(&data, false, false))
break; // error
if (com_token[0] == '}')
break; // end of worldspawn
strlcpy(key, com_token, sizeof(key));
while (key[strlen(key)-1] == ' ') // remove trailing spaces
key[strlen(key)-1] = 0;
- if (!COM_ParseToken_Simple(&data, false))
+ if (!COM_ParseToken_Simple(&data, false, false))
break; // error
strlcpy(value, com_token, sizeof(value));
if (!strcmp("gridsize", key))
mod->brush.PointInLeaf = Mod_Q1BSP_PointInLeaf;
mod->Draw = R_Q1BSP_Draw;
mod->DrawDepth = R_Q1BSP_DrawDepth;
+ mod->DrawDebug = R_Q1BSP_DrawDebug;
mod->GetLightInfo = R_Q1BSP_GetLightInfo;
mod->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
mod->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
mod->DrawLight = R_Q1BSP_DrawLight;
+ mod->DrawAddWaterPlanes = NULL;
mod_base = (unsigned char *)header;
mod->radius2 = modelradius * modelradius;
for (j = 0;j < mod->nummodelsurfaces;j++)
- if (mod->data_surfaces[j + mod->firstmodelsurface].texture->surfaceflags & Q3SURFACEFLAG_SKY)
+ if (mod->data_surfaces[j + mod->firstmodelsurface].texture->basematerialflags & MATERIALFLAG_SKY)
break;
if (j < mod->nummodelsurfaces)
mod->DrawSky = R_Q1BSP_DrawSky;
else
mod->DrawSky = NULL;
+
+ for (j = 0;j < mod->nummodelsurfaces;j++)
+ if (mod->data_surfaces[j + mod->firstmodelsurface].texture->basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
+ break;
+ if (j < mod->nummodelsurfaces)
+ mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
+ else
+ mod->DrawAddWaterPlanes = NULL;
}
}