// The offset of the current project in canonical coordinates. // The offset is related to the kOfxImageEffectPropProjectSize and is the offset from the origin // of the project 'subwindow'. For example for a PAL SD project that is in letterbox form, the // project offset is the offset to the bottom left hand corner of the letter box. The project // offset is in canonical coordinates. void OfxImageEffectInstance::getProjectOffset(double & xOffset, double & yOffset) const { Format f; _ofxEffectInstance->getRenderFormat(&f); RectI pixelF; pixelF.x1 = f.x1; pixelF.x2 = f.x2; pixelF.y1 = f.y1; pixelF.y2 = f.y2; RectD canonicalF; pixelF.toCanonical_noClipping(0, f.getPixelAspectRatio(), &canonicalF); xOffset = canonicalF.left(); yOffset = canonicalF.bottom(); }
// 0___1___2___3 // | /| /| /| // | / | / | / | // |/ |/ |/ | // 4---5---6----7 // | /| /| /| // | / | / | / | // |/ |/ |/ | // 8---9--10--11 // | /| /| /| // | / | / | / | // |/ |/ |/ | // 12--13--14--15 void ViewerGL::Implementation::drawRenderingVAO(unsigned int mipMapLevel, int textureIndex, ViewerGL::DrawPolygonModeEnum polygonMode, bool background) { // always running in the main thread assert( qApp && qApp->thread() == QThread::currentThread() ); assert( QGLContext::currentContext() == _this->context() ); bool useShader = _this->getBitDepth() != eImageBitDepthByte; ///the texture rectangle in image coordinates. The values in it are multiples of tile size. /// const TextureRect &roiRounded = this->displayTextures[textureIndex].texture->getTextureRect(); const TextureRect& roiNotRounded = this->displayTextures[textureIndex].roiNotRoundedToTileSize; ///This is the coordinates in the image being rendered where datas are valid, this is in pixel coordinates ///at the time we initialize it but we will convert it later to canonical coordinates. See 1) const double par = roiRounded.par; RectD canonicalRoIRoundedToTileSize; roiRounded.toCanonical_noClipping(mipMapLevel, par /*, rod*/, &canonicalRoIRoundedToTileSize); RectD canonicalRoINotRounded; roiNotRounded.toCanonical_noClipping(mipMapLevel, par, &canonicalRoINotRounded); ///the RoD of the image in canonical coords. RectD rod = _this->getRoD(textureIndex); bool clipToDisplayWindow; { QMutexLocker l(&this->clipToDisplayWindowMutex); clipToDisplayWindow = this->clipToDisplayWindow; } RectD rectClippedToRoI(canonicalRoIRoundedToTileSize); rectClippedToRoI.intersect(rod, &rectClippedToRoI); if (clipToDisplayWindow) { RectD canonicalProjectFormat; this->getProjectFormatCanonical(canonicalProjectFormat); rod.intersect(canonicalProjectFormat, &rod); rectClippedToRoI.intersect(canonicalProjectFormat, &rectClippedToRoI); } //if user RoI is enabled, clip the rod to that roi bool userRoiEnabled; { QMutexLocker l(&this->userRoIMutex); userRoiEnabled = this->userRoIEnabled; } ////The texture real size (r.w,r.h) might be slightly bigger than the actual ////pixel coordinates bounds r.x1,r.x2 r.y1 r.y2 because we clipped these bounds against the bounds ////in the ViewerInstance::renderViewer function. That means we need to draw actually only the part of ////the texture that contains the bounds. ////Notice that r.w and r.h are scaled to the closest Po2 of the current scaling factor, so we need to scale it up ////So it is in the same coordinates as the bounds. ///Edit: we no longer divide by the closestPo2 since the viewer now computes images at lower resolution by itself, the drawing ///doesn't need to be scaled. if (userRoiEnabled) { { QMutexLocker l(&this->userRoIMutex); //if the userRoI isn't intersecting the rod, just don't render anything if ( !rod.intersect(this->userRoI, &rod) ) { return; } } rectClippedToRoI.intersect(rod, &rectClippedToRoI); //clipTexCoords<RectD>(canonicalTexRect,rectClippedToRoI,texBottom,texTop,texLeft,texRight); } if (polygonMode != eDrawPolygonModeWhole) { /// draw only the plane defined by the wipe handle QPolygonF polygonPoints, polygonTexCoords; RectD floatRectClippedToRoI; floatRectClippedToRoI.x1 = rectClippedToRoI.x1; floatRectClippedToRoI.y1 = rectClippedToRoI.y1; floatRectClippedToRoI.x2 = rectClippedToRoI.x2; floatRectClippedToRoI.y2 = rectClippedToRoI.y2; Implementation::WipePolygonEnum polyType = this->getWipePolygon(floatRectClippedToRoI, polygonMode == eDrawPolygonModeWipeRight, &polygonPoints); if (polyType == Implementation::eWipePolygonEmpty) { ///don't draw anything return; } else if (polyType == Implementation::eWipePolygonPartial) { this->getPolygonTextureCoordinates(polygonPoints, canonicalRoIRoundedToTileSize, polygonTexCoords); this->bindTextureAndActivateShader(textureIndex, useShader); GL_GPU::glBegin(GL_POLYGON); for (int i = 0; i < polygonTexCoords.size(); ++i) { const QPointF & tCoord = polygonTexCoords[i]; const QPointF & vCoord = polygonPoints[i]; GL_GPU::glTexCoord2d( tCoord.x(), tCoord.y() ); GL_GPU::glVertex2d( vCoord.x(), vCoord.y() ); } GL_GPU::glEnd(); this->unbindTextureAndReleaseShader(useShader); } else { ///draw the all polygon as usual polygonMode = eDrawPolygonModeWhole; } } if (polygonMode == eDrawPolygonModeWhole) { const double pixelCenterOffset = 0.5; // draw vertices at the center of the first and last pixel in the texture, with the same texture coordinates rectClippedToRoI.x1 += pixelCenterOffset * par; rectClippedToRoI.x2 -= pixelCenterOffset * par; rectClippedToRoI.y1 += pixelCenterOffset; rectClippedToRoI.y2 -= pixelCenterOffset; ///Vertices are in canonical coords GLfloat vertices[32] = { (GLfloat)rod.left(), (GLfloat)rod.top(), //0 (GLfloat)rectClippedToRoI.x1 + pixelCenterOffset, (GLfloat)rod.top(), //1 (GLfloat)rectClippedToRoI.x2 - pixelCenterOffset, (GLfloat)rod.top(), //2 (GLfloat)rod.right(), (GLfloat)rod.top(), //3 (GLfloat)rod.left(), (GLfloat)rectClippedToRoI.y2 - pixelCenterOffset, //4 (GLfloat)rectClippedToRoI.x1, (GLfloat)rectClippedToRoI.y2, //5 (GLfloat)rectClippedToRoI.x2, (GLfloat)rectClippedToRoI.y2, //6 (GLfloat)rod.right(), (GLfloat)rectClippedToRoI.y2, //7 (GLfloat)rod.left(), (GLfloat)rectClippedToRoI.y1, //8 (GLfloat)rectClippedToRoI.x1, (GLfloat)rectClippedToRoI.y1, //9 (GLfloat)rectClippedToRoI.x2, (GLfloat)rectClippedToRoI.y1, //10 (GLfloat)rod.right(), (GLfloat)rectClippedToRoI.y1, //11 (GLfloat)rod.left(), (GLfloat)rod.bottom(), //12 (GLfloat)rectClippedToRoI.x1, (GLfloat)rod.bottom(), //13 (GLfloat)rectClippedToRoI.x2, (GLfloat)rod.bottom(), //14 (GLfloat)rod.right(), (GLfloat)rod.bottom() //15 }; // GLfloat texBottom = 0; // GLfloat texTop = (GLfloat)(r.y2 - r.y1) / (GLfloat)(r.h /** r.closestPo2*/); // GLfloat texLeft = 0; // GLfloat texRight = (GLfloat)(r.x2 - r.x1) / (GLfloat)(r.w /** r.closestPo2*/); GLfloat texBottom = (GLfloat)(rectClippedToRoI.y1 - canonicalRoIRoundedToTileSize.y1) / canonicalRoIRoundedToTileSize.height(); GLfloat texTop = (GLfloat)(rectClippedToRoI.y2 - canonicalRoIRoundedToTileSize.y1) / canonicalRoIRoundedToTileSize.height(); GLfloat texLeft = (GLfloat)(rectClippedToRoI.x1 - canonicalRoIRoundedToTileSize.x1) / canonicalRoIRoundedToTileSize.width(); GLfloat texRight = (GLfloat)(rectClippedToRoI.x2 - canonicalRoIRoundedToTileSize.x1) / canonicalRoIRoundedToTileSize.width(); GLfloat renderingTextureCoordinates[32] = { texLeft, texTop, //0 texLeft, texTop, //1 texRight, texTop, //2 texRight, texTop, //3 texLeft, texTop, //4 texLeft, texTop, //5 texRight, texTop, //6 texRight, texTop, //7 texLeft, texBottom, //8 texLeft, texBottom, //9 texRight, texBottom, //10 texRight, texBottom, //11 texLeft, texBottom, // 12 texLeft, texBottom, //13 texRight, texBottom, //14 texRight, texBottom //15 }; if ( background && this->viewerTab->isCheckerboardEnabled() && (polygonMode != eDrawPolygonModeWipeRight) ) { bool isblend = GL_GPU::glIsEnabled(GL_BLEND); if (isblend) { GL_GPU::glDisable(GL_BLEND); } this->drawCheckerboardTexture(rod); if (isblend) { GL_GPU::glEnable(GL_BLEND); } } this->bindTextureAndActivateShader(textureIndex, useShader); glCheckError(GL_GPU); GL_GPU::glBindBuffer(GL_ARRAY_BUFFER, this->vboVerticesId); GL_GPU::glBufferSubData(GL_ARRAY_BUFFER, 0, 32 * sizeof(GLfloat), vertices); GL_GPU::glEnableClientState(GL_VERTEX_ARRAY); GL_GPU::glVertexPointer(2, GL_FLOAT, 0, 0); GL_GPU::glBindBuffer(GL_ARRAY_BUFFER, this->vboTexturesId); GL_GPU::glBufferSubData(GL_ARRAY_BUFFER, 0, 32 * sizeof(GLfloat), renderingTextureCoordinates); GL_GPU::glClientActiveTexture(GL_TEXTURE0); GL_GPU::glEnableClientState(GL_TEXTURE_COORD_ARRAY); GL_GPU::glTexCoordPointer(2, GL_FLOAT, 0, 0); GL_GPU::glDisableClientState(GL_COLOR_ARRAY); GL_GPU::glBindBuffer(GL_ARRAY_BUFFER, 0); GL_GPU::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->iboTriangleStripId); GL_GPU::glDrawElements(GL_TRIANGLE_STRIP, 28, GL_UNSIGNED_BYTE, 0); glCheckErrorIgnoreOSXBug(GL_GPU); GL_GPU::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); GL_GPU::glDisableClientState(GL_VERTEX_ARRAY); GL_GPU::glDisableClientState(GL_TEXTURE_COORD_ARRAY); glCheckError(GL_GPU); this->unbindTextureAndReleaseShader(useShader); } } // drawRenderingVAO