]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - radiant/brushtokens.h
uncrustify iqmmodel code
[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         RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
103         for (std::size_t j = 0; j < 3; ++j) {
104             RETURN_FALSE_IF_FAIL(Tokeniser_getDouble(tokeniser, facePlane.planePoints()[i][j]));
105         }
106         RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
107     }
108     facePlane.MakePlane();
109     return true;
110 }
111
112 inline bool FacePlane_Doom3_importTokens(FacePlane &facePlane, Tokeniser &tokeniser)
113 {
114     Plane3 plane;
115     // parse plane equation
116     RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
117     RETURN_FALSE_IF_FAIL(Tokeniser_getDouble(tokeniser, plane.a));
118     RETURN_FALSE_IF_FAIL(Tokeniser_getDouble(tokeniser, plane.b));
119     RETURN_FALSE_IF_FAIL(Tokeniser_getDouble(tokeniser, plane.c));
120     RETURN_FALSE_IF_FAIL(Tokeniser_getDouble(tokeniser, plane.d));
121     plane.d = -plane.d;
122     RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
123
124     facePlane.setDoom3Plane(plane);
125     return true;
126 }
127
128 inline bool FaceShader_Doom3_importTokens(FaceShader &faceShader, Tokeniser &tokeniser)
129 {
130     const char *shader = tokeniser.getToken();
131     if (shader == 0) {
132         Tokeniser_unexpectedError(tokeniser, shader, "#shader-name");
133         return false;
134     }
135     if (string_equal(shader, "_emptyname")) {
136         shader = texdef_name_default();
137     }
138     faceShader.setShader(shader);
139     return true;
140 }
141
142 inline bool FaceShader_importTokens(FaceShader &faceShader, Tokeniser &tokeniser)
143 {
144     const char *texture = tokeniser.getToken();
145     if (texture == 0) {
146         Tokeniser_unexpectedError(tokeniser, texture, "#texture-name");
147         return false;
148     }
149     if (string_equal(texture, "NULL")) {
150         faceShader.setShader(texdef_name_default());
151     } else {
152         StringOutputStream shader(string_length(GlobalTexturePrefix_get()) + string_length(texture));
153         shader << GlobalTexturePrefix_get() << texture;
154         faceShader.setShader(shader.c_str());
155     }
156     return true;
157 }
158
159
160 class Doom3FaceTokenImporter {
161     Face &m_face;
162 public:
163     Doom3FaceTokenImporter(Face &face) : m_face(face)
164     {
165     }
166
167     bool importTokens(Tokeniser &tokeniser)
168     {
169         RETURN_FALSE_IF_FAIL(FacePlane_Doom3_importTokens(m_face.getPlane(), tokeniser));
170         RETURN_FALSE_IF_FAIL(FaceTexdef_BP_importTokens(m_face.getTexdef(), tokeniser));
171         RETURN_FALSE_IF_FAIL(FaceShader_Doom3_importTokens(m_face.getShader(), tokeniser));
172         RETURN_FALSE_IF_FAIL(FaceShader_importContentsFlagsValue(m_face.getShader(), tokeniser));
173
174         m_face.getTexdef().m_projectionInitialised = true;
175         m_face.getTexdef().m_scaleApplied = true;
176
177         return true;
178     }
179 };
180
181 class Quake4FaceTokenImporter {
182     Face &m_face;
183 public:
184     Quake4FaceTokenImporter(Face &face) : m_face(face)
185     {
186     }
187
188     bool importTokens(Tokeniser &tokeniser)
189     {
190         RETURN_FALSE_IF_FAIL(FacePlane_Doom3_importTokens(m_face.getPlane(), tokeniser));
191         RETURN_FALSE_IF_FAIL(FaceTexdef_BP_importTokens(m_face.getTexdef(), tokeniser));
192         RETURN_FALSE_IF_FAIL(FaceShader_Doom3_importTokens(m_face.getShader(), tokeniser));
193
194         m_face.getTexdef().m_projectionInitialised = true;
195         m_face.getTexdef().m_scaleApplied = true;
196
197         return true;
198     }
199 };
200
201 class Quake2FaceTokenImporter {
202     Face &m_face;
203 public:
204     Quake2FaceTokenImporter(Face &face) : m_face(face)
205     {
206     }
207
208     bool importTokens(Tokeniser &tokeniser)
209     {
210         RETURN_FALSE_IF_FAIL(FacePlane_importTokens(m_face.getPlane(), tokeniser));
211         RETURN_FALSE_IF_FAIL(FaceShader_importTokens(m_face.getShader(), tokeniser));
212         RETURN_FALSE_IF_FAIL(FaceTexdef_importTokens(m_face.getTexdef(), tokeniser));
213         if (Tokeniser_nextTokenIsDigit(tokeniser)) {
214             m_face.getShader().m_flags.m_specified = true;
215             RETURN_FALSE_IF_FAIL(FaceShader_importContentsFlagsValue(m_face.getShader(), tokeniser));
216         }
217         m_face.getTexdef().m_scaleApplied = true;
218         return true;
219     }
220 };
221
222 class Quake3FaceTokenImporter {
223     Face &m_face;
224 public:
225     Quake3FaceTokenImporter(Face &face) : m_face(face)
226     {
227     }
228
229     bool importTokens(Tokeniser &tokeniser)
230     {
231         RETURN_FALSE_IF_FAIL(FacePlane_importTokens(m_face.getPlane(), tokeniser));
232         RETURN_FALSE_IF_FAIL(FaceShader_importTokens(m_face.getShader(), tokeniser));
233         RETURN_FALSE_IF_FAIL(FaceTexdef_importTokens(m_face.getTexdef(), tokeniser));
234         RETURN_FALSE_IF_FAIL(FaceShader_importContentsFlagsValue(m_face.getShader(), tokeniser));
235         m_face.getTexdef().m_scaleApplied = true;
236         return true;
237     }
238 };
239
240 class Quake3BPFaceTokenImporter {
241     Face &m_face;
242 public:
243     Quake3BPFaceTokenImporter(Face &face) : m_face(face)
244     {
245     }
246
247     bool importTokens(Tokeniser &tokeniser)
248     {
249         RETURN_FALSE_IF_FAIL(FacePlane_importTokens(m_face.getPlane(), tokeniser));
250         RETURN_FALSE_IF_FAIL(FaceTexdef_BP_importTokens(m_face.getTexdef(), tokeniser));
251         RETURN_FALSE_IF_FAIL(FaceShader_importTokens(m_face.getShader(), tokeniser));
252         RETURN_FALSE_IF_FAIL(FaceShader_importContentsFlagsValue(m_face.getShader(), tokeniser));
253
254         m_face.getTexdef().m_projectionInitialised = true;
255         m_face.getTexdef().m_scaleApplied = true;
256
257         return true;
258     }
259 };
260
261 class QuakeFaceTokenImporter {
262     Face &m_face;
263 public:
264     QuakeFaceTokenImporter(Face &face) : m_face(face)
265     {
266     }
267
268     bool importTokens(Tokeniser &tokeniser)
269     {
270         RETURN_FALSE_IF_FAIL(FacePlane_importTokens(m_face.getPlane(), tokeniser));
271         RETURN_FALSE_IF_FAIL(FaceShader_importTokens(m_face.getShader(), tokeniser));
272         RETURN_FALSE_IF_FAIL(FaceTexdef_importTokens(m_face.getTexdef(), tokeniser));
273         m_face.getTexdef().m_scaleApplied = true;
274         return true;
275     }
276 };
277
278 class HalfLifeFaceTokenImporter {
279     Face &m_face;
280 public:
281     HalfLifeFaceTokenImporter(Face &face) : m_face(face)
282     {
283     }
284
285     bool importTokens(Tokeniser &tokeniser)
286     {
287         RETURN_FALSE_IF_FAIL(FacePlane_importTokens(m_face.getPlane(), tokeniser));
288         RETURN_FALSE_IF_FAIL(FaceShader_importTokens(m_face.getShader(), tokeniser));
289         RETURN_FALSE_IF_FAIL(FaceTexdef_HalfLife_importTokens(m_face.getTexdef(), tokeniser));
290         m_face.getTexdef().m_scaleApplied = true;
291         return true;
292     }
293 };
294
295
296 inline void FacePlane_Doom3_exportTokens(const FacePlane &facePlane, TokenWriter &writer)
297 {
298     // write plane equation
299     writer.writeToken("(");
300     writer.writeFloat(facePlane.getDoom3Plane().a);
301     writer.writeFloat(facePlane.getDoom3Plane().b);
302     writer.writeFloat(facePlane.getDoom3Plane().c);
303     writer.writeFloat(-facePlane.getDoom3Plane().d);
304     writer.writeToken(")");
305 }
306
307 inline void FacePlane_exportTokens(const FacePlane &facePlane, TokenWriter &writer)
308 {
309     // write planepts
310     for (std::size_t i = 0; i < 3; i++) {
311         writer.writeToken("(");
312         for (std::size_t j = 0; j < 3; j++) {
313             writer.writeFloat(Face::m_quantise(facePlane.planePoints()[i][j]));
314         }
315         writer.writeToken(")");
316     }
317 }
318
319 inline void FaceTexdef_BP_exportTokens(const FaceTexdef &faceTexdef, TokenWriter &writer)
320 {
321     // write alternate texdef
322     writer.writeToken("(");
323     {
324         writer.writeToken("(");
325         for (std::size_t i = 0; i < 3; i++) {
326             writer.writeFloat(faceTexdef.m_projection.m_brushprimit_texdef.coords[0][i]);
327         }
328         writer.writeToken(")");
329     }
330     {
331         writer.writeToken("(");
332         for (std::size_t i = 0; i < 3; i++) {
333             writer.writeFloat(faceTexdef.m_projection.m_brushprimit_texdef.coords[1][i]);
334         }
335         writer.writeToken(")");
336     }
337     writer.writeToken(")");
338 }
339
340 inline void FaceTexdef_exportTokens(const FaceTexdef &faceTexdef, TokenWriter &writer)
341 {
342     ASSERT_MESSAGE(texdef_sane(faceTexdef.m_projection.m_texdef), "FaceTexdef_exportTokens: bad texdef");
343     // write texdef
344     writer.writeFloat(faceTexdef.m_projection.m_texdef.shift[0]);
345     writer.writeFloat(faceTexdef.m_projection.m_texdef.shift[1]);
346     writer.writeFloat(faceTexdef.m_projection.m_texdef.rotate);
347     writer.writeFloat(faceTexdef.m_projection.m_texdef.scale[0]);
348     writer.writeFloat(faceTexdef.m_projection.m_texdef.scale[1]);
349 }
350
351 inline void FaceTexdef_HalfLife_exportTokens(const FaceTexdef &faceTexdef, TokenWriter &writer)
352 {
353     ASSERT_MESSAGE(texdef_sane(faceTexdef.m_projection.m_texdef), "FaceTexdef_exportTokens: bad texdef");
354     // write texdef
355     writer.writeToken("[");
356     writer.writeFloat(faceTexdef.m_projection.m_basis_s.x());
357     writer.writeFloat(faceTexdef.m_projection.m_basis_s.y());
358     writer.writeFloat(faceTexdef.m_projection.m_basis_s.z());
359     writer.writeFloat(faceTexdef.m_projection.m_texdef.shift[0]);
360     writer.writeToken("]");
361     writer.writeToken("[");
362     writer.writeFloat(faceTexdef.m_projection.m_basis_t.x());
363     writer.writeFloat(faceTexdef.m_projection.m_basis_t.y());
364     writer.writeFloat(faceTexdef.m_projection.m_basis_t.z());
365     writer.writeFloat(faceTexdef.m_projection.m_texdef.shift[1]);
366     writer.writeToken("]");
367     writer.writeFloat(-faceTexdef.m_projection.m_texdef.rotate);
368     writer.writeFloat(faceTexdef.m_projection.m_texdef.scale[0]);
369     writer.writeFloat(faceTexdef.m_projection.m_texdef.scale[1]);
370 }
371
372 inline void FaceShader_ContentsFlagsValue_exportTokens(const FaceShader &faceShader, TokenWriter &writer)
373 {
374     // write surface flags
375     writer.writeInteger(faceShader.m_flags.m_contentFlags);
376     writer.writeInteger(faceShader.m_flags.m_surfaceFlags);
377     writer.writeInteger(faceShader.m_flags.m_value);
378 }
379
380 inline void FaceShader_exportTokens(const FaceShader &faceShader, TokenWriter &writer)
381 {
382     // write shader name
383     if (string_empty(shader_get_textureName(faceShader.getShader()))) {
384         writer.writeToken("NULL");
385     } else {
386         writer.writeToken(shader_get_textureName(faceShader.getShader()));
387     }
388 }
389
390 inline void FaceShader_Doom3_exportTokens(const FaceShader &faceShader, TokenWriter &writer)
391 {
392     // write shader name
393     if (string_empty(shader_get_textureName(faceShader.getShader()))) {
394         writer.writeString("_emptyname");
395     } else {
396         writer.writeString(faceShader.getShader());
397     }
398 }
399
400 class Doom3FaceTokenExporter {
401     const Face &m_face;
402 public:
403     Doom3FaceTokenExporter(const Face &face) : m_face(face)
404     {
405     }
406
407     void exportTokens(TokenWriter &writer) const
408     {
409         FacePlane_Doom3_exportTokens(m_face.getPlane(), writer);
410         FaceTexdef_BP_exportTokens(m_face.getTexdef(), writer);
411         FaceShader_Doom3_exportTokens(m_face.getShader(), writer);
412         FaceShader_ContentsFlagsValue_exportTokens(m_face.getShader(), writer);
413         writer.nextLine();
414     }
415 };
416
417 class Quake4FaceTokenExporter {
418     const Face &m_face;
419 public:
420     Quake4FaceTokenExporter(const Face &face) : m_face(face)
421     {
422     }
423
424     void exportTokens(TokenWriter &writer) const
425     {
426         FacePlane_Doom3_exportTokens(m_face.getPlane(), writer);
427         FaceTexdef_BP_exportTokens(m_face.getTexdef(), writer);
428         FaceShader_Doom3_exportTokens(m_face.getShader(), writer);
429         writer.nextLine();
430     }
431 };
432
433 class Quake2FaceTokenExporter {
434     const Face &m_face;
435 public:
436     Quake2FaceTokenExporter(const Face &face) : m_face(face)
437     {
438     }
439
440     void exportTokens(TokenWriter &writer) const
441     {
442         FacePlane_exportTokens(m_face.getPlane(), writer);
443         FaceShader_exportTokens(m_face.getShader(), writer);
444         FaceTexdef_exportTokens(m_face.getTexdef(), writer);
445         if (m_face.getShader().m_flags.m_specified || m_face.isDetail()) {
446             FaceShader_ContentsFlagsValue_exportTokens(m_face.getShader(), writer);
447         }
448         writer.nextLine();
449     }
450 };
451
452 class Quake3FaceTokenExporter {
453     const Face &m_face;
454 public:
455     Quake3FaceTokenExporter(const Face &face) : m_face(face)
456     {
457     }
458
459     void exportTokens(TokenWriter &writer) const
460     {
461         FacePlane_exportTokens(m_face.getPlane(), writer);
462         FaceShader_exportTokens(m_face.getShader(), writer);
463         FaceTexdef_exportTokens(m_face.getTexdef(), writer);
464         FaceShader_ContentsFlagsValue_exportTokens(m_face.getShader(), writer);
465         writer.nextLine();
466     }
467 };
468
469 class Quake3BPFaceTokenExporter {
470     const Face &m_face;
471 public:
472     Quake3BPFaceTokenExporter(const Face &face) : m_face(face)
473     {
474     }
475
476     void exportTokens(TokenWriter &writer) const
477     {
478         FacePlane_exportTokens(m_face.getPlane(), writer);
479         FaceTexdef_BP_exportTokens(m_face.getTexdef(), writer);
480         FaceShader_exportTokens(m_face.getShader(), writer);
481         FaceShader_ContentsFlagsValue_exportTokens(m_face.getShader(), writer);
482         writer.nextLine();
483     }
484 };
485
486 class QuakeFaceTokenExporter {
487     const Face &m_face;
488 public:
489     QuakeFaceTokenExporter(const Face &face) : m_face(face)
490     {
491     }
492
493     void exportTokens(TokenWriter &writer) const
494     {
495         FacePlane_exportTokens(m_face.getPlane(), writer);
496         FaceShader_exportTokens(m_face.getShader(), writer);
497         FaceTexdef_exportTokens(m_face.getTexdef(), writer);
498         writer.nextLine();
499     }
500 };
501
502 class HalfLifeFaceTokenExporter {
503     const Face &m_face;
504 public:
505     HalfLifeFaceTokenExporter(const Face &face) : m_face(face)
506     {
507     }
508
509     void exportTokens(TokenWriter &writer) const
510     {
511         FacePlane_exportTokens(m_face.getPlane(), writer);
512         FaceShader_exportTokens(m_face.getShader(), writer);
513         FaceTexdef_HalfLife_exportTokens(m_face.getTexdef(), writer);
514         writer.nextLine();
515     }
516 };
517
518
519 class BrushTokenImporter : public MapImporter {
520     Brush &m_brush;
521
522 public:
523     BrushTokenImporter(Brush &brush) : m_brush(brush)
524     {
525     }
526
527     bool importTokens(Tokeniser &tokeniser)
528     {
529         if (Brush::m_type == eBrushTypeQuake3BP || Brush::m_type == eBrushTypeDoom3 ||
530             Brush::m_type == eBrushTypeQuake4) {
531             tokeniser.nextLine();
532             RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "{"));
533         }
534         while (1) {
535             // check for end of brush
536             tokeniser.nextLine();
537             const char *token = tokeniser.getToken();
538             if (string_equal(token, "}")) {
539                 break;
540             }
541
542             tokeniser.ungetToken();
543
544             m_brush.push_back(FaceSmartPointer(new Face(&m_brush)));
545
546             //!todo BP support
547             tokeniser.nextLine();
548
549             Face &face = *m_brush.back();
550
551             switch (Brush::m_type) {
552                 case eBrushTypeDoom3: {
553                     Doom3FaceTokenImporter importer(face);
554                     RETURN_FALSE_IF_FAIL(importer.importTokens(tokeniser));
555                 }
556                     break;
557                 case eBrushTypeQuake4: {
558                     Quake4FaceTokenImporter importer(face);
559                     RETURN_FALSE_IF_FAIL(importer.importTokens(tokeniser));
560                 }
561                     break;
562                 case eBrushTypeQuake2: {
563                     Quake2FaceTokenImporter importer(face);
564                     RETURN_FALSE_IF_FAIL(importer.importTokens(tokeniser));
565                 }
566                     break;
567                 case eBrushTypeQuake3: {
568                     Quake3FaceTokenImporter importer(face);
569                     RETURN_FALSE_IF_FAIL(importer.importTokens(tokeniser));
570                 }
571                     break;
572                 case eBrushTypeQuake3BP: {
573                     Quake3BPFaceTokenImporter importer(face);
574                     RETURN_FALSE_IF_FAIL(importer.importTokens(tokeniser));
575                 }
576                     break;
577                 case eBrushTypeQuake: {
578                     QuakeFaceTokenImporter importer(face);
579                     RETURN_FALSE_IF_FAIL(importer.importTokens(tokeniser));
580                 }
581                     break;
582                 case eBrushTypeHalfLife: {
583                     HalfLifeFaceTokenImporter importer(face);
584                     RETURN_FALSE_IF_FAIL(importer.importTokens(tokeniser));
585                 }
586                     break;
587             }
588             face.planeChanged();
589         }
590         if (Brush::m_type == eBrushTypeQuake3BP || Brush::m_type == eBrushTypeDoom3 ||
591             Brush::m_type == eBrushTypeQuake4) {
592             tokeniser.nextLine();
593             RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "}"));
594         }
595
596         m_brush.planeChanged();
597         m_brush.shaderChanged();
598
599         return true;
600     }
601 };
602
603
604 class BrushTokenExporter : public MapExporter {
605     const Brush &m_brush;
606
607 public:
608     BrushTokenExporter(const Brush &brush) : m_brush(brush)
609     {
610     }
611
612     void exportTokens(TokenWriter &writer) const
613     {
614         m_brush.evaluateBRep(); // ensure b-rep is up-to-date, so that non-contributing faces can be identified.
615
616         if (!m_brush.hasContributingFaces()) {
617             return;
618         }
619
620         writer.writeToken("{");
621         writer.nextLine();
622
623         if (Brush::m_type == eBrushTypeQuake3BP) {
624             writer.writeToken("brushDef");
625             writer.nextLine();
626             writer.writeToken("{");
627             writer.nextLine();
628         }
629
630         if (Brush::m_type == eBrushTypeDoom3 || Brush::m_type == eBrushTypeQuake4) {
631             writer.writeToken("brushDef3");
632             writer.nextLine();
633             writer.writeToken("{");
634             writer.nextLine();
635         }
636
637         for (Brush::const_iterator i = m_brush.begin(); i != m_brush.end(); ++i) {
638             const Face &face = *(*i);
639
640             if (face.contributes()) {
641                 switch (Brush::m_type) {
642                     case eBrushTypeDoom3: {
643                         Doom3FaceTokenExporter exporter(face);
644                         exporter.exportTokens(writer);
645                     }
646                         break;
647                     case eBrushTypeQuake4: {
648                         Quake4FaceTokenExporter exporter(face);
649                         exporter.exportTokens(writer);
650                     }
651                         break;
652                     case eBrushTypeQuake2: {
653                         Quake2FaceTokenExporter exporter(face);
654                         exporter.exportTokens(writer);
655                     }
656                         break;
657                     case eBrushTypeQuake3: {
658                         Quake3FaceTokenExporter exporter(face);
659                         exporter.exportTokens(writer);
660                     }
661                         break;
662                     case eBrushTypeQuake3BP: {
663                         Quake3BPFaceTokenExporter exporter(face);
664                         exporter.exportTokens(writer);
665                     }
666                         break;
667                     case eBrushTypeQuake: {
668                         QuakeFaceTokenExporter exporter(face);
669                         exporter.exportTokens(writer);
670                     }
671                         break;
672                     case eBrushTypeHalfLife: {
673                         HalfLifeFaceTokenExporter exporter(face);
674                         exporter.exportTokens(writer);
675                     }
676                         break;
677                 }
678             }
679         }
680
681         if (Brush::m_type == eBrushTypeQuake3BP || Brush::m_type == eBrushTypeDoom3 ||
682             Brush::m_type == eBrushTypeQuake4) {
683             writer.writeToken("}");
684             writer.nextLine();
685         }
686
687         writer.writeToken("}");
688         writer.nextLine();
689     }
690 };
691
692
693 #endif