diff --git a/r_bsp.c b/r_bsp.c index 4f1c49ef..a27a98b1 100644 --- a/r_bsp.c +++ b/r_bsp.c @@ -143,7 +143,7 @@ void R_RotateBmodel (void) R_TransformFrustum (); } - +#if 1 /* ================ @@ -316,7 +316,297 @@ void R_RecursiveClipBPoly (bedge_t *pedges, mnode_t *pnode, msurface_t *psurf) } } +#else +/* +================ +R_RecursiveClipBPoly +================ +*/ +void R_RecursiveClipBPoly (bedge_t *pedges, mnode_t *pnode, msurface_t *psurf) +{ + bedge_t *psideedges[2], *pnextedge, *ptedge; + int i, side, lastside; + float dist, frac, lastdist; + mplane_t *splitplane, tplane; + mvertex_t *pvert, *plastvert, *ptvert; + mnode_t *pn; + + psideedges[0] = psideedges[1] = NULL; + + makeclippededge = false; + +// transform the BSP plane into model space +// FIXME: cache these? + splitplane = pnode->plane; + tplane.dist = splitplane->dist - + DotProduct(r_entorigin, splitplane->normal); + tplane.normal[0] = DotProduct (entity_rotation[0], splitplane->normal); + tplane.normal[1] = DotProduct (entity_rotation[1], splitplane->normal); + tplane.normal[2] = DotProduct (entity_rotation[2], splitplane->normal); + +// clip edges to BSP plane + for ( ; pedges ; pedges = pnextedge) + { + pnextedge = pedges->pnext; + + // set the status for the last point as the previous point + // FIXME: cache this stuff somehow? + plastvert = pedges->v[0]; + lastdist = DotProduct (plastvert->position, tplane.normal) - + tplane.dist; + + if (lastdist > 0) + lastside = 0; + else + lastside = 1; + + pvert = pedges->v[1]; + + dist = DotProduct (pvert->position, tplane.normal) - tplane.dist; + + if (dist > 0) + side = 0; + else + side = 1; + + if (side != lastside) + { + // clipped + if (numbverts >= MAX_BMODEL_VERTS) + return; + + // generate the clipped vertex + frac = lastdist / (lastdist - dist); + ptvert = &pbverts[numbverts++]; + ptvert->position[0] = plastvert->position[0] + + frac * (pvert->position[0] - + plastvert->position[0]); + ptvert->position[1] = plastvert->position[1] + + frac * (pvert->position[1] - + plastvert->position[1]); + ptvert->position[2] = plastvert->position[2] + + frac * (pvert->position[2] - + plastvert->position[2]); + // split into two edges, one on each side, and remember entering + // and exiting points + // FIXME: share the clip edge by having a winding direction flag? + if (numbedges >= (MAX_BMODEL_EDGES - 1)) + { + gEngfuncs.Con_Printf ("Out of edges for bmodel\n"); + return; + } + + ptedge = &pbedges[numbedges]; + ptedge->pnext = psideedges[lastside]; + psideedges[lastside] = ptedge; + ptedge->v[0] = plastvert; + ptedge->v[1] = ptvert; + + ptedge = &pbedges[numbedges + 1]; + ptedge->pnext = psideedges[side]; + psideedges[side] = ptedge; + ptedge->v[0] = ptvert; + ptedge->v[1] = pvert; + + numbedges += 2; + + if (side == 0) + { + // entering for front, exiting for back + pfrontenter = ptvert; + makeclippededge = true; + } + else + { + pfrontexit = ptvert; + makeclippededge = true; + } + } + else + { + // add the edge to the appropriate side + pedges->pnext = psideedges[side]; + psideedges[side] = pedges; + } + } + +// if anything was clipped, reconstitute and add the edges along the clip +// plane to both sides (but in opposite directions) + if (makeclippededge) + { + if (numbedges >= (MAX_BMODEL_EDGES - 2)) + { + gEngfuncs.Con_Printf ("Out of edges for bmodel\n"); + return; + } + + ptedge = &pbedges[numbedges]; + ptedge->pnext = psideedges[0]; + psideedges[0] = ptedge; + ptedge->v[0] = pfrontexit; + ptedge->v[1] = pfrontenter; + + ptedge = &pbedges[numbedges + 1]; + ptedge->pnext = psideedges[1]; + psideedges[1] = ptedge; + ptedge->v[0] = pfrontenter; + ptedge->v[1] = pfrontexit; + + numbedges += 2; + } + +// draw or recurse further + for (i=0 ; i<2 ; i++) + { + if (psideedges[i]) + { + // draw if we've reached a non-solid leaf, done if all that's left is a + // solid leaf, and continue down the tree if it's not a leaf + pn = pnode->children[i]; + + // we're done with this branch if the node or leaf isn't in the PVS + if (pn->visframe == r_visframecount) + { + if (pn->contents < 0) + { + if (pn->contents != CONTENTS_SOLID) + { + r_currentbkey = ((mleaf_t *)pn)->cluster; + R_RenderBmodelFace (psideedges[i], psurf); + } + } + else + { + R_RecursiveClipBPoly (psideedges[i], pnode->children[i], + psurf); + } + } + } + } +} +#endif +#if 0 +/* +================ +R_DrawSolidClippedSubmodelPolygons +================ +*/ +void R_DrawSolidClippedSubmodelPolygons (model_t *pmodel) +{ + int i, j, lindex; + vec_t dot; + msurface_t *psurf; + int numsurfaces; + mplane_t *pplane; + mvertex_t bverts[MAX_BMODEL_VERTS]; + bedge_t bedges[MAX_BMODEL_EDGES], *pbedge; + medge_t *pedge, *pedges; + +// FIXME: use bounding-box-based frustum clipping info? + + psurf = &pmodel->surfaces[pmodel->firstmodelsurface]; + numsurfaces = pmodel->nummodelsurfaces; + pedges = pmodel->edges; + + for (i=0 ; iplane; + + dot = DotProduct (modelorg, pplane->normal) - pplane->dist; + + // draw the polygon + if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) || + (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) + { + // FIXME: use bounding-box-based frustum clipping info? + + // copy the edges to bedges, flipping if necessary so always + // clockwise winding + // FIXME: if edges and vertices get caches, these assignments must move + // outside the loop, and overflow checking must be done here + pbverts = bverts; + pbedges = bedges; + numbverts = numbedges = 0; + + if (psurf->numedges > 0) + { + pbedge = &bedges[numbedges]; + numbedges += psurf->numedges; + + for (j=0 ; jnumedges ; j++) + { + lindex = pmodel->surfedges[psurf->firstedge+j]; + + if (lindex > 0) + { + pedge = &pedges[lindex]; + pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[0]]; + pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[1]]; + } + else + { + lindex = -lindex; + pedge = &pedges[lindex]; + pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[1]]; + pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[0]]; + } + + pbedge[j].pnext = &pbedge[j+1]; + } + + pbedge[j-1].pnext = NULL; // mark end of edges + + R_RecursiveClipBPoly (pbedge, RI.currententity->topnode, psurf); + } + else + { + gEngfuncs.Host_Error ("no edges in bmodel"); + } + } + } +} + + +/* +================ +R_DrawSubmodelPolygons +================ +*/ +void R_DrawSubmodelPolygons (model_t *pmodel, int clipflags) +{ + int i; + vec_t dot; + msurface_t *psurf; + int numsurfaces; + mplane_t *pplane; + +// FIXME: use bounding-box-based frustum clipping info? + + psurf = &pmodel->surfaces[pmodel->firstmodelsurface]; + numsurfaces = pmodel->nummodelsurfaces; + + for (i=0 ; iplane; + + dot = DotProduct (modelorg, pplane->normal) - pplane->dist; + + // draw the polygon + if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) || + (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) + { + r_currentkey = ((mleaf_t *)RI.currententity->topnode)->cluster; + + // FIXME: use bounding-box-based frustum clipping info? + R_RenderFace (psurf, clipflags); + } + } +} + +#else /* ================ @@ -436,6 +726,8 @@ void R_DrawSubmodelPolygons (model_t *pmodel, int clipflags, mnode_t *topnode) } } +#endif + int c_drawnode; diff --git a/r_local.h b/r_local.h index 37d2eac3..d3e8320e 100644 --- a/r_local.h +++ b/r_local.h @@ -1235,6 +1235,9 @@ extern mvertex_t *r_pcurrentvertbase; extern int r_maxvalidedgeoffset; extern int r_currentkey; extern int r_currentbkey; +extern qboolean insubmodel; + +extern vec3_t r_entorigin; // // r_blitscreen.c diff --git a/r_main.c b/r_main.c index 94b05473..3c3310e0 100644 --- a/r_main.c +++ b/r_main.c @@ -1097,7 +1097,156 @@ void R_DrawEntitiesOnList( void ) //GL_CheckForErrors(); } -#if 0 +#if 1 +qboolean insubmodel; + + +/* +============= +R_BmodelCheckBBox +============= +*/ +int R_BmodelCheckBBox (float *minmaxs) +{ + int i, *pindex, clipflags; + vec3_t acceptpt, rejectpt; + float d; + + clipflags = 0; + + for (i=0 ; i<4 ; i++) + { + // generate accept and reject points + // FIXME: do with fast look-ups or integer tests based on the sign bit + // of the floating point values + + pindex = pfrustum_indexes[i]; + + rejectpt[0] = minmaxs[pindex[0]]; + rejectpt[1] = minmaxs[pindex[1]]; + rejectpt[2] = minmaxs[pindex[2]]; + + d = DotProduct (rejectpt, view_clipplanes[i].normal); + d -= view_clipplanes[i].dist; + + if (d <= 0) + return BMODEL_FULLY_CLIPPED; + + acceptpt[0] = minmaxs[pindex[3+0]]; + acceptpt[1] = minmaxs[pindex[3+1]]; + acceptpt[2] = minmaxs[pindex[3+2]]; + + d = DotProduct (acceptpt, view_clipplanes[i].normal); + d -= view_clipplanes[i].dist; + + if (d <= 0) + clipflags |= (1<nodes; + + while (1) + { + if (node->visframe != r_visframecount) + return NULL; // not visible at all + + if (node->contents < 0) + { + if (node->contents != CONTENTS_SOLID) + return node; // we've reached a non-solid leaf, so it's + // visible and not BSP clipped + return NULL; // in solid, so not visible + } + + splitplane = node->plane; + sides = BOX_ON_PLANE_SIDE (mins, maxs, splitplane); + + if (sides == 3) + return node; // this is the splitter + + // not split yet; recurse down the contacted side + if (sides & 1) + node = node->children[0]; + else + node = node->children[1]; + } +} + + +/* +============= +RotatedBBox + +Returns an axially aligned box that contains the input box at the given rotation +============= +*/ +void RotatedBBox (vec3_t mins, vec3_t maxs, vec3_t angles, vec3_t tmins, vec3_t tmaxs) +{ + vec3_t tmp, v; + int i, j; + vec3_t forward, right, up; + + if (!angles[0] && !angles[1] && !angles[2]) + { + VectorCopy (mins, tmins); + VectorCopy (maxs, tmaxs); + return; + } + + for (i=0 ; i<3 ; i++) + { + tmins[i] = 99999; + tmaxs[i] = -99999; + } + + AngleVectors (angles, forward, right, up); + + for ( i = 0; i < 8; i++ ) + { + if ( i & 1 ) + tmp[0] = mins[0]; + else + tmp[0] = maxs[0]; + + if ( i & 2 ) + tmp[1] = mins[1]; + else + tmp[1] = maxs[1]; + + if ( i & 4 ) + tmp[2] = mins[2]; + else + tmp[2] = maxs[2]; + + + VectorScale (forward, tmp[0], v); + VectorMA (v, -tmp[1], right, v); + VectorMA (v, tmp[2], up, v); + + for (j=0 ; j<3 ; j++) + { + if (v[j] < tmins[j]) + tmins[j] = v[j]; + if (v[j] > tmaxs[j]) + tmaxs[j] = v[j]; + } + } +} + /* ============= @@ -1117,26 +1266,26 @@ void R_DrawBEntitiesOnList (void) VectorCopy (modelorg, oldorigin); insubmodel = true; - r_dlightframecount = r_framecount; + //r_dlightframecount = r_framecount; - for (i=0 ; inum_solid_entities && !RI.onlyClientDraw; i++ ) { - currententity = &r_newrefdef.entities[i]; - currentmodel = currententity->model; - if (!currentmodel) + RI.currententity = tr.draw_list->solid_entities[i]; + RI.currentmodel = RI.currententity->model; + if (!RI.currentmodel) continue; - if (currentmodel->nummodelsurfaces == 0) + if (RI.currentmodel->nummodelsurfaces == 0) continue; // clip brush only - if ( currententity->flags & RF_BEAM ) - continue; - if (currentmodel->type != mod_brush) + //if ( currententity->flags & RF_BEAM ) + //continue; + if (RI.currentmodel->type != mod_brush) continue; // see if the bounding box lets us trivially reject, also sets // trivial accept status - RotatedBBox (currentmodel->mins, currentmodel->maxs, - currententity->angles, mins, maxs); - VectorAdd (mins, currententity->origin, minmaxs); - VectorAdd (maxs, currententity->origin, (minmaxs+3)); + RotatedBBox (RI.currentmodel->mins, RI.currentmodel->maxs, + RI.currententity->angles, mins, maxs); + VectorAdd (mins, RI.currententity->origin, minmaxs); + VectorAdd (maxs, RI.currententity->origin, (minmaxs+3)); clipflags = R_BmodelCheckBBox (minmaxs); if (clipflags == BMODEL_FULLY_CLIPPED) @@ -1146,30 +1295,47 @@ void R_DrawBEntitiesOnList (void) if (!topnode) continue; // no part in a visible leaf - VectorCopy (currententity->origin, r_entorigin); + VectorCopy (RI.currententity->origin, r_entorigin); VectorSubtract (r_origin, r_entorigin, modelorg); - - r_pcurrentvertbase = currentmodel->vertexes; + //VectorSubtract (r_origin, RI.currententity->origin, modelorg); + r_pcurrentvertbase = RI.currentmodel->vertexes; // FIXME: stop transforming twice R_RotateBmodel (); // calculate dynamic lighting for bmodel - R_PushDlights (currentmodel); + // this will reset RI.currententity, do we need this? + //R_PushDlights (); + /*if (clmodel->firstmodelsurface != 0) + { + for (k=0 ; knodes + clmodel->firstnode); + } + }*/ - if (topnode->contents == CONTENTS_NODE) + // RI.currentmodel = tr.draw_list->solid_entities[i]->model; + // RI.currententity = tr.draw_list->solid_entities[i]; + RI.currententity->topnode = topnode; +//ASSERT( RI.currentmodel == tr.draw_list->solid_entities[i]->model ); + if (topnode->contents >= 0) { // not a leaf; has to be clipped to the world BSP r_clipflags = clipflags; - R_DrawSolidClippedSubmodelPolygons (currentmodel, topnode); + R_DrawSolidClippedSubmodelPolygons (RI.currentmodel, topnode); } else { // falls entirely in one leaf, so we just put all the // edges in the edge list and let 1/z sorting handle // drawing order - R_DrawSubmodelPolygons (currentmodel, clipflags, topnode); + //ASSERT( RI.currentmodel == tr.draw_list->solid_entities[i]->model ); + + + R_DrawSubmodelPolygons (RI.currentmodel, clipflags, topnode); } + RI.currententity->topnode = NULL; // put back world rotation and frustum clipping // FIXME: R_RotateBmodel should just work off base_vxx @@ -1227,7 +1393,7 @@ void R_EdgeDrawing (void) R_RenderWorld (); // move brushes to separate list to merge with edges? - //R_DrawBEntitiesOnList (); + R_DrawBEntitiesOnList (); // display all edges R_ScanEdges (); @@ -1372,7 +1538,7 @@ void R_RenderScene( void ) // begin a new frame tr.framecount++; -// R_PushDlights(); + R_PushDlights(); R_SetupFrustum(); R_SetupFrame(); diff --git a/r_rast.c b/r_rast.c index 62ad160f..9b6b2b25 100644 --- a/r_rast.c +++ b/r_rast.c @@ -600,7 +600,7 @@ void R_RenderFace (msurface_t *fa, int clipflags) r_pedge = &pedges[lindex]; // if the edge is cached, we can just reuse the edge - //if (!insubmodel) + if (!insubmodel) { if (r_pedge->cachededgeoffset & FULLY_CLIPPED_CACHED) { @@ -644,7 +644,7 @@ void R_RenderFace (msurface_t *fa, int clipflags) lindex = -lindex; r_pedge = &pedges[lindex]; // if the edge is cached, we can just reuse the edge - //if (!insubmodel) + if (!insubmodel) { if (r_pedge->cachededgeoffset & FULLY_CLIPPED_CACHED) { @@ -715,7 +715,7 @@ void R_RenderFace (msurface_t *fa, int clipflags) surface_p->msurf = fa; surface_p->nearzi = r_nearzi; surface_p->flags = fa->flags; - surface_p->insubmodel = false; + surface_p->insubmodel = insubmodel; surface_p->spanstate = 0; surface_p->entity = RI.currententity; surface_p->key = r_currentkey++; @@ -836,7 +836,7 @@ void R_RenderBmodelFace (bedge_t *pedges, msurface_t *psurf) surface_p->msurf = psurf; surface_p->nearzi = r_nearzi; surface_p->flags = psurf->flags; - surface_p->insubmodel = false; //true; + surface_p->insubmodel = true; surface_p->spanstate = 0; surface_p->entity = RI.currententity; surface_p->key = r_currentbkey;