ember/external/CEGUIOgreRenderer/Texture.cpp
2022-03-19 21:24:27 +01:00

379 lines
13 KiB
C++

/***********************************************************************
created: Tue Feb 17 2009
author: Paul D Turner
*************************************************************************/
/***************************************************************************
* Copyright (C) 2004 - 2011 Paul D Turner & The CEGUI Development Team
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
***************************************************************************/
#include "Texture.h"
#include "OgreMacros.h"
#include "CEGUI/Exceptions.h"
#include "CEGUI/System.h"
#include "ImageCodec.h"
#include <OgreTextureManager.h>
#include <OgreHardwarePixelBuffer.h>
#include <sstream>
// Start of CEGUI namespace section
namespace CEGUI
{
//----------------------------------------------------------------------------//
uint32 OgreTexture::d_textureNumber = 0;
//----------------------------------------------------------------------------//
OgreTexture::OgreTexture(const String& name) :
d_isLinked(false),
d_size(0, 0),
d_dataSize(0, 0),
d_texelScaling(0, 0),
d_name(name)
{
createEmptyOgreTexture(Texture::PF_RGBA);
}
//----------------------------------------------------------------------------//
OgreTexture::OgreTexture(const String& name, const String& filename,
const String& resourceGroup) :
d_isLinked(false),
d_size(0, 0),
d_dataSize(0, 0),
d_texelScaling(0, 0),
d_name(name)
{
loadFromFile(filename, resourceGroup);
}
//----------------------------------------------------------------------------//
OgreTexture::OgreTexture(const String& name, const Sizef& sz) :
d_isLinked(false),
d_size(0, 0),
d_dataSize(0, 0),
d_texelScaling(0, 0),
d_name(name)
{
createEmptyOgreTexture(Texture::PF_RGBA);
// throw exception if no texture was able to be created
if (OGRE_ISNULL(d_texture))
CEGUI_THROW(RendererException(
"Failed to create Texture object with spcecified size."));
d_size.d_width = d_texture->getWidth();
d_size.d_height = d_texture->getHeight();
d_dataSize = sz;
updateCachedScaleValues();
}
//----------------------------------------------------------------------------//
OgreTexture::OgreTexture(const String& name, Ogre::TexturePtr& tex,
bool take_ownership) :
d_isLinked(false),
d_size(0, 0),
d_dataSize(0, 0),
d_texelScaling(0, 0),
d_name(name)
{
setOgreTexture(tex, take_ownership);
}
//----------------------------------------------------------------------------//
OgreTexture::~OgreTexture()
{
freeOgreTexture();
}
//----------------------------------------------------------------------------//
const String& OgreTexture::getName() const
{
return d_name;
}
//----------------------------------------------------------------------------//
const Sizef& OgreTexture::getSize() const
{
return d_size;
}
//----------------------------------------------------------------------------//
const Sizef& OgreTexture::getOriginalDataSize() const
{
return d_dataSize;
}
//----------------------------------------------------------------------------//
const Vector2f& OgreTexture::getTexelScaling() const
{
return d_texelScaling;
}
//----------------------------------------------------------------------------//
void OgreTexture::loadFromFile(const String& filename,
const String& resourceGroup)
{
// get and check existence of CEGUI::System object
System* sys = System::getSingletonPtr();
if (!sys)
CEGUI_THROW(RendererException(
"CEGUI::System object has not been created!"));
// load file to memory via resource provider
RawDataContainer texFile;
sys->getResourceProvider()->loadRawDataContainer(filename, texFile,
resourceGroup);
ImageCodec& ic(sys->getImageCodec());
// if we're using the integrated Ogre codec, set the file-type hint string
if (ic.getIdentifierString().substr(0, 14) == "OgreImageCodec")
{
String type;
String::size_type i = filename.find_last_of(".");
if (i != String::npos && filename.length() - i > 1)
type = filename.substr(i+1);
static_cast<OgreImageCodec&>(ic).setImageFileDataType(type);
}
Texture* res = sys->getImageCodec().load(texFile, this);
// unload file data buffer
sys->getResourceProvider()->unloadRawDataContainer(texFile);
// throw exception if data was load loaded to texture.
if (!res)
CEGUI_THROW(RendererException(
sys->getImageCodec().getIdentifierString() +
" failed to load image '" + filename + "'."));
}
//----------------------------------------------------------------------------//
void OgreTexture::loadFromMemory(const void* buffer, const Sizef& buffer_size,
PixelFormat pixel_format)
{
using namespace Ogre;
if (!isPixelFormatSupported(pixel_format))
CEGUI_THROW(InvalidRequestException(
"Data was supplied in an unsupported pixel format."));
Ogre::PixelBox pixelBox(buffer_size.d_width, buffer_size.d_height,
1, toOgrePixelFormat(pixel_format), (char*) buffer);
createEmptyOgreTexture(pixel_format);
d_texture->freeInternalResources();
d_texture->setWidth(buffer_size.d_width);
d_texture->setHeight(buffer_size.d_height);
d_texture->setDepth(1);
d_texture->createInternalResources();
d_texture->getBuffer(0, 0).get()->blitFromMemory(pixelBox);
// throw exception if no texture was able to be created
if (OGRE_ISNULL(d_texture))
CEGUI_THROW(RendererException(
"Failed to blit to Texture from memory."));
d_size.d_width = d_texture->getWidth();
d_size.d_height = d_texture->getHeight();
d_dataSize = buffer_size;
updateCachedScaleValues();
}
//----------------------------------------------------------------------------//
void OgreTexture::blitFromMemory(const void* sourceData, const Rectf& area)
{
if (OGRE_ISNULL(d_texture)) // TODO: exception?
return;
// NOTE: const_cast because Ogre takes pointer to non-const here. Rather
// than allow that to dictate poor choices in our own APIs, we choose to
// address the issue as close to the source of the problem as possible.
Ogre::PixelBox pb(area.getWidth(), area.getHeight(),
1, d_texture->getFormat(), const_cast<void*>(sourceData));
Ogre::Box box(area.left(), area.top(), area.right(), area.bottom());
d_texture->getBuffer()->blitFromMemory(pb, box);
}
//----------------------------------------------------------------------------//
void OgreTexture::blitToMemory(void* targetData)
{
if (OGRE_ISNULL(d_texture)) // TODO: exception?
return;
Ogre::PixelBox pb(d_size.d_width, d_size.d_height,
1, d_texture->getFormat(), targetData);
d_texture->getBuffer()->blitToMemory(pb);
}
//----------------------------------------------------------------------------//
void OgreTexture::freeOgreTexture()
{
if (!OGRE_ISNULL(d_texture) && !d_isLinked)
Ogre::TextureManager::getSingleton().remove(d_texture->getHandle());
OGRE_RESET(d_texture);
}
//----------------------------------------------------------------------------//
Ogre::String OgreTexture::getUniqueName()
{
#if OGRE_VERSION < 0x10A00
Ogre::StringUtil::StrStreamType strstream;
strstream << "_cegui_ogre_" << d_textureNumber++;
return strstream.str();
#endif
#if OGRE_VERSION >= 0x10A00
Ogre::StringStream strstream;
strstream << "_cegui_ogre_" << d_textureNumber++;
return strstream.str();
#endif
}
//----------------------------------------------------------------------------//
void OgreTexture::updateCachedScaleValues()
{
//
// calculate what to use for x scale
//
const float orgW = d_dataSize.d_width;
const float texW = d_size.d_width;
// if texture and original data width are the same, scale is based
// on the original size.
// if texture is wider (and source data was not stretched), scale
// is based on the size of the resulting texture.
d_texelScaling.d_x = 1.0f / ((orgW == texW) ? orgW : texW);
//
// calculate what to use for y scale
//
const float orgH = d_dataSize.d_height;
const float texH = d_size.d_height;
// if texture and original data height are the same, scale is based
// on the original size.
// if texture is taller (and source data was not stretched), scale
// is based on the size of the resulting texture.
d_texelScaling.d_y = 1.0f / ((orgH == texH) ? orgH : texH);
}
//----------------------------------------------------------------------------//
void OgreTexture::setOgreTexture(Ogre::TexturePtr texture, bool take_ownership)
{
freeOgreTexture();
d_texture = texture;
d_isLinked = !take_ownership;
if (!OGRE_ISNULL(d_texture))
{
d_size.d_width = d_texture->getWidth();
d_size.d_height= d_texture->getHeight();
d_dataSize = d_size;
}
else
d_size = d_dataSize = Sizef(0, 0);
updateCachedScaleValues();
}
//----------------------------------------------------------------------------//
Ogre::TexturePtr OgreTexture::getOgreTexture() const
{
return d_texture;
}
//----------------------------------------------------------------------------//
bool OgreTexture::isPixelFormatSupported(const PixelFormat fmt) const
{
CEGUI_TRY
{
return Ogre::TextureManager::getSingleton().
isEquivalentFormatSupported(Ogre::TEX_TYPE_2D,
toOgrePixelFormat(fmt),
Ogre::TU_DEFAULT);
}
CEGUI_CATCH(InvalidRequestException&)
{
return false;
}
}
//----------------------------------------------------------------------------//
Ogre::PixelFormat OgreTexture::toOgrePixelFormat(const Texture::PixelFormat fmt)
{
switch (fmt)
{
case Texture::PF_RGBA: return Ogre::PF_A8B8G8R8;
case Texture::PF_RGB: return Ogre::PF_B8G8R8;
case Texture::PF_RGB_565: return Ogre::PF_R5G6B5;
case Texture::PF_RGBA_4444: return Ogre::PF_A4R4G4B4;
case Texture::PF_PVRTC2: return Ogre::PF_PVRTC_RGBA2;
case Texture::PF_PVRTC4: return Ogre::PF_PVRTC_RGBA4;
case Texture::PF_RGBA_DXT1: return Ogre::PF_DXT1;
case Texture::PF_RGBA_DXT3: return Ogre::PF_DXT3;
case Texture::PF_RGBA_DXT5: return Ogre::PF_DXT5;
default:
CEGUI_THROW(InvalidRequestException(
"Invalid pixel format translation."));
}
}
//----------------------------------------------------------------------------//
Texture::PixelFormat OgreTexture::fromOgrePixelFormat(
const Ogre::PixelFormat fmt)
{
switch (fmt)
{
case Ogre::PF_A8R8G8B8: return Texture::PF_RGBA;
case Ogre::PF_A8B8G8R8: return Texture::PF_RGBA;
case Ogre::PF_R8G8B8: return Texture::PF_RGB;
case Ogre::PF_B8G8R8: return Texture::PF_RGB;
case Ogre::PF_R5G6B5: return Texture::PF_RGB_565;
case Ogre::PF_A4R4G4B4: return Texture::PF_RGBA_4444;
case Ogre::PF_PVRTC_RGBA2: return Texture::PF_PVRTC2;
case Ogre::PF_PVRTC_RGBA4: return Texture::PF_PVRTC4;
case Ogre::PF_DXT1: return Texture::PF_RGBA_DXT1;
case Ogre::PF_DXT3: return Texture::PF_RGBA_DXT3;
case Ogre::PF_DXT5: return Texture::PF_RGBA_DXT5;
default:
CEGUI_THROW(InvalidRequestException(
"Invalid pixel format translation."));
}
}
//----------------------------------------------------------------------------//
void OgreTexture::createEmptyOgreTexture(PixelFormat pixel_format)
{
// try to create a Ogre::Texture with given dimensions
d_texture = Ogre::TextureManager::getSingleton().createManual(
getUniqueName(), "General", Ogre::TEX_TYPE_2D,
1, 1, 0,
toOgrePixelFormat(pixel_format));
}
//----------------------------------------------------------------------------//
} // End of CEGUI namespace section