From e24d834dcbcc61f28fdf0e2c1ba75693d9e23ed1 Mon Sep 17 00:00:00 2001 From: havoc Date: Tue, 19 Aug 2003 00:25:08 +0000 Subject: [PATCH] more q3bsp work (and no it still doesn't work right) 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 --- bspfile.h | 35 +++ cgamevm.c | 2 +- chase.c | 2 +- cl_collision.c | 30 ++- cl_collision.h | 7 +- cl_main.c | 2 +- cl_particles.c | 26 +-- cl_screen.c | 4 +- collision.c | 267 +++++++++++++++++++---- collision.h | 43 ++-- darkplaces.dsp | 8 + gl_models.c | 2 +- gl_rmain.c | 38 ++-- gl_rsurf.c | 32 ++- host.c | 9 +- makefile | 2 +- mathlib.c | 8 +- model_brush.c | 562 +++++++++++++------------------------------------ model_shared.h | 14 +- pr_cmds.c | 2 +- r_crosshairs.c | 2 +- r_explosion.c | 2 +- r_light.c | 10 +- r_shadow.c | 6 +- render.h | 15 +- sv_move.c | 4 +- sv_phys.c | 10 +- sv_user.c | 4 +- todo | 4 + view.c | 2 +- world.c | 29 +-- world.h | 3 +- 32 files changed, 606 insertions(+), 580 deletions(-) diff --git a/bspfile.h b/bspfile.h index 35945c20..48c83219 100644 --- 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 { diff --git a/cgamevm.c b/cgamevm.c index dfa6c9ec..a2dc9294 100644 --- 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 1d0fe2a6..f03eb49f 100644 --- 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; diff --git a/cl_collision.c b/cl_collision.c index 1abd1cb9..657a0ff4 100644 --- a/cl_collision.c +++ b/cl_collision.c @@ -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) diff --git a/cl_collision.h b/cl_collision.h index c7ba4022..8a4f9828 100644 --- a/cl_collision.h +++ b/cl_collision.h @@ -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 diff --git a/cl_main.c b/cl_main.c index f46a90cd..88b134c8 100644 --- 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; } diff --git a/cl_particles.c b/cl_particles.c index e03b0e36..7e4221b4 100644 --- a/cl_particles.c +++ b/cl_particles.c @@ -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; diff --git a/cl_screen.c b/cl_screen.c index 19e72e96..f90470f1 100644 --- a/cl_screen.c +++ b/cl_screen.c @@ -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); diff --git a/collision.c b/collision.c index 4936e2d4..0e2cff89 100644 --- a/collision.c +++ b/collision.c @@ -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, diff --git a/collision.h b/collision.h index dfc02ff1..3093f30b 100644 --- a/collision.h +++ b/collision.h @@ -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); diff --git a/darkplaces.dsp b/darkplaces.dsp index a3ee127b..0e57d95d 100644 --- a/darkplaces.dsp +++ b/darkplaces.dsp @@ -400,6 +400,10 @@ SOURCE=.\wavefile.c # End Source File # Begin Source File +SOURCE=.\winding.c +# End Source File +# Begin Source File + SOURCE=.\world.c # End Source File # Begin Source File @@ -660,6 +664,10 @@ SOURCE=.\wavefile.h # End Source File # Begin Source File +SOURCE=.\winding.h +# End Source File +# Begin Source File + SOURCE=.\winquake.h # End Source File # Begin Source File diff --git a/gl_models.c b/gl_models.c index a1effa88..7d3a7002 100644 --- a/gl_models.c +++ b/gl_models.c @@ -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); diff --git a/gl_rmain.c b/gl_rmain.c index 5df08491..54832756 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -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) diff --git a/gl_rsurf.c b/gl_rsurf.c index 892193e8..39f129b0 100644 --- a/gl_rsurf.c +++ b/gl_rsurf.c @@ -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 50392158..69e38368 100644 --- 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); } diff --git a/makefile b/makefile index a9edef57..bd43e706 100644 --- 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 diff --git a/mathlib.c b/mathlib.c index 83f39a82..3fe396b8 100644 --- 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); } diff --git a/model_brush.c b/model_brush.c index 5530052b..38e7d23a 100644 --- a/model_brush.c +++ b/model_brush.c @@ -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; } } diff --git a/model_shared.h b/model_shared.h index 05075887..1d6b78e5 100644 --- a/model_shared.h +++ b/model_shared.h @@ -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 diff --git a/pr_cmds.c b/pr_cmds.c index faf7b176..47ddc33c 100644 --- 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)); } /* diff --git a/r_crosshairs.c b/r_crosshairs.c index 4ed1ca65..6cd5cfae 100644 --- a/r_crosshairs.c +++ b/r_crosshairs.c @@ -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]); diff --git a/r_explosion.c b/r_explosion.c index 23a44c6d..de586331 100644 --- a/r_explosion.c +++ b/r_explosion.c @@ -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; diff --git a/r_light.c b/r_light.c index 04f9a757..6a49a87f 100644 --- 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; diff --git a/r_shadow.c b/r_shadow.c index 4234f968..6cbf5784 100644 --- a/r_shadow.c +++ b/r_shadow.c @@ -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; diff --git a/render.h b/render.h index f523fe4a..342f92b5 100644 --- 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 diff --git a/sv_move.c b/sv_move.c index 8bb9b75b..6feab85d 100644 --- 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); diff --git a/sv_phys.c b/sv_phys.c index febfea83..6cfd9058 100644 --- 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; } } diff --git a/sv_user.c b/sv_user.c index 5bfa0c4c..05624d81 100644 --- 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 29b0cf37..fbda9665 100644 --- 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 94fe265d..54eb0ab1 100644 --- 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 530fb2af..38565987 100644 --- 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 4bbcb282..1e8486c7 100644 --- 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 -- 2.39.2