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 
FaceShader_importContentsFlagsValue(FaceShader & faceShader,Tokeniser & tokeniser)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 
FaceTexdef_importTokens(FaceTexdef & texdef,Tokeniser & tokeniser)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 
FaceTexdef_BP_importTokens(FaceTexdef & texdef,Tokeniser & tokeniser)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 
FaceTexdef_HalfLife_importTokens(FaceTexdef & texdef,Tokeniser & tokeniser)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 
FacePlane_importTokens(FacePlane & facePlane,Tokeniser & tokeniser)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 
FacePlane_Doom3_importTokens(FacePlane & facePlane,Tokeniser & tokeniser)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 
FaceShader_Doom3_importTokens(FaceShader & faceShader,Tokeniser & tokeniser)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 
FaceShader_importTokens(FaceShader & faceShader,Tokeniser & tokeniser)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:
Doom3FaceTokenImporter(Face & face)162 Doom3FaceTokenImporter( Face& face ) : m_face( face ){
163 }
importTokens(Tokeniser & tokeniser)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:
Quake4FaceTokenImporter(Face & face)181 Quake4FaceTokenImporter( Face& face ) : m_face( face ){
182 }
importTokens(Tokeniser & tokeniser)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:
Quake2FaceTokenImporter(Face & face)199 Quake2FaceTokenImporter( Face& face ) : m_face( face ){
200 }
importTokens(Tokeniser & tokeniser)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:
Quake3FaceTokenImporter(Face & face)218 Quake3FaceTokenImporter( Face& face ) : m_face( face ){
219 }
importTokens(Tokeniser & tokeniser)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:
Quake3BPFaceTokenImporter(Face & face)234 Quake3BPFaceTokenImporter( Face& face ) : m_face( face ){
235 }
importTokens(Tokeniser & tokeniser)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:
QuakeFaceTokenImporter(Face & face)253 QuakeFaceTokenImporter( Face& face ) : m_face( face ){
254 }
importTokens(Tokeniser & tokeniser)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:
HalfLifeFaceTokenImporter(Face & face)268 HalfLifeFaceTokenImporter( Face& face ) : m_face( face ){
269 }
importTokens(Tokeniser & tokeniser)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 
FacePlane_Doom3_exportTokens(const FacePlane & facePlane,TokenWriter & writer)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 
FacePlane_exportTokens(const FacePlane & facePlane,TokenWriter & writer)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 
FaceTexdef_BP_exportTokens(const FaceTexdef & faceTexdef,TokenWriter & writer)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 
FaceTexdef_exportTokens(const FaceTexdef & faceTexdef,TokenWriter & writer)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 
FaceTexdef_HalfLife_exportTokens(const FaceTexdef & faceTexdef,TokenWriter & writer)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 
FaceShader_ContentsFlagsValue_exportTokens(const FaceShader & faceShader,TokenWriter & writer)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 
FaceShader_exportTokens(const FaceShader & faceShader,TokenWriter & writer)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 
FaceShader_Doom3_exportTokens(const FaceShader & faceShader,TokenWriter & writer)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:
Doom3FaceTokenExporter(const Face & face)388 Doom3FaceTokenExporter( const Face& face ) : m_face( face ){
389 }
exportTokens(TokenWriter & writer)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:
Quake4FaceTokenExporter(const Face & face)403 Quake4FaceTokenExporter( const Face& face ) : m_face( face ){
404 }
exportTokens(TokenWriter & writer)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:
Quake2FaceTokenExporter(const Face & face)417 Quake2FaceTokenExporter( const Face& face ) : m_face( face ){
418 }
exportTokens(TokenWriter & writer)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:
Quake3FaceTokenExporter(const Face & face)434 Quake3FaceTokenExporter( const Face& face ) : m_face( face ){
435 }
exportTokens(TokenWriter & writer)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:
Quake3BPFaceTokenExporter(const Face & face)449 Quake3BPFaceTokenExporter( const Face& face ) : m_face( face ){
450 }
exportTokens(TokenWriter & writer)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:
QuakeFaceTokenExporter(const Face & face)464 QuakeFaceTokenExporter( const Face& face ) : m_face( face ){
465 }
exportTokens(TokenWriter & writer)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:
HalfLifeFaceTokenExporter(const Face & face)478 HalfLifeFaceTokenExporter( const Face& face ) : m_face( face ){
479 }
exportTokens(TokenWriter & writer)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:
BrushTokenImporter(Brush & brush)494 BrushTokenImporter( Brush& brush ) : m_brush( brush ){
495 }
importTokens(Tokeniser & tokeniser)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 		m_brush.push_back( FaceSmartPointer( new Face( &m_brush ) ) );
513 
514 		//!todo BP support
515 		tokeniser.nextLine();
516 
517 		Face& face = *m_brush.back();
518 
519 		switch ( Brush::m_type )
520 		{
521 		case eBrushTypeDoom3:
522 		{
523 			Doom3FaceTokenImporter importer( face );
524 			RETURN_FALSE_IF_FAIL( importer.importTokens( tokeniser ) );
525 		}
526 		break;
527 		case eBrushTypeQuake4:
528 		{
529 			Quake4FaceTokenImporter importer( face );
530 			RETURN_FALSE_IF_FAIL( importer.importTokens( tokeniser ) );
531 		}
532 		break;
533 		case eBrushTypeQuake2:
534 		{
535 			Quake2FaceTokenImporter importer( face );
536 			RETURN_FALSE_IF_FAIL( importer.importTokens( tokeniser ) );
537 		}
538 		break;
539 		case eBrushTypeQuake3:
540 		{
541 			Quake3FaceTokenImporter importer( face );
542 			RETURN_FALSE_IF_FAIL( importer.importTokens( tokeniser ) );
543 		}
544 		break;
545 		case eBrushTypeQuake3BP:
546 		{
547 			Quake3BPFaceTokenImporter importer( face );
548 			RETURN_FALSE_IF_FAIL( importer.importTokens( tokeniser ) );
549 		}
550 		break;
551 		case eBrushTypeQuake:
552 		{
553 			QuakeFaceTokenImporter importer( face );
554 			RETURN_FALSE_IF_FAIL( importer.importTokens( tokeniser ) );
555 		}
556 		break;
557 		case eBrushTypeHalfLife:
558 		{
559 			HalfLifeFaceTokenImporter importer( face );
560 			RETURN_FALSE_IF_FAIL( importer.importTokens( tokeniser ) );
561 		}
562 		break;
563 		}
564 		face.planeChanged();
565 	}
566 	if ( Brush::m_type == eBrushTypeQuake3BP || Brush::m_type == eBrushTypeDoom3 || Brush::m_type == eBrushTypeQuake4 ) {
567 		tokeniser.nextLine();
568 		RETURN_FALSE_IF_FAIL( Tokeniser_parseToken( tokeniser, "}" ) );
569 	}
570 
571 	m_brush.planeChanged();
572 	m_brush.shaderChanged();
573 
574 	return true;
575 }
576 };
577 
578 
579 class BrushTokenExporter : public MapExporter
580 {
581 const Brush& m_brush;
582 
583 public:
BrushTokenExporter(const Brush & brush)584 BrushTokenExporter( const Brush& brush ) : m_brush( brush ){
585 }
exportTokens(TokenWriter & writer)586 void exportTokens( TokenWriter& writer ) const {
587 	m_brush.evaluateBRep(); // ensure b-rep is up-to-date, so that non-contributing faces can be identified.
588 
589 	if ( !m_brush.hasContributingFaces() ) {
590 		return;
591 	}
592 
593 	writer.writeToken( "{" );
594 	writer.nextLine();
595 
596 	if ( Brush::m_type == eBrushTypeQuake3BP ) {
597 		writer.writeToken( "brushDef" );
598 		writer.nextLine();
599 		writer.writeToken( "{" );
600 		writer.nextLine();
601 	}
602 
603 	if ( Brush::m_type == eBrushTypeDoom3 || Brush::m_type == eBrushTypeQuake4 ) {
604 		writer.writeToken( "brushDef3" );
605 		writer.nextLine();
606 		writer.writeToken( "{" );
607 		writer.nextLine();
608 	}
609 
610 	for ( Brush::const_iterator i = m_brush.begin(); i != m_brush.end(); ++i )
611 	{
612 		const Face& face = *( *i );
613 
614 		if ( face.contributes() ) {
615 			switch ( Brush::m_type )
616 			{
617 			case eBrushTypeDoom3:
618 			{
619 				Doom3FaceTokenExporter exporter( face );
620 				exporter.exportTokens( writer );
621 			}
622 			break;
623 			case eBrushTypeQuake4:
624 			{
625 				Quake4FaceTokenExporter exporter( face );
626 				exporter.exportTokens( writer );
627 			}
628 			break;
629 			case eBrushTypeQuake2:
630 			{
631 				Quake2FaceTokenExporter exporter( face );
632 				exporter.exportTokens( writer );
633 			}
634 			break;
635 			case eBrushTypeQuake3:
636 			{
637 				Quake3FaceTokenExporter exporter( face );
638 				exporter.exportTokens( writer );
639 			}
640 			break;
641 			case eBrushTypeQuake3BP:
642 			{
643 				Quake3BPFaceTokenExporter exporter( face );
644 				exporter.exportTokens( writer );
645 			}
646 			break;
647 			case eBrushTypeQuake:
648 			{
649 				QuakeFaceTokenExporter exporter( face );
650 				exporter.exportTokens( writer );
651 			}
652 			break;
653 			case eBrushTypeHalfLife:
654 			{
655 				HalfLifeFaceTokenExporter exporter( face );
656 				exporter.exportTokens( writer );
657 			}
658 			break;
659 			}
660 		}
661 	}
662 
663 	if ( Brush::m_type == eBrushTypeQuake3BP || Brush::m_type == eBrushTypeDoom3 || Brush::m_type == eBrushTypeQuake4 ) {
664 		writer.writeToken( "}" );
665 		writer.nextLine();
666 	}
667 
668 	writer.writeToken( "}" );
669 	writer.nextLine();
670 }
671 };
672 
673 
674 #endif
675