[Hdrflow-svn] SF.net SVN: hdrflow: [376] trunk/lib/openlibraries
Status: Pre-Alpha
Brought to you by:
glslang
From: <gl...@us...> - 2007-11-06 22:00:48
|
Revision: 376 http://hdrflow.svn.sourceforge.net/hdrflow/?rev=376&view=rev Author: glslang Date: 2007-11-06 13:59:54 -0800 (Tue, 06 Nov 2007) Log Message: ----------- + portability fixes Modified Paths: -------------- trunk/lib/openlibraries/configure.ac trunk/lib/openlibraries/src/openimagelib/plugins/jpg/jpg_vc8.vcproj trunk/lib/openlibraries/src/openobjectlib/plugins/Makefile.am Added Paths: ----------- trunk/lib/openlibraries/src/openobjectlib/plugins/wavefront/ trunk/lib/openlibraries/src/openobjectlib/plugins/wavefront/Makefile.am trunk/lib/openlibraries/src/openobjectlib/plugins/wavefront/config.hpp trunk/lib/openlibraries/src/openobjectlib/plugins/wavefront/obj.cpp trunk/lib/openlibraries/src/openobjectlib/plugins/wavefront/obj_plugin.cpp trunk/lib/openlibraries/src/openobjectlib/plugins/wavefront/obj_plugin.hpp trunk/lib/openlibraries/src/openobjectlib/plugins/wavefront/obj_plugin.opl trunk/lib/openlibraries/src/openobjectlib/plugins/wavefront/obj_vc8.icproj trunk/lib/openlibraries/src/openobjectlib/plugins/wavefront/obj_vc8.vcproj trunk/lib/openlibraries/src/openobjectlib/plugins/wavefront/spirit.hpp Removed Paths: ------------- trunk/lib/openlibraries/src/openobjectlib/plugins/obj/ trunk/lib/openlibraries/src/openobjectlib/plugins/wavefront/Makefile.am trunk/lib/openlibraries/src/openobjectlib/plugins/wavefront/config.hpp trunk/lib/openlibraries/src/openobjectlib/plugins/wavefront/obj.cpp trunk/lib/openlibraries/src/openobjectlib/plugins/wavefront/obj_plugin.cpp trunk/lib/openlibraries/src/openobjectlib/plugins/wavefront/obj_plugin.hpp trunk/lib/openlibraries/src/openobjectlib/plugins/wavefront/obj_plugin.opl trunk/lib/openlibraries/src/openobjectlib/plugins/wavefront/obj_vc8.vcproj trunk/lib/openlibraries/src/openobjectlib/plugins/wavefront/spirit.hpp Modified: trunk/lib/openlibraries/configure.ac =================================================================== --- trunk/lib/openlibraries/configure.ac 2007-11-06 21:20:38 UTC (rev 375) +++ trunk/lib/openlibraries/configure.ac 2007-11-06 21:59:54 UTC (rev 376) @@ -367,8 +367,8 @@ src/openobjectlib/sg/Makefile src/openobjectlib/plugins/Makefile src/openobjectlib/plugins/3ds/Makefile -src/openobjectlib/plugins/obj/Makefile src/openobjectlib/plugins/X3D/Makefile +src/openobjectlib/plugins/wavefront/Makefile src/openassetlib/Makefile src/openassetlib/al/Makefile src/openassetlib/py/Makefile Modified: trunk/lib/openlibraries/src/openimagelib/plugins/jpg/jpg_vc8.vcproj =================================================================== --- trunk/lib/openlibraries/src/openimagelib/plugins/jpg/jpg_vc8.vcproj 2007-11-06 21:20:38 UTC (rev 375) +++ trunk/lib/openlibraries/src/openimagelib/plugins/jpg/jpg_vc8.vcproj 2007-11-06 21:59:54 UTC (rev 376) @@ -41,11 +41,11 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=""$(SolutionDir)\src";"C:\Boost\include\boost-1_34_1";"C:\Program Files\HDR\include"" - PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;IL_EXPORTS;OPENIMAGELIB_BUILD;HAVE_FLEX_STRING;HAVE_JPEGHDR" + PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;IL_EXPORTS;OPENIMAGELIB_BUILD;HAVE_FLEX_STRING" MinimalRebuild="true" ExceptionHandling="2" BasicRuntimeChecks="3" - RuntimeLibrary="1" + RuntimeLibrary="3" BufferSecurityCheck="true" EnableEnhancedInstructionSet="0" TreatWChar_tAsBuiltInType="true" Modified: trunk/lib/openlibraries/src/openobjectlib/plugins/Makefile.am =================================================================== --- trunk/lib/openlibraries/src/openobjectlib/plugins/Makefile.am 2007-11-06 21:20:38 UTC (rev 375) +++ trunk/lib/openlibraries/src/openobjectlib/plugins/Makefile.am 2007-11-06 21:59:54 UTC (rev 376) @@ -3,4 +3,4 @@ # # -SUBDIRS = 3ds obj X3D +SUBDIRS = 3ds X3D wavefront Copied: trunk/lib/openlibraries/src/openobjectlib/plugins/wavefront (from rev 351, trunk/lib/openlibraries/src/openobjectlib/plugins/obj) Deleted: trunk/lib/openlibraries/src/openobjectlib/plugins/wavefront/Makefile.am =================================================================== --- trunk/lib/openlibraries/src/openobjectlib/plugins/obj/Makefile.am 2007-10-08 21:33:45 UTC (rev 351) +++ trunk/lib/openlibraries/src/openobjectlib/plugins/wavefront/Makefile.am 2007-11-06 21:59:54 UTC (rev 376) @@ -1,32 +0,0 @@ - -# -# -# - -libdir = $(OPENOBJECTLIB_PLUGINPATH) - -lib_LTLIBRARIES = libopenobjectlib_obj.la - -libopenobjectlib_obj_la_SOURCES = \ - config.hpp \ - obj.cpp \ - obj_plugin.hpp \ - obj_plugin.cpp \ - spirit.hpp - -libopenobjectlib_obj_la_CXXFLAGS = \ - $(BOOST_INCLUDE_PATH) \ - -DOBJ_EXPORTS - -libopenobjectlib_obj_la_LIBADD = \ - $(BOOST_FILESYSTEM_LIBS) - -libopenobjectlib_obj_la_LDFLAGS = \ - $(OLIB_LDFLAGS) \ - $(BOOST_LIB_PATH) \ - -version-info $(OL_LT_CURRENT):$(OL_LT_REVISION):$(OL_LT_AGE) - -libopenobjectlib_obj_ladir = $(OPENOBJECTLIB_PLUGINPATH) -libopenobjectlib_obj_la_DATA = obj_plugin.opl - -nobase_dist_libopenobjectlib_obj_la_DATA = obj_plugin.opl Copied: trunk/lib/openlibraries/src/openobjectlib/plugins/wavefront/Makefile.am (from rev 375, trunk/lib/openlibraries/src/openobjectlib/plugins/obj/Makefile.am) =================================================================== --- trunk/lib/openlibraries/src/openobjectlib/plugins/wavefront/Makefile.am (rev 0) +++ trunk/lib/openlibraries/src/openobjectlib/plugins/wavefront/Makefile.am 2007-11-06 21:59:54 UTC (rev 376) @@ -0,0 +1,32 @@ + +# +# +# + +libdir = $(OPENOBJECTLIB_PLUGINPATH) + +lib_LTLIBRARIES = libopenobjectlib_obj.la + +libopenobjectlib_obj_la_SOURCES = \ + config.hpp \ + obj.cpp \ + obj_plugin.hpp \ + obj_plugin.cpp \ + spirit.hpp + +libopenobjectlib_obj_la_CXXFLAGS = \ + $(BOOST_INCLUDE_PATH) \ + -DOBJ_EXPORTS + +libopenobjectlib_obj_la_LIBADD = \ + $(BOOST_FILESYSTEM_LIBS) + +libopenobjectlib_obj_la_LDFLAGS = \ + $(OLIB_LDFLAGS) \ + $(BOOST_LIB_PATH) \ + -version-info $(OL_LT_CURRENT):$(OL_LT_REVISION):$(OL_LT_AGE) + +libopenobjectlib_obj_ladir = $(OPENOBJECTLIB_PLUGINPATH) +libopenobjectlib_obj_la_DATA = obj_plugin.opl + +nobase_dist_libopenobjectlib_obj_la_DATA = obj_plugin.opl Deleted: trunk/lib/openlibraries/src/openobjectlib/plugins/wavefront/config.hpp =================================================================== --- trunk/lib/openlibraries/src/openobjectlib/plugins/obj/config.hpp 2007-10-08 21:33:45 UTC (rev 351) +++ trunk/lib/openlibraries/src/openobjectlib/plugins/wavefront/config.hpp 2007-11-06 21:59:54 UTC (rev 376) @@ -1,25 +0,0 @@ - -// OBJ - An OBJ plugin to sg. - -// Copyright (C) 2005-2006 VM Inc. -// Released under the LGPL. -// For more information, see http://www.openlibraries.org. - -#ifndef OBJ_CONFIG_INC_ -#define OBJ_CONFIG_INC_ - -#ifdef WIN32 -# ifdef OBJ_EXPORTS -# define OBJ_DECLSPEC __declspec( dllexport ) -# else -# define OBJ_DECLSPEC __declspec( dllimport ) -# endif -#else -# ifdef OBJ_EXPORTS -# define OBJ_DECLSPEC __attribute__( ( visibility( "default" ) ) ) -# else -# define OBJ_DECLSPEC __attribute__( ( visibility( "default" ) ) ) -# endif -#endif - -#endif Copied: trunk/lib/openlibraries/src/openobjectlib/plugins/wavefront/config.hpp (from rev 375, trunk/lib/openlibraries/src/openobjectlib/plugins/obj/config.hpp) =================================================================== --- trunk/lib/openlibraries/src/openobjectlib/plugins/wavefront/config.hpp (rev 0) +++ trunk/lib/openlibraries/src/openobjectlib/plugins/wavefront/config.hpp 2007-11-06 21:59:54 UTC (rev 376) @@ -0,0 +1,25 @@ + +// OBJ - An OBJ plugin to sg. + +// Copyright (C) 2005-2006 VM Inc. +// Released under the LGPL. +// For more information, see http://www.openlibraries.org. + +#ifndef OBJ_CONFIG_INC_ +#define OBJ_CONFIG_INC_ + +#ifdef WIN32 +# ifdef OBJ_EXPORTS +# define OBJ_DECLSPEC __declspec( dllexport ) +# else +# define OBJ_DECLSPEC __declspec( dllimport ) +# endif +#else +# ifdef OBJ_EXPORTS +# define OBJ_DECLSPEC __attribute__( ( visibility( "default" ) ) ) +# else +# define OBJ_DECLSPEC __attribute__( ( visibility( "default" ) ) ) +# endif +#endif + +#endif Deleted: trunk/lib/openlibraries/src/openobjectlib/plugins/wavefront/obj.cpp =================================================================== --- trunk/lib/openlibraries/src/openobjectlib/plugins/obj/obj.cpp 2007-10-08 21:33:45 UTC (rev 351) +++ trunk/lib/openlibraries/src/openobjectlib/plugins/wavefront/obj.cpp 2007-11-06 21:59:54 UTC (rev 376) @@ -1,33 +0,0 @@ - -// OBJ - An OBJ plugin to sg. - -// Copyright (C) 2005-2006 VM Inc. -// Released under the LGPL. -// For more information, see http://www.openlibraries.org. - -#include <openobjectlib/plugins/obj/obj_plugin.hpp> - -namespace opl = olib::openpluginlib; -namespace OBJ = olib::openobjectlib::plugins::OBJ; - -extern "C" -{ - OBJ_DECLSPEC bool openplugin_init( void ) - { - return true; - } - - OBJ_DECLSPEC bool openplugin_uninit( void ) - { - return true; - } - - OBJ_DECLSPEC bool openplugin_create_plugin( const char*, opl::openplugin** plug ) - { - *plug = new OBJ::OBJ_plugin; - return true; - } - - OBJ_DECLSPEC void openplugin_destroy_plugin( opl::openplugin* plug ) - { delete static_cast<OBJ::OBJ_plugin*>( plug ); } -} Copied: trunk/lib/openlibraries/src/openobjectlib/plugins/wavefront/obj.cpp (from rev 375, trunk/lib/openlibraries/src/openobjectlib/plugins/obj/obj.cpp) =================================================================== --- trunk/lib/openlibraries/src/openobjectlib/plugins/wavefront/obj.cpp (rev 0) +++ trunk/lib/openlibraries/src/openobjectlib/plugins/wavefront/obj.cpp 2007-11-06 21:59:54 UTC (rev 376) @@ -0,0 +1,33 @@ + +// OBJ - An OBJ plugin to sg. + +// Copyright (C) 2005-2006 VM Inc. +// Released under the LGPL. +// For more information, see http://www.openlibraries.org. + +#include <openobjectlib/plugins/obj/obj_plugin.hpp> + +namespace opl = olib::openpluginlib; +namespace OBJ = olib::openobjectlib::plugins::OBJ; + +extern "C" +{ + OBJ_DECLSPEC bool openplugin_init( void ) + { + return true; + } + + OBJ_DECLSPEC bool openplugin_uninit( void ) + { + return true; + } + + OBJ_DECLSPEC bool openplugin_create_plugin( const char*, opl::openplugin** plug ) + { + *plug = new OBJ::OBJ_plugin; + return true; + } + + OBJ_DECLSPEC void openplugin_destroy_plugin( opl::openplugin* plug ) + { delete static_cast<OBJ::OBJ_plugin*>( plug ); } +} Deleted: trunk/lib/openlibraries/src/openobjectlib/plugins/wavefront/obj_plugin.cpp =================================================================== --- trunk/lib/openlibraries/src/openobjectlib/plugins/obj/obj_plugin.cpp 2007-10-08 21:33:45 UTC (rev 351) +++ trunk/lib/openlibraries/src/openobjectlib/plugins/wavefront/obj_plugin.cpp 2007-11-06 21:59:54 UTC (rev 376) @@ -1,1172 +0,0 @@ - -// OBJ - An OBJ plugin to sg. - -// Copyright (C) 2005-2006 VM Inc. -// Released under the LGPL. -// For more information, see http://www.openlibraries.org. - -#include <algorithm> -#include <map> -#include <string> -#include <vector> - -#include <boost/filesystem/fstream.hpp> -#include <boost/tokenizer.hpp> - -#include <openpluginlib/pl/geometry.hpp> -#include <openpluginlib/pl/property.hpp> -#include <openpluginlib/pl/utf8_utils.hpp> - -#include <openobjectlib/sg/appearance.hpp> -#include <openobjectlib/sg/spatial.hpp> -#include <openobjectlib/sg/meshes.hpp> - -#include <openobjectlib/plugins/obj/obj_plugin.hpp> -#include <openobjectlib/plugins/obj/spirit.hpp> - -namespace fs = boost::filesystem; -namespace spirit = boost::spirit; -namespace opl = olib::openpluginlib; -namespace sg = olib::openobjectlib::sg; - -namespace olib { namespace openobjectlib { namespace plugins { namespace OBJ { - -namespace -{ - opl::string get_base_url( const opl::string& url ) - { -#ifdef WIN32 - size_t pos = url.find_last_of( '\\' ); - if( pos != opl::string::npos ) - return opl::string( url.begin( ), url.begin( ) + pos + 1 ); -#else - return opl::string( url.begin( ), url.begin( ) + url.find_last_of( '/' ) + 1 ); -#endif - return opl::string( ); - } - - /////////////////////////////////////////////////////////////// - // grammar state - struct material_state - { - explicit material_state( const opl::string& name_ ) - : ka( 0.2f, 0.2f, 0.2f ) - , kd( 0.8f, 0.8f, 0.8f ) - , ks( 0.2f, 0.2f, 0.2f ) - , tf( 1.0f, 1.0f, 1.0f ) - , ns( 65.0f ) - , name( name_ ) - { } - - opl::vec3f ka, kd, ks, tf; - float ns; - float sharpness; - opl::string name; - opl::string map_kd; - }; - - struct group_state - { - typedef std::vector<int> vec_ints; - - explicit group_state( const opl::string& mtl_ ) - : mtl( mtl_ ) - { } - - vec_ints vi, vni, vti; - opl::string mtl; - }; - - struct grammar_state - { - typedef std::vector<float> vec_floats; - typedef std::vector<int> vec_ints; - typedef std::map<opl::string, group_state> groups; - typedef std::map<opl::string, material_state> materials; - - explicit grammar_state( ) - : grp( 0 ) - , mtl( 0 ) - { set_group( "default" ); } - - - // XXX merge these two members by means of templates. - // XXX this totally sucks. needs a revamp ASAP. - void set_group( const opl::string& name ) - { - typedef groups::iterator iterator; - - iterator I = group.find( name ); - if( I != group.end( ) ) - { - grp = &( I->second ); - } - else - { - opl::string mtl_name( "default" ); - - if( mtl ) mtl_name = mtl->name; - - grp = &( group.insert( groups::value_type( name, group_state( mtl_name ) ) ).first->second ); - } - } - - void set_material( const opl::string& name ) - { - typedef materials::iterator iterator; - - iterator I = material.find( name ); - if( I != material.end( ) ) - { - mtl = &( I->second ); - } - else - { - mtl = &( material.insert( materials::value_type( name, material_state( name ) ) ).first->second ); - } - - grp->mtl = name; - } - - groups group; - materials material; - vec_floats v, vn, vt; - - group_state* grp; - material_state* mtl; - }; - - /////////////////////////////////// - /// functors - class geometry_action - { - public: - explicit geometry_action( grammar_state::vec_floats& v ) - : v_( v ) - { } - - void operator( )( const char* first, const char* last ) const - { v_.push_back( static_cast<float>( atof( opl::string( first, last ).c_str( ) ) ) ); } - - private: - grammar_state::vec_floats& v_; - }; - - // - class topology_action - { - public: - explicit topology_action( grammar_state& gs ) - : gs_( gs ) - { } - - void operator( )( const char* first, const char* last ) const - { - const char* iter = first; - - for( ; iter != last && *iter != '/'; ++iter ) - ; - - gs_.grp->vi.push_back( atoi( opl::string( first, iter ).c_str( ) ) - 1 ); - - // texture - if( iter != last && *++iter != '/' ) - { - for( ; iter != last && *iter != '/'; ++iter ) - ; - - gs_.grp->vti.push_back( atoi( opl::string( first, iter ).c_str( ) ) - 1 ); - } - - // normal - if( iter != last ) - { - first = ++iter; - - gs_.grp->vni.push_back( atoi( opl::string( first, last ).c_str( ) ) - 1 ); - } - } - - private: - grammar_state& gs_; - }; - - // - class topology_wrap_up_action - { - public: - explicit topology_wrap_up_action( grammar_state& gs ) - : gs_( gs ) - { } - - void operator( )( const char* /*first*/, const char* /*last*/ ) const - { - gs_.grp->vi.push_back( -1 ); - gs_.grp->vni.push_back( -1 ); - gs_.grp->vti.push_back( -1 ); - } - - private: - grammar_state& gs_; - }; - - // - struct group_action - { - explicit group_action( grammar_state& gs ) - : gs_( gs ) - { } - - void operator( )( const char* first, const char* last ) const - { - opl::string s; - - if( ++first == last ) - s.assign( "default" ); - else - s.assign( ++first, last ); // XXX needs a proper trim left and trim right. - - gs_.set_group( s ); - } - - grammar_state& gs_; - }; - - // - struct use_material_action - { - explicit use_material_action( grammar_state& gs ) - : gs_( gs ) - { } - - void operator( )( const char* first, const char* last ) const - { gs_.set_material( opl::string( first, last ) ); } - - grammar_state& gs_; - }; - - // - struct material_action - { - explicit material_action( grammar_state& gs ) - : gs_( gs ) - { } - - void operator( )( const char* first, const char* last ) const - { gs_.set_material( opl::string( first, last ) ); } - - grammar_state& gs_; - }; - - // - opl::vec3f extract_vec3f_info( const opl::string& str ) - { - typedef boost::tokenizer<boost::char_separator<char> > tokenizer; - - opl::vec3f vec; - - std::string st( str.c_str( ) ); - - boost::char_separator<char> sep( " \t" ); - tokenizer tok( st.begin( ), st.end( ), sep ); - - tokenizer::const_iterator I = tok.begin( ); - if( I != tok.end( ) ) - vec[ 0 ] = static_cast<float>( strtod( I->c_str( ), 0 ) ); - ++I; - - if( I != tok.end( ) ) - vec[ 1 ] = static_cast<float>( strtod( I->c_str( ), 0 ) ); - ++I; - - if( I != tok.end( ) ) - vec[ 2 ] = static_cast<float>( strtod( I->c_str( ), 0 ) ); - ++I; - - return vec; - } - - struct ka_action - { - explicit ka_action( grammar_state& gs ) - : gs_( gs ) - { } - - void operator( )( const char* first, const char* last ) const - { - opl::string tmp( first, last ); - opl::vec3f ka = extract_vec3f_info( tmp ); - - gs_.mtl->ka = ka; - } - - grammar_state& gs_; - }; - - struct kd_action - { - explicit kd_action( grammar_state& gs ) - : gs_( gs ) - { } - - void operator( )( const char* first, const char* last ) const - { - opl::string tmp( first, last ); - opl::vec3f kd = extract_vec3f_info( tmp ); - - gs_.mtl->kd = kd; - } - - grammar_state& gs_; - }; - - struct ks_action - { - explicit ks_action( grammar_state& gs ) - : gs_( gs ) - { } - - void operator( )( const char* first, const char* last ) const - { - opl::string tmp( first, last ); - opl::vec3f ks = extract_vec3f_info( tmp ); - - gs_.mtl->ks = ks; - } - - grammar_state& gs_; - }; - - struct map_kd_action - { - explicit map_kd_action( grammar_state& gs ) - : gs_( gs ) - { } - - void operator( )( const char* first, const char* last ) const - { - opl::string tmp( first, last ); - - gs_.mtl->map_kd = tmp; - } - - grammar_state& gs_; - }; - - /////////////////////////////////////////////////////////////// - // skip grammar (whitespace and comments) - struct skip_grammar : public spirit::grammar<skip_grammar> - { - template<class ScannerT> - struct definition - { - definition( const skip_grammar& /*self*/) - { - skip - = spirit::space_p - | spirit::comment_p( "#" ) - ; - -# ifndef NDEBUG - BOOST_SPIRIT_DEBUG_NODE( skip ); -# endif - } - - spirit::rule<ScannerT> skip; - - const spirit::rule<ScannerT>& start( ) const - { return skip; } - }; - }; - - ////////////////////////////////////////////////////////////// - // obj material grammar. - struct mtl_grammar : public spirit::grammar<mtl_grammar> - { - mtl_grammar( grammar_state& eval_ ) - : eval( eval_ ) - { } - - template<class ScannerT> - struct definition - { - definition( const mtl_grammar& self ) - { - using namespace boost::spirit; - - keywords - = "newmtl", "Ka", "Kd", "Ks", "illum", "Ns", "d", "map_Kd", "Tf" - ; - - NEWMTL = strlit<>( "newmtl" ); - KA = strlit<>( "Ka" ); - KD = strlit<>( "Kd" ); - KS = strlit<>( "Ks" ); - ILLUM = strlit<>( "illum" ); - NS = strlit<>( "Ns" ); - NI = strlit<>( "Ni" ); - D = strlit<>( "d" ); - MAP_KD = strlit<>( "map_Kd" ); - TF = strlit<>( "Tf" ); - REFL = strlit<>( "refl" ); - REFLTYPE = strlit<>( "-type" ); - REFLMM = strlit<>( "-mm" ); - REFLCLAMP = strlit<>( "-clamp" ); - SHARPNESS = strlit<>( "sharpness" ); - ON = strlit<>( "on" ); - OFF = strlit<>( "off" ); - - INTEGER_DECIMAL_CONSTANT - = lexeme_d[ +digit_p ] - ; - - INTEGER_CONSTANT - = INTEGER_DECIMAL_CONSTANT - ; - - FLOAT_CONSTANT_1 // 12345[eE][+-]123[lLfF]? - = lexeme_d - [ - +digit_p - >> ( chlit<>( 'e' ) | chlit<>( 'E' ) ) - >> !sign_p - >> +digit_p - >> !as_lower_d[ chlit<>( 'l' ) | chlit<>( 'f' ) ] - ] - ; - - FLOAT_CONSTANT_2 // .123([[eE][+-]123)?[lLfF]? - = lexeme_d - [ - - *digit_p - >> chlit<>('.') - >> +digit_p - >> !( ( chlit<>( 'e' ) | chlit<>( 'E' ) ) - >> !sign_p - >> +digit_p - ) - >> !as_lower_d[ chlit<>( 'l' ) | chlit<>( 'f' ) ] - ] - ; - - FLOAT_CONSTANT_3 // 12345.([[eE][+-]123)?[lLfF]? - = lexeme_d - [ - +digit_p - >> chlit<>( '.' ) - >> *digit_p - >> !( ( chlit<>( 'e' ) | chlit<>( 'E' ) ) - >> !sign_p - >> +digit_p - ) - >> !as_lower_d[ chlit<>( 'l' ) | chlit<>( 'f' ) ] - ] - ; - - FLOAT_CONSTANT - = FLOAT_CONSTANT_1 - | FLOAT_CONSTANT_2 - | FLOAT_CONSTANT_3 - ; - - CONSTANT - = !sign_p >> longest_d[ FLOAT_CONSTANT | INTEGER_CONSTANT ] - ; - - - IDENTIFIER - = lexeme_d - [ - ( ( alpha_p | '_' | '$' ) >> *( alnum_p | '_' | '$' | '-' | '.' ) ) - ( keywords >> anychar_p - ( alnum_p | '_' | '$' ) ) - ] - ; - - newmtl - = NEWMTL >> IDENTIFIER[ material_action( ( const_cast<mtl_grammar&>( self ) ).eval ) ] - >> *( ka | kd | ks | ns | ni | illum | d | sharpness | tf | refl | map_Kd ) - ; - - ka - = KA >> ( CONSTANT >> CONSTANT >> CONSTANT )[ ka_action( ( const_cast<mtl_grammar&>( self ) ).eval ) ] - ; - - kd = KD >> ( CONSTANT >> CONSTANT >> CONSTANT )[ kd_action( ( const_cast<mtl_grammar&>( self ) ).eval ) ] - ; - - ks = KS >> ( CONSTANT >> CONSTANT >> CONSTANT )[ ks_action( ( const_cast<mtl_grammar&>( self ) ).eval ) ] - ; - - ns = NS >> CONSTANT - ; - - ni = NI >> CONSTANT - ; - - sharpness - = SHARPNESS >> CONSTANT - ; - - illum - = ILLUM >> CONSTANT - ; - - d - = D >> CONSTANT - ; - - map_Kd - = MAP_KD >> IDENTIFIER[ map_kd_action( ( const_cast<mtl_grammar&>( self ) ).eval ) ] - ; - - tf - = TF >> ( CONSTANT >> CONSTANT >> CONSTANT ) - ; - - reflmm - = REFLMM >> CONSTANT >> CONSTANT - ; - - reflclamp - = REFLCLAMP >> ( ON | OFF ) - ; - - refl - = REFL >> REFLTYPE >> IDENTIFIER >> !( reflmm | reflclamp ) >> IDENTIFIER - ; - - unit - = *newmtl - ; - -# ifndef NDEBUG - BOOST_SPIRIT_DEBUG_NODE( INTEGER_DECIMAL_CONSTANT ); - BOOST_SPIRIT_DEBUG_NODE( INTEGER_CONSTANT ); - BOOST_SPIRIT_DEBUG_NODE( FLOAT_CONSTANT ); - BOOST_SPIRIT_DEBUG_NODE( FLOAT_CONSTANT_1 ); - BOOST_SPIRIT_DEBUG_NODE( FLOAT_CONSTANT_2 ); - BOOST_SPIRIT_DEBUG_NODE( FLOAT_CONSTANT_3 ); - BOOST_SPIRIT_DEBUG_NODE( CONSTANT ); - BOOST_SPIRIT_DEBUG_NODE( ILLUM ); - BOOST_SPIRIT_DEBUG_NODE( NS ); - BOOST_SPIRIT_DEBUG_NODE( NI ); - BOOST_SPIRIT_DEBUG_NODE( KS ); - BOOST_SPIRIT_DEBUG_NODE( KD ); - BOOST_SPIRIT_DEBUG_NODE( KA ); - BOOST_SPIRIT_DEBUG_NODE( D ); - BOOST_SPIRIT_DEBUG_NODE( NEWMTL ); - BOOST_SPIRIT_DEBUG_NODE( IDENTIFIER ); - BOOST_SPIRIT_DEBUG_NODE( MAP_KD ); - BOOST_SPIRIT_DEBUG_NODE( TF ); - BOOST_SPIRIT_DEBUG_NODE( SHARPNESS ); - BOOST_SPIRIT_DEBUG_NODE( REFL ); - BOOST_SPIRIT_DEBUG_NODE( REFLTYPE ); - BOOST_SPIRIT_DEBUG_NODE( REFLMM ); - BOOST_SPIRIT_DEBUG_NODE( REFLCLAMP ); - BOOST_SPIRIT_DEBUG_NODE( ON ); - BOOST_SPIRIT_DEBUG_NODE( OFF ); - BOOST_SPIRIT_DEBUG_NODE( unit ); - BOOST_SPIRIT_DEBUG_NODE( newmtl ); - BOOST_SPIRIT_DEBUG_NODE( ka ); - BOOST_SPIRIT_DEBUG_NODE( kd ); - BOOST_SPIRIT_DEBUG_NODE( ks ); - BOOST_SPIRIT_DEBUG_NODE( ns ); - BOOST_SPIRIT_DEBUG_NODE( ni ); - BOOST_SPIRIT_DEBUG_NODE( illum ); - BOOST_SPIRIT_DEBUG_NODE( d ); - BOOST_SPIRIT_DEBUG_NODE( map_Kd ); - BOOST_SPIRIT_DEBUG_NODE( tf ); - BOOST_SPIRIT_DEBUG_NODE( sharpness ); - BOOST_SPIRIT_DEBUG_NODE( refl ); - BOOST_SPIRIT_DEBUG_NODE( reflmm ); - BOOST_SPIRIT_DEBUG_NODE( reflclamp ); -# endif - } - - spirit::symbols<> keywords; - - spirit::rule<ScannerT> unit, newmtl, ka, kd, ks, ns, ni, illum, d, map_Kd, tf, sharpness, refl, reflmm, reflclamp; - spirit::rule<ScannerT> IDENTIFIER, NEWMTL, KA, KD, KS, NS, NI, ILLUM, SHARPNESS; - spirit::rule<ScannerT> INTEGER_DECIMAL_CONSTANT, INTEGER_CONSTANT; - spirit::rule<ScannerT> FLOAT_CONSTANT, FLOAT_CONSTANT_1, FLOAT_CONSTANT_2; - spirit::rule<ScannerT> FLOAT_CONSTANT_3, CONSTANT, D, MAP_KD, TF; - spirit::rule<ScannerT> REFL, REFLTYPE, REFLMM, REFLCLAMP, ON, OFF; - - const spirit::rule<ScannerT>& start( ) const - { return unit; } - }; - - grammar_state& eval; - }; - - ////////////////////////////////////////////////////////////// - // obj grammar. some may think is a bit overkill to use a - // spirit grammar for the obj format. however, using spirit - // here gives us good insight on how spirit may be used for - // more interesting grammars like the sg fx one. - struct OBJ_grammar : public spirit::grammar<OBJ_grammar> - { - OBJ_grammar( grammar_state& eval_ ) - : eval( eval_ ) - { } - - template<class ScannerT> - struct definition - { - struct load_material_action - { - explicit load_material_action( const fs::path& base_url, grammar_state& gs ) - : gs_( gs ) - , base_url_( base_url ) - { } - - void operator( )( const char* first, const char* last ) const - { - fs::path orig_path( std::string( first, last ), fs::native ); - - fs::ifstream file; - file.open( orig_path, std::ios::in ); - if( !file.is_open( ) ) - { - file.open( base_url_ / orig_path, std::ios::in ); - if( !file.is_open( ) ) - return; - } - - file.unsetf( std::ios::skipws ); - - std::string mtl( ( std::istreambuf_iterator<char>( file ) ), std::istreambuf_iterator<char>( ) ); - - mtl_grammar mtl_g( gs_ ); - skip_grammar skip_g; - -# ifndef NDEBUG - BOOST_SPIRIT_DEBUG_NODE( mtl_g ); - BOOST_SPIRIT_DEBUG_NODE( skip_g ); -# endif - - spirit::parse_info<> result = spirit::parse( mtl.c_str( ), mtl_g, skip_g ); - } - - grammar_state& gs_; - fs::path base_url_; - }; - - static const int RESERVE_SIZE = 1000; - - ////////////////////////////////////////////////// - // grammar definition - definition( const OBJ_grammar& self ) - : V( 'v' ) - , N( 'n' ) - , T( 't' ) - , F( 'f' ) - , U( 'u' ) - , G( 'g' ) - , S( 's' ) - , O( 'o' ) - , SLASH( '/' ) - { - using namespace boost::spirit; - - keywords - = "v", "vn", "vt", "f", "g", "s", "u", "mtllib", "usemtl", "on", "off" - ; - - MTLLIB = strlit<>( "mtllib" ); - USEMTL = strlit<>( "usemtl" ); - ON = strlit<>( "on" ); - OFF = strlit<>( "off" ); - - IDENTIFIER - = lexeme_d - [ - ( ( alpha_p | '_' | '$' ) >> *( alnum_p | '_' | '$' | '-' | '.' ) ) - ( keywords >> anychar_p - ( alnum_p | '_' | '$' ) ) - ] - ; - - INTEGER_DECIMAL_CONSTANT - = lexeme_d[ +digit_p ] - ; - - INTEGER_CONSTANT - = INTEGER_DECIMAL_CONSTANT - ; - - FLOAT_CONSTANT_1 // 12345[eE][+-]123[lLfF]? - = lexeme_d - [ - +digit_p - >> ( chlit<>( 'e' ) | chlit<>( 'E' ) ) - >> !sign_p - >> +digit_p - >> !as_lower_d[ chlit<>( 'l' ) | chlit<>( 'f' ) ] - ] - ; - - FLOAT_CONSTANT_2 // .123([[eE][+-]123)?[lLfF]? - = lexeme_d - [ - - *digit_p - >> chlit<>('.') - >> +digit_p - >> !( ( chlit<>( 'e' ) | chlit<>( 'E' ) ) - >> !sign_p - >> +digit_p - ) - >> !as_lower_d[ chlit<>( 'l' ) | chlit<>( 'f' ) ] - ] - ; - - FLOAT_CONSTANT_3 // 12345.([[eE][+-]123)?[lLfF]? - = lexeme_d - [ - +digit_p - >> chlit<>( '.' ) - >> *digit_p - >> !( ( chlit<>( 'e' ) | chlit<>( 'E' ) ) - >> !sign_p - >> +digit_p - ) - >> !as_lower_d[ chlit<>( 'l' ) | chlit<>( 'f' ) ] - ] - ; - - FLOAT_CONSTANT - = FLOAT_CONSTANT_1 - | FLOAT_CONSTANT_2 - | FLOAT_CONSTANT_3 - ; - - CONSTANT - = !sign_p >> longest_d[ FLOAT_CONSTANT | INTEGER_CONSTANT ] - ; - - vertex_element - = V - >> CONSTANT[ geometry_action( ( const_cast<OBJ_grammar&>( self ) ).eval.v ) ] - >> CONSTANT[ geometry_action( ( const_cast<OBJ_grammar&>( self ) ).eval.v ) ] - >> CONSTANT[ geometry_action( ( const_cast<OBJ_grammar&>( self ) ).eval.v ) ] - ; - - normal_element - = V >> N - >> CONSTANT[ geometry_action( ( const_cast<OBJ_grammar&>( self ) ).eval.vn ) ] - >> CONSTANT[ geometry_action( ( const_cast<OBJ_grammar&>( self ) ).eval.vn ) ] - >> CONSTANT[ geometry_action( ( const_cast<OBJ_grammar&>( self ) ).eval.vn ) ] - ; - - texcoord_element - = V >> T - >> CONSTANT[ geometry_action( ( const_cast<OBJ_grammar&>( self ) ).eval.vt ) ] - >> CONSTANT[ geometry_action( ( const_cast<OBJ_grammar&>( self ) ).eval.vt ) ] - >> ( *CONSTANT ) - ; - - face // can be one of %d, %d//%d, %d/%d, %d/%d/%d - = longest_d - [ - INTEGER_CONSTANT - | INTEGER_CONSTANT >> SLASH >> SLASH >> INTEGER_CONSTANT - | INTEGER_CONSTANT >> SLASH >> INTEGER_CONSTANT - | INTEGER_CONSTANT >> SLASH >> INTEGER_CONSTANT >> SLASH >> INTEGER_CONSTANT - ] - [ topology_action( ( const_cast<OBJ_grammar&>( self ) ).eval ) ] - ; - - face_element - = ( F >> face >> face >> face >> *face ) - [ topology_wrap_up_action( ( const_cast<OBJ_grammar&>( self ) ).eval ) ] - ; - - material_element - = MTLLIB >> IDENTIFIER[ load_material_action( self.base_url_, ( const_cast<OBJ_grammar&>( self ) ).eval ) ] - ; - - usemtl_element - = USEMTL >> IDENTIFIER[ use_material_action( ( const_cast<OBJ_grammar&>( self ) ).eval ) ] - ; - - group_element - = ( G >> *IDENTIFIER )[ group_action( ( const_cast<OBJ_grammar&>( self ) ).eval ) ] - ; - - smoothing_group_element - = S >> ( INTEGER_CONSTANT | ON | OFF ) - ; - - theo_element - = ( O >> *IDENTIFIER ) - ; - - elements - = vertex_element - | normal_element - | texcoord_element - | face_element - | material_element - | group_element - | smoothing_group_element - | theo_element - | usemtl_element - ; - - unit - = *elements - ; - - #ifndef NDEBUG - BOOST_SPIRIT_DEBUG_NODE( INTEGER_DECIMAL_CONSTANT ); - BOOST_SPIRIT_DEBUG_NODE( INTEGER_CONSTANT ); - BOOST_SPIRIT_DEBUG_NODE( FLOAT_CONSTANT ); - BOOST_SPIRIT_DEBUG_NODE( FLOAT_CONSTANT_1 ); - BOOST_SPIRIT_DEBUG_NODE( FLOAT_CONSTANT_2 ); - BOOST_SPIRIT_DEBUG_NODE( FLOAT_CONSTANT_3 ); - BOOST_SPIRIT_DEBUG_NODE( CONSTANT ); - BOOST_SPIRIT_DEBUG_NODE( IDENTIFIER ); - BOOST_SPIRIT_DEBUG_NODE( MTLLIB ); - BOOST_SPIRIT_DEBUG_NODE( USEMTL ); - BOOST_SPIRIT_DEBUG_NODE( ON ); - BOOST_SPIRIT_DEBUG_NODE( OFF ); - - BOOST_SPIRIT_DEBUG_NODE( unit ); - BOOST_SPIRIT_DEBUG_NODE( elements ); - BOOST_SPIRIT_DEBUG_NODE( vertex_element ); - BOOST_SPIRIT_DEBUG_NODE( normal_element ); - BOOST_SPIRIT_DEBUG_NODE( texcoord_element ); - BOOST_SPIRIT_DEBUG_NODE( face_element ); - BOOST_SPIRIT_DEBUG_NODE( material_element ); - BOOST_SPIRIT_DEBUG_NODE( param_element ); - BOOST_SPIRIT_DEBUG_NODE( group_element ); - BOOST_SPIRIT_DEBUG_NODE( smoothing_group_element ); - BOOST_SPIRIT_DEBUG_NODE( face ); - BOOST_SPIRIT_DEBUG_NODE( theo_element ); - BOOST_SPIRIT_DEBUG_NODE( usemtl_element ); - #endif - } - - //////////////////////////////////////////////////// - spirit::symbols<> keywords; - - spirit::chlit<> V, N, T, F, U, G, S, O, SLASH; - - spirit::rule<ScannerT> INTEGER_DECIMAL_CONSTANT, INTEGER_CONSTANT; - spirit::rule<ScannerT> FLOAT_CONSTANT, FLOAT_CONSTANT_1, FLOAT_CONSTANT_2; - spirit::rule<ScannerT> FLOAT_CONSTANT_3, CONSTANT, IDENTIFIER, MTLLIB, USEMTL; - spirit::rule<ScannerT> ON, OFF; - - spirit::rule<ScannerT> unit, elements, vertex_element, normal_element; - spirit::rule<ScannerT> texcoord_element, face_element, material_element; - spirit::rule<ScannerT> param_element, group_element, face, smoothing_group_element; - spirit::rule<ScannerT> theo_element, usemtl_element; - - const spirit::rule<ScannerT>& start( ) const - { return unit; } - }; - - void set_base_url( const fs::path& base_url ) - { base_url_ = base_url; } - - grammar_state& eval; - fs::path base_url_; - }; - - // - template<typename C, typename V> - void copy_( const C& c, V& v ) - { -#if _MSC_VER >= 1400 - std::copy( c.begin( ), c.end( ), stdext::checked_array_iterator<typename V::iterator>( v.begin( ), v.size( ) ) ); -#else - std::copy( c.begin( ), c.end( ), v.begin( ) ); -#endif - } - - void unify_indices( OBJ_grammar& g ) - { - std::vector<float> vn, vt; - vn.resize( g.eval.v.size( ) ); - vt.resize( g.eval.v.size( ) ); - - if( !g.eval.vn.empty( ) ) - { - typedef std::map<opl::string, group_state>::const_iterator const_iterator; - for( const_iterator I = g.eval.group.begin( ); I != g.eval.group.end( ); ++I ) - { - for( int j = 0; j < I->second.vni.size( ); ++j ) - { - int i0 = I->second.vi[ j ]; - int i1 = I->second.vni[ j ]; - if( i0 == -1 ) - continue; - - i0 *= 3; - i1 *= 3; - - vn[ i0 + 0 ] = g.eval.vn[ i1 + 0 ]; - vn[ i0 + 1 ] = g.eval.vn[ i1 + 1 ]; - vn[ i0 + 2 ] = g.eval.vn[ i1 + 2 ]; - } - } - g.eval.vn = vn; - } - - if( !g.eval.vt.empty( ) ) - { - typedef std::map<opl::string, group_state>::const_iterator const_iterator; - for( const_iterator I = g.eval.group.begin( ); I != g.eval.group.end( ); ++I ) - { - for( int j = 0; j < I->second.vti.size( ); ++j ) - { - int i0 = I->second.vi[ j ]; - int i1 = I->second.vti[ j ]; - if( i0 == -1 ) - continue; - - i0 *= 3; - i1 *= 3; - - vt[ i0 + 0 ] = g.eval.vt[ i1 + 0 ]; - vt[ i0 + 1 ] = g.eval.vt[ i1 + 1 ]; - vt[ i0 + 2 ] = g.eval.vt[ i1 + 2 ]; - } - } - g.eval.vt = vt; - } - } - - void build_topology( const group_state& state, const sg::mesh_ptr& geometry ) - { - opl::m_int32* index = geometry->pointer<opl::m_int32>( L"index" ); - opl::m_int32* count = geometry->pointer<opl::m_int32>( L"count" ); - - index->reserve( state.vi.size( ) ); - count->reserve( state.vi.size( ) / 3 ); - - for( int i = 0; i < state.vi.size( ); ++i ) - { - int prim_count = 0; - for( int j = i; j < state.vi.size( ); ++j, ++i ) - { - if( state.vi[ j ] == -1 ) - { - count->push_back( prim_count ); - break; - } - - index->push_back( state.vi[ j ] ); - ++prim_count; - } - } - } - - // - void add_attribute( const sg::mesh_ptr& ifs, const sg::attribute_array_ptr& attr, const opl::wstring& name ) - { - sg::v_attribute_array_ptr* attr_ = ifs->pointer<sg::v_attribute_array_ptr>( name ); - attr_->get( ) = attr; - } - - sg::mesh_ptr create_geometry_node( - const OBJ_grammar& g, - const sg::attribute_array_ptr& coordinate, - const sg::attribute_array_ptr& normal, - const sg::attribute_array_ptr& texcoord ) - { - sg::mesh_ptr ifs( new sg::mesh( ) ); - ifs->prim_type( ) = sg::mesh::POLYGONS; - - if( !g.eval.v.empty( ) ) - add_attribute( ifs, coordinate, L"coord" ); - - if( !g.eval.vn.empty( ) ) - add_attribute( ifs, normal, L"normal" ); - - if( !g.eval.vt.empty( ) ) - { - sg::mv_uv_set_ptr* uv_ = ifs->pointer<sg::mv_uv_set_ptr>( L"uv" ); - - sg::uv_set_ptr uv_set( new sg::uv_set( ) ); - uv_->push_back( sg::v_uv_set_ptr( uv_set ) ); - - sg::v_attribute_array_ptr* uv = uv_set->pointer<sg::v_attribute_array_ptr>( L"uv" ); - uv->get( ) = texcoord; - } - - return ifs; - } - - // XXX TODO: create could try to share common materials between groups... - sg::appearance_ptr create_appearance_node( const OBJ_grammar& g, const group_state& grp_state ) - { - typedef grammar_state::materials::const_iterator const_iterator; - - sg::appearance_ptr appearance( new sg::appearance( ) ); - - sg::v_material_ptr* material = appearance->pointer<sg::v_material_ptr>( L"material" ); - - sg::material_ptr mtl( new sg::material( ) ); - material->get( ) = mtl; - - const_iterator I = g.eval.material.find( grp_state.mtl ); - if( I == g.eval.material.end( ) ) - return appearance; - - opl::v_color* diffuse = mtl->pointer<opl::v_color>( L"diffuseColor" ); - - ( *diffuse ).get( )[ 0 ] = I->second.kd[ 0 ]; - ( *diffuse ).get( )[ 1 ] = I->second.kd[ 1 ]; - ( *diffuse ).get( )[ 2 ] = I->second.kd[ 2 ]; - - if( !I->second.map_kd.empty( ) ) - { - sg::m_texture_ptr* texture = appearance->pointer<sg::m_texture_ptr>( L"texture" ); - - sg::texture_ptr tex( new sg::texture( ) ); - texture->push_back( tex ); - - opl::m_url* url = tex->pointer<opl::m_url>( L"url" ); - url->push_back( fs::path( I->second.map_kd.c_str( ), fs::native ) ); - } - - return appearance; - } - - void center_object( std::vector<float>& v ) - { - float min[ 3 ]; - float max[ 3 ]; - - min[ 0 ] = max[ 0 ] = v[ 0 ]; - min[ 1 ] = max[ 1 ] = v[ 1 ]; - min[ 2 ] = max[ 2 ] = v[ 2 ]; - - for( size_t i = 3; i < v.size( ); i += 3 ) - { - if( min[ 0 ] >= v[ i + 0 ] ) - min[ 0 ] = v[ i + 0 ]; - else if( max[ 0 ] < v[ i + 0 ] ) - max[ 0 ] = v[ i + 0 ]; - - if( min[ 1 ] >= v[ i + 1 ] ) - min[ 1 ] = v[ i + 1 ]; - else if( max[ 1 ] < v[ i + 1 ] ) - max[ 1 ] = v[ i + 1 ]; - - if( min[ 2 ] >= v[ i + 2 ] ) - min[ 2 ] = v[ i + 2 ]; - else if( max[ 2 ] < v[ i + 2 ] ) - max[ 2 ] = v[ i + 2 ]; - } - - float centre[ 3 ]; - centre[ 0 ] = ( max[ 0 ] + min[ 0 ] ) * 0.5f; - centre[ 1 ] = ( max[ 1 ] + min[ 1 ] ) * 0.5f; - centre[ 2 ] = ( max[ 2 ] + min[ 2 ] ) * 0.5f; - - for( size_t i = 0; i < v.size( ); i += 3 ) - { - v[ i + 0 ] -= centre[ 0 ]; - v[ i + 1 ] -= centre[ 1 ]; - v[ i + 2 ] -= centre[ 2 ]; - } - } - - void create_geometry( const std::vector<float>& v, sg::attribute_array_ptr& arr, int comp ) - { - opl::m_float* val = arr->pointer<opl::m_float>( L"value" ); - opl::v_int32* nc = arr->pointer<opl::v_int32>( L"components" ); - - val->resize( v.size( ) ); - nc->get( ) = comp; - - copy_( v, *val ); - } - - sg::spatial_ptr build_obj_graph( OBJ_grammar& g ) - { - sg::spatial_ptr grp( new sg::group( ) ); - sg::m_spatial_ptr* children = grp->pointer<sg::m_spatial_ptr>( L"children" ); - - sg::attribute_array_ptr varr( new sg::attribute_array( ) ); - sg::attribute_array_ptr narr( new sg::attribute_array( ) ); - sg::attribute_array_ptr tarr( new sg::attribute_array( ) ); - - unify_indices( g ); - - center_object( g.eval.v ); - create_geometry( g.eval.v, varr, 3 ); - create_geometry( g.eval.vn, narr, 3 ); - create_geometry( g.eval.vt, tarr, 2 ); - - typedef std::map<opl::string, group_state>::const_iterator const_iterator; - for( const_iterator I = g.eval.group.begin( ); I != g.eval.group.end( ); ++I ) - { - sg::spatial_ptr shape( new sg::shape( ) ); - - sg::v_mesh_ptr* geometry = shape->pointer<sg::v_mesh_ptr>( L"geometry" ); - sg::v_appearance_ptr* appearance = shape->pointer<sg::v_appearance_ptr>( L"appearance" ); - - appearance->get( ) = create_appearance_node( g, I->second ); - - sg::mesh_ptr ifs = create_geometry_node( g, varr, narr, tarr ); - geometry->get( ) = ifs; - - build_topology( I->second, ifs ); - - children->push_back( shape ); - } - - return grp; - } - - // - bool parse_and_build_obj_graph( const fs::path& base_url, const std::string& obj, sg::spatial_ptr& root ) - { - grammar_state eval; - - OBJ_grammar obj_g( eval ); - skip_grammar skip_g; - -#ifndef NDEBUG - BOOST_SPIRIT_DEBUG_NODE( obj_g ); - BOOST_SPIRIT_DEBUG_NODE( skip_g ); -#endif - - obj_g.set_base_url( base_url ); - spirit::parse_info<> result = spirit::parse( obj.c_str( ), obj_g, skip_g ); - - return result.full && ( root = build_obj_graph( obj_g ) ); - } - - // - sg::scene_ptr load_obj( const fs::path& path ) - { - sg::scene_ptr sc( new sg::scene( ) ); - - fs::ifstream file( path, std::ios::in ); - if( !file.is_open( ) ) - return sc; - - file.unsetf( std::ios::skipws ); - - std::string obj( ( std::istreambuf_iterator<char>( file ) ), std::istreambuf_iterator<char>( ) ); - - sg::spatial_ptr root; - if( !parse_and_build_obj_graph( path.branch_path( ), obj, root ) ) - return sc; - - sc->set_root( root ); - - return sc; - } -} - -sg::scene_ptr OBJ_plugin::load( const fs::path& path, const opl::string& /*options*/ ) -{ return load_obj( path ); } - -bool OBJ_plugin::store( const fs::path& /*path*/, const sg::scene_ptr& /*root*/ ) -{ return false; } - -} } } } Copied: trunk/lib/openlibraries/src/openobjectlib/plugins/wavefront/obj_plugin.cpp (from rev 375, trunk/lib/openlibraries/src/openobjectlib/plugins/obj/obj_plugin.cpp) =================================================================== --- trunk/lib/openlibraries/src/openobjectlib/plugins/wavefront/obj_plugin.cpp (rev 0) +++ trunk/lib/openlibraries/src/openobjectlib/plugins/wavefront/obj_plugin.cpp 2007-11-06 21:59:54 UTC (rev 376) @@ -0,0 +1,1172 @@ + +// OBJ - An OBJ plugin to sg. + +// Copyright (C) 2005-2006 VM Inc. +// Released under the LGPL. +// For more information, see http://www.openlibraries.org. + +#include <algorithm> +#include <map> +#include <string> +#include <vector> + +#include <boost/filesystem/fstream.hpp> +#include <boost/tokenizer.hpp> + +#include <openpluginlib/pl/geometry.hpp> +#include <openpluginlib/pl/property.hpp> +#include <openpluginlib/pl/utf8_utils.hpp> + +#include <openobjectlib/sg/appearance.hpp> +#include <openobjectlib/sg/spatial.hpp> +#include <openobjectlib/sg/meshes.hpp> + +#include <openobjectlib/plugins/obj/obj_plugin.hpp> +#include <openobjectlib/plugins/obj/spirit.hpp> + +namespace fs = boost::filesystem; +namespace spirit = boost::spirit; +namespace opl = olib::openpluginlib; +namespace sg = olib::openobjectlib::sg; + +namespace olib { namespace openobjectlib { namespace plugins { namespace OBJ { + +namespace +{ + opl::string get_base_url( const opl::string& url ) + { +#ifdef WIN32 + size_t pos = url.find_last_of( '\\' ); + if( pos != opl::string::npos ) + return opl::string( url.begin( ), url.begin( ) + pos + 1 ); +#else + return opl::string( url.begin( ), url.begin( ) + url.find_last_of( '/' ) + 1 ); +#endif + return opl::string( ); + } + + /////////////////////////////////////////////////////////////// + // grammar state + struct material_state + { + explicit material_state( const opl::string& name_ ) + : ka( 0.2f, 0.2f, 0.2f ) + , kd( 0.8f, 0.8f, 0.8f ) + , ks( 0.2f, 0.2f, 0.2f ) + , tf( 1.0f, 1.0f, 1.0f ) + , ns( 65.0f ) + , name( name_ ) + { } + + opl::vec3f ka, kd, ks, tf; + float ns; + float sharpness; + opl::string name; + opl::string map_kd; + }; + + struct group_state + { + typedef std::vector<int> vec_ints; + + explicit group_state( const opl::string& mtl_ ) + : mtl( mtl_ ) + { } + + vec_ints vi, vni, vti; + opl::string mtl; + }; + + struct grammar_state + { + typedef std::vector<float> vec_floats; + typedef std::vector<int> vec_ints; + typedef std::map<opl::string, group_state> groups; + typedef std::map<opl::string, material_state> materials; + + explicit grammar_state( ) + : grp( 0 ) + , mtl( 0 ) + { set_group( "default" ); } + + + // XXX merge these two members by means of templates. + // XXX this totally sucks. needs a revamp ASAP. + void set_group( const opl::string& name ) + { + typedef groups::iterator iterator; + + iterator I = group.find( name ); + if( I != group.end( ) ) + { + grp = &( I->second ); + } + else + { + opl::string mtl_name( "default" ); + + if( mtl ) mtl_name = mtl->name; + + grp = &( group.insert( groups::value_type( name, group_state( mtl_name ) ) ).first->second ); + } + } + + void set_material( const opl::string& name ) + { + typedef materials::iterator iterator; + + iterator I = material.find( name ); + if( I != material.end( ) ) + { + mtl = &( I->second ); + } + else + { + mtl = &( material.insert( materials::value_type( name, material_state( name ) ) ).first->second ); + } + + grp->mtl = name; + } + + groups group; + materials material; + vec_floats v, vn, vt; + + group_state* grp; + material_state* mtl; + }; + + /////////////////////////////////// + /// functors + class geometry_action + { + public: + explicit geometry_action( grammar_state::vec_floats& v ) + : v_( v ) + { } + + void operator( )( const char* first, const char* last ) const + { v_.push_back( static_cast<float>( atof( opl::string( first, last ).c_str( ) ) ) ); } + + private: + grammar_state::vec_floats& v_; + }; + + // + class topology_action + { + public: + explicit topology_action( grammar_state& gs ) + : gs_( gs ) + { } + + void operator( )( const char* first, const char* last ) const + { + const char* iter = first; + + for( ; iter != last && *iter != '/'; ++iter ) + ; + + gs_.grp->vi.push_back( atoi( opl::string( first, iter ).c_str( ) ) - 1 ); + + // texture + if( iter != last && *++iter != '/' ) + { + for( ; iter != last && *iter != '/'; ++iter ) + ; + + gs_.grp->vti.push_back( atoi( opl::string( first, iter ).c_str( ) ) - 1 ); + } + + // normal + if( iter != last ) + { + first = ++iter; + + gs_.grp->vni.push_back( atoi( opl::string( first, last ).c_str( ) ) - 1 ); + } + } + + private: + grammar_state& gs_; + }; + + // + class topology_wrap_up_action + { + public: + explicit topology_wrap_up_action( grammar_state& gs ) + : gs_( gs ) + { } + + void operator( )( const char* /*first*/, const char* /*last*/ ) const + { + gs_.grp->vi.push_back( -1 ); + gs_.grp->vni.push_back( -1 ); + gs_.grp->vti.push_back( -1 ); + } + + private: + grammar_state& gs_; + }; + + // + struct group_action + { + explicit group_action( grammar_state& gs ) + : gs_( gs ) + { } + + void operator( )( const char* first, const char* last ) const + { + opl::string s; + + if( ++first == last ) + s.assign( "default" ); + else + s.assign( ++first, last ); // XXX needs a proper trim left and trim right. + + gs_.set_group( s ); + } + + grammar_state& gs_; + }; + + // + struct use_material_action + { + explicit use_material_action( grammar_state& gs ) + : gs_( gs ) + { } + + void operator( )( const char* first, const char* last ) const + { gs_.set_material( opl::string( first, last ) ); } + + grammar_state& gs_; + }; + + // + struct material_action + { + explicit material_action( grammar_state& gs ) + : gs_( gs ) + { } + + void operator( )( const char* first, const char* last ) const + { gs_.set_material( opl::string( first, last ) ); } + + grammar_state& gs_; + }; + + // + opl::vec3f extract_vec3f_info( const opl::string& str ) + { + typedef boost::tokenizer<boost::char_separator<char> > tokenizer; + + opl::vec3f vec; + + std::string st( str.c_str( ) ); + + boost::char_separator<char> sep( " \t" ); + tokenizer tok( st.begin( ), st.end( ), sep ); + + tokenizer::const_iterator I = tok.begin( ); + if( I != tok.end( ) ) + vec[ 0 ] = static_cast<float>( strtod( I->c_str( ), 0 ) ); + ++I; + + if( I != tok.end( ) ) + vec[ 1 ] = static_cast<float>( strtod( I->c_str( ), 0 ) ); + ++I; + + if( I != tok.end( ) ) + vec[ 2 ] = static_cast<float>( strtod( I->c_str( ), 0 ) ); + ++I; + + return vec; + } + + struct ka_action + { + explicit ka_action( grammar_state& gs ) + : gs_( gs ) + { } + + void operator( )( const char* first, const char* last ) const + { + opl::string tmp( first, last ); + opl::vec3f ka = extract_vec3f_info( tmp ); + + gs_.mtl->ka = ka; + } + + grammar_state& gs_; + }; + + struct kd_action + { + explicit kd_action( grammar_state& gs ) + : gs_( gs ) + { } + + void operator( )( const char* first, const char* last ) const + { + opl::string tmp( first, last ); + opl::vec3f kd = extract_vec3f_info( tmp ); + + gs_.mtl->kd = kd; + } + + grammar_state& gs_; + }; + + struct ks_action + { + explicit ks_action( grammar_state& gs ) + : gs_( gs ) + { } + + void operator( )( const char* first, const char* last ) const + { + opl::string tmp( first, last ); + opl::vec3f ks = extract_vec3f_info( tmp ); + + gs_.mtl->ks = ks; + } + + grammar_state& gs_; + }; + + struct map_kd_action + { + explicit map_kd_action( grammar_state& gs ) + : gs_( gs ) + { } + + void operator( )( const char* first, const char* last ) const + { + opl::string tmp( first, last ); + + gs_.mtl->map_kd = tmp; + } + + grammar_state& gs_; + }; + + /////////////////////////////////////////////////////////////// + // skip grammar (whitespace and comments) + struct skip_grammar : public spirit::grammar<skip_grammar> + { + template<class ScannerT> + struct definition + { + definition( const skip_grammar& /*self*/) + { + skip + = spirit::space_p + | spirit::comment_p( "#" ) + ; + +# ifndef NDEBUG + BOOST_SPIRIT_DEBUG_NODE( skip ); +# endif + } + + spirit::rule<ScannerT> skip; + + const spirit::rule<ScannerT>& start( ) const + { return skip; } + }; + }; + + ////////////////////////////////////////////////////////////// + // obj material grammar. + struct mtl_grammar : public spirit::grammar<mtl_grammar> + { + mtl_grammar( grammar_state& eval_ ) + : eval( eval_ ) + { } + + template<class ScannerT> + struct definition + { + definition( const mtl_grammar& self ) + { + using namespace boost::spirit; + + keywords + = "newmtl", "Ka", "Kd", "Ks", "illum", "Ns", "d", "map_Kd", "Tf" + ; + + NEWMTL = strlit<>( "newmtl" ); + KA = strlit<>( "Ka" ); + KD = strlit<>( "Kd" ); + KS = strlit<>( "Ks" ); + ILLUM = strlit<>( "illum" ); + NS = strlit<>( "Ns" ); + NI = strlit<>( "Ni" ); + D = strlit<>( "d" ); + MAP_KD = strlit<>( "map_Kd" ); + TF = strlit<>( "Tf" ); + REFL = strlit<>( "refl" ); + REFLTYPE = strlit<>( "-type" ); + REFLMM = strlit<>( "-mm" ); + REFLCLAMP = strlit<>( "-clamp" ); + SHARPNESS = strlit<>( "sharpness" ); + ON = strlit<>( "on" ); + OFF = strlit<>( "off" ); + + INTEGER_DECIMAL_CONSTANT + = lexeme_d[ +digit_p ] + ; + + INTEGER_CONSTANT + = INTEGER_DECIMAL_CONSTANT + ; + + FLOAT_CONSTANT_1 // 12345[eE][+-]123[lLfF]? + = lexeme_d + [ + +digit_p + >> ( chlit<>( 'e' ) | chlit<>( 'E' ) ) + >> !sign_p + >> +digit_p + >> !as_lower_d[ chlit<>( 'l' ) | chlit<>( 'f' ) ] + ] + ; + + FLOAT_CONSTANT_2 // .123([[eE][+-]123)?[lLfF]? + = lexeme_d + [ + + *digit_p + >> chlit<>('.') + >> +digit_p + >> !( ( chlit<>( 'e' ) | chlit<>( 'E' ) ) + >> !sign_p + >> +digit_p + ) + >> !as_lower_d[ chlit<>( 'l' ) | chlit<>( 'f' ) ] + ] + ; + + FLOAT_CONSTANT_3 // 12345.([[eE][+-]123)?[lLfF]? + = lexeme_d + [ + +digit_p + >> chlit<>( '.' ) + >> *digit_p + >> !( ( chlit<>( 'e' ) | chlit<>( 'E' ) ) + >> !sign_p + >> +digit_p + ) + >> !as_lower_d[ chlit<>( 'l' ) | chlit<>( 'f' ) ] + ] + ; + + FLOAT_CONSTANT + = FLOAT_CONSTANT_1 + | FLOAT_CONSTANT_2 + | FLOAT_CONSTANT_3 + ; + + CONSTANT + = !sign_p >> longest_d[ FLOAT_CONSTANT | INTEGER_CONSTANT ] + ; + + + IDENTIFIER + = lexeme_d + [ + ( ( alpha_p | '_' | '$' ) >> *( alnum_p | '_' | '$' | '-' | '.' ) ) - ( keywords >> anychar_p - ( alnum_p | '_' | '$' ) ) + ] + ; + + newmtl + = NEWMTL >> IDENTIFIER[ material_action( ( const_cast<mtl_grammar&>( self ) ).eval ) ] + >> *( ka | kd | ks | ns | ni | illum | d | sharpness | tf | refl | map_Kd ) + ; + + ka + = KA >> ( CONSTANT >> CONSTANT >> CONSTANT )[ ka_action( ( const_cast<mtl_grammar&>( self ) ).eval ) ] + ; + + kd = KD >> ( CONSTANT >> CONSTANT >> CONSTANT )[ kd_action( ( const_cast<mtl_grammar&>( self ) ).eval ) ] + ; + + ks = KS >> ( CONSTANT >> CONSTANT >> CONSTANT )[ ks_action( ( const_cast<mtl_grammar&>( self ) ).eval ) ] + ; + + ns = NS >> CONSTANT + ; + + ni = NI >> CONSTANT + ; + + sharpness + = SHARPNESS >> CONSTANT + ; + + illum + = ILLUM >> CONSTANT + ; + + d + = D >> CONSTANT + ; + + map_Kd + = MAP_KD >> IDENTIFIER[ map_kd_action( ( const_cast<mtl_grammar&>( self ) ).eval ) ] + ; + + tf + = TF >> ( CONSTANT >> CONSTANT >> CONSTANT ) + ; + + reflmm + = REFLMM >> CONSTANT >> CONSTANT + ; + + reflclamp + = REFLCLAMP >> ( ON | OFF ) + ; + + refl + = REFL >> REFLTYPE >> IDENTIFIER >> !( reflmm | reflclamp ) >> IDENTIFIER + ; + + unit + = *newmtl + ; + +# ifndef NDEBUG + BOOST_SPIRIT_DEBUG_NODE( INTEGER_DECIMAL_CONSTANT ); + BOOST_SPIRIT_DEBUG_NODE( INTEGER_CONSTANT ); + BOOST_SPIRIT_DEBUG_NODE( FLOAT_CONSTANT ); + BOOST_SPIRIT_DEBUG_NODE( FLOAT_CONSTANT_1 ); + BOOST_SPIRIT_DEBUG_NODE( FLOAT_CONSTANT_2 ); + BOOST_SPIRIT_DEBUG_NODE( FLOAT_CONSTANT_3 ); + BOOST_SPIRIT_DEBUG_NODE( CONSTANT ); + BOOST_SPIRIT_DEBUG_NODE( ILLUM ); + BOOST_SPIRIT_DEBUG_NODE( NS ); + BOOST_SPIRIT_DEBUG_NODE( NI ); + BOOST_SPIRIT_DEBUG_NODE( KS ); + BOOST_SPIRIT_DEBUG_NODE( KD ); + BOOST_SPIRIT_DEBUG_NODE( KA ); + BOOST_SPIRIT_DEBUG_NODE( D ); + BOOST_SPIRIT_DEBUG_NODE( NEWMTL ); + BOOST_SPIRIT_DEBUG_NODE( IDENTIFIER ); + BOOST_SPIRIT_DEBUG_NODE( MAP_KD ); + BOOST_SPIRIT_DEBUG_NODE( TF ); + BOOST_SPIRIT_DEBUG_NODE( SHARPNESS ); + BOOST_SPIRIT_DEBUG_NODE( REFL ); + BOOST_SPIRIT_DEBUG_NODE( REFLTYPE ); + BOOST_SPIRIT_DEBUG_NODE( REFLMM ); + BOOST_SPIRIT_DEBUG_NODE( REFLCLAMP ); + BOOST_SPIRIT_DEBUG_NODE( ON ); + BOOST_SPIRIT_DEBUG_NODE( OFF ); + BOOST_SPIRIT_DEBUG_NODE( unit ); + BOOST_SPIRIT_DEBUG_NODE( newmtl ); + BOOST_SPIRIT_DEBUG_NODE( ka ); + BOOST_SPIRIT_DEBUG_NODE( kd ); + BOOST_SPIRIT_DEBUG_NODE( ks ); + BOOST_SPIRIT_DEBUG_NODE( ns ); + BOOST_SPIRIT_DEBUG_NODE( ni ); + BOOST_SPIRIT_DEBUG_NODE( illum ); + BOOST_SPIRIT_DEBUG_NODE( d ); + BOOST_SPIRIT_DEBUG_NODE( map_Kd ); + BOOST_SPIRIT_DEBUG_NODE( tf ); + BOOST_SPIRIT_DEBUG_NODE( sharpness ); + BOOST_SPIRIT_DEBUG_NODE( refl ); + BOOST_SPIRIT_DEBUG_NODE( reflmm ); + BOOST_SPIRIT_DEBUG_NODE( reflclamp ); +# endif + } + + spirit::symbols<> keywords; + + spirit::rule<ScannerT> unit, newmtl, ka, kd, ks, ns, ni, illum, d, map_Kd, tf, sharpness, refl, reflmm, reflclamp; + spirit::rule<ScannerT> IDENTIFIER, NEWMTL, KA, KD, KS, NS, NI, ILLUM, SHARPNESS; + spirit::rule<ScannerT> INTEGER_DECIMAL_CONSTANT, INTEGER_CONSTANT; + spirit::rule<ScannerT> FLOAT_CONSTANT, FLOAT_CONSTANT_1, FLOAT_CONSTANT_2; + spirit::rule<ScannerT> FLOAT_CONSTANT_3, CONSTANT, D, MAP_KD, TF; + spirit::rule<ScannerT> REFL, REFLTYPE, REFLMM, REFLCLAMP, ON, OFF; + + const spirit::rule<ScannerT>& start( ) const + { return unit; } + }; + + grammar_state& eval; + }; + + ////////////////////////////////////////////////////////////// + // obj grammar. some may think is a bit overkill to use a + // spirit grammar for the obj format. however, using spirit + // here gives us good insight on how spirit may be used for + // more interesting grammars like the sg fx one. + struct OBJ_grammar : public spirit::grammar<OBJ_grammar> + { + OBJ_grammar( grammar_state& eval_ ) + : eval( eval_ ) + { } + + template<class ScannerT> + struct definition + { + struct load_material_action + { + explicit load_material_action( const fs::path& base_url, grammar_state& gs ) + : gs_( gs ) + , base_url_( base_url ) + { } + + void operator( )( const char* first, const char* last ) const + { + fs::path orig_path( std::string( first, last ), fs::native ); + + fs::ifstream file; + file.open( orig_path, std::ios::in ); + if( !file.is_open( ) ) + { + file.open( base_url_ / orig_path, std::ios::in ); + if( !file.is_open( ) ) + return; + } + + file.unsetf( std::ios::skipws ); + + std::string mtl( ( std::istreambuf_iterator<char>( file ) ), std::istreambuf_iterator<char>( ) ); + + mtl_grammar mtl_g( gs_ ); + skip_grammar skip_g; + +# ifndef NDEBUG + BOOST_SPIRIT_DEBUG_NODE( mtl_g ); + BOOST_SPIRIT_DEBUG_NODE( skip_g ); +# endif + + spirit::parse_info<> result = spirit::parse( mtl.c_str( ), mtl_g, skip_g ); + } + + grammar_state& gs_; + fs::path base_url_; + }; + + static const int RESERVE_SIZE = 1000; + + ////////////////////////////////////////////////// + // grammar definition + definition( const OBJ_grammar& self ) + : V( 'v' ) + , N( 'n' ) + , T( 't' ) + , F( 'f' ) + , U( 'u' ) + , G( 'g' ) + , S( 's' ) + , O( 'o' ) + , SLASH( '/' ) + { + using namespace boost::spirit; + + keywords + = "v", "vn", "vt", "f", "g", "s", "u", "mtllib", "usemtl", "on", "off" + ; + + MTLLIB = strlit<>( "mtllib" ); + USEMTL = strlit<>( "usemtl" ); + ON = strlit<>( "on" ); + OFF = strlit<>( "off" ); + + IDENTIFIER + = lexeme_d + [ + ( ( alpha_p | '_' | '$' ) >> *( alnum_p | '_' | '$' | '-' | '.' ) ) - ( keywords >> anychar_p - ( alnum_p | '_' | '$' ) ) + ] + ; + + INTEGER_DECIMAL_CONSTANT + = lexeme_d[ +digit_p ] + ; + + INTEGER_CONSTANT + = INTEGER_DECIMAL_CONSTANT + ; + + FLOAT_CONSTANT_1 // 12345[eE][+-]123[lLfF]? + = lexeme_d + [ + +digit_p + >> ( chlit<>( 'e' ) | chlit<>( 'E' ) ) + >> !sign_p + >> +digit_p + >> !as_lower_d[ chlit<>( 'l' ) | chlit<>( 'f' ) ] + ] + ; + + FLOAT_CONSTANT_2 // .123([[eE][+-]123)?[lLfF]? + = lexeme_d + [ + + *digit_p + >> chlit<>('.') + >> +digit_p + >> !( ( chlit<>( 'e' ) | chlit<>( 'E' ) ) + >> !sign_p + >> +digit_p + ) + >> !as_lower_d[ chlit<>( 'l' ) | chlit<>( 'f' ) ] + ] + ; + + FLOAT_CONSTANT_3 // 12345.([[eE][+-]123)?[lLfF]? + = lexeme_d + [ + +digit_p + >> chlit<>( '.' ) + >> *digit_p + >> !( ( chlit<>( 'e' ) | chlit<>( 'E' ) ) + >> !sign_p + >> +digit_p + ) + >> !as_lower_d[ chlit<>( 'l' ) | chlit<>( 'f' ) ] + ] + ; + + FLOAT_CONSTANT + = FLOAT_CONSTANT_1 + | FLOAT_CONSTANT_2 + | FLOAT_CONSTANT_3 + ; + + CONSTANT + = !sign_p >> longest_d[ FLOAT_CONSTANT | INTEGER_CONSTANT ] + ; + + vertex_element + = V + >> CONSTANT[ geometry_action( ( const_cast<OBJ_grammar&>( self ) ).eval.v ) ] + >> CONSTANT[ geometry_action( ( const_cast<OBJ_grammar&>( self ) ).eval.v ) ] + >> CONSTANT[ geometry_action( ( const_cast<OBJ_grammar&>( self ) ).eval.v ) ] + ; + + normal_element + = V >> N + >> CONSTANT[ geometry_action( ( const_cast<OBJ_grammar&>( self ) ).eval.vn ) ] + >> CONSTANT[ geometry_action( ( const_cast<OBJ_grammar&>( self ) ).eval.vn ) ] + >> CONSTANT[ geometry_action( ( const_cast<OBJ_grammar&>( self ) ).eval.vn ) ] + ; + + texcoord_element + = V >> T + >> CONSTANT[ geometry_action( ( const_cast<OBJ_grammar&>( self ) ).eval.vt ) ] + >> CONSTANT[ geometry_action( ( const_cast<OBJ_grammar&>( self ) ).eval.vt ) ] + >> ( *CONSTANT ) + ; + + face // can be one of %d, %d//%d, %d/%d, %d/%d/%d + = longest_d + [ + INTEGER_CONSTANT + | INTEGER_CONSTANT >> ... [truncated message content] |