]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake3/q3map2/convert_map.c
Merge branch 'NateEag-master-patch-12920' into 'master'
[xonotic/netradiant.git] / tools / quake3 / q3map2 / convert_map.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 /* marker */
32 #define CONVERT_MAP_C
33
34
35
36 /* dependencies */
37 #include "q3map2.h"
38
39
40
41 /*
42    ConvertBrush()
43    exports a map brush
44  */
45
46 #define SNAP_FLOAT_TO_INT   4
47 #define SNAP_INT_TO_FLOAT   ( 1.0 / SNAP_FLOAT_TO_INT )
48
49 typedef vec_t vec2_t[2];
50
51 static vec_t Det3x3( vec_t a00, vec_t a01, vec_t a02,
52                                          vec_t a10, vec_t a11, vec_t a12,
53                                          vec_t a20, vec_t a21, vec_t a22 ){
54         return
55                 a00 * ( a11 * a22 - a12 * a21 )
56                 -   a01 * ( a10 * a22 - a12 * a20 )
57                 +   a02 * ( a10 * a21 - a11 * a20 );
58 }
59
60 void GetBestSurfaceTriangleMatchForBrushside( side_t *buildSide, bspDrawVert_t *bestVert[3] ){
61         bspDrawSurface_t *s;
62         int i;
63         int t;
64         vec_t best = 0;
65         vec_t thisarea;
66         vec3_t normdiff;
67         vec3_t v1v0, v2v0, norm;
68         bspDrawVert_t *vert[3];
69         winding_t *polygon;
70         plane_t *buildPlane = &mapplanes[buildSide->planenum];
71         int matches = 0;
72
73         // first, start out with NULLs
74         bestVert[0] = bestVert[1] = bestVert[2] = NULL;
75
76         // brute force through all surfaces
77         for ( s = bspDrawSurfaces; s != bspDrawSurfaces + numBSPDrawSurfaces; ++s )
78         {
79                 if ( s->surfaceType != MST_PLANAR && s->surfaceType != MST_TRIANGLE_SOUP ) {
80                         continue;
81                 }
82                 if ( strcmp( buildSide->shaderInfo->shader, bspShaders[s->shaderNum].shader ) ) {
83                         continue;
84                 }
85                 for ( t = 0; t + 3 <= s->numIndexes; t += 3 )
86                 {
87                         vert[0] = &bspDrawVerts[s->firstVert + bspDrawIndexes[s->firstIndex + t + 0]];
88                         vert[1] = &bspDrawVerts[s->firstVert + bspDrawIndexes[s->firstIndex + t + 1]];
89                         vert[2] = &bspDrawVerts[s->firstVert + bspDrawIndexes[s->firstIndex + t + 2]];
90                         if ( s->surfaceType == MST_PLANAR && VectorCompare( vert[0]->normal, vert[1]->normal ) && VectorCompare( vert[1]->normal, vert[2]->normal ) ) {
91                                 VectorSubtract( vert[0]->normal, buildPlane->normal, normdiff );
92                                 if ( VectorLength( normdiff ) >= normalEpsilon ) {
93                                         continue;
94                                 }
95                                 VectorSubtract( vert[1]->normal, buildPlane->normal, normdiff );
96                                 if ( VectorLength( normdiff ) >= normalEpsilon ) {
97                                         continue;
98                                 }
99                                 VectorSubtract( vert[2]->normal, buildPlane->normal, normdiff );
100                                 if ( VectorLength( normdiff ) >= normalEpsilon ) {
101                                         continue;
102                                 }
103                         }
104                         else
105                         {
106                                 // this is more prone to roundoff errors, but with embedded
107                                 // models, there is no better way
108                                 VectorSubtract( vert[1]->xyz, vert[0]->xyz, v1v0 );
109                                 VectorSubtract( vert[2]->xyz, vert[0]->xyz, v2v0 );
110                                 CrossProduct( v2v0, v1v0, norm );
111                                 VectorNormalize( norm, norm );
112                                 VectorSubtract( norm, buildPlane->normal, normdiff );
113                                 if ( VectorLength( normdiff ) >= normalEpsilon ) {
114                                         continue;
115                                 }
116                         }
117                         if ( abs( DotProduct( vert[0]->xyz, buildPlane->normal ) - buildPlane->dist ) >= distanceEpsilon ) {
118                                 continue;
119                         }
120                         if ( abs( DotProduct( vert[1]->xyz, buildPlane->normal ) - buildPlane->dist ) >= distanceEpsilon ) {
121                                 continue;
122                         }
123                         if ( abs( DotProduct( vert[2]->xyz, buildPlane->normal ) - buildPlane->dist ) >= distanceEpsilon ) {
124                                 continue;
125                         }
126                         // Okay. Correct surface type, correct shader, correct plane. Let's start with the business...
127                         polygon = CopyWinding( buildSide->winding );
128                         for ( i = 0; i < 3; ++i )
129                         {
130                                 // 0: 1, 2
131                                 // 1: 2, 0
132                                 // 2; 0, 1
133                                 vec3_t *v1 = &vert[( i + 1 ) % 3]->xyz;
134                                 vec3_t *v2 = &vert[( i + 2 ) % 3]->xyz;
135                                 vec3_t triNormal;
136                                 vec_t triDist;
137                                 vec3_t sideDirection;
138                                 // we now need to generate triNormal and triDist so that they represent the plane spanned by normal and (v2 - v1).
139                                 VectorSubtract( *v2, *v1, sideDirection );
140                                 CrossProduct( sideDirection, buildPlane->normal, triNormal );
141                                 triDist = DotProduct( *v1, triNormal );
142                                 ChopWindingInPlace( &polygon, triNormal, triDist, distanceEpsilon );
143                                 if ( !polygon ) {
144                                         goto exwinding;
145                                 }
146                         }
147                         thisarea = WindingArea( polygon );
148                         if ( thisarea > 0 ) {
149                                 ++matches;
150                         }
151                         if ( thisarea > best ) {
152                                 best = thisarea;
153                                 bestVert[0] = vert[0];
154                                 bestVert[1] = vert[1];
155                                 bestVert[2] = vert[2];
156                         }
157                         FreeWinding( polygon );
158 exwinding:
159                         ;
160                 }
161         }
162         //if(strncmp(buildSide->shaderInfo->shader, "textures/common/", 16))
163         //      fprintf(stderr, "brushside with %s: %d matches (%f area)\n", buildSide->shaderInfo->shader, matches, best);
164 }
165
166 #define FRAC( x ) ( ( x ) - floor( x ) )
167 static void ConvertOriginBrush( FILE *f, int num, vec3_t origin, qboolean brushPrimitives ){
168         int originSize = 256;
169
170         char pattern[6][7][3] = {
171                 { "+++", "+-+", "-++", "-  ", " + ", " - ", "-  " },
172                 { "+++", "-++", "++-", "-  ", "  +", "+  ", "  +" },
173                 { "+++", "++-", "+-+", " - ", "  +", " - ", "  +" },
174                 { "---", "+--", "-+-", "-  ", " + ", " - ", "+  " },
175                 { "---", "--+", "+--", "-  ", "  +", "-  ", "  +" },
176                 { "---", "-+-", "--+", " - ", "  +", " + ", "  +" }
177         };
178         int i;
179 #define S( a,b,c ) ( pattern[a][b][c] == '+' ? +1 : pattern[a][b][c] == '-' ? -1 : 0 )
180
181         /* start brush */
182         fprintf( f, "\t// brush %d\n", num );
183         fprintf( f, "\t{\n" );
184         if ( brushPrimitives ) {
185                 fprintf( f, "\tbrushDef\n" );
186                 fprintf( f, "\t{\n" );
187         }
188         /* print brush side */
189         /* ( 640 24 -224 ) ( 448 24 -224 ) ( 448 -232 -224 ) common/caulk 0 48 0 0.500000 0.500000 0 0 0 */
190
191         for ( i = 0; i < 6; ++i )
192         {
193                 if ( brushPrimitives ) {
194                         fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( ( %.8f %.8f %.8f ) ( %.8f %.8f %.8f ) ) %s %d 0 0\n",
195                                          origin[0] + 8 * S( i,0,0 ), origin[1] + 8 * S( i,0,1 ), origin[2] + 8 * S( i,0,2 ),
196                                          origin[0] + 8 * S( i,1,0 ), origin[1] + 8 * S( i,1,1 ), origin[2] + 8 * S( i,1,2 ),
197                                          origin[0] + 8 * S( i,2,0 ), origin[1] + 8 * S( i,2,1 ), origin[2] + 8 * S( i,2,2 ),
198                                          1.0f / 16.0f, 0.0f, FRAC( ( S( i,5,0 ) * origin[0] + S( i,5,1 ) * origin[1] + S( i,5,2 ) * origin[2] ) / 16.0 + 0.5 ),
199                                          0.0f, 1.0f / 16.0f, FRAC( ( S( i,6,0 ) * origin[0] + S( i,6,1 ) * origin[1] + S( i,6,2 ) * origin[2] ) / 16.0 + 0.5 ),
200                                          "common/origin",
201                                          0
202                                          );
203                 }
204                 else
205                 {
206                         fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) %s %.8f %.8f %.8f %.8f %.8f %d 0 0\n",
207                                          origin[0] + 8 * S( i,0,0 ), origin[1] + 8 * S( i,0,1 ), origin[2] + 8 * S( i,0,2 ),
208                                          origin[0] + 8 * S( i,1,0 ), origin[1] + 8 * S( i,1,1 ), origin[2] + 8 * S( i,1,2 ),
209                                          origin[0] + 8 * S( i,2,0 ), origin[1] + 8 * S( i,2,1 ), origin[2] + 8 * S( i,2,2 ),
210                                          "common/origin",
211                                          FRAC( ( S( i,3,0 ) * origin[0] + S( i,3,1 ) * origin[1] + S( i,3,2 ) * origin[2] ) / 16.0 + 0.5 ) * originSize,
212                                          FRAC( ( S( i,4,0 ) * origin[0] + S( i,4,1 ) * origin[1] + S( i,4,2 ) * origin[2] ) / 16.0 + 0.5 ) * originSize,
213                                          0.0f, 16.0 / originSize, 16.0 / originSize,
214                                          0
215                                          );
216                 }
217         }
218 #undef S
219
220         /* end brush */
221         if ( brushPrimitives ) {
222                 fprintf( f, "\t}\n" );
223         }
224         fprintf( f, "\t}\n\n" );
225 }
226
227 static void ConvertBrushFast( FILE *f, int num, bspBrush_t *brush, vec3_t origin, qboolean brushPrimitives ){
228         int i;
229         bspBrushSide_t  *side;
230         side_t          *buildSide;
231         bspShader_t     *shader;
232         char            *texture;
233         plane_t         *buildPlane;
234         vec3_t pts[ 3 ];
235
236
237         /* clear out build brush */
238         for ( i = 0; i < buildBrush->numsides; i++ )
239         {
240                 buildSide = &buildBrush->sides[ i ];
241                 if ( buildSide->winding != NULL ) {
242                         FreeWinding( buildSide->winding );
243                         buildSide->winding = NULL;
244                 }
245         }
246         buildBrush->numsides = 0;
247
248         qboolean modelclip = qfalse;
249         /* try to guess if thats model clip */
250         if ( force ){
251                 int notNoShader = 0;
252                 modelclip = qtrue;
253                 for ( i = 0; i < brush->numSides; i++ )
254                 {
255                         /* get side */
256                         side = &bspBrushSides[ brush->firstSide + i ];
257
258                         /* get shader */
259                         if ( side->shaderNum < 0 || side->shaderNum >= numBSPShaders ) {
260                                 continue;
261                         }
262                         shader = &bspShaders[ side->shaderNum ];
263                         //"noshader" happens on modelclip and unwanted sides ( usually breaking complex brushes )
264                         if( Q_stricmp( shader->shader, "noshader" ) ){
265                                 notNoShader++;
266                         }
267                         if( notNoShader > 1 ){
268                                 modelclip = qfalse;
269                                 break;
270                         }
271                 }
272         }
273
274         /* iterate through bsp brush sides */
275         for ( i = 0; i < brush->numSides; i++ )
276         {
277                 /* get side */
278                 side = &bspBrushSides[ brush->firstSide + i ];
279
280                 /* get shader */
281                 if ( side->shaderNum < 0 || side->shaderNum >= numBSPShaders ) {
282                         continue;
283                 }
284                 shader = &bspShaders[ side->shaderNum ];
285                 //"noshader" happens on modelclip and unwanted sides ( usually breaking complex brushes )
286                 if( !Q_stricmp( shader->shader, "default" ) || ( !Q_stricmp( shader->shader, "noshader" ) && !modelclip ) )
287                         continue;
288
289                 /* add build side */
290                 buildSide = &buildBrush->sides[ buildBrush->numsides ];
291                 buildBrush->numsides++;
292
293                 /* tag it */
294                 buildSide->shaderInfo = ShaderInfoForShader( shader->shader );
295                 buildSide->planenum = side->planeNum;
296                 buildSide->winding = NULL;
297         }
298
299         if ( !CreateBrushWindings( buildBrush ) ) {
300                 //Sys_Printf( "CreateBrushWindings failed\n" );
301                 return;
302         }
303
304         /* start brush */
305         fprintf( f, "\t// brush %d\n", num );
306         fprintf( f, "\t{\n" );
307         if ( brushPrimitives ) {
308                 fprintf( f, "\tbrushDef\n" );
309                 fprintf( f, "\t{\n" );
310         }
311
312         /* iterate through build brush sides */
313         for ( i = 0; i < buildBrush->numsides; i++ )
314         {
315                 /* get build side */
316                 buildSide = &buildBrush->sides[ i ];
317
318                 /* get plane */
319                 buildPlane = &mapplanes[ buildSide->planenum ];
320
321                 /* dummy check */
322                 if ( buildSide->shaderInfo == NULL || buildSide->winding == NULL ) {
323                         continue;
324                 }
325
326                 /* get texture name */
327                 if ( !Q_strncasecmp( buildSide->shaderInfo->shader, "textures/", 9 ) ) {
328                         texture = buildSide->shaderInfo->shader + 9;
329                 }
330                 else{
331                         texture = buildSide->shaderInfo->shader;
332                 }
333
334                 {
335                         vec3_t vecs[ 2 ];
336                         MakeNormalVectors( buildPlane->normal, vecs[ 0 ], vecs[ 1 ] );
337                         VectorMA( vec3_origin, buildPlane->dist, buildPlane->normal, pts[ 0 ] );
338                         VectorAdd( pts[ 0 ], origin, pts[ 0 ] );
339                         VectorMA( pts[ 0 ], 256.0f, vecs[ 0 ], pts[ 1 ] );
340                         VectorMA( pts[ 0 ], 256.0f, vecs[ 1 ], pts[ 2 ] );
341                 }
342
343                 {
344                         if ( brushPrimitives ) {
345                                 fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( ( %.8f %.8f %.8f ) ( %.8f %.8f %.8f ) ) %s %d 0 0\n",
346                                                  pts[ 0 ][ 0 ], pts[ 0 ][ 1 ], pts[ 0 ][ 2 ],
347                                                  pts[ 1 ][ 0 ], pts[ 1 ][ 1 ], pts[ 1 ][ 2 ],
348                                                  pts[ 2 ][ 0 ], pts[ 2 ][ 1 ], pts[ 2 ][ 2 ],
349                                                  1.0f / 32.0f, 0.0f, 0.0f,
350                                                  0.0f, 1.0f / 32.0f, 0.0f,
351                                                  texture,
352                                                  0
353                                                  );
354                         }
355                         else
356                         {
357                                 fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) %s %.8f %.8f %.8f %.8f %.8f %d 0 0\n",
358                                                  pts[ 0 ][ 0 ], pts[ 0 ][ 1 ], pts[ 0 ][ 2 ],
359                                                  pts[ 1 ][ 0 ], pts[ 1 ][ 1 ], pts[ 1 ][ 2 ],
360                                                  pts[ 2 ][ 0 ], pts[ 2 ][ 1 ], pts[ 2 ][ 2 ],
361                                                  texture,
362                                                  0.0f, 0.0f, 0.0f, 0.5f, 0.5f,
363                                                  0
364                                                  );
365                         }
366                 }
367         }
368
369         /* end brush */
370         if ( brushPrimitives ) {
371                 fprintf( f, "\t}\n" );
372         }
373         fprintf( f, "\t}\n\n" );
374 }
375
376 static void ConvertBrush( FILE *f, int num, bspBrush_t *brush, vec3_t origin, qboolean brushPrimitives ){
377         int i, j;
378         bspBrushSide_t  *side;
379         side_t          *buildSide;
380         bspShader_t     *shader;
381         char            *texture;
382         plane_t         *buildPlane;
383         vec3_t pts[ 3 ];
384         bspDrawVert_t   *vert[3];
385
386
387         /* clear out build brush */
388         for ( i = 0; i < buildBrush->numsides; i++ )
389         {
390                 buildSide = &buildBrush->sides[ i ];
391                 if ( buildSide->winding != NULL ) {
392                         FreeWinding( buildSide->winding );
393                         buildSide->winding = NULL;
394                 }
395         }
396         buildBrush->numsides = 0;
397
398         qboolean modelclip = qfalse;
399         /* try to guess if thats model clip */
400         if ( force ){
401                 int notNoShader = 0;
402                 modelclip = qtrue;
403                 for ( i = 0; i < brush->numSides; i++ )
404                 {
405                         /* get side */
406                         side = &bspBrushSides[ brush->firstSide + i ];
407
408                         /* get shader */
409                         if ( side->shaderNum < 0 || side->shaderNum >= numBSPShaders ) {
410                                 continue;
411                         }
412                         shader = &bspShaders[ side->shaderNum ];
413                         //"noshader" happens on modelclip and unwanted sides ( usually breaking complex brushes )
414                         if( Q_stricmp( shader->shader, "noshader" ) ){
415                                 notNoShader++;
416                         }
417                         if( notNoShader > 1 ){
418                                 modelclip = qfalse;
419                                 break;
420                         }
421                 }
422         }
423
424         /* iterate through bsp brush sides */
425         for ( i = 0; i < brush->numSides; i++ )
426         {
427                 /* get side */
428                 side = &bspBrushSides[ brush->firstSide + i ];
429
430                 /* get shader */
431                 if ( side->shaderNum < 0 || side->shaderNum >= numBSPShaders ) {
432                         continue;
433                 }
434                 shader = &bspShaders[ side->shaderNum ];
435                 //"noshader" happens on modelclip and unwanted sides ( usually breaking complex brushes )
436                 if( !Q_stricmp( shader->shader, "default" ) || ( !Q_stricmp( shader->shader, "noshader" ) && !modelclip ) )
437                         continue;
438
439                 /* add build side */
440                 buildSide = &buildBrush->sides[ buildBrush->numsides ];
441                 buildBrush->numsides++;
442
443                 /* tag it */
444                 buildSide->shaderInfo = ShaderInfoForShader( shader->shader );
445                 buildSide->planenum = side->planeNum;
446                 buildSide->winding = NULL;
447         }
448
449         /* make brush windings */
450         if ( !CreateBrushWindings( buildBrush ) ) {
451                 //Sys_Printf( "CreateBrushWindings failed\n" );
452                 return;
453         }
454
455         /* start brush */
456         fprintf( f, "\t// brush %d\n", num );
457         fprintf( f, "\t{\n" );
458         if ( brushPrimitives ) {
459                 fprintf( f, "\tbrushDef\n" );
460                 fprintf( f, "\t{\n" );
461         }
462
463         /* iterate through build brush sides */
464         for ( i = 0; i < buildBrush->numsides; i++ )
465         {
466                 /* get build side */
467                 buildSide = &buildBrush->sides[ i ];
468
469                 /* get plane */
470                 buildPlane = &mapplanes[ buildSide->planenum ];
471
472                 /* dummy check */
473                 if ( buildSide->shaderInfo == NULL || buildSide->winding == NULL ) {
474                         continue;
475                 }
476
477                 // st-texcoords -> texMat block
478                 // start out with dummy
479                 VectorSet( buildSide->texMat[0], 1 / 32.0, 0, 0 );
480                 VectorSet( buildSide->texMat[1], 0, 1 / 32.0, 0 );
481
482                 // find surface for this side (by brute force)
483                 // surface format:
484                 //   - meshverts point in pairs of three into verts
485                 //   - (triangles)
486                 //   - find the triangle that has most in common with our side
487                 GetBestSurfaceTriangleMatchForBrushside( buildSide, vert );
488
489                 /* get texture name */
490                 if ( !Q_strncasecmp( buildSide->shaderInfo->shader, "textures/", 9 ) ) {
491                         texture = buildSide->shaderInfo->shader + 9;
492                 }
493                 else{
494                         texture = buildSide->shaderInfo->shader;
495                 }
496
497                 /* recheck and fix winding points, fails occur somehow */
498                 int match = 0;
499                 for ( j = 0; j < buildSide->winding->numpoints; j++ ){
500                         if ( fabs( DotProduct( buildSide->winding->p[ j ], buildPlane->normal ) - buildPlane->dist ) >= distanceEpsilon ) {
501                                 continue;
502                         }
503                         else{
504                                 VectorCopy( buildSide->winding->p[ j ], pts[ match ] );
505                                 match++;
506                                 /* got 3 fine points? */
507                                 if( match > 2 )
508                                         break;
509                         }
510                 }
511
512                 if( match > 2 ){
513                         //Sys_Printf( "pointsKK " );
514                         vec4_t testplane;
515                         if ( PlaneFromPoints( testplane, pts[0], pts[1], pts[2] ) ){
516                                 if( !PlaneEqual( buildPlane, testplane, testplane[3] ) ){
517                                         //Sys_Printf( "1: %f %f %f %f\n2: %f %f %f %f\n", buildPlane->normal[0], buildPlane->normal[1], buildPlane->normal[2], buildPlane->dist, testplane[0], testplane[1], testplane[2], testplane[3] );
518                                         match--;
519                                         //Sys_Printf( "planentEQ " );
520                                 }
521                         }
522                         else{
523                                 match--;
524                         }
525                 }
526
527
528                 if( match > 2 ){
529                         //Sys_Printf( "ok " );
530                         /* offset by origin */
531                         for ( j = 0; j < 3; j++ )
532                                 VectorAdd( pts[ j ], origin, pts[ j ] );
533                 }
534                 else{
535                         vec3_t vecs[ 2 ];
536                         MakeNormalVectors( buildPlane->normal, vecs[ 0 ], vecs[ 1 ] );
537                         VectorMA( vec3_origin, buildPlane->dist, buildPlane->normal, pts[ 0 ] );
538                         VectorAdd( pts[ 0 ], origin, pts[ 0 ] );
539                         VectorMA( pts[ 0 ], 256.0f, vecs[ 0 ], pts[ 1 ] );
540                         VectorMA( pts[ 0 ], 256.0f, vecs[ 1 ], pts[ 2 ] );
541                         //Sys_Printf( "not\n" );
542                 }
543
544                 if ( vert[0] && vert[1] && vert[2] ) {
545                         if ( brushPrimitives ) {
546                                 int i;
547                                 vec3_t texX, texY;
548                                 vec2_t xyI, xyJ, xyK;
549                                 vec2_t stI, stJ, stK;
550                                 vec_t D, D0, D1, D2;
551
552                                 ComputeAxisBase( buildPlane->normal, texX, texY );
553
554                                 xyI[0] = DotProduct( vert[0]->xyz, texX );
555                                 xyI[1] = DotProduct( vert[0]->xyz, texY );
556                                 xyJ[0] = DotProduct( vert[1]->xyz, texX );
557                                 xyJ[1] = DotProduct( vert[1]->xyz, texY );
558                                 xyK[0] = DotProduct( vert[2]->xyz, texX );
559                                 xyK[1] = DotProduct( vert[2]->xyz, texY );
560                                 stI[0] = vert[0]->st[0]; stI[1] = vert[0]->st[1];
561                                 stJ[0] = vert[1]->st[0]; stJ[1] = vert[1]->st[1];
562                                 stK[0] = vert[2]->st[0]; stK[1] = vert[2]->st[1];
563
564                                 //   - solve linear equations:
565                                 //     - (x, y) := xyz . (texX, texY)
566                                 //     - st[i] = texMat[i][0]*x + texMat[i][1]*y + texMat[i][2]
567                                 //       (for three vertices)
568                                 D = Det3x3(
569                                         xyI[0], xyI[1], 1,
570                                         xyJ[0], xyJ[1], 1,
571                                         xyK[0], xyK[1], 1
572                                         );
573                                 if ( D != 0 ) {
574                                         for ( i = 0; i < 2; ++i )
575                                         {
576                                                 D0 = Det3x3(
577                                                         stI[i], xyI[1], 1,
578                                                         stJ[i], xyJ[1], 1,
579                                                         stK[i], xyK[1], 1
580                                                         );
581                                                 D1 = Det3x3(
582                                                         xyI[0], stI[i], 1,
583                                                         xyJ[0], stJ[i], 1,
584                                                         xyK[0], stK[i], 1
585                                                         );
586                                                 D2 = Det3x3(
587                                                         xyI[0], xyI[1], stI[i],
588                                                         xyJ[0], xyJ[1], stJ[i],
589                                                         xyK[0], xyK[1], stK[i]
590                                                         );
591                                                 VectorSet( buildSide->texMat[i], D0 / D, D1 / D, D2 / D );
592                                         }
593                                 }
594                                 else{
595                                         fprintf( stderr, "degenerate triangle found when solving texMat equations for\n(%f %f %f) (%f %f %f) (%f %f %f)\n( %f %f %f )\n( %f %f %f ) -> ( %f %f )\n( %f %f %f ) -> ( %f %f )\n( %f %f %f ) -> ( %f %f )\n",
596                                                          buildPlane->normal[0], buildPlane->normal[1], buildPlane->normal[2],
597                                                          vert[0]->normal[0], vert[0]->normal[1], vert[0]->normal[2],
598                                                          texX[0], texX[1], texX[2], texY[0], texY[1], texY[2],
599                                                          vert[0]->xyz[0], vert[0]->xyz[1], vert[0]->xyz[2], xyI[0], xyI[1],
600                                                          vert[1]->xyz[0], vert[1]->xyz[1], vert[1]->xyz[2], xyJ[0], xyJ[1],
601                                                          vert[2]->xyz[0], vert[2]->xyz[1], vert[2]->xyz[2], xyK[0], xyK[1]
602                                                          );
603                                 }
604
605                                 /* print brush side */
606                                 /* ( 640 24 -224 ) ( 448 24 -224 ) ( 448 -232 -224 ) common/caulk 0 48 0 0.500000 0.500000 0 0 0 */
607                                 fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( ( %.8f %.8f %.8f ) ( %.8f %.8f %.8f ) ) %s %d 0 0\n",
608                                                  pts[ 0 ][ 0 ], pts[ 0 ][ 1 ], pts[ 0 ][ 2 ],
609                                                  pts[ 1 ][ 0 ], pts[ 1 ][ 1 ], pts[ 1 ][ 2 ],
610                                                  pts[ 2 ][ 0 ], pts[ 2 ][ 1 ], pts[ 2 ][ 2 ],
611                                                  buildSide->texMat[0][0], buildSide->texMat[0][1], FRAC( buildSide->texMat[0][2] ),
612                                                  buildSide->texMat[1][0], buildSide->texMat[1][1], FRAC( buildSide->texMat[1][2] ),
613                                                  texture,
614                                                  0
615                                                  );
616                         }
617                         else
618                         {
619                                 // invert QuakeTextureVecs
620                                 int i;
621                                 vec3_t vecs[2];
622                                 int sv, tv;
623                                 vec2_t stI, stJ, stK;
624                                 vec3_t sts[2];
625                                 vec2_t shift, scale;
626                                 vec_t rotate;
627                                 vec_t D, D0, D1, D2;
628
629                                 TextureAxisFromPlane( buildPlane, vecs[0], vecs[1] );
630                                 if ( vecs[0][0] ) {
631                                         sv = 0;
632                                 }
633                                 else if ( vecs[0][1] ) {
634                                         sv = 1;
635                                 }
636                                 else{
637                                         sv = 2;
638                                 }
639                                 if ( vecs[1][0] ) {
640                                         tv = 0;
641                                 }
642                                 else if ( vecs[1][1] ) {
643                                         tv = 1;
644                                 }
645                                 else{
646                                         tv = 2;
647                                 }
648
649                                 stI[0] = vert[0]->st[0] * buildSide->shaderInfo->shaderWidth; stI[1] = vert[0]->st[1] * buildSide->shaderInfo->shaderHeight;
650                                 stJ[0] = vert[1]->st[0] * buildSide->shaderInfo->shaderWidth; stJ[1] = vert[1]->st[1] * buildSide->shaderInfo->shaderHeight;
651                                 stK[0] = vert[2]->st[0] * buildSide->shaderInfo->shaderWidth; stK[1] = vert[2]->st[1] * buildSide->shaderInfo->shaderHeight;
652
653                                 D = Det3x3(
654                                         vert[0]->xyz[sv], vert[0]->xyz[tv], 1,
655                                         vert[1]->xyz[sv], vert[1]->xyz[tv], 1,
656                                         vert[2]->xyz[sv], vert[2]->xyz[tv], 1
657                                         );
658                                 if ( D != 0 ) {
659                                         for ( i = 0; i < 2; ++i )
660                                         {
661                                                 D0 = Det3x3(
662                                                         stI[i], vert[0]->xyz[tv], 1,
663                                                         stJ[i], vert[1]->xyz[tv], 1,
664                                                         stK[i], vert[2]->xyz[tv], 1
665                                                         );
666                                                 D1 = Det3x3(
667                                                         vert[0]->xyz[sv], stI[i], 1,
668                                                         vert[1]->xyz[sv], stJ[i], 1,
669                                                         vert[2]->xyz[sv], stK[i], 1
670                                                         );
671                                                 D2 = Det3x3(
672                                                         vert[0]->xyz[sv], vert[0]->xyz[tv], stI[i],
673                                                         vert[1]->xyz[sv], vert[1]->xyz[tv], stJ[i],
674                                                         vert[2]->xyz[sv], vert[2]->xyz[tv], stK[i]
675                                                         );
676                                                 VectorSet( sts[i], D0 / D, D1 / D, D2 / D );
677                                         }
678                                 }
679                                 else{
680                                         fprintf( stderr, "degenerate triangle found when solving texDef equations\n" ); // FIXME add stuff here
681
682                                 }
683                                 // now we must solve:
684                                 //      // now we must invert:
685                                 //      ang = rotate / 180 * Q_PI;
686                                 //      sinv = sin(ang);
687                                 //      cosv = cos(ang);
688                                 //      ns = cosv * vecs[0][sv];
689                                 //      nt = sinv * vecs[0][sv];
690                                 //      vecsrotscaled[0][sv] = ns / scale[0];
691                                 //      vecsrotscaled[0][tv] = nt / scale[0];
692                                 //      ns = -sinv * vecs[1][tv];
693                                 //      nt =  cosv * vecs[1][tv];
694                                 //      vecsrotscaled[1][sv] = ns / scale[1];
695                                 //      vecsrotscaled[1][tv] = nt / scale[1];
696                                 scale[0] = 1.0 / sqrt( sts[0][0] * sts[0][0] + sts[0][1] * sts[0][1] );
697                                 scale[1] = 1.0 / sqrt( sts[1][0] * sts[1][0] + sts[1][1] * sts[1][1] );
698                                 rotate = atan2( sts[0][1] * vecs[0][sv] - sts[1][0] * vecs[1][tv], sts[0][0] * vecs[0][sv] + sts[1][1] * vecs[1][tv] ) * ( 180.0f / Q_PI );
699                                 shift[0] = buildSide->shaderInfo->shaderWidth * FRAC( sts[0][2] / buildSide->shaderInfo->shaderWidth );
700                                 shift[1] = buildSide->shaderInfo->shaderHeight * FRAC( sts[1][2] / buildSide->shaderInfo->shaderHeight );
701
702                                 /* print brush side */
703                                 /* ( 640 24 -224 ) ( 448 24 -224 ) ( 448 -232 -224 ) common/caulk 0 48 0 0.500000 0.500000 0 0 0 */
704                                 fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) %s %.8f %.8f %.8f %.8f %.8f %d 0 0\n",
705                                                  pts[ 0 ][ 0 ], pts[ 0 ][ 1 ], pts[ 0 ][ 2 ],
706                                                  pts[ 1 ][ 0 ], pts[ 1 ][ 1 ], pts[ 1 ][ 2 ],
707                                                  pts[ 2 ][ 0 ], pts[ 2 ][ 1 ], pts[ 2 ][ 2 ],
708                                                  texture,
709                                                  shift[0], shift[1], rotate, scale[0], scale[1],
710                                                  0
711                                                  );
712                         }
713                 }
714                 else
715                 {
716                         //vec3_t vecs[ 2 ];
717                         if ( strncmp( buildSide->shaderInfo->shader, "textures/common/", 16 ) ) {
718                                 if ( strcmp( buildSide->shaderInfo->shader, "noshader" ) ) {
719                                         if ( strcmp( buildSide->shaderInfo->shader, "default" ) ) {
720                                                 //fprintf( stderr, "no matching triangle for brushside using %s (hopefully nobody can see this side anyway)\n", buildSide->shaderInfo->shader );
721                                                 texture = "common/WTF";
722                                         }
723                                 }
724                         }
725 /*
726                         MakeNormalVectors( buildPlane->normal, vecs[ 0 ], vecs[ 1 ] );
727                         VectorMA( vec3_origin, buildPlane->dist, buildPlane->normal, pts[ 0 ] );
728                         VectorMA( pts[ 0 ], 256.0f, vecs[ 1 ], pts[ 2 ] );
729                         VectorMA( pts[ 0 ], 256.0f, vecs[ 0 ], pts[ 1 ] );
730 */
731                         if ( brushPrimitives ) {
732                                 fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( ( %.8f %.8f %.8f ) ( %.8f %.8f %.8f ) ) %s %d 0 0\n",
733                                                  pts[ 0 ][ 0 ], pts[ 0 ][ 1 ], pts[ 0 ][ 2 ],
734                                                  pts[ 1 ][ 0 ], pts[ 1 ][ 1 ], pts[ 1 ][ 2 ],
735                                                  pts[ 2 ][ 0 ], pts[ 2 ][ 1 ], pts[ 2 ][ 2 ],
736                                                  1.0f / 16.0f, 0.0f, 0.0f,
737                                                  0.0f, 1.0f / 16.0f, 0.0f,
738                                                  texture,
739                                                  0
740                                                  );
741                         }
742                         else
743                         {
744                                 fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) %s %.8f %.8f %.8f %.8f %.8f %d 0 0\n",
745                                                  pts[ 0 ][ 0 ], pts[ 0 ][ 1 ], pts[ 0 ][ 2 ],
746                                                  pts[ 1 ][ 0 ], pts[ 1 ][ 1 ], pts[ 1 ][ 2 ],
747                                                  pts[ 2 ][ 0 ], pts[ 2 ][ 1 ], pts[ 2 ][ 2 ],
748                                                  texture,
749                                                  0.0f, 0.0f, 0.0f, 0.25f, 0.25f,
750                                                  0
751                                                  );
752                         }
753                 }
754         }
755
756         /* end brush */
757         if ( brushPrimitives ) {
758                 fprintf( f, "\t}\n" );
759         }
760         fprintf( f, "\t}\n\n" );
761 }
762 #undef FRAC
763
764 #if 0
765 /* iterate through the brush sides (ignore the first 6 bevel planes) */
766 for ( i = 0; i < brush->numSides; i++ )
767 {
768         /* get side */
769         side = &bspBrushSides[ brush->firstSide + i ];
770
771         /* get shader */
772         if ( side->shaderNum < 0 || side->shaderNum >= numBSPShaders ) {
773                 continue;
774         }
775         shader = &bspShaders[ side->shaderNum ];
776         if ( !Q_stricmp( shader->shader, "default" ) || !Q_stricmp( shader->shader, "noshader" ) ) {
777                 continue;
778         }
779
780         /* get texture name */
781         if ( !Q_strncasecmp( shader->shader, "textures/", 9 ) ) {
782                 texture = shader->shader + 9;
783         }
784         else{
785                 texture = shader->shader;
786         }
787
788         /* get plane */
789         plane = &bspPlanes[ side->planeNum ];
790
791         /* make plane points */
792         {
793                 vec3_t vecs[ 2 ];
794
795
796                 MakeNormalVectors( plane->normal, vecs[ 0 ], vecs[ 1 ] );
797                 VectorMA( vec3_origin, plane->dist, plane->normal, pts[ 0 ] );
798                 VectorMA( pts[ 0 ], 256.0f, vecs[ 0 ], pts[ 1 ] );
799                 VectorMA( pts[ 0 ], 256.0f, vecs[ 1 ], pts[ 2 ] );
800         }
801
802         /* offset by origin */
803         for ( j = 0; j < 3; j++ )
804                 VectorAdd( pts[ j ], origin, pts[ j ] );
805
806         /* print brush side */
807         /* ( 640 24 -224 ) ( 448 24 -224 ) ( 448 -232 -224 ) common/caulk 0 48 0 0.500000 0.500000 0 0 0 */
808         fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) %s 0 0 0 0.5 0.5 0 0 0\n",
809                          pts[ 0 ][ 0 ], pts[ 0 ][ 1 ], pts[ 0 ][ 2 ],
810                          pts[ 1 ][ 0 ], pts[ 1 ][ 1 ], pts[ 1 ][ 2 ],
811                          pts[ 2 ][ 0 ], pts[ 2 ][ 1 ], pts[ 2 ][ 2 ],
812                          texture );
813 }
814 #endif
815
816
817
818 /*
819    ConvertPatch()
820    converts a bsp patch to a map patch
821
822     {
823         patchDef2
824         {
825             base_wall/concrete
826             ( 9 3 0 0 0 )
827             (
828                 ( ( 168 168 -192 0 2 ) ( 168 168 -64 0 1 ) ( 168 168 64 0 0 ) ... )
829                 ...
830             )
831         }
832     }
833
834  */
835
836 static void ConvertPatch( FILE *f, int num, bspDrawSurface_t *ds, vec3_t origin ){
837         int x, y;
838         bspShader_t     *shader;
839         char            *texture;
840         bspDrawVert_t   *dv;
841         vec3_t xyz;
842
843
844         /* only patches */
845         if ( ds->surfaceType != MST_PATCH ) {
846                 return;
847         }
848
849         /* get shader */
850         if ( ds->shaderNum < 0 || ds->shaderNum >= numBSPShaders ) {
851                 return;
852         }
853         shader = &bspShaders[ ds->shaderNum ];
854
855         /* get texture name */
856         if ( !Q_strncasecmp( shader->shader, "textures/", 9 ) ) {
857                 texture = shader->shader + 9;
858         }
859         else{
860                 texture = shader->shader;
861         }
862
863         /* start patch */
864         fprintf( f, "\t// patch %d\n", num );
865         fprintf( f, "\t{\n" );
866         fprintf( f, "\t\tpatchDef2\n" );
867         fprintf( f, "\t\t{\n" );
868         fprintf( f, "\t\t\t%s\n", texture );
869         fprintf( f, "\t\t\t( %d %d 0 0 0 )\n", ds->patchWidth, ds->patchHeight );
870         fprintf( f, "\t\t\t(\n" );
871
872         /* iterate through the verts */
873         for ( x = 0; x < ds->patchWidth; x++ )
874         {
875                 /* start row */
876                 fprintf( f, "\t\t\t\t(" );
877
878                 /* iterate through the row */
879                 for ( y = 0; y < ds->patchHeight; y++ )
880                 {
881                         /* get vert */
882                         dv = &bspDrawVerts[ ds->firstVert + ( y * ds->patchWidth ) + x ];
883
884                         /* offset it */
885                         VectorAdd( origin, dv->xyz, xyz );
886
887                         /* print vertex */
888                         fprintf( f, " ( %f %f %f %f %f )", xyz[ 0 ], xyz[ 1 ], xyz[ 2 ], dv->st[ 0 ], dv->st[ 1 ] );
889                 }
890
891                 /* end row */
892                 fprintf( f, " )\n" );
893         }
894
895         /* end patch */
896         fprintf( f, "\t\t\t)\n" );
897         fprintf( f, "\t\t}\n" );
898         fprintf( f, "\t}\n\n" );
899 }
900
901
902
903 /*
904    ConvertModel()
905    exports a bsp model to a map file
906  */
907
908 static void ConvertModel( FILE *f, bspModel_t *model, int modelNum, vec3_t origin, qboolean brushPrimitives ){
909         int i, num;
910         bspBrush_t          *brush;
911         bspDrawSurface_t    *ds;
912
913
914         /* convert bsp planes to map planes */
915         nummapplanes = numBSPPlanes;
916         AUTOEXPAND_BY_REALLOC( mapplanes, nummapplanes, allocatedmapplanes, 1024 );
917         for ( i = 0; i < numBSPPlanes; i++ )
918         {
919                 VectorCopy( bspPlanes[ i ].normal, mapplanes[ i ].normal );
920                 mapplanes[ i ].dist = bspPlanes[ i ].dist;
921                 mapplanes[ i ].type = PlaneTypeForNormal( mapplanes[ i ].normal );
922                 mapplanes[ i ].hash_chain = 0;
923         }
924
925         /* allocate a build brush */
926         buildBrush = AllocBrush( 512 );
927         buildBrush->entityNum = 0;
928         buildBrush->original = buildBrush;
929
930         if ( origin[0] != 0 || origin[1] != 0 || origin[2] != 0 ) {
931                 ConvertOriginBrush( f, -1, origin, brushPrimitives );
932         }
933
934         /* go through each brush in the model */
935         for ( i = 0; i < model->numBSPBrushes; i++ )
936         {
937                 num = i + model->firstBSPBrush;
938                 brush = &bspBrushes[ num ];
939                 if( fast ){
940                         ConvertBrushFast( f, num, brush, origin, brushPrimitives );
941                 }
942                 else{
943                         ConvertBrush( f, num, brush, origin, brushPrimitives );
944                 }
945         }
946
947         /* free the build brush */
948         free( buildBrush );
949
950         /* go through each drawsurf in the model */
951         for ( i = 0; i < model->numBSPSurfaces; i++ )
952         {
953                 num = i + model->firstBSPSurface;
954                 ds = &bspDrawSurfaces[ num ];
955
956                 /* we only love patches */
957                 if ( ds->surfaceType == MST_PATCH ) {
958                         ConvertPatch( f, num, ds, origin );
959                 }
960         }
961 }
962
963
964
965 /*
966    ConvertEPairs()
967    exports entity key/value pairs to a map file
968  */
969
970 static void ConvertEPairs( FILE *f, entity_t *e, qboolean skip_origin ){
971         epair_t *ep;
972
973
974         /* walk epairs */
975         for ( ep = e->epairs; ep != NULL; ep = ep->next )
976         {
977                 /* ignore empty keys/values */
978                 if ( ep->key[ 0 ] == '\0' || ep->value[ 0 ] == '\0' ) {
979                         continue;
980                 }
981
982                 /* ignore model keys with * prefixed values */
983                 if ( !Q_stricmp( ep->key, "model" ) && ep->value[ 0 ] == '*' ) {
984                         continue;
985                 }
986
987                 /* ignore origin keys if skip_origin is set */
988                 if ( skip_origin && !Q_stricmp( ep->key, "origin" ) ) {
989                         continue;
990                 }
991
992                 /* emit the epair */
993                 fprintf( f, "\t\"%s\" \"%s\"\n", ep->key, ep->value );
994         }
995 }
996
997
998
999 /*
1000    ConvertBSPToMap()
1001    exports an quake map file from the bsp
1002  */
1003
1004 int ConvertBSPToMap_Ext( char *bspName, qboolean brushPrimitives ){
1005         int i, modelNum;
1006         FILE            *f;
1007         bspModel_t      *model;
1008         entity_t        *e;
1009         vec3_t origin;
1010         const char      *value;
1011         char name[ 1024 ], base[ 1024 ];
1012
1013
1014         /* note it */
1015         Sys_Printf( "--- Convert BSP to MAP ---\n" );
1016
1017         /* create the bsp filename from the bsp name */
1018         strcpy( name, bspName );
1019         StripExtension( name );
1020         strcat( name, "_converted.map" );
1021         Sys_Printf( "writing %s\n", name );
1022
1023         ExtractFileBase( bspName, base );
1024         strcat( base, ".bsp" );
1025
1026         /* open it */
1027         f = fopen( name, "wb" );
1028         if ( f == NULL ) {
1029                 Error( "Open failed on %s\n", name );
1030         }
1031
1032         /* print header */
1033         fprintf( f, "// Generated by Q3Map2 (ydnar) -convert -format map\n" );
1034
1035         /* walk entity list */
1036         for ( i = 0; i < numEntities; i++ )
1037         {
1038                 /* get entity */
1039                 e = &entities[ i ];
1040
1041                 /* start entity */
1042                 fprintf( f, "// entity %d\n", i );
1043                 fprintf( f, "{\n" );
1044
1045                 /* get model num */
1046                 if ( i == 0 ) {
1047                         modelNum = 0;
1048                 }
1049                 else
1050                 {
1051                         value = ValueForKey( e, "model" );
1052                         if ( value[ 0 ] == '*' ) {
1053                                 modelNum = atoi( value + 1 );
1054                         }
1055                         else{
1056                                 modelNum = -1;
1057                         }
1058                 }
1059
1060                 /* export keys */
1061                 ConvertEPairs( f, e, modelNum >= 0 );
1062                 fprintf( f, "\n" );
1063
1064                 /* only handle bsp models */
1065                 if ( modelNum >= 0 ) {
1066                         /* get model */
1067                         model = &bspModels[ modelNum ];
1068
1069                         /* get entity origin */
1070                         value = ValueForKey( e, "origin" );
1071                         if ( value[ 0 ] == '\0' ) {
1072                                 VectorClear( origin );
1073                         }
1074                         else{
1075                                 GetVectorForKey( e, "origin", origin );
1076                         }
1077
1078                         /* convert model */
1079                         ConvertModel( f, model, modelNum, origin, brushPrimitives );
1080                 }
1081
1082                 /* end entity */
1083                 fprintf( f, "}\n\n" );
1084         }
1085
1086         /* close the file and return */
1087         fclose( f );
1088
1089         /* return to sender */
1090         return 0;
1091 }
1092
1093 int ConvertBSPToMap( char *bspName ){
1094         return ConvertBSPToMap_Ext( bspName, qfalse );
1095 }
1096
1097 int ConvertBSPToMap_BP( char *bspName ){
1098         return ConvertBSPToMap_Ext( bspName, qtrue );
1099 }