From: havoc Date: Sat, 23 Aug 2003 02:17:04 +0000 (+0000) Subject: q3bsp is working, but no curves yet, and no realtime lighting support X-Git-Tag: xonotic-v0.1.0preview~6428 X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=commitdiff_plain;h=5552ddb99b125f0164e80905d354608bd0a8c1a8 q3bsp is working, but no curves yet, and no realtime lighting support git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@3403 d7cf8633-e32d-0410-b094-e92efae38249 --- diff --git a/collision.c b/collision.c index 0e2cff89..4418bc66 100644 --- a/collision.c +++ b/collision.c @@ -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; diff --git a/collision.h b/collision.h index 3093f30b..49dde748 100644 --- a/collision.h +++ b/collision.h @@ -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); diff --git a/gl_rsurf.c b/gl_rsurf.c index 39f129b0..80f8096b 100644 --- a/gl_rsurf.c +++ b/gl_rsurf.c @@ -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; diff --git a/model_brush.c b/model_brush.c index 38e7d23a..77e9560d 100644 --- a/model_brush.c +++ b/model_brush.c @@ -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); diff --git a/model_shared.h b/model_shared.h index 1d6b78e5..6e6605ff 100644 --- a/model_shared.h +++ b/model_shared.h @@ -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; diff --git a/r_light.c b/r_light.c index 6a49a87f..273c3dc1 100644 --- 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); } diff --git a/r_shadow.c b/r_shadow.c index 6cbf5784..320ce23e 100644 --- a/r_shadow.c +++ b/r_shadow.c @@ -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 fbda9665..0caffb7c 100644 --- 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 @@ -24,12 +22,13 @@ 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 @@ -49,8 +47,11 @@ 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) @@ -270,6 +272,7 @@ ? 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 38565987..5b028c4d 100644 --- 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;