From d3b158411b1d81181e05f750d9a7b0b2268438e2 Mon Sep 17 00:00:00 2001 From: havoc Date: Wed, 13 Aug 2003 23:08:58 +0000 Subject: [PATCH] no time to explain, more changes on the path to q3bsp support git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@3394 d7cf8633-e32d-0410-b094-e92efae38249 --- cl_particles.c | 4 +- collision.c | 382 ------------------------------------------------- collision.h | 34 ----- gl_rmain.c | 360 +++------------------------------------------- gl_rsurf.c | 44 ++++-- model_brush.c | 365 +++++++++++----------------------------------- model_shared.h | 18 ++- pr_cmds.c | 2 +- r_light.c | 12 +- r_shadow.c | 228 +++++------------------------ r_shadow.h | 3 - render.h | 5 +- snd_dma.c | 8 +- sv_main.c | 27 +--- todo | 90 ++++++------ world.c | 10 +- 16 files changed, 249 insertions(+), 1343 deletions(-) diff --git a/cl_particles.c b/cl_particles.c index 08745192..e03b0e36 100644 --- a/cl_particles.c +++ b/cl_particles.c @@ -163,9 +163,9 @@ float CL_TraceLine (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal, int trace.fraction = 1; VectorCopy (end, trace.endpos); #if QW - PM_RecursiveHullCheck (cl.model_precache[1]->brushq1.hulls, 0, 0, 1, start, end, &trace); + PM_RecursiveHullCheck (cl.model_precache[1]->hulls, 0, 0, 1, start, end, &trace); #else - RecursiveHullCheck (cl.worldmodel->brushq1.hulls, 0, 0, 1, start, end, &trace); + RecursiveHullCheck (cl.worldmodel->hulls, 0, 0, 1, start, end, &trace); #endif VectorCopy(trace.endpos, impact); VectorCopy(trace.plane.normal, normal); diff --git a/collision.c b/collision.c index ef8e06f0..4936e2d4 100644 --- a/collision.c +++ b/collision.c @@ -206,39 +206,6 @@ static void RecursiveHullCheckPoint (RecursiveHullCheckTraceInfo_t *t, int num) } #endif -void Collision_RoundUpToHullSize(const model_t *cmodel, const vec3_t inmins, const vec3_t inmaxs, vec3_t outmins, vec3_t outmaxs) -{ - vec3_t size; - const hull_t *hull; - - VectorSubtract(inmaxs, inmins, size); - if (cmodel->brushq1.ishlbsp) - { - if (size[0] < 3) - hull = &cmodel->brushq1.hulls[0]; // 0x0x0 - else if (size[0] <= 32) - { - if (size[2] < 54) // pick the nearest of 36 or 72 - hull = &cmodel->brushq1.hulls[3]; // 32x32x36 - else - hull = &cmodel->brushq1.hulls[1]; // 32x32x72 - } - else - hull = &cmodel->brushq1.hulls[2]; // 64x64x64 - } - else - { - if (size[0] < 3) - hull = &cmodel->brushq1.hulls[0]; // 0x0x0 - else if (size[0] <= 32) - hull = &cmodel->brushq1.hulls[1]; // 32x32x56 - else - hull = &cmodel->brushq1.hulls[2]; // 64x64x88 - } - VectorCopy(inmins, outmins); - VectorAdd(inmins, hull->clip_size, outmaxs); -} - static hull_t box_hull; static dclipnode_t box_clipnodes[6]; static mplane_t box_planes[6]; @@ -562,301 +529,6 @@ void Collision_TraceBrushPolygonTransformFloat(trace_t *trace, const colbrushf_t Collision_TraceBrushBrushFloat(trace, thisbrush_start, thisbrush_end, &polyf_brushstart, &polyf_brushend); } -colbrushd_t *Collision_AllocBrushDouble(mempool_t *mempool, int numpoints, int numplanes) -{ - colbrushd_t *brush; - brush = Mem_Alloc(mempool, sizeof(colbrushd_t) + sizeof(colpointd_t) * numpoints + sizeof(colplaned_t) * numplanes); - brush->numpoints = numpoints; - brush->numplanes = numplanes; - brush->planes = (void *)(brush + 1); - brush->points = (void *)(brush->planes + brush->numplanes); - return brush; -} - -void Collision_CalcPlanesForPolygonBrushDouble(colbrushd_t *brush) -{ - int i; - double edge0[3], edge1[3], normal[3], dist, bestdist; - colpointd_t *p, *p2; - - // choose best surface normal for polygon's plane - bestdist = 0; - for (i = 2, p = brush->points + 2;i < brush->numpoints;i++, p++) - { - VectorSubtract(p[-1].v, p[0].v, edge0); - VectorSubtract(p[1].v, p[0].v, edge1); - CrossProduct(edge0, edge1, normal); - dist = DotProduct(normal, normal); - if (i == 2 || bestdist < dist) - { - bestdist = dist; - VectorCopy(normal, brush->planes->normal); - } - } - - VectorNormalize(brush->planes->normal); - brush->planes->dist = DotProduct(brush->points->v, brush->planes->normal); - - // negate plane to create other side - VectorNegate(brush->planes[0].normal, brush->planes[1].normal); - brush->planes[1].dist = -brush->planes[0].dist; - for (i = 0, p = brush->points + (brush->numpoints - 1), p2 = brush->points + 2;i < brush->numpoints;i++, p = p2, p2++) - { - VectorSubtract(p->v, p2->v, edge0); - CrossProduct(edge0, brush->planes->normal, brush->planes[i].normal); - VectorNormalize(brush->planes[i].normal); - brush->planes[i].dist = DotProduct(p->v, brush->planes[i].normal); - } - -#if 1 - // validity check - will be disabled later - for (i = 0;i < brush->numplanes;i++) - { - int j; - for (j = 0, p = brush->points;j < brush->numpoints;j++, p++) - if (DotProduct(p->v, brush->planes[i].normal) > brush->planes[i].dist + (1.0 / 32.0)) - Con_Printf("Error in brush plane generation, plane %i\n"); - } -#endif -} - -colbrushd_t *Collision_AllocBrushFromPermanentPolygonDouble(mempool_t *mempool, int numpoints, double *points) -{ - colbrushd_t *brush; - brush = Mem_Alloc(mempool, sizeof(colbrushd_t) + sizeof(colplaned_t) * (numpoints + 2)); - brush->numpoints = numpoints; - brush->numplanes = numpoints + 2; - brush->planes = (void *)(brush + 1); - brush->points = (colpointd_t *)points; - return brush; -} - - -double nearestplanedist_double(const double *normal, const colpointd_t *points, int numpoints) -{ - double dist, bestdist; - bestdist = DotProduct(points->v, normal); - points++; - while(--numpoints) - { - dist = DotProduct(points->v, normal); - if (bestdist > dist) - bestdist = dist; - points++; - } - return bestdist; -} - -double furthestplanedist_double(const double *normal, const colpointd_t *points, int numpoints) -{ - double dist, bestdist; - bestdist = DotProduct(points->v, normal); - points++; - while(--numpoints) - { - dist = DotProduct(points->v, normal); - if (bestdist < dist) - bestdist = dist; - points++; - } - return bestdist; -} - -// NOTE: start and end of each brush pair must have same numplanes/numpoints -void Collision_TraceBrushBrushDouble(trace_t *trace, const colbrushd_t *thisbrush_start, const colbrushd_t *thisbrush_end, const colbrushd_t *thatbrush_start, const colbrushd_t *thatbrush_end) -{ - int nplane, nplane2, fstartsolid, fendsolid; - double enterfrac, leavefrac, d1, d2, f, newimpactnormal[3]; - const colplaned_t *startplane, *endplane; - - enterfrac = -1; - leavefrac = 1; - fstartsolid = true; - fendsolid = true; - - for (nplane = 0;nplane < thatbrush_start->numplanes + thisbrush_start->numplanes;nplane++) - { - nplane2 = nplane; - if (nplane2 >= thatbrush_start->numplanes) - { - nplane2 -= thatbrush_start->numplanes; - startplane = thisbrush_start->planes + nplane2; - endplane = thisbrush_end->planes + nplane2; - } - else - { - startplane = thatbrush_start->planes + nplane2; - endplane = thatbrush_end->planes + nplane2; - } - d1 = nearestplanedist_double(startplane->normal, thisbrush_start->points, thisbrush_start->numpoints) - furthestplanedist_double(startplane->normal, thatbrush_start->points, thatbrush_start->numpoints); - d2 = nearestplanedist_double(endplane->normal, thisbrush_end->points, thisbrush_end->numpoints) - furthestplanedist_double(endplane->normal, thatbrush_end->points, thatbrush_end->numpoints) - COLLISIONEPSILON2; - //Con_Printf("%c%i: d1 = %f, d2 = %f, d1 / (d1 - d2) = %f\n", nplane2 != nplane ? 'b' : 'a', nplane2, d1, d2, d1 / (d1 - d2)); - - f = d1 - d2; - if (f >= 0) - { - // moving into brush - if (d2 > 0) - return; - if (d1 < 0) - continue; - // enter - fstartsolid = false; - f = (d1 - COLLISIONEPSILON) / f; - f = bound(0, f, 1); - if (enterfrac < f) - { - enterfrac = f; - VectorBlend(startplane->normal, endplane->normal, enterfrac, newimpactnormal); - } - } - else if (f < 0) - { - // moving out of brush - if (d1 > 0) - return; - if (d2 < 0) - continue; - // leave - fendsolid = false; - f = (d1 + COLLISIONEPSILON) / f; - f = bound(0, f, 1); - if (leavefrac > f) - leavefrac = f; - } - } - - if (fstartsolid) - { - trace->startsolid = true; - if (fendsolid) - trace->allsolid = true; - } - - // LordHavoc: we need an epsilon nudge here because for a point trace the - // penetrating line segment is normally zero length if this brush was - // generated from a polygon (infinitely thin), and could even be slightly - // positive or negative due to rounding errors in that case. - if (enterfrac > -1 && enterfrac < trace->fraction && enterfrac - (1.0f / 1024.0f) <= leavefrac) - { - trace->fraction = bound(0, enterfrac, 1); - VectorCopy(newimpactnormal, trace->plane.normal); - } -} - -static colplaned_t polyd_planes[256 + 2]; -static colbrushd_t polyd_brush; -void Collision_TraceBrushPolygonDouble(trace_t *trace, const colbrushd_t *thisbrush_start, const colbrushd_t *thisbrush_end, int numpoints, const double *points) -{ - if (numpoints > 256) - { - Con_Printf("Polygon with more than 256 points not supported yet (fixme!)\n"); - return; - } - polyd_brush.numpoints = numpoints; - polyd_brush.numplanes = numpoints + 2; - polyd_brush.points = (colpointd_t *)points; - polyd_brush.planes = polyd_planes; - Collision_CalcPlanesForPolygonBrushDouble(&polyd_brush); - Collision_TraceBrushBrushDouble(trace, thisbrush_start, thisbrush_end, &polyd_brush, &polyd_brush); -} - - - - -typedef struct colbrushbmodelinfo_s -{ - model_t *model; - trace_t *trace; - const matrix4x4_t *modelmatrixstart; - const matrix4x4_t *modelmatrixend; - const colbrushf_t *thisbrush_start; - const colbrushf_t *thisbrush_end; -} -colbrushbmodelinfo_t; - -static int colframecount = 1; - -void Collision_RecursiveTraceBrushNode(colbrushbmodelinfo_t *info, mnode_t *node) -{ - if (node->contents) - { - // collide with surfaces marked by this leaf - int i, *mark; - mleaf_t *leaf = (mleaf_t *)node; - msurface_t *surf; - for (i = 0, mark = leaf->firstmarksurface;i < leaf->nummarksurfaces;i++, mark++) - { - surf = info->model->brushq1.surfaces + *mark; - // don't check a surface twice - if (surf->colframe != colframecount) - { - surf->colframe = colframecount; - if (surf->flags & SURF_SOLIDCLIP) - { - Collision_TraceBrushPolygonFloat(info->trace, info->thisbrush_start, info->thisbrush_end, surf->poly_numverts, surf->poly_verts); - //Collision_TraceBrushPolygonTransformFloat(info->trace, info->thisbrush_start, info->thisbrush_end, surf->poly_numverts, surf->poly_verts, info->modelmatrixstart, info->modelmatrixend); - } - } - } - } - else - { - // recurse down node sides - int i; - float dist; - colpointf_t *ps, *pe; - // FIXME? if TraceBrushPolygonTransform were to be made usable, the - // node planes would need to be transformed too - dist = node->plane->dist - (1.0f / 8.0f); - for (i = 0, ps = info->thisbrush_start->points, pe = info->thisbrush_end->points;i < info->thisbrush_start->numpoints;i++, ps++, pe++) - { - if (DotProduct(ps->v, node->plane->normal) > dist || DotProduct(pe->v, node->plane->normal) > dist) - { - Collision_RecursiveTraceBrushNode(info, node->children[0]); - break; - } - } - dist = node->plane->dist + (1.0f / 8.0f); - for (i = 0, ps = info->thisbrush_start->points, pe = info->thisbrush_end->points;i < info->thisbrush_start->numpoints;i++, ps++, pe++) - { - if (DotProduct(ps->v, node->plane->normal) < dist || DotProduct(pe->v, node->plane->normal) < dist) - { - Collision_RecursiveTraceBrushNode(info, node->children[1]); - break; - } - } - } -} - -void Collision_TraceBrushBModel(trace_t *trace, const colbrushf_t *thisbrush_start, const colbrushf_t *thisbrush_end, model_t *model) -{ - colbrushbmodelinfo_t info; - colframecount++; - memset(trace, 0, sizeof(*trace)); - trace->fraction = 1; - info.trace = trace; - info.model = model; - info.thisbrush_start = thisbrush_start; - info.thisbrush_end = thisbrush_end; - Collision_RecursiveTraceBrushNode(&info, model->brushq1.nodes + model->brushq1.hulls[0].firstclipnode); -} - -void Collision_TraceBrushBModelTransform(trace_t *trace, const colbrushf_t *thisbrush_start, const colbrushf_t *thisbrush_end, model_t *model, const matrix4x4_t *modelmatrixstart, const matrix4x4_t *modelmatrixend) -{ - colbrushbmodelinfo_t info; - colframecount++; - memset(trace, 0, sizeof(*trace)); - trace->fraction = 1; - info.trace = trace; - info.model = model; - info.modelmatrixstart = modelmatrixstart; - info.modelmatrixend = modelmatrixend; - info.thisbrush_start = thisbrush_start; - info.thisbrush_end = thisbrush_end; - Collision_RecursiveTraceBrushNode(&info, model->brushq1.nodes + model->brushq1.hulls[0].firstclipnode); -} - #define MAX_BRUSHFORBOX 16 @@ -905,60 +577,6 @@ colbrushf_t *Collision_BrushForBox(const matrix4x4_t *matrix, const vec3_t mins, return brush; } -void Collision_PolygonClipTrace (trace_t *trace, const void *cent, model_t *cmodel, const vec3_t corigin, const vec3_t cangles, const vec3_t cmins, const vec3_t cmaxs, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end) -{ - vec3_t impactnormal; - //vec3_t mins2, maxs2; - matrix4x4_t cmatrix, cimatrix, startmatrix, endmatrix; - matrix4x4_t mstartmatrix, mendmatrix, identitymatrix; - colbrushf_t *thisbrush_start, *thisbrush_end, *cbrush; - - Matrix4x4_CreateFromQuakeEntity(&cmatrix, corigin[0], corigin[1], corigin[2], cangles[0], cangles[1], cangles[2], 1); - Matrix4x4_Invert_Simple(&cimatrix, &cmatrix); - Matrix4x4_CreateTranslate(&startmatrix, start[0], start[1], start[2]); - Matrix4x4_CreateTranslate(&endmatrix, end[0], end[1], end[2]); - - Matrix4x4_CreateIdentity(&identitymatrix); - Matrix4x4_Concat(&mstartmatrix, &cimatrix, &startmatrix); - Matrix4x4_Concat(&mendmatrix, &cimatrix, &endmatrix); - thisbrush_start = Collision_BrushForBox(&mstartmatrix, mins, maxs); - //mins2[0] = mins[0] - 0.0625;mins2[1] = mins[1] - 0.0625;mins2[2] = mins[2] - 0.0625; - //maxs2[0] = maxs[0] + 0.0625;maxs2[1] = maxs[1] + 0.0625;maxs2[2] = maxs[2] + 0.0625; - thisbrush_end = Collision_BrushForBox(&mendmatrix, mins, maxs); - - //Collision_PrintBrushAsQHull(thisbrush_start, "thisbrush_start"); - //Collision_PrintBrushAsQHull(thisbrush_end, "thisbrush_end"); - memset (trace, 0, sizeof(trace_t)); - if (cmodel && cmodel->type == mod_brush) - { - // brush model - Collision_TraceBrushBModel(trace, thisbrush_start, thisbrush_end, cmodel); - //Collision_TraceBrushBModelTransform(trace, thisbrush_start, thisbrush_end, cmodel, &cmatrix, &cmatrix); - } - else - { - // bounding box - cbrush = Collision_BrushForBox(&identitymatrix, cmins, cmaxs); - Collision_TraceBrushBrushFloat(trace, thisbrush_start, thisbrush_end, cbrush, cbrush); - //cbrush = Collision_BrushForBox(&cmatrix, cmins, cmaxs); - //trace->fraction = Collision_TraceBrushBrushFloat(trace, thisbrush_start, thisbrush_end, cbrush, cbrush); - } - - if (trace->fraction < 0 || trace->fraction > 1) - Con_Printf("fraction out of bounds %f %s:%d\n", trace->fraction, __FILE__, __LINE__); - - VectorBlend(start, end, trace->fraction, trace->endpos); - if (trace->fraction < 1) - { - trace->ent = (void *) cent; - VectorCopy(trace->plane.normal, impactnormal); - Matrix4x4_Transform(&cmatrix, impactnormal, trace->plane.normal); - VectorNormalize(trace->plane.normal); - //Con_Printf("fraction %f normal %f %f %f\n", trace->fraction, trace->plane.normal[0], trace->plane.normal[1], trace->plane.normal[2]); - } -} - - // LordHavoc: currently unused and not yet tested // note: this can be used for tracing a moving sphere vs a stationary sphere, // by simply adding the moving sphere's radius to the sphereradius parameter, diff --git a/collision.h b/collision.h index 0e746e4e..dfc02ff1 100644 --- a/collision.h +++ b/collision.h @@ -36,7 +36,6 @@ typedef struct trace_s } trace_t; -void Collision_RoundUpToHullSize(const model_t *cmodel, const vec3_t inmins, const vec3_t inmaxs, vec3_t outmins, vec3_t outmaxs); void Collision_Init(void); void Collision_ClipTrace_Box(trace_t *trace, const vec3_t cmins, const vec3_t cmaxs, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end); @@ -69,39 +68,6 @@ void Collision_TraceBrushBrushFloat(trace_t *trace, const colbrushf_t *thisbrush void Collision_TraceBrushPolygonFloat(trace_t *trace, const colbrushf_t *thisbrush_start, const colbrushf_t *thisbrush_end, int numpoints, const float *points); void Collision_TraceBrushPolygonTransformFloat(trace_t *trace, const colbrushf_t *thisbrush_start, const colbrushf_t *thisbrush_end, int numpoints, const float *points, const matrix4x4_t *polygonmatrixstart, const matrix4x4_t *polygonmatrixend); -typedef struct colpointd_s -{ - double v[3]; -} -colpointd_t; - -typedef struct colplaned_s -{ - double normal[3]; - double dist; -} -colplaned_t; - -typedef struct colbrushd_s -{ - int numplanes; - int numpoints; - colplaned_t *planes; - colpointd_t *points; -} -colbrushd_t; - -colbrushd_t *Collision_AllocBrushDouble(mempool_t *mempool, int numpoints, int numplanes); -void Collision_CalcPlanesForPolygonBrushDouble(colbrushd_t *brush); -colbrushd_t *Collision_AllocBrushFromPermanentPolygonDouble(mempool_t *mempool, int numpoints, double *points); -void Collision_TraceBrushBrushDouble(trace_t *trace, const colbrushd_t *thisbrush_start, const colbrushd_t *thisbrush_end, const colbrushd_t *thatbrush_start, const colbrushd_t *thatbrush_end); -void Collision_TraceBrushPolygonDouble(trace_t *trace, const colbrushd_t *thisbrush_start, const colbrushd_t *thisbrush_end, int numpoints, const double *points); - -void Collision_TraceBrushBModel(trace_t *trace, const colbrushf_t *thisbrush_start, const colbrushf_t *thisbrush_end, model_t *model); -void Collision_TraceBrushBModelTransform(trace_t *trace, const colbrushf_t *thisbrush_start, const colbrushf_t *thisbrush_end, model_t *model, const matrix4x4_t *modelmatrixstart, const matrix4x4_t *modelmatrixend); - -void Collision_PolygonClipTrace(trace_t *trace, const void *cent, model_t *cmodel, const vec3_t corigin, const vec3_t cangles, const vec3_t cmins, const vec3_t cmaxs, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end); - colbrushf_t *Collision_BrushForBox(const matrix4x4_t *matrix, const vec3_t mins, const vec3_t maxs); #endif diff --git a/gl_rmain.c b/gl_rmain.c index 8c24694b..5df08491 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -24,6 +24,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // used for dlight push checking and other things int r_framecount; +// used for visibility checking +qbyte r_pvsbits[(MAX_MAP_LEAFS+7)>>3]; + mplane_t frustum[4]; matrix4x4_t r_identitymatrix; @@ -397,132 +400,7 @@ int R_CullBox(const vec3_t mins, const vec3_t maxs) return false; } -int PVS_CullBox(const vec3_t mins, const vec3_t maxs) -{ - int stackpos, sides; - mnode_t *node, *stack[4096]; - if (cl.worldmodel == NULL) - return false; - stackpos = 0; - stack[stackpos++] = cl.worldmodel->brushq1.nodes; - while (stackpos) - { - node = stack[--stackpos]; - if (node->contents < 0) - { - if (((mleaf_t *)node)->pvsframe == cl.worldmodel->brushq1.pvsframecount) - return false; - } - else - { - sides = BoxOnPlaneSide(mins, maxs, node->plane); - if (sides & 2 && stackpos < 4096) - stack[stackpos++] = node->children[1]; - if (sides & 1 && stackpos < 4096) - stack[stackpos++] = node->children[0]; - } - } - return true; -} - -int VIS_CullBox(const vec3_t mins, const vec3_t maxs) -{ - int stackpos, sides; - mnode_t *node, *stack[4096]; - if (R_CullBox(mins, maxs)) - return true; - if (cl.worldmodel == NULL) - return false; - stackpos = 0; - stack[stackpos++] = cl.worldmodel->brushq1.nodes; - while (stackpos) - { - node = stack[--stackpos]; - if (node->contents < 0) - { - if (((mleaf_t *)node)->visframe == r_framecount) - return false; - } - else - { - sides = BoxOnPlaneSide(mins, maxs, node->plane); - if (sides & 2 && stackpos < 4096) - stack[stackpos++] = node->children[1]; - if (sides & 1 && stackpos < 4096) - stack[stackpos++] = node->children[0]; - } - } - return true; -} - -int R_CullSphere(const vec3_t origin, vec_t radius) -{ - return (DotProduct(frustum[0].normal, origin) + radius < frustum[0].dist - || DotProduct(frustum[1].normal, origin) + radius < frustum[1].dist - || DotProduct(frustum[2].normal, origin) + radius < frustum[2].dist - || DotProduct(frustum[3].normal, origin) + radius < frustum[3].dist); -} - -int PVS_CullSphere(const vec3_t origin, vec_t radius) -{ - int stackpos; - mnode_t *node, *stack[4096]; - float dist; - if (cl.worldmodel == NULL) - return false; - stackpos = 0; - stack[stackpos++] = cl.worldmodel->brushq1.nodes; - while (stackpos) - { - node = stack[--stackpos]; - if (node->contents < 0) - { - if (((mleaf_t *)node)->pvsframe == cl.worldmodel->brushq1.pvsframecount) - return false; - } - else - { - dist = PlaneDiff(origin, node->plane); - if (dist <= radius) - stack[stackpos++] = node->children[1]; - if (dist >= -radius) - stack[stackpos++] = node->children[0]; - } - } - return true; -} - -int VIS_CullSphere(const vec3_t origin, vec_t radius) -{ - int stackpos; - mnode_t *node, *stack[4096]; - float dist; - if (R_CullSphere(origin, radius)) - return true; - if (cl.worldmodel == NULL) - return false; - stackpos = 0; - stack[stackpos++] = cl.worldmodel->brushq1.nodes; - while (stackpos) - { - node = stack[--stackpos]; - if (node->contents < 0) - { - if (((mleaf_t *)node)->visframe == r_framecount) - return false; - } - else - { - dist = PlaneDiff(origin, node->plane); - if (dist <= radius) - stack[stackpos++] = node->children[1]; - if (dist >= -radius) - stack[stackpos++] = node->children[0]; - } - } - return true; -} - +#define VIS_CullBox(mins,maxs) (R_CullBox((mins), (maxs)) || (cl.worldmodel && cl.worldmodel->brush.BoxTouchingPVS && !cl.worldmodel->brush.BoxTouchingPVS(cl.worldmodel, r_pvsbits, (mins), (maxs)))) //================================================================================== @@ -552,7 +430,6 @@ static void R_MarkEntities (void) R_LerpAnimation(ent); R_UpdateEntLights(ent); if ((chase_active.integer || !(ent->flags & RENDER_EXTERIORMODEL)) - && !VIS_CullSphere(ent->origin, (ent->model != NULL ? ent->model->radius : 16) * ent->scale) && !VIS_CullBox(ent->mins, ent->maxs)) { ent->visframe = r_framecount; @@ -652,182 +529,21 @@ void R_DrawFakeShadows (void) int shadowframecount = 0; -int Light_CullBox(const vec3_t mins, const vec3_t maxs) -{ - int stackpos, sides; - mnode_t *node, *stack[4096]; - if (cl.worldmodel == NULL) - return false; - stackpos = 0; - stack[stackpos++] = cl.worldmodel->brushq1.nodes; - while (stackpos) - { - node = stack[--stackpos]; - if (node->contents < 0) - { - if (((mleaf_t *)node)->worldnodeframe == shadowframecount) - return false; - } - else - { - sides = BoxOnPlaneSide(mins, maxs, node->plane); - if (sides & 2 && stackpos < 4096) - stack[stackpos++] = node->children[1]; - if (sides & 1 && stackpos < 4096) - stack[stackpos++] = node->children[0]; - } - } - return true; -} - -int LightAndVis_CullBox(const vec3_t mins, const vec3_t maxs) -{ - int stackpos, sides; - mnode_t *node, *stack[4096]; - if (R_CullBox(mins, maxs)) - return true; - if (cl.worldmodel == NULL) - return false; - stackpos = 0; - stack[stackpos++] = cl.worldmodel->brushq1.nodes; - while (stackpos) - { - node = stack[--stackpos]; - if (node->contents < 0) - { - if (((mleaf_t *)node)->visframe == r_framecount && ((mleaf_t *)node)->worldnodeframe == shadowframecount) - return false; - } - else - { - sides = BoxOnPlaneSide(mins, maxs, node->plane); - if (sides & 2 && stackpos < 4096) - stack[stackpos++] = node->children[1]; - if (sides & 1 && stackpos < 4096) - stack[stackpos++] = node->children[0]; - } - } - return true; -} - -int LightAndVis_CullPointCloud(int numpoints, const float *points) -{ - int i; - const float *p; - int stackpos, sides; - mnode_t *node, *stack[4096]; - //if (R_CullBox(mins, maxs)) - // return true; - if (cl.worldmodel == NULL) - return false; - stackpos = 0; - stack[stackpos++] = cl.worldmodel->brushq1.nodes; - while (stackpos) - { - node = stack[--stackpos]; - if (node->contents < 0) - { - if (((mleaf_t *)node)->visframe == r_framecount && ((mleaf_t *)node)->worldnodeframe == shadowframecount) - return false; - } - else - { - sides = 0; - for (i = 0, p = points;i < numpoints && sides != 3;i++, p += 3) - { - if (DotProduct(p, node->plane->normal) < node->plane->dist) - sides |= 1; - else - sides |= 2; - } - if (sides & 2 && stackpos < 4096) - stack[stackpos++] = node->children[1]; - if (sides & 1 && stackpos < 4096) - stack[stackpos++] = node->children[0]; - } - } - return true; -} - - void R_TestAndDrawShadowVolume(entity_render_t *ent, vec3_t lightorigin, float cullradius, float lightradius, vec3_t lightmins, vec3_t lightmaxs, vec3_t clipmins, vec3_t clipmaxs, int lightmarked) { vec3_t relativelightorigin; - #if 0 - int i; - vec3_t temp; - float dist, projectdistance; - float points[16][3]; - #endif // rough checks - if (!(ent->flags & RENDER_SHADOW) || ent->model == NULL || ent->model->DrawShadowVolume == NULL) - return; - if (r_shadow_cull.integer) + if ((ent->flags & RENDER_SHADOW) && ent->model && ent->model->DrawShadowVolume && !(r_shadow_cull.integer && (ent->maxs[0] < lightmins[0] || ent->mins[0] > lightmaxs[0] || ent->maxs[1] < lightmins[1] || ent->mins[1] > lightmaxs[1] || ent->maxs[2] < lightmins[2] || ent->mins[2] > lightmaxs[2]))) { - if (ent->maxs[0] < lightmins[0] || ent->mins[0] > lightmaxs[0] - || ent->maxs[1] < lightmins[1] || ent->mins[1] > lightmaxs[1] - || ent->maxs[2] < lightmins[2] || ent->mins[2] > lightmaxs[2] - || (lightmarked && Light_CullBox(ent->mins, ent->maxs))) - return; + Matrix4x4_Transform(&ent->inversematrix, lightorigin, relativelightorigin); + ent->model->DrawShadowVolume (ent, relativelightorigin, lightradius); } - #if 0 - if (r_shadow_cull.integer) - { - projectdistance = cullradius; - // calculate projected bounding box and decide if it is on-screen - for (i = 0;i < 8;i++) - { - temp[0] = i & 1 ? ent->model->normalmaxs[0] : ent->model->normalmins[0]; - temp[1] = i & 2 ? ent->model->normalmaxs[1] : ent->model->normalmins[1]; - temp[2] = i & 4 ? ent->model->normalmaxs[2] : ent->model->normalmins[2]; - Matrix4x4_Transform(&ent->matrix, temp, points[i]); - VectorSubtract(points[i], lightorigin, temp); - dist = projectdistance / sqrt(DotProduct(temp, temp)); - VectorMA(lightorigin, dist, temp, points[i+8]); - } - if (LightAndVis_CullPointCloud(16, points[0])) - return; - /* - for (i = 0;i < 8;i++) - { - p2[0] = i & 1 ? ent->model->normalmaxs[0] : ent->model->normalmins[0]; - p2[1] = i & 2 ? ent->model->normalmaxs[1] : ent->model->normalmins[1]; - p2[2] = i & 4 ? ent->model->normalmaxs[2] : ent->model->normalmins[2]; - Matrix4x4_Transform(&ent->matrix, p2, p); - VectorSubtract(p, lightorigin, temp); - dist = projectdistance / sqrt(DotProduct(temp, temp)); - VectorMA(p, dist, temp, p2); - if (i) - { - if (mins[0] > p[0]) mins[0] = p[0];if (maxs[0] < p[0]) maxs[0] = p[0]; - if (mins[1] > p[1]) mins[1] = p[1];if (maxs[1] < p[1]) maxs[1] = p[1]; - if (mins[2] > p[2]) mins[2] = p[2];if (maxs[2] < p[2]) maxs[2] = p[2]; - } - else - { - VectorCopy(p, mins); - VectorCopy(p, maxs); - } - if (mins[0] > p2[0]) mins[0] = p2[0];if (maxs[0] < p2[0]) maxs[0] = p2[0]; - if (mins[1] > p2[1]) mins[1] = p2[1];if (maxs[1] < p2[1]) maxs[1] = p2[1]; - if (mins[2] > p2[2]) mins[2] = p2[2];if (maxs[2] < p2[2]) maxs[2] = p2[2]; - } - if (mins[0] >= clipmaxs[0] || maxs[0] <= clipmins[0] - || mins[1] >= clipmaxs[1] || maxs[1] <= clipmins[1] - || mins[2] >= clipmaxs[2] || maxs[2] <= clipmins[2] - || LightAndVis_CullBox(mins, maxs)) - return; - */ - } - #endif - Matrix4x4_Transform(&ent->inversematrix, lightorigin, relativelightorigin); - ent->model->DrawShadowVolume (ent, relativelightorigin, lightradius); } void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, worldlight_t *light); extern void R_Model_Brush_DrawLightForSurfaceList(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, msurface_t **surflist, int numsurfaces, const matrix4x4_t *matrix_modeltofilter, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz); -void R_ShadowVolumeLighting (int visiblevolumes) +void R_ShadowVolumeLighting(int visiblevolumes) { int i; entity_render_t *ent; @@ -837,7 +553,6 @@ void R_ShadowVolumeLighting (int visiblevolumes) worldlight_t *wl; rdlight_t *rd; rmeshstate_t m; - mleaf_t *leaf; matrix4x4_t matrix; matrix4x4_t matrix_worldtofilter, matrix_worldtoattenuationxyz, matrix_worldtoattenuationz; matrix4x4_t matrix_modeltofilter, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz; @@ -863,63 +578,17 @@ void R_ShadowVolumeLighting (int visiblevolumes) { if (d_lightstylevalue[wl->style] <= 0) continue; - if (R_CullBox(wl->mins, wl->maxs)) - //if (R_CullSphere(wl->origin, cullradius)) + if (VIS_CullBox(wl->mins, wl->maxs)) continue; - //if (R_CullBox(wl->mins, wl->maxs) || R_CullSphere(wl->origin, lightradius)) - // continue; - //if (VIS_CullBox(wl->mins, wl->maxs) || VIS_CullSphere(wl->origin, lightradius)) - // continue; if (r_shadow_debuglight.integer >= 0 && lnum != r_shadow_debuglight.integer) continue; + if (R_Shadow_ScissorForBBox(wl->mins, wl->maxs)) + continue; cullradius = wl->cullradius; lightradius = wl->lightradius; - - if (cl.worldmodel != NULL) - { - for (i = 0;i < wl->numleafs;i++) - if (wl->leafs[i]->visframe == r_framecount) - break; - if (i == wl->numleafs) - continue; - leaf = wl->leafs[i++]; - VectorCopy(leaf->mins, clipmins); - VectorCopy(leaf->maxs, clipmaxs); - for (;i < wl->numleafs;i++) - { - leaf = wl->leafs[i]; - if (leaf->visframe == r_framecount) - { - if (clipmins[0] > leaf->mins[0]) clipmins[0] = leaf->mins[0]; - if (clipmaxs[0] < leaf->maxs[0]) clipmaxs[0] = leaf->maxs[0]; - if (clipmins[1] > leaf->mins[1]) clipmins[1] = leaf->mins[1]; - if (clipmaxs[1] < leaf->maxs[1]) clipmaxs[1] = leaf->maxs[1]; - if (clipmins[2] > leaf->mins[2]) clipmins[2] = leaf->mins[2]; - if (clipmaxs[2] < leaf->maxs[2]) clipmaxs[2] = leaf->maxs[2]; - } - } - if (clipmins[0] < wl->mins[0]) clipmins[0] = wl->mins[0]; - if (clipmaxs[0] > wl->maxs[0]) clipmaxs[0] = wl->maxs[0]; - if (clipmins[1] < wl->mins[1]) clipmins[1] = wl->mins[1]; - if (clipmaxs[1] > wl->maxs[1]) clipmaxs[1] = wl->maxs[1]; - if (clipmins[2] < wl->mins[2]) clipmins[2] = wl->mins[2]; - if (clipmaxs[2] > wl->maxs[2]) clipmaxs[2] = wl->maxs[2]; - } - else - { - VectorCopy(wl->mins, clipmins); - VectorCopy(wl->maxs, clipmaxs); - } - - //if (R_Shadow_ScissorForBBoxAndSphere(clipmins, clipmaxs, wl->origin, wl->cullradius)) - if (R_CullBox(clipmins, clipmaxs) || R_Shadow_ScissorForBBox(clipmins, clipmaxs)) - continue; - - // mark the leafs we care about so only things in those leafs will matter - if (cl.worldmodel != NULL) - for (i = 0;i < wl->numleafs;i++) - wl->leafs[i]->worldnodeframe = shadowframecount; + VectorCopy(wl->mins, clipmins); + VectorCopy(wl->maxs, clipmaxs); f = d_lightstylevalue[wl->style] * (1.0f / 256.0f); VectorScale(wl->light, f, lightcolor); @@ -1213,6 +882,9 @@ void R_RenderView (void) R_BuildLightList(); R_TimeReport("setup"); + if (cl.worldmodel && cl.worldmodel->brush.FatPVS) + cl.worldmodel->brush.FatPVS(cl.worldmodel, r_origin, 2, r_pvsbits, sizeof(r_pvsbits)); + R_WorldVisibility(world); R_TimeReport("worldvis"); diff --git a/gl_rsurf.c b/gl_rsurf.c index fe81def5..4582d8ce 100644 --- a/gl_rsurf.c +++ b/gl_rsurf.c @@ -729,7 +729,7 @@ static void RSurfShader_Sky(const entity_render_t *ent, const texture_t *texture rmeshstate_t m; // LordHavoc: HalfLife maps have freaky skypolys... - if (ent->model->brushq1.ishlbsp) + if (ent->model->brush.ishlbsp) return; if (skyrendernow) @@ -1528,6 +1528,7 @@ static void R_DrawPortal_Callback(const void *calldata1, int calldata2) R_Mesh_Draw(portal->numpoints, portal->numpoints - 2, polygonelements); } +// LordHavoc: this is just a nice debugging tool, very slow static void R_DrawPortals(entity_render_t *ent) { int i; @@ -1537,7 +1538,7 @@ static void R_DrawPortals(entity_render_t *ent) return; for (portal = ent->model->brushq1.portals, endportal = portal + ent->model->brushq1.numportals;portal < endportal;portal++) { - if ((portal->here->pvsframe == ent->model->brushq1.pvsframecount || portal->past->pvsframe == ent->model->brushq1.pvsframecount) && portal->numpoints <= POLYGONELEMENTS_MAXPOINTS) + if (portal->numpoints <= POLYGONELEMENTS_MAXPOINTS) { VectorClear(temp); for (i = 0;i < portal->numpoints;i++) @@ -1639,7 +1640,7 @@ void R_SurfaceWorldNode (entity_render_t *ent) static void R_PortalWorldNode(entity_render_t *ent, mleaf_t *viewleaf) { - int c, leafstackpos, *mark, *surfacevisframes; + int c, leafstackpos, *mark, *surfacevisframes, bitnum; #if WORLDNODECULLBACKFACES int n; msurface_t *surf; @@ -1703,7 +1704,8 @@ static void R_PortalWorldNode(entity_render_t *ent, mleaf_t *viewleaf) { leaf->worldnodeframe = r_framecount; // FIXME: R_CullBox is absolute, should be done relative - if (leaf->pvsframe == ent->model->brushq1.pvsframecount && !R_CullBox(leaf->mins, leaf->maxs)) + bitnum = (leaf - ent->model->brushq1.leafs) - 1; + if ((r_pvsbits[bitnum >> 3] & (1 << (bitnum & 7))) && !R_CullBox(leaf->mins, leaf->maxs)) leafstack[leafstackpos++] = leaf; } } @@ -1715,7 +1717,6 @@ void R_PVSUpdate (entity_render_t *ent, mleaf_t *viewleaf) { int j, c, *surfacepvsframes, *mark; mleaf_t *leaf; - qbyte *pvs; model_t *model; model = ent->model; @@ -1728,11 +1729,10 @@ void R_PVSUpdate (entity_render_t *ent, mleaf_t *viewleaf) model->brushq1.pvssurflistlength = 0; if (viewleaf) { - pvs = viewleaf->pvsdata; surfacepvsframes = model->brushq1.surfacepvsframes; - for (j = 0;j < model->brushq1.numleafs-1;j++) + for (j = 0;j < model->brushq1.visleafs;j++) { - if (pvs[j >> 3] & (1 << (j & 7))) + if (r_pvsbits[j >> 3] & (1 << (j & 7))) { leaf = model->brushq1.leafs + j + 1; leaf->pvsframe = model->brushq1.pvsframecount; @@ -1897,6 +1897,34 @@ void R_Model_Brush_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, v } } +/* +void R_Q3BSP_DrawSky(entity_render_t *ent) +{ +} +*/ + +void R_Q3BSP_Draw(entity_render_t *ent) +{ +} + +/* +void R_Q3BSP_DrawFakeShadow(entity_render_t *ent) +{ +} +*/ + +/* +void R_Q3BSP_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius) +{ +} +*/ + +/* +void R_Q3BSP_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltofilter, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz) +{ +} +*/ + static void gl_surf_start(void) { } diff --git a/model_brush.c b/model_brush.c index e20c5709..a1bcd562 100644 --- a/model_brush.c +++ b/model_brush.c @@ -64,6 +64,25 @@ static mleaf_t *Mod_Q1BSP_PointInLeaf(model_t *model, const vec3_t p) return (mleaf_t *)node; } +static void Mod_Q1BSP_AmbientSoundLevelsForPoint(model_t *model, const vec3_t p, qbyte *out, int outsize) +{ + int i; + mleaf_t *leaf; + leaf = Mod_Q1BSP_PointInLeaf(model, p); + if (leaf) + { + i = min(outsize, (int)sizeof(leaf->ambient_sound_level));; + if (i) + { + memcpy(out, leaf->ambient_sound_level, i); + out += i; + outsize -= i; + } + } + if (outsize) + memset(out, 0, outsize); +} + static int Mod_Q1BSP_BoxTouchingPVS_RecursiveBSPNode(const model_t *model, const mnode_t *node, const qbyte *pvs, const vec3_t mins, const vec3_t maxs) { @@ -478,7 +497,7 @@ static void Mod_Q1BSP_TraceBox(struct model_s *model, trace_t *trace, const vec3 VectorSubtract(boxstartmaxs, boxstartmins, boxsize); if (boxsize[0] < 3) rhc.hull = &model->brushq1.hulls[0]; // 0x0x0 - else if (model->brushq1.ishlbsp) + else if (model->brush.ishlbsp) { if (boxsize[0] <= 32) { @@ -766,7 +785,7 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l) } // LordHavoc: HL sky textures are entirely different than quake - if (!loadmodel->brushq1.ishlbsp && !strncmp(tx->name, "sky", 3) && mtwidth == 256 && mtheight == 128) + if (!loadmodel->brush.ishlbsp && !strncmp(tx->name, "sky", 3) && mtwidth == 256 && mtheight == 128) { if (loadmodel->isworldmodel) { @@ -795,7 +814,7 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l) if (!Mod_LoadSkinFrame(&tx->skin, tx->name, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, false, true, true)) { // did not find external texture, load it from the bsp or wad3 - if (loadmodel->brushq1.ishlbsp) + if (loadmodel->brush.ishlbsp) { // internal texture overrides wad qbyte *pixels, *freepixels, *fogpixels; @@ -977,7 +996,7 @@ static void Mod_Q1BSP_LoadLighting(lump_t *l) qbyte *in, *out, *data, d; char litfilename[1024]; loadmodel->brushq1.lightdata = NULL; - if (loadmodel->brushq1.ishlbsp) // LordHavoc: load the colored lighting data straight + if (loadmodel->brush.ishlbsp) // LordHavoc: load the colored lighting data straight { loadmodel->brushq1.lightdata = Mem_Alloc(loadmodel->mempool, l->filelen); memcpy(loadmodel->brushq1.lightdata, mod_base + l->fileofs, l->filelen); @@ -1094,265 +1113,6 @@ static void Mod_Q1BSP_LoadLightList(void) } } -/* -static int castshadowcount = 0; -static void Mod_Q1BSP_ProcessLightList(void) -{ - int j, k, l, *mark, lnum; - mlight_t *e; - msurface_t *surf; - float dist; - mleaf_t *leaf; - qbyte *pvs; - vec3_t temp; - float *v, radius2; - for (lnum = 0, e = loadmodel->brushq1.lights;lnum < loadmodel->brushq1.numlights;lnum++, e++) - { - e->cullradius2 = DotProduct(e->light, e->light) / (e->falloff * e->falloff * 8192.0f * 8192.0f * 2.0f * 2.0f);// + 4096.0f; - if (e->cullradius2 > 4096.0f * 4096.0f) - e->cullradius2 = 4096.0f * 4096.0f; - e->cullradius = e->lightradius = sqrt(e->cullradius2); - leaf = Mod_Q1BSP_PointInLeaf(e->origin, loadmodel); - if (leaf->compressed_vis) - pvs = Mod_Q1BSP_DecompressVis(leaf->compressed_vis, loadmodel); - else - pvs = mod_q1bsp_novis; - for (j = 0;j < loadmodel->brushq1.numsurfaces;j++) - loadmodel->brushq1.surfacevisframes[j] = -1; - for (j = 0, leaf = loadmodel->brushq1.leafs + 1;j < loadmodel->brushq1.numleafs - 1;j++, leaf++) - { - if (pvs[j >> 3] & (1 << (j & 7))) - { - for (k = 0, mark = leaf->firstmarksurface;k < leaf->nummarksurfaces;k++, mark++) - { - surf = loadmodel->brushq1.surfaces + *mark; - if (surf->number != *mark) - Con_Printf("%d != %d\n", surf->number, *mark); - dist = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist; - if (surf->flags & SURF_PLANEBACK) - dist = -dist; - if (dist > 0 && dist < e->cullradius) - { - temp[0] = bound(surf->poly_mins[0], e->origin[0], surf->poly_maxs[0]) - e->origin[0]; - temp[1] = bound(surf->poly_mins[1], e->origin[1], surf->poly_maxs[1]) - e->origin[1]; - temp[2] = bound(surf->poly_mins[2], e->origin[2], surf->poly_maxs[2]) - e->origin[2]; - if (DotProduct(temp, temp) < lightradius2) - loadmodel->brushq1.surfacevisframes[*mark] = -2; - } - } - } - } - // build list of light receiving surfaces - e->numsurfaces = 0; - for (j = 0;j < loadmodel->brushq1.numsurfaces;j++) - if (loadmodel->brushq1.surfacevisframes[j] == -2) - 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->brushq1.numsurfaces;j++) - if (loadmodel->brushq1.surfacevisframes[j] == -2) - e->surfaces[e->numsurfaces++] = loadmodel->brushq1.surfaces + j; - } - // find bounding box and sphere of lit surfaces - // (these will be used for creating a shape to clip the light) - radius2 = 0; - for (j = 0;j < e->numsurfaces;j++) - { - surf = e->surfaces[j]; - if (j == 0) - { - VectorCopy(surf->poly_verts, e->mins); - VectorCopy(surf->poly_verts, e->maxs); - } - for (k = 0, v = surf->poly_verts;k < surf->poly_numverts;k++, v += 3) - { - if (e->mins[0] > v[0]) e->mins[0] = v[0];if (e->maxs[0] < v[0]) e->maxs[0] = v[0]; - if (e->mins[1] > v[1]) e->mins[1] = v[1];if (e->maxs[1] < v[1]) e->maxs[1] = v[1]; - if (e->mins[2] > v[2]) e->mins[2] = v[2];if (e->maxs[2] < v[2]) e->maxs[2] = v[2]; - VectorSubtract(v, e->origin, temp); - dist = DotProduct(temp, temp); - if (radius2 < dist) - radius2 = dist; - } - } - if (e->cullradius2 > radius2) - { - e->cullradius2 = radius2; - e->cullradius = sqrt(e->cullradius2); - } - if (e->mins[0] < e->origin[0] - e->lightradius) e->mins[0] = e->origin[0] - e->lightradius; - if (e->maxs[0] > e->origin[0] + e->lightradius) e->maxs[0] = e->origin[0] + e->lightradius; - if (e->mins[1] < e->origin[1] - e->lightradius) e->mins[1] = e->origin[1] - e->lightradius; - if (e->maxs[1] > e->origin[1] + e->lightradius) e->maxs[1] = e->origin[1] + e->lightradius; - if (e->mins[2] < e->origin[2] - e->lightradius) e->mins[2] = e->origin[2] - e->lightradius; - if (e->maxs[2] > e->origin[2] + e->lightradius) e->maxs[2] = e->origin[2] + e->lightradius; - // clip shadow volumes against eachother to remove unnecessary - // polygons(and sections of polygons) - { - //vec3_t polymins, polymaxs; - int maxverts = 4; - float *verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3])); - float f, *v0, *v1, projectdistance; - - e->shadowvolume = Mod_ShadowMesh_Begin(loadmodel->mempool, 1024); -#if 0 - { - vec3_t outermins, outermaxs, innermins, innermaxs; - innermins[0] = e->mins[0] - 1; - innermins[1] = e->mins[1] - 1; - innermins[2] = e->mins[2] - 1; - innermaxs[0] = e->maxs[0] + 1; - innermaxs[1] = e->maxs[1] + 1; - innermaxs[2] = e->maxs[2] + 1; - outermins[0] = loadmodel->normalmins[0] - 1; - outermins[1] = loadmodel->normalmins[1] - 1; - outermins[2] = loadmodel->normalmins[2] - 1; - outermaxs[0] = loadmodel->normalmaxs[0] + 1; - outermaxs[1] = loadmodel->normalmaxs[1] + 1; - outermaxs[2] = loadmodel->normalmaxs[2] + 1; - // add bounding box around the whole shadow volume set, - // facing inward to limit light area, with an outer bounding box - // facing outward (this is needed by the shadow rendering method) - // X major - verts[ 0] = innermaxs[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2]; - verts[ 3] = innermaxs[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2]; - verts[ 6] = innermaxs[0];verts[ 7] = innermaxs[1];verts[ 8] = innermins[2]; - verts[ 9] = innermaxs[0];verts[10] = innermaxs[1];verts[11] = innermaxs[2]; - Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); - verts[ 0] = outermaxs[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2]; - verts[ 3] = outermaxs[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2]; - verts[ 6] = outermaxs[0];verts[ 7] = outermins[1];verts[ 8] = outermins[2]; - verts[ 9] = outermaxs[0];verts[10] = outermins[1];verts[11] = outermaxs[2]; - Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); - // X minor - verts[ 0] = innermins[0];verts[ 1] = innermaxs[1];verts[ 2] = innermaxs[2]; - verts[ 3] = innermins[0];verts[ 4] = innermaxs[1];verts[ 5] = innermins[2]; - verts[ 6] = innermins[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2]; - verts[ 9] = innermins[0];verts[10] = innermins[1];verts[11] = innermaxs[2]; - Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); - verts[ 0] = outermins[0];verts[ 1] = outermins[1];verts[ 2] = outermaxs[2]; - verts[ 3] = outermins[0];verts[ 4] = outermins[1];verts[ 5] = outermins[2]; - verts[ 6] = outermins[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2]; - verts[ 9] = outermins[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2]; - Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); - // Y major - verts[ 0] = innermaxs[0];verts[ 1] = innermaxs[1];verts[ 2] = innermaxs[2]; - verts[ 3] = innermaxs[0];verts[ 4] = innermaxs[1];verts[ 5] = innermins[2]; - verts[ 6] = innermins[0];verts[ 7] = innermaxs[1];verts[ 8] = innermins[2]; - verts[ 9] = innermins[0];verts[10] = innermaxs[1];verts[11] = innermaxs[2]; - Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); - verts[ 0] = outermins[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2]; - verts[ 3] = outermins[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2]; - verts[ 6] = outermaxs[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2]; - verts[ 9] = outermaxs[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2]; - Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); - // Y minor - verts[ 0] = innermins[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2]; - verts[ 3] = innermins[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2]; - verts[ 6] = innermaxs[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2]; - verts[ 9] = innermaxs[0];verts[10] = innermins[1];verts[11] = innermaxs[2]; - Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); - verts[ 0] = outermaxs[0];verts[ 1] = outermins[1];verts[ 2] = outermaxs[2]; - verts[ 3] = outermaxs[0];verts[ 4] = outermins[1];verts[ 5] = outermins[2]; - verts[ 6] = outermins[0];verts[ 7] = outermins[1];verts[ 8] = outermins[2]; - verts[ 9] = outermins[0];verts[10] = outermins[1];verts[11] = outermaxs[2]; - Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); - // Z major - verts[ 0] = innermaxs[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2]; - verts[ 3] = innermaxs[0];verts[ 4] = innermaxs[1];verts[ 5] = innermaxs[2]; - verts[ 6] = innermins[0];verts[ 7] = innermaxs[1];verts[ 8] = innermaxs[2]; - verts[ 9] = innermins[0];verts[10] = innermins[1];verts[11] = innermaxs[2]; - Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); - verts[ 0] = outermaxs[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2]; - verts[ 3] = outermaxs[0];verts[ 4] = outermins[1];verts[ 5] = outermaxs[2]; - verts[ 6] = outermins[0];verts[ 7] = outermins[1];verts[ 8] = outermaxs[2]; - verts[ 9] = outermins[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2]; - Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); - // Z minor - verts[ 0] = innermaxs[0];verts[ 1] = innermaxs[1];verts[ 2] = innermins[2]; - verts[ 3] = innermaxs[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2]; - verts[ 6] = innermins[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2]; - verts[ 9] = innermins[0];verts[10] = innermaxs[1];verts[11] = innermins[2]; - Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); - verts[ 0] = outermaxs[0];verts[ 1] = outermins[1];verts[ 2] = outermins[2]; - verts[ 3] = outermaxs[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2]; - verts[ 6] = outermins[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2]; - verts[ 9] = outermins[0];verts[10] = outermins[1];verts[11] = outermins[2]; - Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); - } -#endif - castshadowcount++; - for (j = 0;j < e->numsurfaces;j++) - { - surf = e->surfaces[j]; - if (surf->flags & SURF_SHADOWCAST) - surf->castshadow = castshadowcount; - } - for (j = 0;j < e->numsurfaces;j++) - { - surf = e->surfaces[j]; - if (surf->castshadow != castshadowcount) - continue; - f = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist; - if (surf->flags & SURF_PLANEBACK) - f = -f; - projectdistance = e->lightradius; - if (maxverts < surf->poly_numverts) - { - maxverts = surf->poly_numverts; - if (verts) - Mem_Free(verts); - verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3])); - } - // copy the original polygon, for the front cap of the volume - for (k = 0, v0 = surf->poly_verts, v1 = verts;k < surf->poly_numverts;k++, v0 += 3, v1 += 3) - VectorCopy(v0, v1); - Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, surf->poly_numverts, verts); - // project the original polygon, reversed, for the back cap of the volume - for (k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = verts;k < surf->poly_numverts;k++, v0 -= 3, v1 += 3) - { - VectorSubtract(v0, e->origin, temp); - VectorNormalize(temp); - VectorMA(v0, projectdistance, temp, v1); - } - Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, surf->poly_numverts, verts); - // project the shadow volume sides - for (l = surf->poly_numverts - 1, k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = surf->poly_verts;k < surf->poly_numverts;l = k, k++, v0 = v1, v1 += 3) - { - if (!surf->neighborsurfaces[l] || surf->neighborsurfaces[l]->castshadow != castshadowcount) - { - VectorCopy(v1, &verts[0]); - VectorCopy(v0, &verts[3]); - VectorCopy(v0, &verts[6]); - VectorCopy(v1, &verts[9]); - VectorSubtract(&verts[6], e->origin, temp); - VectorNormalize(temp); - VectorMA(&verts[6], projectdistance, temp, &verts[6]); - VectorSubtract(&verts[9], e->origin, temp); - VectorNormalize(temp); - VectorMA(&verts[9], projectdistance, temp, &verts[9]); - Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); - } - } - } - // build the triangle mesh - e->shadowvolume = Mod_ShadowMesh_Finish(loadmodel->mempool, e->shadowvolume); - { - shadowmesh_t *mesh; - l = 0; - for (mesh = e->shadowvolume;mesh;mesh = mesh->next) - l += mesh->numtriangles; - Con_Printf("light %i shadow volume built containing %i triangles\n", lnum, l); - } - } - } -} -*/ - - static void Mod_Q1BSP_LoadVisibility(lump_t *l) { loadmodel->brushq1.num_compressedpvs = 0; @@ -1393,7 +1153,7 @@ static void Mod_Q1BSP_ParseWadsFromEntityLump(const char *data) strcpy(value, com_token); if (!strcmp("wad", key)) // for HalfLife maps { - if (loadmodel->brushq1.ishlbsp) + if (loadmodel->brush.ishlbsp) { j = 0; for (i = 0;i < 4096;i++) @@ -1431,7 +1191,7 @@ static void Mod_Q1BSP_LoadEntities(lump_t *l) return; loadmodel->brush.entities = Mem_Alloc(loadmodel->mempool, l->filelen); memcpy(loadmodel->brush.entities, mod_base + l->fileofs, l->filelen); - if (loadmodel->brushq1.ishlbsp) + if (loadmodel->brush.ishlbsp) Mod_Q1BSP_ParseWadsFromEntityLump(loadmodel->brush.entities); } @@ -1472,7 +1232,7 @@ static void Mod_Q1BSP_LoadSubmodels(lump_t *l) out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out)); loadmodel->brushq1.submodels = out; - loadmodel->brushq1.numsubmodels = count; + loadmodel->brush.numsubmodels = count; for ( i=0 ; ilightofs); if (i == -1) surf->samples = NULL; - else if (loadmodel->brushq1.ishlbsp) // LordHavoc: HalfLife map (bsp version 30) + else if (loadmodel->brush.ishlbsp) // LordHavoc: HalfLife map (bsp version 30) surf->samples = loadmodel->brushq1.lightdata + i; else // LordHavoc: white lighting (bsp version 29) surf->samples = loadmodel->brushq1.lightdata + (i * 3); @@ -2018,7 +1778,7 @@ static void Mod_Q1BSP_LoadLeafs(lump_t *l) loadmodel->brushq1.leafs = out; loadmodel->brushq1.numleafs = count; - pvschainbytes = ((loadmodel->brushq1.num_leafs - 1)+7)>>3; + pvschainbytes = ((loadmodel->brushq1.numleafs - 1)+7)>>3; loadmodel->brushq1.data_decompressedpvs = pvs = Mem_Alloc(loadmodel->mempool, loadmodel->brushq1.numleafs * pvschainbytes); for ( i=0 ; ibrushq1.clipnodes = out; loadmodel->brushq1.numclipnodes = count; - if (loadmodel->brushq1.ishlbsp) + if (loadmodel->brush.ishlbsp) { hull = &loadmodel->brushq1.hulls[1]; hull->clipnodes = out; @@ -3072,13 +2832,46 @@ void Mod_Q1BSP_FatPVS_RecursiveBSPNode(model_t *model, const vec3_t org, vec_t r //of the given point. int Mod_Q1BSP_FatPVS(model_t *model, const vec3_t org, vec_t radius, qbyte *pvsbuffer, int pvsbufferlength) { - int bytes = ((model->brushq1.num_leafs - 1) + 7) >> 3; + int bytes = ((model->brushq1.numleafs - 1) + 7) >> 3; bytes = min(bytes, pvsbufferlength); memset(pvsbuffer, 0, bytes); Mod_Q1BSP_FatPVS_RecursiveBSPNode(model, org, radius, pvsbuffer, bytes, sv.worldmodel->brushq1.nodes); return bytes; } +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; + const hull_t *hull; + + VectorSubtract(inmaxs, inmins, size); + if (cmodel->brush.ishlbsp) + { + if (size[0] < 3) + hull = &cmodel->brushq1.hulls[0]; // 0x0x0 + else if (size[0] <= 32) + { + if (size[2] < 54) // pick the nearest of 36 or 72 + hull = &cmodel->brushq1.hulls[3]; // 32x32x36 + else + hull = &cmodel->brushq1.hulls[1]; // 32x32x72 + } + else + hull = &cmodel->brushq1.hulls[2]; // 64x64x64 + } + else + { + if (size[0] < 3) + hull = &cmodel->brushq1.hulls[0]; // 0x0x0 + else if (size[0] <= 32) + hull = &cmodel->brushq1.hulls[1]; // 32x32x56 + else + hull = &cmodel->brushq1.hulls[2]; // 64x64x88 + } + VectorCopy(inmins, outmins); + VectorAdd(inmins, hull->clip_size, outmaxs); +} + 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); @@ -3102,19 +2895,21 @@ void Mod_Q1BSP_Load(model_t *mod, void *buffer) i = LittleLong(header->version); if (i != BSPVERSION && i != 30) Host_Error("Mod_Q1BSP_Load: %s has wrong version number(%i should be %i(Quake) or 30(HalfLife))", mod->name, i, BSPVERSION); - mod->brushq1.ishlbsp = i == 30; + mod->brush.ishlbsp = i == 30; + mod->brush.AmbientSoundLevelsForPoint = Mod_Q1BSP_AmbientSoundLevelsForPoint; mod->brush.FatPVS = Mod_Q1BSP_FatPVS; mod->brush.BoxTouchingPVS = Mod_Q1BSP_BoxTouchingPVS; mod->brush.LightPoint = Mod_Q1BSP_LightPoint; mod->brush.FindNonSolidLocation = Mod_Q1BSP_FindNonSolidLocation; mod->brush.TraceBox = Mod_Q1BSP_TraceBox; + mod->brush.RoundUpToHullSize = Mod_Q1BSP_RoundUpToHullSize; mod->brushq1.PointInLeaf = Mod_Q1BSP_PointInLeaf; mod->brushq1.BuildPVSTextureChains = Mod_Q1BSP_BuildPVSTextureChains; if (loadmodel->isworldmodel) { - Cvar_SetValue("halflifebsp", mod->brushq1.ishlbsp); + Cvar_SetValue("halflifebsp", mod->brush.ishlbsp); // until we get a texture for it... R_ResetQuakeSky(); } @@ -3155,7 +2950,7 @@ void Mod_Q1BSP_Load(model_t *mod, void *buffer) Mod_Q1BSP_MakePortals(); if (developer.integer) - Con_Printf("Some stats for q1bsp model \"%s\": %i faces, %i nodes, %i leafs, %i visleafs, %i visleafportals\n", loadmodel->name, loadmodel->brushq1.numsurfaces, loadmodel->brushq1.numnodes, loadmodel->brushq1.numleafs, loadmodel->brushq1.num_leafs - 1, loadmodel->brushq1.numportals); + Con_Printf("Some stats for q1bsp model \"%s\": %i faces, %i nodes, %i leafs, %i visleafs, %i visleafportals\n", loadmodel->name, loadmodel->brushq1.numsurfaces, loadmodel->brushq1.numnodes, loadmodel->brushq1.numleafs, loadmodel->brushq1.numleafs - 1, loadmodel->brushq1.numportals); mod->numframes = 2; // regular and alternate animation @@ -3168,7 +2963,7 @@ void Mod_Q1BSP_Load(model_t *mod, void *buffer) // // set up the submodels(FIXME: this is confusing) // - for (i = 0;i < mod->brushq1.numsubmodels;i++) + for (i = 0;i < mod->brush.numsubmodels;i++) { bm = &mod->brushq1.submodels[i]; @@ -3206,7 +3001,7 @@ void Mod_Q1BSP_Load(model_t *mod, void *buffer) if (surf->texinfo->texture->shader == &Cshader_sky) mod->DrawSky = R_Model_Brush_DrawSky; // LordHavoc: submodels always clip, even if water - if (mod->brushq1.numsubmodels - 1) + if (mod->brush.numsubmodels - 1) surf->flags |= SURF_SOLIDCLIP; // calculate bounding shapes for (mesh = surf->mesh;mesh;mesh = mesh->chain) @@ -3245,11 +3040,11 @@ void Mod_Q1BSP_Load(model_t *mod, void *buffer) } Mod_Q1BSP_BuildSurfaceNeighbors(mod->brushq1.surfaces + mod->brushq1.firstmodelsurface, mod->brushq1.nummodelsurfaces, originalloadmodel->mempool); - mod->brushq1.numleafs = bm->visleafs; + mod->brushq1.visleafs = bm->visleafs; // LordHavoc: only register submodels if it is the world // (prevents bsp models from replacing world submodels) - if (loadmodel->isworldmodel && i < (mod->brushq1.numsubmodels - 1)) + if (loadmodel->isworldmodel && i < (mod->brush.numsubmodels - 1)) { char name[10]; // duplicate the basic information @@ -3660,10 +3455,10 @@ void Mod_Q2BSP_Load(model_t *mod, void *buffer) i = LittleLong(header->version); if (i != Q2BSPVERSION) Host_Error("Mod_Q2BSP_Load: %s has wrong version number (%i, should be %i)", mod->name, i, Q2BSPVERSION); - mod->brushq1.ishlbsp = false; + mod->brush.ishlbsp = false; if (loadmodel->isworldmodel) { - Cvar_SetValue("halflifebsp", mod->brushq1.ishlbsp); + Cvar_SetValue("halflifebsp", mod->brush.ishlbsp); // until we get a texture for it... R_ResetQuakeSky(); } @@ -4532,6 +4327,11 @@ int Mod_Q3BSP_FatPVS(model_t *model, const vec3_t org, vec_t radius, qbyte *pvsb return pvsbufferlength; } +//extern void R_Q3BSP_DrawSky(struct entity_render_s *ent); +extern void R_Q3BSP_Draw(struct entity_render_s *ent); +//extern void R_Q3BSP_DrawFakeShadow(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_modeltofilter, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz); void Mod_Q3BSP_Load(model_t *mod, void *buffer) { int i; @@ -4556,8 +4356,11 @@ void Mod_Q3BSP_Load(model_t *mod, void *buffer) mod->brush.LightPoint = Mod_Q3BSP_LightPoint; mod->brush.FindNonSolidLocation = Mod_Q3BSP_FindNonSolidLocation; mod->brush.TraceBox = Mod_Q3BSP_TraceBox; - //mod->brushq1.PointInLeaf = Mod_Q1BSP_PointInLeaf; - //mod->brushq1.BuildPVSTextureChains = Mod_Q1BSP_BuildPVSTextureChains; + //mod->DrawSky = R_Q3BSP_DrawSky; + mod->Draw = R_Q3BSP_Draw; + //mod->DrawFakeShadow = R_Q3BSP_DrawFakeShadow; + //mod->DrawShadowVolume = R_Q3BSP_DrawShadowVolume; + //mod->DrawLight = R_Q3BSP_DrawLight; mod_base = (qbyte *)header; diff --git a/model_shared.h b/model_shared.h index 7023822d..3dbbb0c8 100644 --- a/model_shared.h +++ b/model_shared.h @@ -144,33 +144,41 @@ struct trace_s; typedef struct model_brush_s { + // true if this model is a HalfLife .bsp file + qboolean ishlbsp; + // string of entity definitions (.map format) char *entities; + // number of submodels in this map (just used by server to know how many + // submodels to load) + int numsubmodels; + // common functions + void (*AmbientSoundLevelsForPoint)(struct model_s *model, const vec3_t p, qbyte *out, int outsize); int (*FatPVS)(struct model_s *model, const vec3_t org, vec_t radius, qbyte *pvsbuffer, int pvsbufferlength); int (*BoxTouchingPVS)(struct model_s *model, const qbyte *pvs, const vec3_t mins, const vec3_t maxs); void (*LightPoint)(struct model_s *model, const vec3_t p, vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal); void (*FindNonSolidLocation)(struct model_s *model, const vec3_t in, vec3_t out, vec_t radius); void (*TraceBox)(struct model_s *model, struct trace_s *trace, const vec3_t boxstartmins, const vec3_t boxstartmaxs, const vec3_t boxendmins, const vec3_t boxendmaxs); + // this is actually only found on brushq1, but NULL is handled gracefully + void (*RoundUpToHullSize)(struct model_s *cmodel, const vec3_t inmins, const vec3_t inmaxs, vec3_t outmins, vec3_t outmaxs); } model_brush_t; typedef struct model_brushq1_s { - // true if this model is a HalfLife .bsp file - qboolean ishlbsp; - int firstmodelsurface, nummodelsurfaces; // lightmap format, set to r_lightmaprgba when model is loaded int lightmaprgba; - int numsubmodels; dmodel_t *submodels; int numplanes; mplane_t *planes; - // number of visible leafs, not counting 0 (solid) + // number of actual leafs (including 0 which is solid) int numleafs; + // visible leafs, not counting 0 (solid) + int visleafs; mleaf_t *leafs; int numvertexes; diff --git a/pr_cmds.c b/pr_cmds.c index c0d6e440..0f801f8a 100644 --- a/pr_cmds.c +++ b/pr_cmds.c @@ -1297,7 +1297,7 @@ void PF_precache_model (void) Host_Error ("PF_Precache_*: Precache can only be done in spawn functions"); s = G_STRING(OFS_PARM0); - if (sv.worldmodel->brushq1.ishlbsp && ((!s) || (!s[0]))) + if (sv.worldmodel->brush.ishlbsp && ((!s) || (!s[0]))) return; G_INT(OFS_RETURN) = G_INT(OFS_PARM0); PR_CheckEmptyString (s); diff --git a/r_light.c b/r_light.c index 9fd74782..5cc26979 100644 --- a/r_light.c +++ b/r_light.c @@ -275,7 +275,7 @@ void R_MarkLights(entity_render_t *ent) lightpvsbytes = 0; if (r_vismarklights.integer && ent->model->brush.FatPVS) lightpvsbytes = ent->model->brush.FatPVS(ent->model, lightorigin, 0, lightpvs, sizeof(lightpvs)); - R_RecursiveMarkLights(ent, lightorigin, rd, bit, bitindex, ent->model->brushq1.nodes + ent->model->brushq1.hulls[0].firstclipnode, lightpvs, min(lightpvsbytes * 8, ent->model->brushq1.num_leafs - 1)); + R_RecursiveMarkLights(ent, lightorigin, rd, bit, bitindex, ent->model->brushq1.nodes + ent->model->brushq1.hulls[0].firstclipnode, lightpvs, min(lightpvsbytes * 8, ent->model->brushq1.visleafs)); } } } @@ -301,16 +301,6 @@ void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffu else VectorSet(ambientcolor, 1, 1, 1); - /* - if (leaf == NULL && cl.worldmodel != NULL) - leaf = cl.worldmodel->brushq1.PointInLeaf(cl.worldmodel, p); - if (!leaf || leaf->contents == CONTENTS_SOLID || !cl.worldmodel->brushq1.lightdata) - { - VectorSet(ambientcolor, 1, 1, 1); - return; - } - */ - // FIXME: this .lights related stuff needs to be ported into the Mod_Q1BSP code if (cl.worldmodel->brushq1.numlights) { diff --git a/r_shadow.c b/r_shadow.c index 3995057d..4234f968 100644 --- a/r_shadow.c +++ b/r_shadow.c @@ -772,7 +772,6 @@ void R_Shadow_Stage_Begin(void) if (r_shadow_texture3d.integer && !gl_texture3d) Cvar_SetValueQuick(&r_shadow_texture3d, 0); - //cl.worldmodel->brushq1.numlights = min(cl.worldmodel->brushq1.numlights, 1); if (!r_shadow_attenuation2dtexture || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer) || r_shadow_lightattenuationpower.value != r_shadow_attenpower @@ -901,147 +900,6 @@ void R_Shadow_Stage_End(void) r_shadowstage = SHADOWSTAGE_NONE; } -#if 0 -int R_Shadow_ScissorForBBoxAndSphere(const float *mins, const float *maxs, const float *origin, float radius) -{ - int i, ix1, iy1, ix2, iy2; - float x1, y1, x2, y2, x, y; - vec3_t smins, smaxs; - vec4_t v, v2; - if (!r_shadow_scissor.integer) - return false; - // if view is inside the box, just say yes it's visible - if (r_origin[0] >= mins[0] && r_origin[0] <= maxs[0] - && r_origin[1] >= mins[1] && r_origin[1] <= maxs[1] - && r_origin[2] >= mins[2] && r_origin[2] <= maxs[2]) - { - qglDisable(GL_SCISSOR_TEST); - return false; - } - VectorSubtract(r_origin, origin, v); - if (DotProduct(v, v) < radius * radius) - { - qglDisable(GL_SCISSOR_TEST); - return false; - } - // create viewspace bbox - for (i = 0;i < 8;i++) - { - v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_origin[0]; - v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_origin[1]; - v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_origin[2]; - v2[0] = DotProduct(v, vright); - v2[1] = DotProduct(v, vup); - v2[2] = DotProduct(v, vpn); - if (i) - { - if (smins[0] > v2[0]) smins[0] = v2[0]; - if (smaxs[0] < v2[0]) smaxs[0] = v2[0]; - if (smins[1] > v2[1]) smins[1] = v2[1]; - if (smaxs[1] < v2[1]) smaxs[1] = v2[1]; - if (smins[2] > v2[2]) smins[2] = v2[2]; - if (smaxs[2] < v2[2]) smaxs[2] = v2[2]; - } - else - { - smins[0] = smaxs[0] = v2[0]; - smins[1] = smaxs[1] = v2[1]; - smins[2] = smaxs[2] = v2[2]; - } - } - // now we have a bbox in viewspace - // clip it to the viewspace version of the sphere - v[0] = origin[0] - r_origin[0]; - v[1] = origin[1] - r_origin[1]; - v[2] = origin[2] - r_origin[2]; - v2[0] = DotProduct(v, vright); - v2[1] = DotProduct(v, vup); - v2[2] = DotProduct(v, vpn); - if (smins[0] < v2[0] - radius) smins[0] = v2[0] - radius; - if (smaxs[0] < v2[0] - radius) smaxs[0] = v2[0] + radius; - if (smins[1] < v2[1] - radius) smins[1] = v2[1] - radius; - if (smaxs[1] < v2[1] - radius) smaxs[1] = v2[1] + radius; - if (smins[2] < v2[2] - radius) smins[2] = v2[2] - radius; - if (smaxs[2] < v2[2] - radius) smaxs[2] = v2[2] + radius; - // clip it to the view plane - if (smins[2] < 1) - smins[2] = 1; - // return true if that culled the box - if (smins[2] >= smaxs[2]) - return true; - // ok some of it is infront of the view, transform each corner back to - // worldspace and then to screenspace and make screen rect - // initialize these variables just to avoid compiler warnings - x1 = y1 = x2 = y2 = 0; - for (i = 0;i < 8;i++) - { - v2[0] = (i & 1) ? smins[0] : smaxs[0]; - v2[1] = (i & 2) ? smins[1] : smaxs[1]; - v2[2] = (i & 4) ? smins[2] : smaxs[2]; - v[0] = v2[0] * vright[0] + v2[1] * vup[0] + v2[2] * vpn[0] + r_origin[0]; - v[1] = v2[0] * vright[1] + v2[1] * vup[1] + v2[2] * vpn[1] + r_origin[1]; - v[2] = v2[0] * vright[2] + v2[1] * vup[2] + v2[2] * vpn[2] + r_origin[2]; - v[3] = 1.0f; - GL_TransformToScreen(v, v2); - //Con_Printf("%.3f %.3f %.3f %.3f transformed to %.3f %.3f %.3f %.3f\n", v[0], v[1], v[2], v[3], v2[0], v2[1], v2[2], v2[3]); - x = v2[0]; - y = v2[1]; - if (i) - { - if (x1 > x) x1 = x; - if (x2 < x) x2 = x; - if (y1 > y) y1 = y; - if (y2 < y) y2 = y; - } - else - { - x1 = x2 = x; - y1 = y2 = y; - } - } - /* - // this code doesn't handle boxes with any points behind view properly - x1 = 1000;x2 = -1000; - y1 = 1000;y2 = -1000; - for (i = 0;i < 8;i++) - { - v[0] = (i & 1) ? mins[0] : maxs[0]; - v[1] = (i & 2) ? mins[1] : maxs[1]; - v[2] = (i & 4) ? mins[2] : maxs[2]; - v[3] = 1.0f; - GL_TransformToScreen(v, v2); - //Con_Printf("%.3f %.3f %.3f %.3f transformed to %.3f %.3f %.3f %.3f\n", v[0], v[1], v[2], v[3], v2[0], v2[1], v2[2], v2[3]); - if (v2[2] > 0) - { - x = v2[0]; - y = v2[1]; - - if (x1 > x) x1 = x; - if (x2 < x) x2 = x; - if (y1 > y) y1 = y; - if (y2 < y) y2 = y; - } - } - */ - ix1 = x1 - 1.0f; - iy1 = y1 - 1.0f; - ix2 = x2 + 1.0f; - iy2 = y2 + 1.0f; - //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2); - if (ix1 < r_refdef.x) ix1 = r_refdef.x; - if (iy1 < r_refdef.y) iy1 = r_refdef.y; - if (ix2 > r_refdef.x + r_refdef.width) ix2 = r_refdef.x + r_refdef.width; - if (iy2 > r_refdef.y + r_refdef.height) iy2 = r_refdef.y + r_refdef.height; - if (ix2 <= ix1 || iy2 <= iy1) - return true; - // set up the scissor rectangle - qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1); - qglEnable(GL_SCISSOR_TEST); - c_rt_scissored++; - return false; -} -#endif - int R_Shadow_ScissorForBBox(const float *mins, const float *maxs) { int i, ix1, iy1, ix2, iy2; @@ -1847,8 +1705,8 @@ static qbyte lightpvs[(MAX_MAP_LEAFS + 7)/ 8]; static int castshadowcount = 1; void R_Shadow_NewWorldLight(vec3_t origin, float radius, vec3_t color, int style, const char *cubemapname, int castshadow) { - int i, j, k, l, maxverts = 256, *mark, tris; - float *vertex3f = NULL; + int i, j, k, l, maxverts = 256, *mark, tris, numsurfaces; + float *vertex3f = NULL, mins[3], maxs[3]; worldlight_t *e; shadowmesh_t *mesh, *castmesh; mleaf_t *leaf; @@ -1876,8 +1734,8 @@ void R_Shadow_NewWorldLight(vec3_t origin, float radius, vec3_t color, int style e->cullradius = e->lightradius; for (k = 0;k < 3;k++) { - e->mins[k] = e->origin[k] - e->lightradius; - e->maxs[k] = e->origin[k] + e->lightradius; + mins[k] = e->origin[k] - e->lightradius; + maxs[k] = e->origin[k] + e->lightradius; } e->next = r_shadow_worldlightchain; @@ -1891,6 +1749,8 @@ void R_Shadow_NewWorldLight(vec3_t origin, float radius, vec3_t color, int style if (cl.worldmodel) { castshadowcount++; + VectorCopy(e->origin, e->mins); + VectorCopy(e->origin, e->maxs); i = CL_PointContents(e->origin); if (r_shadow_portallight.integer && i != CONTENTS_SOLID && i != CONTENTS_SKY) { @@ -1903,11 +1763,19 @@ void R_Shadow_NewWorldLight(vec3_t origin, float radius, vec3_t color, int style Portal_Visibility(cl.worldmodel, e->origin, byteleafpvs, bytesurfacepvs, NULL, 0, true, RadiusFromBoundsAndOrigin(e->mins, e->maxs, e->origin)); for (i = 0, leaf = cl.worldmodel->brushq1.leafs;i < cl.worldmodel->brushq1.numleafs;i++, leaf++) - if (byteleafpvs[i] && BoxesOverlap(leaf->mins, leaf->maxs, e->mins, e->maxs)) - leaf->worldnodeframe = castshadowcount; + { + if (byteleafpvs[i] && BoxesOverlap(leaf->mins, leaf->maxs, mins, maxs)) + { + for (k = 0;k < 3;k++) + { + if (e->mins[k] > leaf->mins[k]) e->mins[k] = leaf->mins[k]; + if (e->maxs[k] < leaf->maxs[k]) e->maxs[k] = leaf->maxs[k]; + } + } + } for (i = 0, surf = cl.worldmodel->brushq1.surfaces;i < cl.worldmodel->brushq1.numsurfaces;i++, surf++) - if (bytesurfacepvs[i] && BoxesOverlap(surf->poly_mins, surf->poly_maxs, e->mins, e->maxs)) + if (bytesurfacepvs[i] && BoxesOverlap(surf->poly_mins, surf->poly_maxs, mins, maxs)) surf->castshadow = castshadowcount; Mem_Free(byteleafpvs); @@ -1916,56 +1784,25 @@ void R_Shadow_NewWorldLight(vec3_t origin, float radius, vec3_t color, int style else { lightpvsbytes = cl.worldmodel->brush.FatPVS(cl.worldmodel, origin, 0, lightpvs, sizeof(lightpvs)); - for (i = 0, leaf = cl.worldmodel->brushq1.leafs + 1;i < cl.worldmodel->brushq1.numleafs - 1;i++, leaf++) + for (i = 0, leaf = cl.worldmodel->brushq1.leafs + 1;i < cl.worldmodel->brushq1.visleafs;i++, leaf++) { - if (lightpvs[i >> 3] & (1 << (i & 7)) && BoxesOverlap(leaf->mins, leaf->maxs, e->mins, e->maxs)) + if (lightpvs[i >> 3] & (1 << (i & 7)) && BoxesOverlap(leaf->mins, leaf->maxs, mins, maxs)) { - leaf->worldnodeframe = castshadowcount; + for (k = 0;k < 3;k++) + { + if (e->mins[k] > leaf->mins[k]) e->mins[k] = leaf->mins[k]; + if (e->maxs[k] < leaf->maxs[k]) e->maxs[k] = leaf->maxs[k]; + } for (j = 0, mark = leaf->firstmarksurface;j < leaf->nummarksurfaces;j++, mark++) { surf = cl.worldmodel->brushq1.surfaces + *mark; - if (surf->castshadow != castshadowcount && BoxesOverlap(surf->poly_mins, surf->poly_maxs, e->mins, e->maxs)) + if (surf->castshadow != castshadowcount && BoxesOverlap(surf->poly_mins, surf->poly_maxs, mins, maxs)) surf->castshadow = castshadowcount; } } } } - e->numleafs = 0; - for (i = 0, leaf = cl.worldmodel->brushq1.leafs + 1;i < cl.worldmodel->brushq1.numleafs;i++, leaf++) - if (leaf->worldnodeframe == castshadowcount) - e->numleafs++; - e->numsurfaces = 0; - for (i = 0, surf = cl.worldmodel->brushq1.surfaces + cl.worldmodel->brushq1.firstmodelsurface;i < cl.worldmodel->brushq1.nummodelsurfaces;i++, surf++) - if (surf->castshadow == castshadowcount) - e->numsurfaces++; - - if (e->numleafs) - e->leafs = Mem_Alloc(r_shadow_mempool, e->numleafs * sizeof(mleaf_t *)); - if (e->numsurfaces) - e->surfaces = Mem_Alloc(r_shadow_mempool, e->numsurfaces * sizeof(msurface_t *)); - e->numleafs = 0; - for (i = 0, leaf = cl.worldmodel->brushq1.leafs + 1;i < cl.worldmodel->brushq1.numleafs;i++, leaf++) - if (leaf->worldnodeframe == castshadowcount) - e->leafs[e->numleafs++] = leaf; - e->numsurfaces = 0; - for (i = 0, surf = cl.worldmodel->brushq1.surfaces + cl.worldmodel->brushq1.firstmodelsurface;i < cl.worldmodel->brushq1.nummodelsurfaces;i++, surf++) - if (surf->castshadow == castshadowcount) - e->surfaces[e->numsurfaces++] = surf; - - // find bounding box of lit leafs - VectorCopy(e->origin, e->mins); - VectorCopy(e->origin, e->maxs); - for (j = 0;j < e->numleafs;j++) - { - leaf = e->leafs[j]; - for (k = 0;k < 3;k++) - { - if (e->mins[k] > leaf->mins[k]) e->mins[k] = leaf->mins[k]; - if (e->maxs[k] < leaf->maxs[k]) e->maxs[k] = leaf->maxs[k]; - } - } - for (k = 0;k < 3;k++) { if (e->mins[k] < e->origin[k] - e->lightradius) e->mins[k] = e->origin[k] - e->lightradius; @@ -1973,6 +1810,17 @@ void R_Shadow_NewWorldLight(vec3_t origin, float radius, vec3_t color, int style } e->cullradius = RadiusFromBoundsAndOrigin(e->mins, e->maxs, e->origin); + numsurfaces = 0; + for (i = 0, surf = cl.worldmodel->brushq1.surfaces + cl.worldmodel->brushq1.firstmodelsurface;i < cl.worldmodel->brushq1.nummodelsurfaces;i++, surf++) + if (surf->castshadow == castshadowcount) + numsurfaces++; + if (numsurfaces) + e->surfaces = Mem_Alloc(r_shadow_mempool, numsurfaces * sizeof(msurface_t *)); + e->numsurfaces = 0; + for (i = 0, surf = cl.worldmodel->brushq1.surfaces + cl.worldmodel->brushq1.firstmodelsurface;i < cl.worldmodel->brushq1.nummodelsurfaces;i++, surf++) + if (surf->castshadow == castshadowcount) + e->surfaces[e->numsurfaces++] = surf; + if (e->castshadows) { castshadowcount++; @@ -2026,7 +1874,7 @@ void R_Shadow_NewWorldLight(vec3_t origin, float radius, vec3_t color, int style Con_Printf("static shadow volume built containing %i triangles\n", l); } } - Con_Printf("%f %f %f, %f %f %f, %f, %f, %d, %d\n", e->mins[0], e->mins[1], e->mins[2], e->maxs[0], e->maxs[1], e->maxs[2], e->cullradius, e->lightradius, e->numleafs, e->numsurfaces); + Con_Printf("%f %f %f, %f %f %f, %f, %f, %d\n", e->mins[0], e->mins[1], e->mins[2], e->maxs[0], e->maxs[1], e->maxs[2], e->cullradius, e->lightradius, e->numsurfaces); } void R_Shadow_FreeWorldLight(worldlight_t *light) @@ -2042,8 +1890,6 @@ void R_Shadow_FreeWorldLight(worldlight_t *light) Mod_ShadowMesh_Free(light->shadowvolume); if (light->surfaces) Mem_Free(light->surfaces); - if (light->leafs) - Mem_Free(light->leafs); Mem_Free(light); } diff --git a/r_shadow.h b/r_shadow.h index 20a3f360..449c62ea 100644 --- a/r_shadow.h +++ b/r_shadow.h @@ -25,7 +25,6 @@ void R_Shadow_Stage_ShadowVolumes(void); void R_Shadow_Stage_LightWithShadows(void); void R_Shadow_Stage_LightWithoutShadows(void); void R_Shadow_Stage_End(void); -//int R_Shadow_ScissorForBBoxAndSphere(const float *mins, const float *maxs, const float *origin, float radius); int R_Shadow_ScissorForBBox(const float *mins, const float *maxs); typedef struct worldlight_s @@ -57,8 +56,6 @@ typedef struct worldlight_s struct worldlight_s *next; msurface_t **surfaces; int numsurfaces; - mleaf_t **leafs; - int numleafs; rtexture_t *cubemap; int style; shadowmesh_t *shadowvolume; diff --git a/render.h b/render.h index 2bd3e247..f523fe4a 100644 --- a/render.h +++ b/render.h @@ -21,6 +21,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #ifndef RENDER_H #define RENDER_H +extern qbyte r_pvsbits[(MAX_MAP_LEAFS+7)>>3]; + extern matrix4x4_t r_identitymatrix; // 1.0f / N table @@ -122,9 +124,6 @@ void R_DrawExplosions(void); //#define PARANOID 1 int R_CullBox(const vec3_t mins, const vec3_t maxs); -int PVS_CullBox(const vec3_t mins, const vec3_t maxs); -int R_CullSphere(const vec3_t origin, vec_t radius); -int PVS_CullSphere(const vec3_t origin, vec_t radius); extern qboolean fogenabled; extern vec3_t fogcolor; diff --git a/snd_dma.c b/snd_dma.c index 6de33897..89cf1573 100644 --- a/snd_dma.c +++ b/snd_dma.c @@ -680,18 +680,20 @@ S_UpdateAmbientSounds */ void S_UpdateAmbientSounds (void) { - mleaf_t *l; float vol; int ambient_channel; channel_t *chan; + qbyte ambientlevels[NUM_AMBIENTS]; // LordHavoc: kill ambient sounds until proven otherwise for (ambient_channel = 0 ; ambient_channel < NUM_AMBIENTS;ambient_channel++) channels[ambient_channel].sfx = NULL; - if (!snd_ambient || ambient_level.value <= 0 || !cl.worldmodel || !cl.worldmodel->brushq1.PointInLeaf || (l = cl.worldmodel->brushq1.PointInLeaf(cl.worldmodel, listener_origin)) == NULL) + if (!snd_ambient || ambient_level.value <= 0 || !cl.worldmodel || !cl.worldmodel->brush.AmbientSoundLevelsForPoint) return; + cl.worldmodel->brush.AmbientSoundLevelsForPoint(cl.worldmodel, listener_origin, ambientlevels, sizeof(ambientlevels)); + // calc ambient sound levels for (ambient_channel = 0 ; ambient_channel< NUM_AMBIENTS ; ambient_channel++) { @@ -701,7 +703,7 @@ void S_UpdateAmbientSounds (void) chan->forceloop = true; chan->sfx = ambient_sfx[ambient_channel]; - vol = ambient_level.value * l->ambient_sound_level[ambient_channel]; + vol = ambient_level.value * ambientlevels[ambient_channel]; if (vol < 8) vol = 0; diff --git a/sv_main.c b/sv_main.c index 310a726f..e9f1c33c 100644 --- a/sv_main.c +++ b/sv_main.c @@ -20,10 +20,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // sv_main.c -- server main program #include "quakedef.h" -#include "portals.h" static cvar_t sv_cullentities_pvs = {0, "sv_cullentities_pvs", "0"}; // fast but loose -static cvar_t sv_cullentities_portal = {0, "sv_cullentities_portal", "0"}; // extremely accurate visibility checking, but too slow static cvar_t sv_cullentities_trace = {0, "sv_cullentities_trace", "1"}; // tends to get false negatives, uses a timeout to keep entities visible a short time after becoming hidden static cvar_t sv_cullentities_stats = {0, "sv_cullentities_stats", "0"}; static cvar_t sv_entpatch = {0, "sv_entpatch", "1"}; @@ -62,7 +60,6 @@ void SV_Init (void) Cvar_RegisterVariable (&sv_nostep); Cvar_RegisterVariable (&sv_deltacompress); Cvar_RegisterVariable (&sv_cullentities_pvs); - Cvar_RegisterVariable (&sv_cullentities_portal); Cvar_RegisterVariable (&sv_cullentities_trace); Cvar_RegisterVariable (&sv_cullentities_stats); Cvar_RegisterVariable (&sv_entpatch); @@ -387,7 +384,7 @@ SV_WriteEntitiesToClient void SV_WriteEntitiesToClient (client_t *client, edict_t *clent, sizebuf_t *msg) { int e, clentnum, bits, alpha, glowcolor, glowsize, scale, effects, lightsize; - int culled_pvs, culled_portal, culled_trace, visibleentities, totalentities; + int culled_pvs, culled_trace, visibleentities, totalentities; qbyte *pvs; vec3_t origin, angles, entmins, entmaxs, testorigin, testeye; float nextfullupdate, alphaf; @@ -405,7 +402,6 @@ void SV_WriteEntitiesToClient (client_t *client, edict_t *clent, sizebuf_t *msg) fatbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, testeye, 8, sv_writeentitiestoclient_pvs, sizeof(sv_writeentitiestoclient_pvs)); culled_pvs = 0; - culled_portal = 0; culled_trace = 0; visibleentities = 0; totalentities = 0; @@ -509,13 +505,6 @@ void SV_WriteEntitiesToClient (client_t *client, edict_t *clent, sizebuf_t *msg) continue; } - // or not visible through the portals - if (sv_cullentities_portal.integer && !Portal_CheckBox(sv.worldmodel, testeye, entmins, entmaxs)) - { - culled_portal++; - continue; - } - // don't try to cull embedded brush models with this, they're sometimes huge (spanning several rooms) if (sv_cullentities_trace.integer && (model == NULL || model->type != mod_brush || model->name[0] != '*')) { @@ -713,7 +702,7 @@ void SV_WriteEntitiesToClient (client_t *client, edict_t *clent, sizebuf_t *msg) } if (sv_cullentities_stats.integer) - Con_Printf("client \"%s\" entities: %d total, %d visible, %d culled by: %d pvs %d portal %d trace\n", client->name, totalentities, visibleentities, culled_pvs + culled_portal + culled_trace, culled_pvs, culled_portal, culled_trace); + Con_Printf("client \"%s\" entities: %d total, %d visible, %d culled by: %d pvs %d trace\n", client->name, totalentities, visibleentities, culled_pvs + culled_trace, culled_pvs, culled_trace); } #else static int numsendentities; @@ -833,7 +822,6 @@ static int sententitiesmark = 0; static int sententities[MAX_EDICTS]; static int sententitiesconsideration[MAX_EDICTS]; static int sv_writeentitiestoclient_culled_pvs; -static int sv_writeentitiestoclient_culled_portal; static int sv_writeentitiestoclient_culled_trace; static int sv_writeentitiestoclient_visibleentities; static int sv_writeentitiestoclient_totalentities; @@ -924,12 +912,6 @@ void SV_MarkWriteEntityStateToClient(entity_state_t *s) sv_writeentitiestoclient_culled_pvs++; return; } - // or not visible through the portals - if (sv_cullentities_portal.integer && !Portal_CheckBox(sv.worldmodel, sv_writeentitiestoclient_testeye, lightmins, lightmaxs)) - { - sv_writeentitiestoclient_culled_portal++; - return; - } // or not seen by random tracelines if (sv_cullentities_trace.integer) { @@ -1000,7 +982,6 @@ void SV_WriteEntitiesToClient(client_t *client, edict_t *clent, sizebuf_t *msg) sv_writeentitiestoclient_client = client; sv_writeentitiestoclient_culled_pvs = 0; - sv_writeentitiestoclient_culled_portal = 0; sv_writeentitiestoclient_culled_trace = 0; sv_writeentitiestoclient_visibleentities = 0; sv_writeentitiestoclient_totalentities = 0; @@ -1109,7 +1090,7 @@ void SV_WriteEntitiesToClient(client_t *client, edict_t *clent, sizebuf_t *msg) d->currentcommit = NULL; if (sv_cullentities_stats.integer) - Con_Printf("client \"%s\" entities: %d total, %d visible, %d culled by: %d pvs %d portal %d trace\n", client->name, sv_writeentitiestoclient_totalentities, sv_writeentitiestoclient_visibleentities, sv_writeentitiestoclient_culled_pvs + sv_writeentitiestoclient_culled_portal + sv_writeentitiestoclient_culled_trace, sv_writeentitiestoclient_culled_pvs, sv_writeentitiestoclient_culled_portal, sv_writeentitiestoclient_culled_trace); + Con_Printf("client \"%s\" entities: %d total, %d visible, %d culled by: %d pvs %d trace\n", client->name, sv_writeentitiestoclient_totalentities, sv_writeentitiestoclient_visibleentities, sv_writeentitiestoclient_culled_pvs + sv_writeentitiestoclient_culled_trace, sv_writeentitiestoclient_culled_pvs, sv_writeentitiestoclient_culled_trace); } #endif @@ -1836,7 +1817,7 @@ void SV_SpawnServer (const char *server) sv.model_precache[0] = ""; sv.model_precache[1] = sv.modelname; - for (i = 1;i < sv.worldmodel->brushq1.numsubmodels;i++) + for (i = 1;i < sv.worldmodel->brush.numsubmodels;i++) { sv.model_precache[i+1] = localmodels[i]; sv.models[i+1] = Mod_ForName (localmodels[i], false, false, false); diff --git a/todo b/todo index 404c2e6f..a5542565 100644 --- a/todo +++ b/todo @@ -1,48 +1,6 @@ - todo: difficulty ratings are: 0 = trivial, 1 = easy, 2 = easy-moderate, 3 = moderate, 4 = moderate-hard, 5 = hard, 6 = hard++, 7 = nightmare, d = done, -n = done but have not notified the people who asked for it, f = failed -d darkplaces: finish the partial update support in protocol.[ch] and reduce packet size to 1k to fix NAT routers (yummyluv, Vermeulen, Elric) -d darkplaces: fix server crashing from client timeouts (Moz) -d darkplaces: fix server list only querying the master to reply (Rick) -d darkplaces: fix sounds not following entities (yummyluv, SeienAbunae) +-n darkplaces: revert noclip movement to match nq for compatibility with mods that trap movement as input (MauveBib) -n dpmod: make grapple off-hand (joe hill) -0 dpmod: add a "monsterwander" cvar and default it off, this would enable the spawnwanderpath code (Zombie13) -0 darkplaces: stuttering movement when walking over steps or monsters (romi) -0 darkplaces: bullets don't hit walls at steep angles in id1 -0 darkplaces: hack PF_nextent to skip inaccessible client slots depending on maxplayers - but always report ones that are active at the time (FrikaC) -0 darkplaces: client colors being reset to "15 15" each level in prydon gate (FrikaC) -0 darkplaces: make lightning work without bolt models persent (Vermeulen) -0 darkplaces: make the WriteEntitiesToClient code call TraceBox directly instead of SV_Move because checking all the entities is far too slow in helm18 (banshee21) -0 darkplaces: add te_flamejet builtin and add extension (Supajoe) -0 darkplaces: pointcontents crash when building harvester in gvb2? (yummyluv) -0 darkplaces: integrate zinx's psycho.c gamma hack as an easteregg -0 dpmod: crash when dog attacks you in dpdm2 deathmatch 7 with bots present (Zombie13) -0 dpmod: identify what could cause huge angles values (1187488512.0000) on a dog entity, may be related to anglemod, FacingIdeal, ai_run, or dog_run2 (Zombie13) -0 dpmod: modify anglemod to be able to recover from extremely large angles numbers (Zombie13) -0 darkplaces: add error messages to LHNET_OpenSocket_Connectionless or its callers (Zombie13) -0 dpmod: find a way to make deathmatch 7 get more difficulty as kills increase? (Zombie13) -0 darkplaces: can't move when stuck in a monster (SeienAbunae) -0 dpmod: monsters falling out of level? (SeienAbunae) -0 dpmod: add killing spree reporting; how many kills since spawn when you die, as well as announcing when you hit certain numbers of kills (SeienAbunae) -0 dpmod: add combo kill detection; rapid burst of kills (SeienAbunae) -0 darkplaces: may be reading md3 tag matrices wrong (Electro) -d dpmod: add back charge-up on plasma rifle alt-fire and increase the max charge to 50 cells -0 darkplaces: make sure that disappearing entities are removed on the client in quake demos, they aren't currently -0 darkplaces: scrags frequently fly through ceilings - this needs to be fixed -0 dpmod: set oldorigin when spawning to prevent being stuck at the spawn from causing an instant teleport back to where you died (SeienAbunae) -0 darkplaces: model interpolation off crashes? (SeienAbunae) -0 dpmod: impulse 102 isn't removing the bots (SeienAbunae) -d dpmod: make enforcers drop more cells for plasma gun (SeienAbunae) -d dpmod: make tarbabies easier to kill? (SeienAbunae) -f dpmod: make tarbabies have a self.resist_explosive = 3; like zombies (SeienAbunae) -d dpmod: make tarbabies explode larger (SeienAbunae) -0 darkplaces: make sure that sound engine does not remove sounds when volume drops to 0 due to going out of range (SeienAbunae) -0 darkplaces: crashes if you type too long a command line in the console (SeienAbunae) -0 darkplaces: fix 'wall hugging' stuttering (romi) -0 darkplaces: fix intermission failing to move view to intermission camera (romi, Zombie_13) -0 darkplaces: fix key based turning being affected by slowmo - it should not be -0 darkplaces: add view height to chase_active again (yummyluv) -0 darkplaces: examine the surface rendering code to make sure it has no bugs regarding texture selection for any of the passes (sublim3) -1 darkplaces: add rate command (and _cl_rate cvar to save to config) to control client rate (send to server on connect as a command, like other properties) (Transfusion) -3 darkplaces: add sv_rate cvar (limits total rate of the server - rather complicated rules to distribute rate between clients on the server, honoring their requests as best as possible) (Transfusion) 0 darkplaces: ability to disable fopen builtin access to read /, read data/, write data/, or disable fopen builtin entirely 0 darkplaces: add DP_GFX_QUAKE3MODELTAGS, DP_GFX_SKINFILES, and any other new extensions to the wiki 0 darkplaces: add DP_LITSUPPORT extension @@ -54,34 +12,47 @@ d dpmod: make tarbabies explode larger (SeienAbunae) 0 darkplaces: add bullet hole decals to the particlefont (Vermeulen) 0 darkplaces: add cl_particles_quality cvar (1-10) which would scale count of particles and inversely scale alpha of particles (TheBeast) 0 darkplaces: add cvars for sbar alpha (background and foreground) (Throvold@uboot.com) +0 darkplaces: add error messages to LHNET_OpenSocket_Connectionless or its callers (Zombie13) 0 darkplaces: add lightning beam settings to menu (romi) 0 darkplaces: add svc_setanglefloat and DP_SVC_SETANGLEFLOAT extension (FrikaC, SeienAbunae) +0 darkplaces: add te_flamejet builtin and add extension (Supajoe) +0 darkplaces: add view height to chase_active again (yummyluv) +0 darkplaces: bullets don't hit walls at steep angles in id1 +0 darkplaces: can't move when stuck in a monster (SeienAbunae) 0 darkplaces: change particle() macro in cl_particles.c to have a do{}while(0) to eat the ; 0 darkplaces: check out qe1 textures and make sure they load in all the e1 maps, report of crashing in most but not all maps (Linny Amore) 0 darkplaces: cl_particles_maximum cvar (default 32768) which would change number of particles allowed at once (TheBeast) +0 darkplaces: client colors being reset to "15 15" each level in prydon gate (FrikaC) +0 darkplaces: crashes if you type too long a command line in the console (SeienAbunae) 0 darkplaces: darkplaces-glx -path transfusion crashes, fix the crash even though it's not going to work anyway (Todd) 0 darkplaces: default to 32bit color 0 darkplaces: delay "connect" and "playdemo" and "timedemo" until after video init to cause quicker video startup (KrimZon) 0 darkplaces: document how polygon collision works in the code (KrimZon) 0 darkplaces: document the TEI stuff used in Nexuiz? check telejano site first (SeienAbunae) +0 darkplaces: examine the surface rendering code to make sure it has no bugs regarding texture selection for any of the passes (sublim3) 0 darkplaces: figure out and fix the 'rubbing against a moving door causes block' bug (Static_Fiend) 0 darkplaces: figure out random crashes on map changes (Uffe, QorpsE) 0 darkplaces: figure out what's wrong with gloss rendering vertex calculations, which may be GF2 related (QorpsE) 0 darkplaces: figure out why monsters keep making fall pain sound after they've landed in dpmod (Cruaich) +0 darkplaces: fix 'wall hugging' stuttering (romi) 0 darkplaces: fix a crash when changing level while using qe1 textures (Todd) 0 darkplaces: fix con_notify (should control number of lines) +0 darkplaces: fix intermission failing to move view to intermission camera (romi, Zombie_13) +0 darkplaces: fix key based turning being affected by slowmo - it should not be 0 darkplaces: fix skybox geometry (SeienAbunae) 0 darkplaces: fix the fact singleplayer is using maxplayers 8 0 darkplaces: fix view blends slightly lingering as time goes on, they should go away completely (Cruaich) -2 darkplaces: frikbot scores don't update - discovered this is because of the fact they have no client (Todd) 0 darkplaces: get rid of stencil options and make 32bit color automatically use stencil +0 darkplaces: hack PF_nextent to skip inaccessible client slots depending on maxplayers - but always report ones that are active at the time (FrikaC) 0 darkplaces: identify weird lightmap texturing bug on TNT cards - goes away in r_textureunits 1 (NotoriousRay, Uffe) +0 darkplaces: integrate zinx's psycho.c gamma hack as an easteregg 0 darkplaces: make Com_HexDumpToConsole not use color 0 darkplaces: make DP_EF_FULLBRIGHT extension (FrikaC) 0 darkplaces: make S_Update take a matrix4x4_t * 0 darkplaces: make a flag for rtlights that makes them appear in normal mode (not just r_shadow_realtime_world mode) (Vermeulen) 0 darkplaces: make dedicated server not load images (maybe all fail?) 0 darkplaces: make fopen builtin check / as well as data/ when reading (writing would always go in data/) +0 darkplaces: make lightning work without bolt models persent (Vermeulen) 0 darkplaces: make memory pools have a flag to print them as temporary pools (I.E. consider them leaks if anything is in them) (Vicious) 0 darkplaces: make server queries use a queue to avoid flooding out queries too fast, and then change the reply receive code drop packets from servers not in the list (Willis) 0 darkplaces: make sure EF_FULLBRIGHT works on bmodels (FrikaC) @@ -90,22 +61,39 @@ d dpmod: make tarbabies explode larger (SeienAbunae) 0 darkplaces: make sure PR_SetString points NULL strings at pr_strings (which would be an offset of 0) (Fuh) 0 darkplaces: make sure QuakeDoneQuick works (Chris Kemp) 0 darkplaces: make sure r_fullbright works - need to fix maxplayers checking +0 darkplaces: make sure that disappearing entities are removed on the client in quake demos, they aren't currently 0 darkplaces: make sure that sky works without a valid size (just treat it as single layer clouds or non-animated) (tell Vermeulen) +0 darkplaces: make sure that sound engine does not remove sounds when volume drops to 0 due to going out of range (SeienAbunae) +0 darkplaces: make the WriteEntitiesToClient code call TraceBox directly instead of SV_Move because checking all the entities is far too slow in helm18 (banshee21) +0 darkplaces: may be reading md3 tag matrices wrong (Electro) +0 darkplaces: model interpolation off crashes? (SeienAbunae) +0 darkplaces: pointcontents crash when building harvester in gvb2? (yummyluv) 0 darkplaces: r_shadow should load .ent when importing light entities 0 darkplaces: r_skyscroll1 and r_skyscroll2 cvars (SeienAbunae) 0 darkplaces: rename r_picmip and r_max_size and such to glquake names 0 darkplaces: reset zoom on connect (Rick) --n darkplaces: revert noclip movement to match nq for compatibility with mods that trap movement as input (MauveBib) +0 darkplaces: scrags frequently fly through ceilings - this needs to be fixed 0 darkplaces: segfault reading memory in windows when starting a new server from menu (yummyluv) +0 darkplaces: stuttering movement when walking over steps or monsters (romi) 0 darkplaces: test TecnoX and find the frikbot crash in SV_Physics (KrimZon) 0 darkplaces: test zlib support with entirely pk3'd id1 data (should crash because of zlib not being setup early enough - fix this) (Mabus) 0 darkplaces: the new sound engine should have a cvar for random variations of pitch on sounds like in doom (RenegadeC) 0 darkplaces: try not adding gravity when onground to see if it gets rid of ramp sliding (Midgar) 0 darkplaces: tweak the blood decals in the particlefont to make them look more like the q2e_blood.avi video (Vermeulen) +0 dpmod: add a "monsterwander" cvar and default it off, this would enable the spawnwanderpath code (Zombie13) +0 dpmod: add combo kill detection; rapid burst of kills (SeienAbunae) 0 dpmod: add flame thrower enforcers back (scar3crow) 0 dpmod: add flame thrower weapon, and make its altfire drop a canister of fuel (10 fuel units?), which can be ignited to set off as a bomb about the size of a rocket blast, plus some fireballs raining down (scar3crow) +0 dpmod: add killing spree reporting; how many kills since spawn when you die, as well as announcing when you hit certain numbers of kills (SeienAbunae) +0 dpmod: crash when dog attacks you in dpdm2 deathmatch 7 with bots present (Zombie13) +0 dpmod: find a way to make deathmatch 7 get more difficulty as kills increase? (Zombie13) +0 dpmod: identify what could cause huge angles values (1187488512.0000) on a dog entity, may be related to anglemod, FacingIdeal, ai_run, or dog_run2 (Zombie13) +0 dpmod: impulse 102 isn't removing the bots (SeienAbunae) 0 dpmod: impulse 154 should cycle to deathmatch 7 (Rick) 0 dpmod: items aren't respawning in coop, they should +0 dpmod: modify anglemod to be able to recover from extremely large angles numbers (Zombie13) +0 dpmod: monsters falling out of level? (SeienAbunae) +0 dpmod: set oldorigin when spawning to prevent being stuck at the spawn from causing an instant teleport back to where you died (SeienAbunae) 0 dpmod: try making ball lightning mortar shamblers (scar3crow) 0 dpmod: up nail limit to 500 (scar3crow) 0 dpzoo: colored lighting @@ -140,6 +128,7 @@ d dpmod: make tarbabies explode larger (SeienAbunae) 1 darkplaces: add log cvar to set console logging target (default "", or default "qconsole.log" if -condebug is used) 1 darkplaces: add r_displayrefresh cvar for windows video refresh settings (Willis) 1 darkplaces: add r_waterwarp to allow disabling view squishing underwater +1 darkplaces: add rate command (and _cl_rate cvar to save to config) to control client rate (send to server on connect as a command, like other properties) (Transfusion) 1 darkplaces: add some particles to teleportsplash (Uffe) 1 darkplaces: check out QMB lightning and lava effects (jeremy janzen) 1 darkplaces: clear stainmaps on map restart/change based on cl_stainmapsclearonload cvar (John Truex, Electro) @@ -185,6 +174,7 @@ d dpmod: make tarbabies explode larger (SeienAbunae) 2 darkplaces: add stats to slist menu displaying how many masters/servers have been queried and replied (tell yummyluv) 2 darkplaces: figure out how to prevent "alias a a" - infinite loop when executed, this should be detected when executing it (Vicious) 2 darkplaces: figure out why -sndspeed 22050, 44100 and 16000 are choppy in windows? (cheapalert) +2 darkplaces: frikbot scores don't update - discovered this is because of the fact they have no client (Todd) 2 darkplaces: implement menu_clearkeyconfig and menu_keyconfig and the corresponding menu (diGGer) 2 darkplaces: lerp lightstyles (Mitchell) 2 darkplaces: locked console scrollback (sublim3) @@ -211,6 +201,7 @@ d dpmod: make tarbabies explode larger (SeienAbunae) 3 darkplaces: add back r_waterripple (Vermeulen) 3 darkplaces: add ogg music playback using optional library after adding wav music playback (Joseph Caporale, Static_Fiend) 3 darkplaces: add stainmaps to realtime lighting mode +3 darkplaces: add sv_rate cvar (limits total rate of the server - rather complicated rules to distribute rate between clients on the server, honoring their requests as best as possible) (Transfusion) 3 darkplaces: call checkvelocity (to clear NaNs) every time velocity is set in physics, to fix frikbot (tell FrikaC) 3 darkplaces: dpshaders (when supported) should have support for envmaps, and should support being lit by diffuse lighting as a fake gloss effect for normal mode (Vermeulen) 3 darkplaces: dsound broken, needs to be managed as part of video system (jeremy janzen) @@ -288,6 +279,7 @@ d darkplaces: figure out what is wrong with loading _glow/_luma textures on md3 d darkplaces: figure out why disconnections are showing up as " disconnected" d darkplaces: figure out why quad is creating two coronas, one at player and one at 0 0 0 - answer: viewmodel dlight (Tomaz) d darkplaces: finish new udp networking code (yummyluv) +d darkplaces: finish the partial update support in protocol.[ch] and reduce packet size to 1k to fix NAT routers (yummyluv, Vermeulen, Elric) d darkplaces: fix PF_substring's mishandling of the end variable (Fuh) d darkplaces: fix Short format entity origins to fix shell casings sitting in floor/above floor (Tomaz) d darkplaces: fix bounding box bugs with viewmodelforclient (diGGer) @@ -300,7 +292,10 @@ d darkplaces: fix md3 shadow volumes d darkplaces: fix network timeouts d darkplaces: fix non-polygonal lightning beam model pitch (it was backwards) (thanks Eksess for reporting this) d darkplaces: fix particle trails (I think trail start is identical to trail end) (Supajoe, SeienAbunae) +d darkplaces: fix server crashing from client timeouts (Moz) d darkplaces: fix server list not working until you set maxplayers above 1 (Rick) +d darkplaces: fix server list only querying the master to reply (Rick) +d darkplaces: fix sounds not following entities (yummyluv, SeienAbunae) d darkplaces: fix starting non-existent maps. (drops to console with an error like it should) d darkplaces: fix startup on multiplayer games so they don't start a game when executing startdemos unless -listen or -dedicated was used (yummyluv) d darkplaces: fix toggling decals in menu @@ -325,10 +320,14 @@ d darkplaces: release new hmap (fixes compilation of TF entities for one person, d darkplaces: release new hqbsp with -wadpath support (also searchs in map's directory and map's parent directory) d darkplaces: remove frags per hour rating from scoreboard because it depends on cl.scores[i]->entertime (which is never set) d darkplaces: tags support on md3 (Electro needs this urgently) +d dpmod: add back charge-up on plasma rifle alt-fire and increase the max charge to 50 cells d dpmod: add back tarbaby gibs (scar3crow) d dpmod: add frags for killing monsters in dpmod (scar3crow) d dpmod: change weapons 8-10 to lightning, plasma, plasma wave (joe hill) d dpmod: fix backpacks (giving no ammo) +d dpmod: make enforcers drop more cells for plasma gun (SeienAbunae) +d dpmod: make tarbabies easier to kill? (SeienAbunae) +d dpmod: make tarbabies explode larger (SeienAbunae) d dpmod: post new dpmod build. d dpmod: switch to new Tomaz weapon models d dpmod: why can't I pick up nails when I have no nailguns? and other similar pickup problems with weapons @@ -338,4 +337,5 @@ d lmp2pcx: post new lmp2pcx build. f darkplaces: add _0.tga support (per texture) to bsp/md2/md3 loaders f darkplaces: examine proquake code to find nat fix and implement similar in darkplaces f darkplaces: look at and integrate Vic's updated zone.[ch] (Vic) +f dpmod: make tarbabies have a self.resist_explosive = 3; like zombies (SeienAbunae) diff --git a/world.c b/world.c index fe825057..373ac3e5 100644 --- a/world.c +++ b/world.c @@ -30,7 +30,6 @@ line of sight checks trace->inopen and trace->inwater, but bullets don't */ cvar_t sv_debugmove = {CVAR_NOTIFY, "sv_debugmove", "0"}; -cvar_t sv_polygoncollisions = {CVAR_NOTIFY, "sv_polygoncollisions", "0"}; cvar_t sv_areagrid_mingridsize = {CVAR_NOTIFY, "sv_areagrid_mingridsize", "64"}; void SV_AreaStats_f(void); @@ -38,7 +37,6 @@ void SV_AreaStats_f(void); void SV_World_Init(void) { Cvar_RegisterVariable(&sv_debugmove); - Cvar_RegisterVariable(&sv_polygoncollisions); Cvar_RegisterVariable(&sv_areagrid_mingridsize); Cmd_AddCommand("sv_areastats", SV_AreaStats_f); Collision_Init(); @@ -491,10 +489,7 @@ trace_t SV_ClipMoveToEntity(edict_t *ent, const vec3_t start, const vec3_t mins, VectorAdd(starttransformed, mins, starttransformedmins); VectorAdd(endtransformed, mins, endtransformedmins); - // FIXME: the PolygonClipTrace should go away (should all be done in model code) - if (sv_polygoncollisions.integer == 1) - Collision_PolygonClipTrace(&trace, ent, model, vec3_origin, vec3_origin, ent->v->mins, ent->v->maxs, starttransformed, mins, maxs, endtransformed); - else if (model && model->brush.TraceBox) + if (model && model->brush.TraceBox) model->brush.TraceBox(model, &trace, starttransformedmins, starttransformedmaxs, endtransformedmins, endtransformedmaxs); else Collision_ClipTrace_Box(&trace, ent->v->mins, ent->v->maxs, starttransformed, mins, maxs, endtransformed); @@ -626,7 +621,8 @@ trace_t SV_Move(const vec3_t start, const vec3_t mins, const vec3_t maxs, const clip.type = type; clip.passedict = passedict; - Collision_RoundUpToHullSize(sv.worldmodel, clip.mins, clip.maxs, clip.hullmins, clip.hullmaxs); + if (sv.worldmodel && sv.worldmodel->brush.RoundUpToHullSize) + sv.worldmodel->brush.RoundUpToHullSize(sv.worldmodel, clip.mins, clip.maxs, clip.hullmins, clip.hullmaxs); // clip to world clip.trace = SV_ClipMoveToEntity(sv.edicts, clip.start, clip.hullmins, clip.hullmaxs, clip.end); -- 2.39.2