TuttleOFX  1
HistogramKeyerOverlay.cpp
Go to the documentation of this file.
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 }