cvar_t mod_q2bsp_littransparentsurfaces = {CF_CLIENT, "mod_q2bsp_littransparentsurfaces", "0", "allows lighting on rain in 3v3gloom3 and other cases of transparent surfaces that have lightmaps that were ignored by quake2"};
cvar_t mod_q1bsp_polygoncollisions = {CF_CLIENT | CF_SERVER, "mod_q1bsp_polygoncollisions", "0", "disables use of precomputed cliphulls and instead collides with polygons (uses Bounding Interval Hierarchy optimizations)"};
+cvar_t mod_q1bsp_traceoutofsolid = {CF_SHARED, "mod_q1bsp_traceoutofsolid", "1", "enables tracebox to move an entity that's stuck in solid brushwork out to empty space, 1 matches FTEQW and QSS and is required by many community maps (items/monsters will be missing otherwise), 0 matches old versions of DP and the original Quake engine (if your map or QC needs 0 it's buggy)"};
cvar_t mod_q1bsp_zero_hullsize_cutoff = {CF_CLIENT | CF_SERVER, "mod_q1bsp_zero_hullsize_cutoff", "3", "bboxes with an X dimension smaller than this will use the smallest cliphull (0x0x0) instead of being rounded up to the player cliphull (32x32x56) in Q1BSP, or crouching player (32x32x36) in HLBSP"};
-cvar_t mod_bsp_portalize = {CF_CLIENT, "mod_bsp_portalize", "1", "enables portal generation from BSP tree (may take several seconds per map), used by r_drawportals, r_useportalculling, r_shadow_realtime_dlight_portalculling, r_shadow_realtime_world_compileportalculling"};
+cvar_t mod_bsp_portalize = {CF_CLIENT, "mod_bsp_portalize", "0", "enables portal generation from BSP tree (takes a minute or more and GBs of memory when loading a complex map), used by r_drawportals, r_useportalculling, r_shadow_realtime_dlight_portalculling, r_shadow_realtime_world_compileportalculling"};
cvar_t mod_recalculatenodeboxes = {CF_CLIENT | CF_SERVER, "mod_recalculatenodeboxes", "1", "enables use of generated node bounding boxes based on BSP tree portal reconstruction, rather than the node boxes supplied by the map compiler"};
cvar_t mod_obj_orientation = {CF_CLIENT | CF_SERVER, "mod_obj_orientation", "1", "fix orientation of OBJ models to the usual conventions (if zero, use coordinates as is)"};
Cvar_RegisterVariable(&mod_q3shader_force_addalpha);
Cvar_RegisterVariable(&mod_q3shader_force_terrain_alphaflag);
Cvar_RegisterVariable(&mod_q1bsp_polygoncollisions);
+ Cvar_RegisterVariable(&mod_q1bsp_traceoutofsolid);
Cvar_RegisterVariable(&mod_q1bsp_zero_hullsize_cutoff);
Cvar_RegisterVariable(&mod_recalculatenodeboxes);
Cvar_SetQuick(&mod_q3shader_force_addalpha, "1");
memset(&mod_q1bsp_texture_solid, 0, sizeof(mod_q1bsp_texture_solid));
- strlcpy(mod_q1bsp_texture_solid.name, "solid" , sizeof(mod_q1bsp_texture_solid.name));
+ dp_strlcpy(mod_q1bsp_texture_solid.name, "solid" , sizeof(mod_q1bsp_texture_solid.name));
mod_q1bsp_texture_solid.surfaceflags = 0;
mod_q1bsp_texture_solid.supercontents = SUPERCONTENTS_SOLID;
mod_q1bsp_texture_sky = mod_q1bsp_texture_solid;
- strlcpy(mod_q1bsp_texture_sky.name, "sky", sizeof(mod_q1bsp_texture_sky.name));
+ dp_strlcpy(mod_q1bsp_texture_sky.name, "sky", sizeof(mod_q1bsp_texture_sky.name));
mod_q1bsp_texture_sky.surfaceflags = Q3SURFACEFLAG_SKY | Q3SURFACEFLAG_NOIMPACT | Q3SURFACEFLAG_NOMARKS | Q3SURFACEFLAG_NODLIGHT | Q3SURFACEFLAG_NOLIGHTMAP;
mod_q1bsp_texture_sky.supercontents = SUPERCONTENTS_SKY | SUPERCONTENTS_NODROP;
mod_q1bsp_texture_lava = mod_q1bsp_texture_solid;
- strlcpy(mod_q1bsp_texture_lava.name, "*lava", sizeof(mod_q1bsp_texture_lava.name));
+ dp_strlcpy(mod_q1bsp_texture_lava.name, "*lava", sizeof(mod_q1bsp_texture_lava.name));
mod_q1bsp_texture_lava.surfaceflags = Q3SURFACEFLAG_NOMARKS;
mod_q1bsp_texture_lava.supercontents = SUPERCONTENTS_LAVA | SUPERCONTENTS_NODROP;
mod_q1bsp_texture_slime = mod_q1bsp_texture_solid;
- strlcpy(mod_q1bsp_texture_slime.name, "*slime", sizeof(mod_q1bsp_texture_slime.name));
+ dp_strlcpy(mod_q1bsp_texture_slime.name, "*slime", sizeof(mod_q1bsp_texture_slime.name));
mod_q1bsp_texture_slime.surfaceflags = Q3SURFACEFLAG_NOMARKS;
mod_q1bsp_texture_slime.supercontents = SUPERCONTENTS_SLIME;
mod_q1bsp_texture_water = mod_q1bsp_texture_solid;
- strlcpy(mod_q1bsp_texture_water.name, "*water", sizeof(mod_q1bsp_texture_water.name));
+ dp_strlcpy(mod_q1bsp_texture_water.name, "*water", sizeof(mod_q1bsp_texture_water.name));
mod_q1bsp_texture_water.surfaceflags = Q3SURFACEFLAG_NOMARKS;
mod_q1bsp_texture_water.supercontents = SUPERCONTENTS_WATER;
}
// recurse both sides, front side first
ret = Mod_Q1BSP_RecursiveHullCheck(t, node->children[p1side], p1f, midf, p1, mid);
// if this side is not empty, return what it is (solid or done)
- if (ret != HULLCHECKSTATE_EMPTY && !t->trace->allsolid)
+ if (ret != HULLCHECKSTATE_EMPTY && (!t->trace->allsolid || !mod_q1bsp_traceoutofsolid.integer))
return ret;
ret = Mod_Q1BSP_RecursiveHullCheck(t, node->children[p2side], midf, p2f, mid, p2);
}
}
- loadmodel->brush.solidskyskinframe = R_SkinFrame_LoadInternalBGRA("sky_solidtexture", 0 , (unsigned char *) solidpixels, w, h, 0, 0, 0, vid.sRGB3D);
- loadmodel->brush.alphaskyskinframe = R_SkinFrame_LoadInternalBGRA("sky_alphatexture", TEXF_ALPHA, (unsigned char *) alphapixels, w, h, 0, 0, 0, vid.sRGB3D);
+ // Load the solid and alpha parts of the sky texture as separate textures
+ loadmodel->brush.solidskyskinframe = R_SkinFrame_LoadInternalBGRA(
+ "sky_solidtexture",
+ 0,
+ (unsigned char *) solidpixels,
+ w, h, w, h,
+ CRC_Block((unsigned char *) solidpixels, w*h*4),
+ vid.sRGB3D);
+ loadmodel->brush.alphaskyskinframe = R_SkinFrame_LoadInternalBGRA(
+ "sky_alphatexture",
+ TEXF_ALPHA,
+ (unsigned char *) alphapixels,
+ w, h, w, h,
+ CRC_Block((unsigned char *) alphapixels, w*h*4),
+ vid.sRGB3D);
Mem_Free(solidpixels);
Mem_Free(alphapixels);
}
// pretty up the buffer (replacing any trailing garbage with 0)
for (j = (int)strlen(name); j < 16; j++)
name[j] = 0;
+ // bones_was_here: force all names to lowercase (matching code below) so we don't crash on e2m9
+ for (j = 0;name[j];j++)
+ if (name[j] >= 'A' && name[j] <= 'Z')
+ name[j] += 'a' - 'A';
if (!strncmp(name, "sky", 3))
numsky++;
skinframemissing = R_SkinFrame_LoadMissing();
for (i = 0, tx = loadmodel->data_textures;i < loadmodel->num_textures;i++, tx++)
{
- strlcpy(tx->name, "NO TEXTURE FOUND", sizeof(tx->name));
+ dp_strlcpy(tx->name, "NO TEXTURE FOUND", sizeof(tx->name));
tx->width = 16;
tx->height = 16;
tx->basealpha = 1.0f;
// no luck with loading shaders or external textures - restore the in-progress texture loading
loadmodel->data_textures[i] = backuptex;
- strlcpy(tx->name, name, sizeof(tx->name));
+ dp_strlcpy(tx->name, name, sizeof(tx->name));
tx->width = mtwidth;
tx->height = mtheight;
tx->basealpha = 1.0f;
else // LadyHavoc: bsp version 29 (normal white lighting)
{
// LadyHavoc: hope is not lost yet, check for a .lit file to load
- strlcpy (litfilename, loadmodel->name, sizeof (litfilename));
+ dp_strlcpy (litfilename, loadmodel->name, sizeof (litfilename));
FS_StripExtension (litfilename, litfilename, sizeof (litfilename));
- strlcpy (dlitfilename, litfilename, sizeof (dlitfilename));
- strlcat (litfilename, ".lit", sizeof (litfilename));
- strlcat (dlitfilename, ".dlit", sizeof (dlitfilename));
+ dp_strlcpy (dlitfilename, litfilename, sizeof (dlitfilename));
+ dp_strlcat (litfilename, ".lit", sizeof (litfilename));
+ dp_strlcat (dlitfilename, ".dlit", sizeof (dlitfilename));
data = (unsigned char*) FS_LoadFile(litfilename, tempmempool, false, &filesize);
if (data)
{
if (com_token[0] == '}')
break; // end of worldspawn
if (com_token[0] == '_')
- strlcpy(key, com_token + 1, sizeof(key));
+ dp_strlcpy(key, com_token + 1, sizeof(key));
else
- strlcpy(key, com_token, sizeof(key));
+ dp_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, false, true))
//Calculates a PVS that is the inclusive or of all leafs within radius pixels
//of the given point.
-static int Mod_BSP_FatPVS(model_t *model, const vec3_t org, vec_t radius, unsigned char *pvsbuffer, int pvsbufferlength, qbool merge)
+static size_t Mod_BSP_FatPVS(model_t *model, const vec3_t org, vec_t radius, unsigned char **pvsbuffer, mempool_t *pool, qbool merge)
{
- int bytes = model->brush.num_pvsclusterbytes;
- bytes = min(bytes, pvsbufferlength);
+ size_t bytes = model->brush.num_pvsclusterbytes;
+
+ if (!*pvsbuffer || bytes != Mem_Size(*pvsbuffer))
+ {
+// Con_Printf("^4FatPVS: allocating a%s ^4buffer in pool %s, old size %zu new size %zu\n", *pvsbuffer == NULL ? " ^5NEW" : "", pool->name, *pvsbuffer != NULL ? Mem_Size(*pvsbuffer) : 0, bytes);
+ if (*pvsbuffer)
+ Mem_Free(*pvsbuffer); // don't reuse stale data when the worldmodel changes
+ *pvsbuffer = Mem_AllocType(pool, unsigned char, bytes);
+ }
+
if (r_novis.integer || r_trippy.integer || !model->brush.num_pvsclusters || !Mod_BSP_GetPVS(model, org))
{
- memset(pvsbuffer, 0xFF, bytes);
+ memset(*pvsbuffer, 0xFF, bytes);
return bytes;
}
if (!merge)
- memset(pvsbuffer, 0, bytes);
- Mod_BSP_FatPVS_RecursiveBSPNode(model, org, radius, pvsbuffer, bytes, model->brush.data_nodes + model->brushq1.hulls[0].firstclipnode);
+ memset(*pvsbuffer, 0, bytes);
+ Mod_BSP_FatPVS_RecursiveBSPNode(model, org, radius, *pvsbuffer, bytes, model->brush.data_nodes + model->brushq1.hulls[0].firstclipnode);
return bytes;
}
hullinfo_t hullinfo;
int totalstylesurfaces, totalstyles, stylecounts[256], remapstyles[256];
model_brush_lightstyleinfo_t styleinfo[256];
- unsigned char *datapointer;
+ int *datapointer;
+ model_brush_lightstyleinfo_t *lsidatapointer;
sizebuf_t sb;
MSG_InitReadBuffer(&sb, (unsigned char *)buffer, (unsigned char *)bufferend - (unsigned char *)buffer);
mod->brushq1.num_compressedpvs = 0;
Mod_Q1BSP_MakeHull0();
- if (mod_bsp_portalize.integer)
+ if (mod_bsp_portalize.integer && cls.state != ca_dedicated)
Mod_BSP_MakePortals();
mod->numframes = 2; // regular and alternate animation
totalstylesurfaces += stylecounts[k];
}
}
- datapointer = (unsigned char *)Mem_Alloc(mod->mempool, mod->num_surfaces * sizeof(int) + totalstyles * sizeof(model_brush_lightstyleinfo_t) + totalstylesurfaces * sizeof(int *));
- mod->modelsurfaces_sorted = (int*)datapointer;datapointer += mod->num_surfaces * sizeof(int);
+ // bones_was_here: using a separate allocation for model_brush_lightstyleinfo_t
+ // because on a 64-bit machine it no longer has the same alignment requirement as int.
+ lsidatapointer = Mem_AllocType(mod->mempool, model_brush_lightstyleinfo_t, totalstyles * sizeof(model_brush_lightstyleinfo_t));
+ datapointer = Mem_AllocType(mod->mempool, int, mod->num_surfaces * sizeof(int) + totalstylesurfaces * sizeof(int));
+ mod->modelsurfaces_sorted = datapointer;datapointer += mod->num_surfaces;
for (i = 0;i < mod->brush.numsubmodels;i++)
{
// LadyHavoc: this code was originally at the end of this loop, but
// copy the base model to this one
*mod = *loadmodel;
// rename the clone back to its proper name
- strlcpy(mod->name, name, sizeof(mod->name));
+ dp_strlcpy(mod->name, name, sizeof(mod->name));
mod->brush.parentmodel = loadmodel;
// textures and memory belong to the main model
mod->texturepool = NULL;
styleinfo[mod->brushq1.num_lightstyles].style = k;
styleinfo[mod->brushq1.num_lightstyles].value = 0;
styleinfo[mod->brushq1.num_lightstyles].numsurfaces = 0;
- styleinfo[mod->brushq1.num_lightstyles].surfacelist = (int *)datapointer;datapointer += stylecounts[k] * sizeof(int);
+ styleinfo[mod->brushq1.num_lightstyles].surfacelist = datapointer;datapointer += stylecounts[k];
remapstyles[k] = mod->brushq1.num_lightstyles;
mod->brushq1.num_lightstyles++;
}
}
}
}
- mod->brushq1.data_lightstyleinfo = (model_brush_lightstyleinfo_t *)datapointer;datapointer += mod->brushq1.num_lightstyles * sizeof(model_brush_lightstyleinfo_t);
+ mod->brushq1.data_lightstyleinfo = lsidatapointer;lsidatapointer += mod->brushq1.num_lightstyles;
memcpy(mod->brushq1.data_lightstyleinfo, styleinfo, mod->brushq1.num_lightstyles * sizeof(model_brush_lightstyleinfo_t));
}
else
msurface_t *surface;
int totalstylesurfaces, totalstyles, stylecounts[256], remapstyles[256];
model_brush_lightstyleinfo_t styleinfo[256];
- unsigned char *datapointer;
+ int *datapointer;
+ model_brush_lightstyleinfo_t *lsidatapointer;
sizebuf_t sb;
MSG_InitReadBuffer(&sb, (unsigned char *)buffer, (unsigned char *)bufferend - (unsigned char *)buffer);
mod->brushq1.num_compressedpvs = 0;
// the MakePortals code works fine on the q2bsp data as well
- if (mod_bsp_portalize.integer)
+ if (mod_bsp_portalize.integer && cls.state != ca_dedicated)
Mod_BSP_MakePortals();
mod->numframes = 0; // q2bsp animations are kind of special, frame is unbounded...
totalstylesurfaces += stylecounts[k];
}
}
- datapointer = (unsigned char *)Mem_Alloc(mod->mempool, mod->num_surfaces * sizeof(int) + totalstyles * sizeof(model_brush_lightstyleinfo_t) + totalstylesurfaces * sizeof(int *));
- mod->modelsurfaces_sorted = (int*)datapointer; datapointer += mod->num_surfaces * sizeof(int);
+ // bones_was_here: using a separate allocation for model_brush_lightstyleinfo_t
+ // because on a 64-bit machine it no longer has the same alignment requirement as int.
+ lsidatapointer = Mem_AllocType(mod->mempool, model_brush_lightstyleinfo_t, totalstyles * sizeof(model_brush_lightstyleinfo_t));
+ datapointer = Mem_AllocType(mod->mempool, int, mod->num_surfaces * sizeof(int) + totalstylesurfaces * sizeof(int));
+ mod->modelsurfaces_sorted = datapointer; datapointer += mod->num_surfaces;
// set up the world model, then on each submodel copy from the world model
// and set up the submodel with the respective model info.
mod = loadmodel;
// copy the base model to this one
*mod = *loadmodel;
// rename the clone back to its proper name
- strlcpy(mod->name, name, sizeof(mod->name));
+ dp_strlcpy(mod->name, name, sizeof(mod->name));
mod->brush.parentmodel = loadmodel;
// textures and memory belong to the main model
mod->texturepool = NULL;
styleinfo[mod->brushq1.num_lightstyles].style = k;
styleinfo[mod->brushq1.num_lightstyles].value = 0;
styleinfo[mod->brushq1.num_lightstyles].numsurfaces = 0;
- styleinfo[mod->brushq1.num_lightstyles].surfacelist = (int *)datapointer;datapointer += stylecounts[k] * sizeof(int);
+ styleinfo[mod->brushq1.num_lightstyles].surfacelist = datapointer;datapointer += stylecounts[k];
remapstyles[k] = mod->brushq1.num_lightstyles;
mod->brushq1.num_lightstyles++;
}
}
}
}
- mod->brushq1.data_lightstyleinfo = (model_brush_lightstyleinfo_t *)datapointer;datapointer += mod->brushq1.num_lightstyles * sizeof(model_brush_lightstyleinfo_t);
+ mod->brushq1.data_lightstyleinfo = lsidatapointer;lsidatapointer += mod->brushq1.num_lightstyles;
memcpy(mod->brushq1.data_lightstyleinfo, styleinfo, mod->brushq1.num_lightstyles * sizeof(model_brush_lightstyleinfo_t));
}
else
if (com_token[0] == '}')
break; // end of worldspawn
if (com_token[0] == '_')
- strlcpy(key, com_token + 1, sizeof(key));
+ dp_strlcpy(key, com_token + 1, sizeof(key));
else
- strlcpy(key, com_token, sizeof(key));
+ dp_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, false, true))
break; // error
- strlcpy(value, com_token, sizeof(value));
+ dp_strlcpy(value, com_token, sizeof(value));
if (!strcasecmp("gridsize", key)) // this one is case insensitive to 100% match q3map2
{
#if _MSC_VER >= 1400
for (i = 0;i < count;i++, in++, out++)
{
- strlcpy (out->shadername, in->shadername, sizeof (out->shadername));
+ dp_strlcpy (out->shadername, in->shadername, sizeof (out->shadername));
n = LittleLong(in->brushindex);
if (n >= loadmodel->brush.num_brushes)
{
for (j = 0;j < 3;j++)
{
// yes the mins/maxs are ints
- out->mins[j] = LittleLong(in->mins[j]) - 1;
- out->maxs[j] = LittleLong(in->maxs[j]) + 1;
+ // bones_was_here: the cast prevents signed underflow with poon-wood.bsp
+ out->mins[j] = (vec_t)LittleLong(in->mins[j]) - 1;
+ out->maxs[j] = (vec_t)LittleLong(in->maxs[j]) + 1;
}
n = LittleLong(in->firstleafface);
c = LittleLong(in->numleaffaces);
loadmodel->brush.numsubmodels = loadmodel->brushq3.num_models;
// the MakePortals code works fine on the q3bsp data as well
- if (mod_bsp_portalize.integer)
+ if (mod_bsp_portalize.integer && cls.state != ca_dedicated)
Mod_BSP_MakePortals();
// FIXME: shader alpha should replace r_wateralpha support in q3bsp
// copy the base model to this one
*mod = *loadmodel;
// rename the clone back to its proper name
- strlcpy(mod->name, name, sizeof(mod->name));
+ dp_strlcpy(mod->name, name, sizeof(mod->name));
mod->brush.parentmodel = loadmodel;
// textures and memory belong to the main model
mod->texturepool = NULL;
texturenames = (char *)Mem_Realloc(loadmodel->mempool, texturenames, maxtextures * MAX_QPATH);
}
textureindex = numtextures++;
- strlcpy(texturenames + textureindex*MAX_QPATH, loadmodel->name, MAX_QPATH);
+ dp_strlcpy(texturenames + textureindex*MAX_QPATH, loadmodel->name, MAX_QPATH);
}
for (j = 1;j < argc;j++)
{
texturenames = (char *)Mem_Realloc(loadmodel->mempool, texturenames, maxtextures * MAX_QPATH);
}
textureindex = numtextures++;
- strlcpy(texturenames + textureindex*MAX_QPATH, argv[1], MAX_QPATH);
+ dp_strlcpy(texturenames + textureindex*MAX_QPATH, argv[1], MAX_QPATH);
}
}
}
// copy the base model to this one
*mod = *loadmodel;
// rename the clone back to its proper name
- strlcpy(mod->name, name, sizeof(mod->name));
+ dp_strlcpy(mod->name, name, sizeof(mod->name));
mod->brush.parentmodel = loadmodel;
// textures and memory belong to the main model
mod->texturepool = NULL;