The Quake III Arena sources as originally released under the GPL license on August 20, 2005.

This commit is contained in:
Travis Bradshaw 2012-01-31 13:41:34 -06:00
commit dbe4ddb103
1409 changed files with 806066 additions and 0 deletions

933
common/aselib.c Normal file
View file

@ -0,0 +1,933 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code 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.
Quake III Arena source code 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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "aselib.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#define MAX_ASE_MATERIALS 32
#define MAX_ASE_OBJECTS 64
#define MAX_ASE_ANIMATIONS 32
#define MAX_ASE_ANIMATION_FRAMES 512
#define VERBOSE( x ) { if ( ase.verbose ) { printf x ; } }
typedef struct
{
float x, y, z;
float nx, ny, nz;
float s, t;
} aseVertex_t;
typedef struct
{
float s, t;
} aseTVertex_t;
typedef int aseFace_t[3];
typedef struct
{
int numFaces;
int numVertexes;
int numTVertexes;
int timeValue;
aseVertex_t *vertexes;
aseTVertex_t *tvertexes;
aseFace_t *faces, *tfaces;
int currentFace, currentVertex;
} aseMesh_t;
typedef struct
{
int numFrames;
aseMesh_t frames[MAX_ASE_ANIMATION_FRAMES];
int currentFrame;
} aseMeshAnimation_t;
typedef struct
{
char name[128];
} aseMaterial_t;
/*
** contains the animate sequence of a single surface
** using a single material
*/
typedef struct
{
char name[128];
int materialRef;
int numAnimations;
aseMeshAnimation_t anim;
} aseGeomObject_t;
typedef struct
{
int numMaterials;
aseMaterial_t materials[MAX_ASE_MATERIALS];
aseGeomObject_t objects[MAX_ASE_OBJECTS];
char *buffer;
char *curpos;
int len;
int currentObject;
qboolean verbose;
qboolean grabAnims;
} ase_t;
static char s_token[1024];
static ase_t ase;
static void ASE_Process( void );
static void ASE_FreeGeomObject( int ndx );
/*
** ASE_Load
*/
void ASE_Load( const char *filename, qboolean verbose, qboolean grabAnims )
{
FILE *fp = fopen( filename, "rb" );
if ( !fp )
Error( "File not found '%s'", filename );
memset( &ase, 0, sizeof( ase ) );
ase.verbose = verbose;
ase.grabAnims = grabAnims;
ase.len = Q_filelength( fp );
ase.curpos = ase.buffer = malloc( ase.len );
printf( "Processing '%s'\n", filename );
if ( fread( ase.buffer, ase.len, 1, fp ) != 1 )
{
fclose( fp );
Error( "fread() != -1 for '%s'", filename );
}
fclose( fp );
ASE_Process();
}
/*
** ASE_Free
*/
void ASE_Free( void )
{
int i;
for ( i = 0; i < ase.currentObject; i++ )
{
ASE_FreeGeomObject( i );
}
}
/*
** ASE_GetNumSurfaces
*/
int ASE_GetNumSurfaces( void )
{
return ase.currentObject;
}
/*
** ASE_GetSurfaceName
*/
const char *ASE_GetSurfaceName( int which )
{
aseGeomObject_t *pObject = &ase.objects[which];
if ( !pObject->anim.numFrames )
return 0;
return pObject->name;
}
/*
** ASE_GetSurfaceAnimation
**
** Returns an animation (sequence of polysets)
*/
polyset_t *ASE_GetSurfaceAnimation( int which, int *pNumFrames, int skipFrameStart, int skipFrameEnd, int maxFrames )
{
aseGeomObject_t *pObject = &ase.objects[which];
polyset_t *psets;
int numFramesInAnimation;
int numFramesToKeep;
int i, f;
if ( !pObject->anim.numFrames )
return 0;
if ( pObject->anim.numFrames > maxFrames && maxFrames != -1 )
{
numFramesInAnimation = maxFrames;
}
else
{
numFramesInAnimation = pObject->anim.numFrames;
if ( maxFrames != -1 )
printf( "WARNING: ASE_GetSurfaceAnimation maxFrames > numFramesInAnimation\n" );
}
if ( skipFrameEnd != -1 )
numFramesToKeep = numFramesInAnimation - ( skipFrameEnd - skipFrameStart + 1 );
else
numFramesToKeep = numFramesInAnimation;
*pNumFrames = numFramesToKeep;
psets = calloc( sizeof( polyset_t ) * numFramesToKeep, 1 );
for ( f = 0, i = 0; i < numFramesInAnimation; i++ )
{
int t;
aseMesh_t *pMesh = &pObject->anim.frames[i];
if ( skipFrameStart != -1 )
{
if ( i >= skipFrameStart && i <= skipFrameEnd )
continue;
}
strcpy( psets[f].name, pObject->name );
strcpy( psets[f].materialname, ase.materials[pObject->materialRef].name );
psets[f].triangles = calloc( sizeof( triangle_t ) * pObject->anim.frames[i].numFaces, 1 );
psets[f].numtriangles = pObject->anim.frames[i].numFaces;
for ( t = 0; t < pObject->anim.frames[i].numFaces; t++ )
{
int k;
for ( k = 0; k < 3; k++ )
{
psets[f].triangles[t].verts[k][0] = pMesh->vertexes[pMesh->faces[t][k]].x;
psets[f].triangles[t].verts[k][1] = pMesh->vertexes[pMesh->faces[t][k]].y;
psets[f].triangles[t].verts[k][2] = pMesh->vertexes[pMesh->faces[t][k]].z;
if ( pMesh->tvertexes && pMesh->tfaces )
{
psets[f].triangles[t].texcoords[k][0] = pMesh->tvertexes[pMesh->tfaces[t][k]].s;
psets[f].triangles[t].texcoords[k][1] = pMesh->tvertexes[pMesh->tfaces[t][k]].t;
}
}
}
f++;
}
return psets;
}
static void ASE_FreeGeomObject( int ndx )
{
aseGeomObject_t *pObject;
int i;
pObject = &ase.objects[ndx];
for ( i = 0; i < pObject->anim.numFrames; i++ )
{
if ( pObject->anim.frames[i].vertexes )
{
free( pObject->anim.frames[i].vertexes );
}
if ( pObject->anim.frames[i].tvertexes )
{
free( pObject->anim.frames[i].tvertexes );
}
if ( pObject->anim.frames[i].faces )
{
free( pObject->anim.frames[i].faces );
}
if ( pObject->anim.frames[i].tfaces )
{
free( pObject->anim.frames[i].tfaces );
}
}
memset( pObject, 0, sizeof( *pObject ) );
}
static aseMesh_t *ASE_GetCurrentMesh( void )
{
aseGeomObject_t *pObject;
if ( ase.currentObject >= MAX_ASE_OBJECTS )
{
Error( "Too many GEOMOBJECTs" );
return 0; // never called
}
pObject = &ase.objects[ase.currentObject];
if ( pObject->anim.currentFrame >= MAX_ASE_ANIMATION_FRAMES )
{
Error( "Too many MESHes" );
return 0;
}
return &pObject->anim.frames[pObject->anim.currentFrame];
}
static int CharIsTokenDelimiter( int ch )
{
if ( ch <= 32 )
return 1;
return 0;
}
static int ASE_GetToken( qboolean restOfLine )
{
int i = 0;
if ( ase.buffer == 0 )
return 0;
if ( ( ase.curpos - ase.buffer ) == ase.len )
return 0;
// skip over crap
while ( ( ( ase.curpos - ase.buffer ) < ase.len ) &&
( *ase.curpos <= 32 ) )
{
ase.curpos++;
}
while ( ( ase.curpos - ase.buffer ) < ase.len )
{
s_token[i] = *ase.curpos;
ase.curpos++;
i++;
if ( ( CharIsTokenDelimiter( s_token[i-1] ) && !restOfLine ) ||
( ( s_token[i-1] == '\n' ) || ( s_token[i-1] == '\r' ) ) )
{
s_token[i-1] = 0;
break;
}
}
s_token[i] = 0;
return 1;
}
static void ASE_ParseBracedBlock( void (*parser)( const char *token ) )
{
int indent = 0;
while ( ASE_GetToken( qfalse ) )
{
if ( !strcmp( s_token, "{" ) )
{
indent++;
}
else if ( !strcmp( s_token, "}" ) )
{
--indent;
if ( indent == 0 )
break;
else if ( indent < 0 )
Error( "Unexpected '}'" );
}
else
{
if ( parser )
parser( s_token );
}
}
}
static void ASE_SkipEnclosingBraces( void )
{
int indent = 0;
while ( ASE_GetToken( qfalse ) )
{
if ( !strcmp( s_token, "{" ) )
{
indent++;
}
else if ( !strcmp( s_token, "}" ) )
{
indent--;
if ( indent == 0 )
break;
else if ( indent < 0 )
Error( "Unexpected '}'" );
}
}
}
static void ASE_SkipRestOfLine( void )
{
ASE_GetToken( qtrue );
}
static void ASE_KeyMAP_DIFFUSE( const char *token )
{
char buffer[1024], buff1[1024], buff2[1024];
char *buf1, *buf2;
int i = 0, count;
if ( !strcmp( token, "*BITMAP" ) )
{
ASE_GetToken( qfalse );
strcpy( buffer, s_token + 1 );
if ( strchr( buffer, '"' ) )
*strchr( buffer, '"' ) = 0;
while ( buffer[i] )
{
if ( buffer[i] == '\\' )
buffer[i] = '/';
i++;
}
buf1 = buffer;
buf2 = gamedir;
// need to compare win32 volumes to potential unix junk
//
if ( (gamedir[1] == ':' && (buffer[0] == '/' && buffer[1] == '/')) ||
(buffer[1] == ':' && (gamedir[0] == '/' && gamedir[1] == '/')) ) {
if (buffer[1] == ':') {
buf1 = buffer + 2;
buf2 = gamedir + 2;
} else {
buf1 = gamedir + 2;
buf2 = buffer +2;
}
count = 0;
while (*buf2 && count < 2) {
if (*buf2 == '/') {
count++;
}
buf2++;
}
}
strcpy(buff1, buf1);
strlwr(buff1);
strcpy(buff2, buf2);
strlwr(buff2);
if ( strstr( buff2, buff1 + 2 ) )
{
strcpy( ase.materials[ase.numMaterials].name, strstr( buff2, buff1 + 2 ) + strlen( buff1 ) - 2 );
}
else
{
sprintf( ase.materials[ase.numMaterials].name, "(not converted: '%s')", buffer );
printf( "WARNING: illegal material name '%s'\n", buffer );
}
}
else
{
}
}
static void ASE_KeyMATERIAL( const char *token )
{
if ( !strcmp( token, "*MAP_DIFFUSE" ) )
{
ASE_ParseBracedBlock( ASE_KeyMAP_DIFFUSE );
}
else
{
}
}
static void ASE_KeyMATERIAL_LIST( const char *token )
{
if ( !strcmp( token, "*MATERIAL_COUNT" ) )
{
ASE_GetToken( qfalse );
VERBOSE( ( "..num materials: %s\n", s_token ) );
if ( atoi( s_token ) > MAX_ASE_MATERIALS )
{
Error( "Too many materials!" );
}
ase.numMaterials = 0;
}
else if ( !strcmp( token, "*MATERIAL" ) )
{
VERBOSE( ( "..material %d ", ase.numMaterials ) );
ASE_ParseBracedBlock( ASE_KeyMATERIAL );
ase.numMaterials++;
}
}
static void ASE_KeyMESH_VERTEX_LIST( const char *token )
{
aseMesh_t *pMesh = ASE_GetCurrentMesh();
if ( !strcmp( token, "*MESH_VERTEX" ) )
{
ASE_GetToken( qfalse ); // skip number
ASE_GetToken( qfalse );
pMesh->vertexes[pMesh->currentVertex].y = atof( s_token );
ASE_GetToken( qfalse );
pMesh->vertexes[pMesh->currentVertex].x = -atof( s_token );
ASE_GetToken( qfalse );
pMesh->vertexes[pMesh->currentVertex].z = atof( s_token );
pMesh->currentVertex++;
if ( pMesh->currentVertex > pMesh->numVertexes )
{
Error( "pMesh->currentVertex >= pMesh->numVertexes" );
}
}
else
{
Error( "Unknown token '%s' while parsing MESH_VERTEX_LIST", token );
}
}
static void ASE_KeyMESH_FACE_LIST( const char *token )
{
aseMesh_t *pMesh = ASE_GetCurrentMesh();
if ( !strcmp( token, "*MESH_FACE" ) )
{
ASE_GetToken( qfalse ); // skip face number
ASE_GetToken( qfalse ); // skip label
ASE_GetToken( qfalse ); // first vertex
pMesh->faces[pMesh->currentFace][0] = atoi( s_token );
ASE_GetToken( qfalse ); // skip label
ASE_GetToken( qfalse ); // second vertex
pMesh->faces[pMesh->currentFace][2] = atoi( s_token );
ASE_GetToken( qfalse ); // skip label
ASE_GetToken( qfalse ); // third vertex
pMesh->faces[pMesh->currentFace][1] = atoi( s_token );
ASE_GetToken( qtrue );
/*
if ( ( p = strstr( s_token, "*MESH_MTLID" ) ) != 0 )
{
p += strlen( "*MESH_MTLID" ) + 1;
mtlID = atoi( p );
}
else
{
Error( "No *MESH_MTLID found for face!" );
}
*/
pMesh->currentFace++;
}
else
{
Error( "Unknown token '%s' while parsing MESH_FACE_LIST", token );
}
}
static void ASE_KeyTFACE_LIST( const char *token )
{
aseMesh_t *pMesh = ASE_GetCurrentMesh();
if ( !strcmp( token, "*MESH_TFACE" ) )
{
int a, b, c;
ASE_GetToken( qfalse );
ASE_GetToken( qfalse );
a = atoi( s_token );
ASE_GetToken( qfalse );
c = atoi( s_token );
ASE_GetToken( qfalse );
b = atoi( s_token );
pMesh->tfaces[pMesh->currentFace][0] = a;
pMesh->tfaces[pMesh->currentFace][1] = b;
pMesh->tfaces[pMesh->currentFace][2] = c;
pMesh->currentFace++;
}
else
{
Error( "Unknown token '%s' in MESH_TFACE", token );
}
}
static void ASE_KeyMESH_TVERTLIST( const char *token )
{
aseMesh_t *pMesh = ASE_GetCurrentMesh();
if ( !strcmp( token, "*MESH_TVERT" ) )
{
char u[80], v[80], w[80];
ASE_GetToken( qfalse );
ASE_GetToken( qfalse );
strcpy( u, s_token );
ASE_GetToken( qfalse );
strcpy( v, s_token );
ASE_GetToken( qfalse );
strcpy( w, s_token );
pMesh->tvertexes[pMesh->currentVertex].s = atof( u );
pMesh->tvertexes[pMesh->currentVertex].t = 1.0f - atof( v );
pMesh->currentVertex++;
if ( pMesh->currentVertex > pMesh->numTVertexes )
{
Error( "pMesh->currentVertex > pMesh->numTVertexes" );
}
}
else
{
Error( "Unknown token '%s' while parsing MESH_TVERTLIST" );
}
}
static void ASE_KeyMESH( const char *token )
{
aseMesh_t *pMesh = ASE_GetCurrentMesh();
if ( !strcmp( token, "*TIMEVALUE" ) )
{
ASE_GetToken( qfalse );
pMesh->timeValue = atoi( s_token );
VERBOSE( ( ".....timevalue: %d\n", pMesh->timeValue ) );
}
else if ( !strcmp( token, "*MESH_NUMVERTEX" ) )
{
ASE_GetToken( qfalse );
pMesh->numVertexes = atoi( s_token );
VERBOSE( ( ".....TIMEVALUE: %d\n", pMesh->timeValue ) );
VERBOSE( ( ".....num vertexes: %d\n", pMesh->numVertexes ) );
}
else if ( !strcmp( token, "*MESH_NUMFACES" ) )
{
ASE_GetToken( qfalse );
pMesh->numFaces = atoi( s_token );
VERBOSE( ( ".....num faces: %d\n", pMesh->numFaces ) );
}
else if ( !strcmp( token, "*MESH_NUMTVFACES" ) )
{
ASE_GetToken( qfalse );
if ( atoi( s_token ) != pMesh->numFaces )
{
Error( "MESH_NUMTVFACES != MESH_NUMFACES" );
}
}
else if ( !strcmp( token, "*MESH_NUMTVERTEX" ) )
{
ASE_GetToken( qfalse );
pMesh->numTVertexes = atoi( s_token );
VERBOSE( ( ".....num tvertexes: %d\n", pMesh->numTVertexes ) );
}
else if ( !strcmp( token, "*MESH_VERTEX_LIST" ) )
{
pMesh->vertexes = calloc( sizeof( aseVertex_t ) * pMesh->numVertexes, 1 );
pMesh->currentVertex = 0;
VERBOSE( ( ".....parsing MESH_VERTEX_LIST\n" ) );
ASE_ParseBracedBlock( ASE_KeyMESH_VERTEX_LIST );
}
else if ( !strcmp( token, "*MESH_TVERTLIST" ) )
{
pMesh->currentVertex = 0;
pMesh->tvertexes = calloc( sizeof( aseTVertex_t ) * pMesh->numTVertexes, 1 );
VERBOSE( ( ".....parsing MESH_TVERTLIST\n" ) );
ASE_ParseBracedBlock( ASE_KeyMESH_TVERTLIST );
}
else if ( !strcmp( token, "*MESH_FACE_LIST" ) )
{
pMesh->faces = calloc( sizeof( aseFace_t ) * pMesh->numFaces, 1 );
pMesh->currentFace = 0;
VERBOSE( ( ".....parsing MESH_FACE_LIST\n" ) );
ASE_ParseBracedBlock( ASE_KeyMESH_FACE_LIST );
}
else if ( !strcmp( token, "*MESH_TFACELIST" ) )
{
pMesh->tfaces = calloc( sizeof( aseFace_t ) * pMesh->numFaces, 1 );
pMesh->currentFace = 0;
VERBOSE( ( ".....parsing MESH_TFACE_LIST\n" ) );
ASE_ParseBracedBlock( ASE_KeyTFACE_LIST );
}
else if ( !strcmp( token, "*MESH_NORMALS" ) )
{
ASE_ParseBracedBlock( 0 );
}
}
static void ASE_KeyMESH_ANIMATION( const char *token )
{
aseMesh_t *pMesh = ASE_GetCurrentMesh();
// loads a single animation frame
if ( !strcmp( token, "*MESH" ) )
{
VERBOSE( ( "...found MESH\n" ) );
assert( pMesh->faces == 0 );
assert( pMesh->vertexes == 0 );
assert( pMesh->tvertexes == 0 );
memset( pMesh, 0, sizeof( *pMesh ) );
ASE_ParseBracedBlock( ASE_KeyMESH );
if ( ++ase.objects[ase.currentObject].anim.currentFrame == MAX_ASE_ANIMATION_FRAMES )
{
Error( "Too many animation frames" );
}
}
else
{
Error( "Unknown token '%s' while parsing MESH_ANIMATION", token );
}
}
static void ASE_KeyGEOMOBJECT( const char *token )
{
if ( !strcmp( token, "*NODE_NAME" ) )
{
char *name = ase.objects[ase.currentObject].name;
ASE_GetToken( qtrue );
VERBOSE( ( " %s\n", s_token ) );
strcpy( ase.objects[ase.currentObject].name, s_token + 1 );
if ( strchr( ase.objects[ase.currentObject].name, '"' ) )
*strchr( ase.objects[ase.currentObject].name, '"' ) = 0;
if ( strstr( name, "tag" ) == name )
{
while ( strchr( name, '_' ) != strrchr( name, '_' ) )
{
*strrchr( name, '_' ) = 0;
}
while ( strrchr( name, ' ' ) )
{
*strrchr( name, ' ' ) = 0;
}
}
}
else if ( !strcmp( token, "*NODE_PARENT" ) )
{
ASE_SkipRestOfLine();
}
// ignore unused data blocks
else if ( !strcmp( token, "*NODE_TM" ) ||
!strcmp( token, "*TM_ANIMATION" ) )
{
ASE_ParseBracedBlock( 0 );
}
// ignore regular meshes that aren't part of animation
else if ( !strcmp( token, "*MESH" ) && !ase.grabAnims )
{
/*
if ( strstr( ase.objects[ase.currentObject].name, "tag_" ) == ase.objects[ase.currentObject].name )
{
s_forceStaticMesh = true;
ASE_ParseBracedBlock( ASE_KeyMESH );
s_forceStaticMesh = false;
}
*/
ASE_ParseBracedBlock( ASE_KeyMESH );
if ( ++ase.objects[ase.currentObject].anim.currentFrame == MAX_ASE_ANIMATION_FRAMES )
{
Error( "Too many animation frames" );
}
ase.objects[ase.currentObject].anim.numFrames = ase.objects[ase.currentObject].anim.currentFrame;
ase.objects[ase.currentObject].numAnimations++;
/*
// ignore meshes that aren't part of animations if this object isn't a
// a tag
else
{
ASE_ParseBracedBlock( 0 );
}
*/
}
// according to spec these are obsolete
else if ( !strcmp( token, "*MATERIAL_REF" ) )
{
ASE_GetToken( qfalse );
ase.objects[ase.currentObject].materialRef = atoi( s_token );
}
// loads a sequence of animation frames
else if ( !strcmp( token, "*MESH_ANIMATION" ) )
{
if ( ase.grabAnims )
{
VERBOSE( ( "..found MESH_ANIMATION\n" ) );
if ( ase.objects[ase.currentObject].numAnimations )
{
Error( "Multiple MESH_ANIMATIONS within a single GEOM_OBJECT" );
}
ASE_ParseBracedBlock( ASE_KeyMESH_ANIMATION );
ase.objects[ase.currentObject].anim.numFrames = ase.objects[ase.currentObject].anim.currentFrame;
ase.objects[ase.currentObject].numAnimations++;
}
else
{
ASE_SkipEnclosingBraces();
}
}
// skip unused info
else if ( !strcmp( token, "*PROP_MOTIONBLUR" ) ||
!strcmp( token, "*PROP_CASTSHADOW" ) ||
!strcmp( token, "*PROP_RECVSHADOW" ) )
{
ASE_SkipRestOfLine();
}
}
static void ConcatenateObjects( aseGeomObject_t *pObjA, aseGeomObject_t *pObjB )
{
}
static void CollapseObjects( void )
{
int i;
int numObjects = ase.currentObject;
for ( i = 0; i < numObjects; i++ )
{
int j;
// skip tags
if ( strstr( ase.objects[i].name, "tag" ) == ase.objects[i].name )
{
continue;
}
if ( !ase.objects[i].numAnimations )
{
continue;
}
for ( j = i + 1; j < numObjects; j++ )
{
if ( strstr( ase.objects[j].name, "tag" ) == ase.objects[j].name )
{
continue;
}
if ( ase.objects[i].materialRef == ase.objects[j].materialRef )
{
if ( ase.objects[j].numAnimations )
{
ConcatenateObjects( &ase.objects[i], &ase.objects[j] );
}
}
}
}
}
/*
** ASE_Process
*/
static void ASE_Process( void )
{
while ( ASE_GetToken( qfalse ) )
{
if ( !strcmp( s_token, "*3DSMAX_ASCIIEXPORT" ) ||
!strcmp( s_token, "*COMMENT" ) )
{
ASE_SkipRestOfLine();
}
else if ( !strcmp( s_token, "*SCENE" ) )
ASE_SkipEnclosingBraces();
else if ( !strcmp( s_token, "*MATERIAL_LIST" ) )
{
VERBOSE( ("MATERIAL_LIST\n") );
ASE_ParseBracedBlock( ASE_KeyMATERIAL_LIST );
}
else if ( !strcmp( s_token, "*GEOMOBJECT" ) )
{
VERBOSE( ("GEOMOBJECT" ) );
ASE_ParseBracedBlock( ASE_KeyGEOMOBJECT );
if ( strstr( ase.objects[ase.currentObject].name, "Bip" ) ||
strstr( ase.objects[ase.currentObject].name, "ignore_" ) )
{
ASE_FreeGeomObject( ase.currentObject );
VERBOSE( ( "(discarding BIP/ignore object)\n" ) );
}
else if ( ( strstr( ase.objects[ase.currentObject].name, "h_" ) != ase.objects[ase.currentObject].name ) &&
( strstr( ase.objects[ase.currentObject].name, "l_" ) != ase.objects[ase.currentObject].name ) &&
( strstr( ase.objects[ase.currentObject].name, "u_" ) != ase.objects[ase.currentObject].name ) &&
( strstr( ase.objects[ase.currentObject].name, "tag" ) != ase.objects[ase.currentObject].name ) &&
ase.grabAnims )
{
VERBOSE( ( "(ignoring improperly labeled object '%s')\n", ase.objects[ase.currentObject].name ) );
ASE_FreeGeomObject( ase.currentObject );
}
else
{
if ( ++ase.currentObject == MAX_ASE_OBJECTS )
{
Error( "Too many GEOMOBJECTs" );
}
}
}
else if ( s_token[0] )
{
printf( "Unknown token '%s'\n", s_token );
}
}
if ( !ase.currentObject )
Error( "No animation data!" );
CollapseObjects();
}

31
common/aselib.h Normal file
View file

@ -0,0 +1,31 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code 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.
Quake III Arena source code 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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "cmdlib.h"
#include "mathlib.h"
#include "polyset.h"
void ASE_Load( const char *filename, qboolean verbose, qboolean meshanims );
int ASE_GetNumSurfaces( void );
polyset_t *ASE_GetSurfaceAnimation( int ndx, int *numFrames, int skipFrameStart, int skipFrameEnd, int maxFrames );
const char *ASE_GetSurfaceName( int ndx );
void ASE_Free( void );

564
common/bspfile.c Normal file
View file

@ -0,0 +1,564 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code 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.
Quake III Arena source code 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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "cmdlib.h"
#include "mathlib.h"
#include "bspfile.h"
#include "scriplib.h"
void GetLeafNums (void);
//=============================================================================
int nummodels;
dmodel_t dmodels[MAX_MAP_MODELS];
int numShaders;
dshader_t dshaders[MAX_MAP_SHADERS];
int entdatasize;
char dentdata[MAX_MAP_ENTSTRING];
int numleafs;
dleaf_t dleafs[MAX_MAP_LEAFS];
int numplanes;
dplane_t dplanes[MAX_MAP_PLANES];
int numnodes;
dnode_t dnodes[MAX_MAP_NODES];
int numleafsurfaces;
int dleafsurfaces[MAX_MAP_LEAFFACES];
int numleafbrushes;
int dleafbrushes[MAX_MAP_LEAFBRUSHES];
int numbrushes;
dbrush_t dbrushes[MAX_MAP_BRUSHES];
int numbrushsides;
dbrushside_t dbrushsides[MAX_MAP_BRUSHSIDES];
int numLightBytes;
byte lightBytes[MAX_MAP_LIGHTING];
int numGridPoints;
byte gridData[MAX_MAP_LIGHTGRID];
int numVisBytes;
byte visBytes[MAX_MAP_VISIBILITY];
int numDrawVerts;
drawVert_t drawVerts[MAX_MAP_DRAW_VERTS];
int numDrawIndexes;
int drawIndexes[MAX_MAP_DRAW_INDEXES];
int numDrawSurfaces;
dsurface_t drawSurfaces[MAX_MAP_DRAW_SURFS];
int numFogs;
dfog_t dfogs[MAX_MAP_FOGS];
//=============================================================================
/*
=============
SwapBlock
If all values are 32 bits, this can be used to swap everything
=============
*/
void SwapBlock( int *block, int sizeOfBlock ) {
int i;
sizeOfBlock >>= 2;
for ( i = 0 ; i < sizeOfBlock ; i++ ) {
block[i] = LittleLong( block[i] );
}
}
/*
=============
SwapBSPFile
Byte swaps all data in a bsp file.
=============
*/
void SwapBSPFile( void ) {
int i;
// models
SwapBlock( (int *)dmodels, nummodels * sizeof( dmodels[0] ) );
// shaders (don't swap the name)
for ( i = 0 ; i < numShaders ; i++ ) {
dshaders[i].contentFlags = LittleLong( dshaders[i].contentFlags );
dshaders[i].surfaceFlags = LittleLong( dshaders[i].surfaceFlags );
}
// planes
SwapBlock( (int *)dplanes, numplanes * sizeof( dplanes[0] ) );
// nodes
SwapBlock( (int *)dnodes, numnodes * sizeof( dnodes[0] ) );
// leafs
SwapBlock( (int *)dleafs, numleafs * sizeof( dleafs[0] ) );
// leaffaces
SwapBlock( (int *)dleafsurfaces, numleafsurfaces * sizeof( dleafsurfaces[0] ) );
// leafbrushes
SwapBlock( (int *)dleafbrushes, numleafbrushes * sizeof( dleafbrushes[0] ) );
// brushes
SwapBlock( (int *)dbrushes, numbrushes * sizeof( dbrushes[0] ) );
// brushsides
SwapBlock( (int *)dbrushsides, numbrushsides * sizeof( dbrushsides[0] ) );
// vis
((int *)&visBytes)[0] = LittleLong( ((int *)&visBytes)[0] );
((int *)&visBytes)[1] = LittleLong( ((int *)&visBytes)[1] );
// drawverts (don't swap colors )
for ( i = 0 ; i < numDrawVerts ; i++ ) {
drawVerts[i].lightmap[0] = LittleFloat( drawVerts[i].lightmap[0] );
drawVerts[i].lightmap[1] = LittleFloat( drawVerts[i].lightmap[1] );
drawVerts[i].st[0] = LittleFloat( drawVerts[i].st[0] );
drawVerts[i].st[1] = LittleFloat( drawVerts[i].st[1] );
drawVerts[i].xyz[0] = LittleFloat( drawVerts[i].xyz[0] );
drawVerts[i].xyz[1] = LittleFloat( drawVerts[i].xyz[1] );
drawVerts[i].xyz[2] = LittleFloat( drawVerts[i].xyz[2] );
drawVerts[i].normal[0] = LittleFloat( drawVerts[i].normal[0] );
drawVerts[i].normal[1] = LittleFloat( drawVerts[i].normal[1] );
drawVerts[i].normal[2] = LittleFloat( drawVerts[i].normal[2] );
}
// drawindexes
SwapBlock( (int *)drawIndexes, numDrawIndexes * sizeof( drawIndexes[0] ) );
// drawsurfs
SwapBlock( (int *)drawSurfaces, numDrawSurfaces * sizeof( drawSurfaces[0] ) );
// fogs
for ( i = 0 ; i < numFogs ; i++ ) {
dfogs[i].brushNum = LittleLong( dfogs[i].brushNum );
dfogs[i].visibleSide = LittleLong( dfogs[i].visibleSide );
}
}
/*
=============
CopyLump
=============
*/
int CopyLump( dheader_t *header, int lump, void *dest, int size ) {
int length, ofs;
length = header->lumps[lump].filelen;
ofs = header->lumps[lump].fileofs;
if ( length % size ) {
Error ("LoadBSPFile: odd lump size");
}
memcpy( dest, (byte *)header + ofs, length );
return length / size;
}
/*
=============
LoadBSPFile
=============
*/
void LoadBSPFile( const char *filename ) {
dheader_t *header;
// load the file header
LoadFile (filename, (void **)&header);
// swap the header
SwapBlock( (int *)header, sizeof(*header) );
if ( header->ident != BSP_IDENT ) {
Error( "%s is not a IBSP file", filename );
}
if ( header->version != BSP_VERSION ) {
Error( "%s is version %i, not %i", filename, header->version, BSP_VERSION );
}
numShaders = CopyLump( header, LUMP_SHADERS, dshaders, sizeof(dshader_t) );
nummodels = CopyLump( header, LUMP_MODELS, dmodels, sizeof(dmodel_t) );
numplanes = CopyLump( header, LUMP_PLANES, dplanes, sizeof(dplane_t) );
numleafs = CopyLump( header, LUMP_LEAFS, dleafs, sizeof(dleaf_t) );
numnodes = CopyLump( header, LUMP_NODES, dnodes, sizeof(dnode_t) );
numleafsurfaces = CopyLump( header, LUMP_LEAFSURFACES, dleafsurfaces, sizeof(dleafsurfaces[0]) );
numleafbrushes = CopyLump( header, LUMP_LEAFBRUSHES, dleafbrushes, sizeof(dleafbrushes[0]) );
numbrushes = CopyLump( header, LUMP_BRUSHES, dbrushes, sizeof(dbrush_t) );
numbrushsides = CopyLump( header, LUMP_BRUSHSIDES, dbrushsides, sizeof(dbrushside_t) );
numDrawVerts = CopyLump( header, LUMP_DRAWVERTS, drawVerts, sizeof(drawVert_t) );
numDrawSurfaces = CopyLump( header, LUMP_SURFACES, drawSurfaces, sizeof(dsurface_t) );
numFogs = CopyLump( header, LUMP_FOGS, dfogs, sizeof(dfog_t) );
numDrawIndexes = CopyLump( header, LUMP_DRAWINDEXES, drawIndexes, sizeof(drawIndexes[0]) );
numVisBytes = CopyLump( header, LUMP_VISIBILITY, visBytes, 1 );
numLightBytes = CopyLump( header, LUMP_LIGHTMAPS, lightBytes, 1 );
entdatasize = CopyLump( header, LUMP_ENTITIES, dentdata, 1);
numGridPoints = CopyLump( header, LUMP_LIGHTGRID, gridData, 8 );
free( header ); // everything has been copied out
// swap everything
SwapBSPFile();
}
//============================================================================
/*
=============
AddLump
=============
*/
void AddLump( FILE *bspfile, dheader_t *header, int lumpnum, const void *data, int len ) {
lump_t *lump;
lump = &header->lumps[lumpnum];
lump->fileofs = LittleLong( ftell(bspfile) );
lump->filelen = LittleLong( len );
SafeWrite( bspfile, data, (len+3)&~3 );
}
/*
=============
WriteBSPFile
Swaps the bsp file in place, so it should not be referenced again
=============
*/
void WriteBSPFile( const char *filename ) {
dheader_t outheader, *header;
FILE *bspfile;
header = &outheader;
memset( header, 0, sizeof(dheader_t) );
SwapBSPFile();
header->ident = LittleLong( BSP_IDENT );
header->version = LittleLong( BSP_VERSION );
bspfile = SafeOpenWrite( filename );
SafeWrite( bspfile, header, sizeof(dheader_t) ); // overwritten later
AddLump( bspfile, header, LUMP_SHADERS, dshaders, numShaders*sizeof(dshader_t) );
AddLump( bspfile, header, LUMP_PLANES, dplanes, numplanes*sizeof(dplane_t) );
AddLump( bspfile, header, LUMP_LEAFS, dleafs, numleafs*sizeof(dleaf_t) );
AddLump( bspfile, header, LUMP_NODES, dnodes, numnodes*sizeof(dnode_t) );
AddLump( bspfile, header, LUMP_BRUSHES, dbrushes, numbrushes*sizeof(dbrush_t) );
AddLump( bspfile, header, LUMP_BRUSHSIDES, dbrushsides, numbrushsides*sizeof(dbrushside_t) );
AddLump( bspfile, header, LUMP_LEAFSURFACES, dleafsurfaces, numleafsurfaces*sizeof(dleafsurfaces[0]) );
AddLump( bspfile, header, LUMP_LEAFBRUSHES, dleafbrushes, numleafbrushes*sizeof(dleafbrushes[0]) );
AddLump( bspfile, header, LUMP_MODELS, dmodels, nummodels*sizeof(dmodel_t) );
AddLump( bspfile, header, LUMP_DRAWVERTS, drawVerts, numDrawVerts*sizeof(drawVert_t) );
AddLump( bspfile, header, LUMP_SURFACES, drawSurfaces, numDrawSurfaces*sizeof(dsurface_t) );
AddLump( bspfile, header, LUMP_VISIBILITY, visBytes, numVisBytes );
AddLump( bspfile, header, LUMP_LIGHTMAPS, lightBytes, numLightBytes );
AddLump( bspfile, header, LUMP_LIGHTGRID, gridData, 8 * numGridPoints );
AddLump( bspfile, header, LUMP_ENTITIES, dentdata, entdatasize );
AddLump( bspfile, header, LUMP_FOGS, dfogs, numFogs * sizeof(dfog_t) );
AddLump( bspfile, header, LUMP_DRAWINDEXES, drawIndexes, numDrawIndexes * sizeof(drawIndexes[0]) );
fseek (bspfile, 0, SEEK_SET);
SafeWrite (bspfile, header, sizeof(dheader_t));
fclose (bspfile);
}
//============================================================================
/*
=============
PrintBSPFileSizes
Dumps info about current file
=============
*/
void PrintBSPFileSizes( void ) {
if ( !num_entities ) {
ParseEntities();
}
printf ("%6i models %7i\n"
,nummodels, (int)(nummodels*sizeof(dmodel_t)));
printf ("%6i shaders %7i\n"
,numShaders, (int)(numShaders*sizeof(dshader_t)));
printf ("%6i brushes %7i\n"
,numbrushes, (int)(numbrushes*sizeof(dbrush_t)));
printf ("%6i brushsides %7i\n"
,numbrushsides, (int)(numbrushsides*sizeof(dbrushside_t)));
printf ("%6i fogs %7i\n"
,numFogs, (int)(numFogs*sizeof(dfog_t)));
printf ("%6i planes %7i\n"
,numplanes, (int)(numplanes*sizeof(dplane_t)));
printf ("%6i entdata %7i\n", num_entities, entdatasize);
printf ("\n");
printf ("%6i nodes %7i\n"
,numnodes, (int)(numnodes*sizeof(dnode_t)));
printf ("%6i leafs %7i\n"
,numleafs, (int)(numleafs*sizeof(dleaf_t)));
printf ("%6i leafsurfaces %7i\n"
,numleafsurfaces, (int)(numleafsurfaces*sizeof(dleafsurfaces[0])));
printf ("%6i leafbrushes %7i\n"
,numleafbrushes, (int)(numleafbrushes*sizeof(dleafbrushes[0])));
printf ("%6i drawverts %7i\n"
,numDrawVerts, (int)(numDrawVerts*sizeof(drawVerts[0])));
printf ("%6i drawindexes %7i\n"
,numDrawIndexes, (int)(numDrawIndexes*sizeof(drawIndexes[0])));
printf ("%6i drawsurfaces %7i\n"
,numDrawSurfaces, (int)(numDrawSurfaces*sizeof(drawSurfaces[0])));
printf ("%6i lightmaps %7i\n"
,numLightBytes / (LIGHTMAP_WIDTH*LIGHTMAP_HEIGHT*3), numLightBytes );
printf (" visibility %7i\n"
, numVisBytes );
}
//============================================
int num_entities;
entity_t entities[MAX_MAP_ENTITIES];
void StripTrailing( char *e ) {
char *s;
s = e + strlen(e)-1;
while (s >= e && *s <= 32)
{
*s = 0;
s--;
}
}
/*
=================
ParseEpair
=================
*/
epair_t *ParseEpair( void ) {
epair_t *e;
e = malloc( sizeof(epair_t) );
memset( e, 0, sizeof(epair_t) );
if ( strlen(token) >= MAX_KEY-1 ) {
Error ("ParseEpar: token too long");
}
e->key = copystring( token );
GetToken( qfalse );
if ( strlen(token) >= MAX_VALUE-1 ) {
Error ("ParseEpar: token too long");
}
e->value = copystring( token );
// strip trailing spaces that sometimes get accidentally
// added in the editor
StripTrailing( e->key );
StripTrailing( e->value );
return e;
}
/*
================
ParseEntity
================
*/
qboolean ParseEntity( void ) {
epair_t *e;
entity_t *mapent;
if ( !GetToken (qtrue) ) {
return qfalse;
}
if ( strcmp (token, "{") ) {
Error ("ParseEntity: { not found");
}
if ( num_entities == MAX_MAP_ENTITIES ) {
Error ("num_entities == MAX_MAP_ENTITIES");
}
mapent = &entities[num_entities];
num_entities++;
do {
if ( !GetToken (qtrue) ) {
Error ("ParseEntity: EOF without closing brace");
}
if ( !strcmp (token, "}") ) {
break;
}
e = ParseEpair ();
e->next = mapent->epairs;
mapent->epairs = e;
} while (1);
return qtrue;
}
/*
================
ParseEntities
Parses the dentdata string into entities
================
*/
void ParseEntities( void ) {
num_entities = 0;
ParseFromMemory( dentdata, entdatasize );
while ( ParseEntity () ) {
}
}
/*
================
UnparseEntities
Generates the dentdata string from all the entities
This allows the utilities to add or remove key/value pairs
to the data created by the map editor.
================
*/
void UnparseEntities( void ) {
char *buf, *end;
epair_t *ep;
char line[2048];
int i;
char key[1024], value[1024];
buf = dentdata;
end = buf;
*end = 0;
for (i=0 ; i<num_entities ; i++) {
ep = entities[i].epairs;
if ( !ep ) {
continue; // ent got removed
}
strcat (end,"{\n");
end += 2;
for ( ep = entities[i].epairs ; ep ; ep=ep->next ) {
strcpy (key, ep->key);
StripTrailing (key);
strcpy (value, ep->value);
StripTrailing (value);
sprintf (line, "\"%s\" \"%s\"\n", key, value);
strcat (end, line);
end += strlen(line);
}
strcat (end,"}\n");
end += 2;
if (end > buf + MAX_MAP_ENTSTRING) {
Error ("Entity text too long");
}
}
entdatasize = end - buf + 1;
}
void PrintEntity( const entity_t *ent ) {
epair_t *ep;
printf ("------- entity %p -------\n", ent);
for (ep=ent->epairs ; ep ; ep=ep->next) {
printf( "%s = %s\n", ep->key, ep->value );
}
}
void SetKeyValue( entity_t *ent, const char *key, const char *value ) {
epair_t *ep;
for ( ep=ent->epairs ; ep ; ep=ep->next ) {
if ( !strcmp (ep->key, key) ) {
free (ep->value);
ep->value = copystring(value);
return;
}
}
ep = malloc (sizeof(*ep));
ep->next = ent->epairs;
ent->epairs = ep;
ep->key = copystring(key);
ep->value = copystring(value);
}
const char *ValueForKey( const entity_t *ent, const char *key ) {
epair_t *ep;
for (ep=ent->epairs ; ep ; ep=ep->next) {
if (!strcmp (ep->key, key) ) {
return ep->value;
}
}
return "";
}
vec_t FloatForKey( const entity_t *ent, const char *key ) {
const char *k;
k = ValueForKey( ent, key );
return atof(k);
}
void GetVectorForKey( const entity_t *ent, const char *key, vec3_t vec ) {
const char *k;
double v1, v2, v3;
k = ValueForKey (ent, key);
// scanf into doubles, then assign, so it is vec_t size independent
v1 = v2 = v3 = 0;
sscanf (k, "%lf %lf %lf", &v1, &v2, &v3);
vec[0] = v1;
vec[1] = v2;
vec[2] = v3;
}

118
common/bspfile.h Normal file
View file

@ -0,0 +1,118 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code 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.
Quake III Arena source code 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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#ifdef _TTIMOBUILD
#include "qfiles.h"
#include "surfaceflags.h"
#else
#include "../code/qcommon/qfiles.h"
#include "../code/game/surfaceflags.h"
#endif
extern int nummodels;
extern dmodel_t dmodels[MAX_MAP_MODELS];
extern int numShaders;
extern dshader_t dshaders[MAX_MAP_MODELS];
extern int entdatasize;
extern char dentdata[MAX_MAP_ENTSTRING];
extern int numleafs;
extern dleaf_t dleafs[MAX_MAP_LEAFS];
extern int numplanes;
extern dplane_t dplanes[MAX_MAP_PLANES];
extern int numnodes;
extern dnode_t dnodes[MAX_MAP_NODES];
extern int numleafsurfaces;
extern int dleafsurfaces[MAX_MAP_LEAFFACES];
extern int numleafbrushes;
extern int dleafbrushes[MAX_MAP_LEAFBRUSHES];
extern int numbrushes;
extern dbrush_t dbrushes[MAX_MAP_BRUSHES];
extern int numbrushsides;
extern dbrushside_t dbrushsides[MAX_MAP_BRUSHSIDES];
extern int numLightBytes;
extern byte lightBytes[MAX_MAP_LIGHTING];
extern int numGridPoints;
extern byte gridData[MAX_MAP_LIGHTGRID];
extern int numVisBytes;
extern byte visBytes[MAX_MAP_VISIBILITY];
extern int numDrawVerts;
extern drawVert_t drawVerts[MAX_MAP_DRAW_VERTS];
extern int numDrawIndexes;
extern int drawIndexes[MAX_MAP_DRAW_INDEXES];
extern int numDrawSurfaces;
extern dsurface_t drawSurfaces[MAX_MAP_DRAW_SURFS];
extern int numFogs;
extern dfog_t dfogs[MAX_MAP_FOGS];
void LoadBSPFile( const char *filename );
void WriteBSPFile( const char *filename );
void PrintBSPFileSizes( void );
//===============
typedef struct epair_s {
struct epair_s *next;
char *key;
char *value;
} epair_t;
typedef struct {
vec3_t origin;
struct bspbrush_s *brushes;
struct parseMesh_s *patches;
int firstDrawSurf;
epair_t *epairs;
} entity_t;
extern int num_entities;
extern entity_t entities[MAX_MAP_ENTITIES];
void ParseEntities( void );
void UnparseEntities( void );
void SetKeyValue( entity_t *ent, const char *key, const char *value );
const char *ValueForKey( const entity_t *ent, const char *key );
// will return "" if not present
vec_t FloatForKey( const entity_t *ent, const char *key );
void GetVectorForKey( const entity_t *ent, const char *key, vec3_t vec );
epair_t *ParseEpair( void );
void PrintEntity( const entity_t *ent );

1201
common/cmdlib.c Normal file

File diff suppressed because it is too large Load diff

160
common/cmdlib.h Normal file
View file

@ -0,0 +1,160 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code 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.
Quake III Arena source code 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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// cmdlib.h
#ifndef __CMDLIB__
#define __CMDLIB__
#ifdef _WIN32
#pragma warning(disable : 4244) // MIPS
#pragma warning(disable : 4136) // X86
#pragma warning(disable : 4051) // ALPHA
#pragma warning(disable : 4018) // signed/unsigned mismatch
#pragma warning(disable : 4305) // truncate from double to float
#pragma check_stack(off)
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
#include <time.h>
#include <stdarg.h>
#ifdef _WIN32
#pragma intrinsic( memset, memcpy )
#endif
#ifndef __BYTEBOOL__
#define __BYTEBOOL__
typedef enum { qfalse, qtrue } qboolean;
typedef unsigned char byte;
#endif
#define MAX_OS_PATH 1024
#define MEM_BLOCKSIZE 4096
// the dec offsetof macro doesnt work very well...
#define myoffsetof(type,identifier) ((size_t)&((type *)0)->identifier)
// set these before calling CheckParm
extern int myargc;
extern char **myargv;
char *strupr (char *in);
char *strlower (char *in);
int Q_strncasecmp( const char *s1, const char *s2, int n );
int Q_stricmp( const char *s1, const char *s2 );
void Q_getwd( char *out );
int Q_filelength (FILE *f);
int FileTime( const char *path );
void Q_mkdir( const char *path );
extern char qdir[1024];
extern char gamedir[1024];
extern char writedir[1024];
void SetQdirFromPath( const char *path );
char *ExpandArg( const char *path ); // from cmd line
char *ExpandPath( const char *path ); // from scripts
char *ExpandGamePath (const char *path);
char *ExpandPathAndArchive( const char *path );
double I_FloatTime( void );
void Error( const char *error, ... );
int CheckParm( const char *check );
FILE *SafeOpenWrite( const char *filename );
FILE *SafeOpenRead( const char *filename );
void SafeRead (FILE *f, void *buffer, int count);
void SafeWrite (FILE *f, const void *buffer, int count);
int LoadFile( const char *filename, void **bufferptr );
int LoadFileBlock( const char *filename, void **bufferptr );
int TryLoadFile( const char *filename, void **bufferptr );
void SaveFile( const char *filename, const void *buffer, int count );
qboolean FileExists( const char *filename );
void DefaultExtension( char *path, const char *extension );
void DefaultPath( char *path, const char *basepath );
void StripFilename( char *path );
void StripExtension( char *path );
void ExtractFilePath( const char *path, char *dest );
void ExtractFileBase( const char *path, char *dest );
void ExtractFileExtension( const char *path, char *dest );
int ParseNum (const char *str);
short BigShort (short l);
short LittleShort (short l);
int BigLong (int l);
int LittleLong (int l);
float BigFloat (float l);
float LittleFloat (float l);
char *COM_Parse (char *data);
extern char com_token[1024];
extern qboolean com_eof;
char *copystring(const char *s);
void CRC_Init(unsigned short *crcvalue);
void CRC_ProcessByte(unsigned short *crcvalue, byte data);
unsigned short CRC_Value(unsigned short crcvalue);
void CreatePath( const char *path );
void QCopyFile( const char *from, const char *to );
extern qboolean archive;
extern char archivedir[1024];
extern qboolean verbose;
void qprintf( const char *format, ... );
void _printf( const char *format, ... );
void ExpandWildcards( int *argc, char ***argv );
// for compression routines
typedef struct
{
void *data;
int count, width, height;
} cblock_t;
#endif

1164
common/imagelib.c Normal file

File diff suppressed because it is too large Load diff

44
common/imagelib.h Normal file
View file

@ -0,0 +1,44 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code 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.
Quake III Arena source code 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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// piclib.h
void LoadLBM (const char *filename, byte **picture, byte **palette);
void WriteLBMfile (const char *filename, byte *data, int width, int height
, byte *palette);
void LoadPCX (const char *filename, byte **picture, byte **palette, int *width, int *height);
void WritePCXfile (const char *filename, byte *data, int width, int height
, byte *palette);
// loads / saves either lbm or pcx, depending on extension
void Load256Image (const char *name, byte **pixels, byte **palette,
int *width, int *height);
void Save256Image (const char *name, byte *pixels, byte *palette,
int width, int height);
void LoadTGA (const char *filename, byte **pixels, int *width, int *height);
void LoadTGABuffer ( byte *buffer, byte **pic, int *width, int *height);
void WriteTGA (const char *filename, byte *data, int width, int height);
void Load32BitImage (const char *name, unsigned **pixels, int *width, int *height);

300
common/l3dslib.c Normal file
View file

@ -0,0 +1,300 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code 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.
Quake III Arena source code 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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
// l3dslib.c: library for loading triangles from an Alias triangle file
//
#include <stdio.h>
#include "cmdlib.h"
#include "mathlib.h"
#include "trilib.h"
#include "l3dslib.h"
#define MAIN3DS 0x4D4D
#define EDIT3DS 0x3D3D // this is the start of the editor config
#define EDIT_OBJECT 0x4000
#define OBJ_TRIMESH 0x4100
#define TRI_VERTEXL 0x4110
#define TRI_FACEL1 0x4120
#define MAXVERTS 2000
typedef struct {
int v[4];
} tri;
float fverts[MAXVERTS][3];
tri tris[MAXTRIANGLES];
int bytesread, level, numtris, totaltris;
int vertsfound, trisfound;
triangle_t *ptri;
// Alias stores triangles as 3 explicit vertices in .tri files, so even though we
// start out with a vertex pool and vertex indices for triangles, we have to convert
// to raw, explicit triangles
void StoreAliasTriangles (void)
{
int i, j, k;
if ((totaltris + numtris) > MAXTRIANGLES)
Error ("Error: Too many triangles");
for (i=0; i<numtris ; i++)
{
for (j=0 ; j<3 ; j++)
{
for (k=0 ; k<3 ; k++)
{
ptri[i+totaltris].verts[j][k] = fverts[tris[i].v[j]][k];
}
}
}
totaltris += numtris;
numtris = 0;
vertsfound = 0;
trisfound = 0;
}
int ParseVertexL (FILE *input)
{
int i, j, startbytesread, numverts;
unsigned short tshort;
if (vertsfound)
Error ("Error: Multiple vertex chunks");
vertsfound = 1;
startbytesread = bytesread;
if (feof(input))
Error ("Error: unexpected end of file");
fread(&tshort, sizeof(tshort), 1, input);
bytesread += sizeof(tshort);
numverts = (int)tshort;
if (numverts > MAXVERTS)
Error ("Error: Too many vertices");
for (i=0 ; i<numverts ; i++)
{
for (j=0 ; j<3 ; j++)
{
if (feof(input))
Error ("Error: unexpected end of file");
fread(&fverts[i][j], sizeof(float), 1, input);
bytesread += sizeof(float);
}
}
if (vertsfound && trisfound)
StoreAliasTriangles ();
return bytesread - startbytesread;
}
int ParseFaceL1 (FILE *input)
{
int i, j, startbytesread;
unsigned short tshort;
if (trisfound)
Error ("Error: Multiple face chunks");
trisfound = 1;
startbytesread = bytesread;
if (feof(input))
Error ("Error: unexpected end of file");
fread(&tshort, sizeof(tshort), 1, input);
bytesread += sizeof(tshort);
numtris = (int)tshort;
if (numtris > MAXTRIANGLES)
Error ("Error: Too many triangles");
for (i=0 ; i<numtris ; i++)
{
for (j=0 ; j<4 ; j++)
{
if (feof(input))
Error ("Error: unexpected end of file");
fread(&tshort, sizeof(tshort), 1, input);
bytesread += sizeof(tshort);
tris[i].v[j] = (int)tshort;
}
}
if (vertsfound && trisfound)
StoreAliasTriangles ();
return bytesread - startbytesread;
}
int ParseChunk (FILE *input)
{
#define BLOCK_SIZE 4096
char temp[BLOCK_SIZE];
unsigned short type;
int i, length, w, t, retval;
level++;
retval = 0;
// chunk type
if (feof(input))
Error ("Error: unexpected end of file");
fread(&type, sizeof(type), 1, input);
bytesread += sizeof(type);
// chunk length
if (feof(input))
Error ("Error: unexpected end of file");
fread (&length, sizeof(length), 1, input);
bytesread += sizeof(length);
w = length - 6;
// process chunk if we care about it, otherwise skip it
switch (type)
{
case TRI_VERTEXL:
w -= ParseVertexL (input);
goto ParseSubchunk;
case TRI_FACEL1:
w -= ParseFaceL1 (input);
goto ParseSubchunk;
case EDIT_OBJECT:
// read the name
i = 0;
do
{
if (feof(input))
Error ("Error: unexpected end of file");
fread (&temp[i], 1, 1, input);
i++;
w--;
bytesread++;
} while (temp[i-1]);
case MAIN3DS:
case OBJ_TRIMESH:
case EDIT3DS:
// parse through subchunks
ParseSubchunk:
while (w > 0)
{
w -= ParseChunk (input);
}
retval = length;
goto Done;
default:
// skip other chunks
while (w > 0)
{
t = w;
if (t > BLOCK_SIZE)
t = BLOCK_SIZE;
if (feof(input))
Error ("Error: unexpected end of file");
fread (&temp, t, 1, input);
bytesread += t;
w -= t;
}
retval = length;
goto Done;
}
Done:
level--;
return retval;
}
void Load3DSTriangleList (char *filename, triangle_t **pptri, int *numtriangles)
{
FILE *input;
short int tshort;
bytesread = 0;
level = 0;
numtris = 0;
totaltris = 0;
vertsfound = 0;
trisfound = 0;
if ((input = fopen(filename, "rb")) == 0) {
fprintf(stderr,"reader: could not open file '%s'\n", filename);
exit(0);
}
fread(&tshort, sizeof(tshort), 1, input);
// should only be MAIN3DS, but some files seem to start with EDIT3DS, with
// no MAIN3DS
if ((tshort != MAIN3DS) && (tshort != EDIT3DS)) {
fprintf(stderr,"File is not a 3DS file.\n");
exit(0);
}
// back to top of file so we can parse the first chunk descriptor
fseek(input, 0, SEEK_SET);
ptri = malloc (MAXTRIANGLES * sizeof(triangle_t));
*pptri = ptri;
// parse through looking for the relevant chunk tree (MAIN3DS | EDIT3DS | EDIT_OBJECT |
// OBJ_TRIMESH | {TRI_VERTEXL, TRI_FACEL1}) and skipping other chunks
ParseChunk (input);
if (vertsfound || trisfound)
Error ("Incomplete triangle set");
*numtriangles = totaltris;
fclose (input);
}

26
common/l3dslib.h Normal file
View file

@ -0,0 +1,26 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code 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.
Quake III Arena source code 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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
// l3dslib.h: header file for loading triangles from a 3DS triangle file
//
void Load3DSTriangleList (char *filename, triangle_t **pptri, int *numtriangles);

434
common/mathlib.c Normal file
View file

@ -0,0 +1,434 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code 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.
Quake III Arena source code 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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// mathlib.c -- math primitives
#include "cmdlib.h"
#include "mathlib.h"
#ifdef _WIN32
//Improve floating-point consistency.
//without this option weird floating point issues occur
#pragma optimize( "p", on )
#endif
vec3_t vec3_origin = {0,0,0};
/*
** NormalToLatLong
**
** We use two byte encoded normals in some space critical applications.
** Lat = 0 at (1,0,0) to 360 (-1,0,0), encoded in 8-bit sine table format
** Lng = 0 at (0,0,1) to 180 (0,0,-1), encoded in 8-bit sine table format
**
*/
void NormalToLatLong( const vec3_t normal, byte bytes[2] ) {
// check for singularities
if ( normal[0] == 0 && normal[1] == 0 ) {
if ( normal[2] > 0 ) {
bytes[0] = 0;
bytes[1] = 0; // lat = 0, long = 0
} else {
bytes[0] = 128;
bytes[1] = 0; // lat = 0, long = 128
}
} else {
int a, b;
a = RAD2DEG( atan2( normal[1], normal[0] ) ) * (255.0f / 360.0f );
a &= 0xff;
b = RAD2DEG( acos( normal[2] ) ) * ( 255.0f / 360.0f );
b &= 0xff;
bytes[0] = b; // longitude
bytes[1] = a; // lattitude
}
}
/*
=====================
PlaneFromPoints
Returns false if the triangle is degenrate.
The normal will point out of the clock for clockwise ordered points
=====================
*/
qboolean PlaneFromPoints( vec4_t plane, const vec3_t a, const vec3_t b, const vec3_t c ) {
vec3_t d1, d2;
VectorSubtract( b, a, d1 );
VectorSubtract( c, a, d2 );
CrossProduct( d2, d1, plane );
if ( VectorNormalize( plane, plane ) == 0 ) {
return qfalse;
}
plane[3] = DotProduct( a, plane );
return qtrue;
}
/*
================
MakeNormalVectors
Given a normalized forward vector, create two
other perpendicular vectors
================
*/
void MakeNormalVectors (vec3_t forward, vec3_t right, vec3_t up)
{
float d;
// this rotate and negate guarantees a vector
// not colinear with the original
right[1] = -forward[0];
right[2] = forward[1];
right[0] = forward[2];
d = DotProduct (right, forward);
VectorMA (right, -d, forward, right);
VectorNormalize (right, right);
CrossProduct (right, forward, up);
}
void Vec10Copy( vec_t *in, vec_t *out ) {
out[0] = in[0];
out[1] = in[1];
out[2] = in[2];
out[3] = in[3];
out[4] = in[4];
out[5] = in[5];
out[6] = in[6];
out[7] = in[7];
out[8] = in[8];
out[9] = in[9];
}
void VectorRotate3x3( vec3_t v, float r[3][3], vec3_t d )
{
d[0] = v[0] * r[0][0] + v[1] * r[1][0] + v[2] * r[2][0];
d[1] = v[0] * r[0][1] + v[1] * r[1][1] + v[2] * r[2][1];
d[2] = v[0] * r[0][2] + v[1] * r[1][2] + v[2] * r[2][2];
}
double VectorLength( const vec3_t v ) {
int i;
double length;
length = 0;
for (i=0 ; i< 3 ; i++)
length += v[i]*v[i];
length = sqrt (length); // FIXME
return length;
}
qboolean VectorCompare( const vec3_t v1, const vec3_t v2 ) {
int i;
for (i=0 ; i<3 ; i++)
if (fabs(v1[i]-v2[i]) > EQUAL_EPSILON)
return qfalse;
return qtrue;
}
vec_t Q_rint (vec_t in)
{
return floor (in + 0.5);
}
void VectorMA( const vec3_t va, double scale, const vec3_t vb, vec3_t vc ) {
vc[0] = va[0] + scale*vb[0];
vc[1] = va[1] + scale*vb[1];
vc[2] = va[2] + scale*vb[2];
}
void CrossProduct( const vec3_t v1, const vec3_t v2, vec3_t cross ) {
cross[0] = v1[1]*v2[2] - v1[2]*v2[1];
cross[1] = v1[2]*v2[0] - v1[0]*v2[2];
cross[2] = v1[0]*v2[1] - v1[1]*v2[0];
}
vec_t _DotProduct (vec3_t v1, vec3_t v2)
{
return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
}
void _VectorSubtract (vec3_t va, vec3_t vb, vec3_t out)
{
out[0] = va[0]-vb[0];
out[1] = va[1]-vb[1];
out[2] = va[2]-vb[2];
}
void _VectorAdd (vec3_t va, vec3_t vb, vec3_t out)
{
out[0] = va[0]+vb[0];
out[1] = va[1]+vb[1];
out[2] = va[2]+vb[2];
}
void _VectorCopy (vec3_t in, vec3_t out)
{
out[0] = in[0];
out[1] = in[1];
out[2] = in[2];
}
void _VectorScale (vec3_t v, vec_t scale, vec3_t out)
{
out[0] = v[0] * scale;
out[1] = v[1] * scale;
out[2] = v[2] * scale;
}
vec_t VectorNormalize( const vec3_t in, vec3_t out ) {
vec_t length, ilength;
length = sqrt (in[0]*in[0] + in[1]*in[1] + in[2]*in[2]);
if (length == 0)
{
VectorClear (out);
return 0;
}
ilength = 1.0/length;
out[0] = in[0]*ilength;
out[1] = in[1]*ilength;
out[2] = in[2]*ilength;
return length;
}
vec_t ColorNormalize( const vec3_t in, vec3_t out ) {
float max, scale;
max = in[0];
if (in[1] > max)
max = in[1];
if (in[2] > max)
max = in[2];
if (max == 0) {
out[0] = out[1] = out[2] = 1.0;
return 0;
}
scale = 1.0 / max;
VectorScale (in, scale, out);
return max;
}
void VectorInverse (vec3_t v)
{
v[0] = -v[0];
v[1] = -v[1];
v[2] = -v[2];
}
void ClearBounds (vec3_t mins, vec3_t maxs)
{
mins[0] = mins[1] = mins[2] = 99999;
maxs[0] = maxs[1] = maxs[2] = -99999;
}
void AddPointToBounds( const vec3_t v, vec3_t mins, vec3_t maxs ) {
int i;
vec_t val;
for (i=0 ; i<3 ; i++)
{
val = v[i];
if (val < mins[i])
mins[i] = val;
if (val > maxs[i])
maxs[i] = val;
}
}
/*
=================
PlaneTypeForNormal
=================
*/
int PlaneTypeForNormal (vec3_t normal) {
if (normal[0] == 1.0 || normal[0] == -1.0)
return PLANE_X;
if (normal[1] == 1.0 || normal[1] == -1.0)
return PLANE_Y;
if (normal[2] == 1.0 || normal[2] == -1.0)
return PLANE_Z;
return PLANE_NON_AXIAL;
}
/*
================
MatrixMultiply
================
*/
void MatrixMultiply(float in1[3][3], float in2[3][3], float out[3][3]) {
out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] +
in1[0][2] * in2[2][0];
out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] +
in1[0][2] * in2[2][1];
out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] +
in1[0][2] * in2[2][2];
out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] +
in1[1][2] * in2[2][0];
out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] +
in1[1][2] * in2[2][1];
out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] +
in1[1][2] * in2[2][2];
out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] +
in1[2][2] * in2[2][0];
out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] +
in1[2][2] * in2[2][1];
out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] +
in1[2][2] * in2[2][2];
}
void ProjectPointOnPlane( vec3_t dst, const vec3_t p, const vec3_t normal )
{
float d;
vec3_t n;
float inv_denom;
inv_denom = 1.0F / DotProduct( normal, normal );
d = DotProduct( normal, p ) * inv_denom;
n[0] = normal[0] * inv_denom;
n[1] = normal[1] * inv_denom;
n[2] = normal[2] * inv_denom;
dst[0] = p[0] - d * n[0];
dst[1] = p[1] - d * n[1];
dst[2] = p[2] - d * n[2];
}
/*
** assumes "src" is normalized
*/
void PerpendicularVector( vec3_t dst, const vec3_t src )
{
int pos;
int i;
float minelem = 1.0F;
vec3_t tempvec;
/*
** find the smallest magnitude axially aligned vector
*/
for ( pos = 0, i = 0; i < 3; i++ )
{
if ( fabs( src[i] ) < minelem )
{
pos = i;
minelem = fabs( src[i] );
}
}
tempvec[0] = tempvec[1] = tempvec[2] = 0.0F;
tempvec[pos] = 1.0F;
/*
** project the point onto the plane defined by src
*/
ProjectPointOnPlane( dst, tempvec, src );
/*
** normalize the result
*/
VectorNormalize( dst, dst );
}
/*
===============
RotatePointAroundVector
This is not implemented very well...
===============
*/
void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point,
float degrees ) {
float m[3][3];
float im[3][3];
float zrot[3][3];
float tmpmat[3][3];
float rot[3][3];
int i;
vec3_t vr, vup, vf;
float rad;
vf[0] = dir[0];
vf[1] = dir[1];
vf[2] = dir[2];
PerpendicularVector( vr, dir );
CrossProduct( vr, vf, vup );
m[0][0] = vr[0];
m[1][0] = vr[1];
m[2][0] = vr[2];
m[0][1] = vup[0];
m[1][1] = vup[1];
m[2][1] = vup[2];
m[0][2] = vf[0];
m[1][2] = vf[1];
m[2][2] = vf[2];
memcpy( im, m, sizeof( im ) );
im[0][1] = m[1][0];
im[0][2] = m[2][0];
im[1][0] = m[0][1];
im[1][2] = m[2][1];
im[2][0] = m[0][2];
im[2][1] = m[1][2];
memset( zrot, 0, sizeof( zrot ) );
zrot[0][0] = zrot[1][1] = zrot[2][2] = 1.0F;
rad = DEG2RAD( degrees );
zrot[0][0] = cos( rad );
zrot[0][1] = sin( rad );
zrot[1][0] = -sin( rad );
zrot[1][1] = cos( rad );
MatrixMultiply( m, zrot, tmpmat );
MatrixMultiply( tmpmat, im, rot );
for ( i = 0; i < 3; i++ ) {
dst[i] = rot[i][0] * point[0] + rot[i][1] * point[1] + rot[i][2] * point[2];
}
}

96
common/mathlib.h Normal file
View file

@ -0,0 +1,96 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code 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.
Quake III Arena source code 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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#ifndef __MATHLIB__
#define __MATHLIB__
// mathlib.h
#include <math.h>
#ifdef DOUBLEVEC_T
typedef double vec_t;
#else
typedef float vec_t;
#endif
typedef vec_t vec2_t[3];
typedef vec_t vec3_t[3];
typedef vec_t vec4_t[4];
#define SIDE_FRONT 0
#define SIDE_ON 2
#define SIDE_BACK 1
#define SIDE_CROSS -2
#define Q_PI 3.14159265358979323846
#define DEG2RAD( a ) ( ( (a) * Q_PI ) / 180.0F )
#define RAD2DEG( a ) ( ( (a) * 180.0f ) / Q_PI )
extern vec3_t vec3_origin;
#define EQUAL_EPSILON 0.001
// plane types are used to speed some tests
// 0-2 are axial planes
#define PLANE_X 0
#define PLANE_Y 1
#define PLANE_Z 2
#define PLANE_NON_AXIAL 3
qboolean VectorCompare( const vec3_t v1, const vec3_t v2 );
#define DotProduct(x,y) (x[0]*y[0]+x[1]*y[1]+x[2]*y[2])
#define VectorSubtract(a,b,c) {c[0]=a[0]-b[0];c[1]=a[1]-b[1];c[2]=a[2]-b[2];}
#define VectorAdd(a,b,c) {c[0]=a[0]+b[0];c[1]=a[1]+b[1];c[2]=a[2]+b[2];}
#define VectorCopy(a,b) {b[0]=a[0];b[1]=a[1];b[2]=a[2];}
#define VectorScale(a,b,c) {c[0]=b*a[0];c[1]=b*a[1];c[2]=b*a[2];}
#define VectorClear(x) {x[0] = x[1] = x[2] = 0;}
#define VectorNegate(x) {x[0]=-x[0];x[1]=-x[1];x[2]=-x[2];}
void Vec10Copy( vec_t *in, vec_t *out );
vec_t Q_rint (vec_t in);
vec_t _DotProduct (vec3_t v1, vec3_t v2);
void _VectorSubtract (vec3_t va, vec3_t vb, vec3_t out);
void _VectorAdd (vec3_t va, vec3_t vb, vec3_t out);
void _VectorCopy (vec3_t in, vec3_t out);
void _VectorScale (vec3_t v, vec_t scale, vec3_t out);
double VectorLength( const vec3_t v );
void VectorMA( const vec3_t va, double scale, const vec3_t vb, vec3_t vc );
void CrossProduct( const vec3_t v1, const vec3_t v2, vec3_t cross );
vec_t VectorNormalize( const vec3_t in, vec3_t out );
vec_t ColorNormalize( const vec3_t in, vec3_t out );
void VectorInverse (vec3_t v);
void ClearBounds (vec3_t mins, vec3_t maxs);
void AddPointToBounds( const vec3_t v, vec3_t mins, vec3_t maxs );
qboolean PlaneFromPoints( vec4_t plane, const vec3_t a, const vec3_t b, const vec3_t c );
void NormalToLatLong( const vec3_t normal, byte bytes[2] );
int PlaneTypeForNormal (vec3_t normal);
void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point,
float degrees );
#endif

277
common/md4.c Normal file
View file

@ -0,0 +1,277 @@
/* GLOBAL.H - RSAREF types and constants */
#include <string.h>
/* POINTER defines a generic pointer type */
typedef unsigned char *POINTER;
/* UINT2 defines a two byte word */
typedef unsigned short int UINT2;
/* UINT4 defines a four byte word */
typedef unsigned long int UINT4;
/* MD4.H - header file for MD4C.C */
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991.
All rights reserved.
License to copy and use this software is granted provided that it is identified as the RSA Data Security, Inc. MD4 Message-Digest Algorithm in all material mentioning or referencing this software or this function.
License is also granted to make and use derivative works provided that such works are identified as derived from the RSA Data Security, Inc. MD4 Message-Digest Algorithm in all material mentioning or referencing the derived work.
RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided as is without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this documentation and/or software. */
/* MD4 context. */
typedef struct {
UINT4 state[4]; /* state (ABCD) */
UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
unsigned char buffer[64]; /* input buffer */
} MD4_CTX;
void MD4Init (MD4_CTX *);
void MD4Update (MD4_CTX *, unsigned char *, unsigned int);
void MD4Final (unsigned char [16], MD4_CTX *);
/* MD4C.C - RSA Data Security, Inc., MD4 message-digest algorithm */
/* Copyright (C) 1990-2, RSA Data Security, Inc. All rights reserved.
License to copy and use this software is granted provided that it is identified as the
RSA Data Security, Inc. MD4 Message-Digest Algorithm
in all material mentioning or referencing this software or this function.
License is also granted to make and use derivative works provided that such works are identified as
derived from the RSA Data Security, Inc. MD4 Message-Digest Algorithm
in all material mentioning or referencing the derived work.
RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided
as is without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this documentation and/or software. */
/* Constants for MD4Transform routine. */
#define S11 3
#define S12 7
#define S13 11
#define S14 19
#define S21 3
#define S22 5
#define S23 9
#define S24 13
#define S31 3
#define S32 9
#define S33 11
#define S34 15
static void MD4Transform (UINT4 [4], unsigned char [64]);
static void Encode (unsigned char *, UINT4 *, unsigned int);
static void Decode (UINT4 *, unsigned char *, unsigned int);
static void MD4_memcpy (POINTER, POINTER, unsigned int);
static void MD4_memset (POINTER, int, unsigned int);
static unsigned char PADDING[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/* F, G and H are basic MD4 functions. */
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
/* ROTATE_LEFT rotates x left n bits. */
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
/* FF, GG and HH are transformations for rounds 1, 2 and 3 */
/* Rotation is separate from addition to prevent recomputation */
#define FF(a, b, c, d, x, s) {(a) += F ((b), (c), (d)) + (x); (a) = ROTATE_LEFT ((a), (s));}
#define GG(a, b, c, d, x, s) {(a) += G ((b), (c), (d)) + (x) + (UINT4)0x5a827999; (a) = ROTATE_LEFT ((a), (s));}
#define HH(a, b, c, d, x, s) {(a) += H ((b), (c), (d)) + (x) + (UINT4)0x6ed9eba1; (a) = \
ROTATE_LEFT ((a), (s)); }
/* MD4 initialization. Begins an MD4 operation, writing a new context. */
void MD4Init (MD4_CTX *context)
{
context->count[0] = context->count[1] = 0;
/* Load magic initialization constants.*/
context->state[0] = 0x67452301;
context->state[1] = 0xefcdab89;
context->state[2] = 0x98badcfe;
context->state[3] = 0x10325476;
}
/* MD4 block update operation. Continues an MD4 message-digest operation, processing another message block, and updating the context. */
void MD4Update (MD4_CTX *context, unsigned char *input, unsigned int inputLen)
{
unsigned int i, index, partLen;
/* Compute number of bytes mod 64 */
index = (unsigned int)((context->count[0] >> 3) & 0x3F);
/* Update number of bits */
if ((context->count[0] += ((UINT4)inputLen << 3))< ((UINT4)inputLen << 3))
context->count[1]++;
context->count[1] += ((UINT4)inputLen >> 29);
partLen = 64 - index;
/* Transform as many times as possible.*/
if (inputLen >= partLen)
{
memcpy((POINTER)&context->buffer[index], (POINTER)input, partLen);
MD4Transform (context->state, context->buffer);
for (i = partLen; i + 63 < inputLen; i += 64)
MD4Transform (context->state, &input[i]);
index = 0;
}
else
i = 0;
/* Buffer remaining input */
memcpy ((POINTER)&context->buffer[index], (POINTER)&input[i], inputLen-i);
}
/* MD4 finalization. Ends an MD4 message-digest operation, writing the the message digest and zeroizing the context. */
void MD4Final (unsigned char digest[16], MD4_CTX *context)
{
unsigned char bits[8];
unsigned int index, padLen;
/* Save number of bits */
Encode (bits, context->count, 8);
/* Pad out to 56 mod 64.*/
index = (unsigned int)((context->count[0] >> 3) & 0x3f);
padLen = (index < 56) ? (56 - index) : (120 - index);
MD4Update (context, PADDING, padLen);
/* Append length (before padding) */
MD4Update (context, bits, 8);
/* Store state in digest */
Encode (digest, context->state, 16);
/* Zeroize sensitive information.*/
memset ((POINTER)context, 0, sizeof (*context));
}
/* MD4 basic transformation. Transforms state based on block. */
static void MD4Transform (UINT4 state[4], unsigned char block[64])
{
UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
Decode (x, block, 64);
/* Round 1 */
FF (a, b, c, d, x[ 0], S11); /* 1 */
FF (d, a, b, c, x[ 1], S12); /* 2 */
FF (c, d, a, b, x[ 2], S13); /* 3 */
FF (b, c, d, a, x[ 3], S14); /* 4 */
FF (a, b, c, d, x[ 4], S11); /* 5 */
FF (d, a, b, c, x[ 5], S12); /* 6 */
FF (c, d, a, b, x[ 6], S13); /* 7 */
FF (b, c, d, a, x[ 7], S14); /* 8 */
FF (a, b, c, d, x[ 8], S11); /* 9 */
FF (d, a, b, c, x[ 9], S12); /* 10 */
FF (c, d, a, b, x[10], S13); /* 11 */
FF (b, c, d, a, x[11], S14); /* 12 */
FF (a, b, c, d, x[12], S11); /* 13 */
FF (d, a, b, c, x[13], S12); /* 14 */
FF (c, d, a, b, x[14], S13); /* 15 */
FF (b, c, d, a, x[15], S14); /* 16 */
/* Round 2 */
GG (a, b, c, d, x[ 0], S21); /* 17 */
GG (d, a, b, c, x[ 4], S22); /* 18 */
GG (c, d, a, b, x[ 8], S23); /* 19 */
GG (b, c, d, a, x[12], S24); /* 20 */
GG (a, b, c, d, x[ 1], S21); /* 21 */
GG (d, a, b, c, x[ 5], S22); /* 22 */
GG (c, d, a, b, x[ 9], S23); /* 23 */
GG (b, c, d, a, x[13], S24); /* 24 */
GG (a, b, c, d, x[ 2], S21); /* 25 */
GG (d, a, b, c, x[ 6], S22); /* 26 */
GG (c, d, a, b, x[10], S23); /* 27 */
GG (b, c, d, a, x[14], S24); /* 28 */
GG (a, b, c, d, x[ 3], S21); /* 29 */
GG (d, a, b, c, x[ 7], S22); /* 30 */
GG (c, d, a, b, x[11], S23); /* 31 */
GG (b, c, d, a, x[15], S24); /* 32 */
/* Round 3 */
HH (a, b, c, d, x[ 0], S31); /* 33 */
HH (d, a, b, c, x[ 8], S32); /* 34 */
HH (c, d, a, b, x[ 4], S33); /* 35 */
HH (b, c, d, a, x[12], S34); /* 36 */
HH (a, b, c, d, x[ 2], S31); /* 37 */
HH (d, a, b, c, x[10], S32); /* 38 */
HH (c, d, a, b, x[ 6], S33); /* 39 */
HH (b, c, d, a, x[14], S34); /* 40 */
HH (a, b, c, d, x[ 1], S31); /* 41 */
HH (d, a, b, c, x[ 9], S32); /* 42 */
HH (c, d, a, b, x[ 5], S33); /* 43 */
HH (b, c, d, a, x[13], S34); /* 44 */
HH (a, b, c, d, x[ 3], S31); /* 45 */
HH (d, a, b, c, x[11], S32); /* 46 */
HH (c, d, a, b, x[ 7], S33); /* 47 */
HH (b, c, d, a, x[15], S34); /* 48 */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
/* Zeroize sensitive information.*/
memset ((POINTER)x, 0, sizeof (x));
}
/* Encodes input (UINT4) into output (unsigned char). Assumes len is a multiple of 4. */
static void Encode (unsigned char *output, UINT4 *input, unsigned int len)
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4) {
output[j] = (unsigned char)(input[i] & 0xff);
output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
}
}
/* Decodes input (unsigned char) into output (UINT4). Assumes len is a multiple of 4. */
static void Decode (UINT4 *output, unsigned char *input, unsigned int len)
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4)
output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
}
//===================================================================
unsigned Com_BlockChecksum (void *buffer, int length)
{
int digest[4];
unsigned val;
MD4_CTX ctx;
MD4Init (&ctx);
MD4Update (&ctx, (unsigned char *)buffer, length);
MD4Final ( (unsigned char *)digest, &ctx);
val = digest[0] ^ digest[1] ^ digest[2] ^ digest[3];
return val;
}

197
common/mutex.c Normal file
View file

@ -0,0 +1,197 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code 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.
Quake III Arena source code 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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "cmdlib.h"
#include "threads.h"
#include "mutex.h"
/*
===================================================================
WIN32
===================================================================
*/
#ifdef WIN32
#define USED
#include <windows.h>
void MutexLock (mutex_t *m)
{
CRITICAL_SECTION *crit;
if (!m)
return;
crit = (CRITICAL_SECTION *) m;
EnterCriticalSection (crit);
}
void MutexUnlock (mutex_t *m)
{
CRITICAL_SECTION *crit;
if (!m)
return;
crit = (CRITICAL_SECTION *) m;
LeaveCriticalSection (crit);
}
mutex_t *MutexAlloc(void)
{
CRITICAL_SECTION *crit;
if (numthreads == 1)
return NULL;
crit = (CRITICAL_SECTION *) malloc(sizeof(CRITICAL_SECTION));
InitializeCriticalSection (crit);
return (void *) crit;
}
#endif
/*
===================================================================
OSF1
===================================================================
*/
#ifdef __osf__
#define USED
#include <pthread.h>
void MutexLock (mutex_t *m)
{
pthread_mutex_t *my_mutex;
if (!m)
return;
my_mutex = (pthread_mutex_t *) m;
pthread_mutex_lock (my_mutex);
}
void MutexUnlock (mutex_t *m)
{
pthread_mutex_t *my_mutex;
if (!m)
return;
my_mutex = (pthread_mutex_t *) m;
pthread_mutex_unlock (my_mutex);
}
mutex_t *MutexAlloc(void)
{
pthread_mutex_t *my_mutex;
pthread_mutexattr_t mattrib;
if (numthreads == 1)
return NULL;
my_mutex = malloc (sizeof(*my_mutex));
if (pthread_mutexattr_create (&mattrib) == -1)
Error ("pthread_mutex_attr_create failed");
if (pthread_mutexattr_setkind_np (&mattrib, MUTEX_FAST_NP) == -1)
Error ("pthread_mutexattr_setkind_np failed");
if (pthread_mutex_init (my_mutex, mattrib) == -1)
Error ("pthread_mutex_init failed");
return (void *) my_mutex;
}
#endif
/*
===================================================================
IRIX
===================================================================
*/
#ifdef _MIPS_ISA
#define USED
#include <task.h>
#include <abi_mutex.h>
#include <sys/types.h>
#include <sys/prctl.h>
void MutexLock (mutex_t *m)
{
abilock_t *lck;
if (!m)
return;
lck = (abilock_t *) m;
spin_lock (lck);
}
void MutexUnlock (mutex_t *m)
{
abilock_t *lck;
if (!m)
return;
lck = (abilock_t *) m;
release_lock (lck);
}
mutex_t *MutexAlloc(void)
{
abilock_t *lck;
if (numthreads == 1)
return NULL;
lck = (abilock_t *) malloc(sizeof(abilock_t));
init_lock (lck);
return (void *) lck;
}
#endif
/*
=======================================================================
SINGLE THREAD
=======================================================================
*/
#ifndef USED
void MutexLock (mutex_t *m)
{
}
void MutexUnlock (mutex_t *m)
{
}
mutex_t *MutexAlloc(void)
{
return NULL;
}
#endif

28
common/mutex.h Normal file
View file

@ -0,0 +1,28 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code 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.
Quake III Arena source code 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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
typedef void *mutex_t;
void MutexLock (mutex_t *m);
void MutexUnlock (mutex_t *m);
mutex_t *MutexAlloc(void);

740
common/polylib.c Normal file
View file

@ -0,0 +1,740 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code 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.
Quake III Arena source code 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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "cmdlib.h"
#include "mathlib.h"
#include "polylib.h"
#include "qfiles.h"
extern int numthreads;
// counters are only bumped when running single threaded,
// because they are an awefull coherence problem
int c_active_windings;
int c_peak_windings;
int c_winding_allocs;
int c_winding_points;
#define BOGUS_RANGE WORLD_SIZE
void pw(winding_t *w)
{
int i;
for (i=0 ; i<w->numpoints ; i++)
printf ("(%5.1f, %5.1f, %5.1f)\n",w->p[i][0], w->p[i][1],w->p[i][2]);
}
/*
=============
AllocWinding
=============
*/
winding_t *AllocWinding (int points)
{
winding_t *w;
int s;
if (numthreads == 1)
{
c_winding_allocs++;
c_winding_points += points;
c_active_windings++;
if (c_active_windings > c_peak_windings)
c_peak_windings = c_active_windings;
}
s = sizeof(vec_t)*3*points + sizeof(int);
w = malloc (s);
memset (w, 0, s);
return w;
}
void FreeWinding (winding_t *w)
{
if (*(unsigned *)w == 0xdeaddead)
Error ("FreeWinding: freed a freed winding");
*(unsigned *)w = 0xdeaddead;
if (numthreads == 1)
c_active_windings--;
free (w);
}
/*
============
RemoveColinearPoints
============
*/
int c_removed;
void RemoveColinearPoints (winding_t *w)
{
int i, j, k;
vec3_t v1, v2;
int nump;
vec3_t p[MAX_POINTS_ON_WINDING];
nump = 0;
for (i=0 ; i<w->numpoints ; i++)
{
j = (i+1)%w->numpoints;
k = (i+w->numpoints-1)%w->numpoints;
VectorSubtract (w->p[j], w->p[i], v1);
VectorSubtract (w->p[i], w->p[k], v2);
VectorNormalize(v1,v1);
VectorNormalize(v2,v2);
if (DotProduct(v1, v2) < 0.999)
{
VectorCopy (w->p[i], p[nump]);
nump++;
}
}
if (nump == w->numpoints)
return;
if (numthreads == 1)
c_removed += w->numpoints - nump;
w->numpoints = nump;
memcpy (w->p, p, nump*sizeof(p[0]));
}
/*
============
WindingPlane
============
*/
void WindingPlane (winding_t *w, vec3_t normal, vec_t *dist)
{
vec3_t v1, v2;
VectorSubtract (w->p[1], w->p[0], v1);
VectorSubtract (w->p[2], w->p[0], v2);
CrossProduct (v2, v1, normal);
VectorNormalize (normal, normal);
*dist = DotProduct (w->p[0], normal);
}
/*
=============
WindingArea
=============
*/
vec_t WindingArea (winding_t *w)
{
int i;
vec3_t d1, d2, cross;
vec_t total;
total = 0;
for (i=2 ; i<w->numpoints ; i++)
{
VectorSubtract (w->p[i-1], w->p[0], d1);
VectorSubtract (w->p[i], w->p[0], d2);
CrossProduct (d1, d2, cross);
total += 0.5 * VectorLength ( cross );
}
return total;
}
void WindingBounds (winding_t *w, vec3_t mins, vec3_t maxs)
{
vec_t v;
int i,j;
mins[0] = mins[1] = mins[2] = 99999;
maxs[0] = maxs[1] = maxs[2] = -99999;
for (i=0 ; i<w->numpoints ; i++)
{
for (j=0 ; j<3 ; j++)
{
v = w->p[i][j];
if (v < mins[j])
mins[j] = v;
if (v > maxs[j])
maxs[j] = v;
}
}
}
/*
=============
WindingCenter
=============
*/
void WindingCenter (winding_t *w, vec3_t center)
{
int i;
float scale;
VectorCopy (vec3_origin, center);
for (i=0 ; i<w->numpoints ; i++)
VectorAdd (w->p[i], center, center);
scale = 1.0/w->numpoints;
VectorScale (center, scale, center);
}
/*
=================
BaseWindingForPlane
=================
*/
winding_t *BaseWindingForPlane (vec3_t normal, vec_t dist)
{
int i, x;
vec_t max, v;
vec3_t org, vright, vup;
winding_t *w;
// find the major axis
max = -BOGUS_RANGE;
x = -1;
for (i=0 ; i<3; i++)
{
v = fabs(normal[i]);
if (v > max)
{
x = i;
max = v;
}
}
if (x==-1)
Error ("BaseWindingForPlane: no axis found");
VectorCopy (vec3_origin, vup);
switch (x)
{
case 0:
case 1:
vup[2] = 1;
break;
case 2:
vup[0] = 1;
break;
}
v = DotProduct (vup, normal);
VectorMA (vup, -v, normal, vup);
VectorNormalize (vup, vup);
VectorScale (normal, dist, org);
CrossProduct (vup, normal, vright);
VectorScale (vup, MAX_WORLD_COORD, vup);
VectorScale (vright, MAX_WORLD_COORD, vright);
// project a really big axis aligned box onto the plane
w = AllocWinding (4);
VectorSubtract (org, vright, w->p[0]);
VectorAdd (w->p[0], vup, w->p[0]);
VectorAdd (org, vright, w->p[1]);
VectorAdd (w->p[1], vup, w->p[1]);
VectorAdd (org, vright, w->p[2]);
VectorSubtract (w->p[2], vup, w->p[2]);
VectorSubtract (org, vright, w->p[3]);
VectorSubtract (w->p[3], vup, w->p[3]);
w->numpoints = 4;
return w;
}
/*
==================
CopyWinding
==================
*/
winding_t *CopyWinding (winding_t *w)
{
int size;
winding_t *c;
c = AllocWinding (w->numpoints);
size = (int)((winding_t *)0)->p[w->numpoints];
memcpy (c, w, size);
return c;
}
/*
==================
ReverseWinding
==================
*/
winding_t *ReverseWinding (winding_t *w)
{
int i;
winding_t *c;
c = AllocWinding (w->numpoints);
for (i=0 ; i<w->numpoints ; i++)
{
VectorCopy (w->p[w->numpoints-1-i], c->p[i]);
}
c->numpoints = w->numpoints;
return c;
}
/*
=============
ClipWindingEpsilon
=============
*/
void ClipWindingEpsilon (winding_t *in, vec3_t normal, vec_t dist,
vec_t epsilon, winding_t **front, winding_t **back)
{
vec_t dists[MAX_POINTS_ON_WINDING+4];
int sides[MAX_POINTS_ON_WINDING+4];
int counts[3];
static vec_t dot; // VC 4.2 optimizer bug if not static
int i, j;
vec_t *p1, *p2;
vec3_t mid;
winding_t *f, *b;
int maxpts;
counts[0] = counts[1] = counts[2] = 0;
// determine sides for each point
for (i=0 ; i<in->numpoints ; i++)
{
dot = DotProduct (in->p[i], normal);
dot -= dist;
dists[i] = dot;
if (dot > epsilon)
sides[i] = SIDE_FRONT;
else if (dot < -epsilon)
sides[i] = SIDE_BACK;
else
{
sides[i] = SIDE_ON;
}
counts[sides[i]]++;
}
sides[i] = sides[0];
dists[i] = dists[0];
*front = *back = NULL;
if (!counts[0])
{
*back = CopyWinding (in);
return;
}
if (!counts[1])
{
*front = CopyWinding (in);
return;
}
maxpts = in->numpoints+4; // cant use counts[0]+2 because
// of fp grouping errors
*front = f = AllocWinding (maxpts);
*back = b = AllocWinding (maxpts);
for (i=0 ; i<in->numpoints ; i++)
{
p1 = in->p[i];
if (sides[i] == SIDE_ON)
{
VectorCopy (p1, f->p[f->numpoints]);
f->numpoints++;
VectorCopy (p1, b->p[b->numpoints]);
b->numpoints++;
continue;
}
if (sides[i] == SIDE_FRONT)
{
VectorCopy (p1, f->p[f->numpoints]);
f->numpoints++;
}
if (sides[i] == SIDE_BACK)
{
VectorCopy (p1, b->p[b->numpoints]);
b->numpoints++;
}
if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
continue;
// generate a split point
p2 = in->p[(i+1)%in->numpoints];
dot = dists[i] / (dists[i]-dists[i+1]);
for (j=0 ; j<3 ; j++)
{ // avoid round off error when possible
if (normal[j] == 1)
mid[j] = dist;
else if (normal[j] == -1)
mid[j] = -dist;
else
mid[j] = p1[j] + dot*(p2[j]-p1[j]);
}
VectorCopy (mid, f->p[f->numpoints]);
f->numpoints++;
VectorCopy (mid, b->p[b->numpoints]);
b->numpoints++;
}
if (f->numpoints > maxpts || b->numpoints > maxpts)
Error ("ClipWinding: points exceeded estimate");
if (f->numpoints > MAX_POINTS_ON_WINDING || b->numpoints > MAX_POINTS_ON_WINDING)
Error ("ClipWinding: MAX_POINTS_ON_WINDING");
}
/*
=============
ChopWindingInPlace
=============
*/
void ChopWindingInPlace (winding_t **inout, vec3_t normal, vec_t dist, vec_t epsilon)
{
winding_t *in;
vec_t dists[MAX_POINTS_ON_WINDING+4];
int sides[MAX_POINTS_ON_WINDING+4];
int counts[3];
static vec_t dot; // VC 4.2 optimizer bug if not static
int i, j;
vec_t *p1, *p2;
vec3_t mid;
winding_t *f;
int maxpts;
in = *inout;
counts[0] = counts[1] = counts[2] = 0;
// determine sides for each point
for (i=0 ; i<in->numpoints ; i++)
{
dot = DotProduct (in->p[i], normal);
dot -= dist;
dists[i] = dot;
if (dot > epsilon)
sides[i] = SIDE_FRONT;
else if (dot < -epsilon)
sides[i] = SIDE_BACK;
else
{
sides[i] = SIDE_ON;
}
counts[sides[i]]++;
}
sides[i] = sides[0];
dists[i] = dists[0];
if (!counts[0])
{
FreeWinding (in);
*inout = NULL;
return;
}
if (!counts[1])
return; // inout stays the same
maxpts = in->numpoints+4; // cant use counts[0]+2 because
// of fp grouping errors
f = AllocWinding (maxpts);
for (i=0 ; i<in->numpoints ; i++)
{
p1 = in->p[i];
if (sides[i] == SIDE_ON)
{
VectorCopy (p1, f->p[f->numpoints]);
f->numpoints++;
continue;
}
if (sides[i] == SIDE_FRONT)
{
VectorCopy (p1, f->p[f->numpoints]);
f->numpoints++;
}
if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
continue;
// generate a split point
p2 = in->p[(i+1)%in->numpoints];
dot = dists[i] / (dists[i]-dists[i+1]);
for (j=0 ; j<3 ; j++)
{ // avoid round off error when possible
if (normal[j] == 1)
mid[j] = dist;
else if (normal[j] == -1)
mid[j] = -dist;
else
mid[j] = p1[j] + dot*(p2[j]-p1[j]);
}
VectorCopy (mid, f->p[f->numpoints]);
f->numpoints++;
}
if (f->numpoints > maxpts)
Error ("ClipWinding: points exceeded estimate");
if (f->numpoints > MAX_POINTS_ON_WINDING)
Error ("ClipWinding: MAX_POINTS_ON_WINDING");
FreeWinding (in);
*inout = f;
}
/*
=================
ChopWinding
Returns the fragment of in that is on the front side
of the cliping plane. The original is freed.
=================
*/
winding_t *ChopWinding (winding_t *in, vec3_t normal, vec_t dist)
{
winding_t *f, *b;
ClipWindingEpsilon (in, normal, dist, ON_EPSILON, &f, &b);
FreeWinding (in);
if (b)
FreeWinding (b);
return f;
}
/*
=================
CheckWinding
=================
*/
void CheckWinding (winding_t *w)
{
int i, j;
vec_t *p1, *p2;
vec_t d, edgedist;
vec3_t dir, edgenormal, facenormal;
vec_t area;
vec_t facedist;
if (w->numpoints < 3)
Error ("CheckWinding: %i points",w->numpoints);
area = WindingArea(w);
if (area < 1)
Error ("CheckWinding: %f area", area);
WindingPlane (w, facenormal, &facedist);
for (i=0 ; i<w->numpoints ; i++)
{
p1 = w->p[i];
for (j=0 ; j<3 ; j++)
if (p1[j] > MAX_WORLD_COORD || p1[j] < MIN_WORLD_COORD)
Error ("CheckFace: BUGUS_RANGE: %f",p1[j]);
j = i+1 == w->numpoints ? 0 : i+1;
// check the point is on the face plane
d = DotProduct (p1, facenormal) - facedist;
if (d < -ON_EPSILON || d > ON_EPSILON)
Error ("CheckWinding: point off plane");
// check the edge isnt degenerate
p2 = w->p[j];
VectorSubtract (p2, p1, dir);
if (VectorLength (dir) < ON_EPSILON)
Error ("CheckWinding: degenerate edge");
CrossProduct (facenormal, dir, edgenormal);
VectorNormalize (edgenormal, edgenormal);
edgedist = DotProduct (p1, edgenormal);
edgedist += ON_EPSILON;
// all other points must be on front side
for (j=0 ; j<w->numpoints ; j++)
{
if (j == i)
continue;
d = DotProduct (w->p[j], edgenormal);
if (d > edgedist)
Error ("CheckWinding: non-convex");
}
}
}
/*
============
WindingOnPlaneSide
============
*/
int WindingOnPlaneSide (winding_t *w, vec3_t normal, vec_t dist)
{
qboolean front, back;
int i;
vec_t d;
front = qfalse;
back = qfalse;
for (i=0 ; i<w->numpoints ; i++)
{
d = DotProduct (w->p[i], normal) - dist;
if (d < -ON_EPSILON)
{
if (front)
return SIDE_CROSS;
back = qtrue;
continue;
}
if (d > ON_EPSILON)
{
if (back)
return SIDE_CROSS;
front = qtrue;
continue;
}
}
if (back)
return SIDE_BACK;
if (front)
return SIDE_FRONT;
return SIDE_ON;
}
/*
=================
AddWindingToConvexHull
Both w and *hull are on the same plane
=================
*/
#define MAX_HULL_POINTS 128
void AddWindingToConvexHull( winding_t *w, winding_t **hull, vec3_t normal ) {
int i, j, k;
float *p, *copy;
vec3_t dir;
float d;
int numHullPoints, numNew;
vec3_t hullPoints[MAX_HULL_POINTS];
vec3_t newHullPoints[MAX_HULL_POINTS];
vec3_t hullDirs[MAX_HULL_POINTS];
qboolean hullSide[MAX_HULL_POINTS];
qboolean outside;
if ( !*hull ) {
*hull = CopyWinding( w );
return;
}
numHullPoints = (*hull)->numpoints;
memcpy( hullPoints, (*hull)->p, numHullPoints * sizeof(vec3_t) );
for ( i = 0 ; i < w->numpoints ; i++ ) {
p = w->p[i];
// calculate hull side vectors
for ( j = 0 ; j < numHullPoints ; j++ ) {
k = ( j + 1 ) % numHullPoints;
VectorSubtract( hullPoints[k], hullPoints[j], dir );
VectorNormalize( dir, dir );
CrossProduct( normal, dir, hullDirs[j] );
}
outside = qfalse;
for ( j = 0 ; j < numHullPoints ; j++ ) {
VectorSubtract( p, hullPoints[j], dir );
d = DotProduct( dir, hullDirs[j] );
if ( d >= ON_EPSILON ) {
outside = qtrue;
}
if ( d >= -ON_EPSILON ) {
hullSide[j] = qtrue;
} else {
hullSide[j] = qfalse;
}
}
// if the point is effectively inside, do nothing
if ( !outside ) {
continue;
}
// find the back side to front side transition
for ( j = 0 ; j < numHullPoints ; j++ ) {
if ( !hullSide[ j % numHullPoints ] && hullSide[ (j + 1) % numHullPoints ] ) {
break;
}
}
if ( j == numHullPoints ) {
continue;
}
// insert the point here
VectorCopy( p, newHullPoints[0] );
numNew = 1;
// copy over all points that aren't double fronts
j = (j+1)%numHullPoints;
for ( k = 0 ; k < numHullPoints ; k++ ) {
if ( hullSide[ (j+k) % numHullPoints ] && hullSide[ (j+k+1) % numHullPoints ] ) {
continue;
}
copy = hullPoints[ (j+k+1) % numHullPoints ];
VectorCopy( copy, newHullPoints[numNew] );
numNew++;
}
numHullPoints = numNew;
memcpy( hullPoints, newHullPoints, numHullPoints * sizeof(vec3_t) );
}
FreeWinding( *hull );
w = AllocWinding( numHullPoints );
w->numpoints = numHullPoints;
*hull = w;
memcpy( w->p, hullPoints, numHullPoints * sizeof(vec3_t) );
}

57
common/polylib.h Normal file
View file

@ -0,0 +1,57 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code 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.
Quake III Arena source code 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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
typedef struct
{
int numpoints;
vec3_t p[4]; // variable sized
} winding_t;
#define MAX_POINTS_ON_WINDING 64
// you can define on_epsilon in the makefile as tighter
#ifndef ON_EPSILON
#define ON_EPSILON 0.1
#endif
winding_t *AllocWinding (int points);
vec_t WindingArea (winding_t *w);
void WindingCenter (winding_t *w, vec3_t center);
void ClipWindingEpsilon (winding_t *in, vec3_t normal, vec_t dist,
vec_t epsilon, winding_t **front, winding_t **back);
winding_t *ChopWinding (winding_t *in, vec3_t normal, vec_t dist);
winding_t *CopyWinding (winding_t *w);
winding_t *ReverseWinding (winding_t *w);
winding_t *BaseWindingForPlane (vec3_t normal, vec_t dist);
void CheckWinding (winding_t *w);
void WindingPlane (winding_t *w, vec3_t normal, vec_t *dist);
void RemoveColinearPoints (winding_t *w);
int WindingOnPlaneSide (winding_t *w, vec3_t normal, vec_t dist);
void FreeWinding (winding_t *w);
void WindingBounds (winding_t *w, vec3_t mins, vec3_t maxs);
void AddWindingToConvexHull( winding_t *w, winding_t **hull, vec3_t normal );
void ChopWindingInPlace (winding_t **w, vec3_t normal, vec_t dist, vec_t epsilon);
// frees the original if clipped
void pw(winding_t *w);

51
common/polyset.h Normal file
View file

@ -0,0 +1,51 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code 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.
Quake III Arena source code 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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#ifndef __POLYSET_H__
#define __POLYSET_H__
#define POLYSET_MAXTRIANGLES 4096
#define POLYSET_MAXPOLYSETS 64
typedef float st_t[2];
typedef float rgb_t[3];
typedef struct {
vec3_t verts[3];
vec3_t normals[3];
st_t texcoords[3];
} triangle_t;
typedef struct
{
char name[100];
char materialname[100];
triangle_t *triangles;
int numtriangles;
} polyset_t;
polyset_t *Polyset_LoadSets( const char *file, int *numpolysets, int maxTrisPerSet );
polyset_t *Polyset_CollapseSets( polyset_t *psets, int numpolysets );
polyset_t *Polyset_SplitSets( polyset_t *psets, int numpolysets, int *pNumNewPolysets, int maxTris );
void Polyset_SnapSets( polyset_t *psets, int numpolysets );
void Polyset_ComputeNormals( polyset_t *psets, int numpolysets );
#endif

489
common/qfiles.h Normal file
View file

@ -0,0 +1,489 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code 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.
Quake III Arena source code 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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#ifndef __QFILES_H__
#define __QFILES_H__
//
// qfiles.h: quake file formats
// This file must be identical in the quake and utils directories
//
// surface geometry should not exceed these limits
#define SHADER_MAX_VERTEXES 1000
#define SHADER_MAX_INDEXES (6*SHADER_MAX_VERTEXES)
// the maximum size of game reletive pathnames
#define MAX_QPATH 64
/*
========================================================================
QVM files
========================================================================
*/
#define VM_MAGIC 0x12721444
typedef struct {
int vmMagic;
int instructionCount;
int codeOffset;
int codeLength;
int dataOffset;
int dataLength;
int litLength; // ( dataLength - litLength ) should be byteswapped on load
int bssLength; // zero filled memory appended to datalength
} vmHeader_t;
/*
========================================================================
PCX files are used for 8 bit images
========================================================================
*/
typedef struct {
char manufacturer;
char version;
char encoding;
char bits_per_pixel;
unsigned short xmin,ymin,xmax,ymax;
unsigned short hres,vres;
unsigned char palette[48];
char reserved;
char color_planes;
unsigned short bytes_per_line;
unsigned short palette_type;
char filler[58];
unsigned char data; // unbounded
} pcx_t;
/*
========================================================================
TGA files are used for 24/32 bit images
========================================================================
*/
typedef struct _TargaHeader {
unsigned char id_length, colormap_type, image_type;
unsigned short colormap_index, colormap_length;
unsigned char colormap_size;
unsigned short x_origin, y_origin, width, height;
unsigned char pixel_size, attributes;
} TargaHeader;
/*
========================================================================
.MD3 triangle model file format
========================================================================
*/
#define MD3_IDENT (('3'<<24)+('P'<<16)+('D'<<8)+'I')
#define MD3_VERSION 15
// limits
#define MD3_MAX_LODS 4
#define MD3_MAX_TRIANGLES 8192 // per surface
#define MD3_MAX_VERTS 4096 // per surface
#define MD3_MAX_SHADERS 256 // per surface
#define MD3_MAX_FRAMES 1024 // per model
#define MD3_MAX_SURFACES 32 // per model
#define MD3_MAX_TAGS 16 // per frame
// vertex scales
#define MD3_XYZ_SCALE (1.0/64)
typedef struct md3Frame_s {
vec3_t bounds[2];
vec3_t localOrigin;
float radius;
char name[16];
} md3Frame_t;
typedef struct md3Tag_s {
char name[MAX_QPATH]; // tag name
vec3_t origin;
vec3_t axis[3];
} md3Tag_t;
/*
** md3Surface_t
**
** CHUNK SIZE
** header sizeof( md3Surface_t )
** shaders sizeof( md3Shader_t ) * numShaders
** triangles[0] sizeof( md3Triangle_t ) * numTriangles
** st sizeof( md3St_t ) * numVerts
** XyzNormals sizeof( md3XyzNormal_t ) * numVerts * numFrames
*/
typedef struct {
int ident; //
char name[MAX_QPATH]; // polyset name
int flags;
int numFrames; // all surfaces in a model should have the same
int numShaders; // all surfaces in a model should have the same
int numVerts;
int numTriangles;
int ofsTriangles;
int ofsShaders; // offset from start of md3Surface_t
int ofsSt; // texture coords are common for all frames
int ofsXyzNormals; // numVerts * numFrames
int ofsEnd; // next surface follows
} md3Surface_t;
typedef struct {
char name[MAX_QPATH];
int shaderIndex; // for in-game use
} md3Shader_t;
typedef struct {
int indexes[3];
} md3Triangle_t;
typedef struct {
float st[2];
} md3St_t;
typedef struct {
short xyz[3];
short normal;
} md3XyzNormal_t;
typedef struct {
int ident;
int version;
char name[MAX_QPATH]; // model name
int flags;
int numFrames;
int numTags;
int numSurfaces;
int numSkins;
int ofsFrames; // offset for first frame
int ofsTags; // numFrames * numTags
int ofsSurfaces; // first surface, others follow
int ofsEnd; // end of file
} md3Header_t;
/*
==============================================================================
MD4 file format
==============================================================================
*/
#define MD4_IDENT (('4'<<24)+('P'<<16)+('D'<<8)+'I')
#define MD4_VERSION 1
#define MD4_MAX_BONES 128
typedef struct {
int boneIndex; // these are indexes into the boneReferences,
float boneWeight; // not the global per-frame bone list
} md4Weight_t;
typedef struct {
vec3_t vertex;
vec3_t normal;
float texCoords[2];
int numWeights;
md4Weight_t weights[1]; // variable sized
} md4Vertex_t;
typedef struct {
int indexes[3];
} md4Triangle_t;
typedef struct {
int ident;
char name[MAX_QPATH]; // polyset name
char shader[MAX_QPATH];
int shaderIndex; // for in-game use
int ofsHeader; // this will be a negative number
int numVerts;
int ofsVerts;
int numTriangles;
int ofsTriangles;
// Bone references are a set of ints representing all the bones
// present in any vertex weights for this surface. This is
// needed because a model may have surfaces that need to be
// drawn at different sort times, and we don't want to have
// to re-interpolate all the bones for each surface.
int numBoneReferences;
int ofsBoneReferences;
int ofsEnd; // next surface follows
} md4Surface_t;
typedef struct {
float matrix[3][4];
} md4Bone_t;
typedef struct {
vec3_t bounds[2]; // bounds of all surfaces of all LOD's for this frame
vec3_t localOrigin; // midpoint of bounds, used for sphere cull
float radius; // dist from localOrigin to corner
char name[16];
md4Bone_t bones[1]; // [numBones]
} md4Frame_t;
typedef struct {
int numSurfaces;
int ofsSurfaces; // first surface, others follow
int ofsEnd; // next lod follows
} md4LOD_t;
typedef struct {
int ident;
int version;
char name[MAX_QPATH]; // model name
// frames and bones are shared by all levels of detail
int numFrames;
int numBones;
int ofsFrames; // md4Frame_t[numFrames]
// each level of detail has completely separate sets of surfaces
int numLODs;
int ofsLODs;
int ofsEnd; // end of file
} md4Header_t;
/*
==============================================================================
.BSP file format
==============================================================================
*/
#define BSP_IDENT (('P'<<24)+('S'<<16)+('B'<<8)+'I')
// little-endian "IBSP"
#define BSP_VERSION 46
// there shouldn't be any problem with increasing these values at the
// expense of more memory allocation in the utilities
#define MAX_MAP_MODELS 0x400
#define MAX_MAP_BRUSHES 0x8000
#define MAX_MAP_ENTITIES 0x800
#define MAX_MAP_ENTSTRING 0x40000
#define MAX_MAP_SHADERS 0x400
#define MAX_MAP_AREAS 0x100 // MAX_MAP_AREA_BYTES in q_shared must match!
#define MAX_MAP_FOGS 0x100
#define MAX_MAP_PLANES 0x20000
#define MAX_MAP_NODES 0x20000
#define MAX_MAP_BRUSHSIDES 0x20000
#define MAX_MAP_LEAFS 0x20000
#define MAX_MAP_LEAFFACES 0x20000
#define MAX_MAP_LEAFBRUSHES 0x40000
#define MAX_MAP_PORTALS 0x20000
#define MAX_MAP_LIGHTING 0x800000
#define MAX_MAP_LIGHTGRID 0x800000
#define MAX_MAP_VISIBILITY 0x200000
#define MAX_MAP_DRAW_SURFS 0x20000
#define MAX_MAP_DRAW_VERTS 0x80000
#define MAX_MAP_DRAW_INDEXES 0x80000
// key / value pair sizes in the entities lump
#define MAX_KEY 32
#define MAX_VALUE 1024
// the editor uses these predefined yaw angles to orient entities up or down
#define ANGLE_UP -1
#define ANGLE_DOWN -2
#define LIGHTMAP_WIDTH 128
#define LIGHTMAP_HEIGHT 128
#define MAX_WORLD_COORD ( 128*1024 )
#define MIN_WORLD_COORD ( -128*1024 )
#define WORLD_SIZE ( MAX_WORLD_COORD - MIN_WORLD_COORD )
//=============================================================================
typedef struct {
int fileofs, filelen;
} lump_t;
#define LUMP_ENTITIES 0
#define LUMP_SHADERS 1
#define LUMP_PLANES 2
#define LUMP_NODES 3
#define LUMP_LEAFS 4
#define LUMP_LEAFSURFACES 5
#define LUMP_LEAFBRUSHES 6
#define LUMP_MODELS 7
#define LUMP_BRUSHES 8
#define LUMP_BRUSHSIDES 9
#define LUMP_DRAWVERTS 10
#define LUMP_DRAWINDEXES 11
#define LUMP_FOGS 12
#define LUMP_SURFACES 13
#define LUMP_LIGHTMAPS 14
#define LUMP_LIGHTGRID 15
#define LUMP_VISIBILITY 16
#define HEADER_LUMPS 17
typedef struct {
int ident;
int version;
lump_t lumps[HEADER_LUMPS];
} dheader_t;
typedef struct {
float mins[3], maxs[3];
int firstSurface, numSurfaces;
int firstBrush, numBrushes;
} dmodel_t;
typedef struct {
char shader[MAX_QPATH];
int surfaceFlags;
int contentFlags;
} dshader_t;
// planes x^1 is allways the opposite of plane x
typedef struct {
float normal[3];
float dist;
} dplane_t;
typedef struct {
int planeNum;
int children[2]; // negative numbers are -(leafs+1), not nodes
int mins[3]; // for frustom culling
int maxs[3];
} dnode_t;
typedef struct {
int cluster; // -1 = opaque cluster (do I still store these?)
int area;
int mins[3]; // for frustum culling
int maxs[3];
int firstLeafSurface;
int numLeafSurfaces;
int firstLeafBrush;
int numLeafBrushes;
} dleaf_t;
typedef struct {
int planeNum; // positive plane side faces out of the leaf
int shaderNum;
} dbrushside_t;
typedef struct {
int firstSide;
int numSides;
int shaderNum; // the shader that determines the contents flags
} dbrush_t;
typedef struct {
char shader[MAX_QPATH];
int brushNum;
int visibleSide; // the brush side that ray tests need to clip against (-1 == none)
} dfog_t;
typedef struct {
vec3_t xyz;
float st[2];
float lightmap[2];
vec3_t normal;
byte color[4];
} drawVert_t;
typedef enum {
MST_BAD,
MST_PLANAR,
MST_PATCH,
MST_TRIANGLE_SOUP,
MST_FLARE
} mapSurfaceType_t;
typedef struct {
int shaderNum;
int fogNum;
int surfaceType;
int firstVert;
int numVerts;
int firstIndex;
int numIndexes;
int lightmapNum;
int lightmapX, lightmapY;
int lightmapWidth, lightmapHeight;
vec3_t lightmapOrigin;
vec3_t lightmapVecs[3]; // for patches, [0] and [1] are lodbounds
int patchWidth;
int patchHeight;
} dsurface_t;
#endif

375
common/scriplib.c Normal file
View file

@ -0,0 +1,375 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code 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.
Quake III Arena source code 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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// scriplib.c
#include "cmdlib.h"
#include "scriplib.h"
/*
=============================================================================
PARSING STUFF
=============================================================================
*/
typedef struct
{
char filename[1024];
char *buffer,*script_p,*end_p;
int line;
} script_t;
#define MAX_INCLUDES 8
script_t scriptstack[MAX_INCLUDES];
script_t *script;
int scriptline;
char token[MAXTOKEN];
qboolean endofscript;
qboolean tokenready; // only qtrue if UnGetToken was just called
/*
==============
AddScriptToStack
==============
*/
void AddScriptToStack( const char *filename ) {
int size;
script++;
if (script == &scriptstack[MAX_INCLUDES])
Error ("script file exceeded MAX_INCLUDES");
strcpy (script->filename, ExpandPath (filename) );
size = LoadFile (script->filename, (void **)&script->buffer);
printf ("entering %s\n", script->filename);
script->line = 1;
script->script_p = script->buffer;
script->end_p = script->buffer + size;
}
/*
==============
LoadScriptFile
==============
*/
void LoadScriptFile( const char *filename ) {
script = scriptstack;
AddScriptToStack (filename);
endofscript = qfalse;
tokenready = qfalse;
}
/*
==============
ParseFromMemory
==============
*/
void ParseFromMemory (char *buffer, int size)
{
script = scriptstack;
script++;
if (script == &scriptstack[MAX_INCLUDES])
Error ("script file exceeded MAX_INCLUDES");
strcpy (script->filename, "memory buffer" );
script->buffer = buffer;
script->line = 1;
script->script_p = script->buffer;
script->end_p = script->buffer + size;
endofscript = qfalse;
tokenready = qfalse;
}
/*
==============
UnGetToken
Signals that the current token was not used, and should be reported
for the next GetToken. Note that
GetToken (qtrue);
UnGetToken ();
GetToken (qfalse);
could cross a line boundary.
==============
*/
void UnGetToken (void)
{
tokenready = qtrue;
}
qboolean EndOfScript (qboolean crossline)
{
if (!crossline)
Error ("Line %i is incomplete\n",scriptline);
if (!strcmp (script->filename, "memory buffer"))
{
endofscript = qtrue;
return qfalse;
}
free (script->buffer);
if (script == scriptstack+1)
{
endofscript = qtrue;
return qfalse;
}
script--;
scriptline = script->line;
printf ("returning to %s\n", script->filename);
return GetToken (crossline);
}
/*
==============
GetToken
==============
*/
qboolean GetToken (qboolean crossline)
{
char *token_p;
if (tokenready) // is a token allready waiting?
{
tokenready = qfalse;
return qtrue;
}
if (script->script_p >= script->end_p)
return EndOfScript (crossline);
//
// skip space
//
skipspace:
while (*script->script_p <= 32)
{
if (script->script_p >= script->end_p)
return EndOfScript (crossline);
if (*script->script_p++ == '\n')
{
if (!crossline)
Error ("Line %i is incomplete\n",scriptline);
scriptline = script->line++;
}
}
if (script->script_p >= script->end_p)
return EndOfScript (crossline);
// ; # // comments
if (*script->script_p == ';' || *script->script_p == '#'
|| ( script->script_p[0] == '/' && script->script_p[1] == '/') )
{
if (!crossline)
Error ("Line %i is incomplete\n",scriptline);
while (*script->script_p++ != '\n')
if (script->script_p >= script->end_p)
return EndOfScript (crossline);
scriptline = script->line++;
goto skipspace;
}
// /* */ comments
if (script->script_p[0] == '/' && script->script_p[1] == '*')
{
if (!crossline)
Error ("Line %i is incomplete\n",scriptline);
script->script_p+=2;
while (script->script_p[0] != '*' && script->script_p[1] != '/')
{
if ( *script->script_p == '\n' ) {
scriptline = script->line++;
}
script->script_p++;
if (script->script_p >= script->end_p)
return EndOfScript (crossline);
}
script->script_p += 2;
goto skipspace;
}
//
// copy token
//
token_p = token;
if (*script->script_p == '"')
{
// quoted token
script->script_p++;
while (*script->script_p != '"')
{
*token_p++ = *script->script_p++;
if (script->script_p == script->end_p)
break;
if (token_p == &token[MAXTOKEN])
Error ("Token too large on line %i\n",scriptline);
}
script->script_p++;
}
else // regular token
while ( *script->script_p > 32 && *script->script_p != ';')
{
*token_p++ = *script->script_p++;
if (script->script_p == script->end_p)
break;
if (token_p == &token[MAXTOKEN])
Error ("Token too large on line %i\n",scriptline);
}
*token_p = 0;
if (!strcmp (token, "$include"))
{
GetToken (qfalse);
AddScriptToStack (token);
return GetToken (crossline);
}
return qtrue;
}
/*
==============
TokenAvailable
Returns qtrue if there is another token on the line
==============
*/
qboolean TokenAvailable (void) {
int oldLine;
qboolean r;
oldLine = script->line;
r = GetToken( qtrue );
if ( !r ) {
return qfalse;
}
UnGetToken();
if ( oldLine == script->line ) {
return qtrue;
}
return qfalse;
}
//=====================================================================
void MatchToken( char *match ) {
GetToken( qtrue );
if ( strcmp( token, match ) ) {
Error( "MatchToken( \"%s\" ) failed at line %i", match, scriptline );
}
}
void Parse1DMatrix (int x, vec_t *m) {
int i;
MatchToken( "(" );
for (i = 0 ; i < x ; i++) {
GetToken( qfalse );
m[i] = atof(token);
}
MatchToken( ")" );
}
void Parse2DMatrix (int y, int x, vec_t *m) {
int i;
MatchToken( "(" );
for (i = 0 ; i < y ; i++) {
Parse1DMatrix (x, m + i * x);
}
MatchToken( ")" );
}
void Parse3DMatrix (int z, int y, int x, vec_t *m) {
int i;
MatchToken( "(" );
for (i = 0 ; i < z ; i++) {
Parse2DMatrix (y, x, m + i * x*y);
}
MatchToken( ")" );
}
void Write1DMatrix (FILE *f, int x, vec_t *m) {
int i;
fprintf (f, "( ");
for (i = 0 ; i < x ; i++) {
if (m[i] == (int)m[i] ) {
fprintf (f, "%i ", (int)m[i]);
} else {
fprintf (f, "%f ", m[i]);
}
}
fprintf (f, ")");
}
void Write2DMatrix (FILE *f, int y, int x, vec_t *m) {
int i;
fprintf (f, "( ");
for (i = 0 ; i < y ; i++) {
Write1DMatrix (f, x, m + i*x);
fprintf (f, " ");
}
fprintf (f, ")\n");
}
void Write3DMatrix (FILE *f, int z, int y, int x, vec_t *m) {
int i;
fprintf (f, "(\n");
for (i = 0 ; i < z ; i++) {
Write2DMatrix (f, y, x, m + i*(x*y) );
}
fprintf (f, ")\n");
}

55
common/scriplib.h Normal file
View file

@ -0,0 +1,55 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code 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.
Quake III Arena source code 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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// scriplib.h
#ifndef __CMDLIB__
#include "cmdlib.h"
#endif
#ifndef __MATHLIB__
#include "mathlib.h"
#endif
#define MAXTOKEN 1024
extern char token[MAXTOKEN];
extern char *scriptbuffer,*script_p,*scriptend_p;
extern int grabbed;
extern int scriptline;
extern qboolean endofscript;
void LoadScriptFile( const char *filename );
void ParseFromMemory (char *buffer, int size);
qboolean GetToken (qboolean crossline);
void UnGetToken (void);
qboolean TokenAvailable (void);
void MatchToken( char *match );
void Parse1DMatrix (int x, vec_t *m);
void Parse2DMatrix (int y, int x, vec_t *m);
void Parse3DMatrix (int z, int y, int x, vec_t *m);
void Write1DMatrix (FILE *f, int x, vec_t *m);
void Write2DMatrix (FILE *f, int y, int x, vec_t *m);
void Write3DMatrix (FILE *f, int z, int y, int x, vec_t *m);

72
common/surfaceflags.h Normal file
View file

@ -0,0 +1,72 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code 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.
Quake III Arena source code 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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// This file must be identical in the quake and utils directories
// contents flags are seperate bits
// a given brush can contribute multiple content bits
// these definitions also need to be in q_shared.h!
#define CONTENTS_SOLID 1 // an eye is never valid in a solid
#define CONTENTS_LAVA 8
#define CONTENTS_SLIME 16
#define CONTENTS_WATER 32
#define CONTENTS_FOG 64
#define CONTENTS_AREAPORTAL 0x8000
#define CONTENTS_PLAYERCLIP 0x10000
#define CONTENTS_MONSTERCLIP 0x20000
//bot specific contents types
#define CONTENTS_TELEPORTER 0x40000
#define CONTENTS_JUMPPAD 0x80000
#define CONTENTS_CLUSTERPORTAL 0x100000
#define CONTENTS_DONOTENTER 0x200000
#define CONTENTS_ORIGIN 0x1000000 // removed before bsping an entity
#define CONTENTS_BODY 0x2000000 // should never be on a brush, only in game
#define CONTENTS_CORPSE 0x4000000
#define CONTENTS_DETAIL 0x8000000 // brushes not used for the bsp
#define CONTENTS_STRUCTURAL 0x10000000 // brushes used for the bsp
#define CONTENTS_TRANSLUCENT 0x20000000 // don't consume surface fragments inside
#define CONTENTS_TRIGGER 0x40000000
#define CONTENTS_NODROP 0x80000000 // don't leave bodies or items (death fog, lava)
#define SURF_NODAMAGE 0x1 // never give falling damage
#define SURF_SLICK 0x2 // effects game physics
#define SURF_SKY 0x4 // lighting from environment map
#define SURF_LADDER 0x8
#define SURF_NOIMPACT 0x10 // don't make missile explosions
#define SURF_NOMARKS 0x20 // don't leave missile marks
#define SURF_FLESH 0x40 // make flesh sounds and effects
#define SURF_NODRAW 0x80 // don't generate a drawsurface at all
#define SURF_HINT 0x100 // make a primary bsp splitter
#define SURF_SKIP 0x200 // completely ignore, allowing non-closed brushes
#define SURF_NOLIGHTMAP 0x400 // surface doesn't need a lightmap
#define SURF_POINTLIGHT 0x800 // generate lighting info at vertexes
#define SURF_METALSTEPS 0x1000 // clanking footsteps
#define SURF_NOSTEPS 0x2000 // no footstep sounds
#define SURF_NONSOLID 0x4000 // don't collide against curves with this set
#define SURF_LIGHTFILTER 0x8000 // act as a light filter during q3map -light
#define SURF_ALPHASHADOW 0x10000 // do per-pixel light shadow casting in q3map
#define SURF_NODLIGHT 0x20000 // never add dynamic lights

441
common/threads.c Normal file
View file

@ -0,0 +1,441 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code 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.
Quake III Arena source code 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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "cmdlib.h"
#include "threads.h"
#define MAX_THREADS 64
int dispatch;
int workcount;
int oldf;
qboolean pacifier;
qboolean threaded;
/*
=============
GetThreadWork
=============
*/
int GetThreadWork (void)
{
int r;
int f;
ThreadLock ();
if (dispatch == workcount)
{
ThreadUnlock ();
return -1;
}
f = 10*dispatch / workcount;
if (f != oldf)
{
oldf = f;
if (pacifier)
_printf ("%i...", f);
}
r = dispatch;
dispatch++;
ThreadUnlock ();
return r;
}
void (*workfunction) (int);
void ThreadWorkerFunction (int threadnum)
{
int work;
while (1)
{
work = GetThreadWork ();
if (work == -1)
break;
//_printf ("thread %i, work %i\n", threadnum, work);
workfunction(work);
}
}
void RunThreadsOnIndividual (int workcnt, qboolean showpacifier, void(*func)(int))
{
if (numthreads == -1)
ThreadSetDefault ();
workfunction = func;
RunThreadsOn (workcnt, showpacifier, ThreadWorkerFunction);
}
/*
===================================================================
WIN32
===================================================================
*/
#ifdef WIN32
#define USED
#include <windows.h>
int numthreads = -1;
CRITICAL_SECTION crit;
static int enter;
void ThreadSetDefault (void)
{
SYSTEM_INFO info;
if (numthreads == -1) // not set manually
{
GetSystemInfo (&info);
numthreads = info.dwNumberOfProcessors;
if (numthreads < 1 || numthreads > 32)
numthreads = 1;
}
qprintf ("%i threads\n", numthreads);
}
void ThreadLock (void)
{
if (!threaded)
return;
EnterCriticalSection (&crit);
if (enter)
Error ("Recursive ThreadLock\n");
enter = 1;
}
void ThreadUnlock (void)
{
if (!threaded)
return;
if (!enter)
Error ("ThreadUnlock without lock\n");
enter = 0;
LeaveCriticalSection (&crit);
}
/*
=============
RunThreadsOn
=============
*/
void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int))
{
int threadid[MAX_THREADS];
HANDLE threadhandle[MAX_THREADS];
int i;
int start, end;
start = I_FloatTime ();
dispatch = 0;
workcount = workcnt;
oldf = -1;
pacifier = showpacifier;
threaded = qtrue;
//
// run threads in parallel
//
InitializeCriticalSection (&crit);
if (numthreads == 1)
{ // use same thread
func (0);
}
else
{
for (i=0 ; i<numthreads ; i++)
{
threadhandle[i] = CreateThread(
NULL, // LPSECURITY_ATTRIBUTES lpsa,
0, // DWORD cbStack,
(LPTHREAD_START_ROUTINE)func, // LPTHREAD_START_ROUTINE lpStartAddr,
(LPVOID)i, // LPVOID lpvThreadParm,
0, // DWORD fdwCreate,
&threadid[i]);
}
for (i=0 ; i<numthreads ; i++)
WaitForSingleObject (threadhandle[i], INFINITE);
}
DeleteCriticalSection (&crit);
threaded = qfalse;
end = I_FloatTime ();
if (pacifier)
_printf (" (%i)\n", end-start);
}
#endif
/*
===================================================================
OSF1
===================================================================
*/
#ifdef __osf__
#define USED
int numthreads = 4;
void ThreadSetDefault (void)
{
if (numthreads == -1) // not set manually
{
numthreads = 4;
}
}
#include <pthread.h>
pthread_mutex_t *my_mutex;
void ThreadLock (void)
{
if (my_mutex)
pthread_mutex_lock (my_mutex);
}
void ThreadUnlock (void)
{
if (my_mutex)
pthread_mutex_unlock (my_mutex);
}
/*
=============
RunThreadsOn
=============
*/
void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int))
{
int i;
pthread_t work_threads[MAX_THREADS];
pthread_addr_t status;
pthread_attr_t attrib;
pthread_mutexattr_t mattrib;
int start, end;
start = I_FloatTime ();
dispatch = 0;
workcount = workcnt;
oldf = -1;
pacifier = showpacifier;
threaded = qtrue;
if (pacifier)
setbuf (stdout, NULL);
if (!my_mutex)
{
my_mutex = malloc (sizeof(*my_mutex));
if (pthread_mutexattr_create (&mattrib) == -1)
Error ("pthread_mutex_attr_create failed");
if (pthread_mutexattr_setkind_np (&mattrib, MUTEX_FAST_NP) == -1)
Error ("pthread_mutexattr_setkind_np failed");
if (pthread_mutex_init (my_mutex, mattrib) == -1)
Error ("pthread_mutex_init failed");
}
if (pthread_attr_create (&attrib) == -1)
Error ("pthread_attr_create failed");
if (pthread_attr_setstacksize (&attrib, 0x100000) == -1)
Error ("pthread_attr_setstacksize failed");
for (i=0 ; i<numthreads ; i++)
{
if (pthread_create(&work_threads[i], attrib
, (pthread_startroutine_t)func, (pthread_addr_t)i) == -1)
Error ("pthread_create failed");
}
for (i=0 ; i<numthreads ; i++)
{
if (pthread_join (work_threads[i], &status) == -1)
Error ("pthread_join failed");
}
threaded = qfalse;
end = I_FloatTime ();
if (pacifier)
_printf (" (%i)\n", end-start);
}
#endif
/*
===================================================================
IRIX
===================================================================
*/
#ifdef _MIPS_ISA
#define USED
#include <task.h>
#include <abi_mutex.h>
#include <sys/types.h>
#include <sys/prctl.h>
int numthreads = -1;
abilock_t lck;
void ThreadSetDefault (void)
{
if (numthreads == -1)
numthreads = prctl(PR_MAXPPROCS);
_printf ("%i threads\n", numthreads);
usconfig (CONF_INITUSERS, numthreads);
}
void ThreadLock (void)
{
spin_lock (&lck);
}
void ThreadUnlock (void)
{
release_lock (&lck);
}
/*
=============
RunThreadsOn
=============
*/
void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int))
{
int i;
int pid[MAX_THREADS];
int start, end;
start = I_FloatTime ();
dispatch = 0;
workcount = workcnt;
oldf = -1;
pacifier = showpacifier;
threaded = qtrue;
if (pacifier)
setbuf (stdout, NULL);
init_lock (&lck);
for (i=0 ; i<numthreads-1 ; i++)
{
pid[i] = sprocsp ( (void (*)(void *, size_t))func, PR_SALL, (void *)i
, NULL, 0x200000); // 2 meg stacks
if (pid[i] == -1)
{
perror ("sproc");
Error ("sproc failed");
}
}
func(i);
for (i=0 ; i<numthreads-1 ; i++)
wait (NULL);
threaded = qfalse;
end = I_FloatTime ();
if (pacifier)
_printf (" (%i)\n", end-start);
}
#endif
/*
=======================================================================
SINGLE THREAD
=======================================================================
*/
#ifndef USED
int numthreads = 1;
void ThreadSetDefault (void)
{
numthreads = 1;
}
void ThreadLock (void)
{
}
void ThreadUnlock (void)
{
}
/*
=============
RunThreadsOn
=============
*/
void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int))
{
int i;
int start, end;
dispatch = 0;
workcount = workcnt;
oldf = -1;
pacifier = showpacifier;
start = I_FloatTime ();
func(0);
end = I_FloatTime ();
if (pacifier)
_printf (" (%i)\n", end-start);
}
#endif

31
common/threads.h Normal file
View file

@ -0,0 +1,31 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code 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.
Quake III Arena source code 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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
extern int numthreads;
void ThreadSetDefault (void);
int GetThreadWork (void);
void RunThreadsOnIndividual (int workcnt, qboolean showpacifier, void(*func)(int));
void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int));
void ThreadLock (void);
void ThreadUnlock (void);

231
common/trilib.c Normal file
View file

@ -0,0 +1,231 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code 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.
Quake III Arena source code 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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
// trilib.c: library for loading triangles from an Alias triangle file
//
#include <stdio.h>
#include "cmdlib.h"
#include "mathlib.h"
#include "polyset.h"
#include "trilib.h"
// on disk representation of a face
#define FLOAT_START 99999.0
#define FLOAT_END -FLOAT_START
#define MAGIC 123322
//#define NOISY 1
typedef struct {
float v[3];
} vector;
typedef struct
{
vector n; /* normal */
vector p; /* point */
vector c; /* color */
float u; /* u */
float v; /* v */
} aliaspoint_t;
typedef struct {
aliaspoint_t pt[3];
} tf_triangle;
static void ByteSwapTri (tf_triangle *tri)
{
int i;
for (i=0 ; i<sizeof(tf_triangle)/4 ; i++)
{
((int *)tri)[i] = BigLong (((int *)tri)[i]);
}
}
static void ReadPolysetGeometry( triangle_t *tripool, FILE *input, int count, triangle_t *ptri )
{
tf_triangle tri;
int i;
for (i = 0; i < count; ++i) {
int j;
fread( &tri, sizeof(tf_triangle), 1, input );
ByteSwapTri (&tri);
for (j=0 ; j<3 ; j++)
{
int k;
for (k=0 ; k<3 ; k++)
{
ptri->verts[j][k] = tri.pt[j].p.v[k];
ptri->normals[j][k] = tri.pt[j].n.v[k];
// ptri->colors[j][k] = tri.pt[j].c.v[k];
}
ptri->texcoords[j][0] = tri.pt[j].u;
ptri->texcoords[j][1] = tri.pt[j].v;
}
ptri++;
if ((ptri - tripool ) >= POLYSET_MAXTRIANGLES)
Error ("Error: too many triangles; increase POLYSET_MAXTRIANGLES\n");
}
}
void TRI_LoadPolysets( const char *filename, polyset_t **ppPSET, int *numpsets )
{
FILE *input;
float start;
char name[256], tex[256];
int i, count, magic, pset = 0;
triangle_t *ptri;
polyset_t *pPSET;
int iLevel;
int exitpattern;
float t;
t = -FLOAT_START;
*((unsigned char *)&exitpattern + 0) = *((unsigned char *)&t + 3);
*((unsigned char *)&exitpattern + 1) = *((unsigned char *)&t + 2);
*((unsigned char *)&exitpattern + 2) = *((unsigned char *)&t + 1);
*((unsigned char *)&exitpattern + 3) = *((unsigned char *)&t + 0);
if ((input = fopen(filename, "rb")) == 0)
Error ("reader: could not open file '%s'", filename);
iLevel = 0;
fread(&magic, sizeof(int), 1, input);
if (BigLong(magic) != MAGIC)
Error ("%s is not a Alias object separated triangle file, magic number is wrong.", filename);
pPSET = calloc( 1, POLYSET_MAXPOLYSETS * sizeof( polyset_t ) );
ptri = calloc( 1, POLYSET_MAXTRIANGLES * sizeof( triangle_t ) );
*ppPSET = pPSET;
while (feof(input) == 0) {
if (fread(&start, sizeof(float), 1, input) < 1)
break;
*(int *)&start = BigLong(*(int *)&start);
if (*(int *)&start != exitpattern)
{
if (start == FLOAT_START) {
/* Start of an object or group of objects. */
i = -1;
do {
/* There are probably better ways to read a string from */
/* a file, but this does allow you to do error checking */
/* (which I'm not doing) on a per character basis. */
++i;
fread( &(name[i]), sizeof( char ), 1, input);
} while( name[i] != '\0' );
if ( i != 0 )
strncpy( pPSET[pset].name, name, sizeof( pPSET[pset].name ) - 1 );
else
strcpy( pPSET[pset].name , "(unnamed)" );
strlwr( pPSET[pset].name );
// indent();
// fprintf(stdout,"OBJECT START: %s\n",name);
fread( &count, sizeof(int), 1, input);
count = BigLong(count);
++iLevel;
if (count != 0) {
// indent();
// fprintf(stdout,"NUMBER OF TRIANGLES: %d\n",count);
i = -1;
do {
++i;
fread( &(tex[i]), sizeof( char ), 1, input);
} while( tex[i] != '\0' );
/*
if ( i != 0 )
strncpy( pPSET[pset].texname, tex, sizeof( pPSET[pset].texname ) - 1 );
else
strcpy( pPSET[pset].texname, "(unnamed)" );
strlwr( pPSET[pset].texname );
*/
// indent();
// fprintf(stdout," Object texture name: '%s'\n",tex);
}
/* Else (count == 0) this is the start of a group, and */
/* no texture name is present. */
}
else if (start == FLOAT_END) {
/* End of an object or group. Yes, the name should be */
/* obvious from context, but it is in here just to be */
/* safe and to provide a little extra information for */
/* those who do not wish to write a recursive reader. */
/* Mea culpa. */
--iLevel;
i = -1;
do {
++i;
fread( &(name[i]), sizeof( char ), 1, input);
} while( name[i] != '\0' );
if ( i != 0 )
strncpy( pPSET[pset].name, name, sizeof( pPSET[pset].name ) - 1 );
else
strcpy( pPSET[pset].name , "(unnamed)" );
strlwr( pPSET[pset].name );
// indent();
// fprintf(stdout,"OBJECT END: %s\n",name);
continue;
}
}
//
// read the triangles
//
if ( count > 0 )
{
pPSET[pset].triangles = ptri;
ReadPolysetGeometry( pPSET[0].triangles, input, count, ptri );
ptri += count;
pPSET[pset].numtriangles = count;
if ( ++pset >= POLYSET_MAXPOLYSETS )
{
Error ("Error: too many polysets; increase POLYSET_MAXPOLYSETS\n");
}
}
}
*numpsets = pset;
fclose (input);
}

26
common/trilib.h Normal file
View file

@ -0,0 +1,26 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code 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.
Quake III Arena source code 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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
// trilib.h: header file for loading triangles from an Alias triangle file
//
void TRI_LoadPolysets( const char *filename, polyset_t **ppPSET, int *numpsets );