2008-07-25 07:31:37 +00:00
/* -------------------------------------------------------------------------------
2012-03-17 20:01:54 +00:00
Copyright ( C ) 1999 - 2007 id Software , Inc . and contributors .
For a list of contributors , see the accompanying CONTRIBUTORS file .
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
This file is part of GtkRadiant .
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
GtkRadiant 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 2 of the License , or
( at your option ) any later version .
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
GtkRadiant 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 .
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
You should have received a copy of the GNU General Public License
along with GtkRadiant ; if not , write to the Free Software
Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
This code has been altered significantly from its original form , to support
several games based on the Quake III Arena engine , in the form of " Q3Map2. "
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2007-11-04 03:34:51 +00:00
/* marker */
# define MODEL_C
/* dependencies */
# include "q3map2.h"
2012-03-17 20:01:54 +00:00
/*
PicoPrintFunc ( )
callback for picomodel . lib
*/
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
void PicoPrintFunc ( int level , const char * str ) {
if ( str = = NULL ) {
2007-11-04 03:34:51 +00:00
return ;
2012-03-17 20:01:54 +00:00
}
switch ( level )
2007-11-04 03:34:51 +00:00
{
2012-03-17 20:01:54 +00:00
case PICO_NORMAL :
Sys_Printf ( " %s \n " , str ) ;
break ;
case PICO_VERBOSE :
Sys_FPrintf ( SYS_VRB , " %s \n " , str ) ;
break ;
case PICO_WARNING :
2016-05-16 19:20:20 +00:00
Sys_FPrintf ( SYS_WRN , " WARNING: %s \n " , str ) ;
2012-03-17 20:01:54 +00:00
break ;
case PICO_ERROR :
2016-05-16 19:20:20 +00:00
Sys_FPrintf ( SYS_ERR , " ERROR: %s \n " , str ) ;
2012-03-17 20:01:54 +00:00
break ;
case PICO_FATAL :
Error ( " ERROR: %s \n " , str ) ;
break ;
2007-11-04 03:34:51 +00:00
}
}
2012-03-17 20:01:54 +00:00
/*
PicoLoadFileFunc ( )
callback for picomodel . lib
*/
2007-11-04 03:34:51 +00:00
2010-10-05 08:57:07 +00:00
void PicoLoadFileFunc ( const char * name , byte * * buffer , int * bufSize ) {
* bufSize = vfsLoadFile ( name , ( void * * ) buffer , 0 ) ;
2007-11-04 03:34:51 +00:00
}
/*
2012-03-17 20:01:54 +00:00
FindModel ( ) - ydnar
finds an existing picoModel and returns a pointer to the picoModel_t struct or NULL if not found
*/
picoModel_t * FindModel ( char * name , int frame ) {
int i ;
2007-11-04 03:34:51 +00:00
/* init */
2012-03-17 20:01:54 +00:00
if ( numPicoModels < = 0 ) {
2007-11-04 03:34:51 +00:00
memset ( picoModels , 0 , sizeof ( picoModels ) ) ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
/* dummy check */
2012-03-17 20:01:54 +00:00
if ( name = = NULL | | name [ 0 ] = = ' \0 ' ) {
2007-11-04 03:34:51 +00:00
return NULL ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
/* search list */
2012-03-17 20:01:54 +00:00
for ( i = 0 ; i < MAX_MODELS ; i + + )
2007-11-04 03:34:51 +00:00
{
2012-03-17 20:01:54 +00:00
if ( picoModels [ i ] ! = NULL & &
! strcmp ( PicoGetModelName ( picoModels [ i ] ) , name ) & &
PicoGetModelFrameNum ( picoModels [ i ] ) = = frame ) {
2007-11-04 03:34:51 +00:00
return picoModels [ i ] ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
}
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
/* no matching picoModel found */
return NULL ;
}
/*
2012-03-17 20:01:54 +00:00
LoadModel ( ) - ydnar
loads a picoModel and returns a pointer to the picoModel_t struct or NULL if not found
*/
picoModel_t * LoadModel ( char * name , int frame ) {
int i ;
picoModel_t * model , * * pm ;
2007-11-04 03:34:51 +00:00
/* init */
2012-03-17 20:01:54 +00:00
if ( numPicoModels < = 0 ) {
2007-11-04 03:34:51 +00:00
memset ( picoModels , 0 , sizeof ( picoModels ) ) ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
/* dummy check */
2012-03-17 20:01:54 +00:00
if ( name = = NULL | | name [ 0 ] = = ' \0 ' ) {
2007-11-04 03:34:51 +00:00
return NULL ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
/* try to find existing picoModel */
model = FindModel ( name , frame ) ;
2012-03-17 20:01:54 +00:00
if ( model ! = NULL ) {
2007-11-04 03:34:51 +00:00
return model ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
/* none found, so find first non-null picoModel */
pm = NULL ;
2012-03-17 20:01:54 +00:00
for ( i = 0 ; i < MAX_MODELS ; i + + )
2007-11-04 03:34:51 +00:00
{
2012-03-17 20:01:54 +00:00
if ( picoModels [ i ] = = NULL ) {
2007-11-04 03:34:51 +00:00
pm = & picoModels [ i ] ;
break ;
}
}
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
/* too many picoModels? */
2012-03-17 20:01:54 +00:00
if ( pm = = NULL ) {
2007-11-04 03:34:51 +00:00
Error ( " MAX_MODELS (%d) exceeded, there are too many model files referenced by the map. " , MAX_MODELS ) ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
/* attempt to parse model */
2010-10-05 08:57:07 +00:00
* pm = PicoLoadModel ( name , frame ) ;
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
/* if loading failed, make a bogus model to silence the rest of the warnings */
2012-03-17 20:01:54 +00:00
if ( * pm = = NULL ) {
2007-11-04 03:34:51 +00:00
/* allocate a new model */
* pm = PicoNewModel ( ) ;
2012-03-17 20:01:54 +00:00
if ( * pm = = NULL ) {
2007-11-04 03:34:51 +00:00
return NULL ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
/* set data */
PicoSetModelName ( * pm , name ) ;
PicoSetModelFrameNum ( * pm , frame ) ;
}
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
/* debug code */
#if 0
{
2012-03-17 20:01:54 +00:00
int numSurfaces , numVertexes ;
picoSurface_t * ps ;
2007-11-04 03:34:51 +00:00
Sys_Printf ( " Model %s \n " , name ) ;
numSurfaces = PicoGetModelNumSurfaces ( * pm ) ;
2012-03-17 20:01:54 +00:00
for ( i = 0 ; i < numSurfaces ; i + + )
2007-11-04 03:34:51 +00:00
{
ps = PicoGetModelSurface ( * pm , i ) ;
numVertexes = PicoGetSurfaceNumVertexes ( ps ) ;
Sys_Printf ( " Surface %d has %d vertexes \n " , i , numVertexes ) ;
}
}
# endif
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
/* set count */
2012-03-17 20:01:54 +00:00
if ( * pm ! = NULL ) {
2007-11-04 03:34:51 +00:00
numPicoModels + + ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
/* return the picoModel */
return * pm ;
}
/*
2012-03-17 20:01:54 +00:00
InsertModel ( ) - ydnar
adds a picomodel into the bsp
*/
void InsertModel ( char * name , int frame , m4x4_t transform , remap_t * remap , shaderInfo_t * celShader , int eNum , int castShadows , int recvShadows , int spawnFlags , float lightmapScale ) {
int i , j , k , s , numSurfaces ;
m4x4_t identity , nTransform ;
picoModel_t * model ;
picoShader_t * shader ;
picoSurface_t * surface ;
shaderInfo_t * si ;
mapDrawSurface_t * ds ;
bspDrawVert_t * dv ;
char * picoShaderName ;
char shaderName [ MAX_QPATH ] ;
picoVec_t * xyz , * normal , * st ;
byte * color ;
picoIndex_t * indexes ;
remap_t * rm , * glob ;
2008-09-13 18:28:57 +00:00
double normalEpsilon_save ;
double distanceEpsilon_save ;
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
/* get model */
model = LoadModel ( name , frame ) ;
2012-03-17 20:01:54 +00:00
if ( model = = NULL ) {
2007-11-04 03:34:51 +00:00
return ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
/* handle null matrix */
2012-03-17 20:01:54 +00:00
if ( transform = = NULL ) {
2007-11-04 03:34:51 +00:00
m4x4_identity ( identity ) ;
transform = identity ;
}
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
/* hack: Stable-1_2 and trunk have differing row/column major matrix order
this transpose is necessary with Stable - 1 _2
uncomment the following line with old m4x4_t ( non 1.3 / spog_branch ) code */
//% m4x4_transpose( transform );
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
/* create transform matrix for normals */
memcpy ( nTransform , transform , sizeof ( m4x4_t ) ) ;
2012-03-17 20:01:54 +00:00
if ( m4x4_invert ( nTransform ) ) {
2007-11-04 03:34:51 +00:00
Sys_FPrintf ( SYS_VRB , " WARNING: Can't invert model transform matrix, using transpose instead \n " ) ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
m4x4_transpose ( nTransform ) ;
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
/* fix bogus lightmap scale */
2012-03-17 20:01:54 +00:00
if ( lightmapScale < = 0.0f ) {
2007-11-04 03:34:51 +00:00
lightmapScale = 1.0f ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
/* each surface on the model will become a new map drawsurface */
numSurfaces = PicoGetModelNumSurfaces ( model ) ;
//% Sys_FPrintf( SYS_VRB, "Model %s has %d surfaces\n", name, numSurfaces );
2012-03-17 20:01:54 +00:00
for ( s = 0 ; s < numSurfaces ; s + + )
2007-11-04 03:34:51 +00:00
{
/* get surface */
surface = PicoGetModelSurface ( model , s ) ;
2012-03-17 20:01:54 +00:00
if ( surface = = NULL ) {
2007-11-04 03:34:51 +00:00
continue ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
/* only handle triangle surfaces initially (fixme: support patches) */
2012-03-17 20:01:54 +00:00
if ( PicoGetSurfaceType ( surface ) ! = PICO_TRIANGLES ) {
2007-11-04 03:34:51 +00:00
continue ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
/* fix the surface's normals */
PicoFixSurfaceNormals ( surface ) ;
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
/* allocate a surface (ydnar: gs mods) */
ds = AllocDrawSurface ( SURFACE_TRIANGLES ) ;
ds - > entityNum = eNum ;
ds - > castShadows = castShadows ;
ds - > recvShadows = recvShadows ;
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
/* get shader name */
2012-03-17 20:01:54 +00:00
shader = PicoGetSurfaceShader ( surface ) ;
if ( shader = = NULL ) {
2007-11-04 03:34:51 +00:00
picoShaderName = " " ;
2012-03-17 20:01:54 +00:00
}
else {
2007-11-04 03:34:51 +00:00
picoShaderName = PicoGetShaderName ( shader ) ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
/* handle shader remapping */
glob = NULL ;
2012-03-17 20:01:54 +00:00
for ( rm = remap ; rm ! = NULL ; rm = rm - > next )
2007-11-04 03:34:51 +00:00
{
2012-03-17 20:01:54 +00:00
if ( rm - > from [ 0 ] = = ' * ' & & rm - > from [ 1 ] = = ' \0 ' ) {
2007-11-04 03:34:51 +00:00
glob = rm ;
2012-03-17 20:01:54 +00:00
}
else if ( ! Q_stricmp ( picoShaderName , rm - > from ) ) {
2007-11-04 03:34:51 +00:00
Sys_FPrintf ( SYS_VRB , " Remapping %s to %s \n " , picoShaderName , rm - > to ) ;
picoShaderName = rm - > to ;
glob = NULL ;
break ;
}
}
2012-03-17 20:01:54 +00:00
if ( glob ! = NULL ) {
2007-11-04 03:34:51 +00:00
Sys_FPrintf ( SYS_VRB , " Globbing %s to %s \n " , picoShaderName , glob - > to ) ;
picoShaderName = glob - > to ;
}
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
/* shader renaming for sof2 */
2012-03-17 20:01:54 +00:00
if ( renameModelShaders ) {
2007-11-04 03:34:51 +00:00
strcpy ( shaderName , picoShaderName ) ;
StripExtension ( shaderName ) ;
2012-03-17 20:01:54 +00:00
if ( spawnFlags & 1 ) {
2007-11-04 03:34:51 +00:00
strcat ( shaderName , " _RMG_BSP " ) ;
2012-03-17 20:01:54 +00:00
}
else {
2007-11-04 03:34:51 +00:00
strcat ( shaderName , " _BSP " ) ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
si = ShaderInfoForShader ( shaderName ) ;
}
2012-03-17 20:01:54 +00:00
else {
2007-11-04 03:34:51 +00:00
si = ShaderInfoForShader ( picoShaderName ) ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
/* set shader */
ds - > shaderInfo = si ;
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
/* set lightmap scale */
ds - > lightmapScale = lightmapScale ;
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
/* force to meta? */
2012-03-17 20:01:54 +00:00
if ( ( si ! = NULL & & si - > forceMeta ) | | ( spawnFlags & 4 ) ) { /* 3rd bit */
2007-11-04 03:34:51 +00:00
ds - > type = SURFACE_FORCED_META ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
/* set particulars */
ds - > numVerts = PicoGetSurfaceNumVertexes ( surface ) ;
ds - > verts = safe_malloc ( ds - > numVerts * sizeof ( ds - > verts [ 0 ] ) ) ;
memset ( ds - > verts , 0 , ds - > numVerts * sizeof ( ds - > verts [ 0 ] ) ) ;
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
ds - > numIndexes = PicoGetSurfaceNumIndexes ( surface ) ;
ds - > indexes = safe_malloc ( ds - > numIndexes * sizeof ( ds - > indexes [ 0 ] ) ) ;
memset ( ds - > indexes , 0 , ds - > numIndexes * sizeof ( ds - > indexes [ 0 ] ) ) ;
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
/* copy vertexes */
2012-03-17 20:01:54 +00:00
for ( i = 0 ; i < ds - > numVerts ; i + + )
2007-11-04 03:34:51 +00:00
{
/* get vertex */
dv = & ds - > verts [ i ] ;
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
/* xyz and normal */
xyz = PicoGetSurfaceXYZ ( surface , i ) ;
VectorCopy ( xyz , dv - > xyz ) ;
m4x4_transform_point ( transform , dv - > xyz ) ;
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
normal = PicoGetSurfaceNormal ( surface , i ) ;
VectorCopy ( normal , dv - > normal ) ;
m4x4_transform_normal ( nTransform , dv - > normal ) ;
VectorNormalize ( dv - > normal , dv - > normal ) ;
/* ydnar: tek-fu celshading support for flat shaded shit */
2012-03-17 20:01:54 +00:00
if ( flat ) {
2007-11-04 03:34:51 +00:00
dv - > st [ 0 ] = si - > stFlat [ 0 ] ;
dv - > st [ 1 ] = si - > stFlat [ 1 ] ;
}
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
/* ydnar: gs mods: added support for explicit shader texcoord generation */
2012-03-17 20:01:54 +00:00
else if ( si - > tcGen ) {
2007-11-04 03:34:51 +00:00
/* project the texture */
dv - > st [ 0 ] = DotProduct ( si - > vecs [ 0 ] , dv - > xyz ) ;
dv - > st [ 1 ] = DotProduct ( si - > vecs [ 1 ] , dv - > xyz ) ;
}
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
/* normal texture coordinates */
2008-07-25 07:31:37 +00:00
else
2007-11-04 03:34:51 +00:00
{
st = PicoGetSurfaceST ( surface , 0 , i ) ;
dv - > st [ 0 ] = st [ 0 ] ;
dv - > st [ 1 ] = st [ 1 ] ;
}
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
/* set lightmap/color bits */
color = PicoGetSurfaceColor ( surface , 0 , i ) ;
2012-03-17 20:01:54 +00:00
for ( j = 0 ; j < MAX_LIGHTMAPS ; j + + )
2007-11-04 03:34:51 +00:00
{
dv - > lightmap [ j ] [ 0 ] = 0.0f ;
dv - > lightmap [ j ] [ 1 ] = 0.0f ;
2018-01-28 03:32:58 +00:00
if ( spawnFlags & 32 ) { // spawnflag 32: model color -> alpha hack
2009-03-31 06:28:17 +00:00
dv - > color [ j ] [ 0 ] = 255.0f ;
dv - > color [ j ] [ 1 ] = 255.0f ;
dv - > color [ j ] [ 2 ] = 255.0f ;
dv - > color [ j ] [ 3 ] = color [ 0 ] * 0.3f + color [ 1 ] * 0.59f + color [ 2 ] * 0.11f ;
}
else
{
dv - > color [ j ] [ 0 ] = color [ 0 ] ;
dv - > color [ j ] [ 1 ] = color [ 1 ] ;
dv - > color [ j ] [ 2 ] = color [ 2 ] ;
dv - > color [ j ] [ 3 ] = color [ 3 ] ;
}
2007-11-04 03:34:51 +00:00
}
}
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
/* copy indexes */
indexes = PicoGetSurfaceIndexes ( surface , 0 ) ;
2012-03-17 20:01:54 +00:00
for ( i = 0 ; i < ds - > numIndexes ; i + + )
2007-11-04 03:34:51 +00:00
ds - > indexes [ i ] = indexes [ i ] ;
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
/* set cel shader */
ds - > celShader = celShader ;
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
/* ydnar: giant hack land: generate clipping brushes for model triangles */
2012-03-17 20:01:54 +00:00
if ( si - > clipModel | | ( spawnFlags & 2 ) ) { /* 2nd bit */
2008-09-13 18:28:57 +00:00
vec3_t points [ 4 ] , backs [ 3 ] ;
2012-03-17 20:01:54 +00:00
vec4_t plane , reverse , pa , pb , pc ;
2007-11-04 03:34:51 +00:00
/* temp hack */
2012-03-17 20:01:54 +00:00
if ( ! si - > clipModel & &
( ( si - > compileFlags & C_TRANSLUCENT ) | | ! ( si - > compileFlags & C_SOLID ) ) ) {
2007-11-04 03:34:51 +00:00
continue ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
/* overflow check */
2012-03-17 20:01:54 +00:00
if ( ( nummapplanes + 64 ) > = ( MAX_MAP_PLANES > > 1 ) ) {
2007-11-04 03:34:51 +00:00
continue ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
/* walk triangle list */
2012-03-17 20:01:54 +00:00
for ( i = 0 ; i < ds - > numIndexes ; i + = 3 )
2007-11-04 03:34:51 +00:00
{
/* overflow hack */
2012-03-17 20:01:54 +00:00
if ( ( nummapplanes + 64 ) > = ( MAX_MAP_PLANES > > 1 ) ) {
2016-05-16 19:20:20 +00:00
Sys_FPrintf ( SYS_WRN , " WARNING: MAX_MAP_PLANES (%d) hit generating clip brushes for model %s. \n " ,
2012-03-17 20:01:54 +00:00
MAX_MAP_PLANES , name ) ;
2007-11-04 03:34:51 +00:00
break ;
}
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
/* make points and back points */
2012-03-17 20:01:54 +00:00
for ( j = 0 ; j < 3 ; j + + )
2007-11-04 03:34:51 +00:00
{
/* get vertex */
dv = & ds - > verts [ ds - > indexes [ i + j ] ] ;
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
/* copy xyz */
VectorCopy ( dv - > xyz , points [ j ] ) ;
2012-03-17 20:01:54 +00:00
# if !Q3MAP2_EXPERIMENTAL_MODEL_CLIPPING_FIX
2011-01-19 06:41:33 +00:00
// The code below is totally unneeded regardless of Q3MAP2_EXPERIMENTAL_MODEL_CLIPPING_FIX.
// backs is reinitialized further below. However, the extra code does not hurt anything.
2007-11-04 03:34:51 +00:00
VectorCopy ( dv - > xyz , backs [ j ] ) ;
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
/* find nearest axial to normal and push back points opposite */
/* note: this doesn't work as well as simply using the plane of the triangle, below */
2012-03-17 20:01:54 +00:00
for ( k = 0 ; k < 3 ; k + + )
2007-11-04 03:34:51 +00:00
{
2008-09-13 18:28:57 +00:00
if ( fabs ( dv - > normal [ k ] ) > = fabs ( dv - > normal [ ( k + 1 ) % 3 ] ) & &
fabs ( dv - > normal [ k ] ) > = fabs ( dv - > normal [ ( k + 2 ) % 3 ] ) ) {
2007-11-04 03:34:51 +00:00
backs [ j ] [ k ] + = dv - > normal [ k ] < 0.0f ? 64.0f : - 64.0f ;
break ;
}
}
2011-01-19 06:41:33 +00:00
# endif
2007-11-04 03:34:51 +00:00
}
2012-03-17 20:01:54 +00:00
2008-09-13 18:28:57 +00:00
VectorCopy ( points [ 0 ] , points [ 3 ] ) ; // for cyclic usage
2007-11-04 03:34:51 +00:00
/* make plane for triangle */
2008-09-13 18:28:57 +00:00
// div0: add some extra spawnflags:
// 0: snap normals to axial planes for extrusion
// 8: extrude with the original normals
// 16: extrude only with up/down normals (ideal for terrain)
// 24: extrude by distance zero (may need engine changes)
2012-03-17 20:01:54 +00:00
if ( PlaneFromPoints ( plane , points [ 0 ] , points [ 1 ] , points [ 2 ] ) ) {
2008-09-13 18:28:57 +00:00
vec3_t bestNormal ;
float backPlaneDistance = 2 ;
if ( spawnFlags & 8 ) { // use a DOWN normal
if ( spawnFlags & 16 ) {
// 24: normal as is, and zero width (broken)
VectorCopy ( plane , bestNormal ) ;
}
else
{
// 8: normal as is
VectorCopy ( plane , bestNormal ) ;
}
}
else
{
if ( spawnFlags & 16 ) {
// 16: UP/DOWN normal
VectorSet ( bestNormal , 0 , 0 , ( plane [ 2 ] > = 0 ? 1 : - 1 ) ) ;
}
else
{
// 0: axial normal
if ( fabs ( plane [ 0 ] ) > fabs ( plane [ 1 ] ) ) { // x>y
if ( fabs ( plane [ 1 ] ) > fabs ( plane [ 2 ] ) ) { // x>y, y>z
VectorSet ( bestNormal , ( plane [ 0 ] > = 0 ? 1 : - 1 ) , 0 , 0 ) ;
}
else // x>y, z>=y
if ( fabs ( plane [ 0 ] ) > fabs ( plane [ 2 ] ) ) { // x>z, z>=y
VectorSet ( bestNormal , ( plane [ 0 ] > = 0 ? 1 : - 1 ) , 0 , 0 ) ;
}
else { // z>=x, x>y
VectorSet ( bestNormal , 0 , 0 , ( plane [ 2 ] > = 0 ? 1 : - 1 ) ) ;
}
}
else // y>=x
if ( fabs ( plane [ 1 ] ) > fabs ( plane [ 2 ] ) ) { // y>z, y>=x
VectorSet ( bestNormal , 0 , ( plane [ 1 ] > = 0 ? 1 : - 1 ) , 0 ) ;
}
else { // z>=y, y>=x
VectorSet ( bestNormal , 0 , 0 , ( plane [ 2 ] > = 0 ? 1 : - 1 ) ) ;
}
}
}
/* build a brush */
buildBrush = AllocBrush ( 48 ) ;
buildBrush - > entityNum = mapEntityNum ;
buildBrush - > original = buildBrush ;
buildBrush - > contentShader = si ;
buildBrush - > compileFlags = si - > compileFlags ;
buildBrush - > contentFlags = si - > contentFlags ;
normalEpsilon_save = normalEpsilon ;
distanceEpsilon_save = distanceEpsilon ;
if ( si - > compileFlags & C_STRUCTURAL ) { // allow forced structural brushes here
buildBrush - > detail = qfalse ;
// only allow EXACT matches when snapping for these (this is mostly for caulk brushes inside a model)
if ( normalEpsilon > 0 ) {
normalEpsilon = 0 ;
}
if ( distanceEpsilon > 0 ) {
distanceEpsilon = 0 ;
}
}
else {
buildBrush - > detail = qtrue ;
}
2007-11-04 03:34:51 +00:00
/* regenerate back points */
2012-03-17 20:01:54 +00:00
for ( j = 0 ; j < 3 ; j + + )
2007-11-04 03:34:51 +00:00
{
/* get vertex */
dv = & ds - > verts [ ds - > indexes [ i + j ] ] ;
2012-03-17 20:01:54 +00:00
2008-09-13 18:28:57 +00:00
// shift by some units
VectorMA ( dv - > xyz , - 64.0f , bestNormal , backs [ j ] ) ; // 64 prevents roundoff errors a bit
2007-11-04 03:34:51 +00:00
}
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
/* make back plane */
VectorScale ( plane , - 1.0f , reverse ) ;
2008-09-13 18:28:57 +00:00
reverse [ 3 ] = - plane [ 3 ] ;
if ( ( spawnFlags & 24 ) ! = 24 ) {
reverse [ 3 ] + = DotProduct ( bestNormal , plane ) * backPlaneDistance ;
}
// that's at least sqrt(1/3) backPlaneDistance, unless in DOWN mode; in DOWN mode, we are screwed anyway if we encounter a plane that's perpendicular to the xy plane)
2012-03-17 20:01:54 +00:00
if ( PlaneFromPoints ( pa , points [ 2 ] , points [ 1 ] , backs [ 1 ] ) & &
PlaneFromPoints ( pb , points [ 1 ] , points [ 0 ] , backs [ 0 ] ) & &
PlaneFromPoints ( pc , points [ 0 ] , points [ 2 ] , backs [ 2 ] ) ) {
2007-11-04 03:34:51 +00:00
/* set up brush sides */
buildBrush - > numsides = 5 ;
2012-03-17 20:01:54 +00:00
for ( j = 0 ; j < buildBrush - > numsides ; j + + )
2007-11-04 03:34:51 +00:00
buildBrush - > sides [ j ] . shaderInfo = si ;
2008-09-13 18:28:57 +00:00
2007-11-04 03:34:51 +00:00
buildBrush - > sides [ 0 ] . planenum = FindFloatPlane ( plane , plane [ 3 ] , 3 , points ) ;
2008-09-13 18:28:57 +00:00
buildBrush - > sides [ 0 ] . planenum = FindFloatPlane ( plane , plane [ 3 ] , 3 , points ) ;
buildBrush - > sides [ 1 ] . planenum = FindFloatPlane ( pa , pa [ 3 ] , 2 , & points [ 1 ] ) ; // pa contains points[1] and points[2]
buildBrush - > sides [ 2 ] . planenum = FindFloatPlane ( pb , pb [ 3 ] , 2 , & points [ 0 ] ) ; // pb contains points[0] and points[1]
buildBrush - > sides [ 3 ] . planenum = FindFloatPlane ( pc , pc [ 3 ] , 2 , & points [ 2 ] ) ; // pc contains points[2] and points[0] (copied to points[3]
buildBrush - > sides [ 4 ] . planenum = FindFloatPlane ( reverse , reverse [ 3 ] , 3 , backs ) ;
}
else
{
free ( buildBrush ) ;
continue ;
}
normalEpsilon = normalEpsilon_save ;
distanceEpsilon = distanceEpsilon_save ;
/* add to entity */
if ( CreateBrushWindings ( buildBrush ) ) {
AddBrushBevels ( ) ;
//% EmitBrushes( buildBrush, NULL, NULL );
buildBrush - > next = entities [ mapEntityNum ] . brushes ;
entities [ mapEntityNum ] . brushes = buildBrush ;
entities [ mapEntityNum ] . numBrushes + + ;
}
else {
free ( buildBrush ) ;
2007-11-04 03:34:51 +00:00
}
}
}
}
}
}
/*
2012-03-17 20:01:54 +00:00
AddTriangleModels ( )
adds misc_model surfaces to the bsp
*/
void AddTriangleModels ( entity_t * e ) {
int num , frame , castShadows , recvShadows , spawnFlags ;
entity_t * e2 ;
const char * targetName ;
const char * target , * model , * value ;
char shader [ MAX_QPATH ] ;
shaderInfo_t * celShader ;
float temp , baseLightmapScale , lightmapScale ;
vec3_t origin , scale , angles ;
m4x4_t transform ;
epair_t * ep ;
remap_t * remap , * remap2 ;
char * split ;
2007-11-04 03:34:51 +00:00
/* note it */
Sys_FPrintf ( SYS_VRB , " --- AddTriangleModels --- \n " ) ;
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
/* get current brush entity targetname */
2012-03-17 20:01:54 +00:00
if ( e = = entities ) {
2007-11-04 03:34:51 +00:00
targetName = " " ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
else
{
targetName = ValueForKey ( e , " targetname " ) ;
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
/* misc_model entities target non-worldspawn brush model entities */
2012-03-17 20:01:54 +00:00
if ( targetName [ 0 ] = = ' \0 ' ) {
2007-11-04 03:34:51 +00:00
return ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
}
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
/* get lightmap scale */
baseLightmapScale = FloatForKey ( e , " _lightmapscale " ) ;
2012-03-17 20:01:54 +00:00
if ( baseLightmapScale < = 0.0f ) {
2007-11-04 03:34:51 +00:00
baseLightmapScale = 0.0f ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
/* walk the entity list */
2012-03-17 20:01:54 +00:00
for ( num = 1 ; num < numEntities ; num + + )
2007-11-04 03:34:51 +00:00
{
/* get e2 */
e2 = & entities [ num ] ;
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
/* convert misc_models into raw geometry */
2012-03-17 20:01:54 +00:00
if ( Q_stricmp ( " misc_model " , ValueForKey ( e2 , " classname " ) ) ) {
2007-11-04 03:34:51 +00:00
continue ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
/* ydnar: added support for md3 models on non-worldspawn models */
target = ValueForKey ( e2 , " target " ) ;
2012-03-17 20:01:54 +00:00
if ( strcmp ( target , targetName ) ) {
2007-11-04 03:34:51 +00:00
continue ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
/* get model name */
model = ValueForKey ( e2 , " model " ) ;
2012-03-17 20:01:54 +00:00
if ( model [ 0 ] = = ' \0 ' ) {
2016-05-16 19:20:20 +00:00
Sys_FPrintf ( SYS_WRN , " WARNING: misc_model at %i %i %i without a model key \n " ,
2012-03-17 20:01:54 +00:00
( int ) origin [ 0 ] , ( int ) origin [ 1 ] , ( int ) origin [ 2 ] ) ;
2007-11-04 03:34:51 +00:00
continue ;
}
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
/* get model frame */
frame = IntForKey ( e2 , " _frame " ) ;
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
/* worldspawn (and func_groups) default to cast/recv shadows in worldspawn group */
2012-03-17 20:01:54 +00:00
if ( e = = entities ) {
2007-11-04 03:34:51 +00:00
castShadows = WORLDSPAWN_CAST_SHADOWS ;
recvShadows = WORLDSPAWN_RECV_SHADOWS ;
}
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
/* other entities don't cast any shadows, but recv worldspawn shadows */
else
{
castShadows = ENTITY_CAST_SHADOWS ;
recvShadows = ENTITY_RECV_SHADOWS ;
}
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
/* get explicit shadow flags */
GetEntityShadowFlags ( e2 , e , & castShadows , & recvShadows ) ;
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
/* get spawnflags */
spawnFlags = IntForKey ( e2 , " spawnflags " ) ;
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
/* get origin */
GetVectorForKey ( e2 , " origin " , origin ) ;
2012-03-17 20:01:54 +00:00
VectorSubtract ( origin , e - > origin , origin ) ; /* offset by parent */
2007-11-04 03:34:51 +00:00
/* get scale */
scale [ 0 ] = scale [ 1 ] = scale [ 2 ] = 1.0f ;
temp = FloatForKey ( e2 , " modelscale " ) ;
2012-03-17 20:01:54 +00:00
if ( temp ! = 0.0f ) {
2007-11-04 03:34:51 +00:00
scale [ 0 ] = scale [ 1 ] = scale [ 2 ] = temp ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
value = ValueForKey ( e2 , " modelscale_vec " ) ;
2012-03-17 20:01:54 +00:00
if ( value [ 0 ] ! = ' \0 ' ) {
2007-11-04 03:34:51 +00:00
sscanf ( value , " %f %f %f " , & scale [ 0 ] , & scale [ 1 ] , & scale [ 2 ] ) ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
/* get "angle" (yaw) or "angles" (pitch yaw roll) */
angles [ 0 ] = angles [ 1 ] = angles [ 2 ] = 0.0f ;
angles [ 2 ] = FloatForKey ( e2 , " angle " ) ;
value = ValueForKey ( e2 , " angles " ) ;
2012-03-17 20:01:54 +00:00
if ( value [ 0 ] ! = ' \0 ' ) {
2007-11-04 03:34:51 +00:00
sscanf ( value , " %f %f %f " , & angles [ 1 ] , & angles [ 2 ] , & angles [ 0 ] ) ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
/* set transform matrix (thanks spog) */
m4x4_identity ( transform ) ;
m4x4_pivoted_transform_by_vec3 ( transform , origin , angles , eXYZ , scale , vec3_origin ) ;
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
/* get shader remappings */
remap = NULL ;
2012-03-17 20:01:54 +00:00
for ( ep = e2 - > epairs ; ep ! = NULL ; ep = ep - > next )
2007-11-04 03:34:51 +00:00
{
/* look for keys prefixed with "_remap" */
2012-03-17 20:01:54 +00:00
if ( ep - > key ! = NULL & & ep - > value ! = NULL & &
ep - > key [ 0 ] ! = ' \0 ' & & ep - > value [ 0 ] ! = ' \0 ' & &
! Q_strncasecmp ( ep - > key , " _remap " , 6 ) ) {
2007-11-04 03:34:51 +00:00
/* create new remapping */
remap2 = remap ;
remap = safe_malloc ( sizeof ( * remap ) ) ;
remap - > next = remap2 ;
strcpy ( remap - > from , ep - > value ) ;
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
/* split the string */
split = strchr ( remap - > from , ' ; ' ) ;
2012-03-17 20:01:54 +00:00
if ( split = = NULL ) {
2016-05-16 19:20:20 +00:00
Sys_FPrintf ( SYS_WRN , " WARNING: Shader _remap key found in misc_model without a ; character \n " ) ;
2007-11-04 03:34:51 +00:00
free ( remap ) ;
remap = remap2 ;
continue ;
}
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
/* store the split */
* split = ' \0 ' ;
2012-03-17 20:01:54 +00:00
strcpy ( remap - > to , ( split + 1 ) ) ;
2007-11-04 03:34:51 +00:00
/* note it */
//% Sys_FPrintf( SYS_VRB, "Remapping %s to %s\n", remap->from, remap->to );
}
}
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
/* ydnar: cel shader support */
value = ValueForKey ( e2 , " _celshader " ) ;
2012-03-17 20:01:54 +00:00
if ( value [ 0 ] = = ' \0 ' ) {
2007-11-04 03:34:51 +00:00
value = ValueForKey ( & entities [ 0 ] , " _celshader " ) ;
2012-03-17 20:01:54 +00:00
}
if ( value [ 0 ] ! = ' \0 ' ) {
2007-11-04 03:34:51 +00:00
sprintf ( shader , " textures/%s " , value ) ;
celShader = ShaderInfoForShader ( shader ) ;
}
2012-03-17 20:01:54 +00:00
else {
2007-11-04 03:34:51 +00:00
celShader = NULL ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
/* get lightmap scale */
lightmapScale = FloatForKey ( e2 , " _lightmapscale " ) ;
2012-03-17 20:01:54 +00:00
if ( lightmapScale < = 0.0f ) {
2007-11-04 03:34:51 +00:00
lightmapScale = baseLightmapScale ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
/* insert the model */
InsertModel ( ( char * ) model , frame , transform , remap , celShader , mapEntityNum , castShadows , recvShadows , spawnFlags , lightmapScale ) ;
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
/* free shader remappings */
2012-03-17 20:01:54 +00:00
while ( remap ! = NULL )
2007-11-04 03:34:51 +00:00
{
remap2 = remap - > next ;
free ( remap ) ;
remap = remap2 ;
}
}
}