From 0b3f42ffbcf6297576f5bec9b94e77111c1c3f45 Mon Sep 17 00:00:00 2001 From: Garux Date: Sat, 16 Sep 2017 16:37:39 +0300 Subject: [PATCH] * "BrushAlwaysCaulk" option is saveable for brush types other than q3 * brush format is preference for [maptypes, brushtypes]: [mapq1, quake], [mapq2, quake2], [mapq3, quake3]: preferences->Brush->Brush type: Axial projection, Brush primitives, Valve 220 * autodetect brush type on map opening * brush face surfaceflags are optional on loading for flexibility * 'Snap planes to integer grid' option is always off by default --- include/ibrush.h | 16 ++++- include/imap.h | 3 +- include/iscriplib.h | 1 + libs/script/scripttokeniser.h | 5 +- libs/stream/textstream.h | 41 ++++++++++++ plugins/mapq3/plugin.cpp | 110 +++++++++++++++++++++++++------- radiant/brush.h | 17 +---- radiant/brush_primit.h | 3 - radiant/brushmodule.cpp | 115 +++++++++++++++++++++------------- radiant/brushmodule.h | 5 +- radiant/brushtokens.h | 79 +++++++++++++++++++---- radiant/map.cpp | 45 ++++++------- 12 files changed, 309 insertions(+), 131 deletions(-) diff --git a/include/ibrush.h b/include/ibrush.h index 1171f8a7..305d7a12 100644 --- a/include/ibrush.h +++ b/include/ibrush.h @@ -27,6 +27,20 @@ #include "generic/vector.h" #include "itexdef.h" +enum EBrushType +{ + eBrushTypeUNKNOWN = 0, + eBrushTypeQuake, + eBrushTypeQuake2, + eBrushTypeQuake3, + eBrushTypeQuake3BP, + eBrushTypeQuake3Valve220, + eBrushTypeDoom3, + eBrushTypeQuake4, + eBrushTypeValve220, +}; + + namespace scene { class Node; @@ -103,7 +117,7 @@ public: INTEGER_CONSTANT( Version, 1 ); STRING_CONSTANT( Name, "brush" ); virtual scene::Node& createBrush() = 0; -virtual bool useAlternativeTextureProjection() const = 0; +virtual EBrushType getCurrentFormat() const = 0; virtual void Brush_forEachFace( scene::Node& brush, const BrushFaceDataCallback& callback ) = 0; virtual bool Brush_addFace( scene::Node& brush, const _QERFaceData& faceData ) = 0; }; diff --git a/include/imap.h b/include/imap.h index 7af4c472..59f3c42c 100644 --- a/include/imap.h +++ b/include/imap.h @@ -46,6 +46,7 @@ virtual void exportTokens( TokenWriter& writer ) const = 0; }; #include "iscenegraph.h" +#include "ibrush.h" class EntityCreator; @@ -61,7 +62,7 @@ class MapFormat public: INTEGER_CONSTANT( Version, 2 ); STRING_CONSTANT( Name, "map" ); -mutable bool wrongFormat; +mutable EBrushType m_detectedFormat; /// \brief Read a map graph into \p root from \p outputStream, using \p entityTable to create entities. virtual void readGraph( scene::Node& root, TextInputStream& inputStream, EntityCreator& entityTable ) const = 0; diff --git a/include/iscriplib.h b/include/iscriplib.h index 8f645033..c4f96c37 100644 --- a/include/iscriplib.h +++ b/include/iscriplib.h @@ -39,6 +39,7 @@ virtual const char* getToken() = 0; virtual void ungetToken() = 0; virtual std::size_t getLine() const = 0; virtual std::size_t getColumn() const = 0; +virtual bool bufferContains( const char* str ) = 0; }; class TextInputStream; diff --git a/libs/script/scripttokeniser.h b/libs/script/scripttokeniser.h index 8744aec3..17d0779c 100644 --- a/libs/script/scripttokeniser.h +++ b/libs/script/scripttokeniser.h @@ -41,7 +41,7 @@ typedef bool ( ScriptTokeniser::*Tokenise )( char c ); Tokenise m_stack[3]; Tokenise* m_state; -SingleCharacterInputStream m_istream; +SingleCharacterInputStreamDoubleBuffered m_istream; std::size_t m_scriptline; std::size_t m_scriptcolumn; @@ -329,6 +329,9 @@ std::size_t getLine() const { std::size_t getColumn() const { return m_scriptcolumn; } +bool bufferContains( const char* str ){ + return m_istream.bufferContains( str ); +} }; diff --git a/libs/stream/textstream.h b/libs/stream/textstream.h index e8de1391..fb285a10 100644 --- a/libs/stream/textstream.h +++ b/libs/stream/textstream.h @@ -355,6 +355,47 @@ bool readChar( char& c ){ } }; +/// doublefuffered to be able to read forward for map format (valve220) detection +template +class SingleCharacterInputStreamDoubleBuffered +{ +TextInputStreamType& m_inputStream; +char m_bu[SIZE]; +char* m_buffer; +char* m_cur; +char* m_end; + +char m_bu2[SIZE]; +char* m_buffer2; +char* m_end2; + +bool fillBuffer(){ + std::swap( m_buffer, m_buffer2 ); + m_cur = m_buffer; + m_end = m_end2; + m_end2 = m_buffer2 + m_inputStream.read( m_buffer2, SIZE ); + return m_cur != m_end; +} +public: + +SingleCharacterInputStreamDoubleBuffered( TextInputStreamType& inputStream ) : m_inputStream( inputStream ), m_buffer( m_bu ), m_cur( m_buffer ), m_end( m_buffer ), m_buffer2( m_bu2 ){ + m_end2 = m_buffer2 + m_inputStream.read( m_buffer2, SIZE ); +} +bool readChar( char& c ){ + if ( m_cur == m_end && !fillBuffer() ) { + return false; + } + + c = *m_cur++; + return true; +} +bool bufferContains( const char* str ) const{ + return ( std::search( m_cur, m_end, str, str + strlen( str ) ) != m_end ) || + ( std::search( m_buffer2, m_end2, str, str + strlen( str ) ) != m_end2 ); +} +}; + + /// \brief A wrapper for a TextOutputStream, optimised for writing a single character at a time. class SingleCharacterOutputStream : public TextOutputStream { diff --git a/plugins/mapq3/plugin.cpp b/plugins/mapq3/plugin.cpp index 3317830b..97450405 100644 --- a/plugins/mapq3/plugin.cpp +++ b/plugins/mapq3/plugin.cpp @@ -228,7 +228,6 @@ MapDependencies() : class MapQ3API : public TypeSystemRef, public MapFormat, public PrimitiveParser { -mutable bool detectedFormat; public: typedef MapFormat Type; STRING_CONSTANT( Name, "mapq3" ); @@ -248,31 +247,38 @@ scene::Node& parsePrimitive( Tokeniser& tokeniser ) const { if ( string_equal( primitive, "patchDef2" ) ) { return GlobalPatchModule::getTable().createPatch(); } - if ( GlobalBrushModule::getTable().useAlternativeTextureProjection() ) { + if( !m_detectedFormat ){ if ( string_equal( primitive, "brushDef" ) ) { - detectedFormat = true; - return GlobalBrushModule::getTable().createBrush(); + m_detectedFormat = eBrushTypeQuake3BP; + globalErrorStream() << "m_detectedFormat = eBrushTypeQuake3BP\n"; } - else if ( !detectedFormat && string_equal( primitive, "(" ) ) { - detectedFormat = true; - wrongFormat = true; - Tokeniser_unexpectedError( tokeniser, primitive, "#quake3-switch-to-texdef" ); + else if ( string_equal( primitive, "(" ) && tokeniser.bufferContains( " [ " ) && tokeniser.bufferContains( " ] " ) ) { + m_detectedFormat = eBrushTypeQuake3Valve220; + globalErrorStream() << "m_detectedFormat = eBrushTypeQuake3Valve220\n"; + } + else if ( string_equal( primitive, "(" ) ) { + m_detectedFormat = eBrushTypeQuake3; + globalErrorStream() << "m_detectedFormat = eBrushTypeQuake3\n"; + } + else{ + globalErrorStream() << "Format is not detected\n"; + } + + if( m_detectedFormat != GlobalBrushModule::getTable().getCurrentFormat() ){ + Tokeniser_unexpectedError( tokeniser, primitive, "#different-brush-format" ); return g_nullNode; } } - else + + switch ( GlobalBrushModule::getTable().getCurrentFormat() ) { - if ( string_equal( primitive, "(" ) ) { - detectedFormat = true; - tokeniser.ungetToken(); // ( - return GlobalBrushModule::getTable().createBrush(); - } - else if ( !detectedFormat && string_equal( primitive, "brushDef" ) ) { - detectedFormat = true; - wrongFormat = true; - Tokeniser_unexpectedError( tokeniser, primitive, "#quake3-switch-to-brush-primitives" ); - return g_nullNode; - } + case eBrushTypeQuake3: + case eBrushTypeQuake3Valve220: + tokeniser.ungetToken(); // ( + case eBrushTypeQuake3BP: + return GlobalBrushModule::getTable().createBrush(); + default: + break; } } @@ -281,8 +287,6 @@ scene::Node& parsePrimitive( Tokeniser& tokeniser ) const { } void readGraph( scene::Node& root, TextInputStream& inputStream, EntityCreator& entityTable ) const { - detectedFormat = false; - wrongFormat = false; Tokeniser& tokeniser = GlobalScripLibModule::getTable().m_pfnNewSimpleTokeniser( inputStream ); Map_Read( root, tokeniser, entityTable, *this ); tokeniser.release(); @@ -316,9 +320,38 @@ MapFormat* getTable(){ scene::Node& parsePrimitive( Tokeniser& tokeniser ) const { const char* primitive = tokeniser.getToken(); if ( primitive != 0 ) { - if ( string_equal( primitive, "(" ) ) { + if( !m_detectedFormat ){ + if ( string_equal( primitive, "brushDef" ) ) { + m_detectedFormat = eBrushTypeQuake3BP; + globalErrorStream() << "m_detectedFormat = eBrushTypeQuake3BP\n"; + } + else if ( string_equal( primitive, "(" ) && tokeniser.bufferContains( " [ " ) && tokeniser.bufferContains( " ] " ) ) { + m_detectedFormat = eBrushTypeValve220; + globalErrorStream() << "m_detectedFormat = eBrushTypeValve220\n"; + } + else if ( string_equal( primitive, "(" ) ) { + m_detectedFormat = eBrushTypeQuake; + globalErrorStream() << "m_detectedFormat = eBrushTypeQuake\n"; + } + else{ + globalErrorStream() << "Format is not detected\n"; + } + + if( m_detectedFormat != GlobalBrushModule::getTable().getCurrentFormat() ){ + Tokeniser_unexpectedError( tokeniser, primitive, "#different-brush-format" ); + return g_nullNode; + } + } + + switch ( GlobalBrushModule::getTable().getCurrentFormat() ) + { + case eBrushTypeQuake: + case eBrushTypeValve220: tokeniser.ungetToken(); // ( + case eBrushTypeQuake3BP: return GlobalBrushModule::getTable().createBrush(); + default: + break; } } @@ -401,9 +434,38 @@ MapFormat* getTable(){ scene::Node& parsePrimitive( Tokeniser& tokeniser ) const { const char* primitive = tokeniser.getToken(); if ( primitive != 0 ) { - if ( string_equal( primitive, "(" ) ) { + if( !m_detectedFormat ){ + if ( string_equal( primitive, "brushDef" ) ) { + m_detectedFormat = eBrushTypeQuake3BP; + globalErrorStream() << "m_detectedFormat = eBrushTypeQuake3BP\n"; + } + else if ( string_equal( primitive, "(" ) && tokeniser.bufferContains( " [ " ) && tokeniser.bufferContains( " ] " ) ) { + m_detectedFormat = eBrushTypeQuake3Valve220; + globalErrorStream() << "m_detectedFormat = eBrushTypeQuake3Valve220\n"; + } + else if ( string_equal( primitive, "(" ) ) { + m_detectedFormat = eBrushTypeQuake2; + globalErrorStream() << "m_detectedFormat = eBrushTypeQuake2\n"; + } + else{ + globalErrorStream() << "Format is not detected\n"; + } + + if( m_detectedFormat != GlobalBrushModule::getTable().getCurrentFormat() ){ + Tokeniser_unexpectedError( tokeniser, primitive, "#different-brush-format" ); + return g_nullNode; + } + } + + switch ( GlobalBrushModule::getTable().getCurrentFormat() ) + { + case eBrushTypeQuake2: + case eBrushTypeQuake3Valve220: tokeniser.ungetToken(); // ( + case eBrushTypeQuake3BP: return GlobalBrushModule::getTable().createBrush(); + default: + break; } } diff --git a/radiant/brush.h b/radiant/brush.h index f3c3c342..b710cc20 100644 --- a/radiant/brush.h +++ b/radiant/brush.h @@ -68,17 +68,6 @@ const unsigned int BRUSH_DETAIL_FLAG = 27; const unsigned int BRUSH_DETAIL_MASK = ( 1 << BRUSH_DETAIL_FLAG ); -enum EBrushType -{ - eBrushTypeQuake, - eBrushTypeQuake2, - eBrushTypeQuake3, - eBrushTypeQuake3BP, - eBrushTypeDoom3, - eBrushTypeQuake4, - eBrushTypeHalfLife, -}; - #define BRUSH_CONNECTIVITY_DEBUG 0 #define BRUSH_DEGENERATE_DEBUG 0 @@ -1934,15 +1923,11 @@ static void constructStatic( EBrushType type ){ g_bp_globals.m_texdefTypeId = TEXDEFTYPEID_QUAKE; if ( m_type == eBrushTypeQuake3BP || m_type == eBrushTypeDoom3 || m_type == eBrushTypeQuake4 ) { g_bp_globals.m_texdefTypeId = TEXDEFTYPEID_BRUSHPRIMITIVES; - // g_brush_texturelock_enabled = true; // bad idea, this overrides user setting } - else if ( m_type == eBrushTypeHalfLife ) { + else if ( m_type == eBrushTypeValve220 || m_type == eBrushTypeQuake3Valve220 ) { g_bp_globals.m_texdefTypeId = TEXDEFTYPEID_HALFLIFE; - // g_brush_texturelock_enabled = true; // bad idea, this overrides user setting } - Face::m_quantise = ( m_type == eBrushTypeQuake ) ? quantiseInteger : quantiseFloating; - m_state_point = GlobalShaderCache().capture( "$POINT" ); } static void destroyStatic(){ diff --git a/radiant/brush_primit.h b/radiant/brush_primit.h index 02721f77..76ddc8f2 100644 --- a/radiant/brush_primit.h +++ b/radiant/brush_primit.h @@ -128,9 +128,6 @@ enum TexdefTypeId struct bp_globals_t { - // tells if we are internally using brush primitive (texture coordinates and map format) - // this is a shortcut for IntForKey( g_qeglobals.d_project_entity, "brush_primit" ) - // NOTE: must keep the two ones in sync TexdefTypeId m_texdefTypeId; }; diff --git a/radiant/brushmodule.cpp b/radiant/brushmodule.cpp index bc9c18ef..f5fdaa14 100644 --- a/radiant/brushmodule.cpp +++ b/radiant/brushmodule.cpp @@ -35,13 +35,36 @@ #include "preferences.h" LatchedBool g_useAlternativeTextureProjection( false, "Use alternative texture-projection (\"brush primitives\")" ); -bool g_showAlternativeTextureProjectionOption = false; +bool g_multipleBrushTypes = false; +EBrushType g_brushTypes[3]; +int g_brushType; bool g_brush_always_caulk; bool getTextureLockEnabled(){ return g_brush_texturelock_enabled; } +const char* BrushType_getName( EBrushType type ){ + switch ( type ) + { + case eBrushTypeQuake: + case eBrushTypeQuake2: + case eBrushTypeQuake3: + return "Axial Projection"; + case eBrushTypeQuake3BP: + return "Brush Primitives"; + case eBrushTypeQuake3Valve220: + case eBrushTypeValve220: + return "Valve 220"; + case eBrushTypeDoom3: + return "Doom3"; + case eBrushTypeQuake4: + return "Quake4"; + default: + return "unknown"; + } +} + void Face_importSnapPlanes( bool value ){ Face::m_quantise = value ? quantiseInteger : quantiseFloating; } @@ -62,11 +85,12 @@ void Brush_constructPreferences( PreferencesPage& page ){ "Default texture scale", g_texdef_default_scale ); - if ( g_showAlternativeTextureProjectionOption ) { - page.appendCheckBox( - "", "Use alternative texture-projection (\"brush primitives\")", - LatchedBoolImportCaller( g_useAlternativeTextureProjection ), - BoolExportCaller( g_useAlternativeTextureProjection.m_latched ) + if ( g_multipleBrushTypes ) { + const char* names[] = { BrushType_getName( g_brushTypes[0] ), BrushType_getName( g_brushTypes[1] ), BrushType_getName( g_brushTypes[2] ) }; + page.appendCombo( + "Brush Type", + g_brushType, + STRING_ARRAY_RANGE( names ) ); } // d1223m @@ -83,51 +107,38 @@ void Brush_registerPreferencesPage(){ PreferencesDialog_addSettingsPage( FreeCaller1() ); } -void Brush_unlatchPreferences(){ - Brush_toggleFormat( 0 ); -} - -void Brush_toggleFormat( int i ){ - if ( g_showAlternativeTextureProjectionOption ) { - g_useAlternativeTextureProjection.m_value = g_useAlternativeTextureProjection.m_latched ^ i; +void Brush_toggleFormat( EBrushType type ){ + if( g_multipleBrushTypes ){ Brush::destroyStatic(); - Brush::constructStatic( g_useAlternativeTextureProjection.m_value ? eBrushTypeQuake3BP : eBrushTypeQuake3 ); + Brush::constructStatic( type ); } } -int Brush_toggleFormatCount(){ - if ( g_showAlternativeTextureProjectionOption ) { - return 2; - } - return 1; +void Brush_unlatchPreferences(){ + if( g_multipleBrushTypes ) + Brush_toggleFormat( g_brushTypes[g_brushType] ); } void Brush_Construct( EBrushType type ){ - if ( type == eBrushTypeQuake3 ) { - g_showAlternativeTextureProjectionOption = true; - - const char *value = g_pGameDescription->getKeyValue( "brush_primit" ); - if ( !string_empty( value ) ) { - g_useAlternativeTextureProjection.m_latched = atoi( value ); + if ( g_multipleBrushTypes ) { + for ( int i = 0; i < 3; ++i ){ + if( g_brushTypes[i] == type ){ + g_brushType = i; + break; + } } - GlobalPreferenceSystem().registerPreference( - "AlternativeTextureProjection", - BoolImportStringCaller( g_useAlternativeTextureProjection.m_latched ), - BoolExportStringCaller( g_useAlternativeTextureProjection.m_latched ) + "BrushType", + IntImportStringCaller( g_brushType ), + IntExportStringCaller( g_brushType ) ); - g_useAlternativeTextureProjection.useLatched(); - - if ( g_useAlternativeTextureProjection.m_value ) { - type = eBrushTypeQuake3BP; - } - - // d1223m - GlobalPreferenceSystem().registerPreference( - "BrushAlwaysCaulk", - BoolImportStringCaller( g_brush_always_caulk ), - BoolExportStringCaller( g_brush_always_caulk ) ); + type = g_brushTypes[g_brushType]; } + // d1223m + GlobalPreferenceSystem().registerPreference( + "BrushAlwaysCaulk", + BoolImportStringCaller( g_brush_always_caulk ), + BoolExportStringCaller( g_brush_always_caulk ) ); Brush_registerCommands(); Brush_registerPreferencesPage(); @@ -137,6 +148,7 @@ void Brush_Construct( EBrushType type ){ BrushClipPlane::constructStatic(); BrushInstance::constructStatic(); Brush::constructStatic( type ); + Face::m_quantise = quantiseFloating; Brush::m_maxWorldCoord = g_MaxWorldCoord; BrushInstance::m_counter = &g_brushCount; @@ -197,8 +209,8 @@ public: scene::Node& createBrush(){ return ( new BrushNode )->node(); } -bool useAlternativeTextureProjection() const { - return g_useAlternativeTextureProjection.m_value; +EBrushType getCurrentFormat() const { + return Brush::m_type; } void Brush_forEachFace( scene::Node& brush, const BrushFaceDataCallback& callback ){ ::Brush_forEachFace( *Node_getBrush( brush ), FaceCallback( BrushFaceDataFromFaceCaller( callback ) ) ); @@ -288,7 +300,12 @@ typedef BrushCreator Type; STRING_CONSTANT( Name, "quake3" ); BrushQuake3API(){ - Brush_Construct( eBrushTypeQuake3 ); + g_multipleBrushTypes = true; + g_brushTypes[0] = eBrushTypeQuake3; + g_brushTypes[1] = eBrushTypeQuake3BP; + g_brushTypes[2] = eBrushTypeQuake3Valve220; + + Brush_Construct( eBrushTypeQuake3BP ); m_brushquake3 = &GetBrushCreator(); } @@ -313,6 +330,11 @@ typedef BrushCreator Type; STRING_CONSTANT( Name, "quake2" ); BrushQuake2API(){ + g_multipleBrushTypes = true; + g_brushTypes[0] = eBrushTypeQuake2; + g_brushTypes[1] = eBrushTypeQuake3BP; + g_brushTypes[2] = eBrushTypeQuake3Valve220; + Brush_Construct( eBrushTypeQuake2 ); m_brushquake2 = &GetBrushCreator(); @@ -338,6 +360,11 @@ typedef BrushCreator Type; STRING_CONSTANT( Name, "quake" ); BrushQuake1API(){ + g_multipleBrushTypes = true; + g_brushTypes[0] = eBrushTypeQuake; + g_brushTypes[1] = eBrushTypeQuake3BP; + g_brushTypes[2] = eBrushTypeValve220; + Brush_Construct( eBrushTypeQuake ); m_brushquake1 = &GetBrushCreator(); @@ -363,7 +390,7 @@ typedef BrushCreator Type; STRING_CONSTANT( Name, "halflife" ); BrushHalfLifeAPI(){ - Brush_Construct( eBrushTypeHalfLife ); + Brush_Construct( eBrushTypeValve220 ); m_brushhalflife = &GetBrushCreator(); } diff --git a/radiant/brushmodule.h b/radiant/brushmodule.h index a5c67e3c..a88eae73 100644 --- a/radiant/brushmodule.h +++ b/radiant/brushmodule.h @@ -22,9 +22,10 @@ #if !defined( INCLUDED_BRUSHMODULE_H ) #define INCLUDED_BRUSHMODULE_H +#include "ibrush.h" + void Brush_clipperColourChanged(); void Brush_unlatchPreferences(); -int Brush_toggleFormatCount(); -void Brush_toggleFormat( int i ); +void Brush_toggleFormat( EBrushType type ); #endif diff --git a/radiant/brushtokens.h b/radiant/brushtokens.h index 9b4d4fab..93c31aab 100644 --- a/radiant/brushtokens.h +++ b/radiant/brushtokens.h @@ -67,7 +67,7 @@ inline bool FaceTexdef_BP_importTokens( FaceTexdef& texdef, Tokeniser& tokeniser return true; } -inline bool FaceTexdef_HalfLife_importTokens( FaceTexdef& texdef, Tokeniser& tokeniser ){ +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() ) ); @@ -221,7 +221,9 @@ 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 ) ); - RETURN_FALSE_IF_FAIL( FaceShader_importContentsFlagsValue( m_face.getShader(), tokeniser ) ); + if ( Tokeniser_nextTokenIsDigit( tokeniser ) ) { ///optional for more flexibility + RETURN_FALSE_IF_FAIL( FaceShader_importContentsFlagsValue( m_face.getShader(), tokeniser ) ); + } m_face.getTexdef().m_scaleApplied = true; return true; } @@ -237,7 +239,9 @@ 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 ) ); - RETURN_FALSE_IF_FAIL( FaceShader_importContentsFlagsValue( m_face.getShader(), tokeniser ) ); + if ( Tokeniser_nextTokenIsDigit( tokeniser ) ) { ///optional for more flexibility + RETURN_FALSE_IF_FAIL( FaceShader_importContentsFlagsValue( m_face.getShader(), tokeniser ) ); + } m_face.getTexdef().m_projectionInitialised = true; m_face.getTexdef().m_scaleApplied = true; @@ -256,21 +260,45 @@ 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 ) ); + if ( Tokeniser_nextTokenIsDigit( tokeniser ) ) { ///try to load for more flexibility + RETURN_FALSE_IF_FAIL( FaceShader_importContentsFlagsValue( m_face.getShader(), tokeniser ) ); + } m_face.getTexdef().m_scaleApplied = true; return true; } }; -class HalfLifeFaceTokenImporter +class Valve220FaceTokenImporter { Face& m_face; public: -HalfLifeFaceTokenImporter( Face& face ) : m_face( face ){ +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_HalfLife_importTokens( m_face.getTexdef(), tokeniser ) ); + RETURN_FALSE_IF_FAIL( FaceTexdef_Valve220_importTokens( m_face.getTexdef(), tokeniser ) ); + if ( Tokeniser_nextTokenIsDigit( tokeniser ) ) { ///try to load for more flexibility + RETURN_FALSE_IF_FAIL( FaceShader_importContentsFlagsValue( m_face.getShader(), tokeniser ) ); + } + m_face.getTexdef().m_scaleApplied = true; + return true; +} +}; + +class Quake3Valve220FaceTokenImporter +{ +Face& m_face; +public: +Quake3Valve220FaceTokenImporter( 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 + RETURN_FALSE_IF_FAIL( FaceShader_importContentsFlagsValue( m_face.getShader(), tokeniser ) ); + } m_face.getTexdef().m_scaleApplied = true; return true; } @@ -471,11 +499,11 @@ void exportTokens( TokenWriter& writer ) const { } }; -class HalfLifeFaceTokenExporter +class Valve220FaceTokenExporter { const Face& m_face; public: -HalfLifeFaceTokenExporter( const Face& face ) : m_face( face ){ +Valve220FaceTokenExporter( const Face& face ) : m_face( face ){ } void exportTokens( TokenWriter& writer ) const { FacePlane_exportTokens( m_face.getPlane(), writer ); @@ -485,6 +513,21 @@ void exportTokens( TokenWriter& writer ) const { } }; +class Quake3Valve220FaceTokenExporter +{ +const Face& m_face; +public: +Quake3Valve220FaceTokenExporter( const Face& face ) : m_face( face ){ +} +void exportTokens( TokenWriter& writer ) const { + FacePlane_exportTokens( m_face.getPlane(), writer ); + FaceShader_exportTokens( m_face.getShader(), writer ); + FaceTexdef_HalfLife_exportTokens( m_face.getTexdef(), writer ); + FaceShader_ContentsFlagsValue_exportTokens( m_face.getShader(), writer ); + writer.nextLine(); +} +}; + class BrushTokenImporter : public MapImporter { @@ -554,9 +597,15 @@ bool importTokens( Tokeniser& tokeniser ){ RETURN_FALSE_IF_FAIL( importer.importTokens( tokeniser ) ); } break; - case eBrushTypeHalfLife: + case eBrushTypeValve220: { - HalfLifeFaceTokenImporter importer( face ); + Valve220FaceTokenImporter importer( face ); + RETURN_FALSE_IF_FAIL( importer.importTokens( tokeniser ) ); + } + break; + case eBrushTypeQuake3Valve220: + { + Quake3Valve220FaceTokenImporter importer( face ); RETURN_FALSE_IF_FAIL( importer.importTokens( tokeniser ) ); } break; @@ -650,9 +699,15 @@ void exportTokens( TokenWriter& writer ) const { exporter.exportTokens( writer ); } break; - case eBrushTypeHalfLife: + case eBrushTypeValve220: { - HalfLifeFaceTokenExporter exporter( face ); + Valve220FaceTokenExporter exporter( face ); + exporter.exportTokens( writer ); + } + break; + case eBrushTypeQuake3Valve220: + { + Quake3Valve220FaceTokenExporter exporter( face ); exporter.exportTokens( writer ); } break; diff --git a/radiant/map.cpp b/radiant/map.cpp index 4cad6ccb..d2a940fb 100644 --- a/radiant/map.cpp +++ b/radiant/map.cpp @@ -1119,27 +1119,20 @@ void Map_LoadFile( const char *filename ){ if ( string_not_empty( moduleName ) ) { format = ReferenceAPI_getMapModules().findModule( moduleName ); } - - for ( int i = 0; i < Brush_toggleFormatCount(); ++i ) - { - if ( i ) { - Map_Free(); - } - Brush_toggleFormat( i ); - g_map.m_name = filename; - Map_UpdateTitle( g_map ); - g_map.m_resource = GlobalReferenceCache().capture( g_map.m_name.c_str() ); - if ( format ) { - format->wrongFormat = false; - } - g_map.m_resource->attach( g_map ); - if ( format ) { - if ( !format->wrongFormat ) { - break; - } - } + if ( format ) { + format->m_detectedFormat = eBrushTypeUNKNOWN; } + g_map.m_name = filename; + Map_UpdateTitle( g_map ); + g_map.m_resource = GlobalReferenceCache().capture( g_map.m_name.c_str() ); + g_map.m_resource->attach( g_map ); + if ( format && format->m_detectedFormat && format->m_detectedFormat != GlobalBrushModule::getTable().getCurrentFormat() ) { + Map_Free(); + Brush_toggleFormat( format->m_detectedFormat ); + g_map.m_resource = GlobalReferenceCache().capture( g_map.m_name.c_str() ); + g_map.m_resource->attach( g_map ); + } Node_getTraversable( GlobalSceneGraph().root() )->traverse( entity_updateworldspawn() ); } @@ -1675,21 +1668,19 @@ bool Map_ImportFile( const char* filename ){ if ( string_not_empty( moduleName ) ) { format = ReferenceAPI_getMapModules().findModule( moduleName ); } - if ( format ) { - format->wrongFormat = false; + format->m_detectedFormat = eBrushTypeUNKNOWN; } + Resource* resource = GlobalReferenceCache().capture( filename ); resource->refresh(); // avoid loading old version if map has changed on disk since last import if ( !resource->load() ) { GlobalReferenceCache().release( filename ); goto tryDecompile; } - if ( format ) { - if ( format->wrongFormat ) { - GlobalReferenceCache().release( filename ); - goto tryDecompile; - } + if ( format && /*format->m_detectedFormat &&*/ format->m_detectedFormat != GlobalBrushModule::getTable().getCurrentFormat() ) { + GlobalReferenceCache().release( filename ); + goto tryDecompile; } NodeSmartReference clone( NewMapRoot( "" ) ); Node_getTraversable( *resource->getNode() )->traverse( CloneAll( clone ) ); @@ -1744,7 +1735,7 @@ tryDecompile: resource->refresh(); // avoid loading old version if map has changed on disk since last import if ( !resource->load() ) { GlobalReferenceCache().release( filename ); - goto tryDecompile; + return success; } NodeSmartReference clone( NewMapRoot( "" ) ); Node_getTraversable( *resource->getNode() )->traverse( CloneAll( clone ) );