q3bsp is working, but no curves yet, and no realtime lighting support
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Sat, 23 Aug 2003 02:17:04 +0000 (02:17 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Sat, 23 Aug 2003 02:17:04 +0000 (02:17 +0000)
git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@3403 d7cf8633-e32d-0410-b094-e92efae38249

collision.c
collision.h
gl_rsurf.c
model_brush.c
model_shared.h
r_light.c
r_shadow.c
todo
world.c

index 0e2cff8..4418bc6 100644 (file)
@@ -637,6 +637,82 @@ void Collision_TraceBrushBrushFloat(trace_t *trace, const colbrushf_t *thisbrush
        }
 }
 
+// NOTE: start and end of brush pair must have same numplanes/numpoints
+void Collision_TraceLineBrushFloat(trace_t *trace, const vec3_t linestart, const vec3_t lineend, const colbrushf_t *thatbrush_start, const colbrushf_t *thatbrush_end)
+{
+       int nplane, fstartsolid, fendsolid, brushsolid;
+       float enterfrac, leavefrac, d1, d2, f, newimpactnormal[3];
+       const colplanef_t *startplane, *endplane;
+
+       enterfrac = -1;
+       leavefrac = 1;
+       fstartsolid = true;
+       fendsolid = true;
+
+       for (nplane = 0;nplane < thatbrush_start->numplanes;nplane++)
+       {
+               startplane = thatbrush_start->planes + nplane;
+               endplane = thatbrush_end->planes + nplane;
+               d1 = DotProduct(startplane->normal, linestart) - startplane->dist;
+               d2 = DotProduct(endplane->normal, lineend) - endplane->dist;
+
+               f = d1 - d2;
+               if (f >= 0)
+               {
+                       // moving into brush
+                       if (d2 > 0)
+                               return;
+                       if (d1 < 0)
+                               continue;
+                       // enter
+                       fstartsolid = false;
+                       f = (d1 - COLLISIONEPSILON) / f;
+                       f = bound(0, f, 1);
+                       if (enterfrac < f)
+                       {
+                               enterfrac = f;
+                               VectorBlend(startplane->normal, endplane->normal, enterfrac, newimpactnormal);
+                       }
+               }
+               else if (f < 0)
+               {
+                       // moving out of brush
+                       if (d1 > 0)
+                               return;
+                       if (d2 < 0)
+                               continue;
+                       // leave
+                       fendsolid = false;
+                       f = (d1 + COLLISIONEPSILON) / f;
+                       f = bound(0, f, 1);
+                       if (leavefrac > f)
+                               leavefrac = f;
+               }
+       }
+
+       brushsolid = trace->hitsupercontentsmask & thatbrush_start->supercontents;
+       if (fstartsolid)
+       {
+               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 (brushsolid && enterfrac > -1 && enterfrac < trace->fraction && enterfrac - (1.0f / 1024.0f) <= leavefrac)
+       {
+               trace->fraction = bound(0, enterfrac, 1);
+               VectorCopy(newimpactnormal, trace->plane.normal);
+       }
+}
+
 static colplanef_t polyf_planes[256 + 2];
 static colbrushf_t polyf_brush;
 
index 3093f30..49dde74 100644 (file)
@@ -74,6 +74,8 @@ typedef struct colbrushf_s
        colpointf_t *points;
        // renderable triangles, as int[3] elements indexing the points
        int *elements;
+       // used to avoid tracing against the same brush more than once
+       int markframe;
 }
 colbrushf_t;
 
@@ -82,6 +84,7 @@ void Collision_CalcPlanesForPolygonBrushFloat(colbrushf_t *brush);
 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_TraceLineBrushFloat(trace_t *trace, const vec3_t linestart, const vec3_t lineend, 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 39f129b..80f8096 100644 (file)
@@ -1965,16 +1965,57 @@ void R_Q3BSP_DrawSky(entity_render_t *ent)
 }
 */
 
+void R_Q3BSP_RecursiveWorldNode(entity_render_t *ent, q3mnode_t *node, const vec3_t modelorg, qbyte *pvs, int markframe)
+{
+       int i;
+       q3mleaf_t *leaf;
+       while (node->isnode)
+       {
+               if (R_CullBox(node->mins, node->maxs))
+                       return;
+               R_Q3BSP_RecursiveWorldNode(ent, node->children[0], modelorg, pvs, markframe);
+               node = node->children[1];
+       }
+       if (R_CullBox(node->mins, node->maxs))
+               return;
+       leaf = (q3mleaf_t *)node;
+       if (pvs[leaf->clusterindex >> 3] & (1 << (leaf->clusterindex & 7)))
+       {
+               for (i = 0;i < leaf->numleaffaces;i++)
+               {
+                       if (leaf->firstleafface[i]->markframe != markframe)
+                       {
+                               leaf->firstleafface[i]->markframe = markframe;
+                               R_Q3BSP_DrawFace(ent, leaf->firstleafface[i]);
+                       }
+               }
+       }
+}
+
+
+
 void R_Q3BSP_Draw(entity_render_t *ent)
 {
        int i;
        q3mface_t *face;
+       vec3_t modelorg;
        model_t *model;
-       model = ent->model;
+       qbyte *pvs;
+       static int markframe = 0;
        R_Mesh_Matrix(&ent->matrix);
+       model = ent->model;
        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 (ent == &cl_entities[0].render)
+               {
+                       Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
+                       pvs = model->brush.GetPVS(model, modelorg);
+                       R_Q3BSP_RecursiveWorldNode(ent, model->brushq3.data_nodes, modelorg, pvs, ++markframe);
+               }
+               else
+                       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;
index 38e7d23..77e9560 100644 (file)
@@ -2538,32 +2538,27 @@ static void Mod_Q1BSP_BuildPVSTextureChains(model_t *model)
 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;
        float d;
 
-       while (1)
+       while (node->contents >= 0)
        {
-       // if this is a leaf, accumulate the pvs bits
-               if (node->contents < 0)
-               {
-                       if (node->contents != CONTENTS_SOLID && ((mleaf_t *)node)->pvsdata)
-                               for (i = 0;i < pvsbytes;i++)
-                                       pvsbuffer[i] |= ((mleaf_t *)node)->pvsdata[i];
-                       return;
-               }
-
-               plane = node->plane;
-               d = DotProduct(org, plane->normal) - plane->dist;
+               d = PlaneDiff(org, node->plane);
                if (d > radius)
                        node = node->children[0];
                else if (d < -radius)
                        node = node->children[1];
                else
-               {       // go down both
+               {
+                       // go down both sides
                        Mod_Q1BSP_FatPVS_RecursiveBSPNode(model, org, radius, pvsbuffer, pvsbytes, node->children[0]);
                        node = node->children[1];
                }
        }
+       // FIXME: code!
+       // if this is a leaf, accumulate the pvs bits
+       if (node->contents != CONTENTS_SOLID && ((mleaf_t *)node)->pvsdata)
+               for (i = 0;i < pvsbytes;i++)
+                       pvsbuffer[i] |= ((mleaf_t *)node)->pvsdata[i];
 }
 
 //Calculates a PVS that is the inclusive or of all leafs within radius pixels
@@ -2577,6 +2572,20 @@ static int Mod_Q1BSP_FatPVS(model_t *model, const vec3_t org, vec_t radius, qbyt
        return bytes;
 }
 
+//Returns PVS data for a given point
+//(note: always returns valid data, never NULL)
+static qbyte *Mod_Q1BSP_GetPVS(model_t *model, const vec3_t p)
+{
+       mnode_t *node;
+       Mod_CheckLoaded(model);
+       // LordHavoc: modified to start at first clip node,
+       // in other words: first node of the (sub)model
+       node = model->brushq1.nodes + model->brushq1.hulls[0].firstclipnode;
+       while (node->contents == 0)
+               node = node->children[(node->plane->type < 3 ? p[node->plane->type] : DotProduct(p,node->plane->normal)) < node->plane->dist];
+       return ((mleaf_t *)node)->pvsdata;
+}
+
 static void Mod_Q1BSP_RoundUpToHullSize(model_t *cmodel, const vec3_t inmins, const vec3_t inmaxs, vec3_t outmins, vec3_t outmaxs)
 {
        vec3_t size;
@@ -2637,12 +2646,13 @@ void Mod_Q1BSP_Load(model_t *mod, void *buffer)
 
        mod->brush.SuperContentsFromNativeContents = Mod_Q1BSP_SuperContentsFromNativeContents;
        mod->brush.NativeContentsFromSuperContents = Mod_Q1BSP_NativeContentsFromSuperContents;
-       mod->brush.AmbientSoundLevelsForPoint = Mod_Q1BSP_AmbientSoundLevelsForPoint;
+       mod->brush.GetPVS = Mod_Q1BSP_GetPVS;
        mod->brush.FatPVS = Mod_Q1BSP_FatPVS;
        mod->brush.BoxTouchingPVS = Mod_Q1BSP_BoxTouchingPVS;
        mod->brush.LightPoint = Mod_Q1BSP_LightPoint;
        mod->brush.FindNonSolidLocation = Mod_Q1BSP_FindNonSolidLocation;
        mod->brush.TraceBox = Mod_Q1BSP_TraceBox;
+       mod->brush.AmbientSoundLevelsForPoint = Mod_Q1BSP_AmbientSoundLevelsForPoint;
        mod->brush.RoundUpToHullSize = Mod_Q1BSP_RoundUpToHullSize;
        mod->brushq1.PointInLeaf = Mod_Q1BSP_PointInLeaf;
        mod->brushq1.BuildPVSTextureChains = Mod_Q1BSP_BuildPVSTextureChains;
@@ -3363,7 +3373,7 @@ static void Mod_Q3BSP_LoadBrushes(lump_t *l)
 {
        q3dbrush_t *in;
        q3mbrush_t *out;
-       int i, j, n, c, count, numplanes, maxplanes;
+       int i, j, n, c, count, maxplanes;
        mplane_t *planes;
 
        in = (void *)(mod_base + l->fileofs);
@@ -3392,9 +3402,9 @@ static void Mod_Q3BSP_LoadBrushes(lump_t *l)
                out->texture = loadmodel->brushq3.data_textures + n;
 
                // make a list of mplane_t structs to construct a colbrush from
-               if (maxplanes < numplanes)
+               if (maxplanes < out->numbrushsides)
                {
-                       maxplanes = numplanes;
+                       maxplanes = out->numbrushsides;
                        if (planes)
                                Mem_Free(planes);
                        planes = Mem_Alloc(tempmempool, sizeof(mplane_t) * maxplanes);
@@ -3829,13 +3839,18 @@ static void Mod_Q3BSP_LoadNodes(lump_t *l)
                        }
                        else
                        {
-                               n = 1 - n;
+                               n = -1 - n;
                                if (n >= loadmodel->brushq3.num_leafs)
                                        Host_Error("Mod_Q3BSP_LoadNodes: invalid child leaf index %i (%i leafs)\n", n, loadmodel->brushq3.num_leafs);
                                out->children[j] = (q3mnode_t *)(loadmodel->brushq3.data_leafs + n);
                        }
                }
-               // we don't load the mins/maxs
+               for (j = 0;j < 3;j++)
+               {
+                       // yes the mins/maxs are ints
+                       out->mins[j] = LittleLong(in->mins[j]);
+                       out->maxs[j] = LittleLong(in->maxs[j]);
+               }
        }
 
        // set the parent pointers
@@ -3907,22 +3922,120 @@ static void Mod_Q3BSP_FindNonSolidLocation(model_t *model, const vec3_t in, vec3
        VectorCopy(in, out);
 }
 
-static 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_LightPoint(model_t *model, const vec3_t p, vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal)
 {
+       int i, j, k, index[3];
+       float transformed[3], blend1, blend2, blend, yaw, pitch, sinpitch;
+       q3dlightgrid_t *a, *s;
+       // FIXME: write this
+       if (!model->brushq3.num_lightgrid)
+       {
+               ambientcolor[0] += 128;
+               ambientcolor[1] += 128;
+               ambientcolor[2] += 128;
+               return;
+       }
+       Matrix4x4_Transform(&model->brushq3.num_lightgrid_indexfromworld, p, transformed);
+       //Matrix4x4_Print(&model->brushq3.num_lightgrid_indexfromworld);
+       //Con_Printf("%f %f %f transformed %f %f %f clamped ", p[0], p[1], p[2], transformed[0], transformed[1], transformed[2]);
+       transformed[0] = bound(0, transformed[0], model->brushq3.num_lightgrid_isize[0]);
+       transformed[1] = bound(0, transformed[1], model->brushq3.num_lightgrid_isize[1]);
+       transformed[2] = bound(0, transformed[2], model->brushq3.num_lightgrid_isize[2]);
+       index[0] = (int)floor(transformed[0]);
+       index[1] = (int)floor(transformed[1]);
+       index[2] = (int)floor(transformed[2]);
+       //Con_Printf("%f %f %f index %i %i %i:\n", transformed[0], transformed[1], transformed[2], index[0], index[1], index[2]);
+       // now lerp the values
+       VectorClear(diffusenormal);
+       a = &model->brushq3.data_lightgrid[(index[2] * model->brushq3.num_lightgrid_isize[1] + index[1]) * model->brushq3.num_lightgrid_isize[0] + index[0]];
+       for (k = 0;k < 2;k++)
+       {
+               blend1 = (k ? (transformed[2] - index[2]) : (1 - (transformed[2] - index[2])));
+               for (j = 0;j < 2;j++)
+               {
+                       blend2 = blend1 * (j ? (transformed[1] - index[1]) : (1 - (transformed[1] - index[1])));
+                       for (i = 0;i < 2;i++)
+                       {
+                               blend = blend2 * (i ? (transformed[0] - index[0]) : (1 - (transformed[0] - index[0])));
+                               s = a + (k * model->brushq3.num_lightgrid_isize[1] + j) * model->brushq3.num_lightgrid_isize[0] + i;
+                               VectorMA(ambientcolor, blend * (1.0f / 128.0f), s->ambientrgb, ambientcolor);
+                               VectorMA(diffusecolor, blend * (1.0f / 128.0f), s->diffusergb, diffusecolor);
+                               pitch = s->diffusepitch * M_PI / 128;
+                               yaw = s->diffuseyaw * M_PI / 128;
+                               sinpitch = sin(pitch);
+                               diffusenormal[0] += blend * (cos(yaw) * sinpitch);
+                               diffusenormal[1] += blend * (sin(yaw) * sinpitch);
+                               diffusenormal[2] += blend * (cos(pitch));
+                               //Con_Printf("blend %f: ambient %i %i %i, diffuse %i %i %i, diffusepitch %i diffuseyaw %i (%f %f, normal %f %f %f)\n", blend, s->ambientrgb[0], s->ambientrgb[1], s->ambientrgb[2], s->diffusergb[0], s->diffusergb[1], s->diffusergb[2], s->diffusepitch, s->diffuseyaw, pitch, yaw, (cos(yaw) * cospitch), (sin(yaw) * cospitch), (-sin(pitch)));
+                       }
+               }
+       }
+       VectorNormalize(diffusenormal);
+       //Con_Printf("result: ambient %f %f %f diffuse %f %f %f diffusenormal %f %f %f\n", ambientcolor[0], ambientcolor[1], ambientcolor[2], diffusecolor[0], diffusecolor[1], diffusecolor[2], diffusenormal[0], diffusenormal[1], diffusenormal[2]);
+}
+
+static void Mod_Q3BSP_TraceLine_RecursiveBSPNode(trace_t *trace, q3mnode_t *node, const vec3_t start, const vec3_t end, vec_t startfrac, vec_t endfrac, const vec3_t linestart, const vec3_t lineend, int markframe)
+{
+       int i, startside, endside;
+       float dist1, dist2, midfrac, mid[3];
+       q3mleaf_t *leaf;
+       // note: all line fragments past first impact fraction are ignored
+       while (node->isnode)
+       {
+               // recurse down node sides
+               dist1 = PlaneDiff(start, node->plane);
+               dist2 = PlaneDiff(end, node->plane);
+               startside = dist1 < 0;
+               endside = dist2 < 0;
+               if (startside == endside)
+               {
+                       // most of the time the line fragment is on one side of the plane
+                       node = node->children[startside];
+               }
+               else
+               {
+                       // take the near side first
+                       if (startfrac < trace->fraction)
+                       {
+                               // line crosses node plane, split the line
+                               midfrac = dist1 / (dist1 - dist2);
+                               VectorLerp(linestart, midfrac, lineend, mid);
+                               Mod_Q3BSP_TraceLine_RecursiveBSPNode(trace, node->children[startside], start, mid, startfrac, midfrac, linestart, lineend, markframe);
+                               if (midfrac < trace->fraction)
+                                       Mod_Q3BSP_TraceLine_RecursiveBSPNode(trace, node->children[endside], mid, end, midfrac, endfrac, linestart, lineend, markframe);
+                       }
+                       return;
+               }
+       }
+       // hit a leaf
+       leaf = (q3mleaf_t *)node;
+       for (i = 0;i < leaf->numleafbrushes;i++)
+       {
+               if (endfrac >= trace->fraction)
+                       return;
+               if (leaf->firstleafbrush[i]->colbrushf && leaf->firstleafbrush[i]->colbrushf->markframe != markframe)
+               {
+                       leaf->firstleafbrush[i]->colbrushf->markframe = markframe;
+                       Collision_TraceLineBrushFloat(trace, linestart, lineend, leaf->firstleafbrush[i]->colbrushf, leaf->firstleafbrush[i]->colbrushf);
+               }
+       }
+}
+
+static void Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace_t *trace, q3mnode_t *node, const colbrushf_t *thisbrush_start, const colbrushf_t *thisbrush_end, int markframe)
+{
+       int i;
+       float dist;
+       colpointf_t *ps, *pe;
+       q3mleaf_t *leaf;
        if (node->isnode)
        {
                // recurse down node sides
-               int i;
-               float dist;
-               colpointf_t *ps, *pe;
-               // FIXME? if TraceBrushPolygonTransform were to be made usable, the
-               // node planes would need to be transformed too
                dist = node->plane->dist - (1.0f / 8.0f);
                for (i = 0, ps = 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)
                        {
-                               Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end);
+                               Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end, markframe);
                                break;
                        }
                }
@@ -3931,7 +4044,7 @@ static void Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace_t *trace, q3mnode_t *nod
                {
                        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);
+                               Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[1], thisbrush_start, thisbrush_end, markframe);
                                break;
                        }
                }
@@ -3945,42 +4058,56 @@ static void Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace_t *trace, q3mnode_t *nod
        }
        else
        {
-               int i;
-               q3mleaf_t *leaf;
+               // hit a leaf
                leaf = (q3mleaf_t *)node;
                for (i = 0;i < leaf->numleafbrushes;i++)
-                       if (leaf->firstleafbrush[i]->colbrushf)
+               {
+                       if (leaf->firstleafbrush[i]->colbrushf && leaf->firstleafbrush[i]->colbrushf->markframe != markframe)
+                       {
+                               leaf->firstleafbrush[i]->colbrushf->markframe = markframe;
                                Collision_TraceBrushBrushFloat(trace, thisbrush_start, thisbrush_end, leaf->firstleafbrush[i]->colbrushf, leaf->firstleafbrush[i]->colbrushf);
+                       }
+               }
        }
 }
 
-static void Mod_Q3BSP_LightPoint(model_t *model, const vec3_t p, vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal)
-{
-       // FIXME: write this
-       ambientcolor[0] += 255;
-       ambientcolor[1] += 255;
-       ambientcolor[2] += 255;
-}
-
 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;
        matrix4x4_t startmatrix, endmatrix;
-       // FIXME: finish this code
-       Matrix4x4_CreateIdentity(&startmatrix);
-       Matrix4x4_CreateIdentity(&endmatrix);
-       thisbrush_start = Collision_BrushForBox(&startmatrix, boxstartmins, boxstartmaxs);
-       thisbrush_end = Collision_BrushForBox(&endmatrix, boxendmins, boxendmaxs);
+       static int markframe = 0;
        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);
+       Matrix4x4_CreateIdentity(&startmatrix);
+       Matrix4x4_CreateIdentity(&endmatrix);
+       if (VectorCompare(boxstartmins, boxstartmaxs) && VectorCompare(boxendmins, boxendmaxs))
+       {
+               // line trace
+               if (model->brushq3.submodel)
+               {
+                       for (i = 0;i < model->brushq3.data_thismodel->numbrushes;i++)
+                               if (model->brushq3.data_thismodel->firstbrush[i].colbrushf)
+                                       Collision_TraceLineBrushFloat(trace, boxstartmins, boxendmins, model->brushq3.data_thismodel->firstbrush[i].colbrushf, model->brushq3.data_thismodel->firstbrush[i].colbrushf);
+               }
+               else
+                       Mod_Q3BSP_TraceLine_RecursiveBSPNode(trace, model->brushq3.data_nodes, boxstartmins, boxendmins, 0, 1, boxstartmins, boxendmins, ++markframe);
+       }
        else
-               for (i = 0;i < model->brushq3.num_brushes;i++)
-                       if (model->brushq3.data_brushes[i].colbrushf)
-                               Collision_TraceBrushBrushFloat(trace, thisbrush_start, thisbrush_end, model->brushq3.data_brushes[i].colbrushf, model->brushq3.data_brushes[i].colbrushf);
+       {
+               // box trace, performed as box trace
+               thisbrush_start = Collision_BrushForBox(&startmatrix, boxstartmins, boxstartmaxs);
+               thisbrush_end = Collision_BrushForBox(&endmatrix, boxendmins, boxendmaxs);
+               if (model->brushq3.submodel)
+               {
+                       for (i = 0;i < model->brushq3.data_thismodel->numbrushes;i++)
+                               if (model->brushq3.data_thismodel->firstbrush[i].colbrushf)
+                                       Collision_TraceBrushBrushFloat(trace, thisbrush_start, thisbrush_end, model->brushq3.data_thismodel->firstbrush[i].colbrushf, model->brushq3.data_thismodel->firstbrush[i].colbrushf);
+               }
+               else
+                       Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, model->brushq3.data_nodes, thisbrush_start, thisbrush_end, ++markframe);
+       }
 }
 
 
@@ -4019,13 +4146,57 @@ static int Mod_Q3BSP_BoxTouchingPVS(model_t *model, const qbyte *pvs, const vec3
        return Mod_Q3BSP_BoxTouchingPVS_RecursiveBSPNode(model, model->brushq3.data_nodes, pvs, mins, maxs);
 }
 
+//Returns PVS data for a given point
+//(note: always returns valid data, never NULL)
+static qbyte *Mod_Q3BSP_GetPVS(model_t *model, const vec3_t p)
+{
+       q3mnode_t *node;
+       Mod_CheckLoaded(model);
+       node = model->brushq3.data_nodes;
+       while (node->isnode)
+               node = node->children[(node->plane->type < 3 ? p[node->plane->type] : DotProduct(p,node->plane->normal)) < node->plane->dist];
+       return model->brushq3.data_pvschains + ((q3mleaf_t *)node)->clusterindex * model->brushq3.num_pvschainlength;
+}
+
+static void Mod_Q3BSP_FatPVS_RecursiveBSPNode(model_t *model, const vec3_t org, vec_t radius, qbyte *pvsbuffer, int pvsbytes, q3mnode_t *node)
+{
+       int i;
+       float d;
+       qbyte *pvs;
+
+       while (node->isnode)
+       {
+               d = PlaneDiff(org, node->plane);
+               if (d > radius)
+                       node = node->children[0];
+               else if (d < -radius)
+                       node = node->children[1];
+               else
+               {
+                       // go down both sides
+                       Mod_Q3BSP_FatPVS_RecursiveBSPNode(model, org, radius, pvsbuffer, pvsbytes, node->children[0]);
+                       node = node->children[1];
+               }
+       }
+       // if this is a leaf, accumulate the pvs bits
+       pvs = model->brushq3.data_pvschains + ((q3mleaf_t *)node)->clusterindex * model->brushq3.num_pvschainlength;
+       for (i = 0;i < pvsbytes;i++)
+               pvsbuffer[i] |= pvs[i];
+       return;
+}
+
+//Calculates a PVS that is the inclusive or of all leafs within radius pixels
+//of the given point.
 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;
+       int bytes = model->brushq3.num_pvschainlength;
+       bytes = min(bytes, pvsbufferlength);
+       memset(pvsbuffer, 0, bytes);
+       Mod_Q3BSP_FatPVS_RecursiveBSPNode(model, org, radius, pvsbuffer, bytes, model->brushq3.data_nodes);
+       return bytes;
 }
 
+
 static int Mod_Q3BSP_SuperContentsFromNativeContents(model_t *model, int nativecontents)
 {
        int supercontents = 0;
@@ -4081,6 +4252,7 @@ void Mod_Q3BSP_Load(model_t *mod, void *buffer)
 
        mod->brush.SuperContentsFromNativeContents = Mod_Q3BSP_SuperContentsFromNativeContents;
        mod->brush.NativeContentsFromSuperContents = Mod_Q3BSP_NativeContentsFromSuperContents;
+       mod->brush.GetPVS = Mod_Q3BSP_GetPVS;
        mod->brush.FatPVS = Mod_Q3BSP_FatPVS;
        mod->brush.BoxTouchingPVS = Mod_Q3BSP_BoxTouchingPVS;
        mod->brush.LightPoint = Mod_Q3BSP_LightPoint;
@@ -4138,6 +4310,7 @@ void Mod_Q3BSP_Load(model_t *mod, void *buffer)
                        mod->mempool = NULL;
                }
                mod->brushq3.data_thismodel = loadmodel->brushq3.data_models + i;
+               mod->brushq3.submodel = i;
 
                VectorCopy(mod->brushq3.data_thismodel->mins, mod->normalmins);
                VectorCopy(mod->brushq3.data_thismodel->maxs, mod->normalmaxs);
index 1d6b78e..6e6605f 100644 (file)
@@ -154,13 +154,14 @@ typedef struct model_brush_s
        // 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);
+       qbyte *(*GetPVS)(struct model_s *model, const vec3_t p);
        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, int hitsupercontentsmask);
-       // this is actually only found on brushq1, but NULL is handled gracefully
+       // these are actually only found on brushq1, but NULL is handled gracefully
+       void (*AmbientSoundLevelsForPoint)(struct model_s *model, const vec3_t p, qbyte *out, int outsize);
        void (*RoundUpToHullSize)(struct model_s *cmodel, const vec3_t inmins, const vec3_t inmaxs, vec3_t outmins, vec3_t outmaxs);
 }
 model_brush_t;
@@ -284,8 +285,12 @@ q3mtexture_t;
 
 typedef struct q3mnode_s
 {
+       //this part shared between node and leaf
        int isnode; // true
        struct q3mnode_s *parent;
+       vec3_t mins;
+       vec3_t maxs;
+       // this part unique to nodes
        struct mplane_s *plane;
        struct q3mnode_s *children[2];
 }
@@ -293,16 +298,18 @@ q3mnode_t;
 
 typedef struct q3mleaf_s
 {
+       //this part shared between node and leaf
        int isnode; // false
        struct q3mnode_s *parent;
+       vec3_t mins;
+       vec3_t maxs;
+       // this part unique to leafs
        int clusterindex;
        int areaindex;
        int numleaffaces;
        struct q3mface_s **firstleafface;
        int numleafbrushes;
        struct q3mbrush_s **firstleafbrush;
-       vec3_t mins;
-       vec3_t maxs;
 }
 q3mleaf_t;
 
@@ -352,6 +359,7 @@ typedef struct q3mface_s
        int firstelement;
        int numelements;
        int patchsize[2];
+       int markframe;
 
        float *data_vertex3f;
        float *data_texcoordtexture2f;
@@ -368,6 +376,10 @@ q3mface_t;
 
 typedef struct model_brushq3_s
 {
+       // if non-zero this is a submodel
+       // (this is the number of the submodel, an index into data_models)
+       int submodel;
+
        int num_textures;
        q3mtexture_t *data_textures;
 
index 6a49a87..273c3dc 100644 (file)
--- a/r_light.c
+++ b/r_light.c
@@ -365,7 +365,7 @@ static nearlight_t nearlight[MAX_DLIGHTS];
 int R_LightModel(float *ambient4f, float *diffusecolor, float *diffusenormal, const entity_render_t *ent, float colorr, float colorg, float colorb, float colora, int worldcoords)
 {
        int i, j, maxnearlights;
-       float v[3], f, mscale, stylescale, intensity, ambientcolor[3];
+       float v[3], f, mscale, stylescale, intensity, ambientcolor[3], tempdiffusenormal[3];
        nearlight_t *nl;
        mlight_t *sl;
        rdlight_t *rd;
@@ -386,7 +386,11 @@ int R_LightModel(float *ambient4f, float *diffusecolor, float *diffusenormal, co
        else
        {
                if (cl.worldmodel && cl.worldmodel->brush.LightPoint)
-                       cl.worldmodel->brush.LightPoint(cl.worldmodel, ent->origin, ambient4f, diffusecolor, diffusenormal);
+               {
+                       cl.worldmodel->brush.LightPoint(cl.worldmodel, ent->origin, ambient4f, diffusecolor, tempdiffusenormal);
+                       Matrix4x4_Transform3x3(&ent->inversematrix, tempdiffusenormal, diffusenormal);
+                       VectorNormalize(diffusenormal);
+               }
                else
                        VectorSet(ambient4f, 1, 1, 1);
        }
index 6cbf578..320ce23 100644 (file)
@@ -2274,9 +2274,9 @@ void R_Shadow_SetCursorLocationForView(void)
 
 void R_Shadow_UpdateWorldLightSelection(void)
 {
-       R_Shadow_SetCursorLocationForView();
        if (r_editlights.integer)
        {
+               R_Shadow_SetCursorLocationForView();
                R_Shadow_SelectLightInView();
                R_Shadow_DrawLightSprites();
        }
diff --git a/todo b/todo
index fbda966..0caffb7 100644 (file)
--- a/todo
+++ b/todo
@@ -1,10 +1,8 @@
 - 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: check out qe1 textures and make sure they load in all the e1 maps, report of crashing in most but not all maps (Linny Amore)
+-n darkplaces: fix a crash when changing level while using qe1 textures (Todd)
 -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
 0 darkplaces: bullets don't hit walls at steep angles in id1
 0 darkplaces: can't move when stuck in a monster (SeienAbunae)
 0 darkplaces: change particle() macro in cl_particles.c to have a do{}while(0) to eat the ;
-0 darkplaces: check out qe1 textures and make sure they load in all the e1 maps, report of crashing in most but not all maps (Linny Amore)
 0 darkplaces: cl_particles_maximum cvar (default 32768) which would change number of particles allowed at once (TheBeast)
 0 darkplaces: cl_port 26001 causes server browser to read successfully (yummyluv)
 0 darkplaces: client colors being reset to "15 15" each level in prydon gate (FrikaC)
 0 darkplaces: crashes if you type too long a command line in the console (SeienAbunae)
 0 darkplaces: darkplaces-glx -path transfusion crashes, fix the crash even though it's not going to work anyway (Todd)
+0 darkplaces: dedicated server should error out if it has no sockets (yummyluv)
+0 darkplaces: dedicated server should not bother allocating a loopback socket (yummyluv)
 0 darkplaces: default to 32bit color
 0 darkplaces: delay "connect" and "playdemo" and "timedemo" until after video init to cause quicker video startup (KrimZon)
 0 darkplaces: document how polygon collision works in the code (KrimZon)
@@ -40,7 +39,6 @@
 0 darkplaces: figure out what's wrong with gloss rendering vertex calculations, which may be GF2 related (QorpsE)
 0 darkplaces: figure out why monsters keep making fall pain sound after they've landed in dpmod (Cruaich)
 0 darkplaces: fix 'wall hugging' stuttering (romi)
-0 darkplaces: fix a crash when changing level while using qe1 textures (Todd)
 0 darkplaces: fix con_notify (should control number of lines)
 0 darkplaces: fix intermission failing to move view to intermission camera (romi, Zombie_13)
 0 darkplaces: fix key based turning being affected by slowmo - it should not be
 0 darkplaces: fix view blends slightly lingering as time goes on, they should go away completely (Cruaich)
 0 darkplaces: get rid of stencil options and make 32bit color automatically use stencil
 0 darkplaces: hack PF_nextent to skip inaccessible client slots depending on maxplayers - but always report ones that are active at the time (FrikaC)
+0 darkplaces: heartbeat should print an error message if used with no server running (yummyluv)
 0 darkplaces: identify weird lightmap texturing bug on TNT cards - goes away in r_textureunits 1 (NotoriousRay, Uffe)
+0 darkplaces: increase resolution of particlefont to 512x512 (Chillo)
 0 darkplaces: integrate zinx's psycho.c gamma hack as an easteregg
+0 darkplaces: investigate why server is not automatically sending heartbeats (yummyluv)
 0 darkplaces: make Com_HexDumpToConsole not use color
 0 darkplaces: make DP_EF_FULLBRIGHT extension (FrikaC)
 0 darkplaces: make LHNET_Read print out the names of read errors (yummyluv)
@@ -84,6 +85,7 @@
 0 darkplaces: reset zoom on connect (Rick)
 0 darkplaces: scrags frequently fly through ceilings - this needs to be fixed
 0 darkplaces: segfault reading memory in windows when starting a new server from menu (yummyluv)
+0 darkplaces: server is starting before the "port" cvar is set by commandline and scripts? (yummyluv)
 0 darkplaces: stuttering movement when walking over steps or monsters (romi)
 0 darkplaces: test TecnoX and find the frikbot crash in SV_Physics (KrimZon)
 0 darkplaces: test zlib support with entirely pk3'd id1 data (should crash because of zlib not being setup early enough - fix this) (Mabus)
 ? darkplaces: fix colormapping (Demonix)
 ? darkplaces: fix connecting to proquake servers through routers (Demonix)
 ? dpmod: apparently can't fire in start.bsp? (scar3crow)
+d darkplaces: (goodvsbad2) increase chase_stevie height to 2048 (yummyluv)
 d darkplaces: .skin loading for models (override skins - not exactly shaders, but adequate, missing replacements are nodraw, this allows q3 player models with optional accessories) (Electro)
 d darkplaces: 12bit color textures in 16bit mode?? (Tomaz)
 d darkplaces: TEXF_CLAMP needs to use GL_CLAMP_TO_EDGE (if not supported just use REPEAT as a fallback, not aware of any cards that lack this)
diff --git a/world.c b/world.c
index 3856598..5b028c4 100644 (file)
--- a/world.c
+++ b/world.c
@@ -610,6 +610,8 @@ trace_t SV_Move(const vec3_t start, const vec3_t mins, const vec3_t maxs, const
        VectorCopy(end, clip.end);
        VectorCopy(mins, clip.mins);
        VectorCopy(maxs, clip.maxs);
+       VectorCopy(mins, clip.hullmins);
+       VectorCopy(maxs, clip.hullmaxs);
        clip.type = type;
        clip.passedict = passedict;