auto str = StringOutputStream()(bla) use form was not doing copy elision or move, but copy
656 lines
22 KiB
C++
656 lines
22 KiB
C++
/*
|
|
Copyright (C) 2001-2006, William Joseph.
|
|
All Rights Reserved.
|
|
|
|
This file is part of GtkRadiant.
|
|
|
|
GtkRadiant is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
GtkRadiant is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with GtkRadiant; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "stringio.h"
|
|
#include "stream/stringstream.h"
|
|
#include "brush.h"
|
|
|
|
inline bool FaceShader_importContentsFlagsValue( FaceShader& faceShader, Tokeniser& tokeniser ){
|
|
// parse the optional contents/flags/value
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_getInteger( tokeniser, faceShader.m_flags.m_contentFlags ) );
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_getInteger( tokeniser, faceShader.m_flags.m_surfaceFlags ) );
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_getInteger( tokeniser, faceShader.m_flags.m_value ) );
|
|
return true;
|
|
}
|
|
|
|
inline bool FaceTexdef_importTokens( FaceTexdef& texdef, Tokeniser& tokeniser ){
|
|
// parse texdef
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_getFloat( tokeniser, texdef.m_projection.m_texdef.shift[0] ) );
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_getFloat( tokeniser, texdef.m_projection.m_texdef.shift[1] ) );
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_getFloat( tokeniser, texdef.m_projection.m_texdef.rotate ) );
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_getFloat( tokeniser, texdef.m_projection.m_texdef.scale[0] ) );
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_getFloat( tokeniser, texdef.m_projection.m_texdef.scale[1] ) );
|
|
|
|
if( !texdef_sane( texdef.m_projection.m_texdef ) )
|
|
globalWarningStream() << "FaceTexdef_importTokens: bad texdef\n";
|
|
|
|
return true;
|
|
}
|
|
|
|
inline bool FaceTexdef_BP_importTokens( FaceTexdef& texdef, Tokeniser& tokeniser ){
|
|
// parse alternate texdef
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_parseToken( tokeniser, "(" ) );
|
|
{
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_parseToken( tokeniser, "(" ) );
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_getFloat( tokeniser, texdef.m_projection.m_brushprimit_texdef.coords[0][0] ) );
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_getFloat( tokeniser, texdef.m_projection.m_brushprimit_texdef.coords[0][1] ) );
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_getFloat( tokeniser, texdef.m_projection.m_brushprimit_texdef.coords[0][2] ) );
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_parseToken( tokeniser, ")" ) );
|
|
}
|
|
{
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_parseToken( tokeniser, "(" ) );
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_getFloat( tokeniser, texdef.m_projection.m_brushprimit_texdef.coords[1][0] ) );
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_getFloat( tokeniser, texdef.m_projection.m_brushprimit_texdef.coords[1][1] ) );
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_getFloat( tokeniser, texdef.m_projection.m_brushprimit_texdef.coords[1][2] ) );
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_parseToken( tokeniser, ")" ) );
|
|
}
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_parseToken( tokeniser, ")" ) );
|
|
return true;
|
|
}
|
|
|
|
inline bool FaceTexdef_Valve220_importTokens( FaceTexdef& texdef, Tokeniser& tokeniser ){
|
|
// parse texdef
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_parseToken( tokeniser, "[" ) );
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_getFloat( tokeniser, texdef.m_projection.m_basis_s.x() ) );
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_getFloat( tokeniser, texdef.m_projection.m_basis_s.y() ) );
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_getFloat( tokeniser, texdef.m_projection.m_basis_s.z() ) );
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_getFloat( tokeniser, texdef.m_projection.m_texdef.shift[0] ) );
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_parseToken( tokeniser, "]" ) );
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_parseToken( tokeniser, "[" ) );
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_getFloat( tokeniser, texdef.m_projection.m_basis_t.x() ) );
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_getFloat( tokeniser, texdef.m_projection.m_basis_t.y() ) );
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_getFloat( tokeniser, texdef.m_projection.m_basis_t.z() ) );
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_getFloat( tokeniser, texdef.m_projection.m_texdef.shift[1] ) );
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_parseToken( tokeniser, "]" ) );
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_getFloat( tokeniser, texdef.m_projection.m_texdef.rotate ) );
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_getFloat( tokeniser, texdef.m_projection.m_texdef.scale[0] ) );
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_getFloat( tokeniser, texdef.m_projection.m_texdef.scale[1] ) );
|
|
|
|
texdef.m_projection.m_texdef.rotate = -texdef.m_projection.m_texdef.rotate;
|
|
|
|
if( !texdef_sane( texdef.m_projection.m_texdef ) )
|
|
globalWarningStream() << "FaceTexdef_Valve220_importTokens: bad texdef\n";
|
|
|
|
return true;
|
|
}
|
|
|
|
inline bool FacePlane_importTokens( FacePlane& facePlane, Tokeniser& tokeniser ){
|
|
// parse planepts
|
|
for ( std::size_t i = 0; i < 3; i++ )
|
|
{
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_parseToken( tokeniser, "(" ) );
|
|
for ( std::size_t j = 0; j < 3; ++j )
|
|
{
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_getDouble( tokeniser, facePlane.planePoints()[i][j] ) );
|
|
}
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_parseToken( tokeniser, ")" ) );
|
|
}
|
|
facePlane.MakePlane();
|
|
return true;
|
|
}
|
|
|
|
inline bool FacePlane_Doom3_importTokens( FacePlane& facePlane, Tokeniser& tokeniser ){
|
|
Plane3 plane;
|
|
// parse plane equation
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_parseToken( tokeniser, "(" ) );
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_getDouble( tokeniser, plane.a ) );
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_getDouble( tokeniser, plane.b ) );
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_getDouble( tokeniser, plane.c ) );
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_getDouble( tokeniser, plane.d ) );
|
|
plane.d = -plane.d;
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_parseToken( tokeniser, ")" ) );
|
|
|
|
facePlane.setDoom3Plane( plane );
|
|
return true;
|
|
}
|
|
|
|
inline bool FaceShader_Doom3_importTokens( FaceShader& faceShader, Tokeniser& tokeniser ){
|
|
const char *shader = tokeniser.getToken();
|
|
if ( shader == 0 ) {
|
|
Tokeniser_unexpectedError( tokeniser, shader, "#shader-name" );
|
|
return false;
|
|
}
|
|
if ( string_equal( shader, "_emptyname" ) ) {
|
|
shader = texdef_name_default();
|
|
}
|
|
faceShader.setShader( shader );
|
|
return true;
|
|
}
|
|
|
|
inline bool FaceShader_importTokens( FaceShader& faceShader, Tokeniser& tokeniser ){
|
|
const char* texture = tokeniser.getToken();
|
|
if ( texture == 0 ) {
|
|
Tokeniser_unexpectedError( tokeniser, texture, "#texture-name" );
|
|
return false;
|
|
}
|
|
if ( string_equal( texture, "NULL" ) ) {
|
|
faceShader.setShader( texdef_name_default() );
|
|
}
|
|
else
|
|
{
|
|
faceShader.setShader( StringStream<64>( GlobalTexturePrefix_get(), texture ) );
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
|
|
class Doom3FaceTokenImporter
|
|
{
|
|
Face& m_face;
|
|
public:
|
|
Doom3FaceTokenImporter( Face& face ) : m_face( face ){
|
|
}
|
|
bool importTokens( Tokeniser& tokeniser ){
|
|
RETURN_FALSE_IF_FAIL( FacePlane_Doom3_importTokens( m_face.getPlane(), tokeniser ) );
|
|
RETURN_FALSE_IF_FAIL( FaceTexdef_BP_importTokens( m_face.getTexdef(), tokeniser ) );
|
|
RETURN_FALSE_IF_FAIL( FaceShader_Doom3_importTokens( m_face.getShader(), tokeniser ) );
|
|
RETURN_FALSE_IF_FAIL( FaceShader_importContentsFlagsValue( m_face.getShader(), tokeniser ) );
|
|
|
|
m_face.getTexdef().m_projectionInitialised = true;
|
|
m_face.getTexdef().m_scaleApplied = true;
|
|
|
|
return true;
|
|
}
|
|
};
|
|
|
|
class Quake4FaceTokenImporter
|
|
{
|
|
Face& m_face;
|
|
public:
|
|
Quake4FaceTokenImporter( Face& face ) : m_face( face ){
|
|
}
|
|
bool importTokens( Tokeniser& tokeniser ){
|
|
RETURN_FALSE_IF_FAIL( FacePlane_Doom3_importTokens( m_face.getPlane(), tokeniser ) );
|
|
RETURN_FALSE_IF_FAIL( FaceTexdef_BP_importTokens( m_face.getTexdef(), tokeniser ) );
|
|
RETURN_FALSE_IF_FAIL( FaceShader_Doom3_importTokens( m_face.getShader(), tokeniser ) );
|
|
|
|
m_face.getTexdef().m_projectionInitialised = true;
|
|
m_face.getTexdef().m_scaleApplied = true;
|
|
|
|
return true;
|
|
}
|
|
};
|
|
|
|
class QuakeFaceTokenImporter
|
|
{
|
|
Face& m_face;
|
|
public:
|
|
QuakeFaceTokenImporter( Face& face ) : m_face( face ){
|
|
}
|
|
bool importTokens( Tokeniser& tokeniser ){
|
|
RETURN_FALSE_IF_FAIL( FacePlane_importTokens( m_face.getPlane(), tokeniser ) );
|
|
RETURN_FALSE_IF_FAIL( FaceShader_importTokens( m_face.getShader(), tokeniser ) );
|
|
RETURN_FALSE_IF_FAIL( FaceTexdef_importTokens( m_face.getTexdef(), tokeniser ) );
|
|
// optional face flags
|
|
// Q1: normally not present, try to load to handle 3rd party maps with them or extended format with flags
|
|
// Q2: presence determines whether flags are considered as specified (otherwise embedded .wal flags are used)
|
|
// Q3: normally present, load optionally to handle 3rd party maps without them
|
|
if ( Tokeniser_nextTokenIsDigit( tokeniser ) ) {
|
|
m_face.getShader().m_flags.m_specified = true; // enable for Q2
|
|
RETURN_FALSE_IF_FAIL( FaceShader_importContentsFlagsValue( m_face.getShader(), tokeniser ) );
|
|
}
|
|
m_face.getTexdef().m_scaleApplied = true;
|
|
return true;
|
|
}
|
|
};
|
|
|
|
class Quake3BPFaceTokenImporter
|
|
{
|
|
Face& m_face;
|
|
public:
|
|
Quake3BPFaceTokenImporter( Face& face ) : m_face( face ){
|
|
}
|
|
bool importTokens( Tokeniser& tokeniser ){
|
|
RETURN_FALSE_IF_FAIL( FacePlane_importTokens( m_face.getPlane(), tokeniser ) );
|
|
RETURN_FALSE_IF_FAIL( FaceTexdef_BP_importTokens( m_face.getTexdef(), tokeniser ) );
|
|
RETURN_FALSE_IF_FAIL( FaceShader_importTokens( m_face.getShader(), tokeniser ) );
|
|
if ( Tokeniser_nextTokenIsDigit( tokeniser ) ) { ///optional for more flexibility
|
|
m_face.getShader().m_flags.m_specified = true; // enable for Q2
|
|
RETURN_FALSE_IF_FAIL( FaceShader_importContentsFlagsValue( m_face.getShader(), tokeniser ) );
|
|
}
|
|
|
|
m_face.getTexdef().m_projectionInitialised = true;
|
|
m_face.getTexdef().m_scaleApplied = true;
|
|
|
|
return true;
|
|
}
|
|
};
|
|
|
|
class Valve220FaceTokenImporter
|
|
{
|
|
Face& m_face;
|
|
public:
|
|
Valve220FaceTokenImporter( Face& face ) : m_face( face ){
|
|
}
|
|
bool importTokens( Tokeniser& tokeniser ){
|
|
RETURN_FALSE_IF_FAIL( FacePlane_importTokens( m_face.getPlane(), tokeniser ) );
|
|
RETURN_FALSE_IF_FAIL( FaceShader_importTokens( m_face.getShader(), tokeniser ) );
|
|
RETURN_FALSE_IF_FAIL( FaceTexdef_Valve220_importTokens( m_face.getTexdef(), tokeniser ) );
|
|
if ( Tokeniser_nextTokenIsDigit( tokeniser ) ) { ///optional for more flexibility
|
|
m_face.getShader().m_flags.m_specified = true; // enable for Q2
|
|
RETURN_FALSE_IF_FAIL( FaceShader_importContentsFlagsValue( m_face.getShader(), tokeniser ) );
|
|
}
|
|
m_face.getTexdef().m_scaleApplied = true;
|
|
return true;
|
|
}
|
|
};
|
|
|
|
|
|
inline void FacePlane_Doom3_exportTokens( const FacePlane& facePlane, TokenWriter& writer ){
|
|
// write plane equation
|
|
writer.writeToken( "(" );
|
|
writer.writeFloat( facePlane.getDoom3Plane().a );
|
|
writer.writeFloat( facePlane.getDoom3Plane().b );
|
|
writer.writeFloat( facePlane.getDoom3Plane().c );
|
|
writer.writeFloat( -facePlane.getDoom3Plane().d );
|
|
writer.writeToken( ")" );
|
|
}
|
|
|
|
inline void FacePlane_exportTokens( const FacePlane& facePlane, TokenWriter& writer ){
|
|
// write planepts
|
|
for ( std::size_t i = 0; i < 3; i++ )
|
|
{
|
|
writer.writeToken( "(" );
|
|
for ( std::size_t j = 0; j < 3; j++ )
|
|
{
|
|
writer.writeFloat( Face::m_quantise( facePlane.planePoints()[i][j] ) );
|
|
}
|
|
writer.writeToken( ")" );
|
|
}
|
|
}
|
|
|
|
inline void FaceTexdef_BP_exportTokens( const FaceTexdef& faceTexdef, TokenWriter& writer ){
|
|
// write alternate texdef
|
|
writer.writeToken( "(" );
|
|
{
|
|
writer.writeToken( "(" );
|
|
for ( std::size_t i = 0; i < 3; i++ )
|
|
{
|
|
writer.writeFloat( faceTexdef.m_projection.m_brushprimit_texdef.coords[0][i] );
|
|
}
|
|
writer.writeToken( ")" );
|
|
}
|
|
{
|
|
writer.writeToken( "(" );
|
|
for ( std::size_t i = 0; i < 3; i++ )
|
|
{
|
|
writer.writeFloat( faceTexdef.m_projection.m_brushprimit_texdef.coords[1][i] );
|
|
}
|
|
writer.writeToken( ")" );
|
|
}
|
|
writer.writeToken( ")" );
|
|
}
|
|
|
|
inline void FaceTexdef_exportTokens( const FaceTexdef& faceTexdef, TokenWriter& writer ){
|
|
if( !texdef_sane( faceTexdef.m_projection.m_texdef ) )
|
|
globalWarningStream() << "FaceTexdef_exportTokens: bad texdef\n";
|
|
// write texdef
|
|
writer.writeFloat( faceTexdef.m_projection.m_texdef.shift[0] );
|
|
writer.writeFloat( faceTexdef.m_projection.m_texdef.shift[1] );
|
|
writer.writeFloat( faceTexdef.m_projection.m_texdef.rotate );
|
|
writer.writeFloat( faceTexdef.m_projection.m_texdef.scale[0] );
|
|
writer.writeFloat( faceTexdef.m_projection.m_texdef.scale[1] );
|
|
}
|
|
|
|
inline void FaceTexdef_Valve220_exportTokens( const FaceTexdef& faceTexdef, TokenWriter& writer ){
|
|
if( !texdef_sane( faceTexdef.m_projection.m_texdef ) )
|
|
globalWarningStream() << "FaceTexdef_Valve220_exportTokens: bad texdef\n";
|
|
// write texdef
|
|
writer.writeToken( "[" );
|
|
writer.writeFloat( faceTexdef.m_projection.m_basis_s.x() );
|
|
writer.writeFloat( faceTexdef.m_projection.m_basis_s.y() );
|
|
writer.writeFloat( faceTexdef.m_projection.m_basis_s.z() );
|
|
writer.writeFloat( faceTexdef.m_projection.m_texdef.shift[0] );
|
|
writer.writeToken( "]" );
|
|
writer.writeToken( "[" );
|
|
writer.writeFloat( faceTexdef.m_projection.m_basis_t.x() );
|
|
writer.writeFloat( faceTexdef.m_projection.m_basis_t.y() );
|
|
writer.writeFloat( faceTexdef.m_projection.m_basis_t.z() );
|
|
writer.writeFloat( faceTexdef.m_projection.m_texdef.shift[1] );
|
|
writer.writeToken( "]" );
|
|
writer.writeFloat( -faceTexdef.m_projection.m_texdef.rotate );
|
|
writer.writeFloat( faceTexdef.m_projection.m_texdef.scale[0] );
|
|
writer.writeFloat( faceTexdef.m_projection.m_texdef.scale[1] );
|
|
}
|
|
|
|
inline void FaceShader_ContentsFlagsValue_exportTokens( const FaceShader& faceShader, TokenWriter& writer ){
|
|
// write surface flags
|
|
writer.writeInteger( faceShader.m_flags.m_contentFlags );
|
|
writer.writeInteger( faceShader.m_flags.m_surfaceFlags );
|
|
writer.writeInteger( faceShader.m_flags.m_value );
|
|
}
|
|
|
|
inline void FaceShader_exportTokens( const FaceShader& faceShader, TokenWriter& writer ){
|
|
// write shader name
|
|
if ( string_empty( shader_get_textureName( faceShader.getShader() ) ) ) {
|
|
writer.writeToken( "NULL" );
|
|
}
|
|
else
|
|
{
|
|
writer.writeToken( shader_get_textureName( faceShader.getShader() ) );
|
|
}
|
|
}
|
|
|
|
inline void FaceShader_Doom3_exportTokens( const FaceShader& faceShader, TokenWriter& writer ){
|
|
// write shader name
|
|
if ( string_empty( shader_get_textureName( faceShader.getShader() ) ) ) {
|
|
writer.writeString( "_emptyname" );
|
|
}
|
|
else
|
|
{
|
|
writer.writeString( faceShader.getShader() );
|
|
}
|
|
}
|
|
|
|
class Doom3FaceTokenExporter
|
|
{
|
|
const Face& m_face;
|
|
public:
|
|
Doom3FaceTokenExporter( const Face& face ) : m_face( face ){
|
|
}
|
|
void exportTokens( TokenWriter& writer ) const {
|
|
FacePlane_Doom3_exportTokens( m_face.getPlane(), writer );
|
|
FaceTexdef_BP_exportTokens( m_face.getTexdef(), writer );
|
|
FaceShader_Doom3_exportTokens( m_face.getShader(), writer );
|
|
FaceShader_ContentsFlagsValue_exportTokens( m_face.getShader(), writer );
|
|
writer.nextLine();
|
|
}
|
|
};
|
|
|
|
class Quake4FaceTokenExporter
|
|
{
|
|
const Face& m_face;
|
|
public:
|
|
Quake4FaceTokenExporter( const Face& face ) : m_face( face ){
|
|
}
|
|
void exportTokens( TokenWriter& writer ) const {
|
|
FacePlane_Doom3_exportTokens( m_face.getPlane(), writer );
|
|
FaceTexdef_BP_exportTokens( m_face.getTexdef(), writer );
|
|
FaceShader_Doom3_exportTokens( m_face.getShader(), writer );
|
|
writer.nextLine();
|
|
}
|
|
};
|
|
|
|
enum class FaceExportFlags{
|
|
yes,
|
|
no,
|
|
optional
|
|
};
|
|
|
|
template<FaceExportFlags exportFlags>
|
|
void FaceFlags_exportTokens( const Face& face, TokenWriter& writer ){
|
|
if constexpr ( exportFlags == FaceExportFlags::yes ){
|
|
FaceShader_ContentsFlagsValue_exportTokens( face.getShader(), writer );
|
|
}
|
|
else if constexpr ( exportFlags == FaceExportFlags::optional ){
|
|
if ( face.getShader().m_flags.m_specified || face.isDetail() ) {
|
|
FaceShader_ContentsFlagsValue_exportTokens( face.getShader(), writer );
|
|
}
|
|
}
|
|
}
|
|
|
|
template<FaceExportFlags exportFlags>
|
|
class QuakeFaceTokenExporter
|
|
{
|
|
const Face& m_face;
|
|
public:
|
|
QuakeFaceTokenExporter( const Face& face ) : m_face( face ){
|
|
}
|
|
void exportTokens( TokenWriter& writer ) const {
|
|
FacePlane_exportTokens( m_face.getPlane(), writer );
|
|
FaceShader_exportTokens( m_face.getShader(), writer );
|
|
FaceTexdef_exportTokens( m_face.getTexdef(), writer );
|
|
FaceFlags_exportTokens<exportFlags>( m_face, writer );
|
|
writer.nextLine();
|
|
}
|
|
};
|
|
|
|
template<FaceExportFlags exportFlags>
|
|
class Quake3BPFaceTokenExporter
|
|
{
|
|
const Face& m_face;
|
|
public:
|
|
Quake3BPFaceTokenExporter( const Face& face ) : m_face( face ){
|
|
}
|
|
void exportTokens( TokenWriter& writer ) const {
|
|
FacePlane_exportTokens( m_face.getPlane(), writer );
|
|
FaceTexdef_BP_exportTokens( m_face.getTexdef(), writer );
|
|
FaceShader_exportTokens( m_face.getShader(), writer );
|
|
FaceFlags_exportTokens<exportFlags>( m_face, writer );
|
|
writer.nextLine();
|
|
}
|
|
};
|
|
|
|
template<FaceExportFlags exportFlags>
|
|
class Valve220FaceTokenExporter
|
|
{
|
|
const Face& m_face;
|
|
public:
|
|
Valve220FaceTokenExporter( const Face& face ) : m_face( face ){
|
|
}
|
|
void exportTokens( TokenWriter& writer ) const {
|
|
FacePlane_exportTokens( m_face.getPlane(), writer );
|
|
FaceShader_exportTokens( m_face.getShader(), writer );
|
|
FaceTexdef_Valve220_exportTokens( m_face.getTexdef(), writer );
|
|
FaceFlags_exportTokens<exportFlags>( m_face, writer );
|
|
writer.nextLine();
|
|
}
|
|
};
|
|
|
|
|
|
class BrushTokenImporter : public MapImporter
|
|
{
|
|
Brush& m_brush;
|
|
|
|
public:
|
|
BrushTokenImporter( Brush& brush ) : m_brush( brush ){
|
|
}
|
|
bool importTokens( Tokeniser& tokeniser ){
|
|
if ( Brush::m_type == eBrushTypeQuake3BP || Brush::m_type == eBrushTypeQuake2BP || Brush::m_type == eBrushTypeDoom3 || Brush::m_type == eBrushTypeQuake4 ) {
|
|
tokeniser.nextLine();
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_parseToken( tokeniser, "{" ) );
|
|
}
|
|
while ( 1 )
|
|
{
|
|
// check for end of brush
|
|
tokeniser.nextLine();
|
|
const char* token = tokeniser.getToken();
|
|
if ( string_equal( token, "}" ) ) {
|
|
break;
|
|
}
|
|
|
|
tokeniser.ungetToken();
|
|
|
|
m_brush.push_back( FaceSmartPointer( new Face( &m_brush ) ) );
|
|
|
|
//!todo BP support
|
|
tokeniser.nextLine();
|
|
|
|
Face& face = *m_brush.back();
|
|
|
|
switch ( Brush::m_type )
|
|
{
|
|
case eBrushTypeDoom3:
|
|
{
|
|
Doom3FaceTokenImporter importer( face );
|
|
RETURN_FALSE_IF_FAIL( importer.importTokens( tokeniser ) );
|
|
}
|
|
break;
|
|
case eBrushTypeQuake4:
|
|
{
|
|
Quake4FaceTokenImporter importer( face );
|
|
RETURN_FALSE_IF_FAIL( importer.importTokens( tokeniser ) );
|
|
}
|
|
break;
|
|
case eBrushTypeQuake:
|
|
case eBrushTypeQuake2:
|
|
case eBrushTypeQuake3:
|
|
{
|
|
QuakeFaceTokenImporter importer( face );
|
|
RETURN_FALSE_IF_FAIL( importer.importTokens( tokeniser ) );
|
|
}
|
|
break;
|
|
case eBrushTypeQuake2BP:
|
|
case eBrushTypeQuake3BP:
|
|
{
|
|
Quake3BPFaceTokenImporter importer( face );
|
|
RETURN_FALSE_IF_FAIL( importer.importTokens( tokeniser ) );
|
|
}
|
|
break;
|
|
case eBrushTypeValve220:
|
|
case eBrushTypeQuake2Valve220:
|
|
case eBrushTypeQuake3Valve220:
|
|
{
|
|
Valve220FaceTokenImporter importer( face );
|
|
RETURN_FALSE_IF_FAIL( importer.importTokens( tokeniser ) );
|
|
}
|
|
break;
|
|
}
|
|
face.planeChanged();
|
|
}
|
|
if ( Brush::m_type == eBrushTypeQuake3BP || Brush::m_type == eBrushTypeQuake2BP || Brush::m_type == eBrushTypeDoom3 || Brush::m_type == eBrushTypeQuake4 ) {
|
|
tokeniser.nextLine();
|
|
RETURN_FALSE_IF_FAIL( Tokeniser_parseToken( tokeniser, "}" ) );
|
|
}
|
|
|
|
m_brush.planeChanged();
|
|
m_brush.shaderChanged();
|
|
|
|
return true;
|
|
}
|
|
};
|
|
|
|
|
|
class BrushTokenExporter : public MapExporter
|
|
{
|
|
const Brush& m_brush;
|
|
|
|
public:
|
|
BrushTokenExporter( const Brush& brush ) : m_brush( brush ){
|
|
}
|
|
void exportTokens( TokenWriter& writer ) const {
|
|
m_brush.evaluateBRep(); // ensure b-rep is up-to-date, so that non-contributing faces can be identified.
|
|
|
|
if ( !m_brush.hasContributingFaces() ) {
|
|
return;
|
|
}
|
|
|
|
writer.writeToken( "{" );
|
|
writer.nextLine();
|
|
|
|
if ( Brush::m_type == eBrushTypeQuake3BP || Brush::m_type == eBrushTypeQuake2BP ) {
|
|
writer.writeToken( "brushDef" );
|
|
writer.nextLine();
|
|
writer.writeToken( "{" );
|
|
writer.nextLine();
|
|
}
|
|
else if ( Brush::m_type == eBrushTypeDoom3 || Brush::m_type == eBrushTypeQuake4 ) {
|
|
writer.writeToken( "brushDef3" );
|
|
writer.nextLine();
|
|
writer.writeToken( "{" );
|
|
writer.nextLine();
|
|
}
|
|
|
|
for ( Brush::const_iterator i = m_brush.begin(); i != m_brush.end(); ++i )
|
|
{
|
|
const Face& face = *( *i );
|
|
|
|
if ( face.contributes() ) {
|
|
switch ( Brush::m_type )
|
|
{
|
|
case eBrushTypeDoom3:
|
|
{
|
|
Doom3FaceTokenExporter exporter( face );
|
|
exporter.exportTokens( writer );
|
|
}
|
|
break;
|
|
case eBrushTypeQuake4:
|
|
{
|
|
Quake4FaceTokenExporter exporter( face );
|
|
exporter.exportTokens( writer );
|
|
}
|
|
break;
|
|
case eBrushTypeQuake:
|
|
{
|
|
QuakeFaceTokenExporter<FaceExportFlags::no> exporter( face );
|
|
exporter.exportTokens( writer );
|
|
}
|
|
break;
|
|
case eBrushTypeQuake2:
|
|
{
|
|
QuakeFaceTokenExporter<FaceExportFlags::optional> exporter( face );
|
|
exporter.exportTokens( writer );
|
|
}
|
|
break;
|
|
case eBrushTypeQuake3:
|
|
{
|
|
QuakeFaceTokenExporter<FaceExportFlags::yes> exporter( face );
|
|
exporter.exportTokens( writer );
|
|
}
|
|
break;
|
|
case eBrushTypeQuake2BP:
|
|
{
|
|
Quake3BPFaceTokenExporter<FaceExportFlags::optional> exporter( face );
|
|
exporter.exportTokens( writer );
|
|
}
|
|
break;
|
|
case eBrushTypeQuake3BP:
|
|
{
|
|
Quake3BPFaceTokenExporter<FaceExportFlags::yes> exporter( face );
|
|
exporter.exportTokens( writer );
|
|
}
|
|
break;
|
|
case eBrushTypeValve220:
|
|
{
|
|
Valve220FaceTokenExporter<FaceExportFlags::no> exporter( face );
|
|
exporter.exportTokens( writer );
|
|
}
|
|
break;
|
|
case eBrushTypeQuake2Valve220:
|
|
{
|
|
Valve220FaceTokenExporter<FaceExportFlags::optional> exporter( face );
|
|
exporter.exportTokens( writer );
|
|
}
|
|
break;
|
|
case eBrushTypeQuake3Valve220:
|
|
{
|
|
Valve220FaceTokenExporter<FaceExportFlags::yes> exporter( face );
|
|
exporter.exportTokens( writer );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( Brush::m_type == eBrushTypeQuake3BP || Brush::m_type == eBrushTypeQuake2BP || Brush::m_type == eBrushTypeDoom3 || Brush::m_type == eBrushTypeQuake4 ) {
|
|
writer.writeToken( "}" );
|
|
writer.nextLine();
|
|
}
|
|
|
|
writer.writeToken( "}" );
|
|
writer.nextLine();
|
|
}
|
|
};
|