//cvar_t r_subdivide_size = {CVAR_SAVE, "r_subdivide_size", "128", "how large water polygons should be (smaller values produce more polygons which give better warping effects)"};
+cvar_t mod_bsp_portalize = {0, "mod_bsp_portalize", "0", "enables portal generation from BSP tree (may take several seconds per map), used by r_drawportals, r_useportalculling, r_shadow_realtime_world_compileportalculling, sv_cullentities_portal - all of which are off by default"};
cvar_t r_novis = {0, "r_novis", "0", "draws whole level, see also sv_cullentities_pvs 0"};
cvar_t r_nosurftextures = {0, "r_nosurftextures", "0", "pretends there was no texture lump found in the q1bsp/hlbsp loading (useful for debugging this rare case)"};
cvar_t r_subdivisions_tolerance = {0, "r_subdivisions_tolerance", "4", "maximum error tolerance on curve subdivision for rendering purposes (in other words, the curves will be given as many polygons as necessary to represent curves at this quality)"};
cvar_t mod_q3bsp_nolightmaps = {CVAR_SAVE, "mod_q3bsp_nolightmaps", "0", "do not load lightmaps in Q3BSP maps (to save video RAM, but be warned: it looks ugly)"};
cvar_t mod_q3bsp_tracelineofsight_brushes = {0, "mod_q3bsp_tracelineofsight_brushes", "0", "enables culling of entities behind detail brushes, curves, etc"};
cvar_t mod_q3shader_default_offsetmapping = {CVAR_SAVE, "mod_q3shader_default_offsetmapping", "1", "use offsetmapping by default on all surfaces"};
+cvar_t mod_q3shader_default_polygonfactor = {0, "mod_q3shader_default_polygonfactor", "0", "biases depth values of 'polygonoffset' shaders to prevent z-fighting artifacts"};
+cvar_t mod_q3shader_default_polygonoffset = {0, "mod_q3shader_default_polygonoffset", "-2", "biases depth values of 'polygonoffset' shaders to prevent z-fighting artifacts"};
cvar_t mod_q1bsp_polygoncollisions = {0, "mod_q1bsp_polygoncollisions", "0", "disables use of precomputed cliphulls and instead collides with polygons (uses Bounding Interval Hierarchy optimizations)"};
cvar_t mod_collision_bih = {0, "mod_collision_bih", "1", "enables use of generated Bounding Interval Hierarchy tree instead of compiled bsp tree in collision code"};
void Mod_BrushInit(void)
{
// Cvar_RegisterVariable(&r_subdivide_size);
+ Cvar_RegisterVariable(&mod_bsp_portalize);
Cvar_RegisterVariable(&r_novis);
Cvar_RegisterVariable(&r_nosurftextures);
Cvar_RegisterVariable(&r_subdivisions_tolerance);
Cvar_RegisterVariable(&mod_q3bsp_nolightmaps);
Cvar_RegisterVariable(&mod_q3bsp_tracelineofsight_brushes);
Cvar_RegisterVariable(&mod_q3shader_default_offsetmapping);
+ Cvar_RegisterVariable(&mod_q3shader_default_polygonfactor);
+ Cvar_RegisterVariable(&mod_q3shader_default_polygonoffset);
Cvar_RegisterVariable(&mod_q1bsp_polygoncollisions);
Cvar_RegisterVariable(&mod_collision_bih);
Cvar_RegisterVariable(&mod_recalculatenodeboxes);
}
// compile additional data about the surface geometry
- Mod_BuildNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, loadmodel->surfmesh.data_vertex3f, (loadmodel->surfmesh.data_element3i + 3 * surface->num_firsttriangle), loadmodel->surfmesh.data_normal3f, true);
- Mod_BuildTextureVectorsFromNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, (loadmodel->surfmesh.data_element3i + 3 * surface->num_firsttriangle), loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, true);
+ Mod_BuildNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, loadmodel->surfmesh.data_vertex3f, (loadmodel->surfmesh.data_element3i + 3 * surface->num_firsttriangle), loadmodel->surfmesh.data_normal3f, r_smoothnormals_areaweighting.integer != 0);
+ Mod_BuildTextureVectorsFromNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, (loadmodel->surfmesh.data_element3i + 3 * surface->num_firsttriangle), loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, r_smoothnormals_areaweighting.integer != 0);
BoxFromPoints(surface->mins, surface->maxs, surface->num_vertices, (loadmodel->surfmesh.data_vertex3f + 3 * surface->num_firstvertex));
// generate surface extents information
// lightmap is needed on this surface (rather than duplicating the
// logic above)
loadmodel->brushq1.lightmapupdateflags[surfacenum] = true;
+ loadmodel->lit = true;
}
}
if (l->filelen % sizeof(*in))
Host_Error("Mod_Q1BSP_LoadNodes: funny lump size in %s",loadmodel->name);
count = l->filelen / sizeof(*in);
+ if (count == 0)
+ Host_Error("Mod_Q1BSP_LoadNodes: missing BSP tree in %s",loadmodel->name);
out = (mnode_t *)Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
loadmodel->brush.data_nodes = out;
for (j = 0, surface = mod->data_surfaces;j < mod->num_surfaces;j++, surface++)
if (surface->num_triangles > 0)
Mod_ShadowMesh_AddMesh(mod->mempool, mod->brush.shadowmesh, NULL, NULL, NULL, mod->surfmesh.data_vertex3f, NULL, NULL, NULL, NULL, surface->num_triangles, (mod->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
- mod->brush.shadowmesh = Mod_ShadowMesh_Finish(mod->mempool, mod->brush.shadowmesh, false, true, false);
- if (mod->brush.shadowmesh)
+ mod->brush.shadowmesh = Mod_ShadowMesh_Finish(mod->mempool, mod->brush.shadowmesh, false, r_enableshadowvolumes.integer != 0, false);
+ if (mod->brush.shadowmesh && mod->brush.shadowmesh->neighbor3i)
Mod_BuildTriangleNeighbors(mod->brush.shadowmesh->neighbor3i, mod->brush.shadowmesh->element3i, mod->brush.shadowmesh->numtriangles);
return numshadowmeshtriangles;
dmodel_t *bm;
float dist, modelyawradius, modelradius;
msurface_t *surface;
- int numshadowmeshtriangles;
hullinfo_t hullinfo;
int totalstylesurfaces, totalstyles, stylecounts[256], remapstyles[256];
model_brush_lightstyleinfo_t styleinfo[256];
mod->brushq1.num_compressedpvs = 0;
Mod_Q1BSP_MakeHull0();
- Mod_Q1BSP_MakePortals();
+ if (mod_bsp_portalize.integer)
+ Mod_Q1BSP_MakePortals();
mod->numframes = 2; // regular and alternate animation
mod->numskins = 1;
// make a single combined shadow mesh to allow optimized shadow volume creation
- numshadowmeshtriangles = Mod_Q1BSP_CreateShadowMesh(loadmodel);
+ Mod_Q1BSP_CreateShadowMesh(loadmodel);
if (loadmodel->brush.numsubmodels)
loadmodel->brush.submodels = (dp_model_t **)Mem_Alloc(loadmodel->mempool, loadmodel->brush.numsubmodels * sizeof(dp_model_t *));
}
//mod->brushq1.num_visleafs = bm->visleafs;
+ // build a Bounding Interval Hierarchy for culling triangles in light rendering
+ Mod_MakeCollisionBIH(mod, true, &mod->render_bih);
+
if (mod_q1bsp_polygoncollisions.integer)
{
- Mod_MakeCollisionBIH(mod, true, &mod->collision_bih);
+ mod->collision_bih = mod->render_bih;
// point traces and contents checks still use the bsp tree
mod->TraceLine = Mod_CollisionBIH_TraceLine;
mod->TraceBox = Mod_CollisionBIH_TraceBox;
+ mod->TraceBrush = Mod_CollisionBIH_TraceBrush;
}
- else
- Mod_MakeCollisionBIH(mod, true, &mod->render_bih);
// generate VBOs and other shared data before cloning submodels
if (i == 0)
loadmodel->brushq3.data_color4f[i * 4 + 1] = in->color4ub[1] * (1.0f / 255.0f);
loadmodel->brushq3.data_color4f[i * 4 + 2] = in->color4ub[2] * (1.0f / 255.0f);
loadmodel->brushq3.data_color4f[i * 4 + 3] = in->color4ub[3] * (1.0f / 255.0f);
+ if(in->color4ub[0] != 255 || in->color4ub[1] != 255 || in->color4ub[2] != 255)
+ loadmodel->lit = true;
}
}
out->lightmaptexture = loadmodel->brushq3.data_lightmaps[n >> loadmodel->brushq3.num_lightmapmergedwidthheightdeluxepower];
if (loadmodel->brushq3.deluxemapping)
out->deluxemaptexture = loadmodel->brushq3.data_deluxemaps[n >> loadmodel->brushq3.num_lightmapmergedwidthheightdeluxepower];
+ loadmodel->lit = true;
}
}
if(out->num_vertices && out->num_triangles)
continue;
if(out->num_vertices == 0)
- Con_Printf("Mod_Q3BSP_LoadFaces: surface %d has no vertices, ignoring\n", i);
- if(out->num_triangles == 0)
- Con_Printf("Mod_Q3BSP_LoadFaces: surface %d has no triangles, ignoring\n", i);
+ {
+ Con_Printf("Mod_Q3BSP_LoadFaces: surface %d (texture %s) has no vertices, ignoring\n", i, out->texture ? out->texture->name : "(none)");
+ if(out->num_triangles == 0)
+ Con_Printf("Mod_Q3BSP_LoadFaces: surface %d (texture %s) has no triangles, ignoring\n", i, out->texture ? out->texture->name : "(none)");
+ }
+ else if(out->num_triangles == 0)
+ Con_Printf("Mod_Q3BSP_LoadFaces: surface %d (texture %s, near %f %f %f) has no triangles, ignoring\n", i, out->texture ? out->texture->name : "(none)",
+ (loadmodel->surfmesh.data_vertex3f + 3 * out->num_firstvertex)[0 * 3 + 0],
+ (loadmodel->surfmesh.data_vertex3f + 3 * out->num_firstvertex)[1 * 3 + 0],
+ (loadmodel->surfmesh.data_vertex3f + 3 * out->num_firstvertex)[2 * 3 + 0]);
}
// for per pixel lighting
- Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, true);
+ Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, r_smoothnormals_areaweighting.integer != 0);
// generate ushort elements array if possible
if (loadmodel->surfmesh.data_element3s)
if (l->filelen % sizeof(*in))
Host_Error("Mod_Q3BSP_LoadNodes: funny lump size in %s",loadmodel->name);
count = l->filelen / sizeof(*in);
+ if (count == 0)
+ Host_Error("Mod_Q3BSP_LoadNodes: missing BSP tree in %s",loadmodel->name);
out = (mnode_t *)Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
loadmodel->brush.data_nodes = out;
q3dlightgrid_t *a, *s;
// scale lighting by lightstyle[0] so that darkmode in dpmod works properly
- stylescale = r_refdef.scene.rtlightstylevalue[0];
+ if (vid.renderpath == RENDERPATH_GL20)
+ stylescale = 1; // added while render
+ else
+ stylescale = r_refdef.scene.rtlightstylevalue[0];
if (!model->brushq3.num_lightgrid)
{
if (VectorCompare(start, end))
Mod_CollisionBIH_TracePoint(model, frameblend, skeleton, trace, shiftstart, hitsupercontentsmask);
else
- {
Mod_CollisionBIH_TraceLine(model, frameblend, skeleton, trace, shiftstart, shiftend, hitsupercontentsmask);
- VectorSubtract(trace->endpos, boxmins, trace->endpos);
- }
return;
}
Mod_CollisionBIH_TraceBrush_RecursiveBIHNode(trace, model, model->collision_bih.rootnode, &thisbrush_start.brush, &thisbrush_end.brush, segmentmins, segmentmaxs);
}
+void Mod_CollisionBIH_TraceBrush(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, colbrushf_t *start, colbrushf_t *end, int hitsupercontentsmask)
+{
+ float segmentmins[3], segmentmaxs[3];
+
+ if (mod_q3bsp_optimizedtraceline.integer && VectorCompare(start->mins, start->maxs) && VectorCompare(end->mins, end->maxs))
+ {
+ if (VectorCompare(start->mins, end->mins))
+ Mod_CollisionBIH_TracePoint(model, frameblend, skeleton, trace, start->mins, hitsupercontentsmask);
+ else
+ Mod_CollisionBIH_TraceLine(model, frameblend, skeleton, trace, start->mins, end->mins, hitsupercontentsmask);
+ return;
+ }
+
+ // box trace, performed as brush trace
+ memset(trace, 0, sizeof(*trace));
+ trace->fraction = 1;
+ trace->realfraction = 1;
+ trace->hitsupercontentsmask = hitsupercontentsmask;
+ segmentmins[0] = min(start->mins[0], end->mins[0]);
+ segmentmins[1] = min(start->mins[1], end->mins[1]);
+ segmentmins[2] = min(start->mins[2], end->mins[2]);
+ segmentmaxs[0] = max(start->maxs[0], end->maxs[0]);
+ segmentmaxs[1] = max(start->maxs[1], end->maxs[1]);
+ segmentmaxs[2] = max(start->maxs[2], end->maxs[2]);
+ Mod_CollisionBIH_TraceBrush_RecursiveBIHNode(trace, model, model->collision_bih.rootnode, start, end, segmentmins, segmentmaxs);
+}
+
int Mod_CollisionBIH_PointSuperContents(struct model_s *model, int frame, const vec3_t point)
{
trace_t trace;
if (VectorCompare(start, end))
Mod_Q3BSP_TracePoint(model, frameblend, skeleton, trace, shiftstart, hitsupercontentsmask);
else
- {
Mod_Q3BSP_TraceLine(model, frameblend, skeleton, trace, shiftstart, shiftend, hitsupercontentsmask);
- VectorSubtract(trace->endpos, boxmins, trace->endpos);
- }
return;
}
Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, model, model->brush.data_nodes, &thisbrush_start.brush, &thisbrush_end.brush, ++markframe, segmentmins, segmentmaxs);
}
+void Mod_Q3BSP_TraceBrush(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, colbrushf_t *start, colbrushf_t *end, int hitsupercontentsmask)
+{
+ float segmentmins[3], segmentmaxs[3];
+ int i;
+ msurface_t *surface;
+ q3mbrush_t *brush;
+
+ if (mod_q3bsp_optimizedtraceline.integer && VectorCompare(start->mins, start->maxs) && VectorCompare(end->mins, end->maxs))
+ {
+ if (VectorCompare(start->mins, end->mins))
+ Mod_Q3BSP_TracePoint(model, frameblend, skeleton, trace, start->mins, hitsupercontentsmask);
+ else
+ Mod_Q3BSP_TraceLine(model, frameblend, skeleton, trace, start->mins, end->mins, hitsupercontentsmask);
+ return;
+ }
+
+ // box trace, performed as brush trace
+ memset(trace, 0, sizeof(*trace));
+ trace->fraction = 1;
+ trace->realfraction = 1;
+ trace->hitsupercontentsmask = hitsupercontentsmask;
+ segmentmins[0] = min(start->mins[0], end->mins[0]);
+ segmentmins[1] = min(start->mins[1], end->mins[1]);
+ segmentmins[2] = min(start->mins[2], end->mins[2]);
+ segmentmaxs[0] = max(start->maxs[0], end->maxs[0]);
+ segmentmaxs[1] = max(start->maxs[1], end->maxs[1]);
+ segmentmaxs[2] = max(start->maxs[2], end->maxs[2]);
+ if (mod_collision_bih.integer)
+ Mod_CollisionBIH_TraceBrush_RecursiveBIHNode(trace, model, model->collision_bih.rootnode, start, end, segmentmins, segmentmaxs);
+ else if (model->brush.submodel)
+ {
+ for (i = 0, brush = model->brush.data_brushes + model->firstmodelbrush;i < model->nummodelbrushes;i++, brush++)
+ if (brush->colbrushf && BoxesOverlap(segmentmins, segmentmaxs, brush->colbrushf->mins, brush->colbrushf->maxs))
+ Collision_TraceBrushBrushFloat(trace, start, end, brush->colbrushf, brush->colbrushf);
+ if (mod_q3bsp_curves_collisions.integer)
+ for (i = 0, surface = model->data_surfaces + model->firstmodelsurface;i < model->nummodelsurfaces;i++, surface++)
+ if (surface->num_collisiontriangles && BoxesOverlap(segmentmins, segmentmaxs, surface->mins, surface->maxs))
+ Collision_TraceBrushTriangleMeshFloat(trace, start, end, surface->num_collisiontriangles, surface->deprecatedq3data_collisionelement3i, surface->deprecatedq3data_collisionvertex3f, surface->deprecatedq3num_collisionbboxstride, surface->deprecatedq3data_collisionbbox6f, surface->texture->supercontents, surface->texture->surfaceflags, surface->texture, segmentmins, segmentmaxs);
+ }
+ else
+ Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, model, model->brush.data_nodes, start, end, ++markframe, segmentmins, segmentmaxs);
+}
+
static int Mod_Q3BSP_PointSuperContents(struct model_s *model, int frame, const vec3_t point)
{
int i;
void Mod_Q3BSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
{
- int i, j, numshadowmeshtriangles, lumps;
+ int i, j, lumps;
q3dheader_t *header;
float corner[3], yawradius, modelradius;
mod->soundfromcenter = true;
mod->TraceBox = Mod_Q3BSP_TraceBox;
+ mod->TraceBrush = Mod_Q3BSP_TraceBrush;
mod->TraceLine = Mod_Q3BSP_TraceLine;
mod->TracePoint = Mod_Q3BSP_TracePoint;
mod->PointSuperContents = Mod_Q3BSP_PointSuperContents;
loadmodel->brush.numsubmodels = loadmodel->brushq3.num_models;
// the MakePortals code works fine on the q3bsp data as well
- Mod_Q1BSP_MakePortals();
+ if (mod_bsp_portalize.integer)
+ Mod_Q1BSP_MakePortals();
// FIXME: shader alpha should replace r_wateralpha support in q3bsp
loadmodel->brush.supportwateralpha = true;
// make a single combined shadow mesh to allow optimized shadow volume creation
- numshadowmeshtriangles = Mod_Q1BSP_CreateShadowMesh(loadmodel);
+ Mod_Q1BSP_CreateShadowMesh(loadmodel);
loadmodel->brush.num_leafs = 0;
Mod_Q3BSP_RecursiveFindNumLeafs(loadmodel->brush.data_nodes);
loadmodel->type = mod_obj;
loadmodel->soundfromcenter = true;
loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
+ loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
vcurrent.nextindex = -1;
vcurrent.textureindex = textureindex;
vcurrent.submodelindex = submodelindex;
- VectorCopy(v + 3*index1, vcurrent.v);
- Vector2Copy(vt + 2*index2, vcurrent.vt);
- VectorCopy(vn + 3*index3, vcurrent.vn);
+ if (v && index1 >= 0 && index1 < numv)
+ VectorCopy(v + 3*index1, vcurrent.v);
+ if (vt && index2 >= 0 && index2 < numvt)
+ Vector2Copy(vt + 2*index2, vcurrent.vt);
+ if (vn && index3 >= 0 && index3 < numvn)
+ VectorCopy(vn + 3*index3, vcurrent.vn);
if (numtriangles == 0)
{
VectorCopy(vcurrent.v, mins);
// allocate storage for final mesh data
loadmodel->num_textures = numtextures * loadmodel->numskins;
loadmodel->num_texturesperskin = numtextures;
- data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + numtriangles * sizeof(int[3]) + (numvertices <= 65536 ? numtriangles * sizeof(unsigned short[3]) : 0) + numvertices * sizeof(float[14]) + loadmodel->brush.numsubmodels * sizeof(dp_model_t *));
+ data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + numtriangles * sizeof(int[3]) + (numvertices <= 65536 ? numtriangles * sizeof(unsigned short[3]) : 0) + (r_enableshadowvolumes.integer ? numtriangles * sizeof(int[3]) : 0) + numvertices * sizeof(float[14]) + loadmodel->brush.numsubmodels * sizeof(dp_model_t *));
loadmodel->brush.submodels = (dp_model_t **)data;data += loadmodel->brush.numsubmodels * sizeof(dp_model_t *);
loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
loadmodel->surfmesh.num_vertices = numvertices;
loadmodel->surfmesh.num_triangles = numtriangles;
- loadmodel->surfmesh.data_neighbor3i = (int *)data;data += numtriangles * sizeof(int[3]);
+ if (r_enableshadowvolumes.integer)
+ loadmodel->surfmesh.data_neighbor3i = (int *)data;data += numtriangles * sizeof(int[3]);
loadmodel->surfmesh.data_vertex3f = (float *)data;data += numvertices * sizeof(float[3]);
loadmodel->surfmesh.data_svector3f = (float *)data;data += numvertices * sizeof(float[3]);
loadmodel->surfmesh.data_tvector3f = (float *)data;data += numvertices * sizeof(float[3]);
Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
// generate normals if the file did not have them
if (!VectorLength2(loadmodel->surfmesh.data_normal3f))
- Mod_BuildNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_normal3f, true);
- Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, true);
- Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
+ Mod_BuildNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_normal3f, r_smoothnormals_areaweighting.integer != 0);
+ Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, r_smoothnormals_areaweighting.integer != 0);
+ if (loadmodel->surfmesh.data_neighbor3i)
+ Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
// if this is a worldmodel and has no BSP tree, create a fake one for the purpose
loadmodel->brush.num_visleafs = 1;
loadmodel->num_surfaces = 1;
loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
- data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->numframes * sizeof(animscene_t) + loadmodel->numframes * sizeof(float[6]) + loadmodel->surfmesh.num_triangles * sizeof(int[3]) + loadmodel->surfmesh.num_triangles * sizeof(int[3]));
+ data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->numframes * sizeof(animscene_t) + loadmodel->numframes * sizeof(float[6]) + loadmodel->surfmesh.num_triangles * sizeof(int[3]) + (r_enableshadowvolume.integer ? loadmodel->surfmesh.num_triangles * sizeof(int[3]) : 0));
loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
loadmodel->sortedmodelsurfaces[0] = 0;
loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
loadmodel->surfmesh.data_morphmd2framesize6f = (float *)data;data += loadmodel->numframes * sizeof(float[6]);
loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
- loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
+ if (r_enableshadowvolumes.integer)
+ loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
loadmodel->synctype = ST_RAND;
Mem_Free(vertremap);
Mod_MakeSortedSurfaces(loadmodel);
- Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
+ if (loadmodel->surfmesh.data_neighbor3i)
+ Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
Mod_Alias_CalculateBoundingBox();
Mod_Alias_MorphMesh_CompileFrames();