mirror of
https://github.com/id-Software/GtkRadiant.git
synced 2026-03-20 08:59:32 +01:00
The GtkRadiant sources as originally released under the GPL license.
This commit is contained in:
965
tools/quake3/common/aselib.c
Normal file
965
tools/quake3/common/aselib.c
Normal file
@@ -0,0 +1,965 @@
|
||||
/*
|
||||
Copyright (C) 1999-2006 Id Software, Inc. and contributors.
|
||||
For a list of contributors, see the accompanying CONTRIBUTORS file.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#include "aselib.h"
|
||||
#include "inout.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 ) { Sys_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 char gl_filename[1024];
|
||||
|
||||
static void ASE_Process( void );
|
||||
static void ASE_FreeGeomObject( int ndx );
|
||||
|
||||
#if defined (__linux__) || defined (__APPLE__)
|
||||
|
||||
static char* strlwr (char* string)
|
||||
{
|
||||
char *cp;
|
||||
for (cp = string; *cp; ++cp)
|
||||
{
|
||||
if ('A' <= *cp && *cp <= 'Z')
|
||||
*cp += 'a' - 'A';
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
** 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 = safe_malloc( ase.len );
|
||||
|
||||
Sys_Printf( "Processing '%s'\n", filename );
|
||||
|
||||
if ( fread( ase.buffer, ase.len, 1, fp ) != 1 )
|
||||
{
|
||||
fclose( fp );
|
||||
Error( "fread() != -1 for '%s'", filename );
|
||||
}
|
||||
|
||||
fclose( fp );
|
||||
|
||||
strcpy(gl_filename, filename);
|
||||
|
||||
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 )
|
||||
Sys_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 fullpath[1024], bitmap[1024], modeldir[1024];
|
||||
char filename[1024];
|
||||
int i = 0, count;
|
||||
|
||||
strcpy(filename, gl_filename);
|
||||
|
||||
if ( !strcmp( token, "*BITMAP" ) )
|
||||
{
|
||||
ASE_GetToken( qfalse );
|
||||
|
||||
// the purpose of this whole chunk of code below is to extract the relative path
|
||||
// from a full path in the ASE
|
||||
|
||||
strcpy( bitmap, s_token + 1 );
|
||||
if ( strchr( bitmap, '"' ) )
|
||||
*strchr( bitmap, '"' ) = 0;
|
||||
|
||||
/* convert backslash to slash */
|
||||
while ( bitmap[i] )
|
||||
{
|
||||
if ( bitmap[i] == '\\' )
|
||||
bitmap[i] = '/';
|
||||
i++;
|
||||
}
|
||||
|
||||
/* remove filename from path */
|
||||
for( i=strlen(filename); i>0; i--)
|
||||
{
|
||||
if(filename[i] == '/')
|
||||
{
|
||||
filename[i] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* replaces a relative path with a full path */
|
||||
if(bitmap[0] == '.' && bitmap[1] == '.' && bitmap[2] == '/')
|
||||
{
|
||||
while(bitmap[0] == '.' && bitmap[1] == '.' && bitmap[2] == '/')
|
||||
{
|
||||
/* remove last item from path */
|
||||
for( i=strlen(filename); i>0; i--)
|
||||
{
|
||||
if(filename[i] == '/')
|
||||
{
|
||||
filename[i] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
strcpy(bitmap, &bitmap[3]);
|
||||
}
|
||||
strcat(filename, "/");
|
||||
strcat(filename, bitmap);
|
||||
strcpy(bitmap, filename);
|
||||
}
|
||||
|
||||
if ( strstr( bitmap, gamedir ) )
|
||||
{
|
||||
strcpy( ase.materials[ase.numMaterials].name, strstr( bitmap, gamedir ) + strlen( gamedir ) );
|
||||
Sys_Printf("material name: \'%s\'\n", strstr( bitmap, gamedir ) + strlen( gamedir ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf( ase.materials[ase.numMaterials].name, "(not converted: '%s')", bitmap );
|
||||
Sys_Printf( "WARNING: illegal material name '%s'\n", bitmap );
|
||||
}
|
||||
}
|
||||
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] )
|
||||
{
|
||||
Sys_Printf( "Unknown token '%s'\n", s_token );
|
||||
}
|
||||
}
|
||||
|
||||
if ( !ase.currentObject )
|
||||
Error( "No animation data!" );
|
||||
|
||||
CollapseObjects();
|
||||
}
|
||||
31
tools/quake3/common/aselib.h
Normal file
31
tools/quake3/common/aselib.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
Copyright (C) 1999-2006 Id Software, Inc. and contributors.
|
||||
For a list of contributors, see the accompanying CONTRIBUTORS file.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#include "../common/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 );
|
||||
706
tools/quake3/common/bspfile.c
Normal file
706
tools/quake3/common/bspfile.c
Normal file
@@ -0,0 +1,706 @@
|
||||
/*
|
||||
Copyright (C) 1999-2006 Id Software, Inc. and contributors.
|
||||
For a list of contributors, see the accompanying CONTRIBUTORS file.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#include "cmdlib.h"
|
||||
#include "mathlib.h"
|
||||
#include "inout.h"
|
||||
#include "bspfile.h"
|
||||
#include "scriplib.h"
|
||||
|
||||
void GetLeafNums (void);
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int bsp_version = Q3_BSP_VERSION;
|
||||
|
||||
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;
|
||||
|
||||
int numGridPoints;
|
||||
byte *gridData;
|
||||
|
||||
int numVisBytes;
|
||||
byte visBytes[MAX_MAP_VISIBILITY];
|
||||
|
||||
int numDrawVerts = 0;
|
||||
int numDrawVertsBuffer = 0;
|
||||
drawVert_t *drawVerts = NULL;
|
||||
|
||||
int numDrawIndexes;
|
||||
int drawIndexes[MAX_MAP_DRAW_INDEXES];
|
||||
|
||||
int numDrawSurfaces;
|
||||
int numDrawSurfacesBuffer = 0;
|
||||
dsurface_t *drawSurfaces = NULL;
|
||||
|
||||
int numFogs;
|
||||
dfog_t dfogs[MAX_MAP_FOGS];
|
||||
|
||||
void SetLightBytes(int n)
|
||||
{
|
||||
if(lightBytes != 0)
|
||||
free(lightBytes);
|
||||
|
||||
numLightBytes = n;
|
||||
|
||||
if(n == 0)
|
||||
return;
|
||||
|
||||
lightBytes = safe_malloc_info(numLightBytes, "SetLightBytes");
|
||||
|
||||
memset(lightBytes, 0, numLightBytes);
|
||||
}
|
||||
|
||||
void SetGridPoints(int n)
|
||||
{
|
||||
if(gridData != 0)
|
||||
free(gridData);
|
||||
|
||||
numGridPoints = n;
|
||||
|
||||
if(n == 0)
|
||||
return;
|
||||
|
||||
gridData = safe_malloc_info(numGridPoints * 8, "SetGridPoints");
|
||||
|
||||
memset(gridData, 0, numGridPoints * 8);
|
||||
}
|
||||
|
||||
void IncDrawVerts()
|
||||
{
|
||||
numDrawVerts++;
|
||||
|
||||
if(drawVerts == 0)
|
||||
{
|
||||
numDrawVertsBuffer = MAX_MAP_DRAW_VERTS / 37;
|
||||
|
||||
drawVerts = safe_malloc_info(sizeof(drawVert_t) * numDrawVertsBuffer, "IncDrawVerts");
|
||||
|
||||
}
|
||||
else if(numDrawVerts > numDrawVertsBuffer)
|
||||
{
|
||||
numDrawVertsBuffer *= 3; // multiply by 1.5
|
||||
numDrawVertsBuffer /= 2;
|
||||
|
||||
if(numDrawVertsBuffer > MAX_MAP_DRAW_VERTS)
|
||||
numDrawVertsBuffer = MAX_MAP_DRAW_VERTS;
|
||||
|
||||
drawVerts = realloc(drawVerts, sizeof(drawVert_t) * numDrawVertsBuffer);
|
||||
|
||||
if(!drawVerts)
|
||||
Error( "realloc() failed (IncDrawVerts)");
|
||||
}
|
||||
|
||||
memset(drawVerts + (numDrawVerts - 1), 0, sizeof(drawVert_t));
|
||||
}
|
||||
|
||||
void SetDrawVerts(int n)
|
||||
{
|
||||
if(drawVerts != 0)
|
||||
free(drawVerts);
|
||||
|
||||
numDrawVerts = n;
|
||||
numDrawVertsBuffer = numDrawVerts;
|
||||
|
||||
drawVerts = safe_malloc_info(sizeof(drawVert_t) * numDrawVertsBuffer, "IncDrawVerts");
|
||||
|
||||
memset(drawVerts, 0, n * sizeof(drawVert_t));
|
||||
}
|
||||
|
||||
void SetDrawSurfacesBuffer()
|
||||
{
|
||||
if(drawSurfaces != 0)
|
||||
free(drawSurfaces);
|
||||
|
||||
numDrawSurfacesBuffer = MAX_MAP_DRAW_SURFS;
|
||||
|
||||
drawSurfaces = safe_malloc_info(sizeof(dsurface_t) * numDrawSurfacesBuffer, "IncDrawSurfaces");
|
||||
|
||||
memset(drawSurfaces, 0, MAX_MAP_DRAW_SURFS * sizeof(drawVert_t));
|
||||
}
|
||||
|
||||
void SetDrawSurfaces(int n)
|
||||
{
|
||||
if(drawSurfaces != 0)
|
||||
free(drawSurfaces);
|
||||
|
||||
numDrawSurfaces = n;
|
||||
numDrawSurfacesBuffer = numDrawSurfaces;
|
||||
|
||||
drawSurfaces = safe_malloc_info(sizeof(dsurface_t) * numDrawSurfacesBuffer, "IncDrawSurfaces");
|
||||
|
||||
memset(drawSurfaces, 0, n * sizeof(drawVert_t));
|
||||
}
|
||||
|
||||
void BspFilesCleanup()
|
||||
{
|
||||
if(drawVerts != 0)
|
||||
free(drawVerts);
|
||||
if(drawSurfaces != 0)
|
||||
free(drawSurfaces);
|
||||
if(lightBytes != 0)
|
||||
free(lightBytes);
|
||||
if(gridData != 0)
|
||||
free(gridData);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
/*
|
||||
=============
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
GetLumpElements
|
||||
=============
|
||||
*/
|
||||
int GetLumpElements( dheader_t *header, int lump, int size ) {
|
||||
int length, ofs;
|
||||
|
||||
length = header->lumps[lump].filelen;
|
||||
ofs = header->lumps[lump].fileofs;
|
||||
|
||||
if ( length % size ) {
|
||||
Error ("LoadBSPFile: odd lump size");
|
||||
}
|
||||
|
||||
return length / size;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
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 == 0)
|
||||
return 0;
|
||||
|
||||
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 = GetLumpElements( header, LUMP_DRAWVERTS, sizeof(drawVert_t) );
|
||||
SetDrawVerts(numDrawVerts);
|
||||
CopyLump( header, LUMP_DRAWVERTS, drawVerts, sizeof(drawVert_t) );
|
||||
numDrawSurfaces = GetLumpElements( header, LUMP_SURFACES, sizeof(dsurface_t) );
|
||||
SetDrawSurfaces(numDrawSurfaces);
|
||||
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 = GetLumpElements( header, LUMP_LIGHTMAPS, 1 );
|
||||
SetLightBytes(numLightBytes);
|
||||
CopyLump( header, LUMP_LIGHTMAPS, lightBytes, 1 );
|
||||
entdatasize = CopyLump( header, LUMP_ENTITIES, dentdata, 1);
|
||||
|
||||
numGridPoints = GetLumpElements( header, LUMP_LIGHTGRID, 8 );
|
||||
SetGridPoints(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();
|
||||
}
|
||||
|
||||
Sys_Printf ("%6i models %7i\n"
|
||||
,nummodels, (int)(nummodels*sizeof(dmodel_t)));
|
||||
Sys_Printf ("%6i shaders %7i\n"
|
||||
,numShaders, (int)(numShaders*sizeof(dshader_t)));
|
||||
Sys_Printf ("%6i brushes %7i\n"
|
||||
,numbrushes, (int)(numbrushes*sizeof(dbrush_t)));
|
||||
Sys_Printf ("%6i brushsides %7i\n"
|
||||
,numbrushsides, (int)(numbrushsides*sizeof(dbrushside_t)));
|
||||
Sys_Printf ("%6i fogs %7i\n"
|
||||
,numFogs, (int)(numFogs*sizeof(dfog_t)));
|
||||
Sys_Printf ("%6i planes %7i\n"
|
||||
,numplanes, (int)(numplanes*sizeof(dplane_t)));
|
||||
Sys_Printf ("%6i entdata %7i\n", num_entities, entdatasize);
|
||||
|
||||
Sys_Printf ("\n");
|
||||
|
||||
Sys_Printf ("%6i nodes %7i\n"
|
||||
,numnodes, (int)(numnodes*sizeof(dnode_t)));
|
||||
Sys_Printf ("%6i leafs %7i\n"
|
||||
,numleafs, (int)(numleafs*sizeof(dleaf_t)));
|
||||
Sys_Printf ("%6i leafsurfaces %7i\n"
|
||||
,numleafsurfaces, (int)(numleafsurfaces*sizeof(dleafsurfaces[0])));
|
||||
Sys_Printf ("%6i leafbrushes %7i\n"
|
||||
,numleafbrushes, (int)(numleafbrushes*sizeof(dleafbrushes[0])));
|
||||
Sys_Printf ("%6i drawverts %7i\n"
|
||||
,numDrawVerts, (int)(numDrawVerts*sizeof(drawVerts[0])));
|
||||
Sys_Printf ("%6i drawindexes %7i\n"
|
||||
,numDrawIndexes, (int)(numDrawIndexes*sizeof(drawIndexes[0])));
|
||||
Sys_Printf ("%6i drawsurfaces %7i\n"
|
||||
,numDrawSurfaces, (int)(numDrawSurfaces*sizeof(drawSurfaces[0])));
|
||||
|
||||
Sys_Printf ("%6i lightmaps %7i\n"
|
||||
,numLightBytes / (LIGHTMAP_WIDTH*LIGHTMAP_HEIGHT*3), numLightBytes );
|
||||
Sys_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 = safe_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;
|
||||
|
||||
Sys_Printf ("------- entity %p -------\n", ent);
|
||||
for (ep=ent->epairs ; ep ; ep=ep->next) {
|
||||
Sys_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 = safe_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;
|
||||
}
|
||||
|
||||
|
||||
121
tools/quake3/common/bspfile.h
Normal file
121
tools/quake3/common/bspfile.h
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
Copyright (C) 1999-2006 Id Software, Inc. and contributors.
|
||||
For a list of contributors, see the accompanying CONTRIBUTORS file.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "qfiles.h"
|
||||
#include "surfaceflags.h"
|
||||
|
||||
extern int bsp_version;
|
||||
|
||||
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];
|
||||
|
||||
void SetLightBytes(int n);
|
||||
extern int numLightBytes;
|
||||
extern byte *lightBytes;
|
||||
|
||||
void SetGridPoints(int n);
|
||||
extern int numGridPoints;
|
||||
extern byte *gridData;
|
||||
|
||||
extern int numVisBytes;
|
||||
extern byte visBytes[MAX_MAP_VISIBILITY];
|
||||
|
||||
void SetDrawVerts(int n);
|
||||
void IncDrawVerts();
|
||||
extern int numDrawVerts;
|
||||
extern drawVert_t *drawVerts;
|
||||
|
||||
extern int numDrawIndexes;
|
||||
extern int drawIndexes[MAX_MAP_DRAW_INDEXES];
|
||||
|
||||
void SetDrawSurfaces(int n);
|
||||
void SetDrawSurfacesBuffer();
|
||||
extern int numDrawSurfaces;
|
||||
extern dsurface_t *drawSurfaces;
|
||||
|
||||
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 );
|
||||
|
||||
1153
tools/quake3/common/cmdlib.c
Normal file
1153
tools/quake3/common/cmdlib.c
Normal file
File diff suppressed because it is too large
Load Diff
160
tools/quake3/common/cmdlib.h
Normal file
160
tools/quake3/common/cmdlib.h
Normal file
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
Copyright (C) 1999-2006 Id Software, Inc. and contributors.
|
||||
For a list of contributors, see the accompanying CONTRIBUTORS file.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
// cmdlib.h
|
||||
|
||||
#ifndef __CMDLIB__
|
||||
#define __CMDLIB__
|
||||
|
||||
#include "bytebool.h"
|
||||
|
||||
#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
|
||||
|
||||
|
||||
#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)
|
||||
|
||||
#define SAFE_MALLOC
|
||||
#ifdef SAFE_MALLOC
|
||||
void *safe_malloc( size_t size );
|
||||
void *safe_malloc_info( size_t size, char* info );
|
||||
#else
|
||||
#define safe_malloc(a) malloc(a)
|
||||
#endif /* SAFE_MALLOC */
|
||||
|
||||
// set these before calling CheckParm
|
||||
extern int myargc;
|
||||
extern char **myargv;
|
||||
|
||||
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];
|
||||
extern char *moddirparam;
|
||||
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 );
|
||||
void ExpandWildcards( int *argc, char ***argv );
|
||||
|
||||
|
||||
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];
|
||||
|
||||
// sleep for the given amount of milliseconds
|
||||
void Sys_Sleep(int n);
|
||||
|
||||
// for compression routines
|
||||
typedef struct
|
||||
{
|
||||
void *data;
|
||||
int count, width, height;
|
||||
} cblock_t;
|
||||
|
||||
|
||||
#endif
|
||||
1230
tools/quake3/common/imagelib.c
Normal file
1230
tools/quake3/common/imagelib.c
Normal file
File diff suppressed because it is too large
Load Diff
44
tools/quake3/common/imagelib.h
Normal file
44
tools/quake3/common/imagelib.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
Copyright (C) 1999-2006 Id Software, Inc. and contributors.
|
||||
For a list of contributors, see the accompanying CONTRIBUTORS file.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
// 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 ( const byte *buffer, const byte* enddata, 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);
|
||||
|
||||
375
tools/quake3/common/inout.c
Normal file
375
tools/quake3/common/inout.c
Normal file
@@ -0,0 +1,375 @@
|
||||
/*
|
||||
Copyright (C) 1999-2006 Id Software, Inc. and contributors.
|
||||
For a list of contributors, see the accompanying CONTRIBUTORS file.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// deal with in/out tasks, for either stdin/stdout or network/XML stream
|
||||
//
|
||||
|
||||
#include "cmdlib.h"
|
||||
#include "mathlib.h"
|
||||
#include "polylib.h"
|
||||
#include "inout.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <direct.h>
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
// network broadcasting
|
||||
#include "l_net/l_net.h"
|
||||
#include "libxml/tree.h"
|
||||
|
||||
// utf8 conversion
|
||||
#include <glib/gconvert.h>
|
||||
#include <glib/gmem.h>
|
||||
|
||||
#ifdef WIN32
|
||||
HWND hwndOut = NULL;
|
||||
qboolean lookedForServer = qfalse;
|
||||
UINT wm_BroadcastCommand = -1;
|
||||
#endif
|
||||
|
||||
socket_t *brdcst_socket;
|
||||
netmessage_t msg;
|
||||
|
||||
qboolean verbose = qfalse;
|
||||
|
||||
// our main document
|
||||
// is streamed through the network to Radiant
|
||||
// possibly written to disk at the end of the run
|
||||
//++timo FIXME: need to be global, required when creating nodes?
|
||||
xmlDocPtr doc;
|
||||
xmlNodePtr tree;
|
||||
|
||||
// some useful stuff
|
||||
xmlNodePtr xml_NodeForVec( vec3_t v )
|
||||
{
|
||||
xmlNodePtr ret;
|
||||
char buf[1024];
|
||||
|
||||
sprintf (buf, "%f %f %f", v[0], v[1], v[2]);
|
||||
ret = xmlNewNode (NULL, "point");
|
||||
xmlNodeSetContent (ret, buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// send a node down the stream, add it to the document
|
||||
void xml_SendNode (xmlNodePtr node)
|
||||
{
|
||||
xmlBufferPtr xml_buf;
|
||||
char xmlbuf[MAX_NETMESSAGE]; // we have to copy content from the xmlBufferPtr into an aux buffer .. that sucks ..
|
||||
// this index loops through the node buffer
|
||||
int pos = 0;
|
||||
int size;
|
||||
|
||||
xmlAddChild( doc->children, node );
|
||||
|
||||
if (brdcst_socket)
|
||||
{
|
||||
xml_buf = xmlBufferCreate();
|
||||
xmlNodeDump( xml_buf, doc, node, 0, 0 );
|
||||
|
||||
// the XML node might be too big to fit in a single network message
|
||||
// l_net library defines an upper limit of MAX_NETMESSAGE
|
||||
// there are some size check errors, so we use MAX_NETMESSAGE-10 to be safe
|
||||
// if the size of the buffer exceeds MAX_NETMESSAGE-10 we'll send in several network messages
|
||||
while (pos < xml_buf->use)
|
||||
{
|
||||
// what size are we gonna send now?
|
||||
(xml_buf->use - pos < MAX_NETMESSAGE - 10) ? (size = xml_buf->use - pos) : (size = MAX_NETMESSAGE - 10);
|
||||
//++timo just a debug thing
|
||||
if (size == MAX_NETMESSAGE - 10)
|
||||
Sys_FPrintf (SYS_NOXML, "Got to split the buffer\n");
|
||||
memcpy( xmlbuf, xml_buf->content+pos, size);
|
||||
xmlbuf[size] = '\0';
|
||||
NMSG_Clear( &msg );
|
||||
NMSG_WriteString (&msg, xmlbuf );
|
||||
Net_Send(brdcst_socket, &msg );
|
||||
// now that the thing is sent prepare to loop again
|
||||
pos += size;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// NOTE: the NMSG_WriteString is limited to MAX_NETMESSAGE
|
||||
// we will need to split into chunks
|
||||
// (we could also go lower level, in the end it's using send and receiv which are not size limited)
|
||||
//++timo FIXME: MAX_NETMESSAGE is not exactly the max size we can stick in the message
|
||||
// there's some tweaking to do in l_net for that .. so let's give us a margin for now
|
||||
|
||||
//++timo we need to handle the case of a buffer too big to fit in a single message
|
||||
// try without checks for now
|
||||
if (xml_buf->use > MAX_NETMESSAGE-10 )
|
||||
{
|
||||
// if we send that we are probably gonna break the stream at the other end..
|
||||
// and Error will call right there
|
||||
//Error( "MAX_NETMESSAGE exceeded for XML feedback stream in FPrintf (%d)\n", xml_buf->use);
|
||||
Sys_FPrintf (SYS_NOXML, "MAX_NETMESSAGE exceeded for XML feedback stream in FPrintf (%d)\n", xml_buf->use);
|
||||
xml_buf->content[xml_buf->use]='\0'; //++timo this corrupts the buffer but we don't care it's for printing
|
||||
Sys_FPrintf (SYS_NOXML, xml_buf->content);
|
||||
|
||||
}
|
||||
|
||||
size = xml_buf->use;
|
||||
memcpy( xmlbuf, xml_buf->content, size );
|
||||
xmlbuf[size] = '\0';
|
||||
NMSG_Clear( &msg );
|
||||
NMSG_WriteString (&msg, xmlbuf );
|
||||
Net_Send(brdcst_socket, &msg );
|
||||
#endif
|
||||
|
||||
xmlBufferFree( xml_buf );
|
||||
}
|
||||
}
|
||||
|
||||
void xml_Select (char *msg, int entitynum, int brushnum, qboolean bError)
|
||||
{
|
||||
xmlNodePtr node, select;
|
||||
char buf[1024];
|
||||
char level[2];
|
||||
|
||||
// now build a proper "select" XML node
|
||||
sprintf (buf, "Entity %i, Brush %i: %s", entitynum, brushnum, msg);
|
||||
node = xmlNewNode (NULL, "select");
|
||||
xmlNodeSetContent (node, buf);
|
||||
level[0] = (int)'0' + (bError ? SYS_ERR : SYS_WRN) ;
|
||||
level[1] = 0;
|
||||
xmlSetProp (node, "level", (char *)&level);
|
||||
// a 'select' information
|
||||
sprintf (buf, "%i %i", entitynum, brushnum);
|
||||
select = xmlNewNode (NULL, "brush");
|
||||
xmlNodeSetContent (select, buf);
|
||||
xmlAddChild (node, select);
|
||||
xml_SendNode (node);
|
||||
|
||||
sprintf (buf, "Entity %i, Brush %i: %s", entitynum, brushnum, msg);
|
||||
if (bError)
|
||||
Error(buf);
|
||||
else
|
||||
Sys_FPrintf (SYS_NOXML, "%s\n", buf);
|
||||
|
||||
}
|
||||
|
||||
void xml_Point (char *msg, vec3_t pt)
|
||||
{
|
||||
xmlNodePtr node, point;
|
||||
char buf[1024];
|
||||
char level[2];
|
||||
|
||||
node = xmlNewNode (NULL, "pointmsg");
|
||||
xmlNodeSetContent (node, msg);
|
||||
level[0] = (int)'0' + SYS_ERR;
|
||||
level[1] = 0;
|
||||
xmlSetProp (node, "level", (char *)&level);
|
||||
// a 'point' node
|
||||
sprintf (buf, "%g %g %g", pt[0], pt[1], pt[2]);
|
||||
point = xmlNewNode (NULL, "point");
|
||||
xmlNodeSetContent (point, buf);
|
||||
xmlAddChild (node, point);
|
||||
xml_SendNode (node);
|
||||
|
||||
sprintf (buf, "%s (%g %g %g)", msg, pt[0], pt[1], pt[2]);
|
||||
Error (buf);
|
||||
}
|
||||
|
||||
#define WINDING_BUFSIZE 2048
|
||||
void xml_Winding (char *msg, vec3_t p[], int numpoints, qboolean die)
|
||||
{
|
||||
xmlNodePtr node, winding;
|
||||
char buf[WINDING_BUFSIZE];
|
||||
char smlbuf[128];
|
||||
char level[2];
|
||||
int i;
|
||||
|
||||
node = xmlNewNode (NULL, "windingmsg");
|
||||
xmlNodeSetContent (node, msg);
|
||||
level[0] = (int)'0' + SYS_ERR;
|
||||
level[1] = 0;
|
||||
xmlSetProp (node, "level", (char *)&level);
|
||||
// a 'winding' node
|
||||
sprintf( buf, "%i ", numpoints);
|
||||
for(i = 0; i < numpoints; i++)
|
||||
{
|
||||
sprintf (smlbuf, "(%g %g %g)", p[i][0], p[i][1], p[i][2]);
|
||||
// don't overflow
|
||||
if (strlen(buf)+strlen(smlbuf)>WINDING_BUFSIZE)
|
||||
break;
|
||||
strcat( buf, smlbuf);
|
||||
}
|
||||
|
||||
winding = xmlNewNode (NULL, "winding");
|
||||
xmlNodeSetContent (winding, buf);
|
||||
xmlAddChild (node, winding);
|
||||
xml_SendNode (node);
|
||||
|
||||
if(die)
|
||||
Error (msg);
|
||||
else
|
||||
{
|
||||
Sys_Printf(msg);
|
||||
Sys_Printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
// in include
|
||||
#include "stream_version.h"
|
||||
|
||||
void Broadcast_Setup( const char *dest )
|
||||
{
|
||||
address_t address;
|
||||
char sMsg[1024];
|
||||
|
||||
Net_Setup();
|
||||
Net_StringToAddress((char *)dest, &address);
|
||||
brdcst_socket = Net_Connect(&address, 0);
|
||||
if (brdcst_socket)
|
||||
{
|
||||
// send in a header
|
||||
sprintf (sMsg, "<?xml version=\"1.0\"?><q3map_feedback version=\"" Q3MAP_STREAM_VERSION "\">");
|
||||
NMSG_Clear( &msg );
|
||||
NMSG_WriteString(&msg, sMsg );
|
||||
Net_Send(brdcst_socket, &msg );
|
||||
}
|
||||
}
|
||||
|
||||
void Broadcast_Shutdown()
|
||||
{
|
||||
if (brdcst_socket)
|
||||
{
|
||||
Sys_Printf("Disconnecting\n");
|
||||
Net_Disconnect(brdcst_socket);
|
||||
brdcst_socket = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// all output ends up through here
|
||||
void FPrintf (int flag, char *buf)
|
||||
{
|
||||
xmlNodePtr node;
|
||||
static qboolean bGotXML = qfalse;
|
||||
char level[2];
|
||||
|
||||
printf(buf);
|
||||
|
||||
// the following part is XML stuff only.. but maybe we don't want that message to go down the XML pipe?
|
||||
if (flag == SYS_NOXML)
|
||||
return;
|
||||
|
||||
// ouput an XML file of the run
|
||||
// use the DOM interface to build a tree
|
||||
/*
|
||||
<message level='flag'>
|
||||
message string
|
||||
.. various nodes to describe corresponding geometry ..
|
||||
</message>
|
||||
*/
|
||||
if (!bGotXML)
|
||||
{
|
||||
// initialize
|
||||
doc = xmlNewDoc("1.0");
|
||||
doc->children = xmlNewDocRawNode(doc, NULL, "q3map_feedback", NULL);
|
||||
bGotXML = qtrue;
|
||||
}
|
||||
node = xmlNewNode (NULL, "message");
|
||||
{
|
||||
gchar* utf8 = g_locale_to_utf8(buf, -1, NULL, NULL, NULL);
|
||||
xmlNodeSetContent(node, utf8);
|
||||
g_free(utf8);
|
||||
}
|
||||
level[0] = (int)'0' + flag;
|
||||
level[1] = 0;
|
||||
xmlSetProp (node, "level", (char *)&level );
|
||||
|
||||
xml_SendNode (node);
|
||||
}
|
||||
|
||||
#ifdef DBG_XML
|
||||
void DumpXML()
|
||||
{
|
||||
xmlSaveFile( "XMLDump.xml", doc );
|
||||
}
|
||||
#endif
|
||||
|
||||
void Sys_FPrintf (int flag, const char *format, ...)
|
||||
{
|
||||
char out_buffer[4096];
|
||||
va_list argptr;
|
||||
|
||||
if ((flag == SYS_VRB) && (verbose == qfalse))
|
||||
return;
|
||||
|
||||
va_start (argptr, format);
|
||||
vsprintf (out_buffer, format, argptr);
|
||||
va_end (argptr);
|
||||
|
||||
FPrintf (flag, out_buffer);
|
||||
}
|
||||
|
||||
void Sys_Printf (const char *format, ...)
|
||||
{
|
||||
char out_buffer[4096];
|
||||
va_list argptr;
|
||||
|
||||
va_start (argptr, format);
|
||||
vsprintf (out_buffer, format, argptr);
|
||||
va_end (argptr);
|
||||
|
||||
FPrintf (SYS_STD, out_buffer);
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Error
|
||||
|
||||
For abnormal program terminations
|
||||
=================
|
||||
*/
|
||||
void Error( const char *error, ...)
|
||||
{
|
||||
char out_buffer[4096];
|
||||
char tmp[4096];
|
||||
va_list argptr;
|
||||
|
||||
va_start (argptr,error);
|
||||
vsprintf (tmp, error, argptr);
|
||||
va_end (argptr);
|
||||
|
||||
sprintf( out_buffer, "************ ERROR ************\n%s\n", tmp );
|
||||
|
||||
FPrintf( SYS_ERR, out_buffer );
|
||||
|
||||
#ifdef DBG_XML
|
||||
DumpXML();
|
||||
#endif
|
||||
|
||||
//++timo HACK ALERT .. if we shut down too fast the xml stream won't reach the listener.
|
||||
// a clean solution is to send a sync request node in the stream and wait for an answer before exiting
|
||||
Sys_Sleep( 1000 );
|
||||
|
||||
Broadcast_Shutdown();
|
||||
|
||||
exit (1);
|
||||
}
|
||||
|
||||
62
tools/quake3/common/inout.h
Normal file
62
tools/quake3/common/inout.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
Copyright (C) 1999-2006 Id Software, Inc. and contributors.
|
||||
For a list of contributors, see the accompanying CONTRIBUTORS file.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __INOUT__
|
||||
#define __INOUT__
|
||||
|
||||
// inout is the only stuff relying on xml, include the headers there
|
||||
#include "libxml/tree.h"
|
||||
#include "mathlib.h"
|
||||
|
||||
// some useful xml routines
|
||||
xmlNodePtr xml_NodeForVec( vec3_t v );
|
||||
void xml_SendNode (xmlNodePtr node);
|
||||
// print a message in q3map output and send the corresponding select information down the xml stream
|
||||
// bError: do we end with an error on this one or do we go ahead?
|
||||
void xml_Select (char *msg, int entitynum, int brushnum, qboolean bError);
|
||||
// end q3map with an error message and send a point information in the xml stream
|
||||
// note: we might want to add a boolean to use this as a warning or an error thing..
|
||||
void xml_Winding (char *msg, vec3_t p[], int numpoints, qboolean die);
|
||||
void xml_Point (char *msg, vec3_t pt);
|
||||
|
||||
extern qboolean bNetworkBroadcast;
|
||||
void Broadcast_Setup( const char *dest );
|
||||
void Broadcast_Shutdown();
|
||||
|
||||
#define SYS_VRB 0 // verbose support (on/off)
|
||||
#define SYS_STD 1 // standard print level
|
||||
#define SYS_WRN 2 // warnings
|
||||
#define SYS_ERR 3 // error
|
||||
#define SYS_NOXML 4 // don't send that down the XML stream
|
||||
|
||||
extern qboolean verbose;
|
||||
void Sys_Printf (const char *text, ...);
|
||||
void Sys_FPrintf (int flag, const char *text, ...);
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define DBG_XML 1
|
||||
#endif
|
||||
|
||||
#ifdef DBG_XML
|
||||
void DumpXML();
|
||||
#endif
|
||||
|
||||
#endif
|
||||
301
tools/quake3/common/l3dslib.c
Normal file
301
tools/quake3/common/l3dslib.c
Normal file
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
Copyright (C) 1999-2006 Id Software, Inc. and contributors.
|
||||
For a list of contributors, see the accompanying CONTRIBUTORS file.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
//
|
||||
// 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
|
||||
#define MAXTRIANGLES 750
|
||||
|
||||
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 = safe_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
tools/quake3/common/l3dslib.h
Normal file
26
tools/quake3/common/l3dslib.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
Copyright (C) 1999-2006 Id Software, Inc. and contributors.
|
||||
For a list of contributors, see the accompanying CONTRIBUTORS file.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
//
|
||||
// l3dslib.h: header file for loading triangles from a 3DS triangle file
|
||||
//
|
||||
void Load3DSTriangleList (char *filename, triangle_t **pptri, int *numtriangles);
|
||||
|
||||
298
tools/quake3/common/md4.c
Normal file
298
tools/quake3/common/md4.c
Normal file
@@ -0,0 +1,298 @@
|
||||
/*
|
||||
Copyright (C) 1999-2006 Id Software, Inc. and contributors.
|
||||
For a list of contributors, see the accompanying CONTRIBUTORS file.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/* 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
tools/quake3/common/mutex.c
Normal file
197
tools/quake3/common/mutex.c
Normal file
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
Copyright (C) 1999-2006 Id Software, Inc. and contributors.
|
||||
For a list of contributors, see the accompanying CONTRIBUTORS file.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#include "cmdlib.h"
|
||||
#include "qthreads.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 *) safe_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 = safe_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 *) safe_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
tools/quake3/common/mutex.h
Normal file
28
tools/quake3/common/mutex.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
Copyright (C) 1999-2006 Id Software, Inc. and contributors.
|
||||
For a list of contributors, see the accompanying CONTRIBUTORS file.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
|
||||
typedef void *mutex_t;
|
||||
|
||||
void MutexLock (mutex_t *m);
|
||||
void MutexUnlock (mutex_t *m);
|
||||
mutex_t *MutexAlloc(void);
|
||||
745
tools/quake3/common/polylib.c
Normal file
745
tools/quake3/common/polylib.c
Normal file
@@ -0,0 +1,745 @@
|
||||
/*
|
||||
Copyright (C) 1999-2006 Id Software, Inc. and contributors.
|
||||
For a list of contributors, see the accompanying CONTRIBUTORS file.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#include "cmdlib.h"
|
||||
#include "mathlib.h"
|
||||
#include "inout.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++)
|
||||
Sys_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 (points >= MAX_POINTS_ON_WINDING)
|
||||
Error ("AllocWinding failed: MAX_POINTS_ON_WINDING exceeded");
|
||||
|
||||
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 = safe_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: MAX_WORLD_COORD exceeded: %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
tools/quake3/common/polylib.h
Normal file
57
tools/quake3/common/polylib.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
Copyright (C) 1999-2006 Id Software, Inc. and contributors.
|
||||
For a list of contributors, see the accompanying CONTRIBUTORS file.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
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
tools/quake3/common/polyset.h
Normal file
51
tools/quake3/common/polyset.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
Copyright (C) 1999-2006 Id Software, Inc. and contributors.
|
||||
For a list of contributors, see the accompanying CONTRIBUTORS file.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#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
tools/quake3/common/qfiles.h
Normal file
489
tools/quake3/common/qfiles.h
Normal file
@@ -0,0 +1,489 @@
|
||||
/*
|
||||
Copyright (C) 1999-2006 Id Software, Inc. and contributors.
|
||||
For a list of contributors, see the accompanying CONTRIBUTORS file.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#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
|
||||
#define Q3_BSP_VERSION 46
|
||||
#define WOLF_BSP_VERSION 47
|
||||
|
||||
// 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 0x40000 //% 0x20000 /* ydnar */
|
||||
#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 MIN_WORLD_COORD (-65536)
|
||||
#define MAX_WORLD_COORD (65536)
|
||||
#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
|
||||
31
tools/quake3/common/qthreads.h
Normal file
31
tools/quake3/common/qthreads.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
Copyright (C) 1999-2006 Id Software, Inc. and contributors.
|
||||
For a list of contributors, see the accompanying CONTRIBUTORS file.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
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);
|
||||
|
||||
409
tools/quake3/common/scriplib.c
Normal file
409
tools/quake3/common/scriplib.c
Normal file
@@ -0,0 +1,409 @@
|
||||
/*
|
||||
Copyright (C) 1999-2006 Id Software, Inc. and contributors.
|
||||
For a list of contributors, see the accompanying CONTRIBUTORS file.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
// scriplib.c
|
||||
|
||||
#include "cmdlib.h"
|
||||
#include "mathlib.h"
|
||||
#include "inout.h"
|
||||
#include "scriplib.h"
|
||||
#include "vfs.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 index)
|
||||
{
|
||||
int size;
|
||||
|
||||
script++;
|
||||
if (script == &scriptstack[MAX_INCLUDES])
|
||||
Error ("script file exceeded MAX_INCLUDES");
|
||||
strcpy (script->filename, ExpandPath (filename));
|
||||
|
||||
size = vfsLoadFile (script->filename, (void **)&script->buffer, index);
|
||||
|
||||
if (size == -1)
|
||||
Sys_Printf ("Script file %s was not found\n", script->filename);
|
||||
else
|
||||
{
|
||||
if (index > 0)
|
||||
Sys_Printf ("entering %s (%d)\n", script->filename, index+1);
|
||||
else
|
||||
Sys_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, int index)
|
||||
{
|
||||
script = scriptstack;
|
||||
AddScriptToStack (filename, index);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if( script->buffer == NULL )
|
||||
Sys_Printf( "WARNING: Attempt to free already freed script buffer\n" );
|
||||
else
|
||||
free( script->buffer );
|
||||
script->buffer = NULL;
|
||||
if (script == scriptstack+1)
|
||||
{
|
||||
endofscript = qtrue;
|
||||
return qfalse;
|
||||
}
|
||||
script--;
|
||||
scriptline = script->line;
|
||||
Sys_Printf ("returning to %s\n", script->filename);
|
||||
return GetToken (crossline);
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
GetToken
|
||||
==============
|
||||
*/
|
||||
qboolean GetToken (qboolean crossline)
|
||||
{
|
||||
char *token_p;
|
||||
|
||||
|
||||
/* ydnar: dummy testing */
|
||||
if( script == NULL || script->buffer == NULL )
|
||||
return qfalse;
|
||||
|
||||
if (tokenready) // is a token already waiting?
|
||||
{
|
||||
tokenready = qfalse;
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
if ((script->script_p >= script->end_p) || (script->script_p == NULL))
|
||||
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);
|
||||
script->line++;
|
||||
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);
|
||||
script->line++;
|
||||
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' )
|
||||
{
|
||||
script->line++;
|
||||
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, 0);
|
||||
return GetToken (crossline);
|
||||
}
|
||||
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
TokenAvailable
|
||||
|
||||
Returns qtrue if there is another token on the line
|
||||
==============
|
||||
*/
|
||||
qboolean TokenAvailable (void) {
|
||||
int oldLine, oldScriptLine;
|
||||
qboolean r;
|
||||
|
||||
/* save */
|
||||
oldLine = scriptline;
|
||||
oldScriptLine = script->line;
|
||||
|
||||
/* test */
|
||||
r = GetToken( qtrue );
|
||||
if ( !r ) {
|
||||
return qfalse;
|
||||
}
|
||||
UnGetToken();
|
||||
if ( oldLine == scriptline ) {
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
/* restore */
|
||||
//% scriptline = oldLine;
|
||||
//% script->line = oldScriptLine;
|
||||
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
|
||||
//=====================================================================
|
||||
|
||||
|
||||
void MatchToken( char *match ) {
|
||||
GetToken( qtrue );
|
||||
|
||||
if ( strcmp( token, match ) ) {
|
||||
Error( "MatchToken( \"%s\" ) failed at line %i in file %s", match, scriptline, script->filename);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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
tools/quake3/common/scriplib.h
Normal file
55
tools/quake3/common/scriplib.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
Copyright (C) 1999-2006 Id Software, Inc. and contributors.
|
||||
For a list of contributors, see the accompanying CONTRIBUTORS file.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
// scriplib.h
|
||||
|
||||
#ifndef __CMDLIB__
|
||||
#include "../common/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, int index);
|
||||
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);
|
||||
114
tools/quake3/common/surfaceflags.h
Normal file
114
tools/quake3/common/surfaceflags.h
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
Copyright (C) 1999-2006 Id Software, Inc. and contributors.
|
||||
For a list of contributors, see the accompanying CONTRIBUTORS file.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
// Copyright (C) 1999-2000 Id Software, Inc.
|
||||
//
|
||||
// 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_BOTCLIP 0x400000
|
||||
|
||||
#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 // don't dlight even if solid (solid lava, skies)
|
||||
#define SURF_DUST 0x40000 // leave a dust trail when walking on this surface
|
||||
|
||||
|
||||
|
||||
|
||||
/* ydnar flags */
|
||||
|
||||
#define CONTENTS_OPAQUE 0x02
|
||||
#define CONTENTS_LIGHTGRID 0x04
|
||||
|
||||
#define SURF_VERTEXLIT (SURF_POINTLIGHT | SURF_NOLIGHTMAP)
|
||||
|
||||
|
||||
|
||||
/* wolfenstein flags (collisions with valid q3a flags are noted) */
|
||||
|
||||
#define CONTENTS_MISSILECLIP 0x80
|
||||
#define CONTENTS_ITEM 0x100
|
||||
#define CONTENTS_AI_NOSIGHT 0x1000
|
||||
#define CONTENTS_CLIPSHOT 0x2000
|
||||
#define CONTENTS_DONOTENTER_LARGE 0x400000 /* CONTENTS_BOTCLIP */
|
||||
|
||||
#define SURF_CERAMIC 0x40 /* SURF_FLESH */
|
||||
#define SURF_METAL 0x1000 /* SURF_METALSTEPS */
|
||||
#define SURF_WOOD 0x40000 /* SURF_DUST */
|
||||
#define SURF_GRASS 0x80000
|
||||
#define SURF_GRAVEL 0x100000
|
||||
#define SURF_GLASS 0x200000
|
||||
#define SURF_SNOW 0x400000
|
||||
#define SURF_ROOF 0x800000
|
||||
#define SURF_RUBBLE 0x1000000
|
||||
#define SURF_CARPET 0x2000000
|
||||
#define SURF_MONSTERSLICK 0x4000000
|
||||
#define SURF_MONSLICK_W 0x8000000
|
||||
#define SURF_MONSLICK_N 0x10000000
|
||||
#define SURF_MONSLICK_E 0x20000000
|
||||
#define SURF_MONSLICK_S 0x40000000
|
||||
|
||||
|
||||
620
tools/quake3/common/threads.c
Normal file
620
tools/quake3/common/threads.c
Normal file
@@ -0,0 +1,620 @@
|
||||
/*
|
||||
Copyright (C) 1999-2006 Id Software, Inc. and contributors.
|
||||
For a list of contributors, see the accompanying CONTRIBUTORS file.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef WIN32
|
||||
// The below define is necessary to use
|
||||
// pthreads extensions like pthread_mutexattr_settype
|
||||
#define _GNU_SOURCE
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#include "cmdlib.h"
|
||||
#include "mathlib.h"
|
||||
#include "inout.h"
|
||||
#include "qthreads.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)
|
||||
{
|
||||
Sys_Printf ("%i...", f);
|
||||
fflush( stdout ); /* ydnar */
|
||||
}
|
||||
}
|
||||
|
||||
r = dispatch;
|
||||
dispatch++;
|
||||
ThreadUnlock ();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
void (*workfunction) (int);
|
||||
|
||||
void ThreadWorkerFunction (int threadnum)
|
||||
{
|
||||
int work;
|
||||
|
||||
while (1)
|
||||
{
|
||||
work = GetThreadWork ();
|
||||
if (work == -1)
|
||||
break;
|
||||
//Sys_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;
|
||||
}
|
||||
|
||||
Sys_Printf ("%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,
|
||||
|
||||
/* ydnar: cranking stack size to eliminate radiosity crash with 1MB stack on win32 */
|
||||
(4096 * 1024),
|
||||
|
||||
(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)
|
||||
Sys_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 = safe_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)
|
||||
Sys_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);
|
||||
Sys_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)
|
||||
Sys_Printf (" (%i)\n", end-start);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
=======================================================================
|
||||
|
||||
Linux pthreads
|
||||
|
||||
=======================================================================
|
||||
*/
|
||||
|
||||
#ifdef __linux__
|
||||
#define USED
|
||||
|
||||
int numthreads = 4;
|
||||
|
||||
void ThreadSetDefault (void)
|
||||
{
|
||||
if (numthreads == -1) // not set manually
|
||||
{
|
||||
/* default to one thread, only multi-thread when specifically told to */
|
||||
numthreads = 1;
|
||||
}
|
||||
if(numthreads > 1)
|
||||
Sys_Printf("threads: %d\n", numthreads);
|
||||
}
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
typedef struct pt_mutex_s
|
||||
{
|
||||
pthread_t *owner;
|
||||
pthread_mutex_t a_mutex;
|
||||
pthread_cond_t cond;
|
||||
unsigned int lock;
|
||||
} pt_mutex_t;
|
||||
|
||||
pt_mutex_t global_lock;
|
||||
|
||||
void ThreadLock(void)
|
||||
{
|
||||
pt_mutex_t *pt_mutex = &global_lock;
|
||||
|
||||
if(!threaded)
|
||||
return;
|
||||
|
||||
pthread_mutex_lock(&pt_mutex->a_mutex);
|
||||
if(pthread_equal(pthread_self(), (pthread_t)&pt_mutex->owner))
|
||||
pt_mutex->lock++;
|
||||
else
|
||||
{
|
||||
if((!pt_mutex->owner) && (pt_mutex->lock == 0))
|
||||
{
|
||||
pt_mutex->owner = (pthread_t *)pthread_self();
|
||||
pt_mutex->lock = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
pthread_cond_wait(&pt_mutex->cond, &pt_mutex->a_mutex);
|
||||
if((!pt_mutex->owner) && (pt_mutex->lock == 0))
|
||||
{
|
||||
pt_mutex->owner = (pthread_t *)pthread_self();
|
||||
pt_mutex->lock = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&pt_mutex->a_mutex);
|
||||
}
|
||||
|
||||
void ThreadUnlock(void)
|
||||
{
|
||||
pt_mutex_t *pt_mutex = &global_lock;
|
||||
|
||||
if(!threaded)
|
||||
return;
|
||||
|
||||
pthread_mutex_lock(&pt_mutex->a_mutex);
|
||||
pt_mutex->lock--;
|
||||
|
||||
if(pt_mutex->lock == 0)
|
||||
{
|
||||
pt_mutex->owner = NULL;
|
||||
pthread_cond_signal(&pt_mutex->cond);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&pt_mutex->a_mutex);
|
||||
}
|
||||
|
||||
void recursive_mutex_init(pthread_mutexattr_t attribs)
|
||||
{
|
||||
pt_mutex_t *pt_mutex = &global_lock;
|
||||
|
||||
pt_mutex->owner = NULL;
|
||||
if(pthread_mutex_init(&pt_mutex->a_mutex, &attribs) != 0)
|
||||
Error("pthread_mutex_init failed\n");
|
||||
if(pthread_cond_init(&pt_mutex->cond, NULL) != 0)
|
||||
Error("pthread_cond_init failed\n");
|
||||
|
||||
pt_mutex->lock = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
RunThreadsOn
|
||||
=============
|
||||
*/
|
||||
void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int))
|
||||
{
|
||||
pthread_mutexattr_t mattrib;
|
||||
pthread_t work_threads[MAX_THREADS];
|
||||
|
||||
int start, end;
|
||||
int i=0, status=0;
|
||||
|
||||
start = I_FloatTime ();
|
||||
pacifier = showpacifier;
|
||||
|
||||
dispatch = 0;
|
||||
oldf = -1;
|
||||
workcount = workcnt;
|
||||
|
||||
if(numthreads == 1)
|
||||
func(0);
|
||||
else
|
||||
{
|
||||
threaded = qtrue;
|
||||
|
||||
if(pacifier)
|
||||
setbuf(stdout, NULL);
|
||||
|
||||
if(pthread_mutexattr_init(&mattrib) != 0)
|
||||
Error("pthread_mutexattr_init failed");
|
||||
#if __GLIBC_MINOR__ == 1
|
||||
if (pthread_mutexattr_settype(&mattrib, PTHREAD_MUTEX_FAST_NP) != 0)
|
||||
#else
|
||||
if (pthread_mutexattr_settype(&mattrib, PTHREAD_MUTEX_ADAPTIVE_NP) != 0)
|
||||
#endif
|
||||
Error ("pthread_mutexattr_settype failed");
|
||||
recursive_mutex_init(mattrib);
|
||||
|
||||
for (i=0 ; i<numthreads ; i++)
|
||||
{
|
||||
/* Default pthread attributes: joinable & non-realtime scheduling */
|
||||
if(pthread_create(&work_threads[i], NULL, (void*)func, (void*)i) != 0)
|
||||
Error("pthread_create failed");
|
||||
}
|
||||
for (i=0 ; i<numthreads ; i++)
|
||||
{
|
||||
if(pthread_join(work_threads[i], (void **)&status) != 0)
|
||||
Error("pthread_join failed");
|
||||
}
|
||||
pthread_mutexattr_destroy(&mattrib);
|
||||
threaded = qfalse;
|
||||
}
|
||||
|
||||
end = I_FloatTime ();
|
||||
if (pacifier)
|
||||
Sys_Printf (" (%i)\n", end-start);
|
||||
}
|
||||
#endif // ifdef __linux__
|
||||
|
||||
|
||||
/*
|
||||
=======================================================================
|
||||
|
||||
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)
|
||||
Sys_Printf (" (%i)\n", end-start);
|
||||
}
|
||||
|
||||
#endif
|
||||
235
tools/quake3/common/trilib.c
Normal file
235
tools/quake3/common/trilib.c
Normal file
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
Copyright (C) 1999-2006 Id Software, Inc. and contributors.
|
||||
For a list of contributors, see the accompanying CONTRIBUTORS file.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
//
|
||||
// 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
|
||||
|
||||
#if defined (__linux__) || defined (__APPLE__)
|
||||
#define strlwr strlower
|
||||
#endif
|
||||
|
||||
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
tools/quake3/common/trilib.h
Normal file
26
tools/quake3/common/trilib.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
Copyright (C) 1999-2006 Id Software, Inc. and contributors.
|
||||
For a list of contributors, see the accompanying CONTRIBUTORS file.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
//
|
||||
// trilib.h: header file for loading triangles from an Alias triangle file
|
||||
//
|
||||
void TRI_LoadPolysets( const char *filename, polyset_t **ppPSET, int *numpsets );
|
||||
|
||||
4596
tools/quake3/common/unzip.c
Normal file
4596
tools/quake3/common/unzip.c
Normal file
File diff suppressed because it is too large
Load Diff
321
tools/quake3/common/unzip.h
Normal file
321
tools/quake3/common/unzip.h
Normal file
@@ -0,0 +1,321 @@
|
||||
/*
|
||||
Copyright (C) 1999-2006 Id Software, Inc. and contributors.
|
||||
For a list of contributors, see the accompanying CONTRIBUTORS file.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)
|
||||
/* like the STRICT of WIN32, we define a pointer that cannot be converted
|
||||
from (void*) without cast */
|
||||
typedef struct TagunzFile__ { int unused; } unzFile__;
|
||||
typedef unzFile__ *unzFile;
|
||||
#else
|
||||
typedef void* unzFile;
|
||||
#endif
|
||||
|
||||
|
||||
/* tm_unz contain date/time info */
|
||||
typedef struct tm_unz_s
|
||||
{
|
||||
unsigned int tm_sec; /* seconds after the minute - [0,59] */
|
||||
unsigned int tm_min; /* minutes after the hour - [0,59] */
|
||||
unsigned int tm_hour; /* hours since midnight - [0,23] */
|
||||
unsigned int tm_mday; /* day of the month - [1,31] */
|
||||
unsigned int tm_mon; /* months since January - [0,11] */
|
||||
unsigned int tm_year; /* years - [1980..2044] */
|
||||
} tm_unz;
|
||||
|
||||
/* unz_global_info structure contain global data about the ZIPfile
|
||||
These data comes from the end of central dir */
|
||||
typedef struct unz_global_info_s
|
||||
{
|
||||
unsigned long number_entry; /* total number of entries in the central dir on this disk */
|
||||
unsigned long size_comment; /* size of the global comment of the zipfile */
|
||||
} unz_global_info;
|
||||
|
||||
|
||||
/* unz_file_info contain information about a file in the zipfile */
|
||||
typedef struct unz_file_info_s
|
||||
{
|
||||
unsigned long version; /* version made by 2 unsigned chars */
|
||||
unsigned long version_needed; /* version needed to extract 2 unsigned chars */
|
||||
unsigned long flag; /* general purpose bit flag 2 unsigned chars */
|
||||
unsigned long compression_method; /* compression method 2 unsigned chars */
|
||||
unsigned long dosDate; /* last mod file date in Dos fmt 4 unsigned chars */
|
||||
unsigned long crc; /* crc-32 4 unsigned chars */
|
||||
unsigned long compressed_size; /* compressed size 4 unsigned chars */
|
||||
unsigned long uncompressed_size; /* uncompressed size 4 unsigned chars */
|
||||
unsigned long size_filename; /* filename length 2 unsigned chars */
|
||||
unsigned long size_file_extra; /* extra field length 2 unsigned chars */
|
||||
unsigned long size_file_comment; /* file comment length 2 unsigned chars */
|
||||
|
||||
unsigned long disk_num_start; /* disk number start 2 unsigned chars */
|
||||
unsigned long internal_fa; /* internal file attributes 2 unsigned chars */
|
||||
unsigned long external_fa; /* external file attributes 4 unsigned chars */
|
||||
|
||||
tm_unz tmu_date;
|
||||
} unz_file_info;
|
||||
|
||||
/* unz_file_info_interntal contain internal info about a file in zipfile*/
|
||||
typedef struct unz_file_info_internal_s
|
||||
{
|
||||
unsigned long offset_curfile;/* relative offset of static header 4 unsigned chars */
|
||||
} unz_file_info_internal;
|
||||
|
||||
typedef void* (*alloc_func) (void* opaque, unsigned int items, unsigned int size);
|
||||
typedef void (*free_func) (void* opaque, void* address);
|
||||
|
||||
struct internal_state;
|
||||
|
||||
typedef struct z_stream_s {
|
||||
unsigned char *next_in; /* next input unsigned char */
|
||||
unsigned int avail_in; /* number of unsigned chars available at next_in */
|
||||
unsigned long total_in; /* total nb of input unsigned chars read so */
|
||||
|
||||
unsigned char *next_out; /* next output unsigned char should be put there */
|
||||
unsigned int avail_out; /* remaining free space at next_out */
|
||||
unsigned long total_out; /* total nb of unsigned chars output so */
|
||||
|
||||
char *msg; /* last error message, NULL if no error */
|
||||
struct internal_state *state; /* not visible by applications */
|
||||
|
||||
alloc_func zalloc; /* used to allocate the internal state */
|
||||
free_func zfree; /* used to free the internal state */
|
||||
unsigned char* opaque; /* private data object passed to zalloc and zfree */
|
||||
|
||||
int data_type; /* best guess about the data type: ascii or binary */
|
||||
unsigned long adler; /* adler32 value of the uncompressed data */
|
||||
unsigned long reserved; /* reserved for future use */
|
||||
} z_stream;
|
||||
|
||||
typedef z_stream *z_streamp;
|
||||
|
||||
|
||||
/* file_in_zip_read_info_s contain internal information about a file in zipfile,
|
||||
when reading and decompress it */
|
||||
typedef struct
|
||||
{
|
||||
char *read_buffer; /* internal buffer for compressed data */
|
||||
z_stream stream; /* zLib stream structure for inflate */
|
||||
|
||||
unsigned long pos_in_zipfile; /* position in unsigned char on the zipfile, for fseek*/
|
||||
unsigned long stream_initialised; /* flag set if stream structure is initialised*/
|
||||
|
||||
unsigned long offset_local_extrafield;/* offset of the static extra field */
|
||||
unsigned int size_local_extrafield;/* size of the static extra field */
|
||||
unsigned long pos_local_extrafield; /* position in the static extra field in read*/
|
||||
|
||||
unsigned long crc32; /* crc32 of all data uncompressed */
|
||||
unsigned long crc32_wait; /* crc32 we must obtain after decompress all */
|
||||
unsigned long rest_read_compressed; /* number of unsigned char to be decompressed */
|
||||
unsigned long rest_read_uncompressed;/*number of unsigned char to be obtained after decomp*/
|
||||
FILE* file; /* io structore of the zipfile */
|
||||
unsigned long compression_method; /* compression method (0==store) */
|
||||
unsigned long byte_before_the_zipfile;/* unsigned char before the zipfile, (>0 for sfx)*/
|
||||
} file_in_zip_read_info_s;
|
||||
|
||||
|
||||
/* unz_s contain internal information about the zipfile
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
FILE* file; /* io structore of the zipfile */
|
||||
unz_global_info gi; /* public global information */
|
||||
unsigned long byte_before_the_zipfile;/* unsigned char before the zipfile, (>0 for sfx)*/
|
||||
unsigned long num_file; /* number of the current file in the zipfile*/
|
||||
unsigned long pos_in_central_dir; /* pos of the current file in the central dir*/
|
||||
unsigned long current_file_ok; /* flag about the usability of the current file*/
|
||||
unsigned long central_pos; /* position of the beginning of the central dir*/
|
||||
|
||||
unsigned long size_central_dir; /* size of the central directory */
|
||||
unsigned long offset_central_dir; /* offset of start of central directory with
|
||||
respect to the starting disk number */
|
||||
|
||||
unz_file_info cur_file_info; /* public info about the current file in zip*/
|
||||
unz_file_info_internal cur_file_info_internal; /* private info about it*/
|
||||
file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current
|
||||
file if we are decompressing it */
|
||||
} unz_s;
|
||||
|
||||
#define UNZ_OK (0)
|
||||
#define UNZ_END_OF_LIST_OF_FILE (-100)
|
||||
#define UNZ_ERRNO (Z_ERRNO)
|
||||
#define UNZ_EOF (0)
|
||||
#define UNZ_PARAMERROR (-102)
|
||||
#define UNZ_BADZIPFILE (-103)
|
||||
#define UNZ_INTERNALERROR (-104)
|
||||
#define UNZ_CRCERROR (-105)
|
||||
|
||||
#define UNZ_CASESENSITIVE 1
|
||||
#define UNZ_NOTCASESENSITIVE 2
|
||||
#define UNZ_OSDEFAULTCASE 0
|
||||
|
||||
extern int unzStringFileNameCompare (const char* fileName1, const char* fileName2, int iCaseSensitivity);
|
||||
|
||||
/*
|
||||
Compare two filename (fileName1,fileName2).
|
||||
If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
|
||||
If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
|
||||
or strcasecmp)
|
||||
If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
|
||||
(like 1 on Unix, 2 on Windows)
|
||||
*/
|
||||
|
||||
extern unzFile unzOpen (const char *path);
|
||||
extern unzFile unzReOpen (const char* path, unzFile file);
|
||||
|
||||
/*
|
||||
Open a Zip file. path contain the full pathname (by example,
|
||||
on a Windows NT computer "c:\\zlib\\zlib111.zip" or on an Unix computer
|
||||
"zlib/zlib111.zip".
|
||||
If the zipfile cannot be opened (file don't exist or in not valid), the
|
||||
return value is NULL.
|
||||
Else, the return value is a unzFile Handle, usable with other function
|
||||
of this unzip package.
|
||||
*/
|
||||
|
||||
extern int unzClose (unzFile file);
|
||||
|
||||
/*
|
||||
Close a ZipFile opened with unzipOpen.
|
||||
If there is files inside the .Zip opened with unzOpenCurrentFile (see later),
|
||||
these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
|
||||
return UNZ_OK if there is no problem. */
|
||||
|
||||
extern int unzGetGlobalInfo (unzFile file, unz_global_info *pglobal_info);
|
||||
|
||||
/*
|
||||
Write info about the ZipFile in the *pglobal_info structure.
|
||||
No preparation of the structure is needed
|
||||
return UNZ_OK if there is no problem. */
|
||||
|
||||
|
||||
extern int unzGetGlobalComment (unzFile file, char *szComment, unsigned long uSizeBuf);
|
||||
|
||||
/*
|
||||
Get the global comment string of the ZipFile, in the szComment buffer.
|
||||
uSizeBuf is the size of the szComment buffer.
|
||||
return the number of unsigned char copied or an error code <0
|
||||
*/
|
||||
|
||||
|
||||
/***************************************************************************/
|
||||
/* Unzip package allow you browse the directory of the zipfile */
|
||||
|
||||
extern int unzGoToFirstFile (unzFile file);
|
||||
|
||||
/*
|
||||
Set the current file of the zipfile to the first file.
|
||||
return UNZ_OK if there is no problem
|
||||
*/
|
||||
|
||||
extern int unzGoToNextFile (unzFile file);
|
||||
|
||||
/*
|
||||
Set the current file of the zipfile to the next file.
|
||||
return UNZ_OK if there is no problem
|
||||
return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
|
||||
*/
|
||||
|
||||
extern int unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity);
|
||||
|
||||
/*
|
||||
Try locate the file szFileName in the zipfile.
|
||||
For the iCaseSensitivity signification, see unzStringFileNameCompare
|
||||
|
||||
return value :
|
||||
UNZ_OK if the file is found. It becomes the current file.
|
||||
UNZ_END_OF_LIST_OF_FILE if the file is not found
|
||||
*/
|
||||
|
||||
|
||||
extern int unzGetCurrentFileInfo (unzFile file, unz_file_info *pfile_info, char *szFileName, unsigned long fileNameBufferSize, void *extraField, unsigned long extraFieldBufferSize, char *szComment, unsigned long commentBufferSize);
|
||||
|
||||
/*
|
||||
Get Info about the current file
|
||||
if pfile_info!=NULL, the *pfile_info structure will contain somes info about
|
||||
the current file
|
||||
if szFileName!=NULL, the filemane string will be copied in szFileName
|
||||
(fileNameBufferSize is the size of the buffer)
|
||||
if extraField!=NULL, the extra field information will be copied in extraField
|
||||
(extraFieldBufferSize is the size of the buffer).
|
||||
This is the Central-header version of the extra field
|
||||
if szComment!=NULL, the comment string of the file will be copied in szComment
|
||||
(commentBufferSize is the size of the buffer)
|
||||
*/
|
||||
|
||||
/***************************************************************************/
|
||||
/* for reading the content of the current zipfile, you can open it, read data
|
||||
from it, and close it (you can close it before reading all the file)
|
||||
*/
|
||||
|
||||
extern int unzOpenCurrentFile (unzFile file);
|
||||
|
||||
/*
|
||||
Open for reading data the current file in the zipfile.
|
||||
If there is no error, the return value is UNZ_OK.
|
||||
*/
|
||||
|
||||
extern int unzCloseCurrentFile (unzFile file);
|
||||
|
||||
/*
|
||||
Close the file in zip opened with unzOpenCurrentFile
|
||||
Return UNZ_CRCERROR if all the file was read but the CRC is not good
|
||||
*/
|
||||
|
||||
|
||||
extern int unzReadCurrentFile (unzFile file, void* buf, unsigned len);
|
||||
|
||||
/*
|
||||
Read unsigned chars from the current file (opened by unzOpenCurrentFile)
|
||||
buf contain buffer where data must be copied
|
||||
len the size of buf.
|
||||
|
||||
return the number of unsigned char copied if somes unsigned chars are copied
|
||||
return 0 if the end of file was reached
|
||||
return <0 with error code if there is an error
|
||||
(UNZ_ERRNO for IO error, or zLib error for uncompress error)
|
||||
*/
|
||||
|
||||
extern long unztell(unzFile file);
|
||||
|
||||
/*
|
||||
Give the current position in uncompressed data
|
||||
*/
|
||||
|
||||
extern int unzeof (unzFile file);
|
||||
|
||||
/*
|
||||
return 1 if the end of file was reached, 0 elsewhere
|
||||
*/
|
||||
|
||||
extern int unzGetLocalExtrafield (unzFile file, void* buf, unsigned len);
|
||||
|
||||
/*
|
||||
Read extra field from the current file (opened by unzOpenCurrentFile)
|
||||
This is the local-header version of the extra field (sometimes, there is
|
||||
more info in the local-header version than in the central-header)
|
||||
|
||||
if buf==NULL, it return the size of the local extra field
|
||||
|
||||
if buf!=NULL, len is the size of the buffer, the extra header is copied in
|
||||
buf.
|
||||
the return value is the number of unsigned chars copied in buf, or (if <0)
|
||||
the error code
|
||||
*/
|
||||
365
tools/quake3/common/vfs.c
Normal file
365
tools/quake3/common/vfs.c
Normal file
@@ -0,0 +1,365 @@
|
||||
/*
|
||||
Copyright (c) 2001, Loki software, inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
Neither the name of Loki software nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without specific prior
|
||||
written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
//
|
||||
// Rules:
|
||||
//
|
||||
// - Directories should be searched in the following order: ~/.q3a/baseq3,
|
||||
// install dir (/usr/local/games/quake3/baseq3) and cd_path (/mnt/cdrom/baseq3).
|
||||
//
|
||||
// - Pak files are searched first inside the directories.
|
||||
// - Case insensitive.
|
||||
// - Unix-style slashes (/) (windows is backwards .. everyone knows that)
|
||||
//
|
||||
// Leonardo Zide (leo@lokigames.com)
|
||||
//
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined (__linux__) || defined (__APPLE__)
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#else
|
||||
#include <wtypes.h>
|
||||
#include <io.h>
|
||||
#define R_OK 04
|
||||
#define S_ISDIR(mode) (mode & _S_IFDIR)
|
||||
#define PATH_MAX 260
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "cmdlib.h"
|
||||
#include "mathlib.h"
|
||||
#include <glib.h>
|
||||
#include "inout.h"
|
||||
#include "vfs.h"
|
||||
#include "unzip.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char* name;
|
||||
unz_s zipinfo;
|
||||
unzFile zipfile;
|
||||
guint32 size;
|
||||
} VFS_PAKFILE;
|
||||
|
||||
// =============================================================================
|
||||
// Global variables
|
||||
|
||||
static GSList* g_unzFiles;
|
||||
static GSList* g_pakFiles;
|
||||
static char g_strDirs[VFS_MAXDIRS][PATH_MAX];
|
||||
static int g_numDirs;
|
||||
static gboolean g_bUsePak = TRUE;
|
||||
|
||||
// =============================================================================
|
||||
// Static functions
|
||||
|
||||
static void vfsAddSlash (char *str)
|
||||
{
|
||||
int n = strlen (str);
|
||||
if (n > 0)
|
||||
{
|
||||
if (str[n-1] != '\\' && str[n-1] != '/')
|
||||
strcat (str, "/");
|
||||
}
|
||||
}
|
||||
|
||||
static void vfsFixDOSName (char *src)
|
||||
{
|
||||
if (src == NULL)
|
||||
return;
|
||||
|
||||
while (*src)
|
||||
{
|
||||
if (*src == '\\')
|
||||
*src = '/';
|
||||
src++;
|
||||
}
|
||||
}
|
||||
|
||||
//!\todo Define globally or use heap-allocated string.
|
||||
#define NAME_MAX 255
|
||||
|
||||
static void vfsInitPakFile (const char *filename)
|
||||
{
|
||||
unz_global_info gi;
|
||||
unzFile uf;
|
||||
guint32 i;
|
||||
int err;
|
||||
|
||||
uf = unzOpen (filename);
|
||||
if (uf == NULL)
|
||||
return;
|
||||
|
||||
g_unzFiles = g_slist_append (g_unzFiles, uf);
|
||||
|
||||
err = unzGetGlobalInfo (uf,&gi);
|
||||
if (err != UNZ_OK)
|
||||
return;
|
||||
unzGoToFirstFile(uf);
|
||||
|
||||
for (i = 0; i < gi.number_entry; i++)
|
||||
{
|
||||
char filename_inzip[NAME_MAX];
|
||||
unz_file_info file_info;
|
||||
VFS_PAKFILE* file;
|
||||
|
||||
err = unzGetCurrentFileInfo (uf, &file_info, filename_inzip, sizeof(filename_inzip), NULL, 0, NULL, 0);
|
||||
if (err != UNZ_OK)
|
||||
break;
|
||||
|
||||
file = (VFS_PAKFILE*)safe_malloc (sizeof (VFS_PAKFILE));
|
||||
g_pakFiles = g_slist_append (g_pakFiles, file);
|
||||
|
||||
vfsFixDOSName (filename_inzip);
|
||||
g_strdown (filename_inzip);
|
||||
|
||||
file->name = strdup (filename_inzip);
|
||||
file->size = file_info.uncompressed_size;
|
||||
file->zipfile = uf;
|
||||
memcpy (&file->zipinfo, uf, sizeof (unz_s));
|
||||
|
||||
if ((i+1) < gi.number_entry)
|
||||
{
|
||||
err = unzGoToNextFile(uf);
|
||||
if (err!=UNZ_OK)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Global functions
|
||||
|
||||
// reads all pak files from a dir
|
||||
void vfsInitDirectory (const char *path)
|
||||
{
|
||||
char filename[PATH_MAX];
|
||||
char *dirlist;
|
||||
GDir *dir;
|
||||
|
||||
if (g_numDirs == (VFS_MAXDIRS-1))
|
||||
return;
|
||||
|
||||
Sys_Printf ("VFS Init: %s\n", path);
|
||||
|
||||
strcpy (g_strDirs[g_numDirs], path);
|
||||
vfsFixDOSName (g_strDirs[g_numDirs]);
|
||||
vfsAddSlash (g_strDirs[g_numDirs]);
|
||||
g_numDirs++;
|
||||
|
||||
if (g_bUsePak)
|
||||
{
|
||||
dir = g_dir_open (path, 0, NULL);
|
||||
|
||||
if (dir != NULL)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
const char* name = g_dir_read_name(dir);
|
||||
if(name == NULL)
|
||||
break;
|
||||
|
||||
dirlist = g_strdup(name);
|
||||
|
||||
{
|
||||
char *ext = strrchr (dirlist, '.');
|
||||
if ((ext == NULL) || (Q_stricmp (ext, ".pk3") != 0))
|
||||
continue;
|
||||
}
|
||||
|
||||
sprintf (filename, "%s/%s", path, dirlist);
|
||||
vfsInitPakFile (filename);
|
||||
|
||||
g_free(dirlist);
|
||||
}
|
||||
g_dir_close (dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// frees all memory that we allocated
|
||||
void vfsShutdown ()
|
||||
{
|
||||
while (g_unzFiles)
|
||||
{
|
||||
unzClose ((unzFile)g_unzFiles->data);
|
||||
g_unzFiles = g_slist_remove (g_unzFiles, g_unzFiles->data);
|
||||
}
|
||||
|
||||
while (g_pakFiles)
|
||||
{
|
||||
VFS_PAKFILE* file = (VFS_PAKFILE*)g_pakFiles->data;
|
||||
free (file->name);
|
||||
free (file);
|
||||
g_pakFiles = g_slist_remove (g_pakFiles, file);
|
||||
}
|
||||
}
|
||||
|
||||
// return the number of files that match
|
||||
int vfsGetFileCount (const char *filename)
|
||||
{
|
||||
int i, count = 0;
|
||||
char fixed[NAME_MAX], tmp[NAME_MAX];
|
||||
GSList *lst;
|
||||
|
||||
strcpy (fixed, filename);
|
||||
vfsFixDOSName (fixed);
|
||||
g_strdown (fixed);
|
||||
|
||||
for (lst = g_pakFiles; lst != NULL; lst = g_slist_next (lst))
|
||||
{
|
||||
VFS_PAKFILE* file = (VFS_PAKFILE*)lst->data;
|
||||
|
||||
if (strcmp (file->name, fixed) == 0)
|
||||
count++;
|
||||
}
|
||||
|
||||
for (i = 0; i < g_numDirs; i++)
|
||||
{
|
||||
strcpy (tmp, g_strDirs[i]);
|
||||
strcat (tmp, fixed);
|
||||
if (access (tmp, R_OK) == 0)
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
// NOTE: when loading a file, you have to allocate one extra byte and set it to \0
|
||||
int vfsLoadFile (const char *filename, void **bufferptr, int index)
|
||||
{
|
||||
int i, count = 0;
|
||||
char tmp[NAME_MAX], fixed[NAME_MAX];
|
||||
GSList *lst;
|
||||
|
||||
// filename is a full path
|
||||
if (index == -1)
|
||||
{
|
||||
long len;
|
||||
FILE *f;
|
||||
|
||||
f = fopen (filename, "rb");
|
||||
if (f == NULL)
|
||||
return -1;
|
||||
|
||||
fseek (f, 0, SEEK_END);
|
||||
len = ftell (f);
|
||||
rewind (f);
|
||||
|
||||
*bufferptr = safe_malloc (len+1);
|
||||
if (*bufferptr == NULL)
|
||||
return -1;
|
||||
|
||||
fread (*bufferptr, 1, len, f);
|
||||
fclose (f);
|
||||
|
||||
// we need to end the buffer with a 0
|
||||
((char*) (*bufferptr))[len] = 0;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
*bufferptr = NULL;
|
||||
strcpy (fixed, filename);
|
||||
vfsFixDOSName (fixed);
|
||||
g_strdown (fixed);
|
||||
|
||||
for (i = 0; i < g_numDirs; i++)
|
||||
{
|
||||
strcpy (tmp, g_strDirs[i]);
|
||||
strcat (tmp, filename);
|
||||
if (access (tmp, R_OK) == 0)
|
||||
{
|
||||
if (count == index)
|
||||
{
|
||||
long len;
|
||||
FILE *f;
|
||||
|
||||
f = fopen (tmp, "rb");
|
||||
if (f == NULL)
|
||||
return -1;
|
||||
|
||||
fseek (f, 0, SEEK_END);
|
||||
len = ftell (f);
|
||||
rewind (f);
|
||||
|
||||
*bufferptr = safe_malloc (len+1);
|
||||
if (*bufferptr == NULL)
|
||||
return -1;
|
||||
|
||||
fread (*bufferptr, 1, len, f);
|
||||
fclose (f);
|
||||
|
||||
// we need to end the buffer with a 0
|
||||
((char*) (*bufferptr))[len] = 0;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
for (lst = g_pakFiles; lst != NULL; lst = g_slist_next (lst))
|
||||
{
|
||||
VFS_PAKFILE* file = (VFS_PAKFILE*)lst->data;
|
||||
|
||||
if (strcmp (file->name, fixed) != 0)
|
||||
continue;
|
||||
|
||||
if (count == index)
|
||||
{
|
||||
memcpy (file->zipfile, &file->zipinfo, sizeof (unz_s));
|
||||
|
||||
if (unzOpenCurrentFile (file->zipfile) != UNZ_OK)
|
||||
return -1;
|
||||
|
||||
*bufferptr = safe_malloc (file->size+1);
|
||||
// we need to end the buffer with a 0
|
||||
((char*) (*bufferptr))[file->size] = 0;
|
||||
|
||||
i = unzReadCurrentFile (file->zipfile , *bufferptr, file->size);
|
||||
unzCloseCurrentFile (file->zipfile);
|
||||
if (i < 0)
|
||||
return -1;
|
||||
else
|
||||
return file->size;
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
41
tools/quake3/common/vfs.h
Normal file
41
tools/quake3/common/vfs.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
Copyright (c) 2001, Loki software, inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
Neither the name of Loki software nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without specific prior
|
||||
written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _VFS_H_
|
||||
#define _VFS_H_
|
||||
|
||||
#define VFS_MAXDIRS 8
|
||||
|
||||
void vfsInitDirectory (const char *path);
|
||||
void vfsShutdown ();
|
||||
int vfsGetFileCount (const char *filename);
|
||||
int vfsLoadFile (const char *filename, void **buffer, int index);
|
||||
|
||||
#endif // _VFS_H_
|
||||
Reference in New Issue
Block a user