// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 #include "stdafx.h" #include "StokeMXVersion.h" //Auto generated by WiXInstaller\version_gen.py #include "resource.h" #include "stoke/max3d/StokeGlobalInterface.hpp" #include #include #include #include #include #include #include // For refmaker_call_recursive #include #include #include #include #include #include #include #include #include #include // Stupid 3ds Max SDK feels the need to use macros that conflict with OpenVDB. #undef X_AXIS #undef Y_AXIS #undef Z_AXIS #pragma warning( push, 3 ) #pragma warning( disable : 4800 4244 4146 4267 4355 ) #include #pragma warning( pop ) #pragma warning( disable : 4503 ) // "decorated name length exceeded, name was truncated" casued by OpenVDB template // instantiations. #if defined( FIELD3D_AVAILABLE ) #include #endif #include #include #include #include #include #define ReflowGlobal_INTERFACE Interface_ID( 0x3b5876ae, 0x4cae2d96 ) #if defined( FUMEFX_SDK_AVAILABLE ) namespace frantic { namespace max3d { namespace volumetrics { extern std::unique_ptr create_fumefx_iodll_factory(); } } // namespace max3d } // namespace frantic #endif namespace ember { namespace max3d { // Fwd decl. Defined in EmberPipeObject.cpp void SetMaxMarkerCount( std::size_t count ); std::size_t GetMaxMarkerCount(); } // namespace max3d } // namespace ember namespace stoke { namespace max3d { namespace { ReflowGlobalInterface theReflowGlobalInterface; } ReflowGlobalInterface::ReflowGlobalInterface() : frantic::max3d::fnpublish::StaticInterface( ReflowGlobal_INTERFACE, _M( "StokeGlobalInterface" ), 0 ) { this->function( _T("CreateAdvector"), &ReflowGlobalInterface::CreateAdvector ).param( _T("Type") ); this->function( _T("CreateIDAllocator"), &ReflowGlobalInterface::CreateIDAllocator ); this->function( _T("CreateReflowField"), &ReflowGlobalInterface::CreateReflowField ).param( _T("Node") ); this->function( _T( "CreateDummyReflowField" ), &ReflowGlobalInterface::CreateDummyReflowField ); this->function( _T("CreateParticleVelocityField"), &ReflowGlobalInterface::CreateParticleField ) .param( _T("Node") ) .param( _T("Spacing") ) .param( _T("Min"), Point3( 0, 0, 0 ) ) .param( _T("Max"), Point3( 0, 0, 0 ) ) .param( _T("BoundsPadding"), 5 ) .param( _T("RemoveDivergence"), true ); this->function( _T("CreateAdditiveVelocityField"), &ReflowGlobalInterface::CreateAdditiveVelocityField ) .param( _T("Fields") ); this->function( _T("CreateKrakatoaGenerator"), &ReflowGlobalInterface::CreateParticleGenerator ) .param( _T("Node") ) .param( _T("JitterRadius"), 0.f ) .param( _T("IgnoreIDs"), false ); this->function( _T("CreateGeometryGenerator"), &ReflowGlobalInterface::CreateGeometryGenerator ) .param( _T("Node") ) .param( _T("Mode"), _T("Surface") ) .param( _T("VolumeSpacing"), 10.f ) .param( _T("SelectionType"), _T("FaceSelection") ) .param( _T("VertexJitterRadius"), 0.f ); #if defined( FUMEFX_SDK_AVAILABLE ) this->function( _T("CreateFumeFXGenerator"), &ReflowGlobalInterface::CreateFumeFXGenerator ).param( _T("Node") ); #endif this->function( _T("CreateParticleSet"), &ReflowGlobalInterface::CreateParticleSet ).param( _T("ExtraChannels") ); this->function( _T("AdvectParticleSet"), &ReflowGlobalInterface::AdvectParticleSetMXS ) .param( _T("ParticleSet") ) .param( _T("Advector") ) .param( _T("VelocityField") ) .param( _T("TimeStepSeconds") ); this->function( _T( "UpdateAgeChannel" ), &ReflowGlobalInterface::UpdateAgeChannelMXS ) .param( _T( "ParticleSet" ) ) .param( _T( "TimeStepSeconds" ) ); this->function( _T( "UpdateAdvectionOffsetChannel" ), &ReflowGlobalInterface::UpdateAdvectionOffsetChannelMXS ) .param( _T( "ParticleSet" ) ) .param( _T( "Advector" ) ) .param( _T( "VelocityField" ) ) .param( _T( "TimeStepSeconds" ) ); this->function( _T( "ApplyAdvectionOffsetChannel" ), &ReflowGlobalInterface::ApplyAdvectionOffsetChannelMXS ) .param( _T( "ParticleSet" ) ); this->function( _T( "MagmaEvaluateParticleSet" ), &ReflowGlobalInterface::MagmaEvaluateParticleSet ) .param( _T( "ParticleSet" ) ) .param( _T( "Magma" ) ) .param( _T( "EvaluationTime" ) ) .param( _T( "ErrorReporter" ) ); this->function( _T("WriteParticleSet"), &ReflowGlobalInterface::WriteParticleSet ) .param( _T("ParticleSet") ) .param( _T("FilePath") ); this->function( _T("BeginRenderMode"), &ReflowGlobalInterface::BeginRenderMode ).param( _T("NodeList") ); this->function( _T("EndRenderMode"), &ReflowGlobalInterface::EndRenderMode ).param( _T("NodeList") ); this->function( _T("GetSourceType"), &ReflowGlobalInterface::GetSourceType ).param( _T("Node") ); this->function( _T("GetVelocityType"), &ReflowGlobalInterface::GetVelocityType ).param( _T("Node") ); this->function( _T("SetTempDirectory"), &ReflowGlobalInterface::SetTempDirectory ).param( _T("Directory") ); this->function( _T("IsEmberField"), &ReflowGlobalInterface::IsEmberField ).param( _T("Node") ); this->function( _T("CreateMXSField"), &ReflowGlobalInterface::CreateMXSField ) .param( _T("Node") ) .param( _T("StackIndex"), 0 ); #if defined( FUMEFX_SDK_AVAILABLE ) this->function( _T("WriteFXDFile"), &ReflowGlobalInterface::WriteFXDFile ) .param( _T("FilePath") ) .param( _T("Node") ) .param( _T("WSBoundsMin") ) .param( _T("WSBoundsMax") ) .param( _T("Spacing") ) .param( _T("StackIndex"), 0 ); #endif #if defined( FIELD3D_AVAILABLE ) this->function( _T("WriteField3DFile"), &ReflowGlobalInterface::WriteField3DFile ) .param( _T("FilePath") ) .param( _T("Node") ) .param( _T("WSBoundsMin") ) .param( _T("WSBoundsMax") ) .param( _T("Spacing") ) .param( _T("StackIndex"), 0 ); #endif this->function( _T("WriteOpenVDBFile"), &ReflowGlobalInterface::WriteOpenVDBFile ) .param( _T("FilePath") ) .param( _T("Node") ) .param( _T("WSBoundsMin") ) .param( _T("WSBoundsMax") ) .param( _T("Spacing") ) .param( _T("StackIndex"), 0 ); this->read_only_property( _T("HomeDirectory"), &ReflowGlobalInterface::GetRootDirectory ); this->read_only_property( _T("Attributions"), &ReflowGlobalInterface::GetAttributions ); this->read_only_property( _T("Version"), &ReflowGlobalInterface::GetVersion ); this->read_only_property( _T("ViewportType"), &ReflowGlobalInterface::GetViewportType ); this->read_only_property( _T("PointSizeSupported"), &ReflowGlobalInterface::GetPointSizeSupported ); this->read_write_property( _T("LoggingLevel"), &ReflowGlobalInterface::GetLoggingLevel, &ReflowGlobalInterface::SetLoggingLevel ); this->read_write_property( _T("MaxDebuggerIterations"), &ReflowGlobalInterface::GetMaxDebugIterations, &ReflowGlobalInterface::SetMaxDebugIterations ); this->read_write_property( _T("MaxMarkerCount"), &ReflowGlobalInterface::GetMaxMarkerCount, &ReflowGlobalInterface::SetMaxMarkerCount ); this->enumeration() .option( _T("invalid"), SourceType::invalid ) .option( _T("particles"), SourceType::particles ) .option( _T("geometry"), SourceType::geometry ) .option( _T("fumefx"), SourceType::fumefx ); this->enumeration() .option( _T("invalid"), VelocityType::invalid ) .option( _T("particles"), VelocityType::particles ) .option( _T("fumefx"), VelocityType::fumefx ) .option( _T("phoenix"), VelocityType::phoenix ) .option( _T("force"), VelocityType::spacewarp ) .option( _T("field"), VelocityType::field ); this->enumeration() .option( _T("none"), LoggingLevel::none ) .option( _T("error"), LoggingLevel::error ) .option( _T("warning"), LoggingLevel::warning ) .option( _T("progress"), LoggingLevel::progress ) .option( _T("stats"), LoggingLevel::stats ) .option( _T("debug"), LoggingLevel::debug ); this->enumeration() .option( _T("legacy"), ViewportType::legacy ) .option( _T("nitrous"), ViewportType::nitrous ); } EnumID get_enum_id( ReflowGlobalInterface::SourceType::option ) { return ReflowGlobalInterface::kSourceType; } EnumID get_enum_id( ReflowGlobalInterface::VelocityType::option ) { return ReflowGlobalInterface::kVelocityType; } EnumID get_enum_id( ReflowGlobalInterface::LoggingLevel::option ) { return ReflowGlobalInterface::kLoggingLevel; } EnumID get_enum_id( ReflowGlobalInterface::ViewportType::option ) { return ReflowGlobalInterface::kViewportType; } ReflowGlobalInterface::~ReflowGlobalInterface() {} MSTR ReflowGlobalInterface::GetRootDirectory() { MSTR result; try { boost::filesystem::path modulePath( frantic::win32::GetModuleFileName( hInstance ) ); // Module path is expected to be like 'C:\Program Files\Thinkbox\Stoke\3dsMax2013\StokeMX.dlo' // The 'home' location is 'C:\Program Files\Thinkbox\Stoke\' std::wstring dirString = modulePath.parent_path().parent_path().make_preferred().wstring(); dirString = frantic::files::ensure_trailing_pathseparator( dirString ); result = dirString.c_str(); } catch( ... ) { frantic::max3d::rethrow_current_exception_as_max_t(); } return result; } MSTR ReflowGlobalInterface::GetAttributions() { return stoke::get_attributions().c_str(); } MSTR ReflowGlobalInterface::GetVersion() { return _T( FRANTIC_VERSION ); } void ReflowGlobalInterface::SetLoggingLevel( LoggingLevel::option loggingLevel ) { frantic::logging::set_logging_level( loggingLevel ); } ReflowGlobalInterface::LoggingLevel::option ReflowGlobalInterface::GetLoggingLevel() { return LoggingLevel::option( static_cast( frantic::logging::get_logging_level() ) ); } FPInterface* ReflowGlobalInterface::CreateAdvector( const MCHAR* szAdvectorType ) { try { M_STD_STRING type( szAdvectorType ); if( type == _T("RK2") ) return CreateRK2Advector(); if( type == _T("RK3") ) return CreateRK3Advector(); if( type == _T("RK4") ) return CreateRK4Advector(); } catch( ... ) { frantic::max3d::rethrow_current_exception_as_max_t(); } return NULL; } FPInterface* ReflowGlobalInterface::CreateIDAllocator() { try { return stoke::max3d::CreateIDAllocator(); } catch( ... ) { frantic::max3d::rethrow_current_exception_as_max_t(); } return NULL; } FPInterface* ReflowGlobalInterface::CreateReflowField( INode* pFieldNode ) { try { return stoke::max3d::CreateReflowField( pFieldNode ); } catch( ... ) { frantic::max3d::rethrow_current_exception_as_max_t(); } return NULL; } FPInterface* ReflowGlobalInterface::CreateDummyReflowField() { try { return stoke::max3d::CreateDummyReflowField(); } catch( ... ) { frantic::max3d::rethrow_current_exception_as_max_t(); } return NULL; } FPInterface* ReflowGlobalInterface::CreateParticleField( INode* pParticleNode, float spacing, const Point3& minBounds, const Point3& maxBounds, int boundsPadding, bool removeDivergence ) { try { if( minBounds.x < maxBounds.x && minBounds.y < maxBounds.y && minBounds.z < maxBounds.z ) { int bounds[6]; bounds[0] = (int)std::floor( minBounds.x / spacing - 0.5f ); bounds[1] = (int)std::ceil( maxBounds.x / spacing - 0.5f ) + 1; bounds[2] = (int)std::floor( minBounds.y / spacing - 0.5f ); bounds[3] = (int)std::ceil( maxBounds.y / spacing - 0.5f ) + 1; bounds[4] = (int)std::floor( minBounds.z / spacing - 0.5f ); bounds[5] = (int)std::ceil( maxBounds.z / spacing - 0.5f ) + 1; return stoke::max3d::CreateParticleVelocityField( pParticleNode, spacing, &bounds, 0, removeDivergence ); } else { return stoke::max3d::CreateParticleVelocityField( pParticleNode, spacing, NULL, boundsPadding, removeDivergence ); } } catch( ... ) { frantic::max3d::rethrow_current_exception_as_max_t(); } return NULL; } FPInterface* ReflowGlobalInterface::CreateAdditiveVelocityField( const Tab& pFields ) { try { return stoke::max3d::CreateAdditiveVelocityFieldMXS( &pFields ); } catch( ... ) { frantic::max3d::rethrow_current_exception_as_max_t(); } return NULL; } FPInterface* ReflowGlobalInterface::CreateParticleGenerator( INode* pPRTNode, float jitterRadius, bool ignoreIDs ) { try { return stoke::max3d::CreateKrakatoaGenerator( pPRTNode, jitterRadius, ignoreIDs ); } catch( ... ) { frantic::max3d::rethrow_current_exception_as_max_t(); } return NULL; } FPInterface* ReflowGlobalInterface::CreateGeometryGenerator( INode* pPRTNode, const MCHAR* szMode, float volumeSpacing, const MCHAR* szSelectionType, float vertexJitterRadius ) { try { geometry_generator::property_map props; geometry_generator::set_mode( props, geometry_generator::mode::from_string( szMode ) ); geometry_generator::set_volume_spacing( props, volumeSpacing ); geometry_generator::set_selection_type( props, geometry_generator::selection_type::from_string( szSelectionType ) ); geometry_generator::set_vertex_jitter_radius( props, vertexJitterRadius ); return stoke::max3d::CreateGeometryGenerator( pPRTNode, props ); } catch( ... ) { frantic::max3d::rethrow_current_exception_as_max_t(); } return NULL; } #if defined( FUMEFX_SDK_AVAILABLE ) FPInterface* ReflowGlobalInterface::CreateFumeFXGenerator( INode* pFumeNode ) { try { return stoke::max3d::CreateFumeFXGenerator( pFumeNode ); } catch( ... ) { frantic::max3d::rethrow_current_exception_as_max_t(); } return NULL; } #endif FPInterface* ReflowGlobalInterface::CreateParticleSet( const Tab& pExtraChannelDescriptors ) { try { return stoke::max3d::CreateParticleSet( &pExtraChannelDescriptors ); } catch( ... ) { frantic::max3d::rethrow_current_exception_as_max_t(); } return NULL; } void ReflowGlobalInterface::WriteParticleSet( FPInterface* pParticleSetObject, const MCHAR* szFilePath ) { try { stoke::max3d::WriteParticleSetMXS( pParticleSetObject, szFilePath ); } catch( ... ) { frantic::max3d::rethrow_current_exception_as_max_t(); } } void ReflowGlobalInterface::BeginRenderMode( const Tab& nodes, frantic::max3d::TimeWrapper t ) { try { std::set visitedRefs; for( int i = 0, iEnd = nodes.Count(); i < iEnd; ++i ) frantic::max3d::rendering::refmaker_call_recursive( nodes[i], visitedRefs, frantic::max3d::rendering::render_begin_function( t, 0 ) ); } catch( ... ) { frantic::max3d::rethrow_current_exception_as_max_t(); } } void ReflowGlobalInterface::EndRenderMode( const Tab& nodes, frantic::max3d::TimeWrapper t ) { try { std::set visitedRefs; for( int i = 0, iEnd = nodes.Count(); i < iEnd; ++i ) frantic::max3d::rendering::refmaker_call_recursive( nodes[i], visitedRefs, frantic::max3d::rendering::render_end_function( t ) ); } catch( ... ) { frantic::max3d::rethrow_current_exception_as_max_t(); } } void ReflowGlobalInterface::AdvectParticleSetMXS( FPInterface* pParticleSetInterface, FPInterface* pAdvectorInterface, FPInterface* pVelocityFieldInterface, float timeStepSeconds ) { try { stoke::max3d::AdvectParticleSetMXS( pParticleSetInterface, pAdvectorInterface, pVelocityFieldInterface, timeStepSeconds ); } catch( ... ) { frantic::max3d::rethrow_current_exception_as_max_t(); } } void ReflowGlobalInterface::UpdateAgeChannelMXS( FPInterface* pParticleSetInterface, float timeStepSeconds ) { try { stoke::max3d::UpdateAgeChannelMXS( pParticleSetInterface, timeStepSeconds ); } catch( ... ) { frantic::max3d::rethrow_current_exception_as_max_t(); } } void ReflowGlobalInterface::UpdateAdvectionOffsetChannelMXS( FPInterface* pParticleSetInterface, FPInterface* pAdvectorInterface, FPInterface* pVelocityFieldInterface, float timeStepSeconds ) { try { stoke::max3d::UpdateAdvectionOffsetChannelMXS( pParticleSetInterface, pAdvectorInterface, pVelocityFieldInterface, timeStepSeconds ); } catch( ... ) { frantic::max3d::rethrow_current_exception_as_max_t(); } } void ReflowGlobalInterface::ApplyAdvectionOffsetChannelMXS( FPInterface* pParticleSetInterface ) { try { stoke::max3d::ApplyAdvectionOffsetChannelMXS( pParticleSetInterface ); } catch( ... ) { frantic::max3d::rethrow_current_exception_as_max_t(); } } void ReflowGlobalInterface::MagmaEvaluateParticleSet( FPInterface* pParticleSet, ReferenceTarget* pMagmaHolder, frantic::max3d::fnpublish::TimeParameter t, FPInterface* pErrorReporter ) { try { stoke::max3d::MagmaEvaluateParticleSet( pParticleSet, pMagmaHolder, t, pErrorReporter ); } catch( ... ) { frantic::max3d::rethrow_current_exception_as_max_t(); } } ReflowGlobalInterface::SourceType::option ReflowGlobalInterface::GetSourceType( INode* pNode, frantic::max3d::TimeWrapper t ) { try { #if defined( FUMEFX_SDK_AVAILABLE ) if( stoke::max3d::IsFumeFXSource( pNode, t ) ) return SourceType::fumefx; #endif if( stoke::max3d::IsParticleSource( pNode, t ) ) return SourceType::particles; if( stoke::max3d::IsGeometrySource( pNode, t ) ) return SourceType::geometry; } catch( ... ) { frantic::max3d::rethrow_current_exception_as_max_t(); } return SourceType::invalid; } ReflowGlobalInterface::VelocityType::option ReflowGlobalInterface::GetVelocityType( INode* pNode, frantic::max3d::TimeWrapper t ) { try { #if defined( FUMEFX_SDK_AVAILABLE ) if( stoke::max3d::IsFumeFXSource( pNode, t ) ) return VelocityType::fumefx; #endif #if defined( PHOENIX_SDK_AVAILABLE ) if( frantic::max3d::volumetrics::is_phoenix_node( pNode, t ) ) return VelocityType::phoenix; #endif if( frantic::max3d::volumetrics::is_forcefield_node( pNode, t ) ) return VelocityType::spacewarp; if( stoke::max3d::IsParticleSource( pNode, t ) ) return VelocityType::particles; if( frantic::max3d::volumetrics::is_field( pNode, t ) ) return VelocityType::field; } catch( ... ) { frantic::max3d::rethrow_current_exception_as_max_t(); } return VelocityType::invalid; } void ReflowGlobalInterface::SetTempDirectory( const TCHAR* szTempDir ) { try { boost::filesystem::path newPath; if( szTempDir ) newPath = szTempDir; // frantic::particles::g_particleFileStreamFactoryObject.set_temp_directory( newPath ); } catch( ... ) { frantic::max3d::rethrow_current_exception_as_max_t(); } } namespace { int g_maxDebuggerIterations = 10000; } // This global function provides access to the value stored, without exposing it as a global variable. int GetMaximumDebuggerIterations() { return g_maxDebuggerIterations; } void ReflowGlobalInterface::SetMaxDebugIterations( int maxIterations ) { g_maxDebuggerIterations = std::max( maxIterations, 0 ); } int ReflowGlobalInterface::GetMaxDebugIterations() { return g_maxDebuggerIterations; } void ReflowGlobalInterface::SetMaxMarkerCount( int maxIterations ) { ember::max3d::SetMaxMarkerCount( static_cast( std::max( 1, maxIterations ) ) ); } int ReflowGlobalInterface::GetMaxMarkerCount() { return ember::max3d::GetMaxMarkerCount(); } ReflowGlobalInterface::ViewportType::option ReflowGlobalInterface::GetViewportType() { #if MAX_VERSION_MAJOR >= 17 MaxSDK::Graphics::IDisplayManager* pGraphicsManager = MaxSDK::Graphics::GetIDisplayManager(); if( !pGraphicsManager || !pGraphicsManager->IsRetainedModeEnabled() ) return ViewportType::legacy; return ViewportType::nitrous; #else return ViewportType::legacy; #endif } bool ReflowGlobalInterface::GetPointSizeSupported() { #if MAX_VERSION_MAJOR >= 17 MaxSDK::Graphics::IDisplayManager* pGraphicsManager = MaxSDK::Graphics::GetIDisplayManager(); if( !pGraphicsManager || !pGraphicsManager->IsRetainedModeEnabled() ) return false; // Only DX9 supports point size. MaxSDK::Graphics::DeviceCaps caps; if( pGraphicsManager->GetDeviceCaps( caps ) ) return caps.FeatureLevel < MaxSDK::Graphics::Level5_0; return false; #else return false; #endif } bool ReflowGlobalInterface::IsEmberField( INode* pNode, frantic::max3d::fnpublish::TimeWrapper t ) { if( !pNode ) return false; ObjectState os = pNode->EvalWorldState( t ); if( frantic::max3d::volumetrics::IEmberField* pField = frantic::max3d::volumetrics::GetEmberFieldInterface( os.obj ) ) return true; // This assumes that converting to the EmberPipeObject will succeed and produce a field. That is potentially // sketchy. if( os.obj && os.obj->CanConvertToType( EmberPipeObject_CLASSID ) ) return true; return false; } FPInterface* ReflowGlobalInterface::CreateMXSField( INode* pNode, int stackIndex, frantic::max3d::fnpublish::TimeWrapper t ) { return ember::max3d::CreateMXSField( pNode, t, stackIndex ); } #if defined( FUMEFX_SDK_AVAILABLE ) void ReflowGlobalInterface::WriteFXDFile( const MCHAR* szFilePath, INode* pNode, const Point3& minP, const Point3& maxP, float spacing, int stackIndex, frantic::max3d::fnpublish::TimeWrapper t ) { Interval valid = FOREVER; boost::shared_ptr pField; if( stackIndex <= 0 ) { pField = frantic::max3d::volumetrics::create_field( pNode, t, valid ); } else { int derivedIndex = 0; Modifier* pMod = NULL; IDerivedObject* pDerived = GetCOREInterface7()->FindModifier( *pNode, stackIndex, derivedIndex, pMod ); if( pDerived ) pField = frantic::max3d::volumetrics::create_field( pNode, pDerived->Eval( t, derivedIndex ), t, valid ); } if( !pField ) return; frantic::graphics::boundbox3f wsBounds( frantic::max3d::from_max_t( minP ), frantic::max3d::from_max_t( maxP ) ); static std::unique_ptr staticFactory; if( !staticFactory.get() ) { staticFactory = frantic::max3d::volumetrics::create_fumefx_iodll_factory(); } staticFactory->write_fxd_file( szFilePath, pField, wsBounds, wsBounds, spacing, NULL ); // frantic::max3d::volumetrics::get_fumefx_factory().write_fxd_file( szFilePath, pField, wsBounds, wsBounds, // spacing, NULL ); } #endif // Tab* IEmberGlobal::test() { // //static Tab theTab; // Tab* pResult = new Tab; // Tab& theTab = *pResult; // //if( theTab.Count() == 0 ){ // theTab.SetCount( 2 ); // theTab[0] = _T("Density float32[1]"); // theTab[1] = new MCHAR[50]; // // wcsncpy( const_cast(theTab[1]), _T("Velocity float32[3]"), 50 ); // //std::char_traits::copy( const_cast(theTab[1]), _T("Velocity float32[3]"), 50 ); // //} // // //return &theTab; // return pResult; // } // // Tab* IEmberGlobal::test2() const { // //static Tab theTab; // //if( theTab.Count() == 0 ){ // // theTab.SetCount( 2 ); // // theTab[0] = _T("Density float32[1]"); // // theTab[1] = new MCHAR[50]; // // // // wcsncpy( const_cast(theTab[1]), _T("Velocity float32[3]"), 50 ); // // //std::char_traits::copy( const_cast(theTab[1]), _T("Velocity float32[3]"), 50 ); // //} // // //return &theTab; // return this->test(); // } #if defined( FIELD3D_AVAILABLE ) void ReflowGlobalInterface::WriteField3DFile( const MCHAR* szFilePath, INode* pNode, const Point3& pmin, const Point3& pmax, float spacing, int stackIndex, frantic::max3d::fnpublish::TimeWrapper t ) { Interval valid = FOREVER; boost::shared_ptr pField; if( stackIndex <= 0 ) { pField = frantic::max3d::volumetrics::create_field( pNode, t, valid ); } else { int derivedIndex = 0; Modifier* pMod = NULL; IDerivedObject* pDerived = GetCOREInterface7()->FindModifier( *pNode, stackIndex, derivedIndex, pMod ); if( pDerived ) pField = frantic::max3d::volumetrics::create_field( pNode, pDerived->Eval( t, derivedIndex ), t, valid ); } if( !pField ) return; Field3D::V3i ijkMin( static_cast( std::ceil( pmin.x / spacing - 0.5f ) ), // x <= 0.5 -> 0, x > 0.5 -> 1 static_cast( std::ceil( pmin.y / spacing - 0.5f ) ), static_cast( std::ceil( pmin.z / spacing - 0.5f ) ) ); Field3D::V3i ijkMax( static_cast( std::floor( pmax.x / spacing + 0.5f ) ) - 1, // x < 0.5 -> -1, x >= 0.5 -> 0 static_cast( std::floor( pmax.y / spacing + 0.5f ) ) - 1, static_cast( std::floor( pmax.z / spacing + 0.5f ) ) - 1 ); std::vector fields; ember::sample_to_field3d( *pField, fields, Field3D::Box3i( ijkMin, ijkMax ), Field3D::Box3i( ijkMin, ijkMax ), spacing ); ember::write_fields_to_file( szFilePath, fields ); } #endif void ReflowGlobalInterface::WriteOpenVDBFile( const MCHAR* szFilePath, INode* pNode, const Point3& min, const Point3& max, float spacing, int stackIndex, frantic::max3d::fnpublish::TimeWrapper t ) { Interval valid = FOREVER; boost::shared_ptr pField; if( stackIndex <= 0 ) { pField = frantic::max3d::volumetrics::create_field( pNode, t, valid ); } else { int derivedIndex = 0; Modifier* pMod = NULL; IDerivedObject* pDerived = GetCOREInterface7()->FindModifier( *pNode, stackIndex, derivedIndex, pMod ); if( pDerived ) pField = frantic::max3d::volumetrics::create_field( pNode, pDerived->Eval( t, derivedIndex ), t, valid ); } if( !pField ) return; const frantic::graphics::boundbox3f bounds( frantic::max3d::from_max_t( min ), frantic::max3d::from_max_t( max ) ); ember::write_openvdb_file( szFilePath, pField, bounds, spacing ); } namespace { frantic::win32::invoke_queue g_guiInvokeQueue; void print_to_listener( const frantic::tstring& szPrefix, const frantic::tstring& szMessage ) { if( MAXScript_running ) mprintf( _M( "%s: %s\n" ), szPrefix.c_str(), szMessage.c_str() ); } class mprintf_functor_in_main_thread { frantic::tstring m_prefix; public: mprintf_functor_in_main_thread( const MCHAR* prefix ) : m_prefix( prefix ) {} void operator()( const MCHAR* p ) { if( g_guiInvokeQueue.is_owning_thread() ) { if( MAXScript_running ) mprintf( _M( "%s: %s\n" ), m_prefix.c_str(), p ); } else { g_guiInvokeQueue.invoke( &print_to_listener, m_prefix, p ); } } }; void OnSystemStartup( void* /*param*/, NotifyInfo* /*info*/ ) { g_guiInvokeQueue.initialize( hInstance ); // TODO: This makes sure that mprintf is called from the correct thread, but I still need to use synchronization (or // TLS) to prevent race conditions when // streaming into the FF_LOG(XXX) streams. frantic::logging::redirect_stream( frantic::logging::debug, frantic::logging::new_ffstreambuf( mprintf_functor_in_main_thread( _M( "DBG" ) ) ) ); frantic::logging::redirect_stream( frantic::logging::stats, frantic::logging::new_ffstreambuf( mprintf_functor_in_main_thread( _M( "STS" ) ) ) ); frantic::logging::redirect_stream( frantic::logging::progress, frantic::logging::new_ffstreambuf( mprintf_functor_in_main_thread( _M( "PRG" ) ) ) ); frantic::logging::redirect_stream( frantic::logging::warning, frantic::logging::new_ffstreambuf( mprintf_functor_in_main_thread( _M( "WRN" ) ) ) ); frantic::logging::redirect_stream( frantic::logging::error, frantic::logging::new_ffstreambuf( mprintf_functor_in_main_thread( _M( "ERR" ) ) ) ); // The default logging level after initialization is 'warning' frantic::logging::set_logging_level( frantic::logging::level::warning ); // Init the Field3D & OpenVDB libraries. openvdb::initialize(); #if defined( FIELD3D_AVAILABLE ) Field3D::initIO(); #endif } void OnScriptStartup( void* /*param*/, NotifyInfo* /*info*/ ) {} } // namespace void InitStoke() { RegisterNotification( &OnSystemStartup, NULL, NOTIFY_SYSTEM_STARTUP ); RegisterNotification( &OnScriptStartup, NULL, NOTIFY_MXS_STARTUP ); // We need to wait until MXS is ready before we init. // Temporarily set the logging level to none. frantic::logging::set_logging_level( frantic::logging::level::none ); } void InvokeInMainThread( const boost::function& fn ) { g_guiInvokeQueue.invoke( fn ); } } // namespace max3d } // namespace stoke frantic::win32::invoke_queue& GetMainThreadDispatcher() { return stoke::max3d::g_guiInvokeQueue; } stoke::max3d::ReflowGlobalInterface* GetStokeInterface() { return &stoke::max3d::theReflowGlobalInterface; }