TuttleOFX
1
|
00001 #include "HistogramKeyerOverlay.hpp" 00002 #include "HistogramKeyerPlugin.hpp" 00003 #include "HistogramKeyerHistogramDisplay.hpp" 00004 00005 namespace tuttle { 00006 namespace plugin { 00007 namespace histogramKeyer { 00008 00009 HistogramKeyerOverlay::HistogramKeyerOverlay(OfxInteractHandle handle,OFX::ImageEffect* effect) 00010 : OFX::OverlayInteract(handle) 00011 , _plugin( static_cast<HistogramKeyerPlugin*>(_effect) ) 00012 , _infos( effect ) 00013 , _hslParam( _plugin ) 00014 , _rgbParam( _plugin ) 00015 { 00016 _penDown = false; //Mouse is not clicked down by default 00017 _keyDown = false; //Ctrl key is not pressed by default 00018 _plugin->addRefOverlayData(); //add reference to Overlay data 00019 _isFirstTime = true; //temporary 00020 getOverlayData()._isDataInvalid = true; 00021 } 00022 00023 HistogramKeyerOverlay::~HistogramKeyerOverlay() 00024 { 00025 _plugin->releaseOverlayData(); //release Overlay data 00026 } 00027 00028 bool HistogramKeyerOverlay::draw( const OFX::DrawArgs& args ) 00029 { 00030 const OfxPointI fullImgSize = _plugin->_clipSrc->getPixelRodSize(args.time); 00031 const OfxPointI imgSize = _plugin->_clipSrc->getPixelRodSize(args.time, args.renderScale); 00032 const OfxRectI pixelRegionOfDefinition = _plugin->_clipSrc->getPixelRod(args.time); 00033 00034 // Global display option 00035 if( _plugin->_paramGlobalDisplaySelection->getValue() == false ) 00036 return false; 00037 00038 if( _isFirstTime || 00039 getOverlayData()._isDataInvalid || 00040 getOverlayData().isCurrentTimeModified( args.time ) || 00041 getOverlayData().isImageSizeModified( imgSize ) ///< HACK changeClip method doesn't work in nuke when source clip is changed so we have to check size of imgBool all of the time 00042 ) 00043 { 00044 if( getOverlayData().isImageSizeModified( imgSize ) ) 00045 { 00046 getOverlayData().clearAll( imgSize ); 00047 } 00048 00049 if( ! _plugin->_isRendering ) 00050 { 00051 getOverlayData()._isDataInvalid = false; 00052 getOverlayData().computeFullData( _plugin->_clipSrc, args.time, args.renderScale ); 00053 } 00054 else //Data is not updated : draw warning signal 00055 { 00056 //initialize model-view and projection matrixes to identity 00057 glMatrixMode( GL_PROJECTION ); //load standard mode 00058 glLoadIdentity(); //projection to identity 00059 glMatrixMode( GL_MODELVIEW ); //load standard mode 00060 glLoadIdentity(); //model-view to identity 00061 00062 //get current viewport size 00063 GLint viewport[4] = { 0, 0, 0, 0 }; //define result array 00064 glGetIntegerv(GL_VIEWPORT,viewport); //get current viewport size 00065 const double ratio = (viewport[2]-viewport[0]) / (double)(viewport[3]-viewport[1]); //compute ratio 00066 //define new coordinates 00067 glOrtho( 0.0, 1.0, 0.0, 1.0, -1.0, 1.0 ); //set coordinates to 0-1 00068 00069 //display warning sign on screen 00070 Ofx3DPointD warningPoint; //initialize warning drawing point 00071 warningPoint.x = 0.15; //x == viewport width/7; 00072 warningPoint.y = 0.2; //y == viewport height/5; 00073 drawWarning(warningPoint, ratio); //draw warning sign 00074 } 00075 } 00076 00077 // Draw component 00078 bool displaySomething = false; 00079 if(_plugin->_clipSrc->isConnected()) 00080 { 00081 displaySomething = true; 00082 00083 if(_plugin->_paramDisplaySelection->getValue()) //DisplaySelection 00084 this->displaySelectedAreas( fullImgSize,imgSize,pixelRegionOfDefinition ); 00085 00086 ///@todo : remove next lines when Nuke curves overlay works 00087 glPushMatrix(); 00088 glTranslatef(-(fullImgSize.x+kTranslationRGB),0.0f,0.0f); 00089 00090 _rgbParam.draw(args); 00091 glPopMatrix(); 00092 00093 ///@todo : remove next lines when Nuke curves overlay works 00094 glPushMatrix(); 00095 glTranslatef((fullImgSize.x+kTranslationHSL),0.0f,0.0f); 00096 00097 _hslParam.draw(args); 00098 glPopMatrix(); 00099 00100 if( _penDown && !_keyDown ) // Display selection zone 00101 { 00102 this->displaySelectionZone(); 00103 } 00104 } 00105 00106 if( _isFirstTime ) 00107 { 00108 _isFirstTime = false; 00109 } 00110 return displaySomething; 00111 } 00112 00113 /** 00114 * When the pen/mouse is under motion 00115 * @param args current arg 00116 * @return event capted (y or n) 00117 */ 00118 bool HistogramKeyerOverlay::penMotion( const OFX::PenArgs& args ) 00119 { 00120 if( _penDown && !_keyDown ) //the mouse is moving but there is not Ctrl key pressed 00121 { 00122 _squareEnd.x = args.penPosition.x; //needed to draw the selection square 00123 _squareEnd.y = args.penPosition.y; //needed to draw the selection square 00124 return true; //event captured 00125 } 00126 if( _penDown && _keyDown )//the mouse is moving and there is Ctrl key pressed 00127 { 00128 const OfxRectI pixelRegionOfDefinition = _plugin->_clipSrc->getPixelRod(args.time,args.renderScale); //pixel region of definition 00129 int y = args.penPosition.y * args.renderScale.y; 00130 int x = args.penPosition.x * args.renderScale.x; 00131 00132 if( y > static_cast<int>(getOverlayData()._imgBool.shape()[0]) || 00133 y < 0 || 00134 x > static_cast<int>(getOverlayData()._imgBool.shape()[1]) || 00135 x < 0 ) 00136 { 00137 return false; 00138 } 00139 y -= pixelRegionOfDefinition.y1; //repere change (reformat) 00140 x -= pixelRegionOfDefinition.x1; //repere change (reformat) 00141 00142 if( _plugin->_paramSelectionMode->getValue() == 2 ) //selection mode is subtractive mode 00143 getOverlayData()._imgBool[y][x] = 0; //current pixel is no more marked as selected 00144 else 00145 getOverlayData()._imgBool[y][x] = 255; //current pixel is marked as selected 00146 return true; //event captured 00147 } 00148 return false; //event is not captured 00149 } 00150 00151 /** 00152 * When the pen/mouse is clicking down 00153 * @param args current arg 00154 * @return event capted (y or n) 00155 */ 00156 bool HistogramKeyerOverlay::penDown( const OFX::PenArgs& args ) 00157 { 00158 const OfxPointI fullsize = _plugin->_clipSrc->getPixelRodSize(args.time); //full size 00159 const OfxPointI imgSize = _plugin->_clipSrc->getPixelRodSize(args.time, args.renderScale); //size with renderscale 00160 00161 if(!_penDown && !_keyDown && _plugin->_paramDisplaySelection->getValue()) //mouse is already used and there is not Ctrl key pressed 00162 { 00163 _penDown = true; 00164 if( args.penPosition.y < fullsize.y && args.penPosition.y > 0 ) //mouse Y is into the image 00165 _origin.y = args.penPosition.y*args.renderScale.y; 00166 else 00167 { 00168 if(args.penPosition.y > fullsize.y) //clamp the selected Y pixel to the image borders 00169 _origin.y = imgSize.y; //click is on the top of the image 00170 else 00171 _origin.y = 0; //click is on the bottom of the image 00172 } 00173 if( args.penPosition.x < fullsize.x && args.penPosition.x > 0 ) //mouse X is on the image 00174 _origin.x = args.penPosition.x*args.renderScale.x; 00175 else 00176 { 00177 if( args.penPosition.x > fullsize.x ) //clamp the selected X pixel to the image borders 00178 _origin.x = imgSize.x; //click is on the right of the image 00179 else 00180 _origin.x = 0; //click is on the left of the image 00181 } 00182 _end.x = args.penPosition.x*args.renderScale.x; //set X end of the selection square at the origin (initialization) 00183 _end.y = args.penPosition.y*args.renderScale.y; //set Y end of the selection square at the origin (initialization) 00184 00185 _squareBegin.x = _squareEnd.x = args.penPosition.x; //copy x value to square position 00186 _squareBegin.y = _squareEnd.y = args.penPosition.y; //copy v value to square position 00187 } 00188 else //there is Ctrl key pressed 00189 { 00190 if( !_penDown && _plugin->_paramDisplaySelection->getValue()) 00191 _penDown = true; 00192 } 00193 if( _plugin->_paramSelectionMode->getValue() == 1 ) //Selection mode is unique 00194 { 00195 getOverlayData().clearSelection(); //reset past selection 00196 } 00197 return true; 00198 } 00199 00200 /** 00201 * When the pen/mouse is clicking up 00202 * @param args current arg 00203 * @return event capted (y or n) 00204 */ 00205 bool HistogramKeyerOverlay::penUp( const OFX::PenArgs& args ) 00206 { 00207 const OfxPointI fullSize = _plugin->_clipSrc->getPixelRodSize(args.time); //full image size 00208 const OfxPointI imgSize = _plugin->_clipSrc->getPixelRodSize(args.time, args.renderScale); //size with renderscale 00209 const OfxRectI pixelRegionOfDefinition = _plugin->_clipSrc->getPixelRod(args.time,args.renderScale); //pixel region of definition 00210 00211 //clamp selection 00212 _end.x = args.penPosition.x * args.renderScale.x; //attach the end of the selection square to the current pixel X 00213 _end.y = args.penPosition.y * args.renderScale.y; //attach the end of the selection square to the current pixel Y 00214 if( _end.x == _origin.x && _end.y == _origin.y ) //it's just one click! 00215 { 00216 _penDown = false; //change penDown 00217 return false; //event is not capured 00218 } 00219 00220 if( !(args.penPosition.x < fullSize.x && 00221 args.penPosition.x > 0 && 00222 args.penPosition.y < fullSize.y && 00223 args.penPosition.y > 0) ) // if click is not on the image 00224 { 00225 if( args.penPosition.x < 0.0 || args.penPosition.x > fullSize.x ) //problem with X axis 00226 { 00227 if(args.penPosition.x < 0.0) //click is on the left of the image 00228 _end.x = 0.0; //clamp 00229 else 00230 _end.x = imgSize.x; //click is on the right of the image 00231 } 00232 if( args.penPosition.y < 0.0 || args.penPosition.y > fullSize.y ) //problem with Y axis 00233 { 00234 if(args.penPosition.y < 0.0) //click is on the bottom of the image 00235 _end.y = 0.0; //clamp 00236 else 00237 _end.y = imgSize.y; //click is on the top of the image 00238 } 00239 } 00240 00241 if( _penDown && !_keyDown ) //if there is not Ctrl key pressed 00242 { 00243 int startX, endX, startY, endY; 00244 if( _origin.x > _end.x ) //transform selection zone to be OK (X axis) 00245 { 00246 startX = _origin.x; 00247 endX = _end.x; 00248 } 00249 else 00250 { 00251 endX = _origin.x; 00252 startX = _end.x; 00253 } 00254 00255 if( _origin.y > _end.y ) //transform selection zone to be OK (Y axis) 00256 { 00257 startY = _origin.y; 00258 endY = _end.y; 00259 } 00260 else 00261 { 00262 endY = _origin.y; 00263 startY = _end.y; 00264 } 00265 const int step_x = startX - endX; //determinate width of the selected zone 00266 const int step_y = startY - endY; //determinate height of the selected zone 00267 00268 BOOST_ASSERT( endY >= 0 ); 00269 BOOST_ASSERT( endX >= 0 ); 00270 BOOST_ASSERT( getOverlayData()._imgBool.shape()[0] >= std::size_t(endY + step_y) ); 00271 BOOST_ASSERT( getOverlayData()._imgBool.shape()[1] >= std::size_t(endX + step_x) ); 00272 00273 unsigned char fillValue; 00274 if( _plugin->_paramSelectionMode->getValue() == 2 ) //selection mode is subtractive 00275 fillValue = 0; //remove all of the selected pixel 00276 else 00277 fillValue = 255; //mark all of the selected pixel 00278 00279 for( int val_y = 0; val_y < step_y; ++val_y ) 00280 { 00281 for( int val_x = 0; val_x < step_x; ++val_x ) 00282 { 00283 const int y = endY + val_y - pixelRegionOfDefinition.y1; // y in img bool size (reformat) 00284 const int x = endX + val_x - pixelRegionOfDefinition.x1; // x in img bool size (reformat) 00285 00286 getOverlayData()._imgBool[y][x] = fillValue; 00287 } 00288 } 00289 // recompute full data 00290 //getOverlayData().computeFullData(_plugin->_clipSrc,args.time,args.renderScale); 00291 getOverlayData()._isDataInvalid = true; 00292 _plugin->redrawOverlays(); 00293 } 00294 _penDown = false; // treatment is finished 00295 return true; 00296 } 00297 00298 /** 00299 * Ctrl key is pressed down 00300 * @param args current arg 00301 * @return event capted (y or n) 00302 */ 00303 bool HistogramKeyerOverlay::keyDown( const OFX::KeyArgs& args ) 00304 { 00305 if( args.keySymbol == kOfxKey_Control_L || 00306 args.keySymbol == kOfxKey_Control_R ) //if the pressed key is Ctrl key (left or right) 00307 { 00308 _keyDown = true; //treatment begins 00309 return true; //event captured 00310 } 00311 return false; //event is not captured (other key) 00312 } 00313 00314 /** 00315 * Ctrl key is released 00316 * @param args current arg 00317 * @return event capted (y or n) 00318 */ 00319 bool HistogramKeyerOverlay::keyUp( const OFX::KeyArgs& args ) 00320 { 00321 if( ( args.keySymbol == kOfxKey_Control_L || args.keySymbol == kOfxKey_Control_R ) && 00322 _keyDown ) // if the release key is Ctrl (and it has been pressed before) 00323 { 00324 _keyDown = false; // treatment ends 00325 _penDown = false; // pen down 00326 00327 // getOverlayData().computeFullData( _plugin->_clipSrc, args.time, args.renderScale ); 00328 getOverlayData()._isDataInvalid = true; 00329 _plugin->redrawOverlays(); 00330 00331 return true; // event captured 00332 } 00333 return false; // event is not captured (wrong key) 00334 } 00335 00336 /** 00337 * Display the selected areas on the clip (color : gray) 00338 */ 00339 void HistogramKeyerOverlay::displaySelectedAreas( const OfxPointI& fullImgSize, const OfxPointI& imgSize, const OfxRectI& pixelRoD ) 00340 { 00341 glEnable(GL_TEXTURE_2D); //Activate texturing 00342 GLuint Name; //Texture name 00343 glGenTextures(1,&Name); //generate a texture number 00344 glBindTexture(GL_TEXTURE_2D,Name); 00345 BOOST_ASSERT( getOverlayData()._imgBool.shape()[0] == std::size_t(imgSize.y) ); 00346 BOOST_ASSERT( getOverlayData()._imgBool.shape()[1] == std::size_t(imgSize.x) ); 00347 glTexImage2D( 00348 GL_TEXTURE_2D, //Type : texture 2D 00349 0, //Mipmap : none 00350 GL_ALPHA8, //Colors : 4 00351 imgSize.x, //width 00352 imgSize.y, //height 00353 0, //border size 00354 GL_ALPHA, //Format : RGBA 00355 GL_UNSIGNED_BYTE, //color kind 00356 getOverlayData()._imgBool.data() // data buffer 00357 ); 00358 glColor4f(1.0f,1.0f,1.0f,0.5f); 00359 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 00360 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 00361 //Draw Texture on screen 00362 glBegin(GL_QUADS); 00363 glTexCoord2d(0,1); glVertex2i(pixelRoD.x1,pixelRoD.y2); //glVertex2d(0,fullImgSize.y); //Top Left 00364 glTexCoord2d(1,1); glVertex2i(pixelRoD.x2,pixelRoD.y2); //glVertex2d(fullImgSize.x,fullImgSize.y); //Top Right 00365 glTexCoord2d(1,0); glVertex2i(pixelRoD.x2,pixelRoD.y1); //glVertex2d(fullImgSize.x,0); //Bottom Right 00366 glTexCoord2d(0,0); glVertex2i(pixelRoD.x1,pixelRoD.y1); //glVertex2d(0,0); //Bottom Left 00367 glEnd(); 00368 glDisable(GL_TEXTURE_2D); 00369 glColor3f(1.0f,0.0f,0.0f); 00370 } 00371 00372 /** 00373 *Display the selection zone on the clip (color : border gray) 00374 */ 00375 void HistogramKeyerOverlay::displaySelectionZone() 00376 { 00377 glEnable(GL_BLEND); 00378 glBlendFunc (GL_ONE, GL_ONE); 00379 glEnable(GL_LINE_STIPPLE); 00380 glLineStipple(1, (short) 0x0101); //to draw ------- 00381 glBegin( GL_LINE_LOOP ); 00382 glColor3f(.6f,0.6f,0.6f); //white 00383 glVertex2f(_squareBegin.x,_squareBegin.y); //draw selection square 00384 glVertex2f(_squareBegin.x,_squareEnd.y); 00385 glVertex2f(_squareEnd.x,_squareEnd.y); 00386 glVertex2f(_squareEnd.x,_squareBegin.y); 00387 glEnd(); 00388 glDisable(GL_LINE_STIPPLE); 00389 glDisable(GL_BLEND); 00390 glEnd(); 00391 } 00392 00393 00394 /* 00395 * Draw a warning sign on the openGL scene 00396 */ 00397 void HistogramKeyerOverlay::drawWarning(const Ofx3DPointD& centerPoint, const double ratio) 00398 { 00399 float size = 5.0f; //define size 00400 glColor3f(1.0f,.7f,0); //color orange 00401 glLineWidth(size); //change line width (bigger) 00402 //draw triangle 00403 glBegin(GL_LINE_STRIP); //draw exterior triangle 00404 glVertex2d((centerPoint.x - 0.025*ratio),centerPoint.y); //first point of triangle 00405 glVertex2d((centerPoint.x + 0.025*ratio),centerPoint.y); //second point of triangle 00406 glVertex2d(centerPoint.x,(centerPoint.y+0.085*ratio)); //third point of triangle 00407 glVertex2d((centerPoint.x - 0.025*ratio),centerPoint.y); //first point of triangle (boucle) 00408 glEnd(); //end of drawing 00409 //draw ! 00410 glBegin(GL_LINES); //draw ! sign 00411 glVertex2d(centerPoint.x, (centerPoint.y+0.07*ratio)); //first point 00412 glVertex2d(centerPoint.x, (centerPoint.y+0.03*ratio)); //second point 00413 glEnd(); //end of drawing 00414 glBegin(GL_POINTS); //draw ! point 00415 glPointSize(size); //change point size (bigger) 00416 glVertex2d(centerPoint.x, (centerPoint.y + 0.02*ratio)); //point of ! 00417 glEnd(); //end of drawing 00418 //reset basic parameters 00419 glLineWidth(1.0f); //reset line width (normal) 00420 glPointSize(1.0f); //reset point size (normal) 00421 } 00422 00423 00424 /** 00425 * Get overlay data from plugin 00426 * @return 00427 */ 00428 OverlayData& HistogramKeyerOverlay::getOverlayData() 00429 { 00430 return _plugin->getOverlayData(); 00431 } 00432 00433 } 00434 } 00435 }