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