The GtkRadiant sources as originally released under the GPL license.

This commit is contained in:
Travis Bradshaw
2012-01-31 15:20:35 -06:00
commit 0991a5ce8b
1590 changed files with 431941 additions and 0 deletions

View File

@@ -0,0 +1,12 @@
q3map
*.d
*.o
*.bak
*.BAK
*~
*.ncb
*.plg
*.opt
*.log
Debug
Release

View File

@@ -0,0 +1,2 @@
*.dsp -m 'COPY' -k 'b'
*.dsw -m 'COPY' -k 'b'

View File

@@ -0,0 +1,651 @@
/*
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 <assert.h>
#include "q3data.h"
static void Load3DS( const char *filename, _3DS_t *p3DS, qboolean verbose );
static qboolean s_verbose;
#define MAX_MATERIALS 100
#define MAX_NAMED_OBJECTS 100
#define MAX_MESH_MATERIAL_GROUPS 100
#define MAX_TRI_OBJECTS 512
static char s_buffer[1000000];
static int ReadString( FILE *fp, char *buffer )
{
int i = 0;
int bytesRead = 0;
do
{
fread( &buffer[i], 1, sizeof( char ), fp );
bytesRead++;
} while ( buffer[i++] != 0 );
buffer[i] = 0;
return bytesRead;
}
static int ReadChunkAndLength( FILE *fp, short *chunk, long *len )
{
if ( fread( chunk, sizeof( short ), 1, fp ) != 1 )
return 0;
if ( fread( len, sizeof( long ), 1, fp ) != 1 )
Error( "Unexpected EOF found" );
return 1;
}
static void LoadMapName( FILE *fp, char *buffer, int thisChunkLen )
{
unsigned short chunkID;
long chunkLen;
long bytesRead = 0;
while ( ReadChunkAndLength( fp, &chunkID, &chunkLen ) )
{
switch ( chunkID )
{
case _3DS_CHUNK_MAT_MAPNAME:
fread( buffer, chunkLen - 6, 1, fp );
break;
default:
fread( s_buffer, chunkLen - 6, 1, fp );
break;
}
bytesRead += chunkLen;
if ( bytesRead >= thisChunkLen )
return;
}
}
static void LoadMaterialList( FILE *fp, long thisChunkLen, _3DSMaterial_t *pMat )
{
long chunkLen;
unsigned short chunkID;
long bytesRead = 0;
_3DSMaterial_t mat;
char curdir[1024];
char buffer[2048];
memset( &mat, 0, sizeof( mat ) );
if ( s_verbose )
printf( " >>> MATERIAL LIST\n" );
while ( ReadChunkAndLength( fp, &chunkID, &chunkLen ) )
{
switch ( chunkID )
{
case _3DS_CHUNK_MAT_NAME:
fread( mat.name, chunkLen - 6, 1, fp );
if ( s_verbose )
printf( " found mat name '%s'\n", mat.name );
break;
case _3DS_CHUNK_TEXMAP:
LoadMapName( fp, mat.texture, chunkLen - 6 );
if ( s_verbose )
printf( " found texture '%s'\n", mat.texture );
break;
case _3DS_CHUNK_SPECMAP:
LoadMapName( fp, mat.specular, chunkLen - 6 );
if ( s_verbose )
printf( " found specular map '%s'\n", mat.specular );
break;
case _3DS_CHUNK_OPACMAP:
LoadMapName( fp, mat.opacity, chunkLen - 6 );
if ( s_verbose )
printf( " found opacity map '%s'\n", mat.opacity );
break;
case _3DS_CHUNK_REFLMAP:
LoadMapName( fp, mat.reflection, chunkLen - 6 );
if ( s_verbose )
printf( " found reflection map '%s'\n", mat.reflection );
break;
case _3DS_CHUNK_BUMPMAP:
LoadMapName( fp, mat.bump, chunkLen - 6 );
if ( s_verbose )
printf( " found bump map '%s'\n", mat.bump );
break;
default:
fread( s_buffer, chunkLen - 6, 1, fp );
break;
}
bytesRead += chunkLen;
if ( bytesRead >= thisChunkLen )
break;
}
Q_getwd( curdir );
if ( mat.texture[0] )
{
sprintf( buffer, "%s%s", curdir, mat.texture );
if ( strstr( buffer, gamedir + 1 ) )
strcpy( mat.texture, strstr( buffer, gamedir + 1 ) + strlen( gamedir ) - 1 );
else
strcpy( mat.texture, buffer );
}
if ( mat.specular[0] )
{
sprintf( buffer, "%s%s", curdir, mat.specular );
if ( strstr( buffer, gamedir + 1 ) )
strcpy( mat.specular, strstr( buffer, gamedir + 1 ) + strlen( gamedir ) - 1 );
else
strcpy( mat.specular, buffer );
}
if ( mat.bump[0] )
{
sprintf( buffer, "%s%s", curdir, mat.bump );
if ( strstr( buffer, gamedir + 1 ) )
strcpy( mat.bump, strstr( buffer, gamedir + 1 ) + strlen( gamedir ) - 1 );
else
strcpy( mat.bump, buffer );
}
if ( mat.reflection[0] )
{
sprintf( buffer, "%s%s", curdir, mat.reflection );
if ( strstr( buffer, gamedir + 1 ) )
strcpy( mat.reflection, strstr( buffer, gamedir + 1 ) + strlen( gamedir ) - 1 );
else
strcpy( mat.reflection, buffer );
}
if ( mat.opacity[0] )
{
sprintf( buffer, "%s%s", curdir, mat.opacity );
if ( strstr( buffer, gamedir + 1 ) )
strcpy( mat.opacity, strstr( buffer, gamedir + 1 ) + strlen( gamedir ) - 1 );
else
strcpy( mat.opacity, buffer );
}
*pMat = mat;
}
static void LoadMeshMaterialGroup( FILE *fp, long thisChunkLen, _3DSMeshMaterialGroup_t *pMMG )
{
_3DSMeshMaterialGroup_t mmg;
memset( &mmg, 0, sizeof( mmg ) );
ReadString( fp, mmg.name );
fread( &mmg.numFaces, sizeof( mmg.numFaces ), 1, fp );
mmg.pFaces = malloc( sizeof( mmg.pFaces[0] ) * mmg.numFaces );
fread( mmg.pFaces, sizeof( mmg.pFaces[0] ), mmg.numFaces, fp );
if ( s_verbose )
{
printf( " >>> MESH MATERIAL GROUP '%s' (%d faces)\n", mmg.name, mmg.numFaces );
{
int i;
for ( i = 0; i < mmg.numFaces; i++ )
{
printf( " %d\n", mmg.pFaces[i] );
}
}
}
*pMMG = mmg;
}
static void LoadNamedTriObject( FILE *fp, long thisChunkLen, _3DSTriObject_t *pTO )
{
long chunkLen;
unsigned short chunkID;
int i = 0;
long bytesRead = 0;
_3DSTriObject_t triObj;
_3DSMeshMaterialGroup_t meshMaterialGroups[MAX_MESH_MATERIAL_GROUPS];
int numMeshMaterialGroups = 0;
memset( &triObj, 0, sizeof( triObj ) );
if ( s_verbose )
printf( " >>> NAMED TRI OBJECT\n" );
while ( ReadChunkAndLength( fp, &chunkID, &chunkLen ) )
{
switch ( chunkID )
{
case _3DS_CHUNK_MSH_MAT_GROUP:
LoadMeshMaterialGroup( fp, chunkLen - 6, &meshMaterialGroups[numMeshMaterialGroups] );
bytesRead += chunkLen;
numMeshMaterialGroups++;
break;
case _3DS_CHUNK_FACE_ARRAY:
fread( &triObj.numFaces, sizeof( triObj.numFaces ), 1, fp );
assert( triObj.pFaces == 0 );
triObj.pFaces = malloc( sizeof( triObj.pFaces[0] ) * triObj.numFaces );
fread( triObj.pFaces, sizeof( triObj.pFaces[0] ), triObj.numFaces, fp );
bytesRead += sizeof( triObj.numFaces ) + triObj.numFaces * sizeof( triObj.pFaces[0] ) + 6;
if ( s_verbose )
{
printf( " found face array with %d faces\n", triObj.numFaces );
for ( i = 0; i < triObj.numFaces; i++ )
{
printf( " %d: %d,%d,%d\n", i, triObj.pFaces[i].a, triObj.pFaces[i].b, triObj.pFaces[i].c );
}
}
break;
case _3DS_CHUNK_POINT_ARRAY:
fread( &triObj.numPoints, sizeof( triObj.numPoints ), 1, fp );
triObj.pPoints = malloc( sizeof( triObj.pPoints[0] ) * triObj.numPoints );
fread( triObj.pPoints, sizeof( triObj.pPoints[0] ), triObj.numPoints, fp );
bytesRead += sizeof( triObj.numPoints ) + triObj.numPoints * sizeof( triObj.pPoints[0] ) + 6;
// flip points around into our coordinate system
for ( i = 0; i < triObj.numPoints; i++ )
{
float x, y, z;
x = triObj.pPoints[i].x;
y = triObj.pPoints[i].y;
z = triObj.pPoints[i].z;
triObj.pPoints[i].x = -y;
triObj.pPoints[i].y = x;
triObj.pPoints[i].z = z;
}
if ( s_verbose )
{
printf( " found point array with %d points\n", triObj.numPoints );
for ( i = 0; i < triObj.numPoints; i++ )
{
printf( " %d: %f,%f,%f\n", i, triObj.pPoints[i].x, triObj.pPoints[i].y, triObj.pPoints[i].z );
}
}
break;
case _3DS_CHUNK_TEX_VERTS:
fread( &triObj.numTexVerts, sizeof( triObj.numTexVerts ), 1, fp );
triObj.pTexVerts = malloc( sizeof( triObj.pTexVerts[0] ) * triObj.numTexVerts );
fread( triObj.pTexVerts, sizeof( triObj.pTexVerts[0] ), triObj.numTexVerts, fp );
bytesRead += sizeof( triObj.numTexVerts ) + sizeof( triObj.pTexVerts[0] ) * triObj.numTexVerts + 6;
if ( s_verbose )
{
printf( " found tex vert array with %d tex verts\n", triObj.numTexVerts );
for ( i = 0; i < triObj.numTexVerts; i++ )
{
printf( " %d: %f,%f\n", i, triObj.pTexVerts[i].s, triObj.pTexVerts[i].t );
}
}
break;
default:
fread( s_buffer, chunkLen - 6, 1, fp );
bytesRead += chunkLen;
break;
}
if ( bytesRead >= thisChunkLen )
break;
}
*pTO = triObj;
if ( numMeshMaterialGroups == 0 )
{
numMeshMaterialGroups = 1;
strcpy( meshMaterialGroups[0].name, "(null)" );
if ( pTO->numTexVerts ) {
printf( "Warning: assigning (null) skin to tri object\n" );
}
}
else
{
assert( pTO->numFaces == meshMaterialGroups[0].numFaces );
}
pTO->pMeshMaterialGroups = malloc( sizeof( _3DSMeshMaterialGroup_t ) * numMeshMaterialGroups );
memcpy( pTO->pMeshMaterialGroups, meshMaterialGroups, numMeshMaterialGroups * sizeof( meshMaterialGroups[0] ) );
pTO->numMeshMaterialGroups = numMeshMaterialGroups;
//
// sanity checks
//
assert( numMeshMaterialGroups <= 1 );
}
static void LoadNamedObject( FILE *fp, long thisChunkLen, _3DSNamedObject_t *pNO )
{
long chunkLen;
unsigned short chunkID;
int i = 0;
long bytesRead = 0;
char name[100];
_3DSTriObject_t triObj[MAX_TRI_OBJECTS];
int numTriObjects = 0;
memset( triObj, 0, sizeof( triObj ) );
bytesRead += ReadString( fp, name );
if ( s_verbose )
printf( " >>> NAMED OBJECT '%s'\n", name );
while ( ReadChunkAndLength( fp, &chunkID, &chunkLen ) )
{
switch ( chunkID )
{
case _3DS_CHUNK_NAMED_TRI_OBJECT:
LoadNamedTriObject( fp, chunkLen - 6, &triObj[numTriObjects] );
numTriObjects++;
break;
default:
fread( s_buffer, chunkLen - 6, 1, fp );
break;
}
bytesRead += chunkLen;
if ( bytesRead >= thisChunkLen )
break;
}
strcpy( pNO->name, name );
pNO->pTriObjects = malloc( sizeof( _3DSTriObject_t ) * numTriObjects );
memcpy( pNO->pTriObjects, triObj, sizeof( triObj[0] ) * numTriObjects );
pNO->numTriObjects = numTriObjects;
assert( numTriObjects <= 1 );
}
static void LoadEditChunk( FILE *fp, long thisChunkLen, _3DSEditChunk_t *pEC )
{
unsigned short chunkID;
long chunkLen;
long bytesRead = 0;
_3DSEditChunk_t editChunk;
_3DSMaterial_t mat[MAX_MATERIALS];
_3DSNamedObject_t namedObjects[MAX_NAMED_OBJECTS];
int numMaterials = 0, numNamedObjects = 0;
memset( &editChunk, 0, sizeof( editChunk ) );
if ( s_verbose )
printf( ">>> EDIT CHUNK\n" );
while ( ReadChunkAndLength( fp, &chunkID, &chunkLen ) )
{
switch ( chunkID )
{
case _3DS_CHUNK_MAT_LIST:
LoadMaterialList( fp, chunkLen - 6, &mat[numMaterials] );
numMaterials++;
break;
case _3DS_CHUNK_NAMED_OBJECT:
LoadNamedObject( fp, chunkLen - 6, &namedObjects[numNamedObjects] );
if ( namedObjects[numNamedObjects].numTriObjects != 0 )
++numNamedObjects;
break;
case _3DS_CHUNK_MESH_VERSION:
default:
fread( s_buffer, chunkLen - 6, 1, fp );
break;
}
bytesRead += chunkLen;
if ( bytesRead >= thisChunkLen )
break;
}
if ( numMaterials == 0 )
{
numMaterials = 1;
strcpy( mat[0].name, "(null)" );
printf( "Warning: no material definitions found\n" );
}
pEC->numNamedObjects = numNamedObjects;
pEC->pMaterials = malloc( sizeof( _3DSMaterial_t ) * numMaterials );
pEC->pNamedObjects = malloc( sizeof( _3DSNamedObject_t ) * numNamedObjects );
memcpy( pEC->pMaterials, mat, numMaterials * sizeof( mat[0] ) );
memcpy( pEC->pNamedObjects, namedObjects, numNamedObjects * sizeof( namedObjects[0] ) );
}
static void Load3DS( const char *filename, _3DS_t *p3DS, qboolean verbose )
{
FILE *fp;
unsigned short chunkID;
long chunkLen;
_3DSEditChunk_t editChunk;
s_verbose = verbose;
if ( ( fp = fopen( filename, "rb" ) ) == 0 )
Error( "Unable to open '%s'", filename );
// read magic number
if ( ( fread( &chunkID, sizeof( short ), 1, fp ) != 1 ) ||
( LittleShort( chunkID ) != _3DS_CHUNK_MAGIC ) )
{
Error( "Missing or incorrect magic number in '%s'", filename );
}
if ( fread( &chunkLen, sizeof( chunkLen ), 1, fp ) != 1 )
Error( "Unexpected EOF encountered in '%s'", filename );
// version number
if ( !ReadChunkAndLength( fp, &chunkID, &chunkLen ) )
Error( "Missing version number in '%s'", filename );
if ( fread( s_buffer, chunkLen - 6, 1, fp ) != 1 )
Error( "Unexpected EOF encountered in '%s'", filename );
while ( ReadChunkAndLength( fp, &chunkID, &chunkLen ) )
{
switch ( chunkID )
{
case _3DS_CHUNK_EDIT:
LoadEditChunk( fp, chunkLen - 6, &editChunk );
break;
case _3DS_CHUNK_KEYFRAME_DATA:
fread( s_buffer, chunkLen - 6, 1, fp );
break;
default:
fread( s_buffer, chunkLen - 6, 1, fp );
break;
}
}
fclose( fp );
p3DS->editChunk = editChunk;
}
static void ComputeNormals( _3DSTriObject_t *pTO, triangle_t *pTris )
{
vec3_t faceNormals[POLYSET_MAXTRIANGLES];
vec3_t vertexNormals[POLYSET_MAXTRIANGLES*3];
vec3_t side0, side1, facenormal;
int f, v;
memset( faceNormals, 0, sizeof( faceNormals ) );
memset( vertexNormals, 0, sizeof( vertexNormals ) );
//
// compute face normals
//
for ( f = 0; f < pTO->numFaces; f++ )
{
VectorSubtract( pTris[f].verts[0], pTris[f].verts[1], side0 );
VectorSubtract( pTris[f].verts[2], pTris[f].verts[1], side1 );
CrossProduct( side0, side1, facenormal );
VectorNormalize( facenormal, faceNormals[f] );
}
//
// sum vertex normals
//
for ( v = 0; v < pTO->numPoints; v++ )
{
for ( f = 0; f < pTO->numFaces; f++ )
{
if ( ( pTO->pFaces[f].a == v ) ||
( pTO->pFaces[f].b == v ) ||
( pTO->pFaces[f].c == v ) )
{
vertexNormals[v][0] += faceNormals[f][0];
vertexNormals[v][1] += faceNormals[f][1];
vertexNormals[v][2] += faceNormals[f][2];
}
}
VectorNormalize( vertexNormals[v], vertexNormals[v] );
}
//
// copy vertex normals into triangles
//
for ( f = 0; f < pTO->numFaces; f++ )
{
int i0 = pTO->pFaces[f].c;
int i1 = pTO->pFaces[f].b;
int i2 = pTO->pFaces[f].a;
VectorCopy( vertexNormals[i0], pTris[f].normals[0] );
VectorCopy( vertexNormals[i1], pTris[f].normals[1] );
VectorCopy( vertexNormals[i2], pTris[f].normals[2] );
}
}
/*
** void _3DS_LoadPolysets
*/
void _3DS_LoadPolysets( const char *filename, polyset_t **ppPSET, int *numpsets, qboolean verbose )
{
_3DS_t _3ds;
int numPolysets;
polyset_t *pPSET;
triangle_t *ptri, *triangles;
int i;
// load the 3DS
memset( &_3ds, 0, sizeof( _3ds ) );
Load3DS( filename, &_3ds, verbose );
// compute information
numPolysets = _3ds.editChunk.numNamedObjects;
// allocate memory
pPSET = calloc( 1, numPolysets * sizeof( polyset_t ) );
triangles = ptri = calloc( 1, POLYSET_MAXTRIANGLES * sizeof( triangle_t ) );
// copy the data over
for ( i = 0; i < numPolysets; i++ )
{
char matnamebuf[1024];
int j;
triangle_t *tri;
_3DSTriObject_t *pTO = &_3ds.editChunk.pNamedObjects[i].pTriObjects[0];
pPSET[i].triangles = ptri;
pPSET[i].numtriangles = pTO->numFaces;
strcpy( pPSET[i].name, _3ds.editChunk.pNamedObjects[i].name );
strcpy( matnamebuf, filename );
if ( strrchr( matnamebuf, '/' ) )
*( strrchr( matnamebuf, '/' ) + 1 )= 0;
strcat( matnamebuf, pTO->pMeshMaterialGroups[0].name );
if ( strstr( matnamebuf, gamedir ) )
strcpy( pPSET[i].materialname, strstr( matnamebuf, gamedir ) + strlen( gamedir ) );
else
strcpy( pPSET[i].materialname, pTO->pMeshMaterialGroups[0].name );
assert( pPSET[i].numtriangles < POLYSET_MAXTRIANGLES );
for ( tri = ptri, j = 0; j < pPSET[i].numtriangles; j++ )
{
int i0 = pTO->pFaces[j].c;
int i1 = pTO->pFaces[j].b;
int i2 = pTO->pFaces[j].a;
tri->verts[0][0] = pTO->pPoints[i0].x;
tri->verts[0][1] = pTO->pPoints[i0].y;
tri->verts[0][2] = pTO->pPoints[i0].z;
tri->verts[1][0] = pTO->pPoints[i1].x;
tri->verts[1][1] = pTO->pPoints[i1].y;
tri->verts[1][2] = pTO->pPoints[i1].z;
tri->verts[2][0] = pTO->pPoints[i2].x;
tri->verts[2][1] = pTO->pPoints[i2].y;
tri->verts[2][2] = pTO->pPoints[i2].z;
/*
for ( k = 0; k < 3; k++ )
{
tri->colors[0][k] = 1;
tri->colors[1][k] = 1;
tri->colors[2][k] = 1;
}
*/
if ( pTO->pTexVerts )
{
tri->texcoords[0][0] = pTO->pTexVerts[i0].s;
tri->texcoords[0][1] = 1.0f - pTO->pTexVerts[i0].t;
tri->texcoords[1][0] = pTO->pTexVerts[i1].s;
tri->texcoords[1][1] = 1.0f - pTO->pTexVerts[i1].t;
tri->texcoords[2][0] = pTO->pTexVerts[i2].s;
tri->texcoords[2][1] = 1.0f - pTO->pTexVerts[i2].t;
}
tri++;
}
ptri += pPSET[i].numtriangles;
assert( ptri - triangles < POLYSET_MAXTRIANGLES );
}
// compute normal data
#if 0
for ( i = 0; i < numPolysets; i++ )
{
// unique vertices based solely on vertex position
ComputeNormals( &_3ds.editChunk.pNamedObjects[i].pTriObjects[0],
pPSET[i].triangles );
}
#endif
free( _3ds.editChunk.pMaterials );
free( _3ds.editChunk.pNamedObjects );
*ppPSET = pPSET;
*numpsets = numPolysets;
}

View File

@@ -0,0 +1,139 @@
/*
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
{
float x, y, z;
} _3DSPoint_t;
typedef struct
{
short a, b, c;
short flags;
} _3DSFace_t;
typedef struct
{
float s, t;
} _3DSTexVert_t;
typedef struct
{
char name[100];
short numFaces;
short *pFaces;
} _3DSMeshMaterialGroup_t;
typedef struct
{
char name[80];
char texture[100];
char specular[100];
char reflection[100];
char bump[100];
char opacity[100];
} _3DSMaterial_t;
typedef struct
{
short numFaces, numPoints, numTexVerts;
int numMeshMaterialGroups;
_3DSPoint_t *pPoints;
_3DSFace_t *pFaces;
_3DSTexVert_t *pTexVerts;
_3DSMeshMaterialGroup_t *pMeshMaterialGroups;
} _3DSTriObject_t;
typedef struct
{
char name[100];
int numTriObjects;
_3DSTriObject_t *pTriObjects;
} _3DSNamedObject_t;
typedef struct
{
int numNamedObjects;
int numMaterials;
_3DSNamedObject_t *pNamedObjects;
_3DSMaterial_t *pMaterials;
} _3DSEditChunk_t;
typedef struct
{
_3DSEditChunk_t editChunk;
} _3DS_t;
#define _3DS_CHUNK_NULL 0x0000
#define _3DS_CHUNK_UNKNOWN0 0x0001
#define _3DS_CHUNK_M3D_VERSION 0x0002
#define _3DS_CHUNK_M3D_KFVERSION 0x0005
#define _3DS_CHUNK_COLOR_F 0x0010
#define _3DS_CHUNK_COLOR_24 0x0011
#define _3DS_CHUNK_LIN_COLOR_24 0x0012
#define _3DS_CHUNK_LIN_COLOR_F 0x0013
#define _3DS_CHUNK_INT_PERCENTAGE 0x0030
#define _3DS_CHUNK_FLOAT_PERCENT 0x0031
#define _3DS_CHUNK_MASTER_SCALE 0x0100
#define _3DS_CHUNK_CHUNK_TYPE 0x0995
#define _3DS_CHUNK_CHUNK_UNIQUE 0x0996
#define _3DS_CHUNK_NOT_CHUNK 0x0997
#define _3DS_CHUNK_CONTAINER 0x0998
#define _3DS_CHUNK_IS_CHUNK 0x0999
#define _3DS_CHUNK_C_SXP_SELFI_MASKDATA 0x0c3c
#define _3DS_CHUNK_BITMAP 0x1100
#define _3DS_CHUNK_USE_BITMAP 0x1101
#define _3DS_CHUNK_SOLID_BGND 0x1200
#define _3DS_CHUNK_USE_SOLID_BGND 0x1201
#define _3DS_CHUNK_EDIT 0x3d3d
#define _3DS_CHUNK_MESH_VERSION 0x3d3e
#define _3DS_CHUNK_NAMED_OBJECT 0x4000
#define _3DS_CHUNK_NAMED_TRI_OBJECT 0x4100
#define _3DS_CHUNK_POINT_ARRAY 0x4110
#define _3DS_CHUNK_POINT_FLAG_ARRAY 0x4111
#define _3DS_CHUNK_FACE_ARRAY 0x4120
#define _3DS_CHUNK_MSH_MAT_GROUP 0x4130
#define _3DS_CHUNK_TEX_VERTS 0x4140
#define _3DS_CHUNK_SMOOTH_GROUP 0x4150
#define _3DS_CHUNK_MESH_MATRIX 0x4160
#define _3DS_CHUNK_MAGIC 0x4d4d
#define _3DS_CHUNK_MAT_NAME 0xa000
#define _3DS_CHUNK_TEXMAP 0xa200
#define _3DS_CHUNK_SPECMAP 0xa204
#define _3DS_CHUNK_OPACMAP 0xa210
#define _3DS_CHUNK_REFLMAP 0xa220
#define _3DS_CHUNK_BUMPMAP 0xa230
#define _3DS_CHUNK_MAT_MAPNAME 0xa300
#define _3DS_CHUNK_MAT_LIST 0xafff
#define _3DS_CHUNK_KEYFRAME_DATA 0xb000
void _3DS_LoadPolysets( const char *filename, polyset_t **ppPSET, int *numpsets, qboolean verbose );

View File

@@ -0,0 +1,771 @@
/*
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 "q3data.h"
#if 0
/*
==================
MTF
==================
*/
cblock_t MTF (cblock_t in)
{
int i, j, b, code;
byte *out_p;
int index[256];
cblock_t out;
out_p = out.data = malloc(in.count + 4);
// write count
*out_p++ = in.count&255;
*out_p++ = (in.count>>8)&255;
*out_p++ = (in.count>>16)&255;
*out_p++ = (in.count>>24)&255;
for (i=0 ; i<256 ; i++)
index[i] = i;
for (i=0 ; i<in.count ; i++)
{
b = in.data[i];
code = index[b];
*out_p++ = code;
// shuffle b indexes to 0
for (j=0 ; j<256 ; j++)
if (index[j] < code)
index[j]++;
index[b] = 0;
}
out.count = out_p - out.data;
return out;
}
//==========================================================================
int bwt_size;
byte *bwt_data;
int bwtCompare (const void *elem1, const void *elem2)
{
int i;
int i1, i2;
int b1, b2;
i1 = *(int *)elem1;
i2 = *(int *)elem2;
for (i=0 ; i<bwt_size ; i++)
{
b1 = bwt_data[i1];
b2 = bwt_data[i2];
if (b1 < b2)
return -1;
if (b1 > b2)
return 1;
if (++i1 == bwt_size)
i1 = 0;
if (++i2 == bwt_size)
i2 = 0;
}
return 0;
}
/*
==================
BWT
==================
*/
cblock_t BWT (cblock_t in)
{
int *sorted;
int i;
byte *out_p;
cblock_t out;
bwt_size = in.count;
bwt_data = in.data;
sorted = malloc(in.count*sizeof(*sorted));
for (i=0 ; i<in.count ; i++)
sorted[i] = i;
qsort (sorted, in.count, sizeof(*sorted), bwtCompare);
out_p = out.data = malloc(in.count + 8);
// write count
*out_p++ = in.count&255;
*out_p++ = (in.count>>8)&255;
*out_p++ = (in.count>>16)&255;
*out_p++ = (in.count>>24)&255;
// write head index
for (i=0 ; i<in.count ; i++)
if (sorted[i] == 0)
break;
*out_p++ = i&255;
*out_p++ = (i>>8)&255;
*out_p++ = (i>>16)&255;
*out_p++ = (i>>24)&255;
// write the L column
for (i=0 ; i<in.count ; i++)
*out_p++ = in.data[(sorted[i]+in.count-1)%in.count];
free (sorted);
out.count = out_p - out.data;
return out;
}
//==========================================================================
typedef struct hnode_s
{
int count;
qboolean used;
int children[2];
} hnode_t;
int numhnodes;
hnode_t hnodes[512];
unsigned charbits[256];
int charbitscount[256];
int SmallestNode (void)
{
int i;
int best, bestnode;
best = 99999999;
bestnode = -1;
for (i=0 ; i<numhnodes ; i++)
{
if (hnodes[i].used)
continue;
if (!hnodes[i].count)
continue;
if (hnodes[i].count < best)
{
best = hnodes[i].count;
bestnode = i;
}
}
if (bestnode == -1)
return -1;
hnodes[bestnode].used = true;
return bestnode;
}
void BuildChars (int nodenum, unsigned bits, int bitcount)
{
hnode_t *node;
if (nodenum < 256)
{
if (bitcount > 32)
Error ("bitcount > 32");
charbits[nodenum] = bits;
charbitscount[nodenum] = bitcount;
return;
}
node = &hnodes[nodenum];
bits <<= 1;
BuildChars (node->children[0], bits, bitcount+1);
bits |= 1;
BuildChars (node->children[1], bits, bitcount+1);
}
/*
==================
Huffman
==================
*/
cblock_t Huffman (cblock_t in)
{
int i;
hnode_t *node;
int outbits, c;
unsigned bits;
byte *out_p;
cblock_t out;
int max, maxchar;
// count
memset (hnodes, 0, sizeof(hnodes));
for (i=0 ; i<in.count ; i++)
hnodes[in.data[i]].count++;
// normalize counts
max = 0;
maxchar = 0;
for (i=0 ; i<256 ; i++)
{
if (hnodes[i].count > max)
{
max = hnodes[i].count;
maxchar = i;
}
}
if (max == 0)
Error ("Huffman: max == 0");
for (i=0 ; i<256 ; i++)
{
hnodes[i].count = (hnodes[i].count*255+max-1) / max;
}
// build the nodes
numhnodes = 256;
while (numhnodes != 511)
{
node = &hnodes[numhnodes];
// pick two lowest counts
node->children[0] = SmallestNode ();
if (node->children[0] == -1)
break; // no more
node->children[1] = SmallestNode ();
if (node->children[1] == -1)
{
if (node->children[0] != numhnodes-1)
Error ("Bad smallestnode");
break;
}
node->count = hnodes[node->children[0]].count +
hnodes[node->children[1]].count;
numhnodes++;
}
BuildChars (numhnodes-1, 0, 0);
out_p = out.data = malloc(in.count*2 + 1024);
memset (out_p, 0, in.count*2+1024);
// write count
*out_p++ = in.count&255;
*out_p++ = (in.count>>8)&255;
*out_p++ = (in.count>>16)&255;
*out_p++ = (in.count>>24)&255;
// save out the 256 normalized counts so the tree can be recreated
for (i=0 ; i<256 ; i++)
*out_p++ = hnodes[i].count;
// write bits
outbits = 0;
for (i=0 ; i<in.count ; i++)
{
c = charbitscount[in.data[i]];
bits = charbits[in.data[i]];
while (c)
{
c--;
if (bits & (1<<c))
out_p[outbits>>3] |= 1<<(outbits&7);
outbits++;
}
}
out_p += (outbits+7)>>3;
out.count = out_p - out.data;
return out;
}
//==========================================================================
/*
==================
RLE
==================
*/
#define RLE_CODE 0xe8
#define RLE_TRIPPLE 0xe9
int rle_counts[256];
int rle_bytes[256];
cblock_t RLE (cblock_t in)
{
int i;
byte *out_p;
int val;
int repeat;
cblock_t out;
out_p = out.data = malloc (in.count*2);
// write count
*out_p++ = in.count&255;
*out_p++ = (in.count>>8)&255;
*out_p++ = (in.count>>16)&255;
*out_p++ = (in.count>>24)&255;
for (i=0 ; i<in.count ; )
{
val = in.data[i];
rle_bytes[val]++;
repeat = 1;
i++;
while (i<in.count && repeat < 255 && in.data[i] == val)
{
repeat++;
i++;
}
if (repeat < 256)
rle_counts[repeat]++;
if (repeat > 3 || val == RLE_CODE)
{
*out_p++ = RLE_CODE;
*out_p++ = val;
*out_p++ = repeat;
}
else
{
while (repeat--)
*out_p++ = val;
}
}
out.count = out_p - out.data;
return out;
}
//==========================================================================
unsigned lzss_head[256];
unsigned lzss_next[0x20000];
/*
==================
LZSS
==================
*/
#define BACK_WINDOW 0x10000
#define BACK_BITS 16
#define FRONT_WINDOW 16
#define FRONT_BITS 4
cblock_t LZSS (cblock_t in)
{
int i;
byte *out_p;
cblock_t out;
int val;
int j, start, max;
int bestlength, beststart;
int outbits;
if (in.count >= sizeof(lzss_next)/4)
Error ("LZSS: too big");
memset (lzss_head, -1, sizeof(lzss_head));
out_p = out.data = malloc (in.count*2);
memset (out.data, 0, in.count*2);
// write count
*out_p++ = in.count&255;
*out_p++ = (in.count>>8)&255;
*out_p++ = (in.count>>16)&255;
*out_p++ = (in.count>>24)&255;
outbits = 0;
for (i=0 ; i<in.count ; )
{
val = in.data[i];
#if 1
// chained search
bestlength = 0;
beststart = 0;
max = FRONT_WINDOW;
if (i + max > in.count)
max = in.count - i;
start = lzss_head[val];
while (start != -1 && start >= i-BACK_WINDOW)
{
// count match length
for (j=0 ; j<max ; j++)
if (in.data[start+j] != in.data[i+j])
break;
if (j > bestlength)
{
bestlength = j;
beststart = start;
}
start = lzss_next[start];
}
#else
// slow simple search
// search for a match
max = FRONT_WINDOW;
if (i + max > in.count)
max = in.count - i;
start = i - BACK_WINDOW;
if (start < 0)
start = 0;
bestlength = 0;
beststart = 0;
for ( ; start < i ; start++)
{
if (in.data[start] != val)
continue;
// count match length
for (j=0 ; j<max ; j++)
if (in.data[start+j] != in.data[i+j])
break;
if (j > bestlength)
{
bestlength = j;
beststart = start;
}
}
#endif
beststart = BACK_WINDOW - (i-beststart);
if (bestlength < 3)
{ // output a single char
bestlength = 1;
out_p[outbits>>3] |= 1<<(outbits&7); // set bit to mark char
outbits++;
for (j=0 ; j<8 ; j++, outbits++)
if (val & (1<<j) )
out_p[outbits>>3] |= 1<<(outbits&7);
}
else
{ // output a phrase
outbits++; // leave a 0 bit to mark phrase
for (j=0 ; j<BACK_BITS ; j++, outbits++)
if (beststart & (1<<j) )
out_p[outbits>>3] |= 1<<(outbits&7);
for (j=0 ; j<FRONT_BITS ; j++, outbits++)
if (bestlength & (1<<j) )
out_p[outbits>>3] |= 1<<(outbits&7);
}
while (bestlength--)
{
val = in.data[i];
lzss_next[i] = lzss_head[val];
lzss_head[val] = i;
i++;
}
}
out_p += (outbits+7)>>3;
out.count = out_p - out.data;
return out;
}
//==========================================================================
#define MIN_REPT 15
#define MAX_REPT 0
#define HUF_TOKENS (256+MAX_REPT)
unsigned charbits1[256][HUF_TOKENS];
int charbitscount1[256][HUF_TOKENS];
hnode_t hnodes1[256][HUF_TOKENS*2];
int numhnodes1[256];
int order0counts[256];
/*
==================
SmallestNode1
==================
*/
int SmallestNode1 (hnode_t *hnodes, int numhnodes)
{
int i;
int best, bestnode;
best = 99999999;
bestnode = -1;
for (i=0 ; i<numhnodes ; i++)
{
if (hnodes[i].used)
continue;
if (!hnodes[i].count)
continue;
if (hnodes[i].count < best)
{
best = hnodes[i].count;
bestnode = i;
}
}
if (bestnode == -1)
return -1;
hnodes[bestnode].used = true;
return bestnode;
}
/*
==================
BuildChars1
==================
*/
void BuildChars1 (int prev, int nodenum, unsigned bits, int bitcount)
{
hnode_t *node;
if (nodenum < HUF_TOKENS)
{
if (bitcount > 32)
Error ("bitcount > 32");
charbits1[prev][nodenum] = bits;
charbitscount1[prev][nodenum] = bitcount;
return;
}
node = &hnodes1[prev][nodenum];
bits <<= 1;
BuildChars1 (prev, node->children[0], bits, bitcount+1);
bits |= 1;
BuildChars1 (prev, node->children[1], bits, bitcount+1);
}
/*
==================
BuildTree1
==================
*/
void BuildTree1 (int prev)
{
hnode_t *node, *nodebase;
int numhnodes;
// build the nodes
numhnodes = HUF_TOKENS;
nodebase = hnodes1[prev];
while (1)
{
node = &nodebase[numhnodes];
// pick two lowest counts
node->children[0] = SmallestNode1 (nodebase, numhnodes);
if (node->children[0] == -1)
break; // no more
node->children[1] = SmallestNode1 (nodebase, numhnodes);
if (node->children[1] == -1)
break;
node->count = nodebase[node->children[0]].count +
nodebase[node->children[1]].count;
numhnodes++;
}
numhnodes1[prev] = numhnodes-1;
BuildChars1 (prev, numhnodes-1, 0, 0);
}
/*
==================
Huffman1_Count
==================
*/
void Huffman1_Count (cblock_t in)
{
int i;
int prev;
int v;
int rept;
prev = 0;
for (i=0 ; i<in.count ; i++)
{
v = in.data[i];
order0counts[v]++;
hnodes1[prev][v].count++;
prev = v;
#if 1
for (rept=1 ; i+rept < in.count && rept < MAX_REPT ; rept++)
if (in.data[i+rept] != v)
break;
if (rept > MIN_REPT)
{
hnodes1[prev][255+rept].count++;
i += rept-1;
}
#endif
}
}
/*
==================
Huffman1_Build
==================
*/
byte scaled[256][HUF_TOKENS];
void Huffman1_Build (FILE *f)
{
int i, j, v;
int max;
int total;
for (i=0 ; i<256 ; i++)
{
// normalize and save the counts
max = 0;
for (j=0 ; j<HUF_TOKENS ; j++)
{
if (hnodes1[i][j].count > max)
max = hnodes1[i][j].count;
}
if (max == 0)
max = 1;
total = 0;
for (j=0 ; j<HUF_TOKENS ; j++)
{ // easy to overflow 32 bits here!
v = (hnodes1[i][j].count*(double)255+max-1)/max;
if (v > 255)
Error ("v > 255");
scaled[i][j] = hnodes1[i][j].count = v;
if (v)
total++;
}
if (total == 1)
{ // must have two tokens
if (!scaled[i][0])
scaled[i][0] = hnodes1[i][0].count = 1;
else
scaled[i][1] = hnodes1[i][1].count = 1;
}
BuildTree1 (i);
}
#if 0
// count up the total bits
total = 0;
for (i=0 ; i<256 ; i++)
for (j=0 ; j<256 ; j++)
total += charbitscount1[i][j] * hnodes1[i][j].count;
total = (total+7)/8;
printf ("%i bytes huffman1 compressed\n", total);
#endif
fwrite (scaled, 1, sizeof(scaled), f);
}
/*
==================
Huffman1
Order 1 compression with pre-built table
==================
*/
cblock_t Huffman1 (cblock_t in)
{
int i;
int outbits, c;
unsigned bits;
byte *out_p;
cblock_t out;
int prev;
int v;
int rept;
out_p = out.data = malloc(in.count*2 + 1024);
memset (out_p, 0, in.count*2+1024);
// write count
*out_p++ = in.count&255;
*out_p++ = (in.count>>8)&255;
*out_p++ = (in.count>>16)&255;
*out_p++ = (in.count>>24)&255;
// write bits
outbits = 0;
prev = 0;
for (i=0 ; i<in.count ; i++)
{
v = in.data[i];
c = charbitscount1[prev][v];
bits = charbits1[prev][v];
if (!c)
Error ("!bits");
while (c)
{
c--;
if (bits & (1<<c))
out_p[outbits>>3] |= 1<<(outbits&7);
outbits++;
}
prev = v;
#if 1
// check for repeat encodes
for (rept=1 ; i+rept < in.count && rept < MAX_REPT ; rept++)
if (in.data[i+rept] != v)
break;
if (rept > MIN_REPT)
{
c = charbitscount1[prev][255+rept];
bits = charbits1[prev][255+rept];
if (!c)
Error ("!bits");
while (c)
{
c--;
if (bits & (1<<c))
out_p[outbits>>3] |= 1<<(outbits&7);
outbits++;
}
i += rept-1;
}
#endif
}
out_p += (outbits+7)>>3;
out.count = out_p - out.data;
return out;
}
#endif

View File

@@ -0,0 +1,486 @@
/*
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 "q3data.h"
byte *byteimage, *lbmpalette;
int byteimagewidth, byteimageheight;
char mip_prefix[1024]; // directory to dump the textures in
qboolean colormap_issued;
byte colormap_palette[768];
/*
==============
Cmd_Grab
$grab filename x y width height
==============
*/
void Cmd_Grab (void)
{
int xl,yl,w,h,y;
byte *cropped;
char savename[1024];
char dest[1024];
GetToken (qfalse);
if (token[0] == '/' || token[0] == '\\')
sprintf (savename, "%s%s.pcx", writedir, token+1);
else
sprintf (savename, "%spics/%s.pcx", writedir, token);
if (g_release)
{
if (token[0] == '/' || token[0] == '\\')
sprintf (dest, "%s.pcx", token+1);
else
sprintf (dest, "pics/%s.pcx", token);
ReleaseFile (dest);
return;
}
GetToken (qfalse);
xl = atoi (token);
GetToken (qfalse);
yl = atoi (token);
GetToken (qfalse);
w = atoi (token);
GetToken (qfalse);
h = atoi (token);
if (xl<0 || yl<0 || w<0 || h<0 || xl+w>byteimagewidth || yl+h>byteimageheight)
Error ("GrabPic: Bad size: %i, %i, %i, %i",xl,yl,w,h);
// crop it to the proper size
cropped = malloc (w*h);
for (y=0 ; y<h ; y++)
{
memcpy (cropped+y*w, byteimage+(y+yl)*byteimagewidth+xl, w);
}
// save off the new image
printf ("saving %s\n", savename);
CreatePath (savename);
WritePCXfile (savename, cropped, w, h, lbmpalette);
free (cropped);
}
/*
==============
Cmd_Raw
$grab filename x y width height
==============
*/
void Cmd_Raw (void)
{
int xl,yl,w,h,y;
byte *cropped;
char savename[1024];
char dest[1024];
GetToken (qfalse);
sprintf (savename, "%s%s.lmp", writedir, token);
if (g_release)
{
sprintf (dest, "%s.lmp", token);
ReleaseFile (dest);
return;
}
GetToken (qfalse);
xl = atoi (token);
GetToken (qfalse);
yl = atoi (token);
GetToken (qfalse);
w = atoi (token);
GetToken (qfalse);
h = atoi (token);
if (xl<0 || yl<0 || w<0 || h<0 || xl+w>byteimagewidth || yl+h>byteimageheight)
Error ("GrabPic: Bad size: %i, %i, %i, %i",xl,yl,w,h);
// crop it to the proper size
cropped = malloc (w*h);
for (y=0 ; y<h ; y++)
{
memcpy (cropped+y*w, byteimage+(y+yl)*byteimagewidth+xl, w);
}
// save off the new image
printf ("saving %s\n", savename);
CreatePath (savename);
SaveFile (savename, cropped, w*h);
free (cropped);
}
/*
=============================================================================
COLORMAP GRABBING
=============================================================================
*/
/*
===============
BestColor
===============
*/
byte BestColor (int r, int g, int b, int start, int stop)
{
int i;
int dr, dg, db;
int bestdistortion, distortion;
int bestcolor;
byte *pal;
//
// let any color go to 0 as a last resort
//
bestdistortion = 256*256*4;
bestcolor = 0;
pal = colormap_palette + start*3;
for (i=start ; i<= stop ; i++)
{
dr = r - (int)pal[0];
dg = g - (int)pal[1];
db = b - (int)pal[2];
pal += 3;
distortion = dr*dr + dg*dg + db*db;
if (distortion < bestdistortion)
{
if (!distortion)
return i; // perfect match
bestdistortion = distortion;
bestcolor = i;
}
}
return bestcolor;
}
/*
==============
Cmd_Colormap
$colormap filename
the brightes colormap is first in the table (FIXME: reverse this now?)
64 rows of 256 : lightmaps
256 rows of 256 : translucency table
==============
*/
void Cmd_Colormap (void)
{
int levels, brights;
int l, c;
float frac, red, green, blue;
float range;
byte *cropped, *lump_p;
char savename[1024];
char dest[1024];
colormap_issued = qtrue;
if (!g_release)
memcpy (colormap_palette, lbmpalette, 768);
if (!TokenAvailable ())
{ // just setting colormap_issued
return;
}
GetToken (qfalse);
sprintf (savename, "%spics/%s.pcx", writedir, token);
if (g_release)
{
sprintf (dest, "pics/%s.pcx", token);
ReleaseFile (dest);
return;
}
range = 2;
levels = 64;
brights = 1; // ignore 255 (transparent)
cropped = malloc((levels+256)*256);
lump_p = cropped;
// shaded levels
for (l=0;l<levels;l++)
{
frac = range - range*(float)l/(levels-1);
for (c=0 ; c<256-brights ; c++)
{
red = lbmpalette[c*3];
green = lbmpalette[c*3+1];
blue = lbmpalette[c*3+2];
red = (int)(red*frac+0.5);
green = (int)(green*frac+0.5);
blue = (int)(blue*frac+0.5);
//
// note: 254 instead of 255 because 255 is the transparent color, and we
// don't want anything remapping to that
// don't use color 0, because NT can't remap that (or 255)
//
*lump_p++ = BestColor(red,green,blue, 1, 254);
}
// fullbrights allways stay the same
for ( ; c<256 ; c++)
*lump_p++ = c;
}
// 66% transparancy table
for (l=0;l<255;l++)
{
for (c=0 ; c<255 ; c++)
{
red = lbmpalette[c*3]*0.33 + lbmpalette[l*3]*0.66;
green = lbmpalette[c*3+1]*0.33 + lbmpalette[l*3+1]*0.66;
blue = lbmpalette[c*3+2]*0.33 + lbmpalette[l*3+2]*0.66;
*lump_p++ = BestColor(red,green,blue, 1, 254);
}
*lump_p++ = 255;
}
for (c=0 ; c<256 ; c++)
*lump_p++ = 255;
// save off the new image
printf ("saving %s\n", savename);
CreatePath (savename);
WritePCXfile (savename, cropped, 256, levels+256, lbmpalette);
free (cropped);
}
/*
=============================================================================
MIPTEX GRABBING
=============================================================================
*/
byte pixdata[256];
int d_red, d_green, d_blue;
byte palmap[32][32][32];
qboolean palmap_built;
/*
=============
FindColor
=============
*/
int FindColor (int r, int g, int b)
{
int bestcolor;
if (r > 255)
r = 255;
if (r < 0)
r = 0;
if (g > 255)
g = 255;
if (g < 0)
g = 0;
if (b > 255)
b = 255;
if (b < 0)
b = 0;
#ifndef TABLECOLORS
bestcolor = BestColor (r, g, b, 0, 254);
#else
bestcolor = palmap[r>>3][g>>3][b>>3];
#endif
return bestcolor;
}
void BuildPalmap (void)
{
#ifdef TABLECOLORS
int r, g, b;
int bestcolor;
if (palmap_built)
return;
palmap_built = qtrue;
for (r=4 ; r<256 ; r+=8)
{
for (g=4 ; g<256 ; g+=8)
{
for (b=4 ; b<256 ; b+=8)
{
bestcolor = BestColor (r, g, b, 1, 254);
palmap[r>>3][g>>3][b>>3] = bestcolor;
}
}
}
#endif
if (!colormap_issued)
Error ("You must issue a $colormap command first");
}
/*
=============
AveragePixels
=============
*/
byte AveragePixels (int count)
{
int r,g,b;
int i;
int vis;
int pix;
int bestcolor;
byte *pal;
int fullbright;
vis = 0;
r = g = b = 0;
fullbright = 0;
for (i=0 ; i<count ; i++)
{
pix = pixdata[i];
r += lbmpalette[pix*3];
g += lbmpalette[pix*3+1];
b += lbmpalette[pix*3+2];
vis++;
}
r /= vis;
g /= vis;
b /= vis;
// error diffusion
r += d_red;
g += d_green;
b += d_blue;
//
// find the best color
//
bestcolor = FindColor (r, g, b);
// error diffusion
pal = colormap_palette + bestcolor*3;
d_red = r - (int)pal[0];
d_green = g - (int)pal[1];
d_blue = b - (int)pal[2];
return bestcolor;
}
/*
=============================================================================
ENVIRONMENT MAP GRABBING
Creates six pcx files from tga files without any palette edge seams
also copies the tga files for GL rendering.
=============================================================================
*/
// 3dstudio environment map suffixes
char *suf[6] = {"rt", "ft", "lf", "bk", "up", "dn"};
/*
=================
Cmd_Environment
=================
*/
void Cmd_Environment (void)
{
char name[1024];
int i, x, y;
byte image[256*256];
byte *tga;
GetToken (qfalse);
if (g_release)
{
for (i=0 ; i<6 ; i++)
{
sprintf (name, "env/%s%s.pcx", token, suf[i]);
ReleaseFile (name);
sprintf (name, "env/%s%s.tga", token, suf[i]);
ReleaseFile (name);
}
return;
}
// get the palette
BuildPalmap ();
sprintf (name, "%senv/", gamedir);
CreatePath (name);
// convert the images
for (i=0 ; i<6 ; i++)
{
sprintf (name, "%senv/%s%s.tga", gamedir, token, suf[i]);
printf ("loading %s...\n", name);
LoadTGA (name, &tga, NULL, NULL);
for (y=0 ; y<256 ; y++)
{
for (x=0 ; x<256 ; x++)
{
image[y*256+x] = FindColor (tga[(y*256+x)*4+0],tga[(y*256+x)*4+1],tga[(y*256+x)*4+2]);
}
}
free (tga);
sprintf (name, "%senv/%s%s.pcx", writedir, token, suf[i]);
if (FileTime (name) != -1)
printf ("%s already exists, not overwriting.\n", name);
else
WritePCXfile (name, image, 256, 256, colormap_palette);
}
}

View File

@@ -0,0 +1,214 @@
/*
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 <assert.h>
#ifdef WIN32
#include <io.h>
#endif
#include "md3lib.h"
#if defined (__linux__) || defined (__APPLE__)
#define filelength Q_filelength
#endif
/*
** MD3_ComputeTagFromTri
*/
void MD3_ComputeTagFromTri( md3Tag_t *pTag, const float pTri[3][3] )
{
float len[3];
vec3_t axes[3], sides[3];
int longestSide, shortestSide, hypotSide;
int origin;
int j;
float d;
memset( axes, 0, sizeof( axes ) );
memset( sides, 0, sizeof( sides ) );
//
// compute sides
//
for ( j = 0; j < 3; j++ )
{
sides[j][0] = pTri[(j+1)%3][0] - pTri[j][0];
sides[j][1] = pTri[(j+1)%3][1] - pTri[j][1];
sides[j][2] = pTri[(j+1)%3][2] - pTri[j][2];
len[j] = ( float ) sqrt( DotProduct( sides[j], sides[j] ) );
}
#if 0
if ( len[0] > len[1] && len[0] > len[2] )
{
longestSide = 0; shortestSide = 1; origin = 2;
}
else if ( len[1] > len[0] && len[1] > len[2] )
{
longestSide = 1; shortestSide = 2; origin = 0;
}
else if ( len[2] > len[0] && len[2] > len[1] )
{
longestSide = 2; shortestSide = 0; origin = 1;
}
else
{
Error( "invalid tag triangle, must be a right triangle with unequal length sides" );
}
#endif
if ( len[0] > len[1] && len[0] > len[2] ) {
hypotSide = 0;
origin = 2;
} else if ( len[1] > len[0] && len[1] > len[2] ) {
hypotSide = 1;
origin = 0;
} else if ( len[2] > len[0] && len[2] > len[1] ) {
hypotSide = 2;
origin = 1;
}
len[hypotSide] = -1;
if ( len[0] > len[1] && len[0] > len[2] ) {
longestSide = 0;
} else if ( len[1] > len[0] && len[1] > len[2] ) {
longestSide = 1;
} else if ( len[2] > len[0] && len[2] > len[1] ) {
longestSide = 2;
}
len[longestSide] = -1;
if ( len[0] > len[1] && len[0] > len[2] ) {
shortestSide = 0;
} else if ( len[1] > len[0] && len[1] > len[2] ) {
shortestSide = 1;
} else if ( len[2] > len[0] && len[2] > len[1] ) {
shortestSide = 2;
}
len[shortestSide] = -1;
// VectorNormalize( sides[shortestSide], axes[0] );
// VectorNormalize( sides[longestSide], axes[1] );
VectorNormalize( sides[longestSide], axes[0] );
VectorNormalize( sides[shortestSide], axes[1] );
// project shortest side so that it is exactly 90 degrees to the longer side
d = DotProduct( axes[0], axes[1] );
VectorMA( axes[0], -d, axes[1], axes[0] );
VectorNormalize( axes[0], axes[0] );
CrossProduct( sides[longestSide], sides[shortestSide], axes[2] );
VectorNormalize( axes[2], axes[2] );
pTag->origin[0] = pTri[origin][0];
pTag->origin[1] = pTri[origin][1];
pTag->origin[2] = pTri[origin][2];
VectorCopy( axes[0], pTag->axis[0] );
VectorCopy( axes[1], pTag->axis[1] );
VectorCopy( axes[2], pTag->axis[2] );
}
/*
==============
MD3_Dump
==============
*/
void MD3_Dump( const char *filename )
{
md3Header_t header;
md3Tag_t *pTag;
md3Surface_t *pSurface;
FILE *fp;
void *_buffer;
void *buffer;
long fileSize;
int i;
if ( ( fp = fopen( filename, "rb" ) ) == 0 )
{
Error( "Unable to open '%s'\n", filename );
}
fileSize = filelength( fileno( fp ) );
_buffer = malloc( filelength( fileno( fp ) ) );
fread( _buffer, fileSize, 1, fp );
fclose( fp );
buffer = ( char * ) _buffer;
header = *( md3Header_t * ) _buffer;
if ( header.ident != MD3_IDENT )
{
Error( "Incorrect ident for '%s'\n", filename );
}
printf( "Contents of '%s'\n", filename );
printf( " version: %d\n", header.version );
printf( " name: %s\n", header.name );
printf( " num frames: %d\n", header.numFrames );
printf( " num tags: %d\n", header.numTags );
printf( " num surfaces: %d\n", header.numSurfaces );
printf( " num skins: %d\n", header.numSkins );
printf( " file size: %d\n", fileSize );
printf( "--- TAGS ---\n" );
pTag = ( md3Tag_t * ) ( ( ( char * ) buffer ) + header.ofsTags );
for ( i = 0; i < header.numTags; i++, pTag++ )
{
printf( " tag %d ('%s')\n", i, pTag->name );
printf( " origin: %f,%f,%f\n", pTag->origin[0], pTag->origin[1], pTag->origin[2] );
printf( " vf: %f,%f,%f\n", pTag->axis[0][0], pTag->axis[0][1], pTag->axis[0][2] );
printf( " vr: %f,%f,%f\n", pTag->axis[1][0], pTag->axis[1][1], pTag->axis[1][2] );
printf( " vu: %f,%f,%f\n", pTag->axis[2][0], pTag->axis[2][1], pTag->axis[2][2] );
}
printf( "--- SURFACES ---\n" );
pSurface = ( md3Surface_t * ) ( ( ( char * ) buffer ) + header.ofsSurfaces );
for ( i = 0; i < header.numSurfaces; i++ )
{
int j;
md3Shader_t *pShader = ( md3Shader_t * ) ( ( ( char * ) pSurface ) + pSurface->ofsShaders );
printf( "\n surface %d ('%s')\n", i, pSurface->name );
printf( " num frames: %d\n", pSurface->numFrames );
printf( " num shaders: %d\n", pSurface->numShaders );
printf( " num tris: %d\n", pSurface->numTriangles );
printf( " num verts: %d\n", pSurface->numVerts );
if ( pSurface->numShaders > 0 )
{
printf( " --- SHADERS ---\n" );
for ( j = 0; j < pSurface->numShaders; j++, pShader++ )
{
printf( " shader %d ('%s')\n", j, pShader->name );
}
}
pSurface = ( md3Surface_t * ) ( ( ( char * ) pSurface ) + pSurface->ofsEnd );
}
free( _buffer );
}

View 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
*/
#include <stdio.h>
#include "../common/cmdlib.h"
#include "mathlib.h"
#include "../common/qfiles.h"
void MD3_Dump( const char *filename );
void MD3_ComputeTagFromTri( md3Tag_t *pTag, const float tri[3][3] );

2155
tools/quake3/q3data/models.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,151 @@
/*
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 0
/*
** ReindexTriangle
**
** Given a triangle_t, find which indices match into the associated
** surface's base triangles.
*/
static void ReindexTriangle( int surfno, triangle_t *pTri, int indices[3] )
{
int t, i;
md3SurfaceData_t *pSurfData = &g_data.surfData[surfno];
int matches[3][3];
int numMatches = 0;
indices[0] = -1;
indices[1] = -1;
indices[2] = -1;
for ( i = 0; i < 3; i++ )
{
numMatches = 0;
matches[i][0] = -1;
matches[i][1] = -1;
matches[i][2] = -1;
for ( t = 0; t < pSurfData->header.numVerts; t++ )
{
if ( !VectorCompare( pTri->verts[i], pSurfData->baseVertexes[t].xyz ) )
continue;
/*
if ( !VectorCompare( pTri->normals[i], pSurfData->baseVertexes[t].normal ) )
continue;
if ( pTri->texcoords[i][0] != pSurfData->baseVertexes[t].st[0] )
continue;
if ( pTri->texcoords[i][1] != pSurfData->baseVertexes[t].st[1] )
continue;
*/
matches[i][numMatches++] = t;
}
if ( indices[i] == -1 )
{
// Error( "Could not ReindexTriangle, vertex not found" );
}
}
#if 0
for ( t = 0; t < psets[i].numtriangles; t++ )
{
int b;
bTri = &g_data.surfData[i].baseTriangles[t];
for (j=0 ; j<3 ; j++)
{
bVert = &bTri->v[j];
// get the xyz index
for ( k = 0; k < g_data.surfData[i].header.numVerts; k++ )
{
if ( ( g_data.surfData[i].baseVertexes[k].st[0] == bVert->st[0] ) &&
( g_data.surfData[i].baseVertexes[k].st[1] == bVert->st[1] ) &&
( VectorCompare (bVert->xyz, g_data.surfData[i].baseVertexes[k].xyz) ) &&
( VectorCompare (bVert->normal, g_data.surfData[i].baseVertexes[k].normal) ) )
{
break; // this vertex is already in the base vertex list
}
}
if (k == g_data.surfData[i].header.numVerts) { // new index
g_data.surfData[i].baseVertexes[g_data.surfData[i].header.numVerts] = *bVert;
g_data.surfData[i].header.numVerts++;
}
bVert->index = k;
}
}
#endif
}
const char *FindFrameFile (const char *frame)
{
int time1;
char file1[1024];
static char retname[1024];
char base[32];
char suffix[32];
const char *s;
if (strstr (frame, "."))
return frame; // allready in dot format
// split 'run1' into 'run' and '1'
s = frame + strlen(frame)-1;
while (s != frame && *s >= '0' && *s <= '9')
s--;
strcpy (suffix, s+1);
strcpy (base, frame);
base[s-frame+1] = 0;
// check for 'run1.tri'
sprintf (file1, "%s/%s%s.tri", g_cddir, base, suffix);
time1 = FileTime (file1);
if (time1 != -1)
{
sprintf (retname, "%s%s.tri", base, suffix);
return retname;
}
// check for 'run.1'
sprintf (file1, "%s/%s.%s",g_cddir, base, suffix);
time1 = FileTime (file1);
if (time1 != -1)
{
sprintf (retname, "%s.%s", base, suffix);
return retname;
}
Error ("frame %s could not be found",frame);
return NULL;
}
#endif

View File

@@ -0,0 +1,345 @@
/*
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 "p3dlib.h"
#ifdef WIN32
#include <io.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define MAX_POLYSETS 64
#if defined (__linux__) || defined (__APPLE__)
#define _strcmpi Q_stricmp
#define filelength Q_filelength
#define strlwr strlower
#endif
typedef struct
{
long len;
int numPairs;
char polysetNames[MAX_POLYSETS][256];
char shaders[MAX_POLYSETS][256];
char *buffer, *curpos;
} p3d_t;
static p3d_t p3d;
static int P3DProcess();
static int P3DGetToken( int restOfLine );
static char s_token[1024];
static int s_curpair;
/*
** P3DLoad
**
*/
int P3DLoad( const char *filename )
{
FILE *fp = fopen( filename, "rb" );
if ( !fp )
return 0;
memset( &p3d, 0, sizeof( p3d ) );
p3d.len = filelength( fileno( fp ) );
p3d.curpos = p3d.buffer = malloc( p3d.len );
if ( fread( p3d.buffer, p3d.len, 1, fp ) != 1 )
{
fclose( fp );
return 0;
}
fclose( fp );
return P3DProcess();
}
/*
** P3DClose
**
*/
void P3DClose()
{
if ( p3d.buffer )
{
free( p3d.buffer );
p3d.buffer = 0;
}
}
int CharIsTokenDelimiter( int ch )
{
if ( ch <= 32 )
return 1;
return 0;
}
int P3DSkipToToken( const char *name )
{
while ( P3DGetToken( 0 ) )
{
if ( !_strcmpi( s_token, name ) )
return 1;
}
return 0;
}
/*
** P3DGetToken
**
*/
int P3DGetToken( int restOfLine )
{
int i = 0;
if ( p3d.buffer == 0 )
return 0;
if ( ( p3d.curpos - p3d.buffer ) == p3d.len )
return 0;
// skip over crap
while ( ( ( p3d.curpos - p3d.buffer ) < p3d.len ) &&
( *p3d.curpos <= 32 ) )
{
p3d.curpos++;
}
while ( ( p3d.curpos - p3d.buffer ) < p3d.len )
{
s_token[i] = *p3d.curpos;
p3d.curpos++;
i++;
if ( ( CharIsTokenDelimiter( s_token[i-1] ) && !restOfLine ) ||
( ( s_token[i-1] == '\n' ) ) )
{
s_token[i-1] = 0;
break;
}
}
s_token[i] = 0;
return 1;
}
int P3DGetNextPair( char **psetName, char **associatedShader )
{
if ( s_curpair < p3d.numPairs )
{
*psetName = p3d.polysetNames[s_curpair];
*associatedShader = p3d.shaders[s_curpair];
s_curpair++;
return 1;
}
return 0;
}
int P3DSkipToTokenInBlock( const char *name )
{
int iLevel = 0;
while ( P3DGetToken( 0 ) )
{
if ( !_strcmpi( s_token, "}" ) )
iLevel--;
else if ( !_strcmpi( s_token, "{" ) )
iLevel++;
if ( !_strcmpi( s_token, name ) )
return 1;
if ( iLevel == 0 )
{
return 0;
}
}
return 0;
}
/*
** P3DProcess
**
** Nothing fancy here.
*/
int P3DProcess()
{
s_curpair = 0;
// first token should be a string
P3DGetToken( 1 ); // Voodoo Ascii File
// skip to the first Obj declaration
while ( P3DGetToken( 0 ) )
{
if ( !_strcmpi( s_token, "Obj" ) )
{
int j = 0, k = 0;
if ( P3DSkipToToken( "Text" ) )
{
if ( P3DSkipToTokenInBlock( "TMap" ) )
{
char *p;
if ( !P3DSkipToToken( "Path" ) )
return 0;
if ( !P3DGetToken( 1 ) )
return 0;
while ( s_token[j] != 0 )
{
if ( s_token[j] == '\\' )
{
j++;
p3d.shaders[p3d.numPairs][k] = '/';
}
else
{
p3d.shaders[p3d.numPairs][k] = s_token[j];
}
j++;
k++;
}
p3d.shaders[p3d.numPairs][k] = 0;
//
// strip off any explicit extensions
//
if ( ( p = strrchr( p3d.shaders[p3d.numPairs], '/' ) ) != 0 )
{
while ( *p )
{
if ( *p == '.' )
{
*p = 0;
break;
}
p++;
}
}
//
// skip to the end of the Object and grab its name
//
if ( !P3DSkipToToken( "Name" ) )
return 0;
if ( P3DGetToken( 0 ) )
{
// strip off leading 'Obj_' if it exists
if ( strstr( s_token, "Obj_" ) == s_token )
strcpy( p3d.polysetNames[p3d.numPairs], s_token + strlen( "Obj_" ) );
else
strcpy( p3d.polysetNames[p3d.numPairs], s_token );
// strip off trailing unused color information
// if ( strrchr( p3d.polysetNames[p3d.numPairs], '_' ) != 0 )
// *strrchr( p3d.polysetNames[p3d.numPairs], '_' ) = 0;
p3d.numPairs++;
}
else
{
return 0;
}
}
}
}
}
s_curpair = 0;
return 1;
}
#if 0
void SkinFromP3D( const char *file )
{
char filename[1024];
char *psetName, *associatedShader;
/*
** a P3D file contains a list of polysets, each with a list of associated
** texture names that constitute it's
**
** Thus:
**
** P3D file -> skin
** polyset -> polyset
** texture -> texture.SHADER becomes polyset's shader
*/
sprintf( filename, "%s/%s", g_cddir, file );
if ( !P3DLoad( filename ) )
Error( "unable to load '%s'", filename );
while ( P3DGetNextPair( &psetName, &associatedShader ) )
{
int i;
// find the polyset in the object that this particular pset/shader pair
// corresponds to and append the shader to it
for ( i = 0; i < g_data.model.numSurfaces; i++ )
{
if ( !_strcmpi( g_data.surfData[i].header.name, psetName) )
{
char *p;
if ( strstr( associatedShader, gamedir + 1 ) )
{
p = strstr( associatedShader, gamedir + 1 ) + strlen( gamedir ) - 1;
}
else
{
p = associatedShader;
}
strcpy( g_data.surfData[i].shaders[g_data.surfData[i].header.numShaders].name, p );
g_data.surfData[i].header.numShaders++;
}
}
}
P3DClose();
}
#endif

View File

@@ -0,0 +1,29 @@
/*
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
*/
#define P3D_GET_CROSSLINE 1
#define P3D_GET_RESTOFLINE 2
int P3DLoad( const char *filename );
void P3DClose();
int P3DGetNextPair( char **name, char **associatedShader );

View File

@@ -0,0 +1,273 @@
/*
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 <assert.h>
#include "q3data.h"
polyset_t *Polyset_SplitSets( polyset_t *psets, int numpolysets, int *pNumNewPolysets, int maxTris )
{
int p, np, op;
int numNewPolysets = 0;
int numSplitPolysets = 0;
polyset_t *newpsets;
int sumTriangles = 0;
for ( p = 0; p < numpolysets; p++ )
{
numNewPolysets += psets[p].numtriangles / maxTris + 1;
}
if ( numNewPolysets == numpolysets )
return psets;
printf( "Warning: creating %d polysets from input of %d polysets\n", numNewPolysets, numpolysets );
newpsets = calloc( sizeof( polyset_t ) * numNewPolysets, 1 );
for ( np = 0, op = 0; op < numpolysets; op++ )
{
numSplitPolysets = ( psets[op].numtriangles / ( maxTris + 1 ) ) + 1;
if ( numSplitPolysets == 1 )
{
memcpy( &newpsets[np], &psets[op], sizeof( polyset_t ) );
np++;
}
else
{
sumTriangles = 0;
// split this pset into multiple smaller psets
for ( p = 0; p < numSplitPolysets; p++, np++ )
{
memcpy( &newpsets[np], &psets[op], sizeof( polyset_t ) );
newpsets[np].triangles = psets[op].triangles + sumTriangles;
if ( sumTriangles + maxTris > psets[op].numtriangles )
newpsets[np].numtriangles = psets[op].numtriangles - sumTriangles;
else
newpsets[np].numtriangles = maxTris;
sumTriangles += newpsets[np].numtriangles;
}
}
}
*pNumNewPolysets = numNewPolysets;
return newpsets;
}
polyset_t *Polyset_LoadSets( const char *file, int *numpolysets, int maxTrisPerSet )
{
polyset_t *psets;
polyset_t *finalpsets;
//
// load the frame
//
if ( strstr( file, ".3DS" ) || strstr( file, ".3ds" ) )
_3DS_LoadPolysets( file, &psets, numpolysets, g_verbose );
else
Error( "TRI files no longer supported" );
// TRI_LoadPolysets( file, &psets, numpolysets );
/*
//
// scale polysets
//
for ( i = 0; i < psets; i++ )
{
int j;
for ( j = 0; j < psets[i].numtriangles; j++ )
{
}
}
*/
//
// split polysets if necessary
//
finalpsets = Polyset_SplitSets( psets, *numpolysets, numpolysets, maxTrisPerSet );
return finalpsets;
}
polyset_t *Polyset_CollapseSets( polyset_t *psets, int numpolysets )
{
int p;
int sumtriangles = 0;
polyset_t *oldpsets = psets;
//
// no tag checking because this is an $oldbase and thus shouldn't have any
// tags
//
for ( p = 0; p < numpolysets; p++ )
{
sumtriangles += oldpsets[p].numtriangles;
}
psets = calloc( 1, sizeof( polyset_t ) );
psets[0].numtriangles = sumtriangles;
psets[0].triangles = malloc( MD3_MAX_TRIANGLES * sizeof( triangle_t ) );
// each call to "LoadPolysets" only allocates a single large chunk of
// triangle memory that is utilized by all the polysets loaded by
// that one call
memcpy( psets[0].triangles, oldpsets[0].triangles, sizeof( triangle_t ) * sumtriangles );
free( oldpsets[0].triangles );
free( oldpsets );
return psets;
}
static float SnapFloat( float x )
{
int ix;
x *= 1.0f / MD3_XYZ_SCALE;
ix = ( int ) x;
x = ( float ) ix;
x *= MD3_XYZ_SCALE;
return x;
}
void Polyset_SnapSets( polyset_t *psets, int numpolysets )
{
int p;
for ( p = 0; p < numpolysets; p++ )
{
int t;
for ( t = 0; t < psets[p].numtriangles; t++ )
{
int v;
for ( v = 0; v < 3; v++ )
{
psets[p].triangles[t].verts[v][0] = SnapFloat( psets[p].triangles[t].verts[v][0] );
psets[p].triangles[t].verts[v][1] = SnapFloat( psets[p].triangles[t].verts[v][1] );
psets[p].triangles[t].verts[v][2] = SnapFloat( psets[p].triangles[t].verts[v][2] );
}
}
}
}
void Polyset_ComputeNormals( polyset_t *psets, int numpolysets )
{
int p;
int i, t;
int vertexIndex[MD3_MAX_TRIANGLES][3];
vec3_t verts[MD3_MAX_VERTS];
vec3_t normals[MD3_MAX_VERTS];
vec3_t faceNormals[MD3_MAX_TRIANGLES];
//
// iterate through polysets
//
for ( p = 0; p < numpolysets; p++ )
{
int numUniqueVertices = 0;
assert( psets[p].numtriangles < MD3_MAX_TRIANGLES );
memset( vertexIndex, 0xff, sizeof( vertexIndex ) );
memset( verts, 0, sizeof( verts ) );
memset( normals, 0, sizeof( normals ) );
//
// unique vertices
//
for ( t = 0; t < psets[p].numtriangles; t++ )
{
int j;
for ( j = 0; j < 3; j++ )
{
for ( i = 0; i < numUniqueVertices; i++ )
{
if ( VectorCompare( psets[p].triangles[t].verts[j], verts[i] ) )
{
break;
}
}
if ( i == numUniqueVertices )
{
vertexIndex[t][j] = numUniqueVertices;
VectorCopy( (psets[p].triangles[t].verts[j]), (verts[numUniqueVertices]) );
numUniqueVertices++;
}
else
{
vertexIndex[t][j] = i;
}
}
}
//
// compute face normals
//
for ( t = 0; t < psets[p].numtriangles; t++ )
{
vec3_t side0, side1, facenormal;
VectorSubtract( psets[p].triangles[t].verts[0], psets[p].triangles[t].verts[1], side0 );
VectorSubtract( psets[p].triangles[t].verts[2], psets[p].triangles[t].verts[1], side1);
CrossProduct( side0, side1, facenormal );
VectorNormalize( facenormal, faceNormals[t] );
}
//
// sum normals and copy them back
//
for ( i = 0; i < numUniqueVertices; i++ )
{
for ( t = 0; t < psets[p].numtriangles; t++ )
{
if ( vertexIndex[t][0] == i ||
vertexIndex[t][1] == i ||
vertexIndex[t][2] == i )
{
normals[i][0] += faceNormals[t][0];
normals[i][1] += faceNormals[t][1];
normals[i][2] += faceNormals[t][2];
}
}
VectorNormalize( normals[i], normals[i] );
}
for ( t = 0; t < psets[p].numtriangles; t++ )
{
VectorCopy( normals[vertexIndex[t][0]], psets[p].triangles[t].normals[0] );
VectorCopy( normals[vertexIndex[t][1]], psets[p].triangles[t].normals[1] );
VectorCopy( normals[vertexIndex[t][2]], psets[p].triangles[t].normals[2] );
}
}
}

View File

@@ -0,0 +1,666 @@
/*
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
*/
#ifdef WIN32
#include <io.h>
#endif
#include "q3data.h"
#include "md3lib.h"
#include "vfs.h"
qboolean g_verbose;
qboolean g_stripify = qtrue;
qboolean g_release; // don't grab, copy output data to new tree
char g_releasedir[1024]; // c:\quake2\baseq2, etc
qboolean g_archive; // don't grab, copy source data to new tree
char g_only[256]; // if set, only grab this cd
qboolean g_skipmodel; // set true when a cd is not g_only
// bogus externs for some TA hacks (common/ using them against q3map)
char *moddir = NULL;
// some old defined that was in cmdlib lost during merge
char writedir[1024];
#if defined (__linux__) || defined (__APPLE__)
#define strlwr strlower
#endif
/*
=======================================================
PAK FILES
=======================================================
*/
unsigned Com_BlockChecksum (void *buffer, int length);
typedef struct
{
char name[56];
int filepos, filelen;
} packfile_t;
typedef struct
{
char id[4];
int dirofs;
int dirlen;
} packheader_t;
packfile_t pfiles[16384];
FILE *pakfile;
packfile_t *pf;
packheader_t pakheader;
/*
==============
ReleaseFile
Filename should be gamedir reletive.
Either copies the file to the release dir, or adds it to
the pak file.
==============
*/
void ReleaseFile (char *filename)
{
char source[1024];
char dest[1024];
if (!g_release)
return;
sprintf (source, "%s%s", gamedir, filename);
sprintf (dest, "%s/%s", g_releasedir, filename);
printf ("copying to %s\n", dest);
QCopyFile (source, dest);
return;
}
typedef struct
{
// shader
// opaque
// opaque 2
// blend
// blend 2
char names[5][1024];
int num;
} ShaderFiles_t;
ShaderFiles_t s_shaderFiles;
void FindShaderFiles( char *filename )
{
char buffer[1024];
char stripped[1024];
char linebuffer[1024];
int len, i;
char *buf;
char *diffuseExtensions[] =
{
".TGA",
".WAL",
".PCX",
0
};
char *otherExtensions[] =
{
".specular.TGA",
".blend.TGA",
".alpha.TGA",
0
};
s_shaderFiles.num = 0;
strcpy( stripped, filename );
if ( strrchr( stripped, '.' ) )
*strrchr( stripped, '.' ) = 0;
strcat( stripped, ".shader" );
if ( FileExists( stripped ) )
{
char *p;
char mapa[512], mapb[512];
strcpy( s_shaderFiles.names[s_shaderFiles.num], stripped );
s_shaderFiles.num++;
// load and parse
len = LoadFile( stripped, (void **)&buf);
p = buf;
while ( p - buf < len )
{
i = 0;
// skip spaces
while ( *p == ' ' || *p == '\n' || *p == '\t' )
p++;
// grab rest of the line
while ( *p != 0 && *p != '\n' )
{
linebuffer[i] = *p;
i++;
p++;
}
if ( *p == '\n' )
p++;
linebuffer[i] = 0;
strlwr( linebuffer );
// see if the line specifies an opaque map or blendmap
if ( strstr( linebuffer, "opaquemap" ) == linebuffer ||
strstr( linebuffer, "blendmap" ) == linebuffer )
{
int j;
i = 0;
mapa[0] = mapb[0] = 0;
// skip past the keyword
while ( linebuffer[i] != ' ' && linebuffer[i] != '\t' && linebuffer[i] )
i++;
// skip past spaces
while ( ( linebuffer[i] == ' ' || linebuffer[i] == '\t' ) && linebuffer[i] )
i++;
// grab first map name
j = 0;
while ( linebuffer[i] != ' ' && linebuffer[i] != '\t' && linebuffer[i] )
{
mapa[j] = linebuffer[i];
j++;
i++;
}
mapa[j] = 0;
// skip past spaces
while ( ( linebuffer[i] == ' ' || linebuffer[i] == '\t' ) && linebuffer[i] )
i++;
// grab second map name
j = 0;
while ( linebuffer[i] != ' ' && linebuffer[i] != '\t' && linebuffer[i] )
{
mapb[j] = linebuffer[i];
j++;
i++;
}
mapb[j] = 0;
// store map names
if ( mapa[0] != 0 && mapa[0] != '-' )
{
sprintf( s_shaderFiles.names[s_shaderFiles.num], "%s%s", gamedir, mapa );
s_shaderFiles.num++;
}
if ( mapb[0] != 0 && mapb[0] != '-' && mapb[0] != '^' && mapb[0] != '*' )
{
sprintf( s_shaderFiles.names[s_shaderFiles.num], "%s%s", gamedir, mapb );
s_shaderFiles.num++;
}
}
}
}
else
{
if ( strrchr( stripped, '.' ) )
*strrchr( stripped, '.' ) = 0;
// look for diffuse maps
for ( i = 0; i < 3; i++ )
{
strcpy( buffer, stripped );
strcat( buffer, diffuseExtensions[i] );
if ( FileExists( buffer ) )
{
strcpy( s_shaderFiles.names[s_shaderFiles.num], buffer );
s_shaderFiles.num++;
break;
}
}
for ( i = 0; i < 3; i++ )
{
strcpy( buffer, stripped );
strcat( buffer, otherExtensions[i] );
if ( FileExists( buffer ) )
{
strcpy( s_shaderFiles.names[s_shaderFiles.num], buffer );
s_shaderFiles.num++;
}
}
}
}
/*
==============
ReleaseShader
Copies all needed files for a shader to the release directory
==============
*/
void ReleaseShader( char *filename )
{
char fullpath[1024];
char dest[1024];
char stripped[1024];
int i;
sprintf( fullpath, "%s%s", gamedir, filename );
FindShaderFiles( fullpath );
for ( i = 0; i < s_shaderFiles.num; i++ )
{
strcpy( stripped, s_shaderFiles.names[i] );
if ( strstr( stripped, gamedir ) )
{
memmove( stripped, stripped+ strlen( gamedir ), strlen( stripped ) );
}
sprintf( dest, "%s/%s", g_releasedir, stripped );
printf ("copying to %s\n", dest );
QCopyFile( s_shaderFiles.names[i], dest );
}
}
/*
===============
Cmd_File
This is only used to cause a file to be copied during a release
build (default.cfg, maps, etc)
===============
*/
void Cmd_File (void)
{
GetToken (qfalse);
ReleaseFile (token);
}
/*
===============
PackDirectory_r
===============
*/
#ifdef _WIN32
#include "io.h"
void PackDirectory_r (char *dir)
{
struct _finddata_t fileinfo;
int handle;
char dirstring[1024];
char filename[1024];
sprintf (dirstring, "%s%s/*.*", gamedir, dir);
handle = _findfirst (dirstring, &fileinfo);
if (handle == -1)
return;
do
{
sprintf (filename, "%s/%s", dir, fileinfo.name);
if (fileinfo.attrib & _A_SUBDIR)
{ // directory
if (fileinfo.name[0] != '.') // don't pak . and ..
PackDirectory_r (filename);
continue;
}
// copy or pack the file
ReleaseFile (filename);
} while (_findnext( handle, &fileinfo ) != -1);
_findclose (handle);
}
#else
#include <sys/types.h>
#ifndef WIN32
#include <sys/dir.h>
#else
#include <sys/dirent.h>
#endif
void PackDirectory_r (char *dir)
{
#ifdef NeXT
struct direct **namelist, *ent;
#else
struct dirent **namelist, *ent;
#endif
int count;
struct stat st;
int i;
int len;
char fullname[1024];
char dirstring[1024];
char *name;
sprintf (dirstring, "%s%s", gamedir, dir);
count = scandir(dirstring, &namelist, NULL, NULL);
for (i=0 ; i<count ; i++)
{
ent = namelist[i];
name = ent->d_name;
if (name[0] == '.')
continue;
sprintf (fullname, "%s/%s", dir, name);
sprintf (dirstring, "%s%s/%s", gamedir, dir, name);
if (stat (dirstring, &st) == -1)
Error ("fstating %s", pf->name);
if (st.st_mode & S_IFDIR)
{ // directory
PackDirectory_r (fullname);
continue;
}
// copy or pack the file
ReleaseFile (fullname);
}
}
#endif
/*
===============
Cmd_Dir
This is only used to cause a directory to be copied during a
release build (sounds, etc)
===============
*/
void Cmd_Dir (void)
{
GetToken (qfalse);
PackDirectory_r (token);
}
//========================================================================
#define MAX_RTEX 16384
int numrtex;
char rtex[MAX_RTEX][64];
void ReleaseTexture (char *name)
{
int i;
char path[1024];
for (i=0 ; i<numrtex ; i++)
if (!Q_stricmp(name, rtex[i]))
return;
if (numrtex == MAX_RTEX)
Error ("numrtex == MAX_RTEX");
strcpy (rtex[i], name);
numrtex++;
sprintf (path, "textures/%s.wal", name);
ReleaseFile (path);
}
/*
===============
Cmd_Maps
Only relevent for release and pak files.
Releases the .bsp files for the maps, and scans all of the files to
build a list of all textures used, which are then released.
===============
*/
void Cmd_Maps (void)
{
char map[1024];
while (TokenAvailable ())
{
GetToken (qfalse);
sprintf (map, "maps/%s.bsp", token);
ReleaseFile (map);
if (!g_release)
continue;
// get all the texture references
sprintf (map, "%smaps/%s.bsp", gamedir, token);
LoadBSPFile( map );
}
}
//==============================================================
/*
===============
ParseScript
===============
*/
void ParseScript (void)
{
while (1)
{
do
{ // look for a line starting with a $ command
GetToken (qtrue);
if (endofscript)
return;
if (token[0] == '$')
break;
while (TokenAvailable())
GetToken (qfalse);
} while (1);
//
// model commands
//
if (!strcmp (token, "$modelname"))
Cmd_Modelname ();
else if (!strcmp (token, "$base"))
Cmd_Base ();
else if ( !strcmp( token, "$exit" ) )
break;
else if ( !strcmp( token, "$3dsconvert" ) )
Cmd_3DSConvert();
else if (!strcmp (token, "$spritebase"))
Cmd_SpriteBase ();
else if (!strcmp (token, "$cd"))
Cmd_Cd ();
else if (!strcmp (token, "$origin"))
Cmd_Origin ();
else if (!strcmp (token, "$scale"))
Cmd_ScaleUp ();
else if (!strcmp (token, "$frame"))
Cmd_Frame ();
else if (!strcmp (token, "$skin" ))
Cmd_Skin();
else if (!strcmp (token, "$spriteshader"))
Cmd_SpriteShader();
else if (!strcmp( token, "$aseconvert" ))
Cmd_ASEConvert( qfalse );
else if (!strcmp( token, "$aseanimconvert" ) )
Cmd_ASEConvert( qtrue );
//
// image commands
//
else if (!strcmp (token, "$grab"))
Cmd_Grab ();
else if (!strcmp (token, "$raw"))
Cmd_Raw ();
else if (!strcmp (token, "$colormap"))
Cmd_Colormap ();
else if (!strcmp (token, "$environment"))
Cmd_Environment ();
//
// video
//
else if (!strcmp (token, "$video"))
Cmd_Video ();
//
// misc
//
else if (!strcmp (token, "$file"))
Cmd_File ();
else if (!strcmp (token, "$dir"))
Cmd_Dir ();
else if (!strcmp (token, "$maps"))
Cmd_Maps ();
else
Error ("bad command %s\n", token);
}
}
//=======================================================
#include "version.h"
/*
==============
main
==============
*/
int main (int argc, char **argv)
{
static int i; // VC4.2 compiler bug if auto...
char path[1024];
// using GtkRadiant's versioning next to Id's versioning
printf ("Q3Data - (c) 1999 Id Software Inc.\n");
printf ("GtkRadiant - v" RADIANT_VERSION " " __DATE__ "\n");
ExpandWildcards (&argc, &argv);
for (i=1 ; i<argc ; i++)
{
if (!strcmp(argv[i], "-archive"))
{
archive = qtrue;
strcpy (archivedir, argv[i+1]);
printf ("Archiving source to: %s\n", archivedir);
i++;
}
else if (!strcmp(argv[i], "-release"))
{
g_release = qtrue;
strcpy (g_releasedir, argv[i+1]);
printf ("Copy output to: %s\n", g_releasedir);
i++;
}
else if ( !strcmp( argv[i], "-nostrips" ) )
{
g_stripify = qfalse;
printf( "Not optimizing for strips\n" );
}
else if ( !strcmp( argv[i], "-writedir" ) )
{
strcpy( writedir, argv[i+1] );
printf( "Write output to: %s\n", writedir );
i++;
}
else if ( !strcmp( argv[i], "-verbose" ) )
{
g_verbose = qtrue;
}
else if ( !strcmp( argv[i], "-dump" ) )
{
printf( "Dumping contents of: '%s'\n", argv[i+1] );
if ( strstr( argv[i+1], ".md3" ) )
{
MD3_Dump( argv[i+1] );
}
else
{
Error( "Do not know how to dump the contents of '%s'\n", argv[i+1] );
}
i++;
}
else if ( !strcmp( argv[i], "-3dsconvert" ) )
{
// NOTE TTimo this is broken, tried on a sample .3ds
// what happens .. it calls the Convert3DStoMD3,
// which calls the scriptlib function in non initialized state .. and crashes
printf( "Converting %s.3DS to %s.MD3\n", argv[i+1], argv[i+1] );
SetQdirFromPath( argv[i+1] );
vfsInitDirectory( gamedir );
Convert3DStoMD3( argv[i+1] );
i++;
}
else if (!strcmp(argv[i], "-only"))
{
strcpy (g_only, argv[i+1]);
printf ("Only grabbing %s\n", g_only);
i++;
}
else if (!strcmp(argv[i], "-gamedir"))
{
strcpy(gamedir, argv[i+1]);
i++;
}
else if (argv[i][0] == '-')
Error ("Unknown option \"%s\"", argv[i]);
else
break;
}
if (i == argc)
Error ("usage: q3data [-archive <directory>] [-dump <file.md3>] [-release <directory>] [-only <model>] [-3dsconvert <file.3ds>] [-verbose] [file.qdt]");
for ( ; i<argc ; i++)
{
printf ("--------------- %s ---------------\n", argv[i]);
// load the script
strcpy (path, argv[i]);
DefaultExtension (path, ".qdt");
if(!gamedir[0])
SetQdirFromPath (path);
// NOTE TTimo
// q3data went through a partial conversion to use the vfs
// it was never actually tested before 1.1.1
// the code is still mostly using direct file access calls
vfsInitDirectory( gamedir );
LoadScriptFile (ExpandArg(path), -1);
//
// parse it
//
ParseScript ();
// write out the last model
FinishModel ( TYPE_UNKNOWN );
}
return 0;
}

View File

@@ -0,0 +1,200 @@
# Microsoft Developer Studio Project File - Name="q3data" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
CFG=q3data - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "q3data.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "q3data.mak" CFG="q3data - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "q3data - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "q3data - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName "q3data"
# PROP Scc_LocalPath ".."
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "q3data - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
F90=df.exe
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\common" /I "..\..\..\..\libxml2\include" /I "..\..\..\libs" /I "..\..\..\..\gtk2-win32\include\glib-2.0" /I "..\..\..\..\gtk2-win32\lib\glib-2.0\include" /I "..\..\..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 glib-2.0.lib l_net.lib wsock32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /stack:0xf42400 /subsystem:console /debug /machine:I386 /libpath:"..\..\..\libs\pak\release" /libpath:"..\..\..\libs\l_net\release" /libpath:"..\..\..\..\gtk2-win32\lib\\"
# SUBTRACT LINK32 /pdb:none
!ELSEIF "$(CFG)" == "q3data - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
F90=df.exe
# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /MDd /W3 /Gm /ZI /Od /I "..\common" /I "..\..\..\..\libxml2\include" /I "..\..\..\libs" /I "..\..\..\..\gtk2-win32\include\glib-2.0" /I "..\..\..\..\gtk2-win32\lib\glib-2.0\include" /I "..\..\..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# ADD LINK32 glib-2.0.lib l_net.lib wsock32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /stack:0xf42400 /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\..\..\libs\l_net\Debug" /libpath:"..\..\..\libs\pak\Debug" /libpath:"..\..\..\..\gtk2-win32\lib\\"
# SUBTRACT LINK32 /pdb:none
!ENDIF
# Begin Target
# Name "q3data - Win32 Release"
# Name "q3data - Win32 Debug"
# Begin Source File
SOURCE=.\3dslib.c
# End Source File
# Begin Source File
SOURCE=.\3dslib.h
# End Source File
# Begin Source File
SOURCE=..\common\aselib.c
# End Source File
# Begin Source File
SOURCE=..\common\aselib.h
# End Source File
# Begin Source File
SOURCE=..\common\bspfile.c
# End Source File
# Begin Source File
SOURCE=..\common\cmdlib.c
# End Source File
# Begin Source File
SOURCE=.\compress.c
# End Source File
# Begin Source File
SOURCE=..\common\imagelib.c
# End Source File
# Begin Source File
SOURCE=.\images.c
# End Source File
# Begin Source File
SOURCE=..\common\inout.c
# End Source File
# Begin Source File
SOURCE=.\md3lib.c
# End Source File
# Begin Source File
SOURCE=.\md3lib.h
# End Source File
# Begin Source File
SOURCE=..\common\md4.c
# End Source File
# Begin Source File
SOURCE=.\models.c
# End Source File
# Begin Source File
SOURCE=.\p3dlib.c
# End Source File
# Begin Source File
SOURCE=.\p3dlib.h
# End Source File
# Begin Source File
SOURCE=.\polyset.c
# End Source File
# Begin Source File
SOURCE=..\common\polyset.h
# End Source File
# Begin Source File
SOURCE=.\q3data.c
# End Source File
# Begin Source File
SOURCE=.\q3data.h
# End Source File
# Begin Source File
SOURCE=..\common\scriplib.c
# End Source File
# Begin Source File
SOURCE=.\stripper.c
# End Source File
# Begin Source File
SOURCE=..\common\trilib.c
# End Source File
# Begin Source File
SOURCE=..\common\unzip.c
# End Source File
# Begin Source File
SOURCE=..\common\unzip.h
# End Source File
# Begin Source File
SOURCE=..\common\vfs.c
# End Source File
# Begin Source File
SOURCE=.\video.c
# End Source File
# End Target
# End Project

View File

@@ -0,0 +1,99 @@
/*
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
*/
// q3data.h
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <sys/stat.h>
#include "../common/cmdlib.h"
#include "scriplib.h"
#include "mathlib.h"
#include "polyset.h"
#include "trilib.h"
#include "imagelib.h"
#include "qthreads.h"
#include "l3dslib.h"
#include "bspfile.h"
#include "p3dlib.h"
#include "3dslib.h"
#include "aselib.h"
#include "md3lib.h"
void Cmd_ASEConvert( qboolean grabAnims );
void Cmd_3DSConvert( void );
void Cmd_Modelname (void);
void Cmd_SpriteBase (void);
void Cmd_Base (void);
void Cmd_Cd (void);
void Cmd_Origin (void);
void Cmd_ScaleUp (void);
void Cmd_Frame (void);
void Cmd_Modelname (void);
void Cmd_SpriteShader(void);
void Cmd_Skin(void);
void Cmd_Skinsize (void);
void FinishModel (int type);
void Cmd_Grab (void);
void Cmd_Raw (void);
void Cmd_Mip (void);
void Cmd_Environment (void);
void Cmd_Colormap (void);
void Cmd_File (void);
void Cmd_Dir (void);
void Cmd_StartWad (void);
void Cmd_EndWad (void);
void Cmd_Mippal (void);
void Cmd_Mipdir (void);
void Cmd_Video (void);
void ReleaseFile (char *filename);
void ReleaseShader( char *filename );
void Convert3DStoMD3( const char *filename );
void OrderMesh( int input[][3], int output[][3], int numTris );
extern byte *byteimage, *lbmpalette;
extern int byteimagewidth, byteimageheight;
extern qboolean g_release; // don't grab, copy output data to new tree
extern char g_releasedir[1024]; // c:\quake2\baseq2, etc
extern qboolean g_archive; // don't grab, copy source data to new tree
extern qboolean do3ds;
extern char g_only[256]; // if set, only grab this cd
extern qboolean g_skipmodel; // set true when a cd is not g_only
extern qboolean g_verbose;
extern char *trifileext;
#define TYPE_ITEM 0
#define TYPE_PLAYER 1
#define TYPE_WEAPON 2
#define TYPE_HAND 3
#define TYPE_UNKNOWN 4

View File

@@ -0,0 +1,207 @@
<?xml version="1.0" encoding = "Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.00"
Name="q3data">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory=".\Debug"
IntermediateDirectory=".\Debug"
ConfigurationType="1"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="FALSE"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="..\common,..\..\..\..\libxml2\include,..\..\..\libs,..\..\..\..\gtk2-win32\include\glib-2.0,..\..\..\..\gtk2-win32\lib\glib-2.0\include,..\..\..\include"
PreprocessorDefinitions="WIN32,_DEBUG,_CONSOLE"
RuntimeLibrary="3"
PrecompiledHeaderFile=".\Debug/q3data.pch"
AssemblerListingLocation=".\Debug/"
ObjectFile=".\Debug/"
ProgramDataBaseFileName=".\Debug/"
BrowseInformation="1"
WarningLevel="3"
SuppressStartupBanner="TRUE"
DebugInformationFormat="4"
CompileAs="0"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalOptions="/MACHINE:I386"
AdditionalDependencies="glib-2.0.lib wsock32.lib libxml2.lib"
OutputFile=".\Debug/q3data.exe"
LinkIncremental="2"
SuppressStartupBanner="TRUE"
AdditionalLibraryDirectories="&quot;..\..\..\..\libxml2\win32\binaries-debug&quot;;..\..\..\libs\l_net\Debug;..\..\..\libs\pak\Debug;&quot;..\..\..\..\gtk2-win32\lib\&quot;"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile=".\Debug/q3data.pdb"
SubSystem="1"
StackReserveSize="16000000"/>
<Tool
Name="VCMIDLTool"
TypeLibraryName=".\Debug/q3data.tlb"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="_DEBUG"
Culture="1033"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory=".\Release"
IntermediateDirectory=".\Release"
ConfigurationType="1"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="FALSE"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
InlineFunctionExpansion="1"
AdditionalIncludeDirectories="..\common,..\..\..\..\libxml2\include,..\..\..\libs,..\..\..\..\gtk2-win32\include\glib-2.0,..\..\..\..\gtk2-win32\lib\glib-2.0\include,..\..\..\include"
PreprocessorDefinitions="WIN32,NDEBUG,_CONSOLE"
StringPooling="TRUE"
RuntimeLibrary="2"
EnableFunctionLevelLinking="TRUE"
PrecompiledHeaderFile=".\Release/q3data.pch"
AssemblerListingLocation=".\Release/"
ObjectFile=".\Release/"
ProgramDataBaseFileName=".\Release/"
WarningLevel="3"
SuppressStartupBanner="TRUE"
CompileAs="0"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalOptions="/MACHINE:I386"
AdditionalDependencies="glib-2.0.lib wsock32.lib libxml2.lib"
OutputFile=".\Release/q3data.exe"
LinkIncremental="1"
SuppressStartupBanner="TRUE"
AdditionalLibraryDirectories="..\..\..\libs\pak\release;..\..\..\libs\l_net\release;&quot;..\..\..\..\libxml2\win32\binaries-release&quot;;&quot;..\..\..\..\gtk2-win32\lib\&quot;"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile=".\Release/q3data.pdb"
SubSystem="1"
StackReserveSize="16000000"/>
<Tool
Name="VCMIDLTool"
TypeLibraryName=".\Release/q3data.tlb"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="NDEBUG"
Culture="1033"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
</Configuration>
</Configurations>
<Files>
<File
RelativePath=".\3dslib.c">
</File>
<File
RelativePath=".\3dslib.h">
</File>
<File
RelativePath="..\common\aselib.c">
</File>
<File
RelativePath="..\common\aselib.h">
</File>
<File
RelativePath="..\common\bspfile.c">
</File>
<File
RelativePath="..\common\cmdlib.c">
</File>
<File
RelativePath=".\compress.c">
</File>
<File
RelativePath="..\common\imagelib.c">
</File>
<File
RelativePath=".\images.c">
</File>
<File
RelativePath="..\common\inout.c">
</File>
<File
RelativePath=".\md3lib.c">
</File>
<File
RelativePath=".\md3lib.h">
</File>
<File
RelativePath="..\common\md4.c">
</File>
<File
RelativePath=".\models.c">
</File>
<File
RelativePath=".\p3dlib.c">
</File>
<File
RelativePath=".\p3dlib.h">
</File>
<File
RelativePath=".\polyset.c">
</File>
<File
RelativePath="..\common\polyset.h">
</File>
<File
RelativePath=".\q3data.c">
</File>
<File
RelativePath=".\q3data.h">
</File>
<File
RelativePath="..\common\scriplib.c">
</File>
<File
RelativePath=".\stripper.c">
</File>
<File
RelativePath="..\common\trilib.c">
</File>
<File
RelativePath="..\common\unzip.c">
</File>
<File
RelativePath="..\common\unzip.h">
</File>
<File
RelativePath="..\common\vfs.c">
</File>
<File
RelativePath=".\video.c">
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@@ -0,0 +1,303 @@
/*
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 <stdio.h>
#include <string.h>
#include <stdlib.h>
static int s_used[8192]; // same as MD3_MAX_TRIANGLES
/*
** FindNextTriangleInStrip
**
** Given a surface and triangle this tries to find the next triangle
** in the strip that would continue the strip. The next triangle in
** the strip should have the same winding as this triangle.
*/
static int FindNextTriangleInStripOrFan( int mesh[][3], int tri, int orientation, int numTris, int odd )
{
int t;
int sum = 0;
int currentTri[3];
int side;
int a, b, c;
int refa, refb;
currentTri[0] = mesh[tri][(0+orientation)%3];
currentTri[1] = mesh[tri][(1+orientation)%3];
currentTri[2] = mesh[tri][(2+orientation)%3];
if ( odd )
{
refa = currentTri[1];
refb = currentTri[2];
}
else
{
refa = currentTri[2];
refb = currentTri[0];
}
// go through all triangles and look for sides that match
// this triangle's
for ( t = 0; t < numTris; t++ )
{
// don't check against self or against previously used triangles
if ( t == tri )
continue;
if ( s_used[t] )
continue;
// check all three sides of the candidate triangle
for ( side = 0; side < 3; side++ )
{
// check only the second (abutting) side
if ( ( refa == mesh[t][(side+1)%3] ) &&
( refb == mesh[t][side] ) )
{
a = mesh[t][0];
b = mesh[t][1];
c = mesh[t][2];
// rotate the candidate triangle to align it properly in the strip
if ( side == 1 )
{
mesh[t][0] = b;
mesh[t][1] = c;
mesh[t][2] = a;
}
else if ( side == 2 )
{
mesh[t][0] = c;
mesh[t][1] = a;
mesh[t][2] = b;
}
return t;
}
/*
else
{
Error( "fans not implemented yet" );
// check only the third (abutting) side
if ( ( currentTri[2] == pSurf->baseTriangles[t].v[side].index ) &&
( currentTri[0] == pSurf->baseTriangles[t].v[(side+1)%3].index ) )
{
return t;
}
}
*/
}
}
return -1;
}
/*
** StripLength
*/
static int StripLength( int mesh[][3], int strip[][3], int tri, int orientation, int numInputTris, int fillNo )
{
int stripIndex = 0;
int next;
int odd = 1;
strip[stripIndex][0] = mesh[tri][(0+orientation)%3];
strip[stripIndex][1] = mesh[tri][(1+orientation)%3];
strip[stripIndex][2] = mesh[tri][(2+orientation)%3];
s_used[tri] = fillNo;
stripIndex++;
next = tri;
while ( ( next = FindNextTriangleInStripOrFan( mesh, next, orientation, numInputTris, odd ) ) != -1 )
{
s_used[next] = fillNo;
odd = !odd;
strip[stripIndex][0] = mesh[next][0];
strip[stripIndex][1] = mesh[next][1];
strip[stripIndex][2] = mesh[next][2];
stripIndex++;
// all iterations after first need to be with an unrotated reference triangle
orientation = 0;
}
return stripIndex;
}
/*
** BuildOptimizedList
**
** Attempts to build the longest strip/fan possible. Does not adhere
** to pure strip or fan, will intermix between the two so long as some
** type of connectivity can be maintained.
*/
#define MAX_ORIENTATIONS 3
#define MAX_MATCHED_SIDES 4
#define MAX_SEED_TRIANGLES 16
static int BuildOptimizedList( int mesh[][3], int strip[][3], int numInputTris )
{
int t;
int stripLen = 0;
int startTri = -1;
int bestTri = -1, bestLength = 0, bestOrientation = -1;
int matchedSides = 0;
int orientation = 0;
int seedTriangles[MAX_MATCHED_SIDES][MAX_SEED_TRIANGLES];
int seedLengths[MAX_ORIENTATIONS][MAX_MATCHED_SIDES][MAX_SEED_TRIANGLES];
int numSeeds[MAX_MATCHED_SIDES] = { 0, 0, 0 };
int i;
// build a ranked list of candidate seed triangles based on
// number of offshoot strips. Precedence goes to orphans,
// then corners, then edges, and interiors.
memset( seedTriangles, 0xff, sizeof( seedTriangles ) );
memset( seedLengths, 0xff, sizeof( seedLengths ) );
for ( i = 0; i < MAX_MATCHED_SIDES; i++ )
{
// find the triangle with lowest number of child strips
for ( t = 0; t < numInputTris; t++ )
{
int orientation;
int n;
if ( s_used[t] )
continue;
// try the candidate triangle in three different orientations
matchedSides = 0;
for ( orientation = 0; orientation < 3; orientation++ )
{
if ( ( n = FindNextTriangleInStripOrFan( mesh, t, orientation, numInputTris, 1 ) ) != -1 )
{
matchedSides++;
}
}
if ( matchedSides == i )
{
seedTriangles[i][numSeeds[i]] = t;
numSeeds[i]++;
if ( numSeeds[i] == MAX_SEED_TRIANGLES )
break;
}
}
}
// we have a list of potential seed triangles, so we now go through each
// potential candidate and look to see which produces the longest strip
// and select our startTri based on this
for ( i = 0; i < MAX_MATCHED_SIDES; i++ )
{
int j;
for ( j = 0; j < numSeeds[i]; j++ )
{
for ( orientation = 0; orientation < 3; orientation++ )
{
int k;
seedLengths[orientation][i][j] = StripLength( mesh, strip, seedTriangles[i][j], orientation, numInputTris, 2 );
if ( seedLengths[orientation][i][j] > bestLength )
{
bestTri = seedTriangles[i][j];
bestLength = seedLengths[orientation][i][j];
bestOrientation = orientation;
}
for ( k = 0; k < numInputTris; k++ )
{
if ( s_used[k] == 2 )
s_used[k] = 0;
}
}
}
if ( bestTri != -1 )
{
break;
}
}
// build the strip for real
if ( bestTri != -1 )
{
stripLen = StripLength( mesh, strip, bestTri, bestOrientation, numInputTris, 1 );
}
return stripLen;
}
/*
** OrderMesh
**
** Given an input mesh and an output mesh, this routine will reorder
** the triangles within the mesh into strips/fans.
*/
void OrderMesh( int input[][3], int output[][3], int numTris )
{
int i;
int sumStrippedTriangles = 0;
int strippedTriangles;
int totalStrips = 0;
int strip[8192][3]; // could dump directly into 'output', but
// this helps with debugging
memset( s_used, 0, sizeof( s_used ) );
#if 0
FILE *fp = fopen( "strip.txt", "wt" );
for ( i = 0; i < numTris; i++ )
{
fprintf( fp, "%4d: %3d %3d %3d\n", i, input[i][0], input[i][1], input[i][2] );
}
fclose( fp );
#endif
// while there are still triangles that are not part of a strip
while ( sumStrippedTriangles < numTris )
{
// build a strip
strippedTriangles = BuildOptimizedList( input, strip, numTris );
for ( i = 0; i < strippedTriangles; i++ )
{
output[sumStrippedTriangles+i][0] = strip[i][0];
output[sumStrippedTriangles+i][1] = strip[i][1];
output[sumStrippedTriangles+i][2] = strip[i][2];
}
sumStrippedTriangles += strippedTriangles;
totalStrips++;
}
printf( "Triangles on surface: %d\n", sumStrippedTriangles );
printf( "Total strips from surface: %d\n", totalStrips );
printf( "Average strip length: %f\n", ( float ) sumStrippedTriangles / totalStrips );
}

1153
tools/quake3/q3data/video.c Normal file

File diff suppressed because it is too large Load Diff