mirror of
https://github.com/worldforge/ember
synced 2026-08-13 16:23:06 -04:00
379 lines
13 KiB
C++
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
|