cvar_t r_miplightmaps = {CVAR_SAVE, "r_miplightmaps", "0"};
cvar_t r_lightmaprgba = {0, "r_lightmaprgba", "1"};
cvar_t r_nosurftextures = {0, "r_nosurftextures", "0"};
-cvar_t mod_q3bsp_curves_subdivide_level = {0, "mod_q3bsp_curves_subdivide_level", "2"};
+cvar_t r_subdivisions_tolerance = {0, "r_subdivisions_tolerance", "4"};
+cvar_t r_subdivisions_minlevel = {0, "r_subdivisions_minlevel", "0"};
+cvar_t r_subdivisions_maxlevel = {0, "r_subdivisions_maxlevel", "10"};
+cvar_t r_subdivisions_maxvertices = {0, "r_subdivisions_maxvertices", "65536"};
+cvar_t r_subdivisions_collision_tolerance = {0, "r_subdivisions_collision_tolerance", "15"};
+cvar_t r_subdivisions_collision_minlevel = {0, "r_subdivisions_collision_minlevel", "0"};
+cvar_t r_subdivisions_collision_maxlevel = {0, "r_subdivisions_collision_maxlevel", "10"};
+cvar_t r_subdivisions_collision_maxvertices = {0, "r_subdivisions_collision_maxvertices", "4225"};
cvar_t mod_q3bsp_curves_collisions = {0, "mod_q3bsp_curves_collisions", "1"};
cvar_t mod_q3bsp_optimizedtraceline = {0, "mod_q3bsp_optimizedtraceline", "1"};
cvar_t mod_q3bsp_debugtracebrush = {0, "mod_q3bsp_debugtracebrush", "0"};
Cvar_RegisterVariable(&r_miplightmaps);
Cvar_RegisterVariable(&r_lightmaprgba);
Cvar_RegisterVariable(&r_nosurftextures);
- Cvar_RegisterVariable(&mod_q3bsp_curves_subdivide_level);
+ Cvar_RegisterVariable(&r_subdivisions_tolerance);
+ Cvar_RegisterVariable(&r_subdivisions_minlevel);
+ Cvar_RegisterVariable(&r_subdivisions_maxlevel);
+ Cvar_RegisterVariable(&r_subdivisions_maxvertices);
+ Cvar_RegisterVariable(&r_subdivisions_collision_tolerance);
+ Cvar_RegisterVariable(&r_subdivisions_collision_minlevel);
+ Cvar_RegisterVariable(&r_subdivisions_collision_maxlevel);
+ Cvar_RegisterVariable(&r_subdivisions_collision_maxvertices);
Cvar_RegisterVariable(&mod_q3bsp_curves_collisions);
Cvar_RegisterVariable(&mod_q3bsp_optimizedtraceline);
Cvar_RegisterVariable(&mod_q3bsp_debugtracebrush);
}
}
+//Returns PVS data for a given point
+//(note: can return NULL)
+static qbyte *Mod_Q1BSP_GetPVS(model_t *model, const vec3_t p)
+{
+ mnode_t *node;
+ Mod_CheckLoaded(model);
+ node = model->brushq1.nodes;
+ while (node->plane)
+ node = node->children[(node->plane->type < 3 ? p[node->plane->type] : DotProduct(p,node->plane->normal)) < node->plane->dist];
+ if (((mleaf_t *)node)->clusterindex >= 0)
+ return model->brush.data_pvsclusters + ((mleaf_t *)node)->clusterindex * model->brush.num_pvsclusterbytes;
+ else
+ return NULL;
+}
+
static void Mod_Q1BSP_FatPVS_RecursiveBSPNode(model_t *model, const vec3_t org, vec_t radius, qbyte *pvsbuffer, int pvsbytes, mnode_t *node)
{
while (node->plane)
{
int bytes = ((model->brushq1.num_leafs - 1) + 7) >> 3;
bytes = min(bytes, pvsbufferlength);
- if (r_novis.integer)
+ if (r_novis.integer || !Mod_Q1BSP_GetPVS(model, org))
{
memset(pvsbuffer, 0xFF, bytes);
return bytes;
return bytes;
}
-//Returns PVS data for a given point
-//(note: can return NULL)
-static qbyte *Mod_Q1BSP_GetPVS(model_t *model, const vec3_t p)
-{
- mnode_t *node;
- Mod_CheckLoaded(model);
- node = model->brushq1.nodes;
- while (node->plane)
- node = node->children[(node->plane->type < 3 ? p[node->plane->type] : DotProduct(p,node->plane->normal)) < node->plane->dist];
- if (((mleaf_t *)node)->clusterindex >= 0)
- return model->brush.data_pvsclusters + ((mleaf_t *)node)->clusterindex * model->brush.num_pvsclusterbytes;
- else
- return NULL;
-}
-
static void Mod_Q1BSP_RoundUpToHullSize(model_t *cmodel, const vec3_t inmins, const vec3_t inmaxs, vec3_t outmins, vec3_t outmaxs)
{
vec3_t size;
VectorAdd(inmins, hull->clip_size, outmaxs);
}
+/*
+void Mod_Q1BSP_RecursiveGetVisible(mnode_t *node, model_t *model, const vec3_t point, const vec3_t mins, const vec3_t maxs, int maxleafs, mleaf_t *leaflist, int *numleafs, int maxsurfaces, msurface_t *surfacelist, int *numsurfaces, const qbyte *pvs)
+{
+ mleaf_t *leaf;
+ for (;;)
+ {
+ if (!BoxesOverlap(node->mins, node->maxs, mins, maxs))
+ return;
+ if (!node->plane)
+ break;
+ Mod_Q1BSP_RecursiveGetVisible(node->children[0], model, point, mins, maxs, maxleafs, leaflist, numleafs, maxsurfaces, surfacelist, numsurfaces, pvs);
+ node = node->children[1];
+ }
+ leaf = (mleaf_t *)node;
+ if ((pvs == NULL || CHECKPVSBIT(pvs, leaf->clusterindex)))
+ {
+ int marksurfacenum;
+ msurface_t *surf;
+ if (maxleafs && *numleafs < maxleafs)
+ leaflist[(*numleafs)++] = leaf;
+ if (maxsurfaces)
+ {
+ for (marksurfacenum = 0;marksurfacenum < leaf->nummarksurfaces;marksurfacenum++)
+ {
+ surf = model->brushq1.surfaces + leaf->firstmarksurface[marksurfacenum];
+ if (surf->shadowmark != shadowmarkcount)
+ {
+ surf->shadowmark = shadowmarkcount;
+ if (BoxesOverlap(mins, maxs, surf->poly_mins, surf->poly_maxs) && ((surf->flags & SURF_PLANEBACK) ? PlaneDiff(point, surf->plane) < 0 : PlaneDiff(point, surf->plane) > 0) && *numsurfaces < maxsurfaces)
+ surfacelist[(*numsurfaces)++] = surf;
+ }
+ }
+ }
+ }
+}
+
+void Mod_Q1BSP_GetVisible(model_t *model, const vec3_t point, const vec3_t mins, const vec3_t maxs, int maxleafs, mleaf_t *leaflist, int *numleafs, int maxsurfaces, msurface_t *surfacelist, int *numsurfaces)
+{
+ // FIXME: support portals
+ if (maxsurfaces)
+ *numsurfaces = 0;
+ if (maxleafs)
+ *numleafs = 0;
+ pvs = ent->model->brush.GetPVS(ent->model, relativelightorigin);
+ Mod_Q1BSP_RecursiveGetVisible(ent->model->brushq1.nodes + ent->model->brushq1.firstclipnode, model, point, mins, maxs, maxleafs, leaflist, numleafs, maxsurfaces, surfacelist, numsurfaces);
+}
+*/
+
extern void R_Model_Brush_DrawSky(entity_render_t *ent);
extern void R_Model_Brush_Draw(entity_render_t *ent);
extern void R_Model_Brush_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius);
model_t *originalloadmodel;
float dist, modelyawradius, modelradius, *vec;
msurface_t *surf;
+ int numshadowmeshtriangles;
mod->type = mod_brush;
Mod_Q1BSP_LoadLightList();
originalloadmodel = loadmodel;
+ // make a single combined shadow mesh to allow optimized shadow volume creation
+ numshadowmeshtriangles = 0;
+ for (j = 0, surf = loadmodel->brushq1.surfaces;j < loadmodel->brushq1.numsurfaces;j++, surf++)
+ {
+ surf->num_firstshadowmeshtriangle = numshadowmeshtriangles;
+ numshadowmeshtriangles += surf->mesh.num_triangles;
+ }
+ loadmodel->brush.shadowmesh = Mod_ShadowMesh_Begin(loadmodel->mempool, numshadowmeshtriangles * 3, numshadowmeshtriangles, NULL, NULL, NULL, false, false, true);
+ for (j = 0, surf = loadmodel->brushq1.surfaces;j < loadmodel->brushq1.numsurfaces;j++, surf++)
+ Mod_ShadowMesh_AddMesh(loadmodel->mempool, loadmodel->brush.shadowmesh, NULL, NULL, NULL, surf->mesh.data_vertex3f, NULL, NULL, NULL, NULL, surf->mesh.num_triangles, surf->mesh.data_element3i);
+ loadmodel->brush.shadowmesh = Mod_ShadowMesh_Finish(loadmodel->mempool, loadmodel->brush.shadowmesh, false, true);
+ Mod_BuildTriangleNeighbors(loadmodel->brush.shadowmesh->neighbor3i, loadmodel->brush.shadowmesh->element3i, loadmodel->brush.shadowmesh->numtriangles);
+
//
// set up the submodels(FIXME: this is confusing)
//
const char *text;
int flags;
char shadername[Q3PATHLENGTH];
+ char sky[Q3PATHLENGTH];
in = (void *)(mod_base + l->fileofs);
if (l->filelen % sizeof(*in))
{
snprintf(shadername, sizeof(shadername), "%s", com_token);
flags = 0;
+ sky[0] = 0;
if (COM_ParseToken(&text, false) && !strcasecmp(com_token, "{"))
{
while (COM_ParseToken(&text, false))
goto parseerror;
}
}
+ else if (!strcasecmp(com_token, "sky"))
+ {
+ if (COM_ParseToken(&text, true) && strcasecmp(com_token, "\n"))
+ if (strlen(com_token) < sizeof(sky))
+ strcpy(sky, com_token);
+ }
+ else if (!strcasecmp(com_token, "skyparms"))
+ {
+ if (COM_ParseToken(&text, true) && strcasecmp(com_token, "\n"))
+ {
+ if (strlen(com_token) < sizeof(sky) && !atoi(com_token) && strcasecmp(com_token, "-"))
+ strcpy(sky, com_token);
+ if (COM_ParseToken(&text, true) && strcasecmp(com_token, "\n"))
+ COM_ParseToken(&text, true);
+ }
+ }
else
{
// look for linebreak or }
// add shader to list (shadername and flags)
// actually here we just poke into the texture settings
for (j = 0, out = loadmodel->brushq3.data_textures;j < loadmodel->brushq3.num_textures;j++, out++)
+ {
if (!strcasecmp(out->name, shadername))
+ {
out->surfaceparms = flags;
+ if ((flags & Q3SURFACEPARM_SKY) && sky[0])
+ strcpy(loadmodel->brush.skybox, sky);
+ }
+ }
}
else
{
out->type = 0; // error
continue;
}
- // convert patch to Q3FACETYPE_MESH
- xlevel = mod_q3bsp_curves_subdivide_level.integer;
- ylevel = mod_q3bsp_curves_subdivide_level.integer;
- finalwidth = ((patchsize[0] - 1) << xlevel) + 1;
- finalheight = ((patchsize[1] - 1) << ylevel) + 1;
- finalvertices = finalwidth * finalheight;
- finaltriangles = (finalwidth - 1) * (finalheight - 1) * 2;
originalvertex3f = loadmodel->brushq3.data_vertex3f + out->firstvertex * 3;
//originalsvector3f = loadmodel->brushq3.data_svector3f + out->firstvertex * 3;
//originaltvector3f = loadmodel->brushq3.data_tvector3f + out->firstvertex * 3;
//originalelement3i = out->data_element3i;
//originalneighbor3i = out->data_neighbor3i;
*/
+ // convert patch to Q3FACETYPE_MESH
+ xlevel = QuadraticSplinePatchSubdivisionLevelOnX(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_tolerance.value, 10);
+ ylevel = QuadraticSplinePatchSubdivisionLevelOnY(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_tolerance.value, 10);
+ // bound to user settings
+ xlevel = bound(r_subdivisions_minlevel.integer, xlevel, r_subdivisions_maxlevel.integer);
+ ylevel = bound(r_subdivisions_minlevel.integer, ylevel, r_subdivisions_maxlevel.integer);
+ // bound to sanity settings
+ xlevel = bound(0, xlevel, 10);
+ ylevel = bound(0, ylevel, 10);
+ // bound to user limit on vertices
+ while ((xlevel > 0 || ylevel > 0) && (((patchsize[0] - 1) << xlevel) + 1) * (((patchsize[1] - 1) << ylevel) + 1) > min(r_subdivisions_maxvertices.integer, 262144))
+ {
+ if (xlevel > ylevel)
+ xlevel--;
+ else
+ ylevel--;
+ }
+ finalwidth = ((patchsize[0] - 1) << xlevel) + 1;
+ finalheight = ((patchsize[1] - 1) << ylevel) + 1;
+ finalvertices = finalwidth * finalheight;
+ finaltriangles = (finalwidth - 1) * (finalheight - 1) * 2;
out->data_vertex3f = Mem_Alloc(loadmodel->mempool, sizeof(float[20]) * finalvertices);
out->data_svector3f = out->data_vertex3f + finalvertices * 3;
out->data_tvector3f = out->data_svector3f + finalvertices * 3;
Con_Printf("Mod_Q3BSP_LoadFaces: %ix%i curve subdivided to %i vertices / %i triangles\n", patchsize[0], patchsize[1], out->num_vertices, out->num_triangles);
}
// q3map does not put in collision brushes for curves... ugh
+ // build the lower quality collision geometry
out->collisions = true;
+ xlevel = QuadraticSplinePatchSubdivisionLevelOnX(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_collision_tolerance.value, 10);
+ ylevel = QuadraticSplinePatchSubdivisionLevelOnY(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_collision_tolerance.value, 10);
+ // bound to user settings
+ xlevel = bound(r_subdivisions_collision_minlevel.integer, xlevel, r_subdivisions_collision_maxlevel.integer);
+ ylevel = bound(r_subdivisions_collision_minlevel.integer, ylevel, r_subdivisions_collision_maxlevel.integer);
+ // bound to sanity settings
+ xlevel = bound(0, xlevel, 10);
+ ylevel = bound(0, ylevel, 10);
+ // bound to user limit on vertices
+ while ((xlevel > 0 || ylevel > 0) && (((patchsize[0] - 1) << xlevel) + 1) * (((patchsize[1] - 1) << ylevel) + 1) > min(r_subdivisions_collision_maxvertices.integer, 262144))
+ {
+ if (xlevel > ylevel)
+ xlevel--;
+ else
+ ylevel--;
+ }
+ finalwidth = ((patchsize[0] - 1) << xlevel) + 1;
+ finalheight = ((patchsize[1] - 1) << ylevel) + 1;
+ finalvertices = finalwidth * finalheight;
+ finaltriangles = (finalwidth - 1) * (finalheight - 1) * 2;
+ out->data_collisionvertex3f = Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * finalvertices);
+ out->data_collisionelement3i = Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * finaltriangles);
+ out->num_collisionvertices = finalvertices;
+ out->num_collisiontriangles = finaltriangles;
+ QuadraticSplinePatchSubdivideFloatBuffer(patchsize[0], patchsize[1], xlevel, ylevel, 3, originalvertex3f, out->data_collisionvertex3f);
+ // generate elements
+ e = out->data_collisionelement3i;
+ for (y = 0;y < finalheight - 1;y++)
+ {
+ row0 = (y + 0) * finalwidth;
+ row1 = (y + 1) * finalwidth;
+ for (x = 0;x < finalwidth - 1;x++)
+ {
+ *e++ = row0;
+ *e++ = row1;
+ *e++ = row0 + 1;
+ *e++ = row1;
+ *e++ = row1 + 1;
+ *e++ = row0 + 1;
+ row0++;
+ row1++;
+ }
+ }
+ out->num_collisiontriangles = Mod_RemoveDegenerateTriangles(out->num_collisiontriangles, out->data_collisionelement3i, out->data_collisionelement3i, out->data_collisionvertex3f);
+ if (developer.integer)
+ {
+ if (out->num_collisiontriangles < finaltriangles)
+ Con_Printf("Mod_Q3BSP_LoadFaces: %ix%i curve subdivided for collisions to %i vertices / %i triangles, %i degenerate triangles removed (leaving %i)\n", patchsize[0], patchsize[1], out->num_collisionvertices, finaltriangles, finaltriangles - out->num_collisiontriangles, out->num_collisiontriangles);
+ else
+ Con_Printf("Mod_Q3BSP_LoadFaces: %ix%i curve subdivided for collisions to %i vertices / %i triangles\n", patchsize[0], patchsize[1], out->num_collisionvertices, out->num_collisiontriangles);
+ }
break;
case Q3FACETYPE_FLARE:
Con_DPrintf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): Q3FACETYPE_FLARE not supported (yet)\n", i, out->texture->name);
if (face->collisions && face->collisionmarkframe != markframe && BoxesOverlap(nodesegmentmins, nodesegmentmaxs, face->mins, face->maxs))
{
face->collisionmarkframe = markframe;
- Collision_TraceLineTriangleMeshFloat(trace, linestart, lineend, face->num_triangles, face->data_element3i, face->data_vertex3f, face->texture->supercontents, segmentmins, segmentmaxs);
+ Collision_TraceLineTriangleMeshFloat(trace, linestart, lineend, face->num_collisiontriangles, face->data_collisionelement3i, face->data_collisionvertex3f, face->texture->supercontents, segmentmins, segmentmaxs);
if (startfrac > trace->realfraction)
return;
}
if (face->collisions && face->markframe != markframe && BoxesOverlap(nodesegmentmins, nodesegmentmaxs, face->mins, face->maxs))
{
face->markframe = markframe;
- Collision_TraceBrushTriangleMeshFloat(trace, thisbrush_start, thisbrush_end, face->num_triangles, face->data_element3i, face->data_vertex3f, face->texture->supercontents, segmentmins, segmentmaxs);
+ Collision_TraceBrushTriangleMeshFloat(trace, thisbrush_start, thisbrush_end, face->num_collisiontriangles, face->data_collisionelement3i, face->data_collisionvertex3f, face->texture->supercontents, segmentmins, segmentmaxs);
}
}
}
{
face = model->brushq3.data_thismodel->firstface + i;
if (face->collisions)
- Collision_TraceLineTriangleMeshFloat(trace, boxstartmins, boxendmins, face->num_triangles, face->data_element3i, face->data_vertex3f, face->texture->supercontents, segmentmins, segmentmaxs);
+ Collision_TraceLineTriangleMeshFloat(trace, boxstartmins, boxendmins, face->num_collisiontriangles, face->data_collisionelement3i, face->data_collisionvertex3f, face->texture->supercontents, segmentmins, segmentmaxs);
}
}
}
{
face = model->brushq3.data_thismodel->firstface + i;
if (face->collisions)
- Collision_TraceBrushTriangleMeshFloat(trace, thisbrush_start, thisbrush_end, face->num_triangles, face->data_element3i, face->data_vertex3f, face->texture->supercontents, segmentmins, segmentmaxs);
+ Collision_TraceBrushTriangleMeshFloat(trace, thisbrush_start, thisbrush_end, face->num_collisiontriangles, face->data_collisionelement3i, face->data_collisionvertex3f, face->texture->supercontents, segmentmins, segmentmaxs);
}
}
}
{
int bytes = model->brush.num_pvsclusterbytes;
bytes = min(bytes, pvsbufferlength);
- if (r_novis.integer || !loadmodel->brush.num_pvsclusters)
+ if (r_novis.integer || !loadmodel->brush.num_pvsclusters || !Mod_Q3BSP_GetPVS(model, org))
{
memset(pvsbuffer, 0xFF, bytes);
return bytes;
return nativecontents;
}
+/*
+void Mod_Q3BSP_RecursiveGetVisible(q3mnode_t *node, model_t *model, const vec3_t point, const vec3_t mins, const vec3_t maxs, int maxleafs, q3mleaf_t *leaflist, int *numleafs, int maxsurfaces, q3msurface_t *surfacelist, int *numsurfaces, const qbyte *pvs)
+{
+ mleaf_t *leaf;
+ for (;;)
+ {
+ if (!BoxesOverlap(node->mins, node->maxs, mins, maxs))
+ return;
+ if (!node->plane)
+ break;
+ Mod_Q3BSP_RecursiveGetVisible(node->children[0], model, point, mins, maxs, maxleafs, leaflist, numleafs, maxsurfaces, surfacelist, numsurfaces, pvs);
+ node = node->children[1];
+ }
+ leaf = (mleaf_t *)node;
+ if ((pvs == NULL || CHECKPVSBIT(pvs, leaf->clusterindex)))
+ {
+ int marksurfacenum;
+ q3mface_t *surf;
+ if (maxleafs && *numleafs < maxleafs)
+ leaflist[(*numleaf)++] = leaf;
+ if (maxsurfaces)
+ {
+ for (marksurfacenum = 0;marksurfacenum < leaf->nummarksurfaces;marksurfacenum++)
+ {
+ face = leaf->firstleafface[marksurfacenum];
+ if (face->shadowmark != shadowmarkcount)
+ {
+ face->shadowmark = shadowmarkcount;
+ if (BoxesOverlap(mins, maxs, face->mins, face->maxs) && *numsurfaces < maxsurfaces)
+ surfacelist[(*numsurfaces)++] = face;
+ }
+ }
+ }
+ }
+}
+
+void Mod_Q3BSP_GetVisible(model_t *model, const vec3_t point, const vec3_t mins, const vec3_t maxs, int maxleafs, q3mleaf_t *leaflist, int *numleafs, int maxsurfaces, q3msurface_t *surfacelist, int *numsurfaces)
+{
+ // FIXME: support portals
+ if (maxsurfaces)
+ *numsurfaces = 0;
+ if (maxleafs)
+ *numleafs = 0;
+ if (model->submodel)
+ {
+ if (maxsurfaces)
+ {
+ for (marksurfacenum = 0;marksurfacenum < leaf->nummarksurfaces;marksurfacenum++)
+ {
+ face = ent->model->brushq3.surfaces + leaf->firstmarksurface[marksurfacenum];
+ if (BoxesOverlap(mins, maxs, face->mins, face->maxs) && *numsurfaces < maxsurfaces)
+ surfacelist[(*numsurfaces)++] = face;
+ }
+ }
+ }
+ else
+ {
+ pvs = ent->model->brush.GetPVS(ent->model, relativelightorigin);
+ Mod_Q3BSP_RecursiveGetVisible(ent->model->brushq3.data_nodes, model, point, mins, maxs, maxleafs, leaflist, numleafs, maxsurfaces, surfacelist, numsurfaces, pvs);
+ }
+}
+*/
+
extern void R_Q3BSP_DrawSky(struct entity_render_s *ent);
extern void R_Q3BSP_Draw(struct entity_render_s *ent);
extern void R_Q3BSP_DrawShadowVolume(struct entity_render_s *ent, vec3_t relativelightorigin, float lightradius);
extern void R_Q3BSP_DrawLight(struct entity_render_s *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *lightcubemap);
void Mod_Q3BSP_Load(model_t *mod, void *buffer)
{
- int i, j;
+ int i, j, numshadowmeshtriangles;
q3dheader_t *header;
float corner[3], yawradius, modelradius;
+ q3mface_t *face;
mod->type = mod_brushq3;
mod->numframes = 1;
Mod_Q3BSP_LoadPVS(&header->lumps[Q3LUMP_PVS]);
loadmodel->brush.numsubmodels = loadmodel->brushq3.num_models;
+ // make a single combined shadow mesh to allow optimized shadow volume creation
+ numshadowmeshtriangles = 0;
+ for (j = 0, face = loadmodel->brushq3.data_faces;j < loadmodel->brushq3.num_faces;j++, face++)
+ {
+ face->num_firstshadowmeshtriangle = numshadowmeshtriangles;
+ numshadowmeshtriangles += face->num_triangles;
+ }
+ loadmodel->brush.shadowmesh = Mod_ShadowMesh_Begin(loadmodel->mempool, numshadowmeshtriangles * 3, numshadowmeshtriangles, NULL, NULL, NULL, false, false, true);
+ for (j = 0, face = loadmodel->brushq3.data_faces;j < loadmodel->brushq3.num_faces;j++, face++)
+ Mod_ShadowMesh_AddMesh(loadmodel->mempool, loadmodel->brush.shadowmesh, NULL, NULL, NULL, face->data_vertex3f, NULL, NULL, NULL, NULL, face->num_triangles, face->data_element3i);
+ loadmodel->brush.shadowmesh = Mod_ShadowMesh_Finish(loadmodel->mempool, loadmodel->brush.shadowmesh, false, true);
+ Mod_BuildTriangleNeighbors(loadmodel->brush.shadowmesh->neighbor3i, loadmodel->brush.shadowmesh->element3i, loadmodel->brush.shadowmesh->numtriangles);
+
for (i = 0;i < loadmodel->brushq3.num_models;i++)
{
if (i == 0)
// textures and memory belong to the main model
mod->texturepool = NULL;
mod->mempool = NULL;
+ mod->brush.GetPVS = NULL;
+ mod->brush.FatPVS = NULL;
+ mod->brush.BoxTouchingPVS = NULL;
+ mod->brush.LightPoint = NULL;
+ mod->brush.FindNonSolidLocation = Mod_Q3BSP_FindNonSolidLocation;
}
mod->brushq3.data_thismodel = loadmodel->brushq3.data_models + i;
mod->brushq3.submodel = i;