2 Copyright (C) 2001-2006, William Joseph.
5 This file is part of GtkRadiant.
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.
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.
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
22 #if !defined( INCLUDED_BRUSHXML_H )
23 #define INCLUDED_BRUSHXML_H
25 #include "stream/stringstream.h"
26 #include "xml/xmlelement.h"
30 inline void FaceTexdef_BP_importXML( FaceTexdef& texdef, const char* xmlContent ){
31 StringTokeniser content( xmlContent );
33 texdef.m_projection.m_brushprimit_texdef.coords[0][0] = static_cast<float>( atof( content.getToken() ) );
34 texdef.m_projection.m_brushprimit_texdef.coords[0][1] = static_cast<float>( atof( content.getToken() ) );
35 texdef.m_projection.m_brushprimit_texdef.coords[0][2] = static_cast<float>( atof( content.getToken() ) );
36 texdef.m_projection.m_brushprimit_texdef.coords[1][0] = static_cast<float>( atof( content.getToken() ) );
37 texdef.m_projection.m_brushprimit_texdef.coords[1][1] = static_cast<float>( atof( content.getToken() ) );
38 texdef.m_projection.m_brushprimit_texdef.coords[1][2] = static_cast<float>( atof( content.getToken() ) );
40 inline void FaceTexdef_importXML( FaceTexdef& texdef, const char* xmlContent ){
41 StringTokeniser content( xmlContent );
43 texdef.m_projection.m_texdef.shift[0] = static_cast<float>( atof( content.getToken() ) );
44 texdef.m_projection.m_texdef.shift[1] = static_cast<float>( atof( content.getToken() ) );
45 texdef.m_projection.m_texdef.rotate = static_cast<float>( atof( content.getToken() ) );
46 texdef.m_projection.m_texdef.scale[0] = static_cast<float>( atof( content.getToken() ) );
47 texdef.m_projection.m_texdef.scale[1] = static_cast<float>( atof( content.getToken() ) );
49 ASSERT_MESSAGE( texdef_sane( texdef.m_projection.m_texdef ), "FaceTexdef_importXML: bad texdef" );
52 inline void FacePlane_importXML( FacePlane& facePlane, const char* xmlContent ){
53 StringTokeniser content( xmlContent );
55 for ( int i = 0; i < 3; ++i )
57 for ( int j = 0; j < 3; ++j )
59 facePlane.planePoints()[i][j] = atof( content.getToken() );
62 facePlane.MakePlane();
81 StringOutputStream m_content;
83 xml_state_t( EState state )
87 EState state() const {
90 const char* content() const {
91 return m_content.c_str();
93 std::size_t write( const char* buffer, std::size_t length ){
94 return m_content.write( buffer, length );
98 std::vector<xml_state_t> m_xml_state;
101 FaceXMLImporter( Face& face ) : m_face( face ){
102 m_xml_state.push_back( xml_state_t::eDefault );
105 m_face.planeChanged();
108 void pushElement( const XMLElement& element ){
109 ASSERT_MESSAGE( m_xml_state.back().state() == xml_state_t::eDefault, "parse error" );
111 if ( strcmp( element.name(), "planepts" ) == 0 ) {
112 m_xml_state.push_back( xml_state_t::ePlanePts );
114 else if ( strcmp( element.name(), "texdef" ) == 0 ) {
115 m_xml_state.push_back( xml_state_t::eTexdef );
117 else if ( strcmp( element.name(), "bpmatrix" ) == 0 ) {
118 m_xml_state.push_back( xml_state_t::eBPMatrix );
120 else if ( strcmp( element.name(), "flags" ) == 0 ) {
121 m_xml_state.push_back( xml_state_t::eFlags );
123 else if ( strcmp( element.name(), "shader" ) == 0 ) {
124 m_xml_state.push_back( xml_state_t::eShader );
127 void popElement( const char* name ){
128 ASSERT_MESSAGE( m_xml_state.back().state() != xml_state_t::eDefault, "parse error" );
130 switch ( m_xml_state.back().state() )
132 case xml_state_t::ePlanePts:
134 FacePlane_importXML( m_face.getPlane(), m_xml_state.back().content() );
137 case xml_state_t::eTexdef:
139 FaceTexdef_importXML( m_face.getTexdef(), m_xml_state.back().content() );
142 case xml_state_t::eBPMatrix:
144 FaceTexdef_BP_importXML( m_face.getTexdef(), m_xml_state.back().content() );
147 case xml_state_t::eFlags:
149 StringTokeniser content( m_xml_state.back().content() );
151 m_face.getShader().m_flags.m_contentFlags = atoi( content.getToken() );
152 m_face.getShader().m_flags.m_surfaceFlags = atoi( content.getToken() );
153 m_face.getShader().m_flags.m_value = atoi( content.getToken() );
156 case xml_state_t::eShader:
158 m_face.getShader().setShader( m_xml_state.back().content() );
165 m_xml_state.pop_back();
167 std::size_t write( const char* data, std::size_t length ){
168 ASSERT_MESSAGE( !m_xml_state.empty(), "parse error" );
169 return m_xml_state.back().write( data, length );
174 inline void FaceTexdef_exportXML( const FaceTexdef& texdef, XMLImporter& importer ){
175 StaticElement element( "texdef" );
176 importer.pushElement( element );
178 ASSERT_MESSAGE( texdef_sane( texdef.m_projection.m_texdef ), "FaceTexdef_exportXML: bad texdef" );
180 importer << texdef.m_projection.m_texdef.shift[0]
181 << ' ' << texdef.m_projection.m_texdef.shift[1]
182 << ' ' << texdef.m_projection.m_texdef.rotate
183 << ' ' << texdef.m_projection.m_texdef.scale[0]
184 << ' ' << texdef.m_projection.m_texdef.scale[1];
186 importer.popElement( element.name() );
188 inline void FaceTexdef_BP_exportXML( const FaceTexdef& texdef, XMLImporter& importer ){
189 StaticElement element( "texdef" );
190 importer.pushElement( element );
192 for ( int i = 0; i < 2; ++i )
194 for ( int j = 0; j < 3; ++j )
196 importer << texdef.m_projection.m_brushprimit_texdef.coords[i][j] << ' ';
200 importer.popElement( element.name() );
202 inline void FaceShader_ContentsFlagsValue_exportXML( const FaceShader& faceShader, XMLImporter& importer ){
203 StaticElement element( "flags" );
204 importer.pushElement( element );
207 importer << faceShader.m_flags.m_contentFlags
208 << ' ' << faceShader.m_flags.m_surfaceFlags
209 << ' ' << faceShader.m_flags.m_value;
212 importer.popElement( element.name() );
215 inline void FacePlane_exportXML( const FacePlane& facePlane, XMLImporter& importer ){
216 StaticElement element( "planepts" );
217 importer.pushElement( element );
221 for ( int i = 0 ; i < 3 ; i++ )
223 for ( int j = 0 ; j < 3 ; j++ )
225 importer << Face::m_quantise( facePlane.planePoints()[i][j] ) << ' ';
230 importer.popElement( element.name() );
233 inline void FacePolygon_exportXML( const Winding& w, const BasicVector3<double>& normal, XMLImporter& importer ){
234 DynamicElement element( "polygon" );
238 sprintf( tmp, "%f", normal.x() );
239 element.insertAttribute( "nx", tmp );
241 sprintf( tmp, "%f", normal.y() );
242 element.insertAttribute( "ny", tmp );
244 sprintf( tmp, "%f", normal.z() );
245 element.insertAttribute( "nz", tmp );
247 importer.pushElement( element );
249 for ( unsigned int i = 0; i < w.numpoints; ++i )
251 DynamicElement c( "vertex" );
253 sprintf( tmp, "%f", w.points[i].vertex.x() );
254 c.insertAttribute( "x", tmp );
256 sprintf( tmp, "%f", w.points[i].vertex.y() );
257 c.insertAttribute( "y", tmp );
259 sprintf( tmp, "%f", w.points[i].vertex.z() );
260 c.insertAttribute( "z", tmp );
262 sprintf( tmp, "%f", w.points[i].texcoord.x() );
263 c.insertAttribute( "s", tmp );
265 sprintf( tmp, "%f", w.points[i].texcoord.y() );
266 c.insertAttribute( "t", tmp );
268 importer.pushElement( c );
269 importer.popElement( c.name() );
272 importer.popElement( element.name() );
275 class FaceXMLExporter
279 FaceXMLExporter( const Face& face ) : m_face( face ){
281 void exportXML( XMLImporter& importer ){
282 bool bAlternateTexdef = ( Face::m_type == eBrushTypeQuake3BP || Face::m_type == eBrushTypeDoom3 || Face::m_type == eBrushTypeQuake4 );
286 StaticElement element( "shader" );
287 importer.pushElement( element );
288 importer << m_face.getShader().getShader();
289 importer.popElement( element.name() );
292 FacePolygon_exportXML( m_face.getWinding(), m_face.getPlane().plane3().normal(), importer );
293 FacePlane_exportXML( m_face.getPlane(), importer );
295 if ( !bAlternateTexdef ) {
296 FaceTexdef_exportXML( m_face.getTexdef(), importer );
300 FaceTexdef_BP_exportXML( m_face.getTexdef(), importer );
303 FaceShader_ContentsFlagsValue_exportXML( m_face.getShader(), importer );
308 class BrushXMLImporter : public XMLImporter
324 xml_state_t( EState state )
327 EState state() const {
332 std::vector<xml_state_t> m_xml_state;
333 char m_faceImporter[sizeof( FaceXMLImporter )];
336 FaceXMLImporter& faceImporter(){
337 return *reinterpret_cast<FaceXMLImporter*>( m_faceImporter );
341 BrushXMLImporter( Brush& brush ) : m_brush( brush ){
342 m_xml_state.push_back( xml_state_t::eDefault );
344 void pushElement( const XMLElement& element ){
345 switch ( m_xml_state.back().state() )
347 case xml_state_t::eDefault:
348 ASSERT_MESSAGE( strcmp( element.name(), "brush" ) == 0, "parse error" );
349 m_xml_state.push_back( xml_state_t::eBrush );
351 case xml_state_t::eBrush:
352 ASSERT_MESSAGE( strcmp( element.name(), "plane" ) == 0, "parse error" );
353 m_xml_state.push_back( xml_state_t::eFace );
354 m_brush.push_back( FaceSmartPointer( new Face( &m_brush ) ) );
355 constructor( faceImporter(), makeReference( *m_brush.back() ) );
356 m_brush.planeChanged();
357 m_brush.shaderChanged();
359 case xml_state_t::eFace:
360 m_xml_state.push_back( xml_state_t::eFace );
361 faceImporter().pushElement( element );
365 void popElement( const char* name ){
366 ASSERT_MESSAGE( !m_xml_state.empty(), "parse error" );
367 m_xml_state.pop_back();
369 switch ( m_xml_state.back().state() )
371 case xml_state_t::eDefault:
373 case xml_state_t::eBrush:
374 destructor( faceImporter() );
376 case xml_state_t::eFace:
377 faceImporter().popElement( name );
381 std::size_t write( const char* data, std::size_t length ){
382 switch ( m_xml_state.back().state() )
384 case xml_state_t::eFace:
385 return faceImporter().write( data, length );
394 class BrushXMLExporter : public XMLExporter
396 const Brush& m_brush;
399 BrushXMLExporter( const Brush& brush ) : m_brush( brush ){
401 void exportXML( XMLImporter& importer ){
402 m_brush.evaluateBRep(); // ensure b-rep is up-to-date, so that non-contributing faces can be identified.
403 ASSERT_MESSAGE( m_brush.hasContributingFaces(), "exporting an empty brush" );
405 const StaticElement brushElement( "brush" );
406 importer.pushElement( brushElement );
408 for ( Brush::const_iterator i = m_brush.begin(); i != m_brush.end(); ++i )
410 if ( ( *i )->contributes() ) {
411 const StaticElement element( "plane" );
412 importer.pushElement( element );
413 FaceXMLExporter( *( *i ) ).exportXML( importer );
414 importer.popElement( element.name() );
418 importer.popElement( brushElement.name() );