TuttleOFX
1
|
00001 #include "CTLAlgorithm.hpp" 00002 #include "CTLProcess.hpp" 00003 #include "CTLPlugin.hpp" 00004 00005 #include <half.h> 00006 #include <Iex.h> 00007 #include <CtlMessage.h> 00008 00009 00010 namespace tuttle { 00011 namespace plugin { 00012 namespace ctl { 00013 00014 /** 00015 * @brief HACK: workaround CTL limitation to load a module which source code 00016 * comes from a string and not a file. 00017 */ 00018 void loadModule( Ctl::Interpreter& interpreter, const std::string &moduleName, const std::string& code ); 00019 void loadModuleRecursive( Ctl::Interpreter& interpreter,const std::string &moduleName, const std::string& code ); 00020 00021 namespace { 00022 00023 CTLPlugin* ctlPlugin; 00024 00025 void ctlMessageOutput( const std::string& message ) 00026 { 00027 if( ctlPlugin ) 00028 { 00029 ctlPlugin->sendMessage( OFX::Message::eMessageMessage, "CTL message", message ); 00030 } 00031 } 00032 00033 template<class Type> 00034 void fillInputArg( Ctl::FunctionArgPtr& arg, const std::string& argStr, const Type& v, const std::size_t n ) 00035 { 00036 if( !arg || 00037 // !arg->type().cast<half>() || 00038 !arg->isVarying( ) ) 00039 { 00040 // The CTL function has no argument argStr, the argument 00041 // is not of type half, or the argument is not varying 00042 BOOST_THROW_EXCEPTION( Iex::ArgExc( std::string("Cannot set value of argument ")+argStr ) ); 00043 } 00044 00045 memcpy( arg->data(), &v, n*sizeof(Type) ); 00046 } 00047 00048 template<class Type> 00049 void retrieveOutputArg( const Ctl::FunctionArgPtr& arg, const std::string& argStr, Type& v, const std::size_t n ) 00050 { 00051 if( !arg || 00052 // !arg->type( ).cast<half>() || 00053 !arg->isVarying( ) ) 00054 { 00055 // The CTL function has no argument argStr, the argument 00056 // is not of type half, or the argument is not varying 00057 BOOST_THROW_EXCEPTION( Iex::ArgExc( std::string("Cannot set value of argument ")+argStr ) ); 00058 } 00059 00060 memcpy( &v, arg->data(), n*sizeof(Type) ); 00061 } 00062 00063 template<class Type> 00064 void callCtlChunk( 00065 Ctl::FunctionCallPtr call, 00066 const std::size_t n, 00067 Type& rOut, 00068 Type& gOut, 00069 Type& bOut, 00070 Type& aOut, 00071 const Type& r, 00072 const Type& g, 00073 const Type& b, 00074 const Type& a ) 00075 { 00076 // First set the input arguments for the function call: 00077 Ctl::FunctionArgPtr rArg = call->findInputArg( "rIn" ); 00078 fillInputArg( rArg, "rIn", r, n ); 00079 Ctl::FunctionArgPtr gArg = call->findInputArg( "gIn" ); 00080 fillInputArg( gArg, "gIn", g, n ); 00081 Ctl::FunctionArgPtr bArg = call->findInputArg( "bIn" ); 00082 fillInputArg( bArg, "bIn", b, n ); 00083 Ctl::FunctionArgPtr aArg = call->findInputArg( "aIn" ); 00084 fillInputArg( aArg, "aIn", a, n ); 00085 00086 // Now we can call the CTL function for 00087 // pixels 0, through n-1 00088 call->callFunction( n ); 00089 00090 // Retrieve the results 00091 Ctl::FunctionArgPtr rOutArg = call->findOutputArg( "rOut" ); 00092 retrieveOutputArg( rOutArg, "rOut", rOut, n ); 00093 Ctl::FunctionArgPtr gOutArg = call->findOutputArg( "gOut" ); 00094 retrieveOutputArg( gOutArg, "gOut", gOut, n ); 00095 Ctl::FunctionArgPtr bOutArg = call->findOutputArg( "bOut" ); 00096 retrieveOutputArg( bOutArg, "bOut", bOut, n ); 00097 Ctl::FunctionArgPtr aOutArg = call->findOutputArg( "aOut" ); 00098 retrieveOutputArg( aOutArg, "aOut", aOut, n ); 00099 } 00100 00101 template<class Type> 00102 void callCtl( 00103 Ctl::Interpreter &interp, 00104 Ctl::FunctionCallPtr call, 00105 const std::size_t size, 00106 Type* rOut, 00107 Type* gOut, 00108 Type* bOut, 00109 Type* aOut, 00110 const Type* r, 00111 const Type* g, 00112 const Type* b, 00113 const Type* a ) 00114 { 00115 std::size_t n = size; 00116 while( n > 0 ) 00117 { 00118 const std::size_t m = std::min( n, interp.maxSamples() ); 00119 callCtlChunk( call, m, *rOut, *gOut, *bOut, *aOut, *r, *g, *b, *a ); 00120 00121 n -= m; 00122 rOut += m; 00123 gOut += m; 00124 bOut += m; 00125 aOut += m; 00126 r += m; 00127 g += m; 00128 b += m; 00129 a += m; 00130 } 00131 } 00132 00133 } 00134 00135 template<class View> 00136 CTLProcess<View>::CTLProcess( CTLPlugin &effect ) 00137 : ImageGilFilterProcessor<View>( effect, eImageOrientationIndependant ) 00138 , _plugin( effect ) 00139 { 00140 ctlPlugin = &_plugin; 00141 } 00142 00143 template<class View> 00144 void CTLProcess<View>::setup( const OFX::RenderArguments& args ) 00145 { 00146 ctlPlugin = &_plugin; 00147 ImageGilFilterProcessor<View>::setup( args ); 00148 _params = _plugin.getProcessParams( args.renderScale ); 00149 00150 switch( _params._inputType ) 00151 { 00152 case eParamChooseInputCode: 00153 { 00154 TUTTLE_TLOG( TUTTLE_INFO, "CTL -- Load code: " << _params._code ); 00155 loadModule( _interpreter, _params._module, _params._code ); 00156 } 00157 case eParamChooseInputFile: 00158 { 00159 _interpreter.setModulePaths( _params._paths ); 00160 TUTTLE_TLOG( TUTTLE_INFO, "CTL -- Load module: " << _params._module ); 00161 _interpreter.loadModule( _params._module ); 00162 } 00163 } 00164 Ctl::setMessageOutputFunction( ctlMessageOutput ); 00165 } 00166 00167 /** 00168 * @brief Function called by rendering thread each time a process must be done. 00169 * @param[in] procWindowRoW Processing window 00170 */ 00171 template<class View> 00172 void CTLProcess<View>::multiThreadProcessImages( const OfxRectI& procWindowRoW ) 00173 { 00174 using namespace boost::gil; 00175 00176 Ctl::FunctionCallPtr call = _interpreter.newFunctionCall( "main" ); 00177 00178 const OfxPointI procWindowSize = { 00179 procWindowRoW.x2 - procWindowRoW.x1, 00180 procWindowRoW.y2 - procWindowRoW.y1 }; 00181 00182 const std::size_t alignment = 2; 00183 rgba32f_planar_image_t srcWorkLine( procWindowSize.x, 1, alignment ); 00184 rgba32f_planar_view_t srcWorkLineV = view( srcWorkLine ); 00185 rgba32f_planar_image_t dstWorkLine( procWindowSize.x, 1, alignment ); 00186 rgba32f_planar_view_t dstWorkLineV = view( dstWorkLine ); 00187 00188 for( int y = procWindowRoW.y1; 00189 y < procWindowRoW.y2; 00190 ++y ) 00191 { 00192 View srcLineV = subimage_view( this->_srcView, procWindowRoW.x1, y, procWindowSize.x, 1 ); 00193 View dstLineV = subimage_view( this->_dstView, procWindowRoW.x1, y, procWindowSize.x, 1 ); 00194 00195 copy_pixels( srcLineV, srcWorkLineV ); 00196 00197 float* rOut = reinterpret_cast<float*>( &dstWorkLineV(0,0)[0] ); 00198 float* gOut = reinterpret_cast<float*>( &dstWorkLineV(0,0)[1] ); 00199 float* bOut = reinterpret_cast<float*>( &dstWorkLineV(0,0)[2] ); 00200 float* aOut = reinterpret_cast<float*>( &dstWorkLineV(0,0)[3] ); 00201 const float* r = reinterpret_cast<float*>( &srcWorkLineV(0,0)[0] ); 00202 const float* g = reinterpret_cast<float*>( &srcWorkLineV(0,0)[1] ); 00203 const float* b = reinterpret_cast<float*>( &srcWorkLineV(0,0)[2] ); 00204 const float* a = reinterpret_cast<float*>( &srcWorkLineV(0,0)[3] ); 00205 00206 callCtl<float>( 00207 _interpreter, 00208 call, 00209 procWindowSize.x, 00210 rOut, 00211 gOut, 00212 bOut, 00213 aOut, 00214 r, 00215 g, 00216 b, 00217 a 00218 ); 00219 00220 copy_pixels( dstWorkLineV, dstLineV ); 00221 00222 if( this->progressForward( procWindowSize.x ) ) 00223 return; 00224 } 00225 } 00226 00227 } 00228 } 00229 }