more q3bsp work (and no it still doesn't work right)
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Tue, 19 Aug 2003 00:25:08 +0000 (00:25 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Tue, 19 Aug 2003 00:25:08 +0000 (00:25 +0000)
converted over most of the engine to use new SUPERCONTENTS_ values (bit flags), and the q1bsp and q3bsp loaders convert to these, conversion to q1 contents and back is supported as well
other stuff...  I've forgotten what

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@3398 d7cf8633-e32d-0410-b094-e92efae38249

32 files changed:
bspfile.h
cgamevm.c
chase.c
cl_collision.c
cl_collision.h
cl_main.c
cl_particles.c
cl_screen.c
collision.c
collision.h
darkplaces.dsp
gl_models.c
gl_rmain.c
gl_rsurf.c
host.c
makefile
mathlib.c
model_brush.c
model_shared.h
pr_cmds.c
r_crosshairs.c
r_explosion.c
r_light.c
r_shadow.c
render.h
sv_move.c
sv_phys.c
sv_user.c
todo
view.c
world.c
world.h

index 35945c2..48c8321 100644 (file)
--- a/bspfile.h
+++ b/bspfile.h
@@ -172,6 +172,41 @@ typedef struct
 #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
 {
index dfa6c9e..a2dc929 100644 (file)
--- a/cgamevm.c
+++ b/cgamevm.c
@@ -196,7 +196,7 @@ float CGVM_TracePhysics(const float *start, const float *end, const float *world
        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;
diff --git a/chase.c b/chase.c
index 1d0fe2a..f03eb49 100644 (file)
--- a/chase.c
+++ b/chase.c
@@ -68,7 +68,7 @@ void Chase_Update (void)
        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;
index 1abd1cb..657a0ff 100644 (file)
@@ -29,9 +29,9 @@ typedef struct physentity_s
 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;
@@ -45,13 +45,13 @@ float CL_TraceLine (const vec3_t start, const vec3_t end, vec3_t impact, vec3_t
                *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;
@@ -80,11 +80,11 @@ float CL_TraceLine (const vec3_t start, const vec3_t end, vec3_t impact, vec3_t
                        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)
@@ -112,10 +112,22 @@ void CL_FindNonSolidLocation(const vec3_t in, vec3_t out, vec_t radius)
                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)
index c7ba402..8a4f982 100644 (file)
@@ -4,10 +4,11 @@
 
 // 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
index f46a90c..88b134c 100644 (file)
--- a/cl_main.c
+++ b/cl_main.c
@@ -710,7 +710,7 @@ void CL_LinkNetworkEntity(entity_t *e)
                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;
                }
index e03b0e3..7e4221b 100644 (file)
@@ -26,7 +26,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 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)
@@ -152,7 +152,7 @@ void VectorVectors(const vec3_t forward, vec3_t right, vec3_t up)
 #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;
@@ -442,7 +442,7 @@ void CL_SpawnDecalParticleForPoint(const vec3_t org, float maxdist, float size,
        {
                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;
@@ -606,7 +606,7 @@ void CL_ParticleExplosion (vec3_t org)
                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++)
@@ -631,7 +631,7 @@ void CL_ParticleExplosion (vec3_t org)
                                        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);
@@ -746,7 +746,7 @@ void CL_SparkShower (vec3_t org, vec3_t dir, int count)
                                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);
                        }
                }
@@ -790,7 +790,7 @@ void CL_BloodPuff (vec3_t org, vec3_t vel, int count)
                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;
        }
@@ -1072,7 +1072,7 @@ void CL_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent)
        VectorMA(start, dec, vec, pos);
        len -= dec;
 
-       contents = CL_PointContents(pos);
+       contents = CL_PointQ1Contents(pos);
        if (contents == CONTENTS_SKY || contents == CONTENTS_LAVA)
                return;
 
@@ -1265,7 +1265,7 @@ void CL_MoveParticles (void)
                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)
@@ -1322,7 +1322,7 @@ void CL_MoveParticles (void)
                {
                        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;
@@ -1335,7 +1335,7 @@ void CL_MoveParticles (void)
                        {
                        case pt_blood:
                                if (!content)
-                                       content = CL_PointContents(p->org);
+                                       content = CL_PointQ1Contents(p->org);
                                a = content;
                                if (a != CONTENTS_EMPTY)
                                {
@@ -1353,7 +1353,7 @@ void CL_MoveParticles (void)
                                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;
@@ -1370,7 +1370,7 @@ void CL_MoveParticles (void)
                                        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;
index 19e72e9..f90470f 100644 (file)
@@ -698,8 +698,8 @@ static void SCR_CalcRefdef (void)
        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);
index 4936e2d..0e2cff8 100644 (file)
@@ -1,5 +1,6 @@
 
 #include "quakedef.h"
+#include "winding.h"
 
 typedef struct
 {
@@ -15,6 +16,9 @@ typedef struct
 
        // end - start
        double dist[3];
+
+       // overrides the CONTENTS_SOLID in the box bsp tree
+       int boxsupercontents;
 }
 RecursiveHullCheckTraceInfo_t;
 
@@ -44,37 +48,26 @@ loc0:
        // 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;
                }
        }
@@ -240,7 +233,7 @@ 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)
 {
        RecursiveHullCheckTraceInfo_t rhc;
        // fill in a default trace
@@ -256,8 +249,10 @@ void Collision_ClipTrace_Box(trace_t *trace, const vec3_t cmins, const vec3_t cm
        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);
@@ -292,15 +287,175 @@ void Collision_PrintBrushAsQHull(colbrushf_t *brush, const char *name)
                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;
 }
 
@@ -351,14 +506,16 @@ void Collision_CalcPlanesForPolygonBrushFloat(colbrushf_t *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;
 }
 
@@ -370,8 +527,7 @@ float nearestplanedist_float(const float *normal, const colpointf_t *points, int
        while(--numpoints)
        {
                dist = DotProduct(points->v, normal);
-               if (bestdist > dist)
-                       bestdist = dist;
+               bestdist = min(bestdist, dist);
                points++;
        }
        return bestdist;
@@ -385,8 +541,7 @@ float furthestplanedist_float(const float *normal, const colpointf_t *points, in
        while(--numpoints)
        {
                dist = DotProduct(points->v, normal);
-               if (bestdist < dist)
-                       bestdist = dist;
+               bestdist = max(bestdist, dist);
                points++;
        }
        return bestdist;
@@ -398,7 +553,7 @@ float furthestplanedist_float(const float *normal, const colpointf_t *points, in
 // 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;
 
@@ -459,18 +614,23 @@ void Collision_TraceBrushBrushFloat(trace_t *trace, const colbrushf_t *thisbrush
                }
        }
 
+       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);
@@ -542,6 +702,7 @@ void Collision_InitBrushForBox(void)
        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;
@@ -574,9 +735,33 @@ colbrushf_t *Collision_BrushForBox(const matrix4x4_t *matrix, const vec3_t mins,
                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,
index dfc02ff..3093f30 100644 (file)
@@ -11,33 +11,39 @@ plane_t;
 
 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
 {
@@ -54,16 +60,27 @@ colplanef_t;
 
 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);
index a3ee127..0e57d95 100644 (file)
@@ -400,6 +400,10 @@ SOURCE=.\wavefile.c
 # 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
@@ -660,6 +664,10 @@ SOURCE=.\wavefile.h
 # 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
index a1effa8..7d3a700 100644 (file)
@@ -320,7 +320,7 @@ void R_Model_Alias_DrawFakeShadow (entity_render_t *ent)
        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);
index 5df0849..5483275 100644 (file)
@@ -62,6 +62,7 @@ cvar_t r_wateralpha = {CVAR_SAVE, "r_wateralpha","1"};
 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"};
@@ -244,21 +245,22 @@ void GL_Main_Init(void)
        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);
@@ -485,7 +487,7 @@ void R_DrawViewModel (void)
 */
 
 void R_DrawNoModel(entity_render_t *ent);
-void R_DrawModels ()
+void R_DrawModels(void)
 {
        int i;
        entity_render_t *ent;
@@ -506,7 +508,7 @@ void R_DrawModels ()
        }
 }
 
-void R_DrawFakeShadows (void)
+void R_DrawFakeShadows(void)
 {
        int i;
        entity_render_t *ent;
@@ -917,7 +919,7 @@ void R_RenderView (void)
        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)
index 892193e..39f129b 100644 (file)
@@ -1902,9 +1902,17 @@ void R_Model_Brush_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, v
        }
 }
 
+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);
@@ -1926,7 +1934,7 @@ void R_Q3BSP_DrawFace_Mesh(entity_render_t *ent, q3mface_t *face)
        }
        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)
@@ -1935,6 +1943,8 @@ 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:
@@ -1961,8 +1971,22 @@ void R_Q3BSP_Draw(entity_render_t *ent)
        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);
+       }
 }
 
 /*
diff --git a/host.c b/host.c
index 5039215..69e3836 100644 (file)
--- a/host.c
+++ b/host.c
@@ -238,13 +238,8 @@ void Host_ServerOptions (void)
 
        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);
 }
index a9edef5..bd43e70 100644 (file)
--- a/makefile
+++ b/makefile
@@ -56,7 +56,7 @@ SHAREDOBJECTS=        cmd.o collision.o common.o crc.o cvar.o \
                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
index 83f39a8..3fe396b 100644 (file)
--- a/mathlib.c
+++ b/mathlib.c
@@ -215,9 +215,7 @@ void VectorVectors(const vec3_t forward, vec3_t right, vec3_t 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);
        VectorNormalizeFast(right);
        CrossProduct(right, forward, up);
 }
@@ -231,9 +229,7 @@ void VectorVectorsDouble(const double *forward, double *right, double *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);
 }
index 5530052..38e7d23 100644 (file)
@@ -21,6 +21,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #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
 
@@ -323,6 +324,41 @@ static void Mod_Q1BSP_FindNonSolidLocation(model_t *model, const vec3_t in, vec3
        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
@@ -364,37 +400,26 @@ loc0:
        // 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;
                }
        }
@@ -483,7 +508,7 @@ loc0:
        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];
@@ -492,6 +517,7 @@ static void Mod_Q1BSP_TraceBox(struct model_s *model, trace_t *trace, const vec3
        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);
@@ -1993,293 +2019,6 @@ static void Mod_Q1BSP_LoadPlanes(lump_t *l)
        }
 }
 
-#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;
@@ -2455,7 +2194,7 @@ static void Mod_Q1BSP_FinalizePortals(void)
                                // advance to next portal
                                portal++;
                        }
-                       FreeWinding(p->winding);
+                       Winding_Free(p->winding);
                }
                FreePortal(p);
                p = pnext;
@@ -2559,7 +2298,7 @@ static void Mod_Q1BSP_RecursiveNodePortals(mnode_t *node)
        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])
        {
@@ -2577,7 +2316,7 @@ static void Mod_Q1BSP_RecursiveNodePortals(mnode_t *node)
                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");
@@ -2610,7 +2349,7 @@ static void Mod_Q1BSP_RecursiveNodePortals(mnode_t *node)
                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)
                {
@@ -2635,7 +2374,7 @@ static void Mod_Q1BSP_RecursiveNodePortals(mnode_t *node)
                *splitportal = *portal;
                splitportal->chain = temp;
                splitportal->winding = backwinding;
-               FreeWinding(portal->winding);
+               Winding_Free(portal->winding);
                portal->winding = frontwinding;
 
                if (side == 0)
@@ -2654,7 +2393,6 @@ static void Mod_Q1BSP_RecursiveNodePortals(mnode_t *node)
        Mod_Q1BSP_RecursiveNodePortals(back);
 }
 
-
 static void Mod_Q1BSP_MakePortals(void)
 {
        portalchain = NULL;
@@ -2797,7 +2535,7 @@ static void Mod_Q1BSP_BuildPVSTextureChains(model_t *model)
        }
 }
 
-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;
@@ -2830,12 +2568,12 @@ void Mod_Q1BSP_FatPVS_RecursiveBSPNode(model_t *model, const vec3_t org, vec_t r
 
 //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;
 }
 
@@ -2897,6 +2635,8 @@ void Mod_Q1BSP_Load(model_t *mod, void *buffer)
                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;
@@ -3441,7 +3181,7 @@ static void Mod_Q2BSP_LoadModels(lump_t *l)
 */
 }
 
-void Mod_Q2BSP_Load(model_t *mod, void *buffer)
+void static Mod_Q2BSP_Load(model_t *mod, void *buffer)
 {
        int i;
        q2dheader_t *header;
@@ -3493,6 +3233,8 @@ void Mod_Q2BSP_Load(model_t *mod, void *buffer)
        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)
 {
@@ -3553,7 +3295,11 @@ static void Mod_Q3BSP_LoadTextures(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);
@@ -3617,11 +3363,8 @@ static void Mod_Q3BSP_LoadBrushes(lump_t *l)
 {
        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))
@@ -3632,6 +3375,9 @@ static void Mod_Q3BSP_LoadBrushes(lump_t *l)
        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);
@@ -3645,86 +3391,24 @@ static void Mod_Q3BSP_LoadBrushes(lump_t *l)
                        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)
@@ -3960,7 +3644,7 @@ static void Mod_Q3BSP_LoadFaces(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]);
@@ -4217,13 +3901,13 @@ static void Mod_Q3BSP_LoadPVS(lump_t *l)
        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)
        {
@@ -4236,7 +3920,7 @@ void Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace_t *trace, q3mnode_t *node, cons
                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;
@@ -4245,7 +3929,7 @@ void Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace_t *trace, q3mnode_t *node, cons
                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;
@@ -4270,7 +3954,7 @@ void Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace_t *trace, q3mnode_t *node, cons
        }
 }
 
-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;
@@ -4278,7 +3962,7 @@ void Mod_Q3BSP_LightPoint(model_t *model, const vec3_t p, vec3_t ambientcolor, v
        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;
@@ -4290,6 +3974,7 @@ void Mod_Q3BSP_TraceBox(model_t *model, trace_t *trace, const vec3_t boxstartmin
        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
@@ -4329,18 +4014,46 @@ loc0:
        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);
@@ -4350,6 +4063,7 @@ void Mod_Q3BSP_Load(model_t *mod, void *buffer)
 {
        int i;
        q3dheader_t *header;
+       float corner[3], yawradius, modelradius;
 
        mod->type = mod_brushq3;
 
@@ -4365,6 +4079,8 @@ void Mod_Q3BSP_Load(model_t *mod, void *buffer)
                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;
@@ -4422,6 +4138,22 @@ void Mod_Q3BSP_Load(model_t *mod, void *buffer)
                        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;
        }
 }
 
index 0507588..1d6b78e 100644 (file)
@@ -152,12 +152,14 @@ typedef struct model_brush_s
        // 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);
 }
@@ -265,11 +267,15 @@ typedef struct model_brushq2_s
 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;
@@ -559,6 +565,10 @@ void Mod_ShadowMesh_Free(shadowmesh_t *mesh);
 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
index faf7b17..47ddc33 100644 (file)
--- a/pr_cmds.c
+++ b/pr_cmds.c
@@ -1485,7 +1485,7 @@ PF_pointcontents
 */
 void PF_pointcontents (void)
 {
-       G_FLOAT(OFS_RETURN) = SV_PointContents(G_VECTOR(OFS_PARM0));
+       G_FLOAT(OFS_RETURN) = SV_PointQ1Contents(G_VECTOR(OFS_PARM0));
 }
 
 /*
index 4ed1ca6..6cd5cfa 100644 (file)
@@ -82,7 +82,7 @@ void R_DrawWorldCrosshair(void)
        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]);
index 23a44c6..de58633 100644 (file)
@@ -222,7 +222,7 @@ void R_MoveExplosion(explosion_t *e)
                        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;
index 04f9a75..6a49a87 100644 (file)
--- a/r_light.c
+++ b/r_light.c
@@ -151,7 +151,7 @@ void R_DrawCoronas(void)
        {
                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;
@@ -315,7 +315,7 @@ void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffu
                        {
                                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);
@@ -335,7 +335,7 @@ void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffu
                        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);
@@ -458,7 +458,7 @@ int R_LightModel(float *ambient4f, float *diffusecolor, float *diffusenormal, co
                        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);
@@ -595,7 +595,7 @@ void R_UpdateEntLights(entity_render_t *ent)
                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;
index 4234f96..6cbf578 100644 (file)
@@ -1751,7 +1751,7 @@ void R_Shadow_NewWorldLight(vec3_t origin, float radius, vec3_t color, int style
                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;
@@ -1961,7 +1961,7 @@ void R_Shadow_SelectLightInView(void)
                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;
@@ -2256,7 +2256,7 @@ void R_Shadow_SetCursorLocationForView(void)
        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;
index f523fe4..342f92b 100644 (file)
--- a/render.h
+++ b/render.h
@@ -99,13 +99,14 @@ extern      unsigned short  d_lightstylevalue[256]; // 8.8 fraction of base light valu
 
 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
index 8bb9b75..6feab85 100644 (file)
--- a/sv_move.c
+++ b/sv_move.c
@@ -51,7 +51,7 @@ qboolean SV_CheckBottom (edict_t *ent)
                {
                        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;
                }
 
@@ -138,7 +138,7 @@ qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink)
                        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);
index febfea8..6cfd905 100644 (file)
--- a/sv_phys.c
+++ b/sv_phys.c
@@ -854,18 +854,18 @@ qboolean SV_CheckWater (edict_t *ent)
 
        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;
                }
@@ -1117,7 +1117,7 @@ SV_CheckWaterTransition
 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
@@ -1142,7 +1142,7 @@ void SV_CheckWaterTransition (edict_t *ent)
                        SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
 
                ent->v->watertype = CONTENTS_EMPTY;
-               ent->v->waterlevel = cont;
+               ent->v->waterlevel = 0;
        }
 }
 
index 5bfa0c4..05624d8 100644 (file)
--- a/sv_user.c
+++ b/sv_user.c
@@ -103,8 +103,8 @@ void SV_SetIdealPitch (void)
        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;
diff --git a/todo b/todo
index 29b0cf3..fbda966 100644 (file)
--- a/todo
+++ b/todo
@@ -1,6 +1,10 @@
 - 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
diff --git a/view.c b/view.c
index 94fe265..54eb0ab 100644 (file)
--- a/view.c
+++ b/view.c
@@ -394,7 +394,7 @@ void V_CalcViewBlend(void)
        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:
diff --git a/world.c b/world.c
index 530fb2a..3856598 100644 (file)
--- a/world.c
+++ b/world.c
@@ -490,9 +490,9 @@ trace_t SV_ClipMoveToEntity(edict_t *ent, const vec3_t start, const vec3_t mins,
        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;
@@ -584,17 +584,9 @@ void SV_ClipToNode(moveclip_t *clip, link_t *list)
                        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;
        }
@@ -705,10 +697,21 @@ trace_t SV_Move(const vec3_t start, const vec3_t mins, const vec3_t maxs, const
        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);
diff --git a/world.h b/world.h
index 4bbcb28..1e8486c 100644 (file)
--- a/world.h
+++ b/world.h
@@ -57,7 +57,8 @@ int SV_TestEntityPosition (edict_t *ent);
 // 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