You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
207 lines
4.2 KiB
207 lines
4.2 KiB
/* |
|
gl_refrag.c - store entity fragments |
|
Copyright (C) 2010 Uncle Mike |
|
|
|
This program is free software: you can redistribute it and/or modify |
|
it under the terms of the GNU General Public License as published by |
|
the Free Software Foundation, either version 3 of the License, or |
|
(at your option) any later version. |
|
|
|
This program is distributed in the hope that it will be useful, |
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
GNU General Public License for more details. |
|
*/ |
|
|
|
#include "gl_local.h" |
|
#include "entity_types.h" |
|
#include "studio.h" |
|
#include "world.h" // BOX_ON_PLANE_SIDE |
|
|
|
/* |
|
=============================================================================== |
|
|
|
ENTITY FRAGMENT FUNCTIONS |
|
|
|
=============================================================================== |
|
*/ |
|
|
|
static efrag_t **lastlink; |
|
static mnode_t *r_pefragtopnode; |
|
static vec3_t r_emins, r_emaxs; |
|
static cl_entity_t *r_addent; |
|
|
|
/* |
|
================ |
|
R_RemoveEfrags |
|
|
|
Call when removing an object from the world or moving it to another position |
|
================ |
|
*/ |
|
void R_RemoveEfrags( cl_entity_t *ent ) |
|
{ |
|
efrag_t *ef, *old, *walk, **prev; |
|
|
|
ef = ent->efrag; |
|
|
|
while( ef ) |
|
{ |
|
prev = &ef->leaf->efrags; |
|
while( 1 ) |
|
{ |
|
walk = *prev; |
|
if( !walk ) break; |
|
|
|
if( walk == ef ) |
|
{ |
|
// remove this fragment |
|
*prev = ef->leafnext; |
|
break; |
|
} |
|
else prev = &walk->leafnext; |
|
} |
|
|
|
old = ef; |
|
ef = ef->entnext; |
|
|
|
// put it on the free list |
|
old->entnext = gEngfuncs.GetEfragsFreeList(); |
|
gEngfuncs.SetEfragsFreeList( old ); |
|
} |
|
ent->efrag = NULL; |
|
} |
|
|
|
/* |
|
=================== |
|
R_SplitEntityOnNode |
|
=================== |
|
*/ |
|
static void R_SplitEntityOnNode( mnode_t *node ) |
|
{ |
|
efrag_t *ef; |
|
mleaf_t *leaf; |
|
int sides; |
|
|
|
if( node->contents == CONTENTS_SOLID ) |
|
return; |
|
|
|
// add an efrag if the node is a leaf |
|
if( node->contents < 0 ) |
|
{ |
|
if( !r_pefragtopnode ) |
|
r_pefragtopnode = node; |
|
|
|
leaf = (mleaf_t *)node; |
|
|
|
// grab an efrag off the free list |
|
ef = gEngfuncs.GetEfragsFreeList(); |
|
if( !ef ) |
|
{ |
|
gEngfuncs.Con_Printf( S_ERROR "too many efrags!\n" ); |
|
return; // no free fragments... |
|
} |
|
|
|
gEngfuncs.SetEfragsFreeList( ef->entnext ); |
|
ef->entity = r_addent; |
|
|
|
// add the entity link |
|
*lastlink = ef; |
|
lastlink = &ef->entnext; |
|
ef->entnext = NULL; |
|
|
|
// set the leaf links |
|
ef->leaf = leaf; |
|
ef->leafnext = leaf->efrags; |
|
leaf->efrags = ef; |
|
return; |
|
} |
|
|
|
// NODE_MIXED |
|
sides = BOX_ON_PLANE_SIDE( r_emins, r_emaxs, node->plane ); |
|
|
|
if( sides == 3 ) |
|
{ |
|
// split on this plane |
|
// if this is the first splitter of this bmodel, remember it |
|
if( !r_pefragtopnode ) r_pefragtopnode = node; |
|
} |
|
|
|
// recurse down the contacted sides |
|
if( sides & 1 ) R_SplitEntityOnNode( node->children[0] ); |
|
if( sides & 2 ) R_SplitEntityOnNode( node->children[1] ); |
|
} |
|
|
|
/* |
|
=========== |
|
R_AddEfrags |
|
=========== |
|
*/ |
|
void R_AddEfrags( cl_entity_t *ent ) |
|
{ |
|
matrix3x4 transform; |
|
vec3_t outmins, outmaxs; |
|
int i; |
|
|
|
if( !ent->model ) |
|
return; |
|
|
|
r_addent = ent; |
|
lastlink = &ent->efrag; |
|
r_pefragtopnode = NULL; |
|
|
|
// handle entity rotation for right bbox expanding |
|
Matrix3x4_CreateFromEntity( transform, ent->angles, vec3_origin, 1.0f ); |
|
Matrix3x4_TransformAABB( transform, ent->model->mins, ent->model->maxs, outmins, outmaxs ); |
|
|
|
for( i = 0; i < 3; i++ ) |
|
{ |
|
r_emins[i] = ent->origin[i] + outmins[i]; |
|
r_emaxs[i] = ent->origin[i] + outmaxs[i]; |
|
} |
|
|
|
R_SplitEntityOnNode( WORLDMODEL->nodes ); |
|
ent->topnode = r_pefragtopnode; |
|
} |
|
|
|
/* |
|
================ |
|
R_StoreEfrags |
|
|
|
================ |
|
*/ |
|
void R_StoreEfrags( efrag_t **ppefrag, int framecount ) |
|
{ |
|
cl_entity_t *pent; |
|
model_t *clmodel; |
|
efrag_t *pefrag; |
|
|
|
while(( pefrag = *ppefrag ) != NULL ) |
|
{ |
|
pent = pefrag->entity; |
|
clmodel = pent->model; |
|
|
|
switch( clmodel->type ) |
|
{ |
|
case mod_alias: |
|
case mod_brush: |
|
case mod_studio: |
|
case mod_sprite: |
|
pent = pefrag->entity; |
|
|
|
if( pent->visframe != framecount ) |
|
{ |
|
if( gEngfuncs.CL_AddVisibleEntity( pent, ET_FRAGMENTED )) |
|
{ |
|
// mark that we've recorded this entity for this frame |
|
pent->curstate.messagenum = gpGlobals->parsecount; |
|
pent->visframe = framecount; |
|
} |
|
} |
|
|
|
ppefrag = &pefrag->leafnext; |
|
break; |
|
default: |
|
break; |
|
} |
|
} |
|
}
|
|
|