ref_soft: submodel drawing

This commit is contained in:
mittorn 2019-03-23 13:49:55 +07:00
parent 5fc39662ec
commit 58429bbc79
4 changed files with 489 additions and 28 deletions

294
r_bsp.c
View File

@ -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 ; i<numsurfaces ; i++, psurf++)
{
// find which side of the node we are on
pplane = psurf->plane;
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 ; j<psurf->numedges ; 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 ; i<numsurfaces ; i++, psurf++)
{
// find which side of the node we are on
pplane = psurf->plane;
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;

View File

@ -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

212
r_main.c
View File

@ -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<<i);
}
return clipflags;
}
/*
===================
R_FindTopNode
===================
*/
mnode_t *R_FindTopnode (vec3_t mins, vec3_t maxs)
{
mplane_t *splitplane;
int sides;
mnode_t *node;
node = WORLDMODEL->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 ; i<r_newrefdef.num_entities ; i++)
for( i = 0; i < tr.draw_list->num_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 ; k<r_refdef2.numDlights ; k++)
{
R_MarkLights (&r_refdef2.dlights[k], 1<<k,
clmodel->nodes + 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();

View File

@ -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;