//------------------------------------------------------------------------------ // Gridwalkers // // Copyright (c) 2003 Pat Wilson and Flaming Duck Studio // Portions Copyright (c) 2001 GarageGames.Com //------------------------------------------------------------------------------ #include "dgl/gDynamicTexture.h" #include "dgl/gBitmap.h" #include "gui/core/guiControl.h" #include "dgl/dgl.h" #include "util/safeDelete.h" Vector DynamicTexture::smRegisteredGuiUpdaters; Vector DynamicTexture::smRegisteredScreenUpdaters; Vector DynamicTexture::smUpdateAtEndOfFrame; //-------------------------------------------------------------------------- void dynamicTextureCB(const U32 eventCode, void *userData) { DynamicTexture* ts = reinterpret_cast(userData); if(eventCode==TextureManager::BeginZombification) { SAFE_DELETE(ts->mTextureHandle); } else if(eventCode==TextureManager::CacheResurrected) { GBitmap *bmp = new GBitmap( ts->mSize.x, ts->mSize.y, false, GBitmap::RGBA ); ts->mTextureHandle = new TextureHandle( NULL, bmp, BitmapKeepTexture, true ); } } //------------------------------------------------------------------------------ DynamicTexture::DynamicTexture() { initDT(); } //------------------------------------------------------------------------------ DynamicTexture::DynamicTexture( GuiControl * control ) { initDT(); registerForGuiUpdates( control ); } //------------------------------------------------------------------------------ DynamicTexture::DynamicTexture( const RectI &updateRect ) { initDT(); mUpdateRect = updateRect; setUpdateRect( updateRect ); } //------------------------------------------------------------------------------ DynamicTexture::~DynamicTexture() { TextureManager::unregisterEventCallback(mTexCBHandle); SAFE_DELETE( mTextureHandle ); SAFE_DELETE( mTempDynamicTexture ); } //------------------------------------------------------------------------------ void DynamicTexture::setEnableRTT( bool enable /* = true */ ) { mRTT = enable; if( enable && mTempDynamicTexture == NULL ) mTempDynamicTexture = new DynamicTexture( mUpdateRect ); } //------------------------------------------------------------------------------ void DynamicTexture::update() { if( !mHasUpdateRect ) return; RectI *rect = &mUpdateRect; // Different-rect updating provided it is the same size if( 0 ) { /// rect = something differing AssertFatal( rect->extent.x <= mUpdateRect.extent.x && rect->extent.y <= mUpdateRect.extent.x, "Cannot update a DynamicTexture with an update area larger than it's allocated area." ); } // Do the screen copy glReadBuffer( GL_BACK ); glBindTexture( GL_TEXTURE_2D, mTextureHandle->getGLName() ); glCopyTexSubImage2D( GL_TEXTURE_2D, 0, // 0 = no mipmaplevels 0, 0, // X and y offsets, see docs rect->point.x, rect->point.y, rect->extent.x, rect->extent.y ); } //------------------------------------------------------------------------------ void DynamicTexture::setUpdateRect( const RectI &newRect ) { mHasUpdateRect = true; // Check to see if this is being called as part of the constructor if( mTextureHandle == NULL ) { GBitmap *bmp = new GBitmap( newRect.extent.x, newRect.extent.y, false, GBitmap::RGBA ); mTextureHandle = new TextureHandle( NULL, bmp, BitmapKeepTexture, true ); mSize = newRect.extent; } if( mTempDynamicTexture != NULL ) mTempDynamicTexture->setUpdateRect( newRect ); // Flip from upper-left point to lower-left point (for GL) RectI updateRect = newRect; updateRect.point.y = Platform::getWindowSize().y - updateRect.point.y - updateRect.extent.y; if( updateRect.extent == mUpdateRect.extent ) { if( updateRect.point != mUpdateRect.point ) mUpdateRect.point = updateRect.point; } else { TextureObject *to = mTextureHandle->object; mUpdateRect = updateRect; // If the new texture size can fit in the existing allocated size, // then we are golden, otherwise we have to re-create or we'll get // hosed. if( mTextureHandle->getDownloadedWidth() >= mUpdateRect.extent.x && mTextureHandle->getDownloadedHeight() >= mUpdateRect.extent.y ) { // We don't have to resize the actual memory (yay) to->bitmapWidth = mUpdateRect.extent.x; to->bitmapHeight = mUpdateRect.extent.y; } else { // Damn, we gotta reallocate delete mTextureHandle; mTextureHandle = NULL; GBitmap *bmp = new GBitmap( updateRect.extent.x, updateRect.extent.y, false, GBitmap::RGBA ); mTextureHandle = new TextureHandle( NULL, bmp, BitmapKeepTexture, true ); mSize = updateRect.extent; } } // DON'T USE mUpdateRect here // Note that this looks a bit funny, this is because grabbing pixels results in // the rows getting flipped, to adjust for this, the texture coordinates must be flipped TextureObject *obj = (TextureObject *)mTextureHandle; F32 maxX = F32(newRect.extent.x) / F32(obj->texWidth); F32 maxY = F32(newRect.extent.y) / F32(obj->texHeight); mTextureCoords = RectF( (F32)newRect.point.x, maxY, maxX, (F32)newRect.point.y ); } //------------------------------------------------------------------------------ void DynamicTexture::renderGuiControl( GuiControl *ctrl /* = NULL */, bool rttMode /* = false */ ) { if( ctrl == NULL ) { if( mGuiControl == NULL ) return; else ctrl = mGuiControl; } else mGuiControl = ctrl; setUpdateRect( ctrl->mBounds ); // This CHANGES mUpdateRect // If we are simulating rendering to offscreen type thing // grab the current contents of the framebuffer and store them if( rttMode ) { setEnableRTT( true ); storePixels(); } // Now render the control and grab the pixels dglSetClipRect( ctrl->mBounds ); //ctrl->preRender(); ctrl->onRender( ctrl->mBounds.point, ctrl->mBounds ); update(); // Now restore the contents of the framebuffer so it doesn't look like we did // anything at all (bwahahaha, Trogdor strikes again) if( rttMode ) { dglSetClipRect( ctrl->mBounds ); restorePixels(); } } //------------------------------------------------------------------------------ void DynamicTexture::storePixels() { mTempDynamicTexture->update(); } //------------------------------------------------------------------------------ void DynamicTexture::restorePixels() { dglClearBitmapModulation(); dglDrawBitmapStretch( mTempDynamicTexture->getTextureHandle(), mUpdateRect, GFlip_Y ); } //------------------------------------------------------------------------------ void DynamicTexture::registerForGuiUpdates( GuiControl *control ) { if( control == NULL ) return; unregisterForGuiUpdates(); // Sign it up in the vector smRegisteredGuiUpdaters.push_back( this ); mGuiControl = control; } //------------------------------------------------------------------------------ bool DynamicTexture::unregisterForGuiUpdates() { for( RegisteredUpdateItr i = smRegisteredGuiUpdaters.begin(); i != smRegisteredGuiUpdaters.end(); i++ ) { if( (*i) == this ) { smRegisteredGuiUpdaters.erase( i ); return true; } } return false; } //------------------------------------------------------------------------------ void DynamicTexture::updateGuiTextures() { for( RegisteredUpdateItr i = smRegisteredGuiUpdaters.begin(); i != smRegisteredGuiUpdaters.end(); i++ ) { (*i)->renderGuiControl( (*i)->mGuiControl ); } } //------------------------------------------------------------------------------ void DynamicTexture::registerForScreenUpdates() { unregisterForScreenUpdates(); // Sign it up in the vector smRegisteredScreenUpdaters.push_back( this ); } //------------------------------------------------------------------------------ bool DynamicTexture::unregisterForScreenUpdates() { for( RegisteredUpdateItr i = smRegisteredScreenUpdaters.begin(); i != smRegisteredScreenUpdaters.end(); i++ ) { if( (*i) == this ) { smRegisteredScreenUpdaters.erase( i ); return true; } } return false; } //------------------------------------------------------------------------------ void DynamicTexture::updateScreenTextures() { for( RegisteredUpdateItr i = smRegisteredScreenUpdaters.begin(); i != smRegisteredScreenUpdaters.end(); i++ ) { (*i)->update(); } } //------------------------------------------------------------------------------ void DynamicTexture::updateEndOfFrameTextures() { for( RegisteredUpdateItr i = smUpdateAtEndOfFrame.begin(); i != smUpdateAtEndOfFrame.end(); i++ ) { (*i)->update(); } smUpdateAtEndOfFrame.clear(); }