mirror of
https://github.com/DrBeef/JKXR.git
synced 2024-11-23 12:32:26 +00:00
324 lines
7.9 KiB
C++
324 lines
7.9 KiB
C++
|
/*
|
||
|
===========================================================================
|
||
|
Copyright (C) 1999 - 2005, Id Software, Inc.
|
||
|
Copyright (C) 2000 - 2013, Raven Software, Inc.
|
||
|
Copyright (C) 2001 - 2013, Activision, Inc.
|
||
|
Copyright (C) 2013 - 2015, OpenJK contributors
|
||
|
|
||
|
This file is part of the OpenJK source code.
|
||
|
|
||
|
OpenJK is free software; you can redistribute it and/or modify it
|
||
|
under the terms of the GNU General Public License version 2 as
|
||
|
published by the Free Software Foundation.
|
||
|
|
||
|
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.
|
||
|
|
||
|
You should have received a copy of the GNU General Public License
|
||
|
along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||
|
===========================================================================
|
||
|
*/
|
||
|
|
||
|
#include "tr_local.h"
|
||
|
|
||
|
#define MAX_VERTS_ON_DECAL_POLY 10
|
||
|
#define MAX_DECAL_POLYS 500
|
||
|
|
||
|
typedef struct decalPoly_s
|
||
|
{
|
||
|
int time;
|
||
|
int fadetime;
|
||
|
qhandle_t shader;
|
||
|
float color[4];
|
||
|
poly_t poly;
|
||
|
polyVert_t verts[MAX_VERTS_ON_DECAL_POLY];
|
||
|
} decalPoly_t;
|
||
|
|
||
|
enum
|
||
|
{
|
||
|
DECALPOLY_TYPE_NORMAL,
|
||
|
DECALPOLY_TYPE_FADE,
|
||
|
DECALPOLY_TYPE_MAX
|
||
|
};
|
||
|
|
||
|
#define DECAL_FADE_TIME 1000
|
||
|
|
||
|
decalPoly_t* RE_AllocDecal( int type );
|
||
|
|
||
|
static decalPoly_t re_decalPolys[DECALPOLY_TYPE_MAX][MAX_DECAL_POLYS];
|
||
|
|
||
|
static int re_decalPolyHead[DECALPOLY_TYPE_MAX];
|
||
|
static int re_decalPolyTotal[DECALPOLY_TYPE_MAX];
|
||
|
|
||
|
/*
|
||
|
===================
|
||
|
RE_ClearDecals
|
||
|
|
||
|
This is called to remove all decals from the world
|
||
|
===================
|
||
|
*/
|
||
|
void RE_ClearDecals( void ) {
|
||
|
memset( re_decalPolys, 0, sizeof(re_decalPolys) );
|
||
|
memset( re_decalPolyHead, 0, sizeof(re_decalPolyHead) );
|
||
|
memset( re_decalPolyTotal, 0, sizeof(re_decalPolyTotal) );
|
||
|
}
|
||
|
|
||
|
void R_InitDecals( void ) {
|
||
|
RE_ClearDecals();
|
||
|
}
|
||
|
|
||
|
void RE_FreeDecal( int type, int index ) {
|
||
|
if ( !re_decalPolys[type][index].time )
|
||
|
return;
|
||
|
|
||
|
if ( type == DECALPOLY_TYPE_NORMAL ) {
|
||
|
decalPoly_t* fade;
|
||
|
|
||
|
fade = RE_AllocDecal( DECALPOLY_TYPE_FADE );
|
||
|
|
||
|
memcpy( fade, &re_decalPolys[type][index], sizeof( decalPoly_t ) );
|
||
|
|
||
|
fade->time = tr.refdef.time;
|
||
|
fade->fadetime = tr.refdef.time + DECAL_FADE_TIME;
|
||
|
}
|
||
|
|
||
|
re_decalPolys[type][index].time = 0;
|
||
|
|
||
|
re_decalPolyTotal[type]--;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
===================
|
||
|
RE_AllocDecal
|
||
|
|
||
|
Will allways succeed, even if it requires freeing an old active mark
|
||
|
===================
|
||
|
*/
|
||
|
decalPoly_t* RE_AllocDecal( int type ) {
|
||
|
decalPoly_t *le;
|
||
|
|
||
|
// See if the cvar changed
|
||
|
if ( re_decalPolyTotal[type] > r_markcount->integer )
|
||
|
RE_ClearDecals();
|
||
|
|
||
|
le = &re_decalPolys[type][re_decalPolyHead[type]];
|
||
|
|
||
|
// If it has no time its the first occasion its been used
|
||
|
if ( le->time ) {
|
||
|
if ( le->time != tr.refdef.time ) {
|
||
|
int i = re_decalPolyHead[type];
|
||
|
|
||
|
// since we are killing one that existed before, make sure we
|
||
|
// kill all the other marks that belong to the group
|
||
|
do {
|
||
|
i++;
|
||
|
if ( i >= r_markcount->integer )
|
||
|
i = 0;
|
||
|
|
||
|
// Break out on the first one thats not part of the group
|
||
|
if ( re_decalPolys[type][i].time != le->time )
|
||
|
break;
|
||
|
|
||
|
RE_FreeDecal ( type, i );
|
||
|
} while ( i != re_decalPolyHead[type] );
|
||
|
|
||
|
RE_FreeDecal( type, re_decalPolyHead[type] );
|
||
|
}
|
||
|
else
|
||
|
RE_FreeDecal( type, re_decalPolyHead[type] );
|
||
|
}
|
||
|
|
||
|
memset( le, 0, sizeof(decalPoly_t) );
|
||
|
le->time = tr.refdef.time;
|
||
|
|
||
|
re_decalPolyTotal[type]++;
|
||
|
|
||
|
// Move on to the next decal poly and wrap around if need be
|
||
|
re_decalPolyHead[type]++;
|
||
|
if ( re_decalPolyHead[type] >= r_markcount->integer )
|
||
|
re_decalPolyHead[type] = 0;
|
||
|
|
||
|
return le;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
=================
|
||
|
RE_AddDecalToScene
|
||
|
|
||
|
origin should be a point within a unit of the plane
|
||
|
dir should be the plane normal
|
||
|
|
||
|
temporary marks will not be stored or randomly oriented, but immediately
|
||
|
passed to the renderer.
|
||
|
=================
|
||
|
*/
|
||
|
#define MAX_DECAL_FRAGMENTS 128
|
||
|
#define MAX_DECAL_POINTS 384
|
||
|
|
||
|
void RE_AddDecalToScene( qhandle_t decalShader, const vec3_t origin, const vec3_t dir, float orientation, float red, float green, float blue, float alpha, qboolean alphaFade, float radius, qboolean temporary )
|
||
|
{
|
||
|
matrix3_t axis;
|
||
|
float texCoordScale;
|
||
|
vec3_t originalPoints[4];
|
||
|
byte colors[4];
|
||
|
int i, j;
|
||
|
int numFragments;
|
||
|
markFragment_t markFragments[MAX_DECAL_FRAGMENTS], *mf;
|
||
|
vec3_t markPoints[MAX_DECAL_POINTS];
|
||
|
vec3_t projection;
|
||
|
|
||
|
assert(decalShader);
|
||
|
|
||
|
if ( r_markcount->integer <= 0 && !temporary )
|
||
|
return;
|
||
|
|
||
|
if ( radius <= 0 )
|
||
|
Com_Error( ERR_FATAL, "RE_AddDecalToScene: called with <= 0 radius" );
|
||
|
|
||
|
// create the texture axis
|
||
|
VectorNormalize2( dir, axis[0] );
|
||
|
PerpendicularVector( axis[1], axis[0] );
|
||
|
RotatePointAroundVector( axis[2], axis[0], axis[1], orientation );
|
||
|
CrossProduct( axis[0], axis[2], axis[1] );
|
||
|
|
||
|
texCoordScale = 0.5 * 1.0 / radius;
|
||
|
|
||
|
// create the full polygon
|
||
|
for ( i = 0 ; i < 3 ; i++ )
|
||
|
{
|
||
|
originalPoints[0][i] = origin[i] - radius * axis[1][i] - radius * axis[2][i];
|
||
|
originalPoints[1][i] = origin[i] + radius * axis[1][i] - radius * axis[2][i];
|
||
|
originalPoints[2][i] = origin[i] + radius * axis[1][i] + radius * axis[2][i];
|
||
|
originalPoints[3][i] = origin[i] - radius * axis[1][i] + radius * axis[2][i];
|
||
|
}
|
||
|
|
||
|
// get the fragments
|
||
|
VectorScale( dir, -20, projection );
|
||
|
numFragments = R_MarkFragments( 4, (const vec3_t*)originalPoints,
|
||
|
projection, MAX_DECAL_POINTS, markPoints[0],
|
||
|
MAX_DECAL_FRAGMENTS, markFragments );
|
||
|
|
||
|
colors[0] = red * 255;
|
||
|
colors[1] = green * 255;
|
||
|
colors[2] = blue * 255;
|
||
|
colors[3] = alpha * 255;
|
||
|
|
||
|
for ( i = 0, mf = markFragments ; i < numFragments ; i++, mf++ )
|
||
|
{
|
||
|
polyVert_t *v;
|
||
|
polyVert_t verts[MAX_VERTS_ON_DECAL_POLY];
|
||
|
decalPoly_t *decal;
|
||
|
|
||
|
// we have an upper limit on the complexity of polygons
|
||
|
// that we store persistantly
|
||
|
if ( mf->numPoints > MAX_VERTS_ON_DECAL_POLY )
|
||
|
mf->numPoints = MAX_VERTS_ON_DECAL_POLY;
|
||
|
|
||
|
for ( j = 0, v = verts ; j < mf->numPoints ; j++, v++ )
|
||
|
{
|
||
|
vec3_t delta;
|
||
|
|
||
|
VectorCopy( markPoints[mf->firstPoint + j], v->xyz );
|
||
|
|
||
|
VectorSubtract( v->xyz, origin, delta );
|
||
|
v->st[0] = 0.5 + DotProduct( delta, axis[1] ) * texCoordScale;
|
||
|
v->st[1] = 0.5 + DotProduct( delta, axis[2] ) * texCoordScale;
|
||
|
|
||
|
for ( int k=0; k<4; k++ )
|
||
|
v->modulate[k] = colors[k];
|
||
|
}
|
||
|
|
||
|
// if it is a temporary (shadow) mark, add it immediately and forget about it
|
||
|
if ( temporary )
|
||
|
{
|
||
|
RE_AddPolyToScene( decalShader, mf->numPoints, verts, 1 );
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// otherwise save it persistantly
|
||
|
decal = RE_AllocDecal( DECALPOLY_TYPE_NORMAL );
|
||
|
decal->time = tr.refdef.time;
|
||
|
decal->shader = decalShader;
|
||
|
decal->poly.numVerts = mf->numPoints;
|
||
|
decal->color[0] = red;
|
||
|
decal->color[1] = green;
|
||
|
decal->color[2] = blue;
|
||
|
decal->color[3] = alpha;
|
||
|
memcpy( decal->verts, verts, mf->numPoints * sizeof( verts[0] ) );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
===============
|
||
|
R_AddDecals
|
||
|
===============
|
||
|
*/
|
||
|
void R_AddDecals( void )
|
||
|
{
|
||
|
int decalPoly;
|
||
|
int type;
|
||
|
static int lastMarkCount = -1;
|
||
|
|
||
|
if ( r_markcount->integer != lastMarkCount ) {
|
||
|
if ( lastMarkCount != -1 )
|
||
|
RE_ClearDecals();
|
||
|
|
||
|
lastMarkCount = r_markcount->integer;
|
||
|
}
|
||
|
|
||
|
if ( r_markcount->integer <= 0 )
|
||
|
return;
|
||
|
|
||
|
for ( type = DECALPOLY_TYPE_NORMAL; type < DECALPOLY_TYPE_MAX; type ++ )
|
||
|
{
|
||
|
decalPoly = re_decalPolyHead[type];
|
||
|
|
||
|
do
|
||
|
{
|
||
|
decalPoly_t* p = &re_decalPolys[type][decalPoly];
|
||
|
|
||
|
if ( p->time )
|
||
|
{
|
||
|
if ( p->fadetime )
|
||
|
{
|
||
|
int t;
|
||
|
|
||
|
// fade all marks out with time
|
||
|
t = tr.refdef.time - p->time;
|
||
|
if ( t < DECAL_FADE_TIME )
|
||
|
{
|
||
|
float fade;
|
||
|
int j;
|
||
|
|
||
|
fade = 255.0f * (1.0f - ((float)t / DECAL_FADE_TIME));
|
||
|
|
||
|
for ( j = 0 ; j < p->poly.numVerts ; j++ )
|
||
|
{
|
||
|
p->verts[j].modulate[3] = fade;
|
||
|
}
|
||
|
|
||
|
RE_AddPolyToScene( p->shader, p->poly.numVerts, p->verts, 1 );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
RE_FreeDecal ( type, decalPoly );
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
RE_AddPolyToScene( p->shader, p->poly.numVerts, p->verts, 1 );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
decalPoly++;
|
||
|
if ( decalPoly >= r_markcount->integer )
|
||
|
{
|
||
|
decalPoly = 0;
|
||
|
}
|
||
|
}
|
||
|
while ( decalPoly != re_decalPolyHead[type] );
|
||
|
}
|
||
|
}
|