]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - radiant/brushtokens.h
changed doom3 entity-create to add model key for brush-entities
[xonotic/netradiant.git] / radiant / brushtokens.h
1 /*
2 Copyright (C) 2001-2006, William Joseph.
3 All Rights Reserved.
4
5 This file is part of GtkRadiant.
6
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 */
21
22 #if !defined(INCLUDED_BRUSHTOKENS_H)
23 #define INCLUDED_BRUSHTOKENS_H
24
25 #include "stringio.h"
26 #include "stream/stringstream.h"
27 #include "brush.h"
28
29 inline bool FaceShader_importContentsFlagsValue(FaceShader& faceShader, Tokeniser& tokeniser)
30 {
31   // parse the optional contents/flags/value
32   RETURN_FALSE_IF_FAIL(Tokeniser_getInteger(tokeniser, faceShader.m_flags.m_contentFlags));
33   RETURN_FALSE_IF_FAIL(Tokeniser_getInteger(tokeniser, faceShader.m_flags.m_surfaceFlags));
34   RETURN_FALSE_IF_FAIL(Tokeniser_getInteger(tokeniser, faceShader.m_flags.m_value));
35   return true;
36 }
37
38 inline bool FaceTexdef_importTokens(FaceTexdef& texdef, Tokeniser& tokeniser)
39 {
40   // parse texdef
41   RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_texdef.shift[0]));
42   RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_texdef.shift[1]));
43   RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_texdef.rotate));
44   RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_texdef.scale[0]));
45   RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_texdef.scale[1]));
46
47   ASSERT_MESSAGE(texdef_sane(texdef.m_projection.m_texdef), "FaceTexdef_importTokens: bad texdef");
48   return true;
49 }
50
51 inline bool FaceTexdef_BP_importTokens(FaceTexdef& texdef, Tokeniser& tokeniser)
52 {
53   // parse alternate texdef
54   RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
55   {
56     RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
57     RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_brushprimit_texdef.coords[0][0]));
58     RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_brushprimit_texdef.coords[0][1]));
59     RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_brushprimit_texdef.coords[0][2]));
60     RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
61   }
62   {
63     RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
64     RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_brushprimit_texdef.coords[1][0]));
65     RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_brushprimit_texdef.coords[1][1]));
66     RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_brushprimit_texdef.coords[1][2]));
67     RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
68   }
69   RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
70   return true;
71 }
72
73 inline bool FaceTexdef_HalfLife_importTokens(FaceTexdef& texdef, Tokeniser& tokeniser)
74 {
75   // parse texdef
76   RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "["));
77   RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_basis_s.x()));
78   RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_basis_s.y()));
79   RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_basis_s.z()));
80   RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_texdef.shift[0]));
81   RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "]"));
82   RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "["));
83   RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_basis_t.x()));
84   RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_basis_t.y()));
85   RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_basis_t.z()));
86   RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_texdef.shift[1]));
87   RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "]"));
88   RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_texdef.rotate));
89   RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_texdef.scale[0]));
90   RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_texdef.scale[1]));
91
92   texdef.m_projection.m_texdef.rotate = -texdef.m_projection.m_texdef.rotate;
93
94   ASSERT_MESSAGE(texdef_sane(texdef.m_projection.m_texdef), "FaceTexdef_importTokens: bad texdef");
95   return true;
96 }
97
98 inline bool FacePlane_importTokens(FacePlane& facePlane, Tokeniser& tokeniser)
99 {
100   // parse planepts
101   for(std::size_t i = 0; i<3; i++)
102   {
103     RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
104     for(std::size_t j = 0; j < 3; ++j)
105     {
106       RETURN_FALSE_IF_FAIL(Tokeniser_getDouble(tokeniser, facePlane.planePoints()[i][j]));
107     }
108     RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
109   }
110   facePlane.MakePlane();
111   return true;
112 }
113
114 inline bool FacePlane_Doom3_importTokens(FacePlane& facePlane, Tokeniser& tokeniser)
115 {
116   Plane3 plane;
117   // parse plane equation
118   RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
119   RETURN_FALSE_IF_FAIL(Tokeniser_getDouble(tokeniser, plane.a));
120   RETURN_FALSE_IF_FAIL(Tokeniser_getDouble(tokeniser, plane.b));
121   RETURN_FALSE_IF_FAIL(Tokeniser_getDouble(tokeniser, plane.c));
122   RETURN_FALSE_IF_FAIL(Tokeniser_getDouble(tokeniser, plane.d));
123   plane.d = -plane.d;
124   RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
125
126   facePlane.setDoom3Plane(plane);
127   return true;
128 }
129
130 inline bool FaceShader_Doom3_importTokens(FaceShader& faceShader, Tokeniser& tokeniser)
131 {
132   const char *shader = tokeniser.getToken();
133   if(shader == 0)
134   {
135     Tokeniser_unexpectedError(tokeniser, shader, "#shader-name");
136     return false;
137   }
138   if(string_equal(shader, "_emptyname"))
139   {
140     shader = texdef_name_default();
141   }
142   faceShader.setShader(shader);
143   return true;
144 }
145
146 inline bool FaceShader_importTokens(FaceShader& faceShader, Tokeniser& tokeniser)
147 {
148   const char* texture = tokeniser.getToken();
149   if(texture == 0)
150   {
151     Tokeniser_unexpectedError(tokeniser, texture, "#texture-name");
152     return false;
153   }
154   if(string_equal(texture, "NULL"))
155   {
156     faceShader.setShader(texdef_name_default());
157   }
158   else
159   {
160     StringOutputStream shader(string_length(GlobalTexturePrefix_get()) + string_length(texture));
161     shader << GlobalTexturePrefix_get() << texture;
162     faceShader.setShader(shader.c_str());
163   }
164   return true;
165 }
166
167
168
169
170 class Doom3FaceTokenImporter
171 {
172   Face& m_face;
173 public:
174   Doom3FaceTokenImporter(Face& face) : m_face(face)
175   {
176   }
177   bool importTokens(Tokeniser& tokeniser)
178   {
179     RETURN_FALSE_IF_FAIL(FacePlane_Doom3_importTokens(m_face.getPlane(), tokeniser));
180     RETURN_FALSE_IF_FAIL(FaceTexdef_BP_importTokens(m_face.getTexdef(), tokeniser));
181     RETURN_FALSE_IF_FAIL(FaceShader_Doom3_importTokens(m_face.getShader(), tokeniser));
182     RETURN_FALSE_IF_FAIL(FaceShader_importContentsFlagsValue(m_face.getShader(), tokeniser));
183
184     m_face.getTexdef().m_projectionInitialised = true;
185     m_face.getTexdef().m_scaleApplied = true;
186
187     return true;
188   }
189 };
190
191 class Quake4FaceTokenImporter
192 {
193   Face& m_face;
194 public:
195   Quake4FaceTokenImporter(Face& face) : m_face(face)
196   {
197   }
198   bool importTokens(Tokeniser& tokeniser)
199   {
200     RETURN_FALSE_IF_FAIL(FacePlane_Doom3_importTokens(m_face.getPlane(), tokeniser));
201     RETURN_FALSE_IF_FAIL(FaceTexdef_BP_importTokens(m_face.getTexdef(), tokeniser));
202     RETURN_FALSE_IF_FAIL(FaceShader_Doom3_importTokens(m_face.getShader(), tokeniser));
203
204     m_face.getTexdef().m_projectionInitialised = true;
205     m_face.getTexdef().m_scaleApplied = true;
206
207     return true;
208   }
209 };
210
211 class Quake2FaceTokenImporter
212 {
213   Face& m_face;
214 public:
215   Quake2FaceTokenImporter(Face& face) : m_face(face)
216   {
217   }
218   bool importTokens(Tokeniser& tokeniser)
219   {
220     RETURN_FALSE_IF_FAIL(FacePlane_importTokens(m_face.getPlane(), tokeniser));
221     RETURN_FALSE_IF_FAIL(FaceShader_importTokens(m_face.getShader(), tokeniser));
222     RETURN_FALSE_IF_FAIL(FaceTexdef_importTokens(m_face.getTexdef(), tokeniser));
223     if(Tokeniser_nextTokenIsDigit(tokeniser))
224     {
225       m_face.getShader().m_flags.m_specified = true;
226       RETURN_FALSE_IF_FAIL(FaceShader_importContentsFlagsValue(m_face.getShader(), tokeniser));
227     }
228     m_face.getTexdef().m_scaleApplied = true;
229     return true;
230   }
231 };
232
233 class Quake3FaceTokenImporter
234 {
235   Face& m_face;
236 public:
237   Quake3FaceTokenImporter(Face& face) : m_face(face)
238   {
239   }
240   bool importTokens(Tokeniser& tokeniser)
241   {
242     RETURN_FALSE_IF_FAIL(FacePlane_importTokens(m_face.getPlane(), tokeniser));
243     RETURN_FALSE_IF_FAIL(FaceShader_importTokens(m_face.getShader(), tokeniser));
244     RETURN_FALSE_IF_FAIL(FaceTexdef_importTokens(m_face.getTexdef(), tokeniser));
245     RETURN_FALSE_IF_FAIL(FaceShader_importContentsFlagsValue(m_face.getShader(), tokeniser));
246     m_face.getTexdef().m_scaleApplied = true;
247     return true;
248   }
249 };
250
251 class Quake3BPFaceTokenImporter
252 {
253   Face& m_face;
254 public:
255   Quake3BPFaceTokenImporter(Face& face) : m_face(face)
256   {
257   }
258   bool importTokens(Tokeniser& tokeniser)
259   {
260     RETURN_FALSE_IF_FAIL(FacePlane_importTokens(m_face.getPlane(), tokeniser));
261     RETURN_FALSE_IF_FAIL(FaceTexdef_BP_importTokens(m_face.getTexdef(), tokeniser));
262     RETURN_FALSE_IF_FAIL(FaceShader_importTokens(m_face.getShader(), tokeniser));
263     RETURN_FALSE_IF_FAIL(FaceShader_importContentsFlagsValue(m_face.getShader(), tokeniser));
264
265     m_face.getTexdef().m_projectionInitialised = true;
266     m_face.getTexdef().m_scaleApplied = true;
267
268     return true;
269   }
270 };
271
272 class QuakeFaceTokenImporter
273 {
274   Face& m_face;
275 public:
276   QuakeFaceTokenImporter(Face& face) : m_face(face)
277   {
278   }
279   bool importTokens(Tokeniser& tokeniser)
280   {
281     RETURN_FALSE_IF_FAIL(FacePlane_importTokens(m_face.getPlane(), tokeniser));
282     RETURN_FALSE_IF_FAIL(FaceShader_importTokens(m_face.getShader(), tokeniser));
283     RETURN_FALSE_IF_FAIL(FaceTexdef_importTokens(m_face.getTexdef(), tokeniser));
284     m_face.getTexdef().m_scaleApplied = true;
285     return true;
286   }
287 };
288
289 class HalfLifeFaceTokenImporter
290 {
291   Face& m_face;
292 public:
293   HalfLifeFaceTokenImporter(Face& face) : m_face(face)
294   {
295   }
296   bool importTokens(Tokeniser& tokeniser)
297   {
298     RETURN_FALSE_IF_FAIL(FacePlane_importTokens(m_face.getPlane(), tokeniser));
299     RETURN_FALSE_IF_FAIL(FaceShader_importTokens(m_face.getShader(), tokeniser));
300     RETURN_FALSE_IF_FAIL(FaceTexdef_HalfLife_importTokens(m_face.getTexdef(), tokeniser));
301     m_face.getTexdef().m_scaleApplied = true;
302     return true;
303   }
304 };
305
306
307 inline void FacePlane_Doom3_exportTokens(const FacePlane& facePlane, TokenWriter& writer)
308 {
309   // write plane equation
310   writer.writeToken("(");
311   writer.writeFloat(facePlane.getDoom3Plane().a);
312   writer.writeFloat(facePlane.getDoom3Plane().b);
313   writer.writeFloat(facePlane.getDoom3Plane().c);
314   writer.writeFloat(-facePlane.getDoom3Plane().d);
315   writer.writeToken(")");
316 }
317
318 inline void FacePlane_exportTokens(const FacePlane& facePlane, TokenWriter& writer)
319 {
320   // write planepts
321   for(std::size_t i=0; i<3; i++)
322   {
323     writer.writeToken("(");
324     for(std::size_t j=0; j<3; j++)
325     {
326       writer.writeFloat(Face::m_quantise(facePlane.planePoints()[i][j]));
327     }
328     writer.writeToken(")");
329   }
330 }
331
332 inline void FaceTexdef_BP_exportTokens(const FaceTexdef& faceTexdef, TokenWriter& writer)
333 {
334   // write alternate texdef
335   writer.writeToken("(");
336   {
337     writer.writeToken("(");
338     for(std::size_t i=0;i<3;i++)
339     {
340       writer.writeFloat(faceTexdef.m_projection.m_brushprimit_texdef.coords[0][i]);
341     }
342     writer.writeToken(")");
343   }
344   {
345     writer.writeToken("(");
346     for(std::size_t i=0;i<3;i++)
347     {
348       writer.writeFloat(faceTexdef.m_projection.m_brushprimit_texdef.coords[1][i]);
349     }
350     writer.writeToken(")");
351   }
352   writer.writeToken(")");
353 }
354
355 inline void FaceTexdef_exportTokens(const FaceTexdef& faceTexdef, TokenWriter& writer)
356 {
357   ASSERT_MESSAGE(texdef_sane(faceTexdef.m_projection.m_texdef), "FaceTexdef_exportTokens: bad texdef");
358   // write texdef
359   writer.writeFloat(faceTexdef.m_projection.m_texdef.shift[0]);
360   writer.writeFloat(faceTexdef.m_projection.m_texdef.shift[1]);
361   writer.writeFloat(faceTexdef.m_projection.m_texdef.rotate);
362   writer.writeFloat(faceTexdef.m_projection.m_texdef.scale[0]);
363   writer.writeFloat(faceTexdef.m_projection.m_texdef.scale[1]);
364 }
365
366 inline void FaceTexdef_HalfLife_exportTokens(const FaceTexdef& faceTexdef, TokenWriter& writer)
367 {
368   ASSERT_MESSAGE(texdef_sane(faceTexdef.m_projection.m_texdef), "FaceTexdef_exportTokens: bad texdef");
369   // write texdef
370   writer.writeToken("[");
371   writer.writeFloat(faceTexdef.m_projection.m_basis_s.x());
372   writer.writeFloat(faceTexdef.m_projection.m_basis_s.y());
373   writer.writeFloat(faceTexdef.m_projection.m_basis_s.z());
374   writer.writeFloat(faceTexdef.m_projection.m_texdef.shift[0]);
375   writer.writeToken("]");
376   writer.writeToken("[");
377   writer.writeFloat(faceTexdef.m_projection.m_basis_t.x());
378   writer.writeFloat(faceTexdef.m_projection.m_basis_t.y());
379   writer.writeFloat(faceTexdef.m_projection.m_basis_t.z());
380   writer.writeFloat(faceTexdef.m_projection.m_texdef.shift[1]);
381   writer.writeToken("]");
382   writer.writeFloat(-faceTexdef.m_projection.m_texdef.rotate);
383   writer.writeFloat(faceTexdef.m_projection.m_texdef.scale[0]);
384   writer.writeFloat(faceTexdef.m_projection.m_texdef.scale[1]);
385 }
386
387 inline void FaceShader_ContentsFlagsValue_exportTokens(const FaceShader& faceShader, TokenWriter& writer)
388 {
389   // write surface flags
390   writer.writeInteger(faceShader.m_flags.m_contentFlags);
391   writer.writeInteger(faceShader.m_flags.m_surfaceFlags);
392   writer.writeInteger(faceShader.m_flags.m_value);
393 }
394
395 inline void FaceShader_exportTokens(const FaceShader& faceShader, TokenWriter& writer)
396 {
397   // write shader name  
398   if(string_empty(shader_get_textureName(faceShader.getShader())))
399   {
400     writer.writeToken("NULL");
401   }
402   else
403   {
404     writer.writeToken(shader_get_textureName(faceShader.getShader()));
405   }
406 }
407
408 inline void FaceShader_Doom3_exportTokens(const FaceShader& faceShader, TokenWriter& writer)
409 {
410   // write shader name  
411   if(string_empty(shader_get_textureName(faceShader.getShader())))
412   {
413     writer.writeString("_emptyname");
414   }
415   else
416   {
417     writer.writeString(faceShader.getShader());
418   }
419 }
420
421 class Doom3FaceTokenExporter
422 {
423   const Face& m_face;
424 public:
425   Doom3FaceTokenExporter(const Face& face) : m_face(face)
426   {
427   }
428   void exportTokens(TokenWriter& writer) const
429   {
430     FacePlane_Doom3_exportTokens(m_face.getPlane(), writer);
431     FaceTexdef_BP_exportTokens(m_face.getTexdef(), writer);
432     FaceShader_Doom3_exportTokens(m_face.getShader(), writer);
433     FaceShader_ContentsFlagsValue_exportTokens(m_face.getShader(), writer);
434     writer.nextLine();
435   }
436 };
437
438 class Quake4FaceTokenExporter
439 {
440   const Face& m_face;
441 public:
442   Quake4FaceTokenExporter(const Face& face) : m_face(face)
443   {
444   }
445   void exportTokens(TokenWriter& writer) const
446   {
447     FacePlane_Doom3_exportTokens(m_face.getPlane(), writer);
448     FaceTexdef_BP_exportTokens(m_face.getTexdef(), writer);
449     FaceShader_Doom3_exportTokens(m_face.getShader(), writer);
450     writer.nextLine();
451   }
452 };
453
454 class Quake2FaceTokenExporter
455 {
456   const Face& m_face;
457 public:
458   Quake2FaceTokenExporter(const Face& face) : m_face(face)
459   {
460   }
461   void exportTokens(TokenWriter& writer) const
462   {
463     FacePlane_exportTokens(m_face.getPlane(), writer);
464     FaceShader_exportTokens(m_face.getShader(), writer);
465     FaceTexdef_exportTokens(m_face.getTexdef(), writer);
466     if(m_face.getShader().m_flags.m_specified || m_face.isDetail())
467     {
468       FaceShader_ContentsFlagsValue_exportTokens(m_face.getShader(), writer);
469     }
470     writer.nextLine();
471   }
472 };
473
474 class Quake3FaceTokenExporter
475 {
476   const Face& m_face;
477 public:
478   Quake3FaceTokenExporter(const Face& face) : m_face(face)
479   {
480   }
481   void exportTokens(TokenWriter& writer) const
482   {
483     FacePlane_exportTokens(m_face.getPlane(), writer);
484     FaceShader_exportTokens(m_face.getShader(), writer);
485     FaceTexdef_exportTokens(m_face.getTexdef(), writer);
486     FaceShader_ContentsFlagsValue_exportTokens(m_face.getShader(), writer);
487     writer.nextLine();
488   }
489 };
490
491 class Quake3BPFaceTokenExporter
492 {
493   const Face& m_face;
494 public:
495   Quake3BPFaceTokenExporter(const Face& face) : m_face(face)
496   {
497   }
498   void exportTokens(TokenWriter& writer) const
499   {
500     FacePlane_exportTokens(m_face.getPlane(), writer);
501     FaceTexdef_BP_exportTokens(m_face.getTexdef(), writer);
502     FaceShader_exportTokens(m_face.getShader(), writer);
503     FaceShader_ContentsFlagsValue_exportTokens(m_face.getShader(), writer);
504     writer.nextLine();
505   }
506 };
507
508 class QuakeFaceTokenExporter
509 {
510   const Face& m_face;
511 public:
512   QuakeFaceTokenExporter(const Face& face) : m_face(face)
513   {
514   }
515   void exportTokens(TokenWriter& writer) const
516   {
517     FacePlane_exportTokens(m_face.getPlane(), writer);
518     FaceShader_exportTokens(m_face.getShader(), writer);
519     FaceTexdef_exportTokens(m_face.getTexdef(), writer);
520     writer.nextLine();
521   }
522 };
523
524 class HalfLifeFaceTokenExporter
525 {
526   const Face& m_face;
527 public:
528   HalfLifeFaceTokenExporter(const Face& face) : m_face(face)
529   {
530   }
531   void exportTokens(TokenWriter& writer) const
532   {
533     FacePlane_exportTokens(m_face.getPlane(), writer);
534     FaceShader_exportTokens(m_face.getShader(), writer);
535     FaceTexdef_HalfLife_exportTokens(m_face.getTexdef(), writer);
536     writer.nextLine();
537   }
538 };
539
540
541 class BrushTokenImporter : public MapImporter
542 {
543   Brush& m_brush;
544
545 public:
546   BrushTokenImporter(Brush& brush) : m_brush(brush)
547   {
548   }
549   bool importTokens(Tokeniser& tokeniser)
550   {
551     if(Brush::m_type == eBrushTypeQuake3BP || Brush::m_type == eBrushTypeDoom3 || Brush::m_type == eBrushTypeQuake4)
552     {
553       tokeniser.nextLine();
554       RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "{"));
555     }
556     while(1)
557     {
558       // check for end of brush
559       tokeniser.nextLine();
560       const char* token = tokeniser.getToken();
561       if(string_equal(token, "}"))
562       {
563         break;
564       }
565
566       tokeniser.ungetToken();
567
568       m_brush.push_back(FaceSmartPointer(new Face(&m_brush)));
569
570       //!todo BP support
571       tokeniser.nextLine();
572
573       Face& face = *m_brush.back();
574
575       switch(Brush::m_type)
576       {
577       case eBrushTypeDoom3:
578         {
579           Doom3FaceTokenImporter importer(face);
580           RETURN_FALSE_IF_FAIL(importer.importTokens(tokeniser));
581         }
582         break;
583       case eBrushTypeQuake4:
584         {
585           Quake4FaceTokenImporter importer(face);
586           RETURN_FALSE_IF_FAIL(importer.importTokens(tokeniser));
587         }
588         break;
589       case eBrushTypeQuake2:
590         {
591           Quake2FaceTokenImporter importer(face);
592           RETURN_FALSE_IF_FAIL(importer.importTokens(tokeniser));
593         }
594         break;
595       case eBrushTypeQuake3:
596         {
597           Quake3FaceTokenImporter importer(face);
598           RETURN_FALSE_IF_FAIL(importer.importTokens(tokeniser));
599         }
600         break;
601       case eBrushTypeQuake3BP:
602         {
603           Quake3BPFaceTokenImporter importer(face);
604           RETURN_FALSE_IF_FAIL(importer.importTokens(tokeniser));
605         }
606         break;
607       case eBrushTypeQuake:
608         {
609           QuakeFaceTokenImporter importer(face);
610           RETURN_FALSE_IF_FAIL(importer.importTokens(tokeniser));
611         }
612         break;
613       case eBrushTypeHalfLife:
614         {
615           HalfLifeFaceTokenImporter importer(face);
616           RETURN_FALSE_IF_FAIL(importer.importTokens(tokeniser));
617         }
618         break;
619       }
620       face.planeChanged();
621     }
622     if(Brush::m_type == eBrushTypeQuake3BP || Brush::m_type == eBrushTypeDoom3 || Brush::m_type == eBrushTypeQuake4)
623     {
624       tokeniser.nextLine();
625       RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "}"));
626     }
627
628     m_brush.planeChanged();
629     m_brush.shaderChanged();
630
631     return true;
632   }
633 };
634
635
636 class BrushTokenExporter : public MapExporter
637 {
638   const Brush& m_brush;
639
640 public:
641   BrushTokenExporter(const Brush& brush) : m_brush(brush)
642   {
643   }
644   void exportTokens(TokenWriter& writer) const
645   {
646     m_brush.evaluateBRep(); // ensure b-rep is up-to-date, so that non-contributing faces can be identified.
647
648     if(!m_brush.hasContributingFaces())
649     {
650       return;
651     }
652
653     writer.writeToken("{");
654     writer.nextLine();
655
656     if(Brush::m_type == eBrushTypeQuake3BP)
657     {
658       writer.writeToken("brushDef");
659       writer.nextLine();
660       writer.writeToken("{");
661       writer.nextLine();
662     }
663     
664     if(Brush::m_type == eBrushTypeDoom3 || Brush::m_type == eBrushTypeQuake4)
665     {
666       writer.writeToken("brushDef3");
667       writer.nextLine();
668       writer.writeToken("{");
669       writer.nextLine();
670     }
671
672     for(Brush::const_iterator i = m_brush.begin(); i != m_brush.end(); ++i)
673     {
674       const Face& face = *(*i);
675
676       if(face.contributes())
677       {
678         switch(Brush::m_type)
679         {
680         case eBrushTypeDoom3:
681           {
682             Doom3FaceTokenExporter exporter(face);
683             exporter.exportTokens(writer);
684           }
685           break;
686         case eBrushTypeQuake4:
687           {
688             Quake4FaceTokenExporter exporter(face);
689             exporter.exportTokens(writer);
690           }
691           break;
692         case eBrushTypeQuake2:
693           {
694             Quake2FaceTokenExporter exporter(face);
695             exporter.exportTokens(writer);
696           }
697           break;
698         case eBrushTypeQuake3:
699           {
700             Quake3FaceTokenExporter exporter(face);
701             exporter.exportTokens(writer);
702           }
703           break;
704         case eBrushTypeQuake3BP:
705           {
706             Quake3BPFaceTokenExporter exporter(face);
707             exporter.exportTokens(writer);
708           }
709           break;
710         case eBrushTypeQuake:
711           {
712             QuakeFaceTokenExporter exporter(face);
713             exporter.exportTokens(writer);
714           }
715           break;
716         case eBrushTypeHalfLife:
717           {
718             HalfLifeFaceTokenExporter exporter(face);
719             exporter.exportTokens(writer);
720           }
721           break;
722         }
723       }
724     }
725
726     if(Brush::m_type == eBrushTypeQuake3BP || Brush::m_type == eBrushTypeDoom3 || Brush::m_type == eBrushTypeQuake4)
727     {
728       writer.writeToken("}");
729       writer.nextLine();
730     }
731
732     writer.writeToken("}");
733     writer.nextLine();
734   }
735 };
736
737     
738 #endif