/********************************************************************** Filename : GImageInfo.h Content : Image resource representation for GFxPlayer Created : January 30, 2007 Authors : Michael Antonov Notes : Copyright : (c) 2005-2006 Scaleform Corp. All Rights Reserved. Licensees may use this file in accordance with the valid Scaleform Commercial License Agreement provided with the software. This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR ANY PURPOSE. **********************************************************************/ #include "GImageInfo.h" #include "GImage.h" #include "GHeapNew.h" // ***** GFxImageInfoBase GImageInfoBase* GImageInfoBase::CreateSubImage(const GRect& rect, GMemoryHeap* pheap) { return GHEAP_NEW(pheap) GSubImageInfo(this, rect); } // ***** GFxImageInfoBaseImpl implementation GImageInfoBaseImpl::GImageInfoBaseImpl(GTexture *ptexture) : pTexture(ptexture) { if (ptexture) ptexture->AddChangeHandler(this); TextureUsage = GTexture::Usage_Wrap; } GImageInfoBaseImpl::~GImageInfoBaseImpl() { if (pTexture) pTexture->RemoveChangeHandler(this); } GTexture* GImageInfoBaseImpl::GetTexture(GRenderer* prenderer) { if (pTexture) { // We currently only support one renderer GASSERT(pTexture->GetRenderer() == prenderer); return pTexture; } pTexture = *prenderer->CreateTexture(); if (pTexture) { // Use our function to override the texture. if (Recreate(prenderer)) pTexture->AddChangeHandler(this); else pTexture = 0; } return pTexture.GetPtr(); } // GTexture::ChangeHandler implementation void GImageInfoBaseImpl::OnChange(GRenderer* prenderer, EventType changeType) { GUNUSED(prenderer); // Currently we just handle renderer death by destroying its textures // Texture Data loss does not need to be handled because Recreate will // restore the image data if possible. For RT textures we handle it separately. if (pTexture) { if (changeType == Event_RendererReleased) { pTexture->RemoveChangeHandler(this); pTexture = 0; } } } // ***** GImageInfo implementation GImageInfo::GImageInfo(GImage *pimage, bool releaseImage) : pImage(pimage), TargetWidth(0), TargetHeight(0), ReleaseImage(releaseImage) { TextureUsage = GTexture::Usage_Wrap; #ifdef GFX_AMP_SERVER ImageId = GetNextImageId(); #endif } GImageInfo::GImageInfo(GImage *pimage, UInt targetWidth, UInt targetHeight, bool releaseImage) : pImage(pimage), TargetWidth(targetWidth), TargetHeight(targetHeight), ReleaseImage(releaseImage) { TextureUsage = GTexture::Usage_Wrap; #ifdef GFX_AMP_SERVER ImageId = GetNextImageId(); #endif } GImageInfo::GImageInfo(GTexture *ptexture, UInt targetWidth, UInt targetHeight) : GImageInfoBaseImpl(ptexture), pImage(0), TargetWidth(targetWidth), TargetHeight(targetHeight), ReleaseImage(false) { // Note: GImageInfoBaseImpl will install a texture handler on us. #ifdef GFX_AMP_SERVER ImageId = GetNextImageId(); #endif } GImageInfo::~GImageInfo() { // pTexture handler is removed in ~GImageInfoBaseImpl. } #ifdef GFX_AMP_SERVER UInt32 GImageInfoBase::GetNextImageId() { static GLock staticLock; static UInt32 nextImageId = 0; GLock::Locker locker(&staticLock); return (++nextImageId); } #endif // GFX_AMP_SERVER // MA - Notes for future: // // GetWidth() / GetHeight() prefer {TargetWidth, TargetHeight} over the dimensions // of the image to ensure proper scaling in case of RenderTexture substitution. // Technically {TargetWidth, TargetHeight} would not be needed in any other // cases, except that there is no way to obtain them from texture. // So, in the future if we add GTexture::GetWidth() a more appropriate logic // would be: // return TargetWidth ? TargetWidth : // (pImage ? pImage->Width : (pTexture ? pTexture->GetWidth() : 0); // In that situation we can stop passing {TargetWidth, TargetHeight} in the // constructor and just have a special function GetSizeOverride()... // Of course, we would also need to consider all the 'gfxexport' cases, such // as padding of DDS textures, but that can be accounted for by the rectangle // in GSubImageInfo. UInt GImageInfo::GetWidth() const { return TargetWidth ? TargetWidth : (pImage ? pImage->Width : 0); } UInt GImageInfo::GetHeight() const { return TargetHeight ? TargetHeight : (pImage ? pImage->Height : 0); } #ifdef GFX_AMP_SERVER UPInt GImageInfo::GetBytes() const { if (!pImage) { return 0; } return pImage->Width * pImage->Height * pImage->GetBytesPerPixel(); } bool GImageInfo::IsExternal() const { return false; } GImageBase::ImageFormat GImageInfo::GetFormat() const { if (!pImage) { return GImageBase::Image_None; } return pImage->Format; } #endif // GFX_AMP_SERVER // *** Data Assignment void GImageInfo::SetImage(GImage* pimage) { pImage = pimage; if (pTexture) Recreate(pTexture->GetRenderer()); } void GImageInfo::SetImage(GImage* pimage, UInt targetWidth, UInt targetHeight) { TargetWidth = targetWidth; TargetHeight = targetHeight; SetImage(pimage); } // Sets the texture and potential target dimensions. void GImageInfo::SetTexture(GTexture *ptexture) { if (pTexture == ptexture) return; // Clear image, if any. pImage = 0; if (pTexture) pTexture->RemoveChangeHandler(this); if (ptexture) ptexture->AddChangeHandler(this); pTexture = ptexture; } void GImageInfo::SetTexture(GTexture *ptexture, UInt targetWidth, UInt targetHeight) { TargetWidth = targetWidth; TargetHeight = targetHeight; SetTexture(ptexture); } void GImageInfo::SetTextureUsage(UInt usage) { if (!pImage) { GFC_DEBUG_WARNING(1, "No image, keeping existing texture"); return; } if (usage != 0 && usage != TextureUsage && pTexture) { pTexture->RemoveChangeHandler(this); pTexture = 0; } TextureUsage = usage; } // Override GetTexture so that no attempt to create texture takes place if // there is no backup image date for initialization. GTexture* GImageInfo::GetTexture(GRenderer* prenderer) { if (pTexture) { // We currently only support one renderer GASSERT(pTexture->GetRenderer() == prenderer); return pTexture; } // If there is no image, no need to call Recreate on a texture // since it can not possibly succeed. if (!pImage) return 0; pTexture = *prenderer->CreateTexture(); if (pTexture) { // Use our function to override the texture. if (Recreate(prenderer)) pTexture->AddChangeHandler(this); else pTexture = 0; } if (pTexture && ReleaseImage) pImage = 0; return pTexture.GetPtr(); } // Override OnChange so that we can clear out pTexture pointer on data loss // when there is no backup image. Users can override this behavior if desired. void GImageInfo::OnChange(GRenderer* prenderer, EventType changeType) { GImageInfoBaseImpl::OnChange(prenderer, changeType); // Unlike regular ImageInfo which can Recreate its data based on GImage, // GImageInfo texture can not do so (instead it waits for the user to call // SetTexture again). Until such call takes place we just handle data // loss by releasing the texture object. if (pTexture && (changeType == Event_DataLost) && (pImage.GetPtr() == 0) ) { pTexture->RemoveChangeHandler(this); pTexture = 0; } } // Override recreate - to initialize texture data. // We actually populate texture data from the image here. bool GImageInfo::Recreate(GRenderer* prenderer) { GUNUSED(prenderer); if (pTexture) { if (pImage) { if (pTexture->InitTexture(pImage, TextureUsage)) return 1; } else { // This may happen if images were not loaded or bound by user correctly. GFC_DEBUG_WARNING(1, "GImageInfo::GetTexture failed, image not available. " "Please check GFxLoader::LoadImageData flag."); } } return 0; } GImageInfoBase* GSubImageInfo::CreateSubImage(const GRect& rect, GMemoryHeap* pheap) { GRect subrect = rect; subrect.Left += Rect.Left; subrect.Top += Rect.Top; return GHEAP_NEW(pheap) GSubImageInfo(this, subrect); } GSubImageInfo::GSubImageInfo(GImageInfoBase* pbase, GRect rect) : pBaseImage(pbase), Rect(rect) { #ifdef GFX_AMP_SERVER ImageId = GetNextImageId(); #endif } /* /////////////////////////////// GImageFileInfo::~GImageFileInfo() { if (pFileName) GFREE(pFileName); } void GImageFileInfo::SetFileName(const char* name) { if (pFileName) GFREE((void*)pFileName); char* ptr = 0; if (name) { int len = int(strlen(name)); ptr = (char*)GALLOC(len + 1); memcpy(ptr, name, len+1); } pFileName = ptr; } GTexture* GImageFileInfo::GetTexture(class GRenderer* prenderer) { if (pTexture) { // We currently only support one renderer GASSERT(pTexture->GetRenderer() == prenderer); return pTexture; } if (pFileName) { if ((pTexture = *prenderer->CreateTextureFromFile(pFileName, TargetWidth, TargetHeight))) { pTexture->AddChangeHandler(this); } } else { // This may happen if images were not loaded or bound by user correctly. GFC_DEBUG_WARNING(1, "GImageFileInfo::GetTexture failed, image not available. Please check GFxLoader::LoadImageData flag."); } return pTexture; } // GTexture::ChangeHandler implementation void GImageFileInfo::OnChange(GRenderer* prenderer, EventType changeType) { GUNUSED(prenderer); // Currently we just handle renderer death by destroying its textures // Texture Data loss does not need to be handled because if (pTexture) { if (changeType == Event_RendererReleased) { pTexture->RemoveChangeHandler(this); pTexture = 0; } } } bool GImageFileInfo::Recreate(GRenderer* prenderer) { GUNUSED(prenderer); if (pTexture && pFileName) return pTexture->InitTextureFromFile(pFileName, TargetWidth, TargetHeight); return 0; } */