]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake3/q3map2/convert_map.c
q3map2: use ~/Library/Application Support on Mac
[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 ); if ( VectorLength( normdiff ) >= normalEpsilon ) {
92                                         continue;
93                                 }
94                                 VectorSubtract( vert[1]->normal, buildPlane->normal, normdiff ); if ( VectorLength( normdiff ) >= normalEpsilon ) {
95                                         continue;
96                                 }
97                                 VectorSubtract( vert[2]->normal, buildPlane->normal, normdiff ); if ( VectorLength( normdiff ) >= normalEpsilon ) {
98                                         continue;
99                                 }
100                         }
101                         else
102                         {
103                                 // this is more prone to roundoff errors, but with embedded
104                                 // models, there is no better way
105                                 VectorSubtract( vert[1]->xyz, vert[0]->xyz, v1v0 );
106                                 VectorSubtract( vert[2]->xyz, vert[0]->xyz, v2v0 );
107                                 CrossProduct( v2v0, v1v0, norm );
108                                 VectorNormalize( norm, norm );
109                                 VectorSubtract( norm, buildPlane->normal, normdiff ); if ( VectorLength( normdiff ) >= normalEpsilon ) {
110                                         continue;
111                                 }
112                         }
113                         if ( abs( DotProduct( vert[0]->xyz, buildPlane->normal ) - buildPlane->dist ) >= distanceEpsilon ) {
114                                 continue;
115                         }
116                         if ( abs( DotProduct( vert[1]->xyz, buildPlane->normal ) - buildPlane->dist ) >= distanceEpsilon ) {
117                                 continue;
118                         }
119                         if ( abs( DotProduct( vert[2]->xyz, buildPlane->normal ) - buildPlane->dist ) >= distanceEpsilon ) {
120                                 continue;
121                         }
122                         // Okay. Correct surface type, correct shader, correct plane. Let's start with the business...
123                         polygon = CopyWinding( buildSide->winding );
124                         for ( i = 0; i < 3; ++i )
125                         {
126                                 // 0: 1, 2
127                                 // 1: 2, 0
128                                 // 2; 0, 1
129                                 vec3_t *v1 = &vert[( i + 1 ) % 3]->xyz;
130                                 vec3_t *v2 = &vert[( i + 2 ) % 3]->xyz;
131                                 vec3_t triNormal;
132                                 vec_t triDist;
133                                 vec3_t sideDirection;
134                                 // we now need to generate triNormal and triDist so that they represent the plane spanned by normal and (v2 - v1).
135                                 VectorSubtract( *v2, *v1, sideDirection );
136                                 CrossProduct( sideDirection, buildPlane->normal, triNormal );
137                                 triDist = DotProduct( *v1, triNormal );
138                                 ChopWindingInPlace( &polygon, triNormal, triDist, distanceEpsilon );
139                                 if ( !polygon ) {
140                                         goto exwinding;
141                                 }
142                         }
143                         thisarea = WindingArea( polygon );
144                         if ( thisarea > 0 ) {
145                                 ++matches;
146                         }
147                         if ( thisarea > best ) {
148                                 best = thisarea;
149                                 bestVert[0] = vert[0];
150                                 bestVert[1] = vert[1];
151                                 bestVert[2] = vert[2];
152                         }
153                         FreeWinding( polygon );
154 exwinding:
155                         ;
156                 }
157         }
158         //if(strncmp(buildSide->shaderInfo->shader, "textures/common/", 16))
159         //      fprintf(stderr, "brushside with %s: %d matches (%f area)\n", buildSide->shaderInfo->shader, matches, best);
160 }
161
162 #define FRAC( x ) ( ( x ) - floor( x ) )
163 static void ConvertOriginBrush( FILE *f, int num, vec3_t origin, qboolean brushPrimitives ){
164         int originSize = 256;
165
166         char pattern[6][7][3] = {
167                 { "+++", "+-+", "-++", "-  ", " + ", " - ", "-  " },
168                 { "+++", "-++", "++-", "-  ", "  +", "+  ", "  +" },
169                 { "+++", "++-", "+-+", " - ", "  +", " - ", "  +" },
170                 { "---", "+--", "-+-", "-  ", " + ", " - ", "+  " },
171                 { "---", "--+", "+--", "-  ", "  +", "-  ", "  +" },
172                 { "---", "-+-", "--+", " - ", "  +", " + ", "  +" }
173         };
174         int i;
175 #define S( a,b,c ) ( pattern[a][b][c] == '+' ? +1 : pattern[a][b][c] == '-' ? -1 : 0 )
176
177         /* start brush */
178         fprintf( f, "\t// brush %d\n", num );
179         fprintf( f, "\t{\n" );
180         if ( brushPrimitives ) {
181                 fprintf( f, "\tbrushDef\n" );
182                 fprintf( f, "\t{\n" );
183         }
184         /* print brush side */
185         /* ( 640 24 -224 ) ( 448 24 -224 ) ( 448 -232 -224 ) common/caulk 0 48 0 0.500000 0.500000 0 0 0 */
186
187         for ( i = 0; i < 6; ++i )
188         {
189                 if ( brushPrimitives ) {
190                         fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( ( %.8f %.8f %.8f ) ( %.8f %.8f %.8f ) ) %s %d 0 0\n",
191                                          origin[0] + 8 * S( i,0,0 ), origin[1] + 8 * S( i,0,1 ), origin[2] + 8 * S( i,0,2 ),
192                                          origin[0] + 8 * S( i,1,0 ), origin[1] + 8 * S( i,1,1 ), origin[2] + 8 * S( i,1,2 ),
193                                          origin[0] + 8 * S( i,2,0 ), origin[1] + 8 * S( i,2,1 ), origin[2] + 8 * S( i,2,2 ),
194                                          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 ),
195                                          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 ),
196                                          "common/origin",
197                                          0
198                                          );
199                 }
200                 else
201                 {
202                         fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) %s %.8f %.8f %.8f %.8f %.8f %d 0 0\n",
203                                          origin[0] + 8 * S( i,0,0 ), origin[1] + 8 * S( i,0,1 ), origin[2] + 8 * S( i,0,2 ),
204                                          origin[0] + 8 * S( i,1,0 ), origin[1] + 8 * S( i,1,1 ), origin[2] + 8 * S( i,1,2 ),
205                                          origin[0] + 8 * S( i,2,0 ), origin[1] + 8 * S( i,2,1 ), origin[2] + 8 * S( i,2,2 ),
206                                          "common/origin",
207                                          FRAC( ( S( i,3,0 ) * origin[0] + S( i,3,1 ) * origin[1] + S( i,3,2 ) * origin[2] ) / 16.0 + 0.5 ) * originSize,
208                                          FRAC( ( S( i,4,0 ) * origin[0] + S( i,4,1 ) * origin[1] + S( i,4,2 ) * origin[2] ) / 16.0 + 0.5 ) * originSize,
209                                          0.0f, 16.0 / originSize, 16.0 / originSize,
210                                          0
211                                          );
212                 }
213         }
214 #undef S
215
216         /* end brush */
217         if ( brushPrimitives ) {
218                 fprintf( f, "\t}\n" );
219         }
220         fprintf( f, "\t}\n\n" );
221 }
222
223 static void ConvertBrush( FILE *f, int num, bspBrush_t *brush, vec3_t origin, qboolean brushPrimitives ){
224         int i, j;
225         bspBrushSide_t  *side;
226         side_t          *buildSide;
227         bspShader_t     *shader;
228         char            *texture;
229         plane_t         *buildPlane;
230         vec3_t pts[ 3 ];
231         bspDrawVert_t   *vert[3];
232
233
234         /* start brush */
235         fprintf( f, "\t// brush %d\n", num );
236         fprintf( f, "\t{\n" );
237         if ( brushPrimitives ) {
238                 fprintf( f, "\tbrushDef\n" );
239                 fprintf( f, "\t{\n" );
240         }
241
242         /* clear out build brush */
243         for ( i = 0; i < buildBrush->numsides; i++ )
244         {
245                 buildSide = &buildBrush->sides[ i ];
246                 if ( buildSide->winding != NULL ) {
247                         FreeWinding( buildSide->winding );
248                         buildSide->winding = NULL;
249                 }
250         }
251         buildBrush->numsides = 0;
252
253         /* iterate through bsp brush sides */
254         for ( i = 0; i < brush->numSides; i++ )
255         {
256                 /* get side */
257                 side = &bspBrushSides[ brush->firstSide + i ];
258
259                 /* get shader */
260                 if ( side->shaderNum < 0 || side->shaderNum >= numBSPShaders ) {
261                         continue;
262                 }
263                 shader = &bspShaders[ side->shaderNum ];
264                 //if( !Q_stricmp( shader->shader, "default" ) || !Q_stricmp( shader->shader, "noshader" ) )
265                 //      continue;
266
267                 /* add build side */
268                 buildSide = &buildBrush->sides[ buildBrush->numsides ];
269                 buildBrush->numsides++;
270
271                 /* tag it */
272                 buildSide->shaderInfo = ShaderInfoForShader( shader->shader );
273                 buildSide->planenum = side->planeNum;
274                 buildSide->winding = NULL;
275         }
276
277         /* make brush windings */
278         if ( !CreateBrushWindings( buildBrush ) ) {
279                 Sys_Printf( "CreateBrushWindings failed\n" );
280                 return;
281         }
282
283         /* iterate through build brush sides */
284         for ( i = 0; i < buildBrush->numsides; i++ )
285         {
286                 /* get build side */
287                 buildSide = &buildBrush->sides[ i ];
288
289                 /* get plane */
290                 buildPlane = &mapplanes[ buildSide->planenum ];
291
292                 /* dummy check */
293                 if ( buildSide->shaderInfo == NULL || buildSide->winding == NULL ) {
294                         continue;
295                 }
296
297                 // st-texcoords -> texMat block
298                 // start out with dummy
299                 VectorSet( buildSide->texMat[0], 1 / 32.0, 0, 0 );
300                 VectorSet( buildSide->texMat[1], 0, 1 / 32.0, 0 );
301
302                 // find surface for this side (by brute force)
303                 // surface format:
304                 //   - meshverts point in pairs of three into verts
305                 //   - (triangles)
306                 //   - find the triangle that has most in common with our side
307                 GetBestSurfaceTriangleMatchForBrushside( buildSide, vert );
308
309                 /* get texture name */
310                 if ( !Q_strncasecmp( buildSide->shaderInfo->shader, "textures/", 9 ) ) {
311                         texture = buildSide->shaderInfo->shader + 9;
312                 }
313                 else{
314                         texture = buildSide->shaderInfo->shader;
315                 }
316
317                 /* get plane points and offset by origin */
318                 for ( j = 0; j < 3; j++ )
319                 {
320                         VectorAdd( buildSide->winding->p[ j ], origin, pts[ j ] );
321                         //%     pts[ j ][ 0 ] = SNAP_INT_TO_FLOAT * floor( pts[ j ][ 0 ] * SNAP_FLOAT_TO_INT + 0.5f );
322                         //%     pts[ j ][ 1 ] = SNAP_INT_TO_FLOAT * floor( pts[ j ][ 1 ] * SNAP_FLOAT_TO_INT + 0.5f );
323                         //%     pts[ j ][ 2 ] = SNAP_INT_TO_FLOAT * floor( pts[ j ][ 2 ] * SNAP_FLOAT_TO_INT + 0.5f );
324                 }
325
326                 if ( vert[0] && vert[1] && vert[2] ) {
327                         if ( brushPrimitives ) {
328                                 int i;
329                                 vec3_t texX, texY;
330                                 vec2_t xyI, xyJ, xyK;
331                                 vec2_t stI, stJ, stK;
332                                 vec_t D, D0, D1, D2;
333
334                                 ComputeAxisBase( buildPlane->normal, texX, texY );
335
336                                 xyI[0] = DotProduct( vert[0]->xyz, texX );
337                                 xyI[1] = DotProduct( vert[0]->xyz, texY );
338                                 xyJ[0] = DotProduct( vert[1]->xyz, texX );
339                                 xyJ[1] = DotProduct( vert[1]->xyz, texY );
340                                 xyK[0] = DotProduct( vert[2]->xyz, texX );
341                                 xyK[1] = DotProduct( vert[2]->xyz, texY );
342                                 stI[0] = vert[0]->st[0]; stI[1] = vert[0]->st[1];
343                                 stJ[0] = vert[1]->st[0]; stJ[1] = vert[1]->st[1];
344                                 stK[0] = vert[2]->st[0]; stK[1] = vert[2]->st[1];
345
346                                 //   - solve linear equations:
347                                 //     - (x, y) := xyz . (texX, texY)
348                                 //     - st[i] = texMat[i][0]*x + texMat[i][1]*y + texMat[i][2]
349                                 //       (for three vertices)
350                                 D = Det3x3(
351                                         xyI[0], xyI[1], 1,
352                                         xyJ[0], xyJ[1], 1,
353                                         xyK[0], xyK[1], 1
354                                         );
355                                 if ( D != 0 ) {
356                                         for ( i = 0; i < 2; ++i )
357                                         {
358                                                 D0 = Det3x3(
359                                                         stI[i], xyI[1], 1,
360                                                         stJ[i], xyJ[1], 1,
361                                                         stK[i], xyK[1], 1
362                                                         );
363                                                 D1 = Det3x3(
364                                                         xyI[0], stI[i], 1,
365                                                         xyJ[0], stJ[i], 1,
366                                                         xyK[0], stK[i], 1
367                                                         );
368                                                 D2 = Det3x3(
369                                                         xyI[0], xyI[1], stI[i],
370                                                         xyJ[0], xyJ[1], stJ[i],
371                                                         xyK[0], xyK[1], stK[i]
372                                                         );
373                                                 VectorSet( buildSide->texMat[i], D0 / D, D1 / D, D2 / D );
374                                         }
375                                 }
376                                 else{
377                                         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",
378                                                          buildPlane->normal[0], buildPlane->normal[1], buildPlane->normal[2],
379                                                          vert[0]->normal[0], vert[0]->normal[1], vert[0]->normal[2],
380                                                          texX[0], texX[1], texX[2], texY[0], texY[1], texY[2],
381                                                          vert[0]->xyz[0], vert[0]->xyz[1], vert[0]->xyz[2], xyI[0], xyI[1],
382                                                          vert[1]->xyz[0], vert[1]->xyz[1], vert[1]->xyz[2], xyJ[0], xyJ[1],
383                                                          vert[2]->xyz[0], vert[2]->xyz[1], vert[2]->xyz[2], xyK[0], xyK[1]
384                                                          );
385                                 }
386
387                                 /* print brush side */
388                                 /* ( 640 24 -224 ) ( 448 24 -224 ) ( 448 -232 -224 ) common/caulk 0 48 0 0.500000 0.500000 0 0 0 */
389                                 fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( ( %.8f %.8f %.8f ) ( %.8f %.8f %.8f ) ) %s %d 0 0\n",
390                                                  pts[ 0 ][ 0 ], pts[ 0 ][ 1 ], pts[ 0 ][ 2 ],
391                                                  pts[ 1 ][ 0 ], pts[ 1 ][ 1 ], pts[ 1 ][ 2 ],
392                                                  pts[ 2 ][ 0 ], pts[ 2 ][ 1 ], pts[ 2 ][ 2 ],
393                                                  buildSide->texMat[0][0], buildSide->texMat[0][1], FRAC( buildSide->texMat[0][2] ),
394                                                  buildSide->texMat[1][0], buildSide->texMat[1][1], FRAC( buildSide->texMat[1][2] ),
395                                                  texture,
396                                                  0
397                                                  );
398                         }
399                         else
400                         {
401                                 // invert QuakeTextureVecs
402                                 int i;
403                                 vec3_t vecs[2];
404                                 int sv, tv;
405                                 vec2_t stI, stJ, stK;
406                                 vec3_t sts[2];
407                                 vec2_t shift, scale;
408                                 vec_t rotate;
409                                 vec_t D, D0, D1, D2;
410
411                                 TextureAxisFromPlane( buildPlane, vecs[0], vecs[1] );
412                                 if ( vecs[0][0] ) {
413                                         sv = 0;
414                                 }
415                                 else if ( vecs[0][1] ) {
416                                         sv = 1;
417                                 }
418                                 else{
419                                         sv = 2;
420                                 }
421                                 if ( vecs[1][0] ) {
422                                         tv = 0;
423                                 }
424                                 else if ( vecs[1][1] ) {
425                                         tv = 1;
426                                 }
427                                 else{
428                                         tv = 2;
429                                 }
430
431                                 stI[0] = vert[0]->st[0] * buildSide->shaderInfo->shaderWidth; stI[1] = vert[0]->st[1] * buildSide->shaderInfo->shaderHeight;
432                                 stJ[0] = vert[1]->st[0] * buildSide->shaderInfo->shaderWidth; stJ[1] = vert[1]->st[1] * buildSide->shaderInfo->shaderHeight;
433                                 stK[0] = vert[2]->st[0] * buildSide->shaderInfo->shaderWidth; stK[1] = vert[2]->st[1] * buildSide->shaderInfo->shaderHeight;
434
435                                 D = Det3x3(
436                                         vert[0]->xyz[sv], vert[0]->xyz[tv], 1,
437                                         vert[1]->xyz[sv], vert[1]->xyz[tv], 1,
438                                         vert[2]->xyz[sv], vert[2]->xyz[tv], 1
439                                         );
440                                 if ( D != 0 ) {
441                                         for ( i = 0; i < 2; ++i )
442                                         {
443                                                 D0 = Det3x3(
444                                                         stI[i], vert[0]->xyz[tv], 1,
445                                                         stJ[i], vert[1]->xyz[tv], 1,
446                                                         stK[i], vert[2]->xyz[tv], 1
447                                                         );
448                                                 D1 = Det3x3(
449                                                         vert[0]->xyz[sv], stI[i], 1,
450                                                         vert[1]->xyz[sv], stJ[i], 1,
451                                                         vert[2]->xyz[sv], stK[i], 1
452                                                         );
453                                                 D2 = Det3x3(
454                                                         vert[0]->xyz[sv], vert[0]->xyz[tv], stI[i],
455                                                         vert[1]->xyz[sv], vert[1]->xyz[tv], stJ[i],
456                                                         vert[2]->xyz[sv], vert[2]->xyz[tv], stK[i]
457                                                         );
458                                                 VectorSet( sts[i], D0 / D, D1 / D, D2 / D );
459                                         }
460                                 }
461                                 else{
462                                         fprintf( stderr, "degenerate triangle found when solving texDef equations\n" ); // FIXME add stuff here
463
464                                 }
465                                 // now we must solve:
466                                 //      // now we must invert:
467                                 //      ang = rotate / 180 * Q_PI;
468                                 //      sinv = sin(ang);
469                                 //      cosv = cos(ang);
470                                 //      ns = cosv * vecs[0][sv];
471                                 //      nt = sinv * vecs[0][sv];
472                                 //      vecsrotscaled[0][sv] = ns / scale[0];
473                                 //      vecsrotscaled[0][tv] = nt / scale[0];
474                                 //      ns = -sinv * vecs[1][tv];
475                                 //      nt =  cosv * vecs[1][tv];
476                                 //      vecsrotscaled[1][sv] = ns / scale[1];
477                                 //      vecsrotscaled[1][tv] = nt / scale[1];
478                                 scale[0] = 1.0 / sqrt( sts[0][0] * sts[0][0] + sts[0][1] * sts[0][1] );
479                                 scale[1] = 1.0 / sqrt( sts[1][0] * sts[1][0] + sts[1][1] * sts[1][1] );
480                                 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 );
481                                 shift[0] = buildSide->shaderInfo->shaderWidth * FRAC( sts[0][2] / buildSide->shaderInfo->shaderWidth );
482                                 shift[1] = buildSide->shaderInfo->shaderHeight * FRAC( sts[1][2] / buildSide->shaderInfo->shaderHeight );
483
484                                 /* print brush side */
485                                 /* ( 640 24 -224 ) ( 448 24 -224 ) ( 448 -232 -224 ) common/caulk 0 48 0 0.500000 0.500000 0 0 0 */
486                                 fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) %s %.8f %.8f %.8f %.8f %.8f %d 0 0\n",
487                                                  pts[ 0 ][ 0 ], pts[ 0 ][ 1 ], pts[ 0 ][ 2 ],
488                                                  pts[ 1 ][ 0 ], pts[ 1 ][ 1 ], pts[ 1 ][ 2 ],
489                                                  pts[ 2 ][ 0 ], pts[ 2 ][ 1 ], pts[ 2 ][ 2 ],
490                                                  texture,
491                                                  shift[0], shift[1], rotate, scale[0], scale[1],
492                                                  0
493                                                  );
494                         }
495                 }
496                 else
497                 {
498                         vec3_t vecs[ 2 ];
499                         if ( strncmp( buildSide->shaderInfo->shader, "textures/common/", 16 ) ) {
500                                 if ( strcmp( buildSide->shaderInfo->shader, "noshader" ) ) {
501                                         if ( strcmp( buildSide->shaderInfo->shader, "default" ) ) {
502                                                 fprintf( stderr, "no matching triangle for brushside using %s (hopefully nobody can see this side anyway)\n", buildSide->shaderInfo->shader );
503                                                 texture = "common/WTF";
504                                         }
505                                 }
506                         }
507
508                         MakeNormalVectors( buildPlane->normal, vecs[ 0 ], vecs[ 1 ] );
509                         VectorMA( vec3_origin, buildPlane->dist, buildPlane->normal, pts[ 0 ] );
510                         VectorMA( pts[ 0 ], 256.0f, vecs[ 0 ], pts[ 1 ] );
511                         VectorMA( pts[ 0 ], 256.0f, vecs[ 1 ], pts[ 2 ] );
512                         if ( brushPrimitives ) {
513                                 fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( ( %.8f %.8f %.8f ) ( %.8f %.8f %.8f ) ) %s %d 0 0\n",
514                                                  pts[ 0 ][ 0 ], pts[ 0 ][ 1 ], pts[ 0 ][ 2 ],
515                                                  pts[ 1 ][ 0 ], pts[ 1 ][ 1 ], pts[ 1 ][ 2 ],
516                                                  pts[ 2 ][ 0 ], pts[ 2 ][ 1 ], pts[ 2 ][ 2 ],
517                                                  1.0f / 16.0f, 0.0f, 0.0f,
518                                                  0.0f, 1.0f / 16.0f, 0.0f,
519                                                  texture,
520                                                  0
521                                                  );
522                         }
523                         else
524                         {
525                                 fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) %s %.8f %.8f %.8f %.8f %.8f %d 0 0\n",
526                                                  pts[ 0 ][ 0 ], pts[ 0 ][ 1 ], pts[ 0 ][ 2 ],
527                                                  pts[ 1 ][ 0 ], pts[ 1 ][ 1 ], pts[ 1 ][ 2 ],
528                                                  pts[ 2 ][ 0 ], pts[ 2 ][ 1 ], pts[ 2 ][ 2 ],
529                                                  texture,
530                                                  0.0f, 0.0f, 0.0f, 0.25f, 0.25f,
531                                                  0
532                                                  );
533                         }
534                 }
535         }
536
537         /* end brush */
538         if ( brushPrimitives ) {
539                 fprintf( f, "\t}\n" );
540         }
541         fprintf( f, "\t}\n\n" );
542 }
543 #undef FRAC
544
545 #if 0
546 /* iterate through the brush sides (ignore the first 6 bevel planes) */
547 for ( i = 0; i < brush->numSides; i++ )
548 {
549         /* get side */
550         side = &bspBrushSides[ brush->firstSide + i ];
551
552         /* get shader */
553         if ( side->shaderNum < 0 || side->shaderNum >= numBSPShaders ) {
554                 continue;
555         }
556         shader = &bspShaders[ side->shaderNum ];
557         if ( !Q_stricmp( shader->shader, "default" ) || !Q_stricmp( shader->shader, "noshader" ) ) {
558                 continue;
559         }
560
561         /* get texture name */
562         if ( !Q_strncasecmp( shader->shader, "textures/", 9 ) ) {
563                 texture = shader->shader + 9;
564         }
565         else{
566                 texture = shader->shader;
567         }
568
569         /* get plane */
570         plane = &bspPlanes[ side->planeNum ];
571
572         /* make plane points */
573         {
574                 vec3_t vecs[ 2 ];
575
576
577                 MakeNormalVectors( plane->normal, vecs[ 0 ], vecs[ 1 ] );
578                 VectorMA( vec3_origin, plane->dist, plane->normal, pts[ 0 ] );
579                 VectorMA( pts[ 0 ], 256.0f, vecs[ 0 ], pts[ 1 ] );
580                 VectorMA( pts[ 0 ], 256.0f, vecs[ 1 ], pts[ 2 ] );
581         }
582
583         /* offset by origin */
584         for ( j = 0; j < 3; j++ )
585                 VectorAdd( pts[ j ], origin, pts[ j ] );
586
587         /* print brush side */
588         /* ( 640 24 -224 ) ( 448 24 -224 ) ( 448 -232 -224 ) common/caulk 0 48 0 0.500000 0.500000 0 0 0 */
589         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",
590                          pts[ 0 ][ 0 ], pts[ 0 ][ 1 ], pts[ 0 ][ 2 ],
591                          pts[ 1 ][ 0 ], pts[ 1 ][ 1 ], pts[ 1 ][ 2 ],
592                          pts[ 2 ][ 0 ], pts[ 2 ][ 1 ], pts[ 2 ][ 2 ],
593                          texture );
594 }
595 #endif
596
597
598
599 /*
600    ConvertPatch()
601    converts a bsp patch to a map patch
602
603     {
604         patchDef2
605         {
606             base_wall/concrete
607             ( 9 3 0 0 0 )
608             (
609                 ( ( 168 168 -192 0 2 ) ( 168 168 -64 0 1 ) ( 168 168 64 0 0 ) ... )
610                 ...
611             )
612         }
613     }
614
615  */
616
617 static void ConvertPatch( FILE *f, int num, bspDrawSurface_t *ds, vec3_t origin ){
618         int x, y;
619         bspShader_t     *shader;
620         char            *texture;
621         bspDrawVert_t   *dv;
622         vec3_t xyz;
623
624
625         /* only patches */
626         if ( ds->surfaceType != MST_PATCH ) {
627                 return;
628         }
629
630         /* get shader */
631         if ( ds->shaderNum < 0 || ds->shaderNum >= numBSPShaders ) {
632                 return;
633         }
634         shader = &bspShaders[ ds->shaderNum ];
635
636         /* get texture name */
637         if ( !Q_strncasecmp( shader->shader, "textures/", 9 ) ) {
638                 texture = shader->shader + 9;
639         }
640         else{
641                 texture = shader->shader;
642         }
643
644         /* start patch */
645         fprintf( f, "\t// patch %d\n", num );
646         fprintf( f, "\t{\n" );
647         fprintf( f, "\t\tpatchDef2\n" );
648         fprintf( f, "\t\t{\n" );
649         fprintf( f, "\t\t\t%s\n", texture );
650         fprintf( f, "\t\t\t( %d %d 0 0 0 )\n", ds->patchWidth, ds->patchHeight );
651         fprintf( f, "\t\t\t(\n" );
652
653         /* iterate through the verts */
654         for ( x = 0; x < ds->patchWidth; x++ )
655         {
656                 /* start row */
657                 fprintf( f, "\t\t\t\t(" );
658
659                 /* iterate through the row */
660                 for ( y = 0; y < ds->patchHeight; y++ )
661                 {
662                         /* get vert */
663                         dv = &bspDrawVerts[ ds->firstVert + ( y * ds->patchWidth ) + x ];
664
665                         /* offset it */
666                         VectorAdd( origin, dv->xyz, xyz );
667
668                         /* print vertex */
669                         fprintf( f, " ( %f %f %f %f %f )", xyz[ 0 ], xyz[ 1 ], xyz[ 2 ], dv->st[ 0 ], dv->st[ 1 ] );
670                 }
671
672                 /* end row */
673                 fprintf( f, " )\n" );
674         }
675
676         /* end patch */
677         fprintf( f, "\t\t\t)\n" );
678         fprintf( f, "\t\t}\n" );
679         fprintf( f, "\t}\n\n" );
680 }
681
682
683
684 /*
685    ConvertModel()
686    exports a bsp model to a map file
687  */
688
689 static void ConvertModel( FILE *f, bspModel_t *model, int modelNum, vec3_t origin, qboolean brushPrimitives ){
690         int i, num;
691         bspBrush_t          *brush;
692         bspDrawSurface_t    *ds;
693
694
695         /* convert bsp planes to map planes */
696         nummapplanes = numBSPPlanes;
697         AUTOEXPAND_BY_REALLOC( mapplanes, nummapplanes, allocatedmapplanes, 1024 );
698         for ( i = 0; i < numBSPPlanes; i++ )
699         {
700                 VectorCopy( bspPlanes[ i ].normal, mapplanes[ i ].normal );
701                 mapplanes[ i ].dist = bspPlanes[ i ].dist;
702                 mapplanes[ i ].type = PlaneTypeForNormal( mapplanes[ i ].normal );
703                 mapplanes[ i ].hash_chain = 0;
704         }
705
706         /* allocate a build brush */
707         buildBrush = AllocBrush( 512 );
708         buildBrush->entityNum = 0;
709         buildBrush->original = buildBrush;
710
711         if ( origin[0] != 0 || origin[1] != 0 || origin[2] != 0 ) {
712                 ConvertOriginBrush( f, -1, origin, brushPrimitives );
713         }
714
715         /* go through each brush in the model */
716         for ( i = 0; i < model->numBSPBrushes; i++ )
717         {
718                 num = i + model->firstBSPBrush;
719                 brush = &bspBrushes[ num ];
720                 ConvertBrush( f, num, brush, origin, brushPrimitives );
721         }
722
723         /* free the build brush */
724         free( buildBrush );
725
726         /* go through each drawsurf in the model */
727         for ( i = 0; i < model->numBSPSurfaces; i++ )
728         {
729                 num = i + model->firstBSPSurface;
730                 ds = &bspDrawSurfaces[ num ];
731
732                 /* we only love patches */
733                 if ( ds->surfaceType == MST_PATCH ) {
734                         ConvertPatch( f, num, ds, origin );
735                 }
736         }
737 }
738
739
740
741 /*
742    ConvertEPairs()
743    exports entity key/value pairs to a map file
744  */
745
746 static void ConvertEPairs( FILE *f, entity_t *e, qboolean skip_origin ){
747         epair_t *ep;
748
749
750         /* walk epairs */
751         for ( ep = e->epairs; ep != NULL; ep = ep->next )
752         {
753                 /* ignore empty keys/values */
754                 if ( ep->key[ 0 ] == '\0' || ep->value[ 0 ] == '\0' ) {
755                         continue;
756                 }
757
758                 /* ignore model keys with * prefixed values */
759                 if ( !Q_stricmp( ep->key, "model" ) && ep->value[ 0 ] == '*' ) {
760                         continue;
761                 }
762
763                 /* ignore origin keys if skip_origin is set */
764                 if ( skip_origin && !Q_stricmp( ep->key, "origin" ) ) {
765                         continue;
766                 }
767
768                 /* emit the epair */
769                 fprintf( f, "\t\"%s\" \"%s\"\n", ep->key, ep->value );
770         }
771 }
772
773
774
775 /*
776    ConvertBSPToMap()
777    exports an quake map file from the bsp
778  */
779
780 int ConvertBSPToMap_Ext( char *bspName, qboolean brushPrimitives ){
781         int i, modelNum;
782         FILE            *f;
783         bspModel_t      *model;
784         entity_t        *e;
785         vec3_t origin;
786         const char      *value;
787         char name[ 1024 ], base[ 1024 ];
788
789
790         /* note it */
791         Sys_Printf( "--- Convert BSP to MAP ---\n" );
792
793         /* create the bsp filename from the bsp name */
794         strcpy( name, bspName );
795         StripExtension( name );
796         strcat( name, "_converted.map" );
797         Sys_Printf( "writing %s\n", name );
798
799         ExtractFileBase( bspName, base );
800         strcat( base, ".bsp" );
801
802         /* open it */
803         f = fopen( name, "wb" );
804         if ( f == NULL ) {
805                 Error( "Open failed on %s\n", name );
806         }
807
808         /* print header */
809         fprintf( f, "// Generated by Q3Map2 (ydnar) -convert -format map\n" );
810
811         /* walk entity list */
812         for ( i = 0; i < numEntities; i++ )
813         {
814                 /* get entity */
815                 e = &entities[ i ];
816
817                 /* start entity */
818                 fprintf( f, "// entity %d\n", i );
819                 fprintf( f, "{\n" );
820
821                 /* get model num */
822                 if ( i == 0 ) {
823                         modelNum = 0;
824                 }
825                 else
826                 {
827                         value = ValueForKey( e, "model" );
828                         if ( value[ 0 ] == '*' ) {
829                                 modelNum = atoi( value + 1 );
830                         }
831                         else{
832                                 modelNum = -1;
833                         }
834                 }
835
836                 /* export keys */
837                 ConvertEPairs( f, e, modelNum >= 0 );
838                 fprintf( f, "\n" );
839
840                 /* only handle bsp models */
841                 if ( modelNum >= 0 ) {
842                         /* get model */
843                         model = &bspModels[ modelNum ];
844
845                         /* get entity origin */
846                         value = ValueForKey( e, "origin" );
847                         if ( value[ 0 ] == '\0' ) {
848                                 VectorClear( origin );
849                         }
850                         else{
851                                 GetVectorForKey( e, "origin", origin );
852                         }
853
854                         /* convert model */
855                         ConvertModel( f, model, modelNum, origin, brushPrimitives );
856                 }
857
858                 /* end entity */
859                 fprintf( f, "}\n\n" );
860         }
861
862         /* close the file and return */
863         fclose( f );
864
865         /* return to sender */
866         return 0;
867 }
868
869 int ConvertBSPToMap( char *bspName ){
870         return ConvertBSPToMap_Ext( bspName, qfalse );
871 }
872
873 int ConvertBSPToMap_BP( char *bspName ){
874         return ConvertBSPToMap_Ext( bspName, qtrue );
875 }