356 lines
10 KiB
C
356 lines
10 KiB
C
|
/* -------------------------------------------------------------------------------
|
||
|
|
||
|
Copyright (C) 1999-2007 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
|
||
|
|
||
|
-------------------------------------------------------------------------------
|
||
|
|
||
|
This code has been altered significantly from its original form, to support
|
||
|
several games based on the Quake III Arena engine, in the form of "Q3Map2."
|
||
|
|
||
|
------------------------------------------------------------------------------- */
|
||
|
|
||
|
|
||
|
|
||
|
/* dependencies */
|
||
|
#include "vmap.h"
|
||
|
|
||
|
|
||
|
|
||
|
static void ExtrapolateTexcoords( const float *axyz, const float *ast, const float *bxyz, const float *bst, const float *cxyz, const float *cst, const float *axyz_new, float *ast_out, const float *bxyz_new, float *bst_out, const float *cxyz_new, float *cst_out ){
|
||
|
vec4_t scoeffs, tcoeffs;
|
||
|
float md;
|
||
|
m4x4_t solvematrix;
|
||
|
|
||
|
vec3_t norm;
|
||
|
vec3_t dab, dac;
|
||
|
VectorSubtract( bxyz, axyz, dab );
|
||
|
VectorSubtract( cxyz, axyz, dac );
|
||
|
CrossProduct( dab, dac, norm );
|
||
|
|
||
|
// assume:
|
||
|
// s = f(x, y, z)
|
||
|
// s(v + norm) = s(v) when n ortho xyz
|
||
|
|
||
|
// s(v) = DotProduct(v, scoeffs) + scoeffs[3]
|
||
|
|
||
|
// solve:
|
||
|
// scoeffs * (axyz, 1) == ast[0]
|
||
|
// scoeffs * (bxyz, 1) == bst[0]
|
||
|
// scoeffs * (cxyz, 1) == cst[0]
|
||
|
// scoeffs * (norm, 0) == 0
|
||
|
// scoeffs * [axyz, 1 | bxyz, 1 | cxyz, 1 | norm, 0] = [ast[0], bst[0], cst[0], 0]
|
||
|
solvematrix[0] = axyz[0];
|
||
|
solvematrix[4] = axyz[1];
|
||
|
solvematrix[8] = axyz[2];
|
||
|
solvematrix[12] = 1;
|
||
|
solvematrix[1] = bxyz[0];
|
||
|
solvematrix[5] = bxyz[1];
|
||
|
solvematrix[9] = bxyz[2];
|
||
|
solvematrix[13] = 1;
|
||
|
solvematrix[2] = cxyz[0];
|
||
|
solvematrix[6] = cxyz[1];
|
||
|
solvematrix[10] = cxyz[2];
|
||
|
solvematrix[14] = 1;
|
||
|
solvematrix[3] = norm[0];
|
||
|
solvematrix[7] = norm[1];
|
||
|
solvematrix[11] = norm[2];
|
||
|
solvematrix[15] = 0;
|
||
|
|
||
|
md = m4_det( solvematrix );
|
||
|
if ( md * md < 1e-10 ) {
|
||
|
Sys_Printf( "Cannot invert some matrix, some texcoords aren't extrapolated!" );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
m4x4_invert( solvematrix );
|
||
|
|
||
|
scoeffs[0] = ast[0];
|
||
|
scoeffs[1] = bst[0];
|
||
|
scoeffs[2] = cst[0];
|
||
|
scoeffs[3] = 0;
|
||
|
m4x4_transform_vec4( solvematrix, scoeffs );
|
||
|
tcoeffs[0] = ast[1];
|
||
|
tcoeffs[1] = bst[1];
|
||
|
tcoeffs[2] = cst[1];
|
||
|
tcoeffs[3] = 0;
|
||
|
m4x4_transform_vec4( solvematrix, tcoeffs );
|
||
|
|
||
|
ast_out[0] = scoeffs[0] * axyz_new[0] + scoeffs[1] * axyz_new[1] + scoeffs[2] * axyz_new[2] + scoeffs[3];
|
||
|
ast_out[1] = tcoeffs[0] * axyz_new[0] + tcoeffs[1] * axyz_new[1] + tcoeffs[2] * axyz_new[2] + tcoeffs[3];
|
||
|
bst_out[0] = scoeffs[0] * bxyz_new[0] + scoeffs[1] * bxyz_new[1] + scoeffs[2] * bxyz_new[2] + scoeffs[3];
|
||
|
bst_out[1] = tcoeffs[0] * bxyz_new[0] + tcoeffs[1] * bxyz_new[1] + tcoeffs[2] * bxyz_new[2] + tcoeffs[3];
|
||
|
cst_out[0] = scoeffs[0] * cxyz_new[0] + scoeffs[1] * cxyz_new[1] + scoeffs[2] * cxyz_new[2] + scoeffs[3];
|
||
|
cst_out[1] = tcoeffs[0] * cxyz_new[0] + tcoeffs[1] * cxyz_new[1] + tcoeffs[2] * cxyz_new[2] + tcoeffs[3];
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
ScaleBSPMain()
|
||
|
amaze and confuse your enemies with wierd scaled maps!
|
||
|
*/
|
||
|
|
||
|
int ScaleBSPMain( int argc, char **argv ){
|
||
|
int i, j;
|
||
|
float f, a;
|
||
|
vec3_t scale;
|
||
|
vec3_t vec;
|
||
|
char str[ 1024 ];
|
||
|
int uniform, axis;
|
||
|
qboolean texscale;
|
||
|
float *old_xyzst = NULL;
|
||
|
float spawn_ref = 0;
|
||
|
|
||
|
|
||
|
/* arg checking */
|
||
|
if ( argc < 3 ) {
|
||
|
Sys_Printf( "Usage: q3map [-v] -scale [-tex] [-spawn_ref <value>] <value> <mapname>\n" );
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
texscale = qfalse;
|
||
|
for ( i = 1; i < argc - 2; ++i )
|
||
|
{
|
||
|
if ( !strcmp( argv[i], "-tex" ) ) {
|
||
|
texscale = qtrue;
|
||
|
}
|
||
|
else if ( !strcmp( argv[i], "-spawn_ref" ) ) {
|
||
|
spawn_ref = atof( argv[i + 1] );
|
||
|
++i;
|
||
|
}
|
||
|
else{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* get scale */
|
||
|
// if(argc-2 >= i) // always true
|
||
|
scale[2] = scale[1] = scale[0] = atof( argv[ argc - 2 ] );
|
||
|
if ( argc - 3 >= i ) {
|
||
|
scale[1] = scale[0] = atof( argv[ argc - 3 ] );
|
||
|
}
|
||
|
if ( argc - 4 >= i ) {
|
||
|
scale[0] = atof( argv[ argc - 4 ] );
|
||
|
}
|
||
|
|
||
|
uniform = ( ( scale[0] == scale[1] ) && ( scale[1] == scale[2] ) );
|
||
|
|
||
|
if ( scale[0] == 0.0f || scale[1] == 0.0f || scale[2] == 0.0f ) {
|
||
|
Sys_Printf( "Usage: q3map [-v] -scale [-tex] [-spawn_ref <value>] <value> <mapname>\n" );
|
||
|
Sys_Printf( "Non-zero scale value required.\n" );
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* do some path mangling */
|
||
|
strcpy( source, ExpandArg( argv[ argc - 1 ] ) );
|
||
|
StripExtension( source );
|
||
|
DefaultExtension( source, ".bsp" );
|
||
|
|
||
|
/* load the bsp */
|
||
|
Sys_Printf( "Loading %s\n", source );
|
||
|
LoadBSPFile( source );
|
||
|
ParseEntities();
|
||
|
|
||
|
/* note it */
|
||
|
Sys_Printf( "--- ScaleBSP ---\n" );
|
||
|
Sys_FPrintf( SYS_VRB, "%9d entities\n", numEntities );
|
||
|
|
||
|
/* scale entity keys */
|
||
|
for ( i = 0; i < numBSPEntities && i < numEntities; i++ )
|
||
|
{
|
||
|
/* scale origin */
|
||
|
GetVectorForKey( &entities[ i ], "origin", vec );
|
||
|
if ( ( vec[ 0 ] || vec[ 1 ] || vec[ 2 ] ) ) {
|
||
|
if ( !strncmp( ValueForKey( &entities[i], "classname" ), "info_player_", 12 ) ) {
|
||
|
vec[2] += spawn_ref;
|
||
|
}
|
||
|
vec[0] *= scale[0];
|
||
|
vec[1] *= scale[1];
|
||
|
vec[2] *= scale[2];
|
||
|
if ( !strncmp( ValueForKey( &entities[i], "classname" ), "info_player_", 12 ) ) {
|
||
|
vec[2] -= spawn_ref;
|
||
|
}
|
||
|
sprintf( str, "%f %f %f", vec[ 0 ], vec[ 1 ], vec[ 2 ] );
|
||
|
SetKeyValue( &entities[ i ], "origin", str );
|
||
|
}
|
||
|
|
||
|
a = FloatForKey( &entities[ i ], "angle" );
|
||
|
if ( a == -1 || a == -2 ) { // z scale
|
||
|
axis = 2;
|
||
|
}
|
||
|
else if ( fabs( sin( DEG2RAD( a ) ) ) < 0.707 ) {
|
||
|
axis = 0;
|
||
|
}
|
||
|
else{
|
||
|
axis = 1;
|
||
|
}
|
||
|
|
||
|
/* scale door lip */
|
||
|
f = FloatForKey( &entities[ i ], "lip" );
|
||
|
if ( f ) {
|
||
|
f *= scale[axis];
|
||
|
sprintf( str, "%f", f );
|
||
|
SetKeyValue( &entities[ i ], "lip", str );
|
||
|
}
|
||
|
|
||
|
/* scale plat height */
|
||
|
f = FloatForKey( &entities[ i ], "height" );
|
||
|
if ( f ) {
|
||
|
f *= scale[2];
|
||
|
sprintf( str, "%f", f );
|
||
|
SetKeyValue( &entities[ i ], "height", str );
|
||
|
}
|
||
|
|
||
|
// TODO maybe allow a definition file for entities to specify which values are scaled how?
|
||
|
}
|
||
|
|
||
|
/* scale models */
|
||
|
for ( i = 0; i < numBSPModels; i++ )
|
||
|
{
|
||
|
bspModels[ i ].mins[0] *= scale[0];
|
||
|
bspModels[ i ].mins[1] *= scale[1];
|
||
|
bspModels[ i ].mins[2] *= scale[2];
|
||
|
bspModels[ i ].maxs[0] *= scale[0];
|
||
|
bspModels[ i ].maxs[1] *= scale[1];
|
||
|
bspModels[ i ].maxs[2] *= scale[2];
|
||
|
}
|
||
|
|
||
|
/* scale nodes */
|
||
|
for ( i = 0; i < numBSPNodes; i++ )
|
||
|
{
|
||
|
bspNodes[ i ].mins[0] *= scale[0];
|
||
|
bspNodes[ i ].mins[1] *= scale[1];
|
||
|
bspNodes[ i ].mins[2] *= scale[2];
|
||
|
bspNodes[ i ].maxs[0] *= scale[0];
|
||
|
bspNodes[ i ].maxs[1] *= scale[1];
|
||
|
bspNodes[ i ].maxs[2] *= scale[2];
|
||
|
}
|
||
|
|
||
|
/* scale leafs */
|
||
|
for ( i = 0; i < numBSPLeafs; i++ )
|
||
|
{
|
||
|
bspLeafs[ i ].mins[0] *= scale[0];
|
||
|
bspLeafs[ i ].mins[1] *= scale[1];
|
||
|
bspLeafs[ i ].mins[2] *= scale[2];
|
||
|
bspLeafs[ i ].maxs[0] *= scale[0];
|
||
|
bspLeafs[ i ].maxs[1] *= scale[1];
|
||
|
bspLeafs[ i ].maxs[2] *= scale[2];
|
||
|
}
|
||
|
|
||
|
if ( texscale ) {
|
||
|
Sys_Printf( "Using texture unlocking (and probably breaking texture alignment a lot)\n" );
|
||
|
old_xyzst = safe_malloc( sizeof( *old_xyzst ) * numBSPDrawVerts * 5 );
|
||
|
for ( i = 0; i < numBSPDrawVerts; i++ )
|
||
|
{
|
||
|
old_xyzst[5 * i + 0] = bspDrawVerts[i].xyz[0];
|
||
|
old_xyzst[5 * i + 1] = bspDrawVerts[i].xyz[1];
|
||
|
old_xyzst[5 * i + 2] = bspDrawVerts[i].xyz[2];
|
||
|
old_xyzst[5 * i + 3] = bspDrawVerts[i].st[0];
|
||
|
old_xyzst[5 * i + 4] = bspDrawVerts[i].st[1];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* scale drawverts */
|
||
|
for ( i = 0; i < numBSPDrawVerts; i++ )
|
||
|
{
|
||
|
bspDrawVerts[i].xyz[0] *= scale[0];
|
||
|
bspDrawVerts[i].xyz[1] *= scale[1];
|
||
|
bspDrawVerts[i].xyz[2] *= scale[2];
|
||
|
bspDrawVerts[i].normal[0] /= scale[0];
|
||
|
bspDrawVerts[i].normal[1] /= scale[1];
|
||
|
bspDrawVerts[i].normal[2] /= scale[2];
|
||
|
VectorNormalize( bspDrawVerts[i].normal, bspDrawVerts[i].normal );
|
||
|
}
|
||
|
|
||
|
if ( texscale ) {
|
||
|
for ( i = 0; i < numBSPDrawSurfaces; i++ )
|
||
|
{
|
||
|
switch ( bspDrawSurfaces[i].surfaceType )
|
||
|
{
|
||
|
case SURFACE_FACE:
|
||
|
case SURFACE_META:
|
||
|
if ( bspDrawSurfaces[i].numIndexes % 3 ) {
|
||
|
Error( "Not a triangulation!" );
|
||
|
}
|
||
|
for ( j = bspDrawSurfaces[i].firstIndex; j < bspDrawSurfaces[i].firstIndex + bspDrawSurfaces[i].numIndexes; j += 3 )
|
||
|
{
|
||
|
int ia = bspDrawIndexes[j] + bspDrawSurfaces[i].firstVert, ib = bspDrawIndexes[j + 1] + bspDrawSurfaces[i].firstVert, ic = bspDrawIndexes[j + 2] + bspDrawSurfaces[i].firstVert;
|
||
|
bspDrawVert_t *a = &bspDrawVerts[ia], *b = &bspDrawVerts[ib], *c = &bspDrawVerts[ic];
|
||
|
float *oa = &old_xyzst[ia * 5], *ob = &old_xyzst[ib * 5], *oc = &old_xyzst[ic * 5];
|
||
|
// extrapolate:
|
||
|
// a->xyz -> oa
|
||
|
// b->xyz -> ob
|
||
|
// c->xyz -> oc
|
||
|
ExtrapolateTexcoords(
|
||
|
&oa[0], &oa[3],
|
||
|
&ob[0], &ob[3],
|
||
|
&oc[0], &oc[3],
|
||
|
a->xyz, a->st,
|
||
|
b->xyz, b->st,
|
||
|
c->xyz, c->st );
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* scale planes */
|
||
|
if ( uniform ) {
|
||
|
for ( i = 0; i < numBSPPlanes; i++ )
|
||
|
{
|
||
|
bspPlanes[ i ].dist *= scale[0];
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for ( i = 0; i < numBSPPlanes; i++ )
|
||
|
{
|
||
|
bspPlanes[ i ].normal[0] /= scale[0];
|
||
|
bspPlanes[ i ].normal[1] /= scale[1];
|
||
|
bspPlanes[ i ].normal[2] /= scale[2];
|
||
|
f = 1 / VectorLength( bspPlanes[i].normal );
|
||
|
VectorScale( bspPlanes[i].normal, f, bspPlanes[i].normal );
|
||
|
bspPlanes[ i ].dist *= f;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* scale gridsize */
|
||
|
GetVectorForKey( &entities[ 0 ], "gridsize", vec );
|
||
|
if ( ( vec[ 0 ] + vec[ 1 ] + vec[ 2 ] ) == 0.0f ) {
|
||
|
VectorCopy( gridSize, vec );
|
||
|
}
|
||
|
vec[0] *= scale[0];
|
||
|
vec[1] *= scale[1];
|
||
|
vec[2] *= scale[2];
|
||
|
sprintf( str, "%f %f %f", vec[ 0 ], vec[ 1 ], vec[ 2 ] );
|
||
|
SetKeyValue( &entities[ 0 ], "gridsize", str );
|
||
|
|
||
|
/* inject command line parameters */
|
||
|
InjectCommandLine( argv, 0, argc - 1 );
|
||
|
|
||
|
/* write the bsp */
|
||
|
UnparseEntities();
|
||
|
StripExtension( source );
|
||
|
DefaultExtension( source, "_s.bsp" );
|
||
|
Sys_Printf( "Writing %s\n", source );
|
||
|
WriteBSPFile( source );
|
||
|
|
||
|
/* return to sender */
|
||
|
return 0;
|
||
|
}
|