split bsp analyze/info/scale stuff from q3map2
[xonotic/netradiant.git] / tools / quake3 / q3map2 / bsp_scale.c
1 /* -------------------------------------------------------------------------------
2
3    Copyright (C) 1999-2007 id Software, Inc. and contributors.
4    For a list of contributors, see the accompanying CONTRIBUTORS file.
5
6    This file is part of GtkRadiant.
7
8    GtkRadiant is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12
13    GtkRadiant is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with GtkRadiant; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21
22    -------------------------------------------------------------------------------
23
24    This code has been altered significantly from its original form, to support
25    several games based on the Quake III Arena engine, in the form of "Q3Map2."
26
27    ------------------------------------------------------------------------------- */
28
29
30
31 /* dependencies */
32 #include "q3map2.h"
33
34
35
36 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 ){
37         vec4_t scoeffs, tcoeffs;
38         float md;
39         m4x4_t solvematrix;
40
41         vec3_t norm;
42         vec3_t dab, dac;
43         VectorSubtract( bxyz, axyz, dab );
44         VectorSubtract( cxyz, axyz, dac );
45         CrossProduct( dab, dac, norm );
46
47         // assume:
48         //   s = f(x, y, z)
49         //   s(v + norm) = s(v) when n ortho xyz
50
51         // s(v) = DotProduct(v, scoeffs) + scoeffs[3]
52
53         // solve:
54         //   scoeffs * (axyz, 1) == ast[0]
55         //   scoeffs * (bxyz, 1) == bst[0]
56         //   scoeffs * (cxyz, 1) == cst[0]
57         //   scoeffs * (norm, 0) == 0
58         // scoeffs * [axyz, 1 | bxyz, 1 | cxyz, 1 | norm, 0] = [ast[0], bst[0], cst[0], 0]
59         solvematrix[0] = axyz[0];
60         solvematrix[4] = axyz[1];
61         solvematrix[8] = axyz[2];
62         solvematrix[12] = 1;
63         solvematrix[1] = bxyz[0];
64         solvematrix[5] = bxyz[1];
65         solvematrix[9] = bxyz[2];
66         solvematrix[13] = 1;
67         solvematrix[2] = cxyz[0];
68         solvematrix[6] = cxyz[1];
69         solvematrix[10] = cxyz[2];
70         solvematrix[14] = 1;
71         solvematrix[3] = norm[0];
72         solvematrix[7] = norm[1];
73         solvematrix[11] = norm[2];
74         solvematrix[15] = 0;
75
76         md = m4_det( solvematrix );
77         if ( md * md < 1e-10 ) {
78                 Sys_Printf( "Cannot invert some matrix, some texcoords aren't extrapolated!" );
79                 return;
80         }
81
82         m4x4_invert( solvematrix );
83
84         scoeffs[0] = ast[0];
85         scoeffs[1] = bst[0];
86         scoeffs[2] = cst[0];
87         scoeffs[3] = 0;
88         m4x4_transform_vec4( solvematrix, scoeffs );
89         tcoeffs[0] = ast[1];
90         tcoeffs[1] = bst[1];
91         tcoeffs[2] = cst[1];
92         tcoeffs[3] = 0;
93         m4x4_transform_vec4( solvematrix, tcoeffs );
94
95         ast_out[0] = scoeffs[0] * axyz_new[0] + scoeffs[1] * axyz_new[1] + scoeffs[2] * axyz_new[2] + scoeffs[3];
96         ast_out[1] = tcoeffs[0] * axyz_new[0] + tcoeffs[1] * axyz_new[1] + tcoeffs[2] * axyz_new[2] + tcoeffs[3];
97         bst_out[0] = scoeffs[0] * bxyz_new[0] + scoeffs[1] * bxyz_new[1] + scoeffs[2] * bxyz_new[2] + scoeffs[3];
98         bst_out[1] = tcoeffs[0] * bxyz_new[0] + tcoeffs[1] * bxyz_new[1] + tcoeffs[2] * bxyz_new[2] + tcoeffs[3];
99         cst_out[0] = scoeffs[0] * cxyz_new[0] + scoeffs[1] * cxyz_new[1] + scoeffs[2] * cxyz_new[2] + scoeffs[3];
100         cst_out[1] = tcoeffs[0] * cxyz_new[0] + tcoeffs[1] * cxyz_new[1] + tcoeffs[2] * cxyz_new[2] + tcoeffs[3];
101 }
102
103 /*
104    ScaleBSPMain()
105    amaze and confuse your enemies with wierd scaled maps!
106  */
107
108 int ScaleBSPMain( int argc, char **argv ){
109         int i, j;
110         float f, a;
111         vec3_t scale;
112         vec3_t vec;
113         char str[ 1024 ];
114         int uniform, axis;
115         qboolean texscale;
116         float *old_xyzst = NULL;
117         float spawn_ref = 0;
118
119
120         /* arg checking */
121         if ( argc < 3 ) {
122                 Sys_Printf( "Usage: q3map [-v] -scale [-tex] [-spawn_ref <value>] <value> <mapname>\n" );
123                 return 0;
124         }
125
126         texscale = qfalse;
127         for ( i = 1; i < argc - 2; ++i )
128         {
129                 if ( !strcmp( argv[i], "-tex" ) ) {
130                         texscale = qtrue;
131                 }
132                 else if ( !strcmp( argv[i], "-spawn_ref" ) ) {
133                         spawn_ref = atof( argv[i + 1] );
134                         ++i;
135                 }
136                 else{
137                         break;
138                 }
139         }
140
141         /* get scale */
142         // if(argc-2 >= i) // always true
143         scale[2] = scale[1] = scale[0] = atof( argv[ argc - 2 ] );
144         if ( argc - 3 >= i ) {
145                 scale[1] = scale[0] = atof( argv[ argc - 3 ] );
146         }
147         if ( argc - 4 >= i ) {
148                 scale[0] = atof( argv[ argc - 4 ] );
149         }
150
151         uniform = ( ( scale[0] == scale[1] ) && ( scale[1] == scale[2] ) );
152
153         if ( scale[0] == 0.0f || scale[1] == 0.0f || scale[2] == 0.0f ) {
154                 Sys_Printf( "Usage: q3map [-v] -scale [-tex] [-spawn_ref <value>] <value> <mapname>\n" );
155                 Sys_Printf( "Non-zero scale value required.\n" );
156                 return 0;
157         }
158
159         /* do some path mangling */
160         strcpy( source, ExpandArg( argv[ argc - 1 ] ) );
161         StripExtension( source );
162         DefaultExtension( source, ".bsp" );
163
164         /* load the bsp */
165         Sys_Printf( "Loading %s\n", source );
166         LoadBSPFile( source );
167         ParseEntities();
168
169         /* note it */
170         Sys_Printf( "--- ScaleBSP ---\n" );
171         Sys_FPrintf( SYS_VRB, "%9d entities\n", numEntities );
172
173         /* scale entity keys */
174         for ( i = 0; i < numBSPEntities && i < numEntities; i++ )
175         {
176                 /* scale origin */
177                 GetVectorForKey( &entities[ i ], "origin", vec );
178                 if ( ( vec[ 0 ] || vec[ 1 ] || vec[ 2 ] ) ) {
179                         if ( !strncmp( ValueForKey( &entities[i], "classname" ), "info_player_", 12 ) ) {
180                                 vec[2] += spawn_ref;
181                         }
182                         vec[0] *= scale[0];
183                         vec[1] *= scale[1];
184                         vec[2] *= scale[2];
185                         if ( !strncmp( ValueForKey( &entities[i], "classname" ), "info_player_", 12 ) ) {
186                                 vec[2] -= spawn_ref;
187                         }
188                         sprintf( str, "%f %f %f", vec[ 0 ], vec[ 1 ], vec[ 2 ] );
189                         SetKeyValue( &entities[ i ], "origin", str );
190                 }
191
192                 a = FloatForKey( &entities[ i ], "angle" );
193                 if ( a == -1 || a == -2 ) { // z scale
194                         axis = 2;
195                 }
196                 else if ( fabs( sin( DEG2RAD( a ) ) ) < 0.707 ) {
197                         axis = 0;
198                 }
199                 else{
200                         axis = 1;
201                 }
202
203                 /* scale door lip */
204                 f = FloatForKey( &entities[ i ], "lip" );
205                 if ( f ) {
206                         f *= scale[axis];
207                         sprintf( str, "%f", f );
208                         SetKeyValue( &entities[ i ], "lip", str );
209                 }
210
211                 /* scale plat height */
212                 f = FloatForKey( &entities[ i ], "height" );
213                 if ( f ) {
214                         f *= scale[2];
215                         sprintf( str, "%f", f );
216                         SetKeyValue( &entities[ i ], "height", str );
217                 }
218
219                 // TODO maybe allow a definition file for entities to specify which values are scaled how?
220         }
221
222         /* scale models */
223         for ( i = 0; i < numBSPModels; i++ )
224         {
225                 bspModels[ i ].mins[0] *= scale[0];
226                 bspModels[ i ].mins[1] *= scale[1];
227                 bspModels[ i ].mins[2] *= scale[2];
228                 bspModels[ i ].maxs[0] *= scale[0];
229                 bspModels[ i ].maxs[1] *= scale[1];
230                 bspModels[ i ].maxs[2] *= scale[2];
231         }
232
233         /* scale nodes */
234         for ( i = 0; i < numBSPNodes; i++ )
235         {
236                 bspNodes[ i ].mins[0] *= scale[0];
237                 bspNodes[ i ].mins[1] *= scale[1];
238                 bspNodes[ i ].mins[2] *= scale[2];
239                 bspNodes[ i ].maxs[0] *= scale[0];
240                 bspNodes[ i ].maxs[1] *= scale[1];
241                 bspNodes[ i ].maxs[2] *= scale[2];
242         }
243
244         /* scale leafs */
245         for ( i = 0; i < numBSPLeafs; i++ )
246         {
247                 bspLeafs[ i ].mins[0] *= scale[0];
248                 bspLeafs[ i ].mins[1] *= scale[1];
249                 bspLeafs[ i ].mins[2] *= scale[2];
250                 bspLeafs[ i ].maxs[0] *= scale[0];
251                 bspLeafs[ i ].maxs[1] *= scale[1];
252                 bspLeafs[ i ].maxs[2] *= scale[2];
253         }
254
255         if ( texscale ) {
256                 Sys_Printf( "Using texture unlocking (and probably breaking texture alignment a lot)\n" );
257                 old_xyzst = safe_malloc( sizeof( *old_xyzst ) * numBSPDrawVerts * 5 );
258                 for ( i = 0; i < numBSPDrawVerts; i++ )
259                 {
260                         old_xyzst[5 * i + 0] = bspDrawVerts[i].xyz[0];
261                         old_xyzst[5 * i + 1] = bspDrawVerts[i].xyz[1];
262                         old_xyzst[5 * i + 2] = bspDrawVerts[i].xyz[2];
263                         old_xyzst[5 * i + 3] = bspDrawVerts[i].st[0];
264                         old_xyzst[5 * i + 4] = bspDrawVerts[i].st[1];
265                 }
266         }
267
268         /* scale drawverts */
269         for ( i = 0; i < numBSPDrawVerts; i++ )
270         {
271                 bspDrawVerts[i].xyz[0] *= scale[0];
272                 bspDrawVerts[i].xyz[1] *= scale[1];
273                 bspDrawVerts[i].xyz[2] *= scale[2];
274                 bspDrawVerts[i].normal[0] /= scale[0];
275                 bspDrawVerts[i].normal[1] /= scale[1];
276                 bspDrawVerts[i].normal[2] /= scale[2];
277                 VectorNormalize( bspDrawVerts[i].normal, bspDrawVerts[i].normal );
278         }
279
280         if ( texscale ) {
281                 for ( i = 0; i < numBSPDrawSurfaces; i++ )
282                 {
283                         switch ( bspDrawSurfaces[i].surfaceType )
284                         {
285                         case SURFACE_FACE:
286                         case SURFACE_META:
287                                 if ( bspDrawSurfaces[i].numIndexes % 3 ) {
288                                         Error( "Not a triangulation!" );
289                                 }
290                                 for ( j = bspDrawSurfaces[i].firstIndex; j < bspDrawSurfaces[i].firstIndex + bspDrawSurfaces[i].numIndexes; j += 3 )
291                                 {
292                                         int ia = bspDrawIndexes[j] + bspDrawSurfaces[i].firstVert, ib = bspDrawIndexes[j + 1] + bspDrawSurfaces[i].firstVert, ic = bspDrawIndexes[j + 2] + bspDrawSurfaces[i].firstVert;
293                                         bspDrawVert_t *a = &bspDrawVerts[ia], *b = &bspDrawVerts[ib], *c = &bspDrawVerts[ic];
294                                         float *oa = &old_xyzst[ia * 5], *ob = &old_xyzst[ib * 5], *oc = &old_xyzst[ic * 5];
295                                         // extrapolate:
296                                         //   a->xyz -> oa
297                                         //   b->xyz -> ob
298                                         //   c->xyz -> oc
299                                         ExtrapolateTexcoords(
300                                                 &oa[0], &oa[3],
301                                                 &ob[0], &ob[3],
302                                                 &oc[0], &oc[3],
303                                                 a->xyz, a->st,
304                                                 b->xyz, b->st,
305                                                 c->xyz, c->st );
306                                 }
307                                 break;
308                         }
309                 }
310         }
311
312         /* scale planes */
313         if ( uniform ) {
314                 for ( i = 0; i < numBSPPlanes; i++ )
315                 {
316                         bspPlanes[ i ].dist *= scale[0];
317                 }
318         }
319         else
320         {
321                 for ( i = 0; i < numBSPPlanes; i++ )
322                 {
323                         bspPlanes[ i ].normal[0] /= scale[0];
324                         bspPlanes[ i ].normal[1] /= scale[1];
325                         bspPlanes[ i ].normal[2] /= scale[2];
326                         f = 1 / VectorLength( bspPlanes[i].normal );
327                         VectorScale( bspPlanes[i].normal, f, bspPlanes[i].normal );
328                         bspPlanes[ i ].dist *= f;
329                 }
330         }
331
332         /* scale gridsize */
333         GetVectorForKey( &entities[ 0 ], "gridsize", vec );
334         if ( ( vec[ 0 ] + vec[ 1 ] + vec[ 2 ] ) == 0.0f ) {
335                 VectorCopy( gridSize, vec );
336         }
337         vec[0] *= scale[0];
338         vec[1] *= scale[1];
339         vec[2] *= scale[2];
340         sprintf( str, "%f %f %f", vec[ 0 ], vec[ 1 ], vec[ 2 ] );
341         SetKeyValue( &entities[ 0 ], "gridsize", str );
342
343         /* inject command line parameters */
344         InjectCommandLine( argv, 0, argc - 1 );
345
346         /* write the bsp */
347         UnparseEntities();
348         StripExtension( source );
349         DefaultExtension( source, "_s.bsp" );
350         Sys_Printf( "Writing %s\n", source );
351         WriteBSPFile( source );
352
353         /* return to sender */
354         return 0;
355 }