#define CONTENTSQ3_TRIGGER 0x40000000 // used by trigger entities
#define CONTENTSQ3_NODROP 0x80000000 // remove items that fall into this brush
+#define SUPERCONTENTS_SOLID 0x00000001
+#define SUPERCONTENTS_WATER 0x00000002
+#define SUPERCONTENTS_SLIME 0x00000004
+#define SUPERCONTENTS_LAVA 0x00000008
+#define SUPERCONTENTS_SKY 0x00000010
+#define SUPERCONTENTS_BODY 0x00000020
+#define SUPERCONTENTS_CORPSE 0x00000040
+#define SUPERCONTENTS_LIQUIDSMASK (SUPERCONTENTS_LAVA | SUPERCONTENTS_SLIME | SUPERCONTENTS_WATER)
+
+/*
+#define SUPERCONTENTS_DEADMONSTER 0x00000000
+#define SUPERCONTENTS_CURRENT_0 0x00000000
+#define SUPERCONTENTS_CURRENT_90 0x00000000
+#define SUPERCONTENTS_CURRENT_180 0x00000000
+#define SUPERCONTENTS_CURRENT_270 0x00000000
+#define SUPERCONTENTS_CURRENT_DOWN 0x00000000
+#define SUPERCONTENTS_CURRENT_UP 0x00000000
+#define SUPERCONTENTS_AREAPORTAL 0x00000000
+#define SUPERCONTENTS_AUX 0x00000000
+#define SUPERCONTENTS_CLUSTERPORTAL 0x00000000
+#define SUPERCONTENTS_DETAIL 0x00000000
+#define SUPERCONTENTS_STRUCTURAL 0x00000000
+#define SUPERCONTENTS_DONOTENTER 0x00000000
+#define SUPERCONTENTS_JUMPPAD 0x00000000
+#define SUPERCONTENTS_LADDER 0x00000000
+#define SUPERCONTENTS_MONSTER 0x00000000
+#define SUPERCONTENTS_MONSTERCLIP 0x00000000
+#define SUPERCONTENTS_NODROP 0x00000000
+#define SUPERCONTENTS_PLAYERCLIP 0x00000000
+#define SUPERCONTENTS_TELEPORTER 0x00000000
+#define SUPERCONTENTS_TRANSLUCENT 0x00000000
+#define SUPERCONTENTS_TRIGGER 0x00000000
+#define SUPERCONTENTS_WINDOW 0x00000000
+*/
+
typedef struct
{
middle[2] = (worldmins[2] + worldmaxs[2]) * 0.5f;
VectorAdd(start, middle, start2);
VectorAdd(end, middle, end2);
- frac = CL_TraceLine((float *)start2, (float *)end2, impactpos, impactnormal, 0, true, NULL);
+ frac = CL_TraceLine((float *)start2, (float *)end2, impactpos, impactnormal, true, NULL, SUPERCONTENTS_SOLID);
VectorSubtract(impactpos, middle, impactpos);
*impactentnum = -1;
return frac;
chase_dest[1] = r_refdef.vieworg[1] + forward[1] * dist;
chase_dest[2] = r_refdef.vieworg[2] + forward[2] * dist + chase_up.value;
- CL_TraceLine (r_refdef.vieworg, chase_dest, stop, normal, 0, true, NULL);
+ CL_TraceLine(r_refdef.vieworg, chase_dest, stop, normal, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY);
chase_dest[0] = stop[0] + forward[0] * 8 + normal[0] * 4;
chase_dest[1] = stop[1] + forward[1] * 8 + normal[1] * 4;
chase_dest[2] = stop[2] + forward[2] * 8 + normal[2] * 4;
physentity_t;
*/
-int cl_traceline_endcontents;
+int cl_traceline_startsupercontents;
-float CL_TraceLine (const vec3_t start, const vec3_t end, vec3_t impact, vec3_t normal, int contents, int hitbmodels, entity_render_t **hitent)
+float CL_TraceLine(const vec3_t start, const vec3_t end, vec3_t impact, vec3_t normal, int hitbmodels, entity_render_t **hitent, int hitsupercontentsmask)
{
float maxfrac;
int n;
*hitent = NULL;
Mod_CheckLoaded(cl.worldmodel);
if (cl.worldmodel && cl.worldmodel->brush.TraceBox)
- cl.worldmodel->brush.TraceBox(cl.worldmodel, &trace, start, start, end, end);
+ cl.worldmodel->brush.TraceBox(cl.worldmodel, &trace, start, start, end, end, hitsupercontentsmask);
if (impact)
VectorLerp(start, trace.fraction, end, impact);
if (normal)
VectorCopy(trace.plane.normal, normal);
- cl_traceline_endcontents = trace.endcontents;
+ cl_traceline_startsupercontents = trace.startsupercontents;
maxfrac = trace.fraction;
if (hitent && trace.fraction < 1)
*hitent = &cl_entities[0].render;
Matrix4x4_Transform(&imatrix, end, endtransformed);
if (ent->model && ent->model->brush.TraceBox)
- ent->model->brush.TraceBox(ent->model, &trace, starttransformed, starttransformed, endtransformed, endtransformed);
+ ent->model->brush.TraceBox(ent->model, &trace, starttransformed, starttransformed, endtransformed, endtransformed, hitsupercontentsmask);
if (trace.allsolid || trace.startsolid || maxfrac > trace.fraction)
{
- cl_traceline_endcontents = trace.endcontents;
+ cl_traceline_startsupercontents = trace.startsupercontents;
if (hitent)
*hitent = ent;
if (maxfrac > trace.fraction)
cl.worldmodel->brush.FindNonSolidLocation(cl.worldmodel, in, out, radius);
}
-int CL_PointContents(const vec3_t p)
+int CL_PointQ1Contents(const vec3_t p)
{
- CL_TraceLine (p, p, NULL, NULL, 0, true, NULL);
- return cl_traceline_endcontents;
+ CL_TraceLine(p, p, NULL, NULL, true, NULL, 0);
+ return Mod_Q1BSP_NativeContentsFromSuperContents(NULL, cl_traceline_startsupercontents);
+ /*
+ // FIXME: check multiple brush models
+ if (cl.worldmodel && cl.worldmodel->brush.PointContentsQ1)
+ return cl.worldmodel->brush.PointContentsQ1(cl.worldmodel, p);
+ return 0;
+ */
+}
+
+int CL_PointSuperContents(const vec3_t p)
+{
+ CL_TraceLine(p, p, NULL, NULL, true, NULL, 0);
+ return cl_traceline_startsupercontents;
/*
// FIXME: check multiple brush models
if (cl.worldmodel && cl.worldmodel->brush.PointContentsQ1)
// if contents is not zero, it will impact on content changes
// (leafs matching contents are considered empty, others are solid)
-extern int cl_traceline_endcontents; // set by TraceLine
+extern int cl_traceline_startcontents; // set by TraceLine
-float CL_TraceLine(const vec3_t start, const vec3_t end, vec3_t impact, vec3_t normal, int contents, int hitbmodels, entity_render_t **hitent);
+float CL_TraceLine(const vec3_t start, const vec3_t end, vec3_t impact, vec3_t normal, int hitbmodels, entity_render_t **hitent, int hitsupercontentsmask);
void CL_FindNonSolidLocation(const vec3_t in, vec3_t out, vec_t radius);
-int CL_PointContents(const vec3_t p);
+int CL_PointQ1Contents(const vec3_t p);
+int CL_PointSuperContents(const vec3_t p);
#endif
if (e->persistent.muzzleflash > 0)
{
Matrix4x4_Transform(&e->render.matrix, muzzleflashorigin, v2);
- CL_TraceLine(origin, v2, v, NULL, 0, true, NULL);
+ CL_TraceLine(origin, v2, v, NULL, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY);
CL_AllocDlight(NULL, v, e->persistent.muzzleflash, 1, 1, 1, 0, 0);
e->persistent.muzzleflash -= cl.frametime * 1000;
}
siextern float r_avertexnormals[NUMVERTEXNORMALS][3];
#define m_bytenormals r_avertexnormals
#define VectorNormalizeFast VectorNormalize
-#define CL_PointContents(v) (Mod_PointInLeaf(v,cl.worldmodel)->contents)
+#define CL_PointQ1Contents(v) (Mod_PointInLeaf(v,cl.worldmodel)->contents)
typedef unsigned char qbyte;
#define cl_stainmaps.integer 0
void R_Stain (vec3_t origin, float radius, int cr1, int cg1, int cb1, int ca1, int cr2, int cg2, int cb2, int ca2)
#include "pmove.h"
extern qboolean PM_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, pmtrace_t *trace);
#endif
-float CL_TraceLine (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal, int contents, int hitbmodels, void **hitent)
+float CL_TraceLine (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal, int hitbmodels, void **hitent, int hitsupercontentsmask)
{
#if QW
pmtrace_t trace;
{
VectorRandom(org2);
VectorMA(org, maxdist, org2, org2);
- frac = CL_TraceLine(org, org2, v, normal, 0, true, &hitent);
+ frac = CL_TraceLine(org, org2, v, normal, true, &hitent, SUPERCONTENTS_SOLID);
if (bestfrac > frac)
{
bestfrac = frac;
R_Stain(org, 96, 80, 80, 80, 64, 176, 176, 176, 64);
CL_SpawnDecalParticleForPoint(org, 40, 48, 255, tex_bulletdecal[rand()&7], 0xFFFFFF, 0xFFFFFF);
- i = CL_PointContents(org);
+ i = CL_PointQ1Contents(org);
if ((i == CONTENTS_SLIME || i == CONTENTS_WATER) && cl_particles.integer && cl_particles_bubbles.integer)
{
for (i = 0;i < 128 * cl_particles_quality.value;i++)
v[0] = org[0] + lhrandom(-64, 64);
v[1] = org[1] + lhrandom(-64, 64);
v[2] = org[2] + lhrandom(-8, 24);
- if (CL_TraceLine(org, v, v2, NULL, 0, true, NULL) >= 0.1)
+ if (CL_TraceLine(org, v, v2, NULL, true, NULL, SUPERCONTENTS_SOLID) >= 0.1)
break;
}
VectorSubtract(v2, org, v2);
org2[0] = org[0] + 0.125f * lhrandom(-count, count);
org2[1] = org[1] + 0.125f * lhrandom(-count, count);
org2[2] = org[2] + 0.125f * lhrandom(-count, count);
- CL_TraceLine(org, org2, org3, NULL, 0, true, NULL);
+ CL_TraceLine(org, org2, org3, NULL, true, NULL, SUPERCONTENTS_SOLID);
particle(pt_grow, PARTICLE_BILLBOARD, 0x101010, 0x202020, tex_smoke[rand()&7], true, PBLEND_ADD, 3, 3, (1.0f / cl_particles_quality.value) * 255, (1.0f / cl_particles_quality.value) * 1024, 9999, -0.2, 0, org3[0], org3[1], org3[2], lhrandom(-8, 8), lhrandom(-8, 8), lhrandom(0, 16), 15, 0, 0, 0, 0, 0);
}
}
org2[0] = org[0] + 0.125f * lhrandom(-bloodcount, bloodcount);
org2[1] = org[1] + 0.125f * lhrandom(-bloodcount, bloodcount);
org2[2] = org[2] + 0.125f * lhrandom(-bloodcount, bloodcount);
- CL_TraceLine(org, org2, org3, NULL, 0, true, NULL);
+ CL_TraceLine(org, org2, org3, NULL, true, NULL, SUPERCONTENTS_SOLID);
particle(pt_blood, PARTICLE_BILLBOARD, 0xFFFFFF, 0xFFFFFF, tex_bloodparticle[rand()&7], true, PBLEND_MOD, 8, 8, cl_particles_blood_alpha.value * 768 / cl_particles_quality.value, cl_particles_blood_alpha.value * 384 / cl_particles_quality.value, 9999, 0, -1, org3[0], org3[1], org3[2], vel[0] + lhrandom(-s, s), vel[1] + lhrandom(-s, s), vel[2] + lhrandom(-s, s), 0, 0, 0, 0, 1, 0);
bloodcount -= 16 / cl_particles_quality.value;
}
VectorMA(start, dec, vec, pos);
len -= dec;
- contents = CL_PointContents(pos);
+ contents = CL_PointQ1Contents(pos);
if (contents == CONTENTS_SKY || contents == CONTENTS_LAVA)
return;
VectorCopy(p->org, org);
if (p->bounce)
{
- if (CL_TraceLine(p->oldorg, p->org, v, normal, 0, true, &hitent) < 1)
+ if (CL_TraceLine(p->oldorg, p->org, v, normal, true, &hitent, SUPERCONTENTS_SOLID) < 1)
{
VectorCopy(v, p->org);
if (p->bounce < 0)
{
f = p->friction * frametime;
if (!content)
- content = CL_PointContents(p->org);
+ content = CL_PointQ1Contents(p->org);
if (content != CONTENTS_EMPTY)
f *= 4;
f = 1.0f - f;
{
case pt_blood:
if (!content)
- content = CL_PointContents(p->org);
+ content = CL_PointQ1Contents(p->org);
a = content;
if (a != CONTENTS_EMPTY)
{
break;
case pt_bubble:
if (!content)
- content = CL_PointContents(p->org);
+ content = CL_PointQ1Contents(p->org);
if (content != CONTENTS_WATER && content != CONTENTS_SLIME)
{
p->die = -1;
p->vel[2] = /*lhrandom(-32, 32) +*/ p->vel2[2];
}
if (!content)
- content = CL_PointContents(p->org);
+ content = CL_PointQ1Contents(p->org);
a = content;
if (a != CONTENTS_EMPTY && a != CONTENTS_SKY)
p->die = -1;
if (cl.worldmodel)
{
Mod_CheckLoaded(cl.worldmodel);
- contents = CL_PointContents(r_refdef.vieworg);
- if (contents != CONTENTS_EMPTY && contents != CONTENTS_SOLID)
+ contents = CL_PointSuperContents(r_refdef.vieworg);
+ if (contents & SUPERCONTENTS_LIQUIDSMASK)
{
r_refdef.fov_x *= (sin(cl.time * 4.7) * 0.015 + 0.985);
r_refdef.fov_y *= (sin(cl.time * 3.0) * 0.015 + 0.985);
#include "quakedef.h"
+#include "winding.h"
typedef struct
{
// end - start
double dist[3];
+
+ // overrides the CONTENTS_SOLID in the box bsp tree
+ int boxsupercontents;
}
RecursiveHullCheckTraceInfo_t;
// check for empty
if (num < 0)
{
- t->trace->endcontents = num;
- if (t->trace->thiscontents)
+ // translate the fake CONTENTS values in the box bsp tree
+ if (num == CONTENTS_SOLID)
+ num = t->boxsupercontents;
+ else
+ num = 0;
+ if (!t->trace->startfound)
{
- if (num == t->trace->thiscontents)
- t->trace->allsolid = false;
- else
- {
- // if the first leaf is solid, set startsolid
- if (t->trace->allsolid)
- t->trace->startsolid = true;
- return HULLCHECKSTATE_SOLID;
- }
- return HULLCHECKSTATE_EMPTY;
+ t->trace->startfound = true;
+ t->trace->startsupercontents |= num;
+ }
+ if (num & t->trace->hitsupercontentsmask)
+ {
+ // if the first leaf is solid, set startsolid
+ if (t->trace->allsolid)
+ t->trace->startsolid = true;
+ return HULLCHECKSTATE_SOLID;
}
else
{
- if (num != CONTENTS_SOLID)
- {
- t->trace->allsolid = false;
- if (num == CONTENTS_EMPTY)
- t->trace->inopen = true;
- else
- t->trace->inwater = true;
- }
- else
- {
- // if the first leaf is solid, set startsolid
- if (t->trace->allsolid)
- t->trace->startsolid = true;
- return HULLCHECKSTATE_SOLID;
- }
+ t->trace->allsolid = false;
return HULLCHECKSTATE_EMPTY;
}
}
}
}
-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)
+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, int hitsupercontentsmask, int boxsupercontents)
{
RecursiveHullCheckTraceInfo_t rhc;
// fill in a default trace
box_planes[4].dist = cmaxs[2] - mins[2];
box_planes[5].dist = cmins[2] - maxs[2];
// trace a line through the generated clipping hull
+ rhc.boxsupercontents = boxsupercontents;
rhc.hull = &box_hull;
rhc.trace = trace;
+ rhc.trace->hitsupercontentsmask = hitsupercontentsmask;
rhc.trace->fraction = 1;
rhc.trace->allsolid = true;
VectorCopy(start, rhc.start);
Con_Printf("%g %g %g %g\n", brush->planes[i].normal[0], brush->planes[i].normal[1], brush->planes[i].normal[2], brush->planes[i].dist);
}
+void Collision_ValidateBrush(colbrushf_t *brush)
+{
+ int j, k;
+ if (!brush->numpoints)
+ {
+ Con_Printf("Collision_ValidateBrush: brush with no points!\n");
+ Collision_PrintBrushAsQHull(brush, "unnamed");
+ return;
+ }
+ // it's ok for a brush to have one point and no planes...
+ if (brush->numplanes == 0 && brush->numpoints != 1)
+ {
+ Con_Printf("Collision_ValidateBrush: brush with no planes and more than one point!\n");
+ Collision_PrintBrushAsQHull(brush, "unnamed");
+ return;
+ }
+ for (k = 0;k < brush->numplanes;k++)
+ {
+ for (j = 0;j < brush->numpoints;j++)
+ {
+ if (DotProduct(brush->points[j].v, brush->planes[k].normal) - brush->planes[k].dist > (1.0f / 8.0f))
+ {
+ Con_Printf("Collision_NewBrushFromPlanes: point #%i (%f %f %f) infront of plane #%i (%f %f %f %f)\n", j, brush->points[j].v[0], brush->points[j].v[1], brush->points[j].v[2], k, brush->planes[k].normal[0], brush->planes[k].normal[1], brush->planes[k].normal[2], brush->planes[k].dist);
+ Collision_PrintBrushAsQHull(brush, "unnamed");
+ return;
+ }
+ }
+ }
+}
+
-colbrushf_t *Collision_AllocBrushFloat(mempool_t *mempool, int numpoints, int numplanes)
+colbrushf_t *Collision_NewBrushFromPlanes(mempool_t *mempool, int numoriginalplanes, const mplane_t *originalplanes, int supercontents)
{
+ int j, k, m;
+ int numpoints, maxpoints, numplanes, maxplanes, numelements, maxelements, numtriangles, numpolypoints, maxpolypoints;
+ winding_t *w;
colbrushf_t *brush;
- brush = Mem_Alloc(mempool, sizeof(colbrushf_t) + sizeof(colpointf_t) * numpoints + sizeof(colplanef_t) * numplanes);
- brush->numpoints = numpoints;
+ colpointf_t pointsbuf[256];
+ colplanef_t planesbuf[256];
+ int elementsbuf[1024];
+ int polypointbuf[256];
+ // construct a collision brush (points, planes, and renderable mesh) from
+ // a set of planes, this also optimizes out any unnecessary planes (ones
+ // whose polygon is clipped away by the other planes)
+ numpoints = 0;maxpoints = 256;
+ numplanes = 0;maxplanes = 256;
+ numelements = 0;maxelements = 1024;
+ numtriangles = 0;
+ maxpolypoints = 256;
+ for (j = 0;j < numoriginalplanes;j++)
+ {
+ // add the plane uniquely (no duplicates)
+ for (k = 0;k < numplanes;k++)
+ if (VectorCompare(planesbuf[k].normal, originalplanes[j].normal) && planesbuf[k].dist == originalplanes[j].dist)
+ break;
+ // if the plane is a duplicate, skip it
+ if (k < numplanes)
+ continue;
+ // check if there are too many and skip the brush
+ if (numplanes >= 256)
+ {
+ Con_Printf("Mod_Q3BSP_LoadBrushes: failed to build collision brush: too many planes for buffer\n");
+ Winding_Free(w);
+ return NULL;
+ }
+
+ // create a large polygon from the plane
+ w = Winding_NewFromPlane(originalplanes[j].normal[0], originalplanes[j].normal[1], originalplanes[j].normal[2], originalplanes[j].dist);
+ // clip it by all other planes
+ for (k = 0;k < numoriginalplanes && w;k++)
+ {
+ if (k != j)
+ {
+ // we want to keep the inside of the brush plane so we flip
+ // the cutting plane
+ w = Winding_Clip(w, -originalplanes[k].normal[0], -originalplanes[k].normal[1], -originalplanes[k].normal[2], -originalplanes[k].dist, true);
+ }
+ }
+ // if nothing is left, skip it
+ if (!w)
+ continue;
+
+ // copy off the number of points for later when the winding is freed
+ numpolypoints = w->numpoints;
+
+ // check if there are too many polygon vertices for buffer
+ if (numpolypoints > maxpolypoints)
+ {
+ Con_Printf("Collision_NewBrushFromPlanes: failed to build collision brush: too many points for buffer\n");
+ return NULL;
+ }
+
+ // check if there are too many triangle elements for buffer
+ if (numelements + (w->numpoints - 2) * 3 > maxelements)
+ {
+ Con_Printf("Collision_NewBrushFromPlanes: failed to build collision brush: too many triangle elements for buffer\n");
+ return NULL;
+ }
+
+ for (k = 0;k < w->numpoints;k++)
+ {
+ // check if there is already a matching point (no duplicates)
+ for (m = 0;m < numpoints;m++)
+ if (VectorDistance2(w->points[k], pointsbuf[m].v) < DIST_EPSILON)
+ break;
+
+ // if there is no match, add a new one
+ if (m == numpoints)
+ {
+ // check if there are too many and skip the brush
+ if (numpoints >= 256)
+ {
+ Con_Printf("Collision_NewBrushFromPlanes: failed to build collision brush: too many points for buffer\n");
+ Winding_Free(w);
+ return NULL;
+ }
+ // add the new one
+ VectorCopy(w->points[k], pointsbuf[numpoints].v);
+ numpoints++;
+ }
+
+ // store the index into a buffer
+ polypointbuf[k] = m;
+ }
+ Winding_Free(w);
+ w = NULL;
+
+ // add the triangles for the polygon
+ // (this particular code makes a triangle fan)
+ for (k = 0;k < numpolypoints - 2;k++)
+ {
+ numtriangles++;
+ elementsbuf[numelements++] = polypointbuf[0];
+ elementsbuf[numelements++] = polypointbuf[k + 1];
+ elementsbuf[numelements++] = polypointbuf[k + 2];
+ }
+
+ // add the new plane
+ VectorCopy(originalplanes[j].normal, planesbuf[numplanes].normal);
+ planesbuf[numplanes].dist = originalplanes[j].dist;
+ numplanes++;
+ }
+
+ // if nothing is left, there's nothing to allocate
+ if (numtriangles < 4 || numplanes < 4 || numpoints < 4)
+ return NULL;
+
+ // allocate the brush and copy to it
+ brush = Collision_AllocBrushFloat(mempool, numpoints, numplanes, numtriangles, supercontents);
+ memcpy(brush->points, pointsbuf, numpoints * sizeof(colpointf_t));
+ memcpy(brush->planes, planesbuf, numplanes * sizeof(colplanef_t));
+ memcpy(brush->elements, elementsbuf, numtriangles * sizeof(int[3]));
+ Collision_ValidateBrush(brush);
+ return brush;
+}
+
+
+
+colbrushf_t *Collision_AllocBrushFloat(mempool_t *mempool, int numpoints, int numplanes, int numtriangles, int supercontents)
+{
+ colbrushf_t *brush;
+ brush = Mem_Alloc(mempool, sizeof(colbrushf_t) + sizeof(colpointf_t) * numpoints + sizeof(colplanef_t) * numplanes + sizeof(int[3]) * numtriangles);
+ brush->supercontents = supercontents;
brush->numplanes = numplanes;
+ brush->numpoints = numpoints;
+ brush->numtriangles = numtriangles;
brush->planes = (void *)(brush + 1);
brush->points = (void *)(brush->planes + brush->numplanes);
+ brush->elements = (void *)(brush->points + brush->numpoints);
return brush;
}
#endif
}
-colbrushf_t *Collision_AllocBrushFromPermanentPolygonFloat(mempool_t *mempool, int numpoints, float *points)
+colbrushf_t *Collision_AllocBrushFromPermanentPolygonFloat(mempool_t *mempool, int numpoints, float *points, int supercontents)
{
colbrushf_t *brush;
brush = Mem_Alloc(mempool, sizeof(colbrushf_t) + sizeof(colplanef_t) * (numpoints + 2));
+ brush->supercontents = supercontents;
brush->numpoints = numpoints;
brush->numplanes = numpoints + 2;
brush->planes = (void *)(brush + 1);
brush->points = (colpointf_t *)points;
+ Host_Error("Collision_AllocBrushFromPermanentPolygonFloat: FIXME: this code needs to be updated to generate a mesh...\n");
return brush;
}
while(--numpoints)
{
dist = DotProduct(points->v, normal);
- if (bestdist > dist)
- bestdist = dist;
+ bestdist = min(bestdist, dist);
points++;
}
return bestdist;
while(--numpoints)
{
dist = DotProduct(points->v, normal);
- if (bestdist < dist)
- bestdist = dist;
+ bestdist = max(bestdist, dist);
points++;
}
return bestdist;
// NOTE: start and end of each brush pair must have same numplanes/numpoints
void Collision_TraceBrushBrushFloat(trace_t *trace, const colbrushf_t *thisbrush_start, const colbrushf_t *thisbrush_end, const colbrushf_t *thatbrush_start, const colbrushf_t *thatbrush_end)
{
- int nplane, nplane2, fstartsolid, fendsolid;
+ int nplane, nplane2, fstartsolid, fendsolid, brushsolid;
float enterfrac, leavefrac, d1, d2, f, newimpactnormal[3];
const colplanef_t *startplane, *endplane;
}
}
+ brushsolid = trace->hitsupercontentsmask & thatbrush_start->supercontents;
if (fstartsolid)
{
- trace->startsolid = true;
- if (fendsolid)
- trace->allsolid = true;
+ trace->startsupercontents |= thatbrush_start->supercontents;
+ if (brushsolid)
+ {
+ 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)
+ if (brushsolid && enterfrac > -1 && enterfrac < trace->fraction && enterfrac - (1.0f / 1024.0f) <= leavefrac)
{
trace->fraction = bound(0, enterfrac, 1);
VectorCopy(newimpactnormal, trace->plane.normal);
int i;
for (i = 0;i < MAX_BRUSHFORBOX;i++)
{
+ brushforbox_brush[i].supercontents = SUPERCONTENTS_SOLID;
brushforbox_brush[i].numpoints = 8;
brushforbox_brush[i].numplanes = 6;
brushforbox_brush[i].points = brushforbox_point + i * 8;
VectorNormalize(brush->planes[i].normal);
brush->planes[i].dist = furthestplanedist_float(brush->planes[i].normal, brush->points, brush->numpoints);
}
+ Collision_ValidateBrush(brush);
return brush;
}
+void Collision_ClipTrace_BrushBox(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, int hitsupercontentsmask)
+{
+ colbrushf_t *boxbrush, *thisbrush_start, *thisbrush_end;
+ matrix4x4_t identitymatrix;
+ vec3_t startmins, startmaxs, endmins, endmaxs;
+
+ // create brushes for the collision
+ VectorAdd(start, mins, startmins);
+ VectorAdd(start, maxs, startmaxs);
+ VectorAdd(end, mins, endmins);
+ VectorAdd(end, maxs, endmaxs);
+ Matrix4x4_CreateIdentity(&identitymatrix);
+ boxbrush = Collision_BrushForBox(&identitymatrix, cmins, cmaxs);
+ thisbrush_start = Collision_BrushForBox(&identitymatrix, startmins, startmaxs);
+ thisbrush_end = Collision_BrushForBox(&identitymatrix, endmins, endmaxs);
+
+ memset(trace, 0, sizeof(trace_t));
+ trace->hitsupercontentsmask = hitsupercontentsmask;
+ trace->fraction = 1;
+ trace->allsolid = true;
+ Collision_TraceBrushBrushFloat(trace, thisbrush_start, thisbrush_end, boxbrush, boxbrush);
+}
+
// 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,
typedef struct trace_s
{
- // if true, the entire trace was in solid
+ // if true, the entire trace was in solid (see hitsupercontentsmask)
int allsolid;
- // if true, the initial point was in solid
+ // if true, the initial point was in solid (see hitsupercontentsmask)
int startsolid;
// if true, the trace passed through empty somewhere
+ // (set only by Q1BSP tracing)
int inopen;
- // if true, the trace passed through water somewhere
+ // if true, the trace passed through water/slime/lava somewhere
+ // (set only by Q1BSP tracing)
int inwater;
// fraction of the total distance that was traveled before impact
// (1.0 = did not hit anything)
double fraction;
- // final position
+ // final position of the trace (simply a point between start and end)
double endpos[3];
- // surface normal at impact
+ // surface normal at impact (not really correct for edge collisions)
plane_t plane;
// entity the surface is on
+ // (not set by trace functions, only by physics)
void *ent;
- // if not zero, treats this value as empty, and all others as solid (impact
- // on content change)
- int thiscontents;
- // the contents at the impact or end point
- int endcontents;
+ // which SUPERCONTENTS bits to collide with, I.E. to consider solid
+ // (this also affects startsolid/allsolid)
+ int hitsupercontentsmask;
+ // the supercontents mask at the start point
+ int startsupercontents;
+ // initially false, set when the start leaf is found
+ // (set only by Q1BSP tracing and entity box tracing)
+ int startfound;
}
trace_t;
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);
+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, int hitsupercontentsmask, int boxsupercontents);
typedef struct colpointf_s
{
typedef struct colbrushf_s
{
+ // the content flags of this brush
+ int supercontents;
+ // the number of bounding planes on this brush
int numplanes;
+ // the number of corner points on this brush
int numpoints;
+ // the number of renderable triangles on this brush
+ int numtriangles;
+ // array of bounding planes on this brush
colplanef_t *planes;
+ // array of corner points on this brush
colpointf_t *points;
+ // renderable triangles, as int[3] elements indexing the points
+ int *elements;
}
colbrushf_t;
-colbrushf_t *Collision_AllocBrushFloat(mempool_t *mempool, int numpoints, int numplanes);
+colbrushf_t *Collision_AllocBrushFloat(mempool_t *mempool, int numpoints, int numplanes, int numtriangles, int supercontents);
void Collision_CalcPlanesForPolygonBrushFloat(colbrushf_t *brush);
-colbrushf_t *Collision_AllocBrushFromPermanentPolygonFloat(mempool_t *mempool, int numpoints, float *points);
+colbrushf_t *Collision_AllocBrushFromPermanentPolygonFloat(mempool_t *mempool, int numpoints, float *points, int supercontents);
+colbrushf_t *Collision_NewBrushFromPlanes(mempool_t *mempool, int numoriginalplanes, const mplane_t *originalplanes, int supercontents);
void Collision_TraceBrushBrushFloat(trace_t *trace, const colbrushf_t *thisbrush_start, const colbrushf_t *thisbrush_end, const colbrushf_t *thatbrush_start, const colbrushf_t *thatbrush_end);
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);
# End Source File\r
# Begin Source File\r
\r
+SOURCE=.\winding.c\r
+# End Source File\r
+# Begin Source File\r
+\r
SOURCE=.\world.c\r
# End Source File\r
# Begin Source File\r
# End Source File\r
# Begin Source File\r
\r
+SOURCE=.\winding.h\r
+# End Source File\r
+# Begin Source File\r
+\r
SOURCE=.\winquake.h\r
# End Source File\r
# Begin Source File\r
VectorNormalizeFast(lightdirection);
VectorMA(ent->origin, 65536.0f, lightdirection, v2);
- if (CL_TraceLine(ent->origin, v2, floororigin, surfnormal, 0, false, NULL) == 1)
+ if (CL_TraceLine(ent->origin, v2, floororigin, surfnormal, false, NULL, SUPERCONTENTS_SOLID) == 1)
return;
R_Mesh_Matrix(&ent->matrix);
cvar_t r_dynamic = {CVAR_SAVE, "r_dynamic","1"};
cvar_t r_fullbrights = {CVAR_SAVE, "r_fullbrights", "1"};
cvar_t r_shadow_cull = {0, "r_shadow_cull", "1"};
+cvar_t r_drawcollisionbrushes = {0, "r_drawcollisionbrushes", "0"};
cvar_t gl_fogenable = {0, "gl_fogenable", "0"};
cvar_t gl_fogdensity = {0, "gl_fogdensity", "0.25"};
Matrix4x4_CreateIdentity(&r_identitymatrix);
// FIXME: move this to client?
FOG_registercvars();
- Cmd_AddCommand ("timerefresh", R_TimeRefresh_f);
- Cvar_RegisterVariable (&r_drawentities);
- Cvar_RegisterVariable (&r_drawviewmodel);
- Cvar_RegisterVariable (&r_shadows);
- Cvar_RegisterVariable (&r_shadow_staticworldlights);
- Cvar_RegisterVariable (&r_speeds);
- Cvar_RegisterVariable (&r_fullbrights);
- Cvar_RegisterVariable (&r_wateralpha);
- Cvar_RegisterVariable (&r_dynamic);
- Cvar_RegisterVariable (&r_fullbright);
- Cvar_RegisterVariable (&r_textureunits);
- Cvar_RegisterVariable (&r_shadow_cull);
- Cvar_RegisterVariable (&r_lerpsprites);
- Cvar_RegisterVariable (&r_lerpmodels);
- Cvar_RegisterVariable (&r_waterscroll);
+ Cmd_AddCommand("timerefresh", R_TimeRefresh_f);
+ Cvar_RegisterVariable(&r_drawentities);
+ Cvar_RegisterVariable(&r_drawviewmodel);
+ Cvar_RegisterVariable(&r_shadows);
+ Cvar_RegisterVariable(&r_shadow_staticworldlights);
+ Cvar_RegisterVariable(&r_speeds);
+ Cvar_RegisterVariable(&r_fullbrights);
+ Cvar_RegisterVariable(&r_wateralpha);
+ Cvar_RegisterVariable(&r_dynamic);
+ Cvar_RegisterVariable(&r_fullbright);
+ Cvar_RegisterVariable(&r_textureunits);
+ Cvar_RegisterVariable(&r_shadow_cull);
+ Cvar_RegisterVariable(&r_lerpsprites);
+ Cvar_RegisterVariable(&r_lerpmodels);
+ Cvar_RegisterVariable(&r_waterscroll);
+ Cvar_RegisterVariable(&r_drawcollisionbrushes);
if (gamemode == GAME_NEHAHRA || gamemode == GAME_NEXUIZ)
Cvar_SetValue("r_fullbrights", 0);
R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
*/
void R_DrawNoModel(entity_render_t *ent);
-void R_DrawModels ()
+void R_DrawModels(void)
{
int i;
entity_render_t *ent;
}
}
-void R_DrawFakeShadows (void)
+void R_DrawFakeShadows(void)
{
int i;
entity_render_t *ent;
if (!intimerefresh && !r_speeds.integer)
S_ExtraUpdate ();
- R_DrawModels(r_shadow_realtime_world.integer);
+ R_DrawModels();
R_TimeReport("models");
if (r_shadows.integer == 1 && !r_shadow_realtime_world.integer)
}
}
+void R_DrawCollisionBrush(colbrushf_t *brush)
+{
+ int i;
+ i = ((int)brush) / sizeof(colbrushf_t);
+ GL_Color((i & 31) * (1.0f / 32.0f) * r_colorscale, ((i >> 5) & 31) * (1.0f / 32.0f) * r_colorscale, ((i >> 10) & 31) * (1.0f / 32.0f) * r_colorscale, 0.2f);
+ GL_VertexPointer(brush->points->v);
+ R_Mesh_Draw(brush->numpoints, brush->numtriangles, brush->elements);
+}
+
void R_Q3BSP_DrawFace_Mesh(entity_render_t *ent, q3mface_t *face)
{
- const surfmesh_t *mesh;
rmeshstate_t m;
memset(&m, 0, sizeof(m));
GL_BlendFunc(GL_ONE, GL_ZERO);
}
R_Mesh_State_Texture(&m);
GL_VertexPointer(face->data_vertex3f);
- R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
+ R_Mesh_Draw(face->numvertices, face->numtriangles, face->data_element3i);
}
void R_Q3BSP_DrawFace_Patch(entity_render_t *ent, q3mface_t *face)
void R_Q3BSP_DrawFace(entity_render_t *ent, q3mface_t *face)
{
+ if (face->texture->renderflags & Q3MTEXTURERENDERFLAGS_NODRAW)
+ return;
switch(face->type)
{
case Q3FACETYPE_POLYGON:
q3mface_t *face;
model_t *model;
model = ent->model;
- for (i = 0, face = model->brushq3.data_thismodel->firstface;i < model->brushq3.data_thismodel->numfaces;i++, face++)
- R_Q3BSP_DrawFace(ent, face);
+ R_Mesh_Matrix(&ent->matrix);
+ if (r_drawcollisionbrushes.integer < 2)
+ for (i = 0, face = model->brushq3.data_thismodel->firstface;i < model->brushq3.data_thismodel->numfaces;i++, face++)
+ R_Q3BSP_DrawFace(ent, face);
+ if (r_drawcollisionbrushes.integer >= 1)
+ {
+ rmeshstate_t m;
+ memset(&m, 0, sizeof(m));
+ GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
+ GL_DepthMask(false);
+ GL_DepthTest(true);
+ R_Mesh_State_Texture(&m);
+ for (i = 0;i < model->brushq3.data_thismodel->numbrushes;i++)
+ if (model->brushq3.data_thismodel->firstbrush[i].colbrushf && model->brushq3.data_thismodel->firstbrush[i].colbrushf->numtriangles)
+ R_DrawCollisionBrush(model->brushq3.data_thismodel->firstbrush[i].colbrushf);
+ }
}
/*
numplayers = bound(1, numplayers, MAX_SCOREBOARD);
- if (numplayers > 1)
- {
- if (!deathmatch.integer)
- Cvar_SetValueQuick(&deathmatch, 1);
- }
- else
- Cvar_SetValueQuick(&deathmatch, 0);
+ if (numplayers > 1 && !deathmatch.integer)
+ Cvar_SetValueQuick(&deathmatch, 1);
Cvar_SetValueQuick(&sv_maxplayers, numplayers);
}
filematch.o host.o host_cmd.o image.o mathlib.o matrixlib.o \
model_alias.o model_brush.o model_shared.o model_sprite.o \
netconn.o lhnet.o palette.o portals.o protocol.o fs.o \
- sys_shared.o world.o wad.o zone.o
+ sys_shared.o winding.o world.o wad.o zone.o
COMMONOBJECTS= $(CLIENTOBJECTS) $(SERVEROBJECTS) $(SHAREDOBJECTS)
# note that builddate.c is very intentionally not compiled to a .o before
right[2] = forward[1];
d = DotProduct(forward, right);
- right[0] -= d * forward[0];
- right[1] -= d * forward[1];
- right[2] -= d * forward[2];
+ VectorMA(right, -d, forward, right);
VectorNormalizeFast(right);
CrossProduct(right, forward, up);
}
right[2] = forward[1];
d = DotProduct(forward, right);
- right[0] -= d * forward[0];
- right[1] -= d * forward[1];
- right[2] -= d * forward[2];
+ VectorMA(right, -d, forward, right);
VectorNormalize(right);
CrossProduct(right, forward, up);
}
#include "quakedef.h"
#include "image.h"
#include "r_shadow.h"
+#include "winding.h"
// note: model_shared.c sets up r_notexture, and r_surf_notexture
VectorCopy(info.center, out);
}
+int Mod_Q1BSP_SuperContentsFromNativeContents(model_t *model, int nativecontents)
+{
+ switch(nativecontents)
+ {
+ case CONTENTS_EMPTY:
+ return 0;
+ case CONTENTS_SOLID:
+ return SUPERCONTENTS_SOLID;
+ case CONTENTS_WATER:
+ return SUPERCONTENTS_WATER;
+ case CONTENTS_SLIME:
+ return SUPERCONTENTS_SLIME;
+ case CONTENTS_LAVA:
+ return SUPERCONTENTS_LAVA;
+ case CONTENTS_SKY:
+ return SUPERCONTENTS_SKY;
+ }
+ return 0;
+}
+
+int Mod_Q1BSP_NativeContentsFromSuperContents(model_t *model, int supercontents)
+{
+ if (supercontents & SUPERCONTENTS_SOLID)
+ return CONTENTS_SOLID;
+ if (supercontents & SUPERCONTENTS_SKY)
+ return CONTENTS_SKY;
+ if (supercontents & SUPERCONTENTS_LAVA)
+ return CONTENTS_LAVA;
+ if (supercontents & SUPERCONTENTS_SLIME)
+ return CONTENTS_SLIME;
+ if (supercontents & SUPERCONTENTS_WATER)
+ return CONTENTS_WATER;
+ return CONTENTS_EMPTY;
+}
+
typedef struct
{
// the hull we're tracing through
// check for empty
if (num < 0)
{
- t->trace->endcontents = num;
- if (t->trace->thiscontents)
+ num = Mod_Q1BSP_SuperContentsFromNativeContents(NULL, num);
+ if (!t->trace->startfound)
{
- if (num == t->trace->thiscontents)
- t->trace->allsolid = false;
- else
- {
- // if the first leaf is solid, set startsolid
- if (t->trace->allsolid)
- t->trace->startsolid = true;
- return HULLCHECKSTATE_SOLID;
- }
- return HULLCHECKSTATE_EMPTY;
+ t->trace->startfound = true;
+ t->trace->startsupercontents |= num;
+ }
+ if (num & SUPERCONTENTS_LIQUIDSMASK)
+ t->trace->inwater = true;
+ if (num == 0)
+ t->trace->inopen = true;
+ if (num & t->trace->hitsupercontentsmask)
+ {
+ // if the first leaf is solid, set startsolid
+ if (t->trace->allsolid)
+ t->trace->startsolid = true;
+ return HULLCHECKSTATE_SOLID;
}
else
{
- if (num != CONTENTS_SOLID)
- {
- t->trace->allsolid = false;
- if (num == CONTENTS_EMPTY)
- t->trace->inopen = true;
- else
- t->trace->inwater = true;
- }
- else
- {
- // if the first leaf is solid, set startsolid
- if (t->trace->allsolid)
- t->trace->startsolid = true;
- return HULLCHECKSTATE_SOLID;
- }
+ t->trace->allsolid = false;
return HULLCHECKSTATE_EMPTY;
}
}
return HULLCHECKSTATE_DONE;
}
-static void Mod_Q1BSP_TraceBox(struct model_s *model, trace_t *trace, const vec3_t boxstartmins, const vec3_t boxstartmaxs, const vec3_t boxendmins, const vec3_t boxendmaxs)
+static void Mod_Q1BSP_TraceBox(struct model_s *model, trace_t *trace, const vec3_t boxstartmins, const vec3_t boxstartmaxs, const vec3_t boxendmins, const vec3_t boxendmaxs, int hitsupercontentsmask)
{
// this function currently only supports same size start and end
double boxsize[3];
memset(&rhc, 0, sizeof(rhc));
memset(trace, 0, sizeof(trace_t));
rhc.trace = trace;
+ rhc.trace->hitsupercontentsmask = hitsupercontentsmask;
rhc.trace->fraction = 1;
rhc.trace->allsolid = true;
VectorSubtract(boxstartmaxs, boxstartmins, boxsize);
}
}
-#define MAX_POINTS_ON_WINDING 64
-
-typedef struct
-{
- int numpoints;
- int padding;
- double points[8][3]; // variable sized
-}
-winding_t;
-
-/*
-==================
-NewWinding
-==================
-*/
-static winding_t *NewWinding(int points)
-{
- winding_t *w;
- int size;
-
- if (points > MAX_POINTS_ON_WINDING)
- Sys_Error("NewWinding: too many points\n");
-
- size = sizeof(winding_t) + sizeof(double[3]) * (points - 8);
- w = Mem_Alloc(loadmodel->mempool, size);
- memset(w, 0, size);
-
- return w;
-}
-
-static void FreeWinding(winding_t *w)
-{
- Mem_Free(w);
-}
-
-/*
-=================
-BaseWindingForPlane
-=================
-*/
-static winding_t *BaseWindingForPlane(mplane_t *p)
-{
- double org[3], vright[3], vup[3], normal[3];
- winding_t *w;
-
- VectorCopy(p->normal, normal);
- VectorVectorsDouble(normal, vright, vup);
-
- VectorScale(vup, 1024.0*1024.0*1024.0, vup);
- VectorScale(vright, 1024.0*1024.0*1024.0, vright);
-
- // project a really big axis aligned box onto the plane
- w = NewWinding(4);
-
- VectorScale(p->normal, p->dist, org);
-
- VectorSubtract(org, vright, w->points[0]);
- VectorAdd(w->points[0], vup, w->points[0]);
-
- VectorAdd(org, vright, w->points[1]);
- VectorAdd(w->points[1], vup, w->points[1]);
-
- VectorAdd(org, vright, w->points[2]);
- VectorSubtract(w->points[2], vup, w->points[2]);
-
- VectorSubtract(org, vright, w->points[3]);
- VectorSubtract(w->points[3], vup, w->points[3]);
-
- w->numpoints = 4;
-
- return w;
-}
-
-/*
-==================
-ClipWinding
-
-Clips the winding to the plane, returning the new winding on the positive side
-Frees the input winding.
-If keepon is true, an exactly on-plane winding will be saved, otherwise
-it will be clipped away.
-==================
-*/
-static winding_t *ClipWinding(winding_t *in, mplane_t *split, int keepon)
-{
- double dists[MAX_POINTS_ON_WINDING + 1];
- int sides[MAX_POINTS_ON_WINDING + 1];
- int counts[3];
- double dot;
- int i, j;
- double *p1, *p2;
- double mid[3];
- winding_t *neww;
- int maxpts;
-
- counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
-
- // determine sides for each point
- for (i = 0;i < in->numpoints;i++)
- {
- dists[i] = dot = DotProduct(in->points[i], split->normal) - split->dist;
- if (dot > ON_EPSILON)
- sides[i] = SIDE_FRONT;
- else if (dot < -ON_EPSILON)
- sides[i] = SIDE_BACK;
- else
- sides[i] = SIDE_ON;
- counts[sides[i]]++;
- }
- sides[i] = sides[0];
- dists[i] = dists[0];
-
- if (keepon && !counts[0] && !counts[1])
- return in;
-
- if (!counts[0])
- {
- FreeWinding(in);
- return NULL;
- }
- if (!counts[1])
- return in;
-
- maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
- if (maxpts > MAX_POINTS_ON_WINDING)
- Sys_Error("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
-
- neww = NewWinding(maxpts);
-
- for (i = 0;i < in->numpoints;i++)
- {
- if (neww->numpoints >= maxpts)
- Sys_Error("ClipWinding: points exceeded estimate");
-
- p1 = in->points[i];
-
- if (sides[i] == SIDE_ON)
- {
- VectorCopy(p1, neww->points[neww->numpoints]);
- neww->numpoints++;
- continue;
- }
-
- if (sides[i] == SIDE_FRONT)
- {
- VectorCopy(p1, neww->points[neww->numpoints]);
- neww->numpoints++;
- }
-
- if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
- continue;
-
- // generate a split point
- p2 = in->points[(i+1)%in->numpoints];
-
- dot = dists[i] / (dists[i]-dists[i+1]);
- for (j = 0;j < 3;j++)
- { // avoid round off error when possible
- if (split->normal[j] == 1)
- mid[j] = split->dist;
- else if (split->normal[j] == -1)
- mid[j] = -split->dist;
- else
- mid[j] = p1[j] + dot* (p2[j]-p1[j]);
- }
-
- VectorCopy(mid, neww->points[neww->numpoints]);
- neww->numpoints++;
- }
-
- // free the original winding
- FreeWinding(in);
-
- return neww;
-}
-
-
-/*
-==================
-DivideWinding
-
-Divides a winding by a plane, producing one or two windings. The
-original winding is not damaged or freed. If only on one side, the
-returned winding will be the input winding. If on both sides, two
-new windings will be created.
-==================
-*/
-static void DivideWinding(winding_t *in, mplane_t *split, winding_t **front, winding_t **back)
-{
- double dists[MAX_POINTS_ON_WINDING + 1];
- int sides[MAX_POINTS_ON_WINDING + 1];
- int counts[3];
- double dot;
- int i, j;
- double *p1, *p2;
- double mid[3];
- winding_t *f, *b;
- int maxpts;
-
- counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
-
- // determine sides for each point
- for (i = 0;i < in->numpoints;i++)
- {
- dot = DotProduct(in->points[i], split->normal);
- dot -= split->dist;
- dists[i] = dot;
- if (dot > ON_EPSILON) sides[i] = SIDE_FRONT;
- else if (dot < -ON_EPSILON) sides[i] = SIDE_BACK;
- else sides[i] = SIDE_ON;
- counts[sides[i]]++;
- }
- sides[i] = sides[0];
- dists[i] = dists[0];
-
- *front = *back = NULL;
-
- if (!counts[0])
- {
- *back = in;
- return;
- }
- if (!counts[1])
- {
- *front = in;
- return;
- }
-
- maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
-
- if (maxpts > MAX_POINTS_ON_WINDING)
- Sys_Error("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
-
- *front = f = NewWinding(maxpts);
- *back = b = NewWinding(maxpts);
-
- for (i = 0;i < in->numpoints;i++)
- {
- if (f->numpoints >= maxpts || b->numpoints >= maxpts)
- Sys_Error("DivideWinding: points exceeded estimate");
-
- p1 = in->points[i];
-
- if (sides[i] == SIDE_ON)
- {
- VectorCopy(p1, f->points[f->numpoints]);
- f->numpoints++;
- VectorCopy(p1, b->points[b->numpoints]);
- b->numpoints++;
- continue;
- }
-
- if (sides[i] == SIDE_FRONT)
- {
- VectorCopy(p1, f->points[f->numpoints]);
- f->numpoints++;
- }
- else if (sides[i] == SIDE_BACK)
- {
- VectorCopy(p1, b->points[b->numpoints]);
- b->numpoints++;
- }
-
- if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
- continue;
-
- // generate a split point
- p2 = in->points[(i+1)%in->numpoints];
-
- dot = dists[i] / (dists[i]-dists[i+1]);
- for (j = 0;j < 3;j++)
- { // avoid round off error when possible
- if (split->normal[j] == 1)
- mid[j] = split->dist;
- else if (split->normal[j] == -1)
- mid[j] = -split->dist;
- else
- mid[j] = p1[j] + dot* (p2[j]-p1[j]);
- }
-
- VectorCopy(mid, f->points[f->numpoints]);
- f->numpoints++;
- VectorCopy(mid, b->points[b->numpoints]);
- b->numpoints++;
- }
-}
-
typedef struct portal_s
{
mplane_t plane;
// advance to next portal
portal++;
}
- FreeWinding(p->winding);
+ Winding_Free(p->winding);
}
FreePortal(p);
p = pnext;
nodeportal = AllocPortal();
nodeportal->plane = *node->plane;
- nodeportalwinding = BaseWindingForPlane(node->plane);
+ nodeportalwinding = Winding_NewFromPlane(node->plane->normal[0], node->plane->normal[1], node->plane->normal[2], node->plane->dist);
side = 0; // shut up compiler warning
for (portal = (portal_t *)node->portals;portal;portal = portal->next[side])
{
else
Host_Error("Mod_Q1BSP_RecursiveNodePortals: mislinked portal");
- nodeportalwinding = ClipWinding(nodeportalwinding, &clipplane, true);
+ nodeportalwinding = Winding_Clip(nodeportalwinding, clipplane.normal[0], clipplane.normal[1], clipplane.normal[2], clipplane.dist, true);
if (!nodeportalwinding)
{
Con_Printf("Mod_Q1BSP_RecursiveNodePortals: WARNING: new portal was clipped away\n");
RemovePortalFromNodes(portal);
// cut the portal into two portals, one on each side of the node plane
- DivideWinding(portal->winding, plane, &frontwinding, &backwinding);
+ Winding_Divide(portal->winding, plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, &frontwinding, &backwinding);
if (!frontwinding)
{
*splitportal = *portal;
splitportal->chain = temp;
splitportal->winding = backwinding;
- FreeWinding(portal->winding);
+ Winding_Free(portal->winding);
portal->winding = frontwinding;
if (side == 0)
Mod_Q1BSP_RecursiveNodePortals(back);
}
-
static void Mod_Q1BSP_MakePortals(void)
{
portalchain = NULL;
}
}
-void Mod_Q1BSP_FatPVS_RecursiveBSPNode(model_t *model, const vec3_t org, vec_t radius, qbyte *pvsbuffer, int pvsbytes, mnode_t *node)
+static void Mod_Q1BSP_FatPVS_RecursiveBSPNode(model_t *model, const vec3_t org, vec_t radius, qbyte *pvsbuffer, int pvsbytes, mnode_t *node)
{
int i;
mplane_t *plane;
//Calculates a PVS that is the inclusive or of all leafs within radius pixels
//of the given point.
-int Mod_Q1BSP_FatPVS(model_t *model, const vec3_t org, vec_t radius, qbyte *pvsbuffer, int pvsbufferlength)
+static int Mod_Q1BSP_FatPVS(model_t *model, const vec3_t org, vec_t radius, qbyte *pvsbuffer, int pvsbufferlength)
{
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);
+ Mod_Q1BSP_FatPVS_RecursiveBSPNode(model, org, radius, pvsbuffer, bytes, model->brushq1.nodes);
return bytes;
}
Host_Error("Mod_Q1BSP_Load: %s has wrong version number(%i should be %i(Quake) or 30(HalfLife))", mod->name, i, BSPVERSION);
mod->brush.ishlbsp = i == 30;
+ mod->brush.SuperContentsFromNativeContents = Mod_Q1BSP_SuperContentsFromNativeContents;
+ mod->brush.NativeContentsFromSuperContents = Mod_Q1BSP_NativeContentsFromSuperContents;
mod->brush.AmbientSoundLevelsForPoint = Mod_Q1BSP_AmbientSoundLevelsForPoint;
mod->brush.FatPVS = Mod_Q1BSP_FatPVS;
mod->brush.BoxTouchingPVS = Mod_Q1BSP_BoxTouchingPVS;
*/
}
-void Mod_Q2BSP_Load(model_t *mod, void *buffer)
+void static Mod_Q2BSP_Load(model_t *mod, void *buffer)
{
int i;
q2dheader_t *header;
Mod_Q2BSP_LoadModels(&header->lumps[Q2LUMP_MODELS]);
}
+static int Mod_Q3BSP_SuperContentsFromNativeContents(model_t *model, int nativecontents);
+static int Mod_Q3BSP_NativeContentsFromSuperContents(model_t *model, int supercontents);
static void Mod_Q3BSP_LoadEntities(lump_t *l)
{
{
strncpy(out->name, in->name, sizeof(out->name) - 1);
out->surfaceflags = LittleLong(in->surfaceflags);
- out->contents = LittleLong(in->contents);
+ out->nativecontents = LittleLong(in->contents);
+ out->supercontents = Mod_Q3BSP_SuperContentsFromNativeContents(loadmodel, out->nativecontents);
+ out->renderflags = 0;
+ if (!strcmp(out->name, "caulk") || !strcmp(out->name, "common/caulk") || !strcmp(out->name, "textures/common/caulk"))
+ out->renderflags |= Q3MTEXTURERENDERFLAGS_NODRAW;
out->number = i;
Mod_LoadSkinFrame(&out->skin, out->name, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, false, true, true);
{
q3dbrush_t *in;
q3mbrush_t *out;
- int i, j, k, m, n, c, count, numpoints, numplanes;
- winding_t *w;
- mplane_t plane;
- colpointf_t pointsbuf[256*3];
- colplanef_t planesbuf[256], colplanef;
+ int i, j, n, c, count, numplanes, maxplanes;
+ mplane_t *planes;
in = (void *)(mod_base + l->fileofs);
if (l->filelen % sizeof(*in))
loadmodel->brushq3.data_brushes = out;
loadmodel->brushq3.num_brushes = count;
+ maxplanes = 0;
+ planes = NULL;
+
for (i = 0;i < count;i++, in++, out++)
{
n = LittleLong(in->firstbrushside);
Host_Error("Mod_Q3BSP_LoadBrushes: invalid textureindex %i (%i textures)\n", n, loadmodel->brushq3.num_textures);
out->texture = loadmodel->brushq3.data_textures + n;
- // construct a collision brush, which needs points and planes...
- // each point and plane should be unique, and they don't refer to
- // eachother in any way, so keeping them unique is fairly easy
- numpoints = 0;
- numplanes = 0;
- for (j = 0;j < out->numbrushsides;j++)
+ // make a list of mplane_t structs to construct a colbrush from
+ if (maxplanes < numplanes)
{
- // for some reason the planes are all flipped compared to what I
- // would expect, so this has to negate them...
-
- // create a huge polygon for the plane
- VectorNegate(out->firstbrushside[j].plane->normal, plane.normal);
- plane.dist = -out->firstbrushside[j].plane->dist;
- w = BaseWindingForPlane(&plane);
- // clip it by all other planes
- for (k = 0;k < out->numbrushsides && w;k++)
- {
- if (k != j)
- {
- VectorNegate(out->firstbrushside[k].plane->normal, plane.normal);
- plane.dist = -out->firstbrushside[k].plane->dist;
- w = ClipWinding(w, &plane, true);
- }
- }
- // if nothing is left, skip it
- // FIXME: should keep count of how many were skipped and report
- // it, just for sake of statistics
- if (!w)
- continue;
- // add the points uniquely (no duplicates)
- for (k = 0;k < w->numpoints;k++)
- {
- for (m = 0;m < numpoints;m++)
- if (VectorDistance2(w->points[k], pointsbuf[m].v) < DIST_EPSILON)
- break;
- if (m == numpoints)
- {
- // check if there are too many and skip the brush
- if (numpoints >= 256)
- {
- Con_Printf("Mod_Q3BSP_LoadBrushes: failed to build collision brush: too many points for buffer\n");
- FreeWinding(w);
- goto failedtomakecolbrush;
- }
- // add the new one
- VectorCopy(w->points[k], pointsbuf[numpoints].v);
- numpoints++;
- }
- }
- // add the plane uniquely (no duplicates)
- memset(&colplanef, 0, sizeof(colplanef));
- VectorCopy(out->firstbrushside[k].plane->normal, colplanef.normal);
- colplanef.dist = out->firstbrushside[k].plane->dist;
- for (k = 0;k < numplanes;k++)
- if (VectorCompare(planesbuf[k].normal, colplanef.normal) && planesbuf[k].dist == colplanef.dist)
- break;
- if (k == numplanes)
- {
- // check if there are too many and skip the brush
- if (numplanes >= 256)
- {
- Con_Printf("Mod_Q3BSP_LoadBrushes: failed to build collision brush: too many planes for buffer\n");
- FreeWinding(w);
- goto failedtomakecolbrush;
- }
- // add the new one
- planesbuf[numplanes++] = colplanef;
- }
- FreeWinding(w);
+ maxplanes = numplanes;
+ if (planes)
+ Mem_Free(planes);
+ planes = Mem_Alloc(tempmempool, sizeof(mplane_t) * maxplanes);
}
- // if anything is left, create the collision brush
- if (numplanes && numpoints)
+ for (j = 0;j < out->numbrushsides;j++)
{
- out->colbrushf = Collision_AllocBrushFloat(loadmodel->mempool, numpoints, numplanes);
- memcpy(out->colbrushf->points, pointsbuf, numpoints * sizeof(colpointf_t));
- memcpy(out->colbrushf->planes, planesbuf, numplanes * sizeof(colplanef_t));
+ VectorCopy(out->firstbrushside[j].plane->normal, planes[j].normal);
+ planes[j].dist = out->firstbrushside[j].plane->dist;
}
- // return from errors to here
- failedtomakecolbrush:;
+ // make the colbrush from the planes
+ out->colbrushf = Collision_NewBrushFromPlanes(loadmodel->mempool, out->numbrushsides, planes, out->texture->supercontents);
}
+ if (planes)
+ Mem_Free(planes);
}
static void Mod_Q3BSP_LoadEffects(lump_t *l)
invalidelements++;
if (invalidelements)
{
- Con_Printf("Mod_Q3BSP_LoadFaces: Warning: face #%i has %i invalid elements, type = %i, texture->name = \"%s\", texture->surfaceflags = %i, texture->contents = %i, firstvertex = %i, numvertices = %i, firstelement = %i, numelements = %i, elements list:\n", i, invalidelements, out->type, out->texture->name, out->texture->surfaceflags, out->texture->contents, out->firstvertex, out->numvertices, out->firstelement, out->numelements);
+ Con_Printf("Mod_Q3BSP_LoadFaces: Warning: face #%i has %i invalid elements, type = %i, texture->name = \"%s\", texture->surfaceflags = %i, texture->nativecontents = %i, firstvertex = %i, numvertices = %i, firstelement = %i, numelements = %i, elements list:\n", i, invalidelements, out->type, out->texture->name, out->texture->surfaceflags, out->texture->nativecontents, out->firstvertex, out->numvertices, out->firstelement, out->numelements);
for (j = 0;j < out->numelements;j++)
{
Con_Printf(" %i", out->data_element3i[j]);
memcpy(loadmodel->brushq3.data_pvschains, (qbyte *)(in + 1), totalchains);
}
-void Mod_Q3BSP_FindNonSolidLocation(model_t *model, const vec3_t in, vec3_t out, vec_t radius)
+static void Mod_Q3BSP_FindNonSolidLocation(model_t *model, const vec3_t in, vec3_t out, vec_t radius)
{
// FIXME: finish this code
VectorCopy(in, out);
}
-void Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace_t *trace, q3mnode_t *node, const colbrushf_t *thisbrush_start, const colbrushf_t *thisbrush_end)
+static void Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace_t *trace, q3mnode_t *node, const colbrushf_t *thisbrush_start, const colbrushf_t *thisbrush_end)
{
if (node->isnode)
{
dist = node->plane->dist - (1.0f / 8.0f);
for (i = 0, ps = thisbrush_start->points, pe = thisbrush_end->points;i < thisbrush_start->numpoints;i++, ps++, pe++)
{
- if (DotProduct(ps->v, node->plane->normal) > dist || DotProduct(pe->v, node->plane->normal) > dist)
+ if (DotProduct(ps->v, node->plane->normal) >= dist || DotProduct(pe->v, node->plane->normal) >= dist)
{
Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end);
break;
dist = node->plane->dist + (1.0f / 8.0f);
for (i = 0, ps = thisbrush_start->points, pe = thisbrush_end->points;i < thisbrush_start->numpoints;i++, ps++, pe++)
{
- if (DotProduct(ps->v, node->plane->normal) < dist || DotProduct(pe->v, node->plane->normal) < dist)
+ if (DotProduct(ps->v, node->plane->normal) <= dist || DotProduct(pe->v, node->plane->normal) <= dist)
{
Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[1], thisbrush_start, thisbrush_end);
break;
}
}
-void Mod_Q3BSP_LightPoint(model_t *model, const vec3_t p, vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal)
+static void Mod_Q3BSP_LightPoint(model_t *model, const vec3_t p, vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal)
{
// FIXME: write this
ambientcolor[0] += 255;
ambientcolor[2] += 255;
}
-void Mod_Q3BSP_TraceBox(model_t *model, trace_t *trace, const vec3_t boxstartmins, const vec3_t boxstartmaxs, const vec3_t boxendmins, const vec3_t boxendmaxs)
+static void Mod_Q3BSP_TraceBox(model_t *model, trace_t *trace, const vec3_t boxstartmins, const vec3_t boxstartmaxs, const vec3_t boxendmins, const vec3_t boxendmaxs, int hitsupercontentsmask)
{
int i;
colbrushf_t *thisbrush_start, *thisbrush_end;
thisbrush_end = Collision_BrushForBox(&endmatrix, boxendmins, boxendmaxs);
memset(trace, 0, sizeof(*trace));
trace->fraction = 1;
+ trace->hitsupercontentsmask = hitsupercontentsmask;
if (model->brushq3.num_nodes)
Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, model->brushq3.data_nodes, thisbrush_start, thisbrush_end);
else
return false;
}
-int Mod_Q3BSP_BoxTouchingPVS(model_t *model, const qbyte *pvs, const vec3_t mins, const vec3_t maxs)
+static int Mod_Q3BSP_BoxTouchingPVS(model_t *model, const qbyte *pvs, const vec3_t mins, const vec3_t maxs)
{
return Mod_Q3BSP_BoxTouchingPVS_RecursiveBSPNode(model, model->brushq3.data_nodes, pvs, mins, maxs);
}
-int Mod_Q3BSP_FatPVS(model_t *model, const vec3_t org, vec_t radius, qbyte *pvsbuffer, int pvsbufferlength)
+static int Mod_Q3BSP_FatPVS(model_t *model, const vec3_t org, vec_t radius, qbyte *pvsbuffer, int pvsbufferlength)
{
// FIXME: write this
memset(pvsbuffer, 0xFF, pvsbufferlength);
return pvsbufferlength;
}
+static int Mod_Q3BSP_SuperContentsFromNativeContents(model_t *model, int nativecontents)
+{
+ int supercontents = 0;
+ if (nativecontents & Q2CONTENTS_SOLID)
+ supercontents |= SUPERCONTENTS_SOLID;
+ if (nativecontents & Q2CONTENTS_WATER)
+ supercontents |= SUPERCONTENTS_WATER;
+ if (nativecontents & Q2CONTENTS_SLIME)
+ supercontents |= SUPERCONTENTS_SLIME;
+ if (nativecontents & Q2CONTENTS_LAVA)
+ supercontents |= SUPERCONTENTS_LAVA;
+ return supercontents;
+}
+
+static int Mod_Q3BSP_NativeContentsFromSuperContents(model_t *model, int supercontents)
+{
+ int nativecontents = 0;
+ if (supercontents & SUPERCONTENTS_SOLID)
+ nativecontents |= Q2CONTENTS_SOLID;
+ if (supercontents & SUPERCONTENTS_WATER)
+ nativecontents |= Q2CONTENTS_WATER;
+ if (supercontents & SUPERCONTENTS_SLIME)
+ nativecontents |= Q2CONTENTS_SLIME;
+ if (supercontents & SUPERCONTENTS_LAVA)
+ nativecontents |= Q2CONTENTS_LAVA;
+ return nativecontents;
+}
+
//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);
{
int i;
q3dheader_t *header;
+ float corner[3], yawradius, modelradius;
mod->type = mod_brushq3;
R_ResetQuakeSky();
}
+ mod->brush.SuperContentsFromNativeContents = Mod_Q3BSP_SuperContentsFromNativeContents;
+ mod->brush.NativeContentsFromSuperContents = Mod_Q3BSP_NativeContentsFromSuperContents;
mod->brush.FatPVS = Mod_Q3BSP_FatPVS;
mod->brush.BoxTouchingPVS = Mod_Q3BSP_BoxTouchingPVS;
mod->brush.LightPoint = Mod_Q3BSP_LightPoint;
mod->mempool = NULL;
}
mod->brushq3.data_thismodel = loadmodel->brushq3.data_models + i;
+
+ VectorCopy(mod->brushq3.data_thismodel->mins, mod->normalmins);
+ VectorCopy(mod->brushq3.data_thismodel->maxs, mod->normalmaxs);
+ corner[0] = max(fabs(mod->normalmins[0]), fabs(mod->normalmaxs[0]));
+ corner[1] = max(fabs(mod->normalmins[1]), fabs(mod->normalmaxs[1]));
+ corner[2] = max(fabs(mod->normalmins[2]), fabs(mod->normalmaxs[2]));
+ modelradius = sqrt(corner[0]*corner[0]+corner[1]*corner[1]+corner[2]*corner[2]);
+ yawradius = sqrt(corner[0]*corner[0]+corner[1]*corner[1]);
+ mod->rotatedmins[0] = mod->rotatedmins[1] = mod->rotatedmins[2] = -modelradius;
+ mod->rotatedmaxs[0] = mod->rotatedmaxs[1] = mod->rotatedmaxs[2] = modelradius;
+ mod->yawmaxs[0] = mod->yawmaxs[1] = yawradius;
+ mod->yawmins[0] = mod->yawmins[1] = -yawradius;
+ mod->yawmins[2] = mod->normalmins[2];
+ mod->yawmaxs[2] = mod->normalmaxs[2];
+ mod->radius = modelradius;
+ mod->radius2 = modelradius * modelradius;
}
}
// submodels to load)
int numsubmodels;
// common functions
+ int (*SuperContentsFromNativeContents)(struct model_s *model, int nativecontents);
+ int (*NativeContentsFromSuperContents)(struct model_s *model, int supercontents);
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);
+ 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, int hitsupercontentsmask);
// 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_brushq2_t;
*/
+#define Q3MTEXTURERENDERFLAGS_NODRAW 1
+
typedef struct q3mtexture_s
{
char name[Q3PATHLENGTH];
int surfaceflags;
- int contents;
+ int nativecontents;
+ int supercontents;
+ int renderflags;
int number;
skinframe_t skin;
int Mod_LoadSkinFrame(skinframe_t *skinframe, char *basename, int textureflags, int loadpantsandshirt, int usedetailtexture, int loadglowtexture);
int Mod_LoadSkinFrame_Internal(skinframe_t *skinframe, char *basename, int textureflags, int loadpantsandshirt, int usedetailtexture, int loadglowtexture, qbyte *skindata, int width, int height);
+// used for talking to the QuakeC mainly
+int Mod_Q1BSP_NativeContentsFromSuperContents(struct model_s *model, int supercontents);
+int Mod_Q1BSP_SuperContentsFromNativeContents(struct model_s *model, int nativecontents);
+
extern cvar_t r_mipskins;
typedef struct skinfileitem_s
*/
void PF_pointcontents (void)
{
- G_FLOAT(OFS_RETURN) = SV_PointContents(G_VECTOR(OFS_PARM0));
+ G_FLOAT(OFS_RETURN) = SV_PointQ1Contents(G_VECTOR(OFS_PARM0));
}
/*
AngleVectors(cl.viewangles, v2, NULL, NULL);
//VectorCopy(r_origin, v1);
VectorMA(v1, 8192, v2, v2);
- spritescale = CL_TraceLine(v1, v2, spriteorigin, NULL, 0, true, NULL) * (8192.0f / 40.0f) * crosshair_size.value;
+ spritescale = CL_TraceLine(v1, v2, spriteorigin, NULL, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY) * (8192.0f / 40.0f) * crosshair_size.value;
// draw the sprite
R_DrawSprite(GL_SRC_ALPHA, GL_ONE, pic->tex, true, spriteorigin, vright, vup, spritescale, -spritescale, -spritescale, spritescale, color[0], color[1], color[2], color[3]);
VectorMA(e->vert[i], frametime, e->vertvel[i], end);
if (r_explosionclip.integer)
{
- if (CL_TraceLine(e->vert[i], end, impact, normal, 0, true, NULL) < 1)
+ if (CL_TraceLine(e->vert[i], end, impact, normal, true, NULL, SUPERCONTENTS_SOLID) < 1)
{
// clip velocity against the wall
dot = DotProduct(e->vertvel[i], normal) * -1.125f;
{
rd = r_dlight + i;
dist = (DotProduct(rd->origin, vpn) - viewdist);
- if (dist >= 24.0f && CL_TraceLine(rd->origin, r_origin, NULL, NULL, 0, true, NULL) == 1)
+ if (dist >= 24.0f && CL_TraceLine(rd->origin, r_origin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1)
{
cscale = (1.0f / 131072.0f);
scale = rd->cullradius * 0.25f;
{
VectorSubtract (p, sl->origin, v);
f = ((1.0f / (DotProduct(v, v) * sl->falloff + sl->distbias)) - sl->subtract);
- if (f > 0 && CL_TraceLine(p, sl->origin, NULL, NULL, 0, false, NULL) == 1)
+ if (f > 0 && CL_TraceLine(p, sl->origin, NULL, NULL, false, NULL, SUPERCONTENTS_SOLID) == 1)
{
f *= d_lightstylevalue[sl->style] * (1.0f / 65536.0f);
VectorMA(ambientcolor, f, sl->light, ambientcolor);
rd = r_dlight + i;
VectorSubtract(p, rd->origin, v);
f = DotProduct(v, v);
- if (f < rd->cullradius2 && CL_TraceLine(p, rd->origin, NULL, NULL, 0, false, NULL) == 1)
+ if (f < rd->cullradius2 && CL_TraceLine(p, rd->origin, NULL, NULL, false, NULL, SUPERCONTENTS_SOLID) == 1)
{
f = (1.0f / (f + LIGHTOFFSET)) - rd->subtract;
VectorMA(ambientcolor, f, rd->light, ambientcolor);
VectorSubtract (v, rd->origin, v);
if (DotProduct(v, v) < rd->cullradius2)
{
- if (CL_TraceLine(ent->origin, rd->origin, NULL, NULL, 0, false, NULL) != 1)
+ if (CL_TraceLine(ent->origin, rd->origin, NULL, NULL, false, NULL, SUPERCONTENTS_SOLID) != 1)
continue;
VectorSubtract (ent->origin, rd->origin, v);
f = ((1.0f / (DotProduct(v, v) + LIGHTOFFSET)) - rd->subtract);
ent->numentlights = 0;
if (cl.worldmodel)
for (i = 0, sl = cl.worldmodel->brushq1.lights;i < cl.worldmodel->brushq1.numlights && ent->numentlights < MAXENTLIGHTS;i++, sl++)
- if (CL_TraceLine(ent->origin, sl->origin, NULL, NULL, 0, false, NULL) == 1)
+ if (CL_TraceLine(ent->origin, sl->origin, NULL, NULL, false, NULL, SUPERCONTENTS_SOLID) == 1)
ent->entlights[ent->numentlights++] = i;
}
ent->entlightsframe = r_framecount;
castshadowcount++;
VectorCopy(e->origin, e->mins);
VectorCopy(e->origin, e->maxs);
- i = CL_PointContents(e->origin);
+ i = CL_PointQ1Contents(e->origin);
if (r_shadow_portallight.integer && i != CONTENTS_SOLID && i != CONTENTS_SKY)
{
qbyte *byteleafpvs;
if (rating >= 0.95)
{
rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
- if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.vieworg, NULL, NULL, 0, true, NULL) == 1.0f)
+ if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.vieworg, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1.0f)
{
bestrating = rating;
best = light;
vec_t dist, push, frac;
vec3_t dest, endpos, normal;
VectorMA(r_refdef.vieworg, r_editlights_cursordistance.value, vpn, dest);
- frac = CL_TraceLine(r_refdef.vieworg, dest, endpos, normal, 0, true, NULL);
+ frac = CL_TraceLine(r_refdef.vieworg, dest, endpos, normal, true, NULL, SUPERCONTENTS_SOLID);
if (frac < 1)
{
dist = frac * r_editlights_cursordistance.value;
extern qboolean envmap;
-extern cvar_t r_drawentities;
-extern cvar_t r_drawviewmodel;
-extern cvar_t r_speeds;
-extern cvar_t r_fullbright;
-extern cvar_t r_wateralpha;
-extern cvar_t r_dynamic;
-extern cvar_t r_dlightmap;
+extern cvar_t r_drawentities;
+extern cvar_t r_drawviewmodel;
+extern cvar_t r_speeds;
+extern cvar_t r_fullbright;
+extern cvar_t r_wateralpha;
+extern cvar_t r_dynamic;
+extern cvar_t r_dlightmap;
+extern cvar_t r_drawcollisionbrushes;
void R_Init (void);
void R_RenderView (void); // must set r_refdef first
{
start[0] = x ? maxs[0] : mins[0];
start[1] = y ? maxs[1] : mins[1];
- if (SV_PointContents(start) != CONTENTS_SOLID)
+ if (!(SV_PointSuperContents(start) & SUPERCONTENTS_SOLID))
goto realcheck;
}
if (trace.fraction == 1)
{
VectorCopy(trace.endpos, traceendpos);
- if (((int)ent->v->flags & FL_SWIM) && SV_PointContents(traceendpos) == CONTENTS_EMPTY )
+ if (((int)ent->v->flags & FL_SWIM) && !(SV_PointSuperContents(traceendpos) & SUPERCONTENTS_LIQUIDSMASK))
return false; // swim monster left water
VectorCopy (traceendpos, ent->v->origin);
ent->v->waterlevel = 0;
ent->v->watertype = CONTENTS_EMPTY;
- cont = SV_PointContents(point);
+ cont = SV_PointQ1Contents(point);
if (cont <= CONTENTS_WATER)
{
ent->v->watertype = cont;
ent->v->waterlevel = 1;
point[2] = ent->v->origin[2] + (ent->v->mins[2] + ent->v->maxs[2])*0.5;
- cont = SV_PointContents(point);
+ cont = SV_PointQ1Contents(point);
if (cont <= CONTENTS_WATER)
{
ent->v->waterlevel = 2;
point[2] = ent->v->origin[2] + ent->v->view_ofs[2];
- cont = SV_PointContents(point);
+ cont = SV_PointQ1Contents(point);
if (cont <= CONTENTS_WATER)
ent->v->waterlevel = 3;
}
void SV_CheckWaterTransition (edict_t *ent)
{
int cont;
- cont = SV_PointContents(ent->v->origin);
+ cont = SV_PointQ1Contents(ent->v->origin);
if (!ent->v->watertype)
{
// just spawned here
SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
ent->v->watertype = CONTENTS_EMPTY;
- ent->v->waterlevel = cont;
+ ent->v->waterlevel = 0;
}
}
sv_player->v->idealpitch = -dir * sv_idealpitchscale.value;
}
-#if 0
-static vec3_t wishdir;
+#if 1
+static vec3_t wishdir, forward, right, up;
static float wishspeed;
static qboolean onground;
- 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
-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 darkplaces: dedicated server should error out if it has no sockets (yummyluv)
+0 darkplaces: heartbeat should print an error message if used with no server running (yummyluv)
+0 darkplaces: server is starting before the "port" cvar is set by commandline and scripts? (yummyluv)
+0 darkplaces: investigate why server is not automatically sending heartbeats (yummyluv)
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
if (cls.state == ca_connected && cls.signon == SIGNONS)
{
// set contents color
- switch (CL_PointContents(r_refdef.vieworg))
+ switch (CL_PointQ1Contents(r_refdef.vieworg))
{
case CONTENTS_EMPTY:
case CONTENTS_SOLID:
VectorAdd(endtransformed, mins, endtransformedmins);
if (model && model->brush.TraceBox)
- model->brush.TraceBox(model, &trace, starttransformedmins, starttransformedmaxs, endtransformedmins, endtransformedmaxs);
+ model->brush.TraceBox(model, &trace, starttransformedmins, starttransformedmaxs, endtransformedmins, endtransformedmaxs, SUPERCONTENTS_SOLID);
else
- Collision_ClipTrace_Box(&trace, ent->v->mins, ent->v->maxs, starttransformed, mins, maxs, endtransformed);
+ Collision_ClipTrace_Box(&trace, ent->v->mins, ent->v->maxs, starttransformed, mins, maxs, endtransformed, SUPERCONTENTS_SOLID, SUPERCONTENTS_SOLID);
if (trace.fraction < 1 || trace.startsolid)
trace.ent = ent;
clip->trace.fraction = trace.fraction;
VectorCopy(trace.endpos, clip->trace.endpos);
clip->trace.plane = trace.plane;
- //clip->trace.endcontents = trace.endcontents;
clip->trace.ent = touch;
}
- // FIXME: the handling of endcontents is really broken but works well enough for point checks
- if (trace.endcontents < clip->trace.endcontents || trace.endcontents == CONTENTS_SOLID)
- {
- // lower numbered (lava is lower than water, for example)
- // contents override higher numbered contents, except for
- // CONTENTS_SOLID which overrides everything
- clip->trace.endcontents = trace.endcontents;
- }
+ clip->trace.startsupercontents |= trace.startsupercontents;
if (clip->trace.allsolid)
return;
}
return clip.trace;
}
-int SV_PointContents(const vec3_t point)
+int SV_PointQ1Contents(const vec3_t point)
+{
+#if 1
+ return Mod_Q1BSP_NativeContentsFromSuperContents(NULL, SV_Move(point, vec3_origin, vec3_origin, point, MOVE_NOMONSTERS, NULL).startsupercontents);
+#else
+ if (sv.worldmodel && sv.worldmodel->brush.PointContents)
+ return sv.worldmodel->brush.PointContents(sv.worldmodel, point);
+ return CONTENTS_SOLID;
+#endif
+}
+
+int SV_PointSuperContents(const vec3_t point)
{
#if 1
- return SV_Move(point, vec3_origin, vec3_origin, point, MOVE_NOMONSTERS, NULL).endcontents;
+ return SV_Move(point, vec3_origin, vec3_origin, point, MOVE_NOMONSTERS, NULL).startsupercontents;
#else
if (sv.worldmodel && sv.worldmodel->brush.PointContents)
return sv.worldmodel->brush.PointContents(sv.worldmodel, point);
// passedict is explicitly excluded from clipping checks (normally NULL)
trace_t SV_Move(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, edict_t *passedict);
-int SV_PointContents(const vec3_t point);
+int SV_PointQ1Contents(const vec3_t point);
+int SV_PointSuperContents(const vec3_t point);
#endif