示例#1
0
void GuiTabBookCtrl::onRender(Point2I offset, const RectI &updateRect)
{
   RectI tabRect = mTabRect;
   tabRect.point += offset;
   RectI pageRect = mPageRect;
   pageRect.point += offset;

   // We're so nice we'll store the old modulation before we clear it for our rendering! :)
   ColorI oldModulation;
   GFX->getDrawUtil()->getBitmapModulation( &oldModulation );

   // Wipe it out
   GFX->getDrawUtil()->clearBitmapModulation();

   Parent::onRender(offset, updateRect);

   // Clip to tab area
   RectI savedClipRect = GFX->getClipRect();
   RectI clippedTabRect = tabRect;
   clippedTabRect.intersect( savedClipRect );
   GFX->setClipRect( clippedTabRect );

   // Render our tabs
   renderTabs( offset, tabRect );

   // Restore Rect.
   GFX->setClipRect( savedClipRect );

   // Restore old modulation
   GFX->getDrawUtil()->setBitmapModulation( oldModulation );
}
void
Image::copyUnProcessedChannels(const RectI& roi,
                               const ImagePremultiplicationEnum outputPremult,
                               const ImagePremultiplicationEnum originalImagePremult,
                               const std::bitset<4> processChannels,
                               const ImagePtr& originalImage,
                               bool ignorePremult)
{
    int numComp = getComponents().getNumComponents();

    if (numComp == 0) {
        return;
    }
    if ( (numComp == 1) && processChannels[3] ) { // 1 component is alpha
        return;
    } else if ( (numComp == 2) && processChannels[0] && processChannels[1] ) {
        return;
    } else if ( (numComp == 3) && processChannels[0] && processChannels[1] && processChannels[2] ) {
        return;
    } else if ( (numComp == 4) && processChannels[0] && processChannels[1] && processChannels[2] && processChannels[3] ) {
        return;
    }


    if ( originalImage && ( getMipMapLevel() != originalImage->getMipMapLevel() ) ) {
        qDebug() << "WARNING: attempting to call copyUnProcessedChannels on images with different mipMapLevel";

        return;
    }

    QWriteLocker k(&_entryLock);
    assert( !originalImage || getBitDepth() == originalImage->getBitDepth() );


    RectI intersected;
    roi.intersect(_bounds, &intersected);

    bool premult = (outputPremult == eImagePremultiplicationPremultiplied);
    bool originalPremult = (originalImagePremult == eImagePremultiplicationPremultiplied);
    switch ( getBitDepth() ) {
    case eImageBitDepthByte:
        copyUnProcessedChannelsForDepth<unsigned char, 255>(premult, roi, processChannels, originalImage, originalPremult, ignorePremult);
        break;
    case eImageBitDepthShort:
        copyUnProcessedChannelsForDepth<unsigned short, 65535>(premult, roi, processChannels, originalImage, originalPremult, ignorePremult);
        break;
    case eImageBitDepthFloat:
        copyUnProcessedChannelsForDepth<float, 1>(premult, roi, processChannels, originalImage, originalPremult, ignorePremult);
        break;
    default:

        return;
    }
}
示例#3
0
void GFXD3D9Device::setClipRect( const RectI &inRect ) 
{
   // Clip the rect against the renderable size.
   Point2I size = mCurrentRT->getSize();

   RectI maxRect(Point2I(0,0), size);
   RectI rect = inRect;
   rect.intersect(maxRect);

   mClipRect = rect;

   F32 l = F32( mClipRect.point.x );
   F32 r = F32( mClipRect.point.x + mClipRect.extent.x );
   F32 b = F32( mClipRect.point.y + mClipRect.extent.y );
   F32 t = F32( mClipRect.point.y );

   // Set up projection matrix, 
   static Point4F pt;   
   pt.set(2.0f / (r - l), 0.0f, 0.0f, 0.0f);
   mTempMatrix.setColumn(0, pt);

   pt.set(0.0f, 2.0f/(t - b), 0.0f, 0.0f);
   mTempMatrix.setColumn(1, pt);

   pt.set(0.0f, 0.0f, 1.0f, 0.0f);
   mTempMatrix.setColumn(2, pt);

   pt.set((l+r)/(l-r), (t+b)/(b-t), 1.0f, 1.0f);
   mTempMatrix.setColumn(3, pt);

   setProjectionMatrix( mTempMatrix );

   // Set up world/view matrix
   mTempMatrix.identity();
   setViewMatrix( mTempMatrix );
   setWorldMatrix( mTempMatrix );

   setViewport( mClipRect );
}
示例#4
0
void
Gui::debugImage(const Image* image,
                const RectI& roi,
                const QString & filename )
{
    if (image->getBitDepth() != eImageBitDepthFloat) {
        qDebug() << "Debug image only works on float images.";

        return;
    }
    RectI renderWindow;
    RectI bounds = image->getBounds();
    if ( roi.isNull() ) {
        renderWindow = bounds;
    } else {
        if ( !roi.intersect(bounds, &renderWindow) ) {
            qDebug() << "The RoI does not interesect the bounds of the image.";

            return;
        }
    }
    QImage output(renderWindow.width(), renderWindow.height(), QImage::Format_ARGB32);
    const Color::Lut* lut = Color::LutManager::sRGBLut();
    lut->validate();
    Image::ReadAccess acc = image->getReadRights();
    const float* from = (const float*)acc.pixelAt( renderWindow.left(), renderWindow.bottom() );
    assert(from);
    int srcNComps = (int)image->getComponentsCount();
    int srcRowElements = srcNComps * bounds.width();

    for ( int y = renderWindow.height() - 1; y >= 0; --y,
          from += ( srcRowElements - srcNComps * renderWindow.width() ) ) {
        QRgb* dstPixels = (QRgb*)output.scanLine(y);
        assert(dstPixels);

        unsigned error_r = 0x80;
        unsigned error_g = 0x80;
        unsigned error_b = 0x80;

        for (int x = 0; x < renderWindow.width(); ++x, from += srcNComps, ++dstPixels) {
            float r, g, b, a;
            switch (srcNComps) {
            case 1:
                r = g = b = *from;
                a = 1;
                break;
            case 2:
                r = *from;
                g = *(from + 1);
                b = 0;
                a = 1;
                break;
            case 3:
                r = *from;
                g = *(from + 1);
                b = *(from + 2);
                a = 1;
                break;
            case 4:
                r = *from;
                g = *(from + 1);
                b = *(from + 2);
                a = *(from + 3);
                break;
            default:
                assert(false);

                return;
            }
            error_r = (error_r & 0xff) + lut->toColorSpaceUint8xxFromLinearFloatFast(r);
            error_g = (error_g & 0xff) + lut->toColorSpaceUint8xxFromLinearFloatFast(g);
            error_b = (error_b & 0xff) + lut->toColorSpaceUint8xxFromLinearFloatFast(b);
            assert(error_r < 0x10000 && error_g < 0x10000 && error_b < 0x10000);
            *dstPixels = qRgba( U8(error_r >> 8),
                                U8(error_g >> 8),
                                U8(error_b >> 8),
                                U8(a * 255) );
        }
    }

    U64 hashKey = image->getHashKey();
    QString hashKeyStr = QString::number(hashKey);
    QString realFileName = filename.isEmpty() ? QString( hashKeyStr + QString::fromUtf8(".png") ) : filename;
#ifdef DEBUG
    qDebug() << "Writing image: " << realFileName;
    renderWindow.debug();
#endif
    output.save(realFileName);
} // Gui::debugImage
示例#5
0
void GuiInspectorField::onRender( Point2I offset, const RectI &updateRect )
{
   RectI ctrlRect(offset, getExtent());
   
   // Render fillcolor...
   if ( mProfile->mOpaque )
      GFX->getDrawUtil()->drawRectFill(ctrlRect, mProfile->mFillColor);   

   // Render caption...
   if ( mCaption && mCaption[0] )
   {      
      // Backup current ClipRect
      RectI clipBackup = GFX->getClipRect();

      RectI clipRect = updateRect;

      // The rect within this control in which our caption must fit.
      RectI rect( offset + mCaptionRect.point + mProfile->mTextOffset, mCaptionRect.extent + Point2I(1,1) - Point2I(5,0) );

      // Now clipRect is the amount of our caption rect that is actually visible.
      bool hit = clipRect.intersect( rect );

      if ( hit )
      {
         GFX->setClipRect( clipRect );
         GFXDrawUtil *drawer = GFX->getDrawUtil();

         // Backup modulation color
         ColorI currColor;
         drawer->getBitmapModulation( &currColor );

         // Draw caption background...
         if( !isActive() )
            GFX->getDrawUtil()->drawRectFill( clipRect, mProfile->mFillColorNA );
         else if ( mHighlighted )         
            GFX->getDrawUtil()->drawRectFill( clipRect, mProfile->mFillColorHL );             

         // Draw caption text...

         drawer->setBitmapModulation( !isActive() ? mProfile->mFontColorNA : mHighlighted ? mProfile->mFontColorHL : mProfile->mFontColor );
         
         // Clip text with '...' if too long to fit
         String clippedText( mCaption );
         clipText( clippedText, clipRect.extent.x );

         renderJustifiedText( offset + mProfile->mTextOffset, getExtent(), clippedText );

         // Restore modulation color
         drawer->setBitmapModulation( currColor );

         // Restore previous ClipRect
         GFX->setClipRect( clipBackup );
      }
   }

   // Render Children...
   renderChildControls(offset, updateRect);

   // Render border...
   if ( mProfile->mBorder )
      renderBorder(ctrlRect, mProfile);   

   // Render divider...
   Point2I worldPnt = mEditCtrlRect.point + offset;
   GFX->getDrawUtil()->drawLine( worldPnt.x - 5,
      worldPnt.y, 
      worldPnt.x - 5,
      worldPnt.y + getHeight(),
      !isActive() ? mProfile->mBorderColorNA : mHighlighted ? mProfile->mBorderColorHL : mProfile->mBorderColor );
}
示例#6
0
void
Image::copyUnProcessedChannels(const RectI& roi,
                               const ImagePremultiplicationEnum outputPremult,
                               const ImagePremultiplicationEnum originalImagePremult,
                               const std::bitset<4> processChannels,
                               const ImagePtr& originalImage,
                               bool ignorePremult,
                               const OSGLContextPtr& glContext)
{
    int numComp = getComponents().getNumComponents();

    if (numComp == 0) {
        return;
    }
    if ( (numComp == 1) && processChannels[3] ) { // 1 component is alpha
        return;
    } else if ( (numComp == 2) && processChannels[0] && processChannels[1] ) {
        return;
    } else if ( (numComp == 3) && processChannels[0] && processChannels[1] && processChannels[2] ) {
        return;
    } else if ( (numComp == 4) && processChannels[0] && processChannels[1] && processChannels[2] && processChannels[3] ) {
        return;
    }


    if ( originalImage && ( getMipMapLevel() != originalImage->getMipMapLevel() ) ) {
        qDebug() << "WARNING: attempting to call copyUnProcessedChannels on images with different mipMapLevel";

        return;
    }

    QWriteLocker k(&_entryLock);
    assert( !originalImage || getBitDepth() == originalImage->getBitDepth() );


    RectI srcRoi;
    roi.intersect(_bounds, &srcRoi);

    if (getStorageMode() == eStorageModeGLTex) {
        assert(glContext);
        if (glContext->isGPUContext()) {
            copyUnProcessedChannelsGL<GL_GPU>(roi, outputPremult, originalImagePremult, processChannels, originalImage, ignorePremult, glContext, _bounds, srcRoi, getGLTextureTarget(), getGLTextureID(), originalImage->getGLTextureID());
        } else {
            copyUnProcessedChannelsGL<GL_CPU>(roi, outputPremult, originalImagePremult, processChannels, originalImage, ignorePremult, glContext, _bounds, srcRoi, getGLTextureTarget(), getGLTextureID(), originalImage->getGLTextureID());
        }
        return;
    }


    bool premult = (outputPremult == eImagePremultiplicationPremultiplied);
    bool originalPremult = (originalImagePremult == eImagePremultiplicationPremultiplied);
    switch ( getBitDepth() ) {
    case eImageBitDepthByte:
        copyUnProcessedChannelsForDepth<unsigned char, 255>(premult, roi, processChannels, originalImage, originalPremult, ignorePremult);
        break;
    case eImageBitDepthShort:
        copyUnProcessedChannelsForDepth<unsigned short, 65535>(premult, roi, processChannels, originalImage, originalPremult, ignorePremult);
        break;
    case eImageBitDepthFloat:
        copyUnProcessedChannelsForDepth<float, 1>(premult, roi, processChannels, originalImage, originalPremult, ignorePremult);
        break;
    default:

        return;
    }
} // copyUnProcessedChannels
bool GuiSplitContainer::layoutControls( RectI &clientRect )
{
   if ( size() < 2 )
      return false;

   GuiContainer *panelOne = dynamic_cast<GuiContainer*>( at(0) );
   GuiContainer *panelTwo = dynamic_cast<GuiContainer*>( at(1) );

   // 
   AssertFatal( panelOne && panelTwo, "GuiSplitContainer::layoutControl - Missing/Invalid Subordinate Controls! Split contained controls must derive from GuiContainer!" );

   RectI panelOneRect = RectI( clientRect.point, Point2I( 0, 0 ) );
   RectI panelTwoRect;
   RectI splitRect;

   solvePanelConstraints( getSplitPoint(), panelOne, panelTwo, clientRect );

   switch( mOrientation )
   {
   case Horizontal:
      panelOneRect.extent = Point2I( clientRect.extent.x, getSplitPoint().y );
      panelTwoRect = panelOneRect;
      panelTwoRect.intersect( clientRect );
      panelTwoRect.point.y = panelOneRect.extent.y;
      panelTwoRect.extent.y = clientRect.extent.y - panelOneRect.extent.y;

      // Generate new Splitter Rectangle
      splitRect = panelTwoRect;
      splitRect.extent.y = 0;
      splitRect.inset( 0, -mSplitterSize );

      panelOneRect.extent.y -= mSplitterSize;
      panelTwoRect.point.y += mSplitterSize;
      panelTwoRect.extent.y -= mSplitterSize;

      break;

   case Vertical:
      panelOneRect.extent = Point2I( getSplitPoint().x, clientRect.extent.y );
      panelTwoRect = panelOneRect;
      panelTwoRect.intersect( clientRect );
      panelTwoRect.point.x = panelOneRect.extent.x;
      panelTwoRect.extent.x = clientRect.extent.x - panelOneRect.extent.x;

      // Generate new Splitter Rectangle
      splitRect = panelTwoRect;
      splitRect.extent.x = 0;
      splitRect.inset( -mSplitterSize, 0 );

      panelOneRect.extent.x -= mSplitterSize;
      panelTwoRect.point.x += mSplitterSize;
      panelTwoRect.extent.x -= mSplitterSize;

      break;
   }

   // Update Split Rect
   mSplitRect = splitRect;

   // Dock Appropriately
   if( !( mFixedPanel == FirstPanel && !panelOne->isVisible() ) )
      dockControl( panelOne, panelOne->getDocking(), panelOneRect );
   if( !( mFixedPanel == FirstPanel && !panelTwo->isVisible() ) )
      dockControl( panelTwo, panelOne->getDocking(), panelTwoRect );   

   // 
   return false;
}
示例#8
0
/*
 * @brief This is called by LibMV to retrieve an image either for reference or as search frame.
 */
mv::FrameAccessor::Key
TrackerFrameAccessor::GetImage(int /*clip*/,
                               int frame,
                               mv::FrameAccessor::InputMode input_mode,
                               int downscale,            // Downscale by 2^downscale.
                               const mv::Region* region,     // Get full image if NULL.
                               const mv::FrameAccessor::Transform* /*transform*/, // May be NULL.
                               mv::FloatImage** destination)
{
    // Since libmv only uses MONO images for now we have only optimized for this case, remove and handle properly
    // other case(s) when they get integrated into libmv.
    assert(input_mode == mv::FrameAccessor::MONO);


    FrameAccessorCacheKey key;
    key.frame = frame;
    key.mipMapLevel = downscale;
    key.mode = input_mode;

    /*
       Check if a frame exists in the cache with matching key and bounds enclosing the given region
     */
    RectI roi;
    if (region) {
        convertLibMVRegionToRectI(*region, _imp->formatHeight, &roi);

        QMutexLocker k(&_imp->cacheMutex);
        std::pair<FrameAccessorCache::iterator, FrameAccessorCache::iterator> range = _imp->cache.equal_range(key);
        for (FrameAccessorCache::iterator it = range.first; it != range.second; ++it) {
            if ( (roi.x1 >= it->second.bounds.x1) && (roi.x2 <= it->second.bounds.x2) &&
                 ( roi.y1 >= it->second.bounds.y1) && ( roi.y2 <= it->second.bounds.y2) ) {
#ifdef TRACE_LIB_MV
                qDebug() << QThread::currentThread() << "FrameAccessor::GetImage():" << "Found cached image at frame" << frame << "with RoI x1="
                         << region->min(0) << "y1=" << region->max(1) << "x2=" << region->max(0) << "y2=" << region->min(1);
#endif
                // LibMV is kinda dumb on this we must necessarily copy the data either via CopyFrom or the
                // assignment constructor:
                // EDIT: fixed libmv
                *destination = it->second.image.get();
                //destination->CopyFrom<float>(*it->second.image);
                ++it->second.referenceCount;

                return (mv::FrameAccessor::Key)it->second.image.get();
            }
        }
    }

    EffectInstancePtr effect;
    if (_imp->trackerInput) {
        effect = _imp->trackerInput->getEffectInstance();
    }
    if (!effect) {
        return (mv::FrameAccessor::Key)0;
    }

    // Not in accessor cache, call renderRoI
    RenderScale scale;
    scale.y = scale.x = Image::getScaleFromMipMapLevel( (unsigned int)downscale );


    RectD precomputedRoD;
    if (!region) {
        bool isProjectFormat;
        StatusEnum stat = effect->getRegionOfDefinition_public(_imp->trackerInput->getHashValue(), frame, scale, ViewIdx(0), &precomputedRoD, &isProjectFormat);
        if (stat == eStatusFailed) {
            return (mv::FrameAccessor::Key)0;
        }
        double par = effect->getAspectRatio(-1);
        precomputedRoD.toPixelEnclosing( (unsigned int)downscale, par, &roi );
    }

    std::list<ImageComponents> components;
    components.push_back( ImageComponents::getRGBComponents() );

    NodePtr node = _imp->context->getNode();
    const bool isRenderUserInteraction = true;
    const bool isSequentialRender = false;
    AbortableRenderInfoPtr abortInfo = AbortableRenderInfo::create(false, 0);
    AbortableThread* isAbortable = dynamic_cast<AbortableThread*>( QThread::currentThread() );
    if (isAbortable) {
        isAbortable->setAbortInfo( isRenderUserInteraction, abortInfo, node->getEffectInstance() );
    }


    ParallelRenderArgsSetter::CtorArgsPtr tlsArgs(new ParallelRenderArgsSetter::CtorArgs);
    tlsArgs->time = frame;
    tlsArgs->view = ViewIdx(0);
    tlsArgs->isRenderUserInteraction = isRenderUserInteraction;
    tlsArgs->isSequential = isSequentialRender;
    tlsArgs->abortInfo = abortInfo;
    tlsArgs->treeRoot = node;
    tlsArgs->textureIndex = 0;
    tlsArgs->timeline = node->getApp()->getTimeLine();
    tlsArgs->activeRotoPaintNode = NodePtr();
    tlsArgs->activeRotoDrawableItem = RotoDrawableItemPtr();
    tlsArgs->isDoingRotoNeatRender = false;
    tlsArgs->isAnalysis = true;
    tlsArgs->draftMode = false;
    tlsArgs->stats = RenderStatsPtr();
    ParallelRenderArgsSetter frameRenderArgs(tlsArgs); // Stats
    EffectInstance::RenderRoIArgs args( frame,
                                        scale,
                                        downscale,
                                        ViewIdx(0),
                                        false,
                                        roi,
                                        precomputedRoD,
                                        components,
                                        eImageBitDepthFloat,
                                        true,
                                        _imp->context->getNode()->getEffectInstance(),
                                        eStorageModeRAM /*returnOpenGLTex*/,
                                        frame);
    std::map<ImageComponents, ImagePtr> planes;
    EffectInstance::RenderRoIRetCode stat = effect->renderRoI(args, &planes);
    if ( (stat != EffectInstance::eRenderRoIRetCodeOk) || planes.empty() ) {
#ifdef TRACE_LIB_MV
        qDebug() << QThread::currentThread() << "FrameAccessor::GetImage():" << "Failed to call renderRoI on input at frame" << frame << "with RoI x1="
                 << roi.x1 << "y1=" << roi.y1 << "x2=" << roi.x2 << "y2=" << roi.y2;
#endif

        return (mv::FrameAccessor::Key)0;
    }

    assert( !planes.empty() );
    const ImagePtr& sourceImage = planes.begin()->second;
    RectI sourceBounds = sourceImage->getBounds();
    RectI intersectedRoI;
    if ( !roi.intersect(sourceBounds, &intersectedRoI) ) {
#ifdef TRACE_LIB_MV
        qDebug() << QThread::currentThread() << "FrameAccessor::GetImage():" << "RoI does not intersect the source image bounds (RoI x1="
                 << roi.x1 << "y1=" << roi.y1 << "x2=" << roi.x2 << "y2=" << roi.y2 << ")";
#endif

        return (mv::FrameAccessor::Key)0;
    }

#ifdef TRACE_LIB_MV
    qDebug() << QThread::currentThread() << "FrameAccessor::GetImage():" << "renderRoi (frame" << frame << ") OK  (BOUNDS= x1="
             << sourceBounds.x1 << "y1=" << sourceBounds.y1 << "x2=" << sourceBounds.x2 << "y2=" << sourceBounds.y2 << ") (ROI = " << roi.x1 << "y1=" << roi.y1 << "x2=" << roi.x2 << "y2=" << roi.y2 << ")";
#endif

    /*
       Copy the Natron image to the LivMV float image
     */
    FrameAccessorCacheEntry entry;
    entry.image.reset( new MvFloatImage( intersectedRoI.height(), intersectedRoI.width() ) );
    entry.bounds = intersectedRoI;
    entry.referenceCount = 1;
    natronImageToLibMvFloatImage(_imp->enabledChannels,
                                 sourceImage.get(),
                                 intersectedRoI,
                                 *entry.image);
    // we ignore the transform parameter and do it in natronImageToLibMvFloatImage instead

    *destination = entry.image.get();
    //destination->CopyFrom<float>(*entry.image);

    //insert into the cache
    {
        QMutexLocker k(&_imp->cacheMutex);
        _imp->cache.insert( std::make_pair(key, entry) );
    }
#ifdef TRACE_LIB_MV
    qDebug() << QThread::currentThread() << "FrameAccessor::GetImage():" << "Rendered frame" << frame << "with RoI x1="
             << intersectedRoI.x1 << "y1=" << intersectedRoI.y1 << "x2=" << intersectedRoI.x2 << "y2=" << intersectedRoI.y2;
#endif

    return (mv::FrameAccessor::Key)entry.image.get();
} // TrackerFrameAccessor::GetImage
示例#9
0
void
ImageTilesState::getMinimalRectsToRenderFromTilesState(const RectI& roi, const TileStateHeader& stateMap, std::list<RectI>* rectsToRender)
{
    if (stateMap.state->tiles.empty()) {
        return;
    }

    RectI roiRoundedToTileSize = roi;
    roiRoundedToTileSize.roundToTileSize(stateMap.tileSizeX, stateMap.tileSizeY);

    RectI bboxM = getMinimalBboxToRenderFromTilesState(roi, stateMap);
    if (bboxM.isNull()) {
        return;
    }

    bboxM.roundToTileSize(stateMap.tileSizeX, stateMap.tileSizeY);

    // optimization by Fred, Jan 31, 2014
    //
    // Now that we have the smallest enclosing bounding box,
    // let's try to find rectangles for the bottom, the top,
    // the left and the right part.
    // This happens quite often, for example when zooming out
    // (in this case the area to compute is formed of A, B, C and D,
    // and X is already rendered), or when panning (in this case the area
    // is just two rectangles, e.g. A and C, and the rectangles B, D and
    // X are already rendered).
    // The rectangles A, B, C and D from the following drawing are just
    // zeroes, and X contains zeroes and ones.
    //
    // BBBBBBBBBBBBBB
    // BBBBBBBBBBBBBB
    // CXXXXXXXXXXDDD
    // CXXXXXXXXXXDDD
    // CXXXXXXXXXXDDD
    // CXXXXXXXXXXDDD
    // AAAAAAAAAAAAAA

    // First, find if there's an "A" rectangle, and push it to the result
    //find bottom
    RectI bboxX = bboxM;
    RectI bboxA = bboxX;
    bboxA.y2 = bboxA.y1;
    for (int y = bboxX.y1; y < bboxX.y2; y += stateMap.tileSizeY) {
        bool hasRenderedTileOnLine = false;
        for (int x = bboxX.x1; x < bboxX.x2; x += stateMap.tileSizeX) {
            const TileState* tile = stateMap.getTileAt(x, y);
            if (tile->status != eTileStatusNotRendered) {
                hasRenderedTileOnLine = true;
                break;
            }
        }
        if (hasRenderedTileOnLine) {
            break;
        } else {
            bboxX.y1 += stateMap.tileSizeY;
            bboxA.y2 = bboxX.y1;
        }
    }
    if ( !bboxA.isNull() ) { // empty boxes should not be pushed
        // Ensure the bbox lies in the RoI since we rounded to tile size earlier
        RectI bboxAIntersected;
        bboxA.intersect(roi, &bboxAIntersected);
        rectsToRender->push_back(bboxAIntersected);
    }

    // Now, find the "B" rectangle
    //find top
    RectI bboxB = bboxX;
    bboxB.y1 = bboxB.y2;

    for (int y = bboxX.y2 - stateMap.tileSizeY; y >= bboxX.y1; y -= stateMap.tileSizeY) {
        bool hasRenderedTileOnLine = false;
        for (int x = bboxX.x1; x < bboxX.x2; x += stateMap.tileSizeX) {
            const TileState* tile = stateMap.getTileAt(x, y);
            if (tile->status != eTileStatusNotRendered) {
                hasRenderedTileOnLine = true;
                break;
            }
        }
        if (hasRenderedTileOnLine) {
            break;
        } else {
            bboxX.y2 -= stateMap.tileSizeY;
            bboxB.y1 = bboxX.y2;
        }
    }

    if ( !bboxB.isNull() ) { // empty boxes should not be pushed
        // Ensure the bbox lies in the RoI since we rounded to tile size earlier
        RectI bboxBIntersected;
        bboxB.intersect(roi, &bboxBIntersected);
        rectsToRender->push_back(bboxBIntersected);
    }

    //find left
    RectI bboxC = bboxX;
    bboxC.x2 = bboxC.x1;
    if ( bboxX.y1 < bboxX.y2 ) {
        for (int x = bboxX.x1; x < bboxX.x2; x += stateMap.tileSizeX) {
            bool hasRenderedTileOnCol = false;
            for (int y = bboxX.y1; y < bboxX.y2; y += stateMap.tileSizeY) {
                const TileState* tile = stateMap.getTileAt(x, y);
                if (tile->status != eTileStatusNotRendered) {
                    hasRenderedTileOnCol = true;
                    break;
                }

            }
            if (hasRenderedTileOnCol) {
                break;
            } else {
                bboxX.x1 += stateMap.tileSizeX;
                bboxC.x2 = bboxX.x1;
            }
        }
    }
    if ( !bboxC.isNull() ) { // empty boxes should not be pushed
        // Ensure the bbox lies in the RoI since we rounded to tile size earlier
        RectI bboxCIntersected;
        bboxC.intersect(roi, &bboxCIntersected);
        rectsToRender->push_back(bboxCIntersected);
    }

    //find right
    RectI bboxD = bboxX;
    bboxD.x1 = bboxD.x2;
    if ( bboxX.y1 < bboxX.y2 ) {
        for (int x = bboxX.x2 - stateMap.tileSizeX; x >= bboxX.x1; x -= stateMap.tileSizeX) {
            bool hasRenderedTileOnCol = false;
            for (int y = bboxX.y1; y < bboxX.y2; y += stateMap.tileSizeY) {
                const TileState* tile = stateMap.getTileAt(x, y);
                if (tile->status != eTileStatusNotRendered) {
                    hasRenderedTileOnCol = true;
                    break;
                }
            }
            if (hasRenderedTileOnCol) {
                break;
            } else {
                bboxX.x2 -= stateMap.tileSizeX;
                bboxD.x1 = bboxX.x2;
            }
        }
    }
    if ( !bboxD.isNull() ) { // empty boxes should not be pushed
        // Ensure the bbox lies in the RoI since we rounded to tile size earlier
        RectI bboxDIntersected;
        bboxD.intersect(roi, &bboxDIntersected);
        rectsToRender->push_back(bboxDIntersected);
    }

    assert( bboxA.bottom() == bboxM.bottom() );
    assert( bboxA.left() == bboxM.left() );
    assert( bboxA.right() == bboxM.right() );
    assert( bboxA.top() == bboxX.bottom() );

    assert( bboxB.top() == bboxM.top() );
    assert( bboxB.left() == bboxM.left() );
    assert( bboxB.right() == bboxM.right() );
    assert( bboxB.bottom() == bboxX.top() );

    assert( bboxC.top() == bboxX.top() );
    assert( bboxC.left() == bboxM.left() );
    assert( bboxC.right() == bboxX.left() );
    assert( bboxC.bottom() == bboxX.bottom() );

    assert( bboxD.top() == bboxX.top() );
    assert( bboxD.left() == bboxX.right() );
    assert( bboxD.right() == bboxM.right() );
    assert( bboxD.bottom() == bboxX.bottom() );

    // get the bounding box of what's left (the X rectangle in the drawing above)
    bboxX = getMinimalBboxToRenderFromTilesState(bboxX, stateMap);

    if ( !bboxX.isNull() ) { // empty boxes should not be pushed
        // Ensure the bbox lies in the RoI since we rounded to tile size earlier
        RectI bboxXIntersected;
        bboxX.intersect(roi, &bboxXIntersected);
        rectsToRender->push_back(bboxXIntersected);
    }
    
} // getMinimalRectsToRenderFromTilesState
示例#10
0
RectI
ImageTilesState::getMinimalBboxToRenderFromTilesState(const RectI& roi, const TileStateHeader& stateMap)
{

    if (stateMap.state->tiles.empty()) {
        return RectI();
    }

    const RectI& imageBoundsRoundedToTileSize = stateMap.state->boundsRoundedToTileSize;
    const RectI& imageBoundsNotRounded = stateMap.state->bounds;

    assert(imageBoundsRoundedToTileSize.contains(roi));

    RectI roiRoundedToTileSize = roi;
    roiRoundedToTileSize.roundToTileSize(stateMap.tileSizeX, stateMap.tileSizeY);

    // Search for rendered lines from bottom to top
    for (int y = roiRoundedToTileSize.y1; y < roiRoundedToTileSize.y2; y += stateMap.tileSizeY) {

        bool hasTileUnrenderedOnLine = false;
        for (int x = roiRoundedToTileSize.x1; x < roiRoundedToTileSize.x2; x += stateMap.tileSizeX) {

            const TileState* tile = stateMap.getTileAt(x, y);
            if (tile->status == eTileStatusNotRendered) {
                hasTileUnrenderedOnLine = true;
                break;
            }
        }
        if (!hasTileUnrenderedOnLine) {
            roiRoundedToTileSize.y1 += stateMap.tileSizeY;
        } else {
            break;
        }
    }

    // Search for rendered lines from top to bottom
    for (int y = roiRoundedToTileSize.y2 - stateMap.tileSizeY; y >= roiRoundedToTileSize.y1; y -= stateMap.tileSizeY) {

        bool hasTileUnrenderedOnLine = false;
        for (int x = roiRoundedToTileSize.x1; x < roiRoundedToTileSize.x2; x += stateMap.tileSizeX) {

            const TileState* tile = stateMap.getTileAt(x, y);
            if (tile->status == eTileStatusNotRendered) {
                hasTileUnrenderedOnLine = true;
                break;
            }
        }
        if (!hasTileUnrenderedOnLine) {
            roiRoundedToTileSize.y2 -= stateMap.tileSizeY;
        } else {
            break;
        }
    }

    // Avoid making roiRoundedToTileSize.width() iterations for nothing
    if (roiRoundedToTileSize.isNull()) {
        return roiRoundedToTileSize;
    }


    // Search for rendered columns from left to right
    for (int x = roiRoundedToTileSize.x1; x < roiRoundedToTileSize.x2; x += stateMap.tileSizeX) {

        bool hasTileUnrenderedOnCol = false;
        for (int y = roiRoundedToTileSize.y1; y < roiRoundedToTileSize.y2; y += stateMap.tileSizeY) {

            const TileState* tile = stateMap.getTileAt(x, y);
            if (tile->status == eTileStatusNotRendered) {
                hasTileUnrenderedOnCol = true;
                break;
            }
        }
        if (!hasTileUnrenderedOnCol) {
            roiRoundedToTileSize.x1 += stateMap.tileSizeX;
        } else {
            break;
        }
    }

    // Avoid making roiRoundedToTileSize.width() iterations for nothing
    if (roiRoundedToTileSize.isNull()) {
        return roiRoundedToTileSize;
    }

    // Search for rendered columns from right to left
    for (int x = roiRoundedToTileSize.x2 - stateMap.tileSizeX; x >= roiRoundedToTileSize.x1; x -= stateMap.tileSizeX) {

        bool hasTileUnrenderedOnCol = false;
        for (int y = roiRoundedToTileSize.y1; y < roiRoundedToTileSize.y2; y += stateMap.tileSizeY) {

            const TileState* tile = stateMap.getTileAt(x, y);
            if (tile->status == eTileStatusNotRendered) {
                hasTileUnrenderedOnCol = true;
                break;
            }
        }
        if (!hasTileUnrenderedOnCol) {
            roiRoundedToTileSize.x2 -= stateMap.tileSizeX;
        } else {
            break;
        }
    }

    // Intersect the result to the actual image bounds (because the tiles are rounded to tile size)
    RectI ret;
    roiRoundedToTileSize.intersect(imageBoundsNotRounded, &ret);
    return ret;


} // getMinimalBboxToRenderFromTilesState
示例#11
0
void
Image::applyMaskMix(const RectI& roi,
                    const Image* maskImg,
                    const Image* originalImg,
                    bool masked,
                    bool maskInvert,
                    float mix,
                    const OSGLContextPtr& glContext)
{
    ///!masked && mix == 1 has nothing to do
    if ( !masked && (mix == 1) ) {
        return;
    }

    QWriteLocker k(&_entryLock);
    boost::shared_ptr<QReadLocker> originalLock;
    boost::shared_ptr<QReadLocker> maskLock;
    if (originalImg) {
        originalLock.reset( new QReadLocker(&originalImg->_entryLock) );
    }
    if (maskImg) {
        maskLock.reset( new QReadLocker(&maskImg->_entryLock) );
    }
    RectI realRoI;
    roi.intersect(_bounds, &realRoI);

    assert( !originalImg || getBitDepth() == originalImg->getBitDepth() );
    assert( !masked || !maskImg || maskImg->getComponents() == ImageComponents::getAlphaComponents() );

    if (getStorageMode() == eStorageModeGLTex) {
        assert(glContext);
        assert(originalImg->getStorageMode() == eStorageModeGLTex);
        boost::shared_ptr<GLShader> shader = glContext->getOrCreateDefaultShader(OSGLContext::eDefaultGLShaderCopyUnprocessedChannels);
        assert(shader);
        GLuint fboID = glContext->getFBOId();

        glBindFramebuffer(GL_FRAMEBUFFER, fboID);
        int target = getGLTextureTarget();
        glEnable(target);
        glActiveTexture(GL_TEXTURE0);
        glBindTexture( target, getGLTextureID() );
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, getGLTextureID(), 0 /*LoD*/);
        glCheckFramebufferError();

        glActiveTexture(GL_TEXTURE1);
        glBindTexture( target, originalImg->getGLTextureID() );
        glActiveTexture(GL_TEXTURE2);
        glBindTexture(target, maskImg ? maskImg->getGLTextureID() : 0);

        glViewport( realRoI.x1 - _bounds.x1, realRoI.y1 - _bounds.y1, realRoI.width(), realRoI.height() );
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glOrtho( realRoI.x1, realRoI.x2,
                realRoI.y1, realRoI.y2,
                -10.0 * (realRoI.y2 - realRoI.y1), 10.0 * (realRoI.y2 - realRoI.y1) );
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glCheckError();

        // Compute the texture coordinates to match the srcRoi
        Point srcTexCoords[4], vertexCoords[4];
        vertexCoords[0].x = realRoI.x1;
        vertexCoords[0].y = realRoI.y1;
        srcTexCoords[0].x = (realRoI.x1 - _bounds.x1) / (double)_bounds.width();
        srcTexCoords[0].y = (realRoI.y1 - _bounds.y1) / (double)_bounds.height();

        vertexCoords[1].x = realRoI.x2;
        vertexCoords[1].y = realRoI.y1;
        srcTexCoords[1].x = (realRoI.x2 - _bounds.x1) / (double)_bounds.width();
        srcTexCoords[1].y = (realRoI.y1 - _bounds.y1) / (double)_bounds.height();

        vertexCoords[2].x = realRoI.x2;
        vertexCoords[2].y = realRoI.y2;
        srcTexCoords[2].x = (realRoI.x2 - _bounds.x1) / (double)_bounds.width();
        srcTexCoords[2].y = (realRoI.y2 - _bounds.y1) / (double)_bounds.height();

        vertexCoords[3].x = realRoI.x1;
        vertexCoords[3].y = realRoI.y2;
        srcTexCoords[3].x = (realRoI.x1 - _bounds.x1) / (double)_bounds.width();
        srcTexCoords[3].y = (realRoI.y2 - _bounds.y1) / (double)_bounds.height();

        shader->bind();
        shader->setUniform("originalImageTex", 1);
        shader->setUniform("maskImageTex", 2);
        shader->setUniform("outputImageTex", 0);
        shader->setUniform("mixValue", mix);
        shader->setUniform("maskEnabled", maskImg ? 1 : 0);

        glBegin(GL_POLYGON);
        for (int i = 0; i < 4; ++i) {
            glTexCoord2d(srcTexCoords[i].x, srcTexCoords[i].y);
            glVertex2d(vertexCoords[i].x, vertexCoords[i].y);
        }
        glEnd();
        shader->unbind();


        glBindTexture(target, 0);
        glActiveTexture(GL_TEXTURE1);
        glBindTexture(target, 0);
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(target, 0);
        glCheckError();

        return;
    }

    int srcNComps = originalImg ? (int)originalImg->getComponentsCount() : 0;
    //assert(0 < srcNComps && srcNComps <= 4);
    switch (srcNComps) {
    //case 0:
    //    applyMaskMixForSrcComponents<0>(realRoI, maskImg, originalImg, masked, maskInvert, mix);
    //    break;
    case 1:
        applyMaskMixForSrcComponents<1>(realRoI, maskImg, originalImg, masked, maskInvert, mix);
        break;
    case 2:
        applyMaskMixForSrcComponents<2>(realRoI, maskImg, originalImg, masked, maskInvert, mix);
        break;
    case 3:
        applyMaskMixForSrcComponents<3>(realRoI, maskImg, originalImg, masked, maskInvert, mix);
        break;
    case 4:
        applyMaskMixForSrcComponents<4>(realRoI, maskImg, originalImg, masked, maskInvert, mix);
        break;
    default:
        break;
    }
} // applyMaskMix