2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 // current entity info
29 entity_t
*currententity
;
30 vec3_t modelorg
, base_modelorg
;
31 // modelorg is the viewpoint reletive to
32 // the currently rendering entity
33 vec3_t r_entorigin
; // the currently rendering entity in world
36 float entity_rotation
[3][3];
38 vec3_t r_worldmodelorg
;
42 typedef enum {touchessolid
, drawnode
, nodrawnode
} solidstate_t
;
44 #define MAX_BMODEL_VERTS 500 // 6K
45 #define MAX_BMODEL_EDGES 1000 // 12K
47 static mvertex_t
*pbverts
;
48 static bedge_t
*pbedges
;
49 static int numbverts
, numbedges
;
51 static mvertex_t
*pfrontenter
, *pfrontexit
;
53 static qboolean makeclippededge
;
56 //===========================================================================
63 void R_EntityRotate (vec3_t vec
)
67 VectorCopy (vec
, tvec
);
68 vec
[0] = DotProduct (entity_rotation
[0], tvec
);
69 vec
[1] = DotProduct (entity_rotation
[1], tvec
);
70 vec
[2] = DotProduct (entity_rotation
[2], tvec
);
79 void R_RotateBmodel (void)
81 float angle
, s
, c
, temp1
[3][3], temp2
[3][3], temp3
[3][3];
83 // TODO: should use a look-up table
84 // TODO: should really be stored with the entity instead of being reconstructed
85 // TODO: could cache lazily, stored in the entity
86 // TODO: share work with R_SetUpAliasTransform
89 angle
= currententity
->angles
[YAW
];
90 angle
= angle
* M_PI
*2 / 360;
106 angle
= currententity
->angles
[PITCH
];
107 angle
= angle
* M_PI
*2 / 360;
121 R_ConcatRotations (temp2
, temp1
, temp3
);
124 angle
= currententity
->angles
[ROLL
];
125 angle
= angle
* M_PI
*2 / 360;
139 R_ConcatRotations (temp1
, temp3
, entity_rotation
);
142 // rotate modelorg and the transformation matrix
144 R_EntityRotate (modelorg
);
145 R_EntityRotate (vpn
);
146 R_EntityRotate (vright
);
147 R_EntityRotate (vup
);
149 R_TransformFrustum ();
158 void R_RecursiveClipBPoly (bedge_t
*pedges
, mnode_t
*pnode
, msurface_t
*psurf
)
160 bedge_t
*psideedges
[2], *pnextedge
, *ptedge
;
161 int i
, side
, lastside
;
162 float dist
, frac
, lastdist
;
163 mplane_t
*splitplane
, tplane
;
164 mvertex_t
*pvert
, *plastvert
, *ptvert
;
167 psideedges
[0] = psideedges
[1] = NULL
;
169 makeclippededge
= false;
171 // transform the BSP plane into model space
172 // FIXME: cache these?
173 splitplane
= pnode
->plane
;
174 tplane
.dist
= splitplane
->dist
-
175 DotProduct(r_entorigin
, splitplane
->normal
);
176 tplane
.normal
[0] = DotProduct (entity_rotation
[0], splitplane
->normal
);
177 tplane
.normal
[1] = DotProduct (entity_rotation
[1], splitplane
->normal
);
178 tplane
.normal
[2] = DotProduct (entity_rotation
[2], splitplane
->normal
);
180 // clip edges to BSP plane
181 for ( ; pedges
; pedges
= pnextedge
)
183 pnextedge
= pedges
->pnext
;
185 // set the status for the last point as the previous point
186 // FIXME: cache this stuff somehow?
187 plastvert
= pedges
->v
[0];
188 lastdist
= DotProduct (plastvert
->position
, tplane
.normal
) -
196 pvert
= pedges
->v
[1];
198 dist
= DotProduct (pvert
->position
, tplane
.normal
) - tplane
.dist
;
205 if (side
!= lastside
)
208 if (numbverts
>= MAX_BMODEL_VERTS
)
211 // generate the clipped vertex
212 frac
= lastdist
/ (lastdist
- dist
);
213 ptvert
= &pbverts
[numbverts
++];
214 ptvert
->position
[0] = plastvert
->position
[0] +
215 frac
* (pvert
->position
[0] -
216 plastvert
->position
[0]);
217 ptvert
->position
[1] = plastvert
->position
[1] +
218 frac
* (pvert
->position
[1] -
219 plastvert
->position
[1]);
220 ptvert
->position
[2] = plastvert
->position
[2] +
221 frac
* (pvert
->position
[2] -
222 plastvert
->position
[2]);
224 // split into two edges, one on each side, and remember entering
225 // and exiting points
226 // FIXME: share the clip edge by having a winding direction flag?
227 if (numbedges
>= (MAX_BMODEL_EDGES
- 1))
229 Con_Printf ("Out of edges for bmodel\n");
233 ptedge
= &pbedges
[numbedges
];
234 ptedge
->pnext
= psideedges
[lastside
];
235 psideedges
[lastside
] = ptedge
;
236 ptedge
->v
[0] = plastvert
;
237 ptedge
->v
[1] = ptvert
;
239 ptedge
= &pbedges
[numbedges
+ 1];
240 ptedge
->pnext
= psideedges
[side
];
241 psideedges
[side
] = ptedge
;
242 ptedge
->v
[0] = ptvert
;
243 ptedge
->v
[1] = pvert
;
249 // entering for front, exiting for back
250 pfrontenter
= ptvert
;
251 makeclippededge
= true;
256 makeclippededge
= true;
261 // add the edge to the appropriate side
262 pedges
->pnext
= psideedges
[side
];
263 psideedges
[side
] = pedges
;
267 // if anything was clipped, reconstitute and add the edges along the clip
268 // plane to both sides (but in opposite directions)
271 if (numbedges
>= (MAX_BMODEL_EDGES
- 2))
273 Con_Printf ("Out of edges for bmodel\n");
277 ptedge
= &pbedges
[numbedges
];
278 ptedge
->pnext
= psideedges
[0];
279 psideedges
[0] = ptedge
;
280 ptedge
->v
[0] = pfrontexit
;
281 ptedge
->v
[1] = pfrontenter
;
283 ptedge
= &pbedges
[numbedges
+ 1];
284 ptedge
->pnext
= psideedges
[1];
285 psideedges
[1] = ptedge
;
286 ptedge
->v
[0] = pfrontenter
;
287 ptedge
->v
[1] = pfrontexit
;
292 // draw or recurse further
293 for (i
=0 ; i
<2 ; i
++)
297 // draw if we've reached a non-solid leaf, done if all that's left is a
298 // solid leaf, and continue down the tree if it's not a leaf
299 pn
= pnode
->children
[i
];
301 // we're done with this branch if the node or leaf isn't in the PVS
302 if (pn
->visframe
== r_visframecount
)
304 if (pn
->contents
< 0)
306 if (pn
->contents
!= CONTENTS_SOLID
)
308 r_currentbkey
= ((mleaf_t
*)pn
)->key
;
309 R_RenderBmodelFace (psideedges
[i
], psurf
);
314 R_RecursiveClipBPoly (psideedges
[i
], pnode
->children
[i
],
325 R_DrawSolidClippedSubmodelPolygons
328 void R_DrawSolidClippedSubmodelPolygons (model_t
*pmodel
)
335 mvertex_t bverts
[MAX_BMODEL_VERTS
];
336 bedge_t bedges
[MAX_BMODEL_EDGES
], *pbedge
;
337 medge_t
*pedge
, *pedges
;
339 // FIXME: use bounding-box-based frustum clipping info?
341 psurf
= &pmodel
->surfaces
[pmodel
->firstmodelsurface
];
342 numsurfaces
= pmodel
->nummodelsurfaces
;
343 pedges
= pmodel
->edges
;
345 for (i
=0 ; i
<numsurfaces
; i
++, psurf
++)
347 // find which side of the node we are on
348 pplane
= psurf
->plane
;
350 dot
= DotProduct (modelorg
, pplane
->normal
) - pplane
->dist
;
353 if (((psurf
->flags
& SURF_PLANEBACK
) && (dot
< -BACKFACE_EPSILON
)) ||
354 (!(psurf
->flags
& SURF_PLANEBACK
) && (dot
> BACKFACE_EPSILON
)))
356 // FIXME: use bounding-box-based frustum clipping info?
358 // copy the edges to bedges, flipping if necessary so always
360 // FIXME: if edges and vertices get caches, these assignments must move
361 // outside the loop, and overflow checking must be done here
364 numbverts
= numbedges
= 0;
366 if (psurf
->numedges
> 0)
368 pbedge
= &bedges
[numbedges
];
369 numbedges
+= psurf
->numedges
;
371 for (j
=0 ; j
<psurf
->numedges
; j
++)
373 lindex
= pmodel
->surfedges
[psurf
->firstedge
+j
];
377 pedge
= &pedges
[lindex
];
378 pbedge
[j
].v
[0] = &r_pcurrentvertbase
[pedge
->v
[0]];
379 pbedge
[j
].v
[1] = &r_pcurrentvertbase
[pedge
->v
[1]];
384 pedge
= &pedges
[lindex
];
385 pbedge
[j
].v
[0] = &r_pcurrentvertbase
[pedge
->v
[1]];
386 pbedge
[j
].v
[1] = &r_pcurrentvertbase
[pedge
->v
[0]];
389 pbedge
[j
].pnext
= &pbedge
[j
+1];
392 pbedge
[j
-1].pnext
= NULL
; // mark end of edges
394 R_RecursiveClipBPoly (pbedge
, currententity
->topnode
, psurf
);
398 Sys_Error ("no edges in bmodel");
407 R_DrawSubmodelPolygons
410 void R_DrawSubmodelPolygons (model_t
*pmodel
, int clipflags
)
418 // FIXME: use bounding-box-based frustum clipping info?
420 psurf
= &pmodel
->surfaces
[pmodel
->firstmodelsurface
];
421 numsurfaces
= pmodel
->nummodelsurfaces
;
423 for (i
=0 ; i
<numsurfaces
; i
++, psurf
++)
425 // find which side of the node we are on
426 pplane
= psurf
->plane
;
428 dot
= DotProduct (modelorg
, pplane
->normal
) - pplane
->dist
;
431 if (((psurf
->flags
& SURF_PLANEBACK
) && (dot
< -BACKFACE_EPSILON
)) ||
432 (!(psurf
->flags
& SURF_PLANEBACK
) && (dot
> BACKFACE_EPSILON
)))
434 r_currentkey
= ((mleaf_t
*)currententity
->topnode
)->key
;
436 // FIXME: use bounding-box-based frustum clipping info?
437 R_RenderFace (psurf
, clipflags
);
448 void R_RecursiveWorldNode (mnode_t
*node
, int clipflags
)
450 int i
, c
, side
, *pindex
;
451 vec3_t acceptpt
, rejectpt
;
453 msurface_t
*surf
, **mark
;
457 if (node
->contents
== CONTENTS_SOLID
)
460 if (node
->visframe
!= r_visframecount
)
463 // cull the clipping planes if not trivial accept
464 // FIXME: the compiler is doing a lousy job of optimizing here; it could be
465 // twice as fast in ASM
468 for (i
=0 ; i
<4 ; i
++)
470 if (! (clipflags
& (1<<i
)) )
471 continue; // don't need to clip against it
473 // generate accept and reject points
474 // FIXME: do with fast look-ups or integer tests based on the sign bit
475 // of the floating point values
477 pindex
= pfrustum_indexes
[i
];
479 rejectpt
[0] = (float)node
->minmaxs
[pindex
[0]];
480 rejectpt
[1] = (float)node
->minmaxs
[pindex
[1]];
481 rejectpt
[2] = (float)node
->minmaxs
[pindex
[2]];
483 d
= DotProduct (rejectpt
, view_clipplanes
[i
].normal
);
484 d
-= view_clipplanes
[i
].dist
;
489 acceptpt
[0] = (float)node
->minmaxs
[pindex
[3+0]];
490 acceptpt
[1] = (float)node
->minmaxs
[pindex
[3+1]];
491 acceptpt
[2] = (float)node
->minmaxs
[pindex
[3+2]];
493 d
= DotProduct (acceptpt
, view_clipplanes
[i
].normal
);
494 d
-= view_clipplanes
[i
].dist
;
497 clipflags
&= ~(1<<i
); // node is entirely on screen
501 // if a leaf node, draw stuff
502 if (node
->contents
< 0)
504 pleaf
= (mleaf_t
*)node
;
506 mark
= pleaf
->firstmarksurface
;
507 c
= pleaf
->nummarksurfaces
;
513 (*mark
)->visframe
= r_framecount
;
518 // deal with model fragments in this leaf
521 R_StoreEfrags (&pleaf
->efrags
);
524 pleaf
->key
= r_currentkey
;
525 r_currentkey
++; // all bmodels in a leaf share the same key
529 // node is just a decision point, so go down the apropriate sides
531 // find which side of the node we are on
537 dot
= modelorg
[0] - plane
->dist
;
540 dot
= modelorg
[1] - plane
->dist
;
543 dot
= modelorg
[2] - plane
->dist
;
546 dot
= DotProduct (modelorg
, plane
->normal
) - plane
->dist
;
555 // recurse down the children, front side first
556 R_RecursiveWorldNode (node
->children
[side
], clipflags
);
559 c
= node
->numsurfaces
;
563 surf
= cl
.worldmodel
->surfaces
+ node
->firstsurface
;
565 if (dot
< -BACKFACE_EPSILON
)
569 if ((surf
->flags
& SURF_PLANEBACK
) &&
570 (surf
->visframe
== r_framecount
))
574 if (r_worldpolysbacktofront
)
576 if (numbtofpolys
< MAX_BTOFPOLYS
)
578 pbtofpolys
[numbtofpolys
].clipflags
=
580 pbtofpolys
[numbtofpolys
].psurf
= surf
;
586 R_RenderPoly (surf
, clipflags
);
591 R_RenderFace (surf
, clipflags
);
598 else if (dot
> BACKFACE_EPSILON
)
602 if (!(surf
->flags
& SURF_PLANEBACK
) &&
603 (surf
->visframe
== r_framecount
))
607 if (r_worldpolysbacktofront
)
609 if (numbtofpolys
< MAX_BTOFPOLYS
)
611 pbtofpolys
[numbtofpolys
].clipflags
=
613 pbtofpolys
[numbtofpolys
].psurf
= surf
;
619 R_RenderPoly (surf
, clipflags
);
624 R_RenderFace (surf
, clipflags
);
632 // all surfaces on the same node share the same sequence number
636 // recurse down the back side
637 R_RecursiveWorldNode (node
->children
[!side
], clipflags
);
648 void R_RenderWorld (void)
652 btofpoly_t btofpolys
[MAX_BTOFPOLYS
];
654 pbtofpolys
= btofpolys
;
656 currententity
= &cl_entities
[0];
657 VectorCopy (r_origin
, modelorg
);
658 clmodel
= currententity
->model
;
659 r_pcurrentvertbase
= clmodel
->vertexes
;
661 R_RecursiveWorldNode (clmodel
->nodes
, 15);
663 // if the driver wants the polygons back to front, play the visible ones back
665 if (r_worldpolysbacktofront
)
667 for (i
=numbtofpolys
-1 ; i
>=0 ; i
--)
669 R_RenderPoly (btofpolys
[i
].psurf
, btofpolys
[i
].clipflags
);