xash3d-fwgs/ref_gl/gl_refrag.c

209 lines
4.2 KiB
C

/*
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 "common.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;
}
}
}