Revision: 827
http://python-ogre.svn.sourceforge.net/python-ogre/?rev=827&view=rev
Author: andy_miller
Date: 2008-12-05 07:18:28 +0000 (Fri, 05 Dec 2008)
Log Message:
-----------
Initial add of Canvas wrapper and update for mygui
Modified Paths:
--------------
trunk/python-ogre/PythonOgreConfig_nt.py
trunk/python-ogre/PythonOgreConfig_posix.py
trunk/python-ogre/ReportVersion.py
trunk/python-ogre/environment.py
trunk/python-ogre/setup.py
Added Paths:
-----------
trunk/python-ogre/ThirdParty/canvas/
trunk/python-ogre/ThirdParty/canvas/Atlas.cpp
trunk/python-ogre/ThirdParty/canvas/Atlas.h
trunk/python-ogre/ThirdParty/canvas/Canvas.cpp
trunk/python-ogre/ThirdParty/canvas/Canvas.h
trunk/python-ogre/packages_2.5/ogre/gui/canvas/
trunk/python-ogre/packages_2.5/ogre/gui/canvas/__init__.py
trunk/python-ogre/packages_2.5/ogre/gui/mygui/
trunk/python-ogre/packages_2.5/ogre/gui/mygui/__init__.py
Modified: trunk/python-ogre/PythonOgreConfig_nt.py
===================================================================
--- trunk/python-ogre/PythonOgreConfig_nt.py 2008-12-04 13:12:10 UTC (rev 826)
+++ trunk/python-ogre/PythonOgreConfig_nt.py 2008-12-05 07:18:28 UTC (rev 827)
@@ -84,6 +84,7 @@
PATH_hydrax = os.path.join(PATH_THIRDPARTY, 'Hydrax')
PATH_hikari = os.path.join(PATH_THIRDPARTY, 'Hikari' ) #BASE_DIR, 'hikari', 'hikari')
PATH_mygui = os.path.join(BASE_DIR, 'MyGUI_2.2.0_RC1_source' )
+PATH_canvas = os.path.join(PATH_THIRDPARTY, 'canvas')
# it's time for the SDK version
if SDK:
@@ -132,6 +133,7 @@
PATH_LIB_opensteer = os.path.join(PATH_opensteer, 'win32','release')
PATH_LIB_hikari = os.path.join(PATH_hikari ) # , 'lib')
PATH_LIB_mygui = os.path.join(PATH_mygui, 'MyGUIEngine','lib','Release')
+PATH_LIB_canvas = os.path.join(PATH_canvas )
PATH_INCLUDE_Ogre= os.path.join(PATH_Ogre,'OgreMain/include')
PATH_INCLUDE_NEDMALLOC= os.path.join(PATH_Ogre,'OgreMain', 'src', 'nedmalloc')
@@ -183,6 +185,7 @@
PATH_INCLUDE_hydrax= PATH_hydrax
PATH_INCLUDE_hikari = os.path.join(PATH_hikari ) #, 'include')
PATH_INCLUDE_mygui = os.path.join(PATH_mygui,'MyGUIEngine','include')
+PATH_INCLUDE_canvas= PATH_canvas
PATH_INCLUDE_OggVorbisTheora = [ os.path.join(BASE_DIR,'ogg','include')
,os.path.join(BASE_DIR, 'vorbis', 'include')
Modified: trunk/python-ogre/PythonOgreConfig_posix.py
===================================================================
--- trunk/python-ogre/PythonOgreConfig_posix.py 2008-12-04 13:12:10 UTC (rev 826)
+++ trunk/python-ogre/PythonOgreConfig_posix.py 2008-12-05 07:18:28 UTC (rev 827)
@@ -82,6 +82,7 @@
PATH_hydrax = os.path.join(PATH_THIRDPARTY, 'Hydrax')
PATH_hikari = os.path.join(PATH_THIRDPARTY, 'Hikari' ) # BASE_DIR, 'hikari', 'hikari')
PATH_mygui = os.path.join(BASE_DIR, 'MyGUI_2.2.0_RC1_source' )
+PATH_canvas = os.path.join(PATH_THIRDPARTY, 'canvas')
###
### these paths assume you've left all the directory structure as standard
@@ -122,6 +123,7 @@
PATH_LIB_opensteer = os.path.join(LOCAL_LIB)
PATH_LIB_hikari = os.path.join(PATH_hikari ) #, 'lib')
PATH_LIB_mygui = os.path.join(PATH_mygui, 'MyGUIEngine','lib','Release')
+PATH_LIB_canvas = os.path.join(PATH_canvas )
PATH_INCLUDE_Ogre= os.path.join(LOCAL_INCLUDE,'OGRE') # os.path.join(PATH_Ogre,'OgreMain/include')
PATH_INCLUDE_Ogre_Dependencies = PATH_INCLUDE_Ogre # os.path.join( PATH_Ogre, 'Dependencies/include')
@@ -194,4 +196,5 @@
PATH_INCLUDE_hydrax= PATH_hydrax
PATH_INCLUDE_hikari = os.path.join(PATH_hikari ) #, 'include')
PATH_INCLUDE_mygui = os.path.join(PATH_mygui,'MyGUIEngine','include')
+PATH_INCLUDE_canvas= PATH_canvas
Modified: trunk/python-ogre/ReportVersion.py
===================================================================
--- trunk/python-ogre/ReportVersion.py 2008-12-04 13:12:10 UTC (rev 826)
+++ trunk/python-ogre/ReportVersion.py 2008-12-05 07:18:28 UTC (rev 827)
@@ -28,7 +28,7 @@
'ogre.addons.noise', 'ogre.addons.watermesh',
'ogre.addons.particleuniverse', 'ogre.addons.cadunetree',
'ogre.renderer.ogrepcz', 'ogre.addons.hydrax',
- 'ogre.gui.hikari' )
+ 'ogre.gui.hikari','ogre.gui.canvas','ogre.gui.mygui' )
# bm.setupLogging("version.info") # options.logfilename)
# logger = logging.getLogger('PythonOgre.ReportVersionInfo')
Added: trunk/python-ogre/ThirdParty/canvas/Atlas.cpp
===================================================================
--- trunk/python-ogre/ThirdParty/canvas/Atlas.cpp (rev 0)
+++ trunk/python-ogre/ThirdParty/canvas/Atlas.cpp 2008-12-05 07:18:28 UTC (rev 827)
@@ -0,0 +1,515 @@
+/*
+ This file is part of Canvas, a fast, lightweight 2D graphics engine for Ogre3D.
+
+ Copyright (C) 2008 Adam J. Simmons
+ ajs...@gm...
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "Atlas.h"
+namespace CanvasNS
+{
+/************************
+* TextureInfo
+************************/
+
+TextureInfo::TextureInfo() : isEmpty(true), width(0), height(0)
+{
+}
+
+TextureInfo::TextureInfo(int atlasWidth, int atlasHeight, int x, int y, int width, int height) : isEmpty(false), width(width), height(height)
+{
+ texCoords.left = x / (float)atlasWidth;
+ texCoords.top = y / (float)atlasHeight;
+ texCoords.right = (x + width) / (float)atlasWidth;
+ texCoords.bottom = (y + height) / (float)atlasHeight;
+}
+
+/************************
+* GlyphInfo
+************************/
+
+GlyphInfo::GlyphInfo() : bearingX(0), bearingY(0), advance(0)
+{
+}
+
+GlyphInfo::GlyphInfo(Ogre::Real bearingX, Ogre::Real bearingY, Ogre::Real advance)
+ : bearingX(bearingX), bearingY(bearingY), advance(advance)
+{
+}
+
+/************************
+* FontMetrics
+************************/
+
+FontMetrics::FontMetrics() : ascender(0), descender(0), height(0), maxAdvance(0)
+{
+}
+
+FontMetrics::FontMetrics(Ogre::Real ascender, Ogre::Real descender, Ogre::Real height, Ogre::Real maxAdvance)
+ : ascender(ascender), descender(descender), height(height), maxAdvance(maxAdvance)
+{
+
+}
+
+/************************
+* CharCodeRange
+************************/
+
+const CharCodeRange CharCodeRange::BasicLatin = CharCodeRange(32, 166);
+const CharCodeRange CharCodeRange::Latin1 = CharCodeRange(32, 255);
+const CharCodeRange CharCodeRange::All = CharCodeRange();
+
+CharCodeRange::CharCodeRange()
+{
+}
+
+CharCodeRange::CharCodeRange(CharCode from, CharCode to)
+{
+ addRange(from, to);
+}
+
+void CharCodeRange::addRange(CharCode from, CharCode to)
+{
+ ranges.push_back(std::pair<CharCode, CharCode>(from, to));
+}
+
+bool CharCodeRange::isWithinRange(CharCode code) const
+{
+ if(ranges.empty())
+ return true;
+
+ for(std::vector<std::pair<CharCode, CharCode> >::const_iterator i = ranges.begin(); i != ranges.end(); i++)
+ {
+ if(code >= i->first && code <= i->second)
+ return true;
+ }
+
+ return false;
+}
+
+/************************
+* ComputationRect
+************************/
+
+ComputationRect::ComputationRect(const Ogre::String& texFilename, const Ogre::String& resourceGroup)
+ : x(0), y(0), isPlaced(false), isFontGlyph(false), filename(texFilename)
+{
+ image.load(texFilename, resourceGroup);
+ width = (int)image.getWidth();
+ height = (int)image.getHeight();
+ area = width * height;
+}
+
+ComputationRect::ComputationRect(const Ogre::String& texName, unsigned char* buffer, int width, int height)
+ : x(0), y(0), isPlaced(false), isFontGlyph(false), filename(texName)
+{
+ image.loadDynamicImage(buffer, width, height, 1, Ogre::PF_BYTE_BGRA, true);
+ this->width = (int)image.getWidth();
+ this->height = (int)image.getHeight();
+ area = this->width * this->height;
+}
+
+ComputationRect::ComputationRect(const Ogre::String& fontFilename, Ogre::uint fontSize, CharCode charCode, unsigned char* buffer, int width, int height)
+ : x(0), y(0), isPlaced(false), isFontGlyph(true), filename(fontFilename), fontSize(fontSize), charCode(charCode)
+{
+ image.loadDynamicImage(buffer, width, height, 1, Ogre::PF_BYTE_LA, true);
+ this->width = (int)image.getWidth();
+ this->height = (int)image.getHeight();
+ area = this->width * this->height;
+}
+
+/************************
+* FontFaceDefinition
+************************/
+
+FontFaceDefinition::FontFaceDefinition(const Ogre::String& filename, const CharCodeRange& codeRange, short renderType) : filename(filename), codeRange(codeRange), renderType(renderType)
+{
+}
+
+void FontFaceDefinition::addSize(Ogre::uint fontSize)
+{
+ sizes.push_back(fontSize);
+}
+
+/************************
+* FontFace
+************************/
+
+FontFace::FontFace()
+{
+}
+
+FontFace::FontFace(const FontFaceDefinition& definition, const Ogre::String& resourceGroup, ComputationVector& renderContext)
+{
+ FT_Library library;
+ FT_Face face;
+ FT_Error error;
+
+ error = FT_Init_FreeType(&library);
+ if(error)
+ OGRE_EXCEPT(Ogre::Exception::ERR_INTERNAL_ERROR, "Could not load FreeType library.", "FontFace::FontFace");
+
+ Ogre::DataStreamPtr dataStream = Ogre::ResourceGroupManager::getSingleton().openResource(definition.filename, resourceGroup);
+ Ogre::MemoryDataStream stream(dataStream);
+
+ error = FT_New_Memory_Face(library, stream.getPtr(), (FT_Long)stream.size(), 0, &face);
+ if(error)
+ OGRE_EXCEPT(Ogre::Exception::ERR_INTERNAL_ERROR, "FreeType could not load a font-face.", "FontFace::FontFace");
+
+
+ for(std::vector<Ogre::uint>::const_iterator i = definition.sizes.begin(); i != definition.sizes.end(); i++)
+ {
+ FT_ULong charCode = 0;
+ FT_UInt glyphIndex = 1;
+
+ error = FT_Set_Pixel_Sizes(face, 0, (FT_UInt)*i);
+ if(error)
+ OGRE_EXCEPT(Ogre::Exception::ERR_INTERNAL_ERROR, "FreeType could not set a font-size.", "FontFace::FontFace");
+
+ fontMetrics[*i] = FontMetrics(face->size->metrics.ascender / 64.0f, face->size->metrics.descender / 64.0f,
+ face->size->metrics.height / 64.0f, face->size->metrics.max_advance / 64.0f);
+
+ for(charCode = FT_Get_First_Char(face, &glyphIndex); glyphIndex != 0; charCode = FT_Get_Next_Char(face, charCode, &glyphIndex))
+ {
+ if(!definition.codeRange.isWithinRange(charCode))
+ continue;
+
+ if(definition.renderType == FontFaceDefinition::BetterContrast)
+ {
+ error = FT_Load_Glyph(face, glyphIndex, FT_LOAD_DEFAULT);
+ if(error)
+ continue;
+
+ error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
+ if(error)
+ continue;
+ }
+ else
+ {
+ error = FT_Load_Glyph(face, glyphIndex, FT_LOAD_TARGET_LIGHT);
+ if(error)
+ continue;
+
+ error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_LIGHT);
+ if(error)
+ continue;
+ }
+
+ FT_Bitmap& bitmap = face->glyph->bitmap;
+ FT_Glyph_Metrics& metrics = face->glyph->metrics;
+
+ if(!bitmap.buffer || (!bitmap.rows && !bitmap.width))
+ continue;
+
+ unsigned char* buffer = new unsigned char[bitmap.rows * bitmap.pitch * 2];
+
+ for(int idx = 0; idx < bitmap.rows * bitmap.pitch; idx++)
+ {
+ buffer[idx * 2] = 255;
+ buffer[idx * 2 + 1] = bitmap.buffer[idx];
+ }
+
+ fontSizes[*i][charCode] = GlyphInfo(metrics.horiBearingX / 64.0f, metrics.horiBearingY / 64.0f, metrics.horiAdvance / 64.0f);
+
+ renderContext.push_back(new ComputationRect(definition.filename, (Ogre::uint)*i, charCode, buffer, bitmap.pitch, bitmap.rows));
+ }
+ }
+}
+
+/************************
+* Atlas
+************************/
+
+Atlas::Atlas(const std::vector<Ogre::String>& textureFilenames, const std::vector<FontFaceDefinition>& fonts, const Ogre::String& resourceGroup)
+{
+ Ogre::LogManager::getSingleton().logMessage("Loading an Atlas.");
+ Ogre::Timer timer;
+
+ ComputationVector rectangles;
+
+ for(std::vector<FontFaceDefinition>::const_iterator i = fonts.begin(); i != fonts.end(); i++)
+ {
+ fontFaces[i->filename] = FontFace(*i, resourceGroup, rectangles);
+ }
+
+ for(std::vector<Ogre::String>::const_iterator i = textureFilenames.begin(); i != textureFilenames.end(); i++)
+ {
+ rectangles.push_back(new ComputationRect(*i, resourceGroup));
+ }
+
+ unsigned char* vcolBuffer = new unsigned char[16];
+ memset(vcolBuffer, 255, 16);
+
+ rectangles.push_back(new ComputationRect("VertexColor", vcolBuffer, 2, 2));
+
+ guessDimensions(rectangles);
+ pack(rectangles);
+ paint(rectangles);
+
+ int glyphCount = 0;
+ int texCount = -1; // Subtract the default VertexColor texture
+ ComputationRect* rect;
+
+ for(ComputationVector::iterator i = rectangles.begin(); i != rectangles.end(); i++)
+ {
+ rect = (*i);
+
+ if(rect->isFontGlyph)
+ {
+ fontFaces[rect->filename].fontSizes[rect->fontSize][rect->charCode].texInfo = TextureInfo(dimensions.first, dimensions.second, rect->x, rect->y, rect->width, rect->height);
+ glyphCount++;
+ }
+ else
+ {
+ textures[rect->filename] = TextureInfo(dimensions.first, dimensions.second, rect->x, rect->y, rect->width, rect->height);
+ texCount++;
+ }
+
+ delete rect;
+ }
+
+ Ogre::LogManager::getSingleton().logMessage("Atlas loaded in " + Ogre::StringConverter::toString(timer.getMilliseconds() / 1000.0f) +
+ "s. Packed " + Ogre::StringConverter::toString(glyphCount) + " font glyphs and " + Ogre::StringConverter::toString(texCount) +
+ " textures into " + Ogre::StringConverter::toString(dimensions.first) + "x" + Ogre::StringConverter::toString(dimensions.second));
+}
+
+const std::pair<int, int>& Atlas::getDimensions() const
+{
+ return dimensions;
+}
+
+const Ogre::String& Atlas::getMaterialName() const
+{
+ return materialName;
+}
+
+const TextureInfo& Atlas::getTextureInfo(const Ogre::String& filename) const
+{
+ std::map<Ogre::String, TextureInfo>::const_iterator i = textures.find(filename);
+ static TextureInfo empty;
+
+ if(i != textures.end())
+ return i->second;
+
+ return empty;
+}
+
+const FontMetrics& Atlas::getFontMetrics(const Ogre::String& fontFilename, Ogre::uint fontSize) const
+{
+ std::map<Ogre::String, FontFace>::const_iterator font = fontFaces.find(fontFilename);
+ static FontMetrics empty;
+
+ if(font == fontFaces.end())
+ return empty;
+
+ FontMetricsMap::const_iterator iter = font->second.fontMetrics.find(fontSize);
+
+ if(iter == font->second.fontMetrics.end())
+ return empty;
+
+ return iter->second;
+}
+
+const GlyphMap& Atlas::getGlyphMap(const Ogre::String& fontFilename, Ogre::uint fontSize) const
+{
+ std::map<Ogre::String, FontFace>::const_iterator font = fontFaces.find(fontFilename);
+ static GlyphMap empty;
+
+ if(font == fontFaces.end())
+ return empty;
+
+ FontSizeMap::const_iterator size = font->second.fontSizes.find(fontSize);
+
+ if(size == font->second.fontSizes.end())
+ return empty;
+
+ return size->second;
+}
+
+const GlyphInfo& Atlas::getGlyphInfo(const Ogre::String& fontFilename, Ogre::uint fontSize, CharCode charCode) const
+{
+ std::map<Ogre::String, FontFace>::const_iterator font = fontFaces.find(fontFilename);
+ static GlyphInfo empty;
+
+ if(font == fontFaces.end())
+ return empty;
+
+ FontSizeMap::const_iterator size = font->second.fontSizes.find(fontSize);
+
+ if(size == font->second.fontSizes.end())
+ return empty;
+
+ GlyphMap::const_iterator glyph = size->second.find(charCode);
+
+ if(glyph == size->second.end())
+ return empty;
+
+ return glyph->second;
+}
+
+void Atlas::guessDimensions(const ComputationVector& rectangles)
+{
+ int totalArea = 0;
+ int maxWidth = 0;
+ int maxHeight = 0;
+
+ for(ComputationVector::const_iterator i = rectangles.begin(); i != rectangles.end(); i++)
+ {
+ totalArea += (*i)->area;
+ maxWidth = std::max(maxWidth, (*i)->width);
+ maxHeight = std::max(maxHeight, (*i)->height);
+ }
+
+ int squareRoot = (int)sqrt((double)totalArea);
+
+ dimensions.first = Ogre::Bitwise::firstPO2From(std::max(squareRoot, maxWidth));
+ dimensions.second = Ogre::Bitwise::firstPO2From(std::max(squareRoot, maxHeight));
+}
+
+void Atlas::pack(ComputationVector& rectangles)
+{
+ struct compare { bool operator()(ComputationRect* a, ComputationRect* b){ return(a->area > b->area); }};
+ std::sort(rectangles.begin(), rectangles.end(), compare());
+
+ while(true)
+ {
+ for(ComputationVector::iterator i = rectangles.begin(); i != rectangles.end(); i++)
+ {
+ (*i)->isPlaced = false;
+ (*i)->x = -1;
+ (*i)->y = -1;
+ }
+
+ int successCount = 0;
+ fill(rectangles, 0, 0, dimensions.first - 1, dimensions.second - 1, successCount);
+
+ if(successCount == (int)rectangles.size())
+ break;
+
+ static bool toggle = false;
+ toggle = !toggle;
+
+ if(toggle)
+ dimensions.first = Ogre::Bitwise::firstPO2From(dimensions.first + 1);
+ else
+ dimensions.second = Ogre::Bitwise::firstPO2From(dimensions.second + 1);
+ }
+}
+
+void Atlas::fill(ComputationVector& rectangles, int x1, int y1, int x2, int y2, int& count)
+{
+ ComputationVector::iterator iter;
+
+ for(iter = rectangles.begin(); iter != rectangles.end(); iter++)
+ {
+ if((!(*iter)->isPlaced) && (x2 - x1 + 1 >= (*iter)->width) && (y2 - y1 + 1 >= (*iter)->height))
+ break;
+ }
+
+ if(iter == rectangles.end())
+ return;
+
+ ComputationRect* rect = *iter;
+
+ rect->x = x1;
+ rect->y = y1;
+ rect->isPlaced = true;
+ count++;
+
+ int aRight = (x2 - x1 + 1 - rect->width) * rect->height;
+ int aDown = (y2 - y1 + 1 - rect->height) * rect->width;
+ if(aRight < aDown)
+ {
+ if(y1 + rect->height < y2)
+ fill(rectangles, x1, y1 + rect->height, x2, y2, count);
+
+ if((x1 + rect->width < x2) && (y1 < y1 + rect->height - 1))
+ fill(rectangles, x1 + rect->width, y1, x2, y1 + rect->height - 1, count);
+ }
+ else
+ {
+ if(x1 + rect->width < x2)
+ fill(rectangles, x1 + rect->width, y1, x2, y2, count);
+
+ if((y1 + rect->height < y2) && (x1 < x1 + rect->width - 1))
+ fill(rectangles, x1, y1 + rect->height, x1 + rect->width - 1, y2, count);
+ }
+}
+
+void Atlas::paint(const ComputationVector& rectangles)
+{
+ static unsigned int count = 0;
+ Ogre::String texName = "AtlasTexture_" + Ogre::StringConverter::toString(count);
+ materialName = "AtlasMaterial_" + Ogre::StringConverter::toString(count);
+
+ Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().createManual(
+ texName, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
+ Ogre::TEX_TYPE_2D, dimensions.first, dimensions.second, 0, Ogre::PF_BYTE_BGRA,
+ Ogre::TU_STATIC_WRITE_ONLY);
+
+ Ogre::HardwarePixelBufferSharedPtr pixelBuffer = texture->getBuffer();
+ pixelBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD);
+ const Ogre::PixelBox& pixelBox = pixelBuffer->getCurrentLock();
+ size_t dstBpp = Ogre::PixelUtil::getNumElemBytes(pixelBox.format);
+ size_t dstPitch = pixelBox.rowPitch * dstBpp;
+
+ Ogre::uint8* dstData = static_cast<Ogre::uint8*>(pixelBox.data);
+
+ for(ComputationVector::const_iterator i = rectangles.begin(); i != rectangles.end(); i++)
+ {
+ unsigned char* conversionBuf = 0;
+ Ogre::PixelBox srcPixels = (*i)->image.getPixelBox();
+
+ if((*i)->image.getFormat() != Ogre::PF_BYTE_BGRA)
+ {
+ conversionBuf = new unsigned char[(*i)->image.getWidth() * (*i)->image.getHeight() * dstBpp];
+ Ogre::PixelBox convPixels(Ogre::Box(0, 0, (*i)->width, (*i)->height), Ogre::PF_BYTE_BGRA, conversionBuf);
+ Ogre::PixelUtil::bulkPixelConversion((*i)->image.getPixelBox(), convPixels);
+ srcPixels = convPixels;
+ }
+
+ size_t srcPitch = srcPixels.rowPitch * dstBpp;
+ Ogre::uint8* srcData = static_cast<Ogre::uint8*>(srcPixels.data);
+
+ for(size_t row = 0; row < (*i)->image.getHeight(); row++)
+ {
+ for(size_t col = 0; col < srcPitch; col++)
+ {
+ dstData[((row + (*i)->y) * dstPitch) + ((*i)->x * dstBpp) + col] = srcData[(row * srcPitch) + col];
+ }
+ }
+
+ if(conversionBuf)
+ delete[] conversionBuf;
+ }
+
+ pixelBuffer->unlock();
+
+ Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().create(materialName,
+ Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
+ Ogre::Pass* pass = material->getTechnique(0)->getPass(0);
+ pass->setDepthCheckEnabled(false);
+ pass->setDepthWriteEnabled(false);
+ pass->setLightingEnabled(false);
+ pass->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA);
+
+ Ogre::TextureUnitState* texUnit = pass->createTextureUnitState(texName);
+ texUnit->setTextureFiltering(Ogre::FO_NONE, Ogre::FO_NONE, Ogre::FO_NONE);
+
+ count++;
+}
+} // namespace
Added: trunk/python-ogre/ThirdParty/canvas/Atlas.h
===================================================================
--- trunk/python-ogre/ThirdParty/canvas/Atlas.h (rev 0)
+++ trunk/python-ogre/ThirdParty/canvas/Atlas.h 2008-12-05 07:18:28 UTC (rev 827)
@@ -0,0 +1,270 @@
+/*
+ This file is part of Canvas, a fast, lightweight 2D graphics engine for Ogre3D.
+
+ Copyright (C) 2008 Adam J. Simmons
+ ajs...@gm...
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef __Atlas__
+#define __Atlas__
+
+#include "Ogre.h"
+#include "OgreBitwise.h"
+#include <map>
+#include <vector>
+#include <algorithm>
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_GLYPH_H
+
+namespace CanvasNS
+{
+/**
+* TextureInfo represents a texture within an Atlas instance.
+* Contains the actual dimensions of a texture and its location within the atlas.
+*/
+struct TextureInfo
+{
+ bool isEmpty;
+ Ogre::FloatRect texCoords;
+ int width, height;
+
+ TextureInfo();
+ TextureInfo(int atlasWidth, int atlasHeight, int x, int y, int width, int height);
+};
+
+/**
+* GlyphInfo represents a glyph within an Atlas instance.
+* Contains glyph metrics which can be used for text layout purposes.
+* See: http://freetype.sourceforge.net/freetype2/docs/glyphs/glyphs-3.html
+*/
+struct GlyphInfo
+{
+ Ogre::Real bearingX;
+ Ogre::Real bearingY;
+ Ogre::Real advance;
+
+ TextureInfo texInfo;
+
+ GlyphInfo();
+ GlyphInfo(Ogre::Real bearingX, Ogre::Real bearingY, Ogre::Real advance);
+};
+
+/**
+* FontMetrics represents the scaled global metrics for a certain font size.
+* Contains font metrics which can be used for text layout purposes.
+*
+* <ul>
+* <li>ascender - The typographic ascender of the face, expressed in Real pixels.
+* <li>descender - The typographic descender of the face, expressed in Real pixels.
+* <li>height - The height is the vertical distance between two consecutive baselines, expressed in Real pixels.
+* <li>maxAdvance - The maximal advance width, in Real pixels, for all glyphs in this face. This can be used to make word wrapping computations faster.
+* </ul>
+*/
+struct FontMetrics
+{
+ Ogre::Real ascender;
+ Ogre::Real descender;
+ Ogre::Real height;
+ Ogre::Real maxAdvance;
+
+ FontMetrics();
+ FontMetrics(Ogre::Real ascender, Ogre::Real descender, Ogre::Real height, Ogre::Real maxAdvance);
+};
+
+typedef Ogre::uint32 CharCode;
+
+/**
+* CharCodeRange is used to specify the ranges of characters that a font should load.
+* For convenience, two common unicode ranges (BasicLatin & Latin1) have been already defined.
+*/
+struct CharCodeRange
+{
+ std::vector<std::pair<CharCode, CharCode> > ranges;
+
+ CharCodeRange();
+ CharCodeRange(CharCode from, CharCode to);
+
+ /**
+ * Add a range of characters to the definition.
+ *
+ * @param from The beginning of the range, inclusive.
+ * @param to The end of the range, inclusive.
+ */
+ void addRange(CharCode from, CharCode to);
+
+ /**
+ * Test if a character code is within this CharCodeRange.
+ *
+ * @return True if a character code is within any of the ranges, false otherwise.
+ */
+ bool isWithinRange(CharCode code) const;
+
+ static const CharCodeRange BasicLatin;
+ static const CharCodeRange Latin1;
+ static const CharCodeRange All;
+};
+
+/**
+* Defines a font-face for Atlas initialization purposes.
+*/
+struct FontFaceDefinition
+{
+ Ogre::String filename;
+ std::vector<Ogre::uint> sizes;
+ CharCodeRange codeRange;
+ short renderType;
+
+ /**
+ * Specifies the type of rendering that this font should use.
+ * <ul>
+ * <li>BetterContrast - Sharper text, more like Windows' font rendering.
+ * <li>BetterShape - Smoother text, more like MacOSX's font rendering.
+ * </ul>
+ */
+ enum RenderType
+ {
+ BetterContrast,
+ BetterShape
+ };
+
+ /**
+ * Constructs a FontFaceDefinition
+ *
+ * @param filename The filename of the font-face.
+ * @param codeRange The range of CharCode's to render for this font-face.
+ * @param renderType Optional; the type of rendering to use for this font-face.
+ */
+ FontFaceDefinition(const Ogre::String& filename, const CharCodeRange& codeRange = CharCodeRange::BasicLatin, short renderType = FontFaceDefinition::BetterContrast);
+
+ /**
+ * Adds a font-size (in px) to this font-face definition.
+ */
+ void addSize(Ogre::uint fontSize);
+};
+
+struct ComputationRect
+{
+ int width, height;
+ int x, y;
+ int area;
+ bool isPlaced;
+
+ Ogre::String filename;
+ bool isFontGlyph;
+ Ogre::uint fontSize;
+ CharCode charCode;
+
+ Ogre::Image image;
+
+ ComputationRect(const Ogre::String& texFilename, const Ogre::String& resourceGroup);
+ ComputationRect(const Ogre::String& texName, unsigned char* buffer, int width, int height);
+ ComputationRect(const Ogre::String& fontFilename, Ogre::uint fontSize, CharCode charCode, unsigned char* buffer, int width, int height);
+
+};
+
+typedef std::vector<ComputationRect*> ComputationVector;
+
+typedef std::map<CharCode, GlyphInfo> GlyphMap;
+typedef std::map<Ogre::uint, GlyphMap> FontSizeMap;
+typedef std::map<Ogre::uint, FontMetrics> FontMetricsMap;
+
+struct FontFace
+{
+ FontSizeMap fontSizes;
+ FontMetricsMap fontMetrics;
+
+ FontFace();
+
+ FontFace(const FontFaceDefinition& definition, const Ogre::String& resourceGroup, ComputationVector& renderContext);
+};
+
+/**
+* The work-horse of Canvas; Atlas is a programmatic texture-atlas that can hold textures and font-glyphs.
+*/
+class Atlas
+{
+ std::map<Ogre::String, FontFace> fontFaces;
+ std::map<Ogre::String, TextureInfo> textures;
+ std::pair<int, int> dimensions;
+ Ogre::String materialName;
+
+ void guessDimensions(const ComputationVector& rectangles);
+ void pack(ComputationVector& rectangles);
+ void fill(ComputationVector& rectangles, int x1, int y1, int x2, int y2, int& count);
+ void paint(const ComputationVector& rectangles);
+
+public:
+ /**
+ * Constructs an Atlas.
+ *
+ * @param textureFilenames The filenames of the textures to load into this atlas.
+ * @param fonts The fonts to load into this atlas.
+ * @param resourceGroup The name of the resource group where the textures and fonts can be found.
+ */
+ Atlas(const std::vector<Ogre::String>& textureFilenames, const std::vector<FontFaceDefinition>& fonts, const Ogre::String& resourceGroup);
+
+ /**
+ * Retrieve the dimensions of this atlas, in pixels.
+ */
+ const std::pair<int, int>& getDimensions() const;
+
+ /**
+ * Retrieve the name of the internal material
+ */
+ const Ogre::String& getMaterialName() const;
+
+ /**
+ * Retrieve info about a certain texture within this atlas.
+ *
+ * @note If the filename is not found, the returned TextureInfo's member "isEmpty" will be true.
+ *
+ * @param filename The filename of the texture to look up.
+ */
+ const TextureInfo& getTextureInfo(const Ogre::String& filename) const;
+
+ /**
+ * Retrieve the metrics for a certain font size.
+ *
+ * @param fontFilename The filename of the font to look up.
+ * @param fontSize The font size to look up.
+ */
+ const FontMetrics& getFontMetrics(const Ogre::String& fontFilename, Ogre::uint fontSize) const;
+
+ /**
+ * Retrieve the GlyphMap for a certain font size.
+ *
+ * @param fontFilename The filename of the font to look up.
+ * @param fontSize The font size to look up.
+ */
+ const GlyphMap& getGlyphMap(const Ogre::String& fontFilename, Ogre::uint fontSize) const;
+
+ /**
+ * Retrieve info about a certain font glyph within this atlas.
+ *
+ * @param fontFilename The filename of the font-face.
+ * @param fontSize The size of the font.
+ * @param charCode The CharCode to look up.
+ *
+ * @note If the filename, size, or CharCode is not found, the returned GlyphInfo will contain a TextureInfo with
+ * the member "isEmpty" set to true.
+ */
+ const GlyphInfo& getGlyphInfo(const Ogre::String& fontFilename, Ogre::uint fontSize, CharCode charCode) const;
+};
+} //namespace
+#endif
Added: trunk/python-ogre/ThirdParty/canvas/Canvas.cpp
===================================================================
--- trunk/python-ogre/ThirdParty/canvas/Canvas.cpp (rev 0)
+++ trunk/python-ogre/ThirdParty/canvas/Canvas.cpp 2008-12-05 07:18:28 UTC (rev 827)
@@ -0,0 +1,692 @@
+/*
+ This file is part of Canvas, a fast, lightweight 2D graphics engine for Ogre3D.
+
+ Copyright (C) 2008 Adam J. Simmons
+ ajs...@gm...
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "Canvas.h"
+
+using namespace Ogre;
+
+namespace CanvasNS
+{
+/************************
+* Fill
+************************/
+
+Fill::Fill() : isEmpty(true)
+{
+}
+
+Fill::Fill(const Ogre::ColourValue& color) : isEmpty(false), atlasKey("VertexColor")
+{
+ coloring.colors.first = color;
+ coloring.hasGradient = false;
+}
+
+Fill::Fill(const Ogre::ColourValue& gradientColor1, const Ogre::ColourValue& gradientColor2, short orientation) : isEmpty(false), atlasKey("VertexColor")
+{
+ coloring.colors.first = gradientColor1;
+ coloring.colors.second = gradientColor2;
+ coloring.hasGradient = true;
+ coloring.orientation = orientation;
+}
+
+Fill::Fill(const Ogre::String& texture, const Ogre::ColourValue& color) : isEmpty(false), atlasKey(texture)
+{
+ coloring.colors.first = color;
+ coloring.hasGradient = false;
+}
+
+Fill::Fill(const Ogre::String& texture, const Ogre::ColourValue& gradientColor1, const Ogre::ColourValue& gradientColor2, short orientation) : isEmpty(false), atlasKey(texture)
+{
+ coloring.colors.first = gradientColor1;
+ coloring.colors.second = gradientColor2;
+ coloring.hasGradient = true;
+ coloring.orientation = orientation;
+}
+
+/************************
+* Border
+************************/
+
+Border::Border() : isEmpty(true)
+{
+}
+
+Border::Border(int width, const Ogre::ColourValue& color) : widths(width, width, width, width), colors(color, color, color, color), isEmpty(false)
+{
+}
+
+Border::Border(const WidthRect& widths, const ColorRect& colors) : widths(widths), colors(colors), isEmpty(false)
+{
+}
+
+/************************
+* Canvas
+************************/
+
+Canvas::Canvas(Atlas* atlas, Ogre::Viewport* viewport) : atlas(atlas), viewport(viewport), vertexData(0), indexData(0),
+ bufferSize(100), renderQueueID(Ogre::RENDER_QUEUE_OVERLAY), isDirty(false), visibility(true)
+{
+ viewport->getTarget()->addListener(this);
+ material = Ogre::MaterialManager::getSingleton().getByName(atlas->getMaterialName());
+ setUseIdentityProjection(true);
+ setUseIdentityView(true);
+
+ resizeBuffers();
+ clearClip();
+}
+
+
+Canvas::~Canvas()
+{
+ destroyBuffers();
+ viewport->getTarget()->removeListener(this);
+}
+
+void Canvas::drawRectangle(int x, int y, int width, int height, const Fill& fill, const Border& border)
+{
+ PixelRect rect(x, y, x + width, y + height);
+
+ if(border.isEmpty)
+ {
+ if(isOutsideClip(rect))
+ return;
+ }
+ else
+ {
+ if(isOutsideClip(PixelRect(rect.left - border.widths.left, rect.top - border.widths.top, rect.right + border.widths.right, rect.bottom + border.widths.bottom)))
+ return;
+ }
+
+ if(!fill.isEmpty)
+ {
+ TextureInfo texInfo = atlas->getTextureInfo(fill.atlasKey);
+ if(texInfo.isEmpty)
+ return;
+
+ // Draw a simple rectangle with the normal texture-coordinates at each corner
+ if(fill.atlasKey == "VertexColor" || (width == texInfo.width && height == texInfo.height))
+ {
+ drawQuad(rect, texInfo.texCoords, fill.coloring);
+ }
+ else // Draw a tiled rectangle, may contain multiple quads to give the illusion that the texture is "tiling"
+ {
+ Ogre::Real xMax = width / (double)texInfo.width;
+ Ogre::Real yMax = height / (double)texInfo.height;
+
+ Ogre::Real right = 0;
+ Ogre::Real bottom = 0;
+
+ for(Ogre::Real left = 0; left < Ogre::Math::Ceil(xMax); left++)
+ {
+ for(Ogre::Real top = 0; top < Ogre::Math::Ceil(yMax); top++)
+ {
+ if(left + 1 > xMax)
+ right = xMax;
+ else
+ right = left + 1;
+
+ if(top + 1 > yMax)
+ bottom = yMax;
+ else
+ bottom = top + 1;
+
+ PixelRect tile(x + (left * texInfo.width), y + (top * texInfo.height), x + (right * texInfo.width), y + (bottom * texInfo.height));
+
+ if(isOutsideClip(tile))
+ continue;
+
+ Ogre::FloatRect texCoords = texInfo.texCoords;
+ texCoords.right = texCoords.left + (right - left) * (texCoords.width());
+ texCoords.bottom = texCoords.top + (bottom - top) * (texCoords.height());
+
+ Coloring coloring = fill.coloring;
+ if(coloring.hasGradient)
+ {
+ Ogre::Real amount1, amount2;
+
+ if(coloring.orientation == Coloring::Vertical)
+ {
+ amount1 = top / yMax;
+ amount2 = bottom / yMax;
+ }
+ else
+ {
+ amount1 = left / xMax;
+ amount2 = right / xMax;
+ }
+
+ coloring.colors.first = (fill.coloring.colors.first * (1 - amount1)) + (fill.coloring.colors.second * amount1);
+ coloring.colors.second = (fill.coloring.colors.first * (1 - amount2)) + (fill.coloring.colors.second * amount2);
+ }
+
+ drawQuad(tile, texCoords, coloring);
+ }
+ }
+ }
+ }
+
+ // Draw the four sides of the border, if present
+ if(!border.isEmpty)
+ {
+ Ogre::FloatRect vColCoords = atlas->getTextureInfo("VertexColor").texCoords;
+ Corners<Ogre::Vector2> corners;
+
+ PixelRect bRect(rect.left - border.widths.left, rect.top - border.widths.top, rect.right + border.widths.right, rect.bottom + border.widths.bottom);
+
+ // Left Border
+ if(!isOutsideClip(PixelRect(bRect.left, bRect.top, rect.left, bRect.bottom)))
+ {
+ corners.topLeft = Ogre::Vector2(bRect.left, bRect.top);
+ corners.bottomLeft = Ogre::Vector2(bRect.left, bRect.bottom);
+ corners.bottomRight = Ogre::Vector2(rect.left, rect.bottom);
+ corners.topRight = Ogre::Vector2(rect.left, rect.top);
+
+ drawQuad(corners, vColCoords, border.colors.left);
+ }
+
+ // Bottom Border
+ if(!isOutsideClip(PixelRect(bRect.left, rect.bottom, bRect.right, bRect.bottom)))
+ {
+ corners.topLeft = Ogre::Vector2(rect.left, rect.bottom);
+ corners.bottomLeft = Ogre::Vector2(bRect.left, bRect.bottom);
+ corners.bottomRight = Ogre::Vector2(bRect.right, bRect.bottom);
+ corners.topRight = Ogre::Vector2(rect.right, rect.bottom);
+
+ drawQuad(corners, vColCoords, border.colors.bottom);
+ }
+
+ // Right Border
+ if(!isOutsideClip(PixelRect(rect.right, bRect.top, bRect.right, bRect.bottom)))
+ {
+ corners.topLeft = Ogre::Vector2(rect.right, rect.top);
+ corners.bottomLeft = Ogre::Vector2(rect.right, rect.bottom);
+ corners.bottomRight = Ogre::Vector2(bRect.right, bRect.bottom);
+ corners.topRight = Ogre::Vector2(bRect.right, bRect.top);
+
+ drawQuad(corners, vColCoords, border.colors.right);
+ }
+
+ // Top Border
+ if(!isOutsideClip(PixelRect(bRect.left, bRect.top, bRect.right, rect.top)))
+ {
+ corners.topLeft = Ogre::Vector2(bRect.left, bRect.top);
+ corners.bottomLeft = Ogre::Vector2(rect.left, rect.top);
+ corners.bottomRight = Ogre::Vector2(rect.right, rect.top);
+ corners.topRight = Ogre::Vector2(bRect.right, bRect.top);
+
+ drawQuad(corners, vColCoords, border.colors.top);
+ }
+ }
+}
+
+void Canvas::drawGlyph(const GlyphInfo& glyph, int x, int y, int width, int height, const Ogre::ColourValue& color)
+{
+ if(glyph.texInfo.isEmpty)
+ return;
+
+ PixelRect rect(x, y, x + width, y + height);
+
+ if(isOutsideClip(rect))
+ return;
+
+ Coloring coloring;
+ coloring.colors.first = color;
+ coloring.hasGradient = false;
+
+ drawQuad(rect, glyph.texInfo.texCoords, coloring);
+}
+
+void Canvas::clear()
+{
+ quadList.clear();
+ isDirty = true;
+}
+
+void Canvas::setClip(int left, int top, int right, int bottom)
+{
+ clip.left = left;
+ clip.top = top;
+ clip.right = right;
+ clip.bottom = bottom;
+}
+
+void Canvas::clearClip()
+{
+ clip.left = 0;
+ clip.top = 0;
+ clip.right = viewport->getActualWidth();
+ clip.bottom = viewport->getActualHeight();
+}
+
+const Ogre::MaterialPtr& Canvas::getMaterial() const
+{
+ return material;
+}
+
+void Canvas::getRenderOperation(Ogre::RenderOperation& op)
+{
+ op.operationType = Ogre::RenderOperation::OT_TRIANGLE_LIST;
+
+ op.vertexData = vertexData;
+ op.vertexData->vertexStart = 0;
+ op.vertexData->vertexCount = quadList.size() * 4;
+
+ op.useIndexes = true;
+ op.indexData = indexData;
+ op.indexData->indexStart = 0;
+ op.indexData->indexCount = quadList.size() * 6;
+}
+
+void Canvas::getWorldTransforms(Ogre::Matrix4* xform) const
+{
+ xform[0] = this->_getParentNodeFullTransform();
+}
+
+const Ogre::Quaternion& Canvas::getWorldOrientation() const
+{
+ return this->getParentNode()->_getDerivedOrientation();
+}
+
+const Ogre::Vector3& Canvas::getWorldPosition() const
+{
+ return this->getParentNode()->_getDerivedPosition();
+}
+
+Ogre::Real Canvas::getSquaredViewDepth(const Ogre::Camera* cam) const
+{
+ Ogre::Node* node = this->getParentNode();
+ assert(node);
+ return node->getSquaredViewDepth(cam);
+}
+
+const Ogre::LightList& Canvas::getLights() const
+{
+ return this->queryLights();
+}
+
+const Ogre::String& Canvas::getMovableType() const
+{
+ static Ogre::String typeName("Canvas");
+
+ return typeName;
+}
+
+const Ogre::AxisAlignedBox& Canvas::getBoundingBox() const
+{
+ static Ogre::AxisAlignedBox box;
+ box.setInfinite();
+
+ return box;
+}
+
+Ogre::Real Canvas::getBoundingRadius() const
+{
+ return 2.0;
+}
+
+void Canvas::_updateRenderQueue(Ogre::RenderQueue* queue)
+{
+ resizeBuffers();
+ updateGeometry();
+
+ queue->addRenderable(this, renderQueueID);
+}
+
+void Canvas::setVisible(bool visible)
+{
+ mVisible = visibility = visible;
+}
+
+bool Canvas::isVisible() const
+{
+ if (!visibility || mBeyondFarDistance || mRenderingDisabled)
+ return false;
+
+ SceneManager* sm = Root::getSingleton()._getCurrentSceneManager();
+ if (sm && !(mVisibilityFlags & sm->_getCombinedVisibilityMask()))
+ return false;
+
+ return true;
+}
+
+void Canvas::preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt)
+{
+}
+
+void Canvas::postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt)
+{
+}
+
+void Canvas::preViewportUpdate(const Ogre::RenderTargetViewportEvent& evt)
+{
+ if(evt.source == viewport && mVisible)
+ visibility = true;
+}
+
+void Canvas::postViewportUpdate(const Ogre::RenderTargetViewportEvent& evt)
+{
+ if(evt.source == viewport && mVisible)
+ visibility = false;
+}
+
+void Canvas::viewportAdded(const Ogre::RenderTargetViewportEvent& evt)
+{
+}
+
+void Canvas::viewportRemoved(const Ogre::RenderTargetViewportEvent& evt)
+{
+}
+
+void Canvas::destroyBuffers()
+{
+ if(vertexData)
+ {
+ delete vertexData;
+ vertexData = 0;
+
+ buffer.setNull();
+ }
+
+ if(indexData)
+ {
+ delete indexData;
+ indexData = 0;
+ }
+}
+
+void Canvas::resizeBuffers()
+{
+ if(bufferSize < quadList.size())
+ {
+ bufferSize = quadList.size() * 2;
+ destroyBuffers();
+ }
+
+ if(!vertexData)
+ {
+ vertexData = new Ogre::VertexData();
+ vertexData->vertexStart = 0;
+ vertexData->vertexCount = bufferSize * 4;
+
+ Ogre::VertexDeclaration* decl = vertexData->vertexDeclaration;
+ Ogre::VertexBufferBinding* binding = vertexData->vertexBufferBinding;
+
+ size_t offset = 0;
+ decl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
+ offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
+ decl->addElement(0, offset, Ogre::VET_COLOUR, Ogre::VES_DIFFUSE);
+ offset += Ogre::VertexElement::getTypeSize(Ogre::VET_COLOUR);
+ decl->addElement(0, offset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, 0);
+
+ buffer = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(
+ decl->getVertexSize(0), vertexData->vertexCount, Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE);
+ binding->setBinding(0, buffer);
+ }
+
+ if(!indexData)
+ {
+ indexData = new Ogre::IndexData();
+ indexData->indexStart = 0;
+ indexData->indexCount = bufferSize * 6;
+
+ indexData->indexBuffer = Ogre::HardwareBufferManager::getSingleton().createIndexBuffer(
+ Ogre::HardwareIndexBuffer::IT_16BIT, indexData->indexCount, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY);
+
+ unsigned short* indexBuffer = (unsigned short*)indexData->indexBuffer->lock(0, indexData->indexBuffer->getSizeInBytes(), Ogre::HardwareBuffer::HBL_DISCARD);
+
+ // Indexes are generated here because we know that we will only be rendering quads
+ // This means that we only have to handle updating the vertex buffer in Canvas::updateGeometry
+ for(size_t indexIdx, vertexIdx, quadIdx = 0; quadIdx < bufferSize; quadIdx++)
+ {
+ indexIdx = quadIdx * 6;
+ vertexIdx = quadIdx * 4;
+
+ indexBuffer[indexIdx++] = (unsigned short)(vertexIdx + 0);
+ indexBuffer[indexIdx++] = (unsigned short)(vertexIdx + 2);
+ indexBuffer[indexIdx++] = (unsigned short)(vertexIdx + 1);
+ indexBuffer[indexIdx++] = (unsigned short)(vertexIdx + 1);
+ indexBuffer[indexIdx++] = (unsigned short)(vertexIdx + 2);
+ indexBuffer[indexIdx++] = (unsigned short)(vertexIdx + 3);
+ }
+
+ indexData->indexBuffer->unlock();
+ }
+}
+
+bool Canvas::isOutsideClip(const PixelRect& rect)
+{
+ if(rect.left > clip.right)
+ return true;
+ else if(rect.right < clip.left)
+ return true;
+ else if(rect.top > clip.bottom)
+ return true;
+ else if(rect.bottom < clip.top)
+ return true;
+
+ return false;
+}
+
+void Canvas::localize(Ogre::Vector2& vertex)
+{
+ Ogre::Real xTexel = Ogre::Root::getSingleton().getRenderSystem()->getHorizontalTexelOffset();
+ Ogre::Real yTexel = Ogre::Root::getSingleton().getRenderSystem()->getVerticalTexelOffset();
+
+ vertex.x = ((vertex.x + xTexel) / (Ogre::Real)viewport->getActualWidth()) * 2 - 1;
+ vertex.y = ((vertex.y + yTexel) / (Ogre::Real)viewport->getActualHeight()) * -2 + 1;
+}
+
+void Canvas::drawQuad(const PixelRect& rect, const Ogre::FloatRect& texCoords, const Coloring& coloring)
+{
+ PixelRect clipped;
+ Ogre::FloatRect clippedTexCoords(texCoords);
+ Coloring clippedColoring = coloring;
+
+ if(rect.left > clip.left)
+ {
+ clipped.left = rect.left;
+ }
+ else
+ {
+ clipped.left = clip.left;
+ Ogre::Real delta = (clipped.left - rect.left) / (float)rect.width();
+ clippedTexCoords.left += delta * texCoords.width();
+
+ if(coloring.hasGradient && coloring.orientation == Coloring::Horizontal)
+ clippedColoring.colors.first = (coloring.colors.first * (1 - delta)) + (coloring.colors.second * delta);
+ }
+
+ if(rect.top > clip.top)
+ {
+ clipped.top = rect.top;
+ }
+ else
+ {
+ clipped.top = clip.top;
+ Ogre::Real delta = (clipped.top - rect.top) / (float)rect.height();
+ clippedTexCoords.top += delta * texCoords.height();
+
+ if(coloring.hasGradient && coloring.orientation == Coloring::Vertical)
+ clippedColoring.colors.first = (coloring.colors.first * (1 - delta)) + (coloring.colors.second * delta);
+ }
+
+ if(rect.right < clip.right)
+ {
+ clipped.right = rect.right;
+ }
+ else
+ {
+ clipped.right = clip.right;
+ Ogre::Real delta = (clipped.right - rect.right) / (float)rect.width();
+ clippedTexCoords.right += delta * texCoords.width();
+
+ if(coloring.hasGradient && coloring.orientation == Coloring::Horizontal)
+ clippedColoring.colors.second = (coloring.colors.first * (-delta)) + (coloring.colors.second * (1 + delta));
+ }
+
+ if(rect.bottom < clip.bottom)
+ {
+ clipped.bottom = rect.bottom;
+ }
+ else
+ {
+ clipped.bottom = clip.bottom;
+ Ogre::Real delta = (clipped.bottom - rect.bottom) / (float)rect.height();
+ clippedTexCoords.bottom += delta * texCoords.height();
+
+ if(coloring.hasGradient && coloring.orientation == Coloring::Vertical)
+ clippedColoring.colors.second = (coloring.colors.first * (-delta)) + (coloring.colors.second * (1 + delta));
+ }
+
+ Canvas::Quad quad;
+ quad.vertices = Corners<Ogre::Vector2>(Ogre::Vector2(clipped.left, clipped.top), Ogre::Vector2(clipped.left, clipped.bottom),
+ Ogre::Vector2(clipped.right, clipped.bottom), Ogre::Vector2(clipped.right, clipped.top));
+
+ localize(quad.vertices.topLeft);
+ localize(quad.vertices.bottomLeft);
+ localize(quad.vertices.bottomRight);
+ localize(quad.vertices.topRight);
+
+ quad.texCoords.topLeft = Ogre::Vector2(clippedTexCoords.left, clippedTexCoords.top);
+ quad.texCoords.bottomLeft = Ogre::Vector2(clippedTexCoords.left, clippedTexCoords.bottom);
+ quad.texCoords.bottomRight = Ogre::Vector2(clippedTexCoords.right, clippedTexCoords.bottom);
+ quad.texCoords.topRight = Ogre::Vector2(clippedTexCoords.right, clippedTexCoords.top);
+
+ if(clippedColoring.hasGradient)
+ {
+ if(clippedColoring.orientation == Coloring::Vertical)
+ quad.colors = Corners<Ogre::ColourValue>(clippedColoring.colors.first, clippedColoring.colors.second, clippedColoring.colors.second, clippedColoring.colors.first);
+ else
+ quad.colors = Corners<Ogre::ColourValue>(clippedColoring.colors.first, clippedColoring.colors.first, clippedColoring.colors.second, clippedColoring.colors.second);
+ }
+ else
+ {
+ quad.colors = Corners<Ogre::ColourValue>(clippedColoring.colors.first);
+ }
+
+ quadList.push_back(quad);
+ isDirty = true;
+}
+
+void Canvas::drawQuad(const Corners<Ogre::Vector2>& corners, const Ogre::FloatRect& texCoords, const Ogre::ColourValue& color)
+{
+ Corners<Ogre::Vector2> clippedCorners;
+ clippedCorners.topLeft.x = corners.topLeft.x > clip.left ? corners.topLeft.x : clip.left;
+ clippedCorners.topLeft.y = corners.topLeft.y > clip.top ? corners.topLeft.y : clip.top;
+ clippedCorners.bottomLeft.x = corners.bottomLeft.x > clip.left ? corners.bottomLeft.x : clip.left;
+ clippedCorners.bottomLeft.y = corners.bottomLeft.y < clip.bottom ? corners.bottomLeft.y : clip.bottom;
+ clippedCorners.bottomRight.x = corners.bottomRight.x < clip.right ? corners.bottomRight.x : clip.right;
+ clippedCorners.bottomRight.y = corners.bottomRight.y < clip.bottom ? corners.bottomRight.y : clip.bottom;
+ clippedCorners.topRight.x = corners.topRight.x < clip.right ? corners.topRight.x : clip.right;
+ clippedCorners.topRight.y = corners.topRight.y > clip.top ? corners.topRight.y : clip.top;
+
+ Canvas::Quad quad;
+ quad.vertices = clippedCorners;
+
+ localize(quad.vertices.topLeft);
+ localize(quad.vertices.bottomLeft);
+ localize(quad.vertices.bottomRight);
+ localize(quad.vertices.topRight);
+
+ quad.texCoords.topLeft = Ogre::Vector2(texCoords.left, texCoords.top);
+ quad.texCoords.bottomLeft = Ogre::Vector2(texCoords.left, texCoords.bottom);
+ quad.texCoords.bottomRight = Ogre::Vector2(texCoords.right, texCoords.bottom);
+ quad.texCoords.topRight = Ogre::Vector2(texCoords.right, texCoords.top);
+
+ quad.colors = Corners<Ogre::ColourValue>(color);
+
+ quadList.push_back(quad);
+ isDirty = true;
+}
+
+void Canvas::updateGeometry()
+{
+ if(!isDirty)
+ return;
+
+ float* vBuffer = (float*)buffer->lock(0, quadList.size() * buffer->getVertexSize() * 4, Ogre::HardwareBuffer::HBL_DISCARD);
+
+ Ogre::RGBA color;
+ Ogre::RGBA* vBufferCol = 0;
+
+ for(std::vector<Canvas::Quad>::iterator i = quadList.begin(); i != quadList.end(); i++)
+ {
+ // Top-Left Vertex
+ *vBuffer++ = i->vertices.topLeft.x;
+ *vBuffer++ = i->vertices.topLeft.y;
+ *vBuffer++ = 0;
+
+ vBufferCol = (Ogre::RGBA*)vBuffer;
+ Ogre::Root::getSingleton().convertColourValue(i->colors.topLeft, &color);
+ *vBufferCol++ = color;
+
+ vBuffer = (float*)vBufferCol;
+
+ *vBuffer++ = i->texCoords.topLeft.x;
+ *vBuffer++ = i->texCoords.topLeft.y;
+
+ // Top-Right Vertex
+ *vBuffer++ = i->vertices.topRight.x;
+ *vBuffer++ = i->vertices.topRight.y;
+ *vBuffer++ = 0;
+
+ vBufferCol = (Ogre::RGBA*)vBuffer;
+ Ogre::Root::getSingleton().convertColourValue(i->colors.topRight, &color);
+ *vBufferCol++ = color;
+
+ vBuffer = (float*)vBufferCol;
+
+ *vBuffer++ = i->texCoords.topRight.x;
+ *vBuffer++ = i->texCoords.topRight.y;
+
+ // Bottom-Left Vertex
+ *vBuffer++ = i->vertices.bottomLeft.x;
+ *vBuffer++ = i->vertices.bottomLeft.y;
+ *vBuffer++ = 0;
+
+ vBufferCol = (Ogre::RGBA*)vBuffer;
+ Ogre::Root::getSingleton().convertColourValue(i->colors.bottomLeft, &color);
+ *vBufferCol++ = color;
+
+ vBuffer = (float*)vBufferCol;
+
+ *vBuffer++ = i->texCoords.bottomLeft.x;
+ *vBuffer++ = i->texCoords.bottomLeft.y;
+
+ // Bottom-Right Vertex
+ *vBuffer++ = i->vertices.bottomRight.x;
+ *vBuffer++ = i->vertices.bottomRight.y;
+ *vBuffer++ = 0;
+
+ vBufferCol = (Ogre::RGBA*)vBuffer;
+ Ogre::Root::getSingleton().convertColourValue(i->colors.bottomRight, &color);
+ *vBufferCol++ = color;
+
+ vBuffer = (float*)vBufferCol;
+
+ *vBuffer++ = i->texCoords.bottomRight.x;
+ *vBuffer++ = i->texCoords.bottomRight.y;
+ }
+
+ buffer->unlock();
+ isDirty = false;
+}
+} // namespace
Added: trunk/python-ogre/ThirdParty/canvas/Canvas.h
===================================================================
--- trunk/python-ogre/ThirdParty/canvas/Canvas.h (rev 0)
+++ trunk/python-ogre/ThirdParty/canvas/Canvas.h 2008-12-05 07:18:28 UTC (rev 827)
@@ -0,0 +1,278 @@
+/*
+ This file is part of Canvas, a fast, lightweight 2D graphics engine for Ogre3D.
+
+ Copyright (C) 2008 Adam J. Simmons
+ ajs...@gm...
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef __Canvas_H__
+#define __Canvas_H__
+
+#include <vector>
+#include "Atlas.h"
+
+namespace CanvasNS
+{
+class Canvas;
+
+/**
+* An internal templated helper class.
+*/
+template<typename T> struct Corners
+{
+ T topLeft, bottomLeft, bottomRight, topRight;
+
+ Corners()
+ {
+ }
+
+ Corners(const T& all) : topLeft(all), bottomLeft(all), bottomRight(all), topRight(all)
+ {
+ }
+
+ Corners(const T& topLeft, const T& bottomLeft, const T& bottomRight, const T& topRight) :
+ topLeft(topLeft), bottomLeft(bottomLeft), bottomRight(bottomRight), topRight(topRight)
+ {
+ }
+};
+
+/**
+* Internal structure, used to define solid fill colors/gradients.
+*/
+struct Coloring
+{
+ std::pair<Ogre::ColourValue, Ogre::ColourValue> colors;
+ bool hasGradient;
+ short orientation;
+
+ enum GradientOrientation
+ {
+ Vertical,
+ Horizontal
+ };
+};
+
+/**
+* Defines the "fill" (color, texture, gradient) for a shape drawn with Canvas.
+*/
+struct Fill
+{
+ bool isEmpty;
+ Ogre::String atlasKey;
+ Coloring coloring;
+
+ /**
+ * Create an empty fill.
+ */
+ Fill();
+
+ /**
+ * Create a pure-color fill.
+ */
+ Fill(const Ogre::ColourValue& color);
+
+ /**
+ * Create a gradient fill.
+ *
+ * @param gradientColor1 In a vertical gradient, the top color, and in a horizontal gradient, the left color.
+ * @param gradientColor2 In a vertical gradient, the bottom color, and in a horizontal gradient, the right color.
+ * @param orientation The orientation of the gradient, can be either Coloring::Vertical or Coloring::Horizontal.
+ */
+ Fill(const Ogre::ColourValue& gradientColor1, const Ogre::ColourValue& gradientColor2, short orientation = CanvasNS::Coloring::Vertical);
+
+ /**
+ * Create a texture fill (must be loaded in current atlas) with an optional multiplied color.
+ *
+ * @param texture The filename of the texture, should be loaded in the current atlas.
+ * @param color The optional color to multiply the texture with.
+ */
+ Fill(const Ogre::String& texture, const Ogre::ColourValue& color = Ogre::ColourValue::White);
+
+ /**
+ * Create a texture fill (must be loaded in current atlas) with a multiplied gradient.
+ *
+ * @param texture The filename of the texture, should be loaded in the current atlas.
+ * @param gradientColor1 In a vertical gradient, the top color, and in a horizontal gradient, the left color.
+ * @param gradientColor2 In a vertical gradient, the bottom color, and in a horizontal gradient, the right color.
+ * @param orientation The orientation of the gradient, can be either Coloring::Vertical or Coloring::Horizontal.
+ */
+ Fill(const Ogre::String& texture, const Ogre::ColourValue& gradientColor1, const Ogre::ColourValue& gradientColor2, short orientation = CanvasNS::Coloring::Vertical);
+};
+
+typedef Ogre::TRect<int> WidthRect;
+typedef Ogre::TRect<int> ClipRect;
+typedef Ogre::TRect<int> PixelRect;
+typedef Ogre::TRect<Ogre::ColourValue> ColorRect;
+
+/**
+* Defines the "border" for a rectangle drawn with Canvas.
+*/
+struct Border
+{
+ bool isEmpty;
+ WidthRect widths;
+ ColorRect colors;
+
+ /**
+ * Create an empty border.
+ */
+ Border();
+
+ /**
+ * Create a border with a uniform pixel width and uniform color
+ *
+ * @param width The width, in pixels, for every side of the border.
+ * @param color The color for every side of the border.
+ */
+ Border(int width, const Ogre::ColourValue& color);
+
+ /**
+ * Create a border with custom pixel widths and colors for each side.
+ *
+ * @param widths The widths, in pixels, to use for each side.
+ * @param colors The colors to use for each side.
+ */
+ Border(const WidthRect& widths, const ColorRect& colors);
+};
+
+/**
+* The Canvas.
+*/
+class Canvas : public Ogre::Renderable, public Ogre::MovableObject, public Ogre::RenderTargetListener
+{
+ struct Quad
+ {
+ Corners<Ogre::Vector2> vertices;
+ Corners<Ogre::Vector2> texCoords;
+ Corners<Ogre::ColourValue> colors;
+ };
+
+ Atlas* atlas;
+ std::vector<Canvas::Quad> quadList;
+ Ogre::HardwareVertexBufferSharedPtr buffer;
+ Ogre::VertexData* vertexData;
+ Ogre::IndexData* indexData;
+ size_t bufferSize;
+ Ogre::MaterialPtr material;
+ Ogre::Viewport* viewport;
+ Ogre::uint8 renderQueueID;
+ ClipRect clip;
+ bool isDirty;
+ bool visibility;
+
+public:
+ /**
+ * Constructs the canvas.
+ *
+ * @param atlas The texture atlas to use for this canvas.
+ * @param viewport The viewport that this canvas will display in.
+ */
+ Canvas(Atlas* atlas, Ogre::Viewport* viewport);
+
+ /**
+ * Destroys the canvas.
+ */
+ ~Canvas();
+
+ /**
+ * Draws a rectangle on the canvas.
+ *
+ * @param x The x-coordinate of the origin, in pixels.
+ * @param y The y-coordinate of the origin, in pixels.
+ * @param width The width of the rectangle, in pixels.
+ * @param height The height of the rectangle, in pixels.
+ * @param fill The fill to use.
+ * @param border The optional border.
+ */
+ void drawRectangle(int x, int y, int width, int height, const Fill& fill, const Border& border = Border());
+
+ /**
+ * Draws a glyph on the canvas.
+ *
+ * @param glyph The GlyphInfo of the glyph to draw (obtained from Atlas).
+ * @param x The x-coordinate of the origin, in pixels.
+ * @param y The y-coordinate of the origin, in pixels.
+ * @param width The width of the rectangle, in pixels.
+ * @param height The height of the rectangle, in pixels.
+ * @param color The color of the glyph.
+ */
+ void drawGlyph(const GlyphInfo& glyph, int x, int y, int width, int height, const Ogre::ColourValue& color);
+
+ /**
+ * Clears the canvas.
+ */
+ void clear();
+
+ /**
+ * Sets the current clipping boundaries to use for subsequent draw calls.
+ *
+ * @param left The left-boundary, in pixels.
+ * @param top The top-boundary, in pixels.
+ * @param right The right-boundary, in pixels.
+ * @param bottom The bottom-boundary, in pixels.
+ */
+ void setClip(int left, int top, int right, int bottom);
+
+ /**
+ * Resets the current clipping boundaries to the dimensions of the viewport.
+ */
+ void clearClip();
+
+ // Inherited from Ogre::Renderable
+ const Ogre::MaterialPtr& getMaterial() const;
+ void getRenderOperation(Ogre::RenderOperation& op);
+ void getWorldTransforms(Ogre::Matrix4* xform) const;
+ const Ogre::Quaternion& getWorldOrientation() const;
+ const Ogre::Vector3& getWorldPosition() const;
+ Ogre::Real getSquaredViewDepth(const Ogre::Camera* cam) const;
+ const Ogre::LightList& getLights() const;
+
+ // Inherited from Ogre::MovableObject
+ const Ogre::String& getMovableType() const;
+ const Ogre::AxisAlignedBox& getBoundingBox() const;
+ Ogre::Real getBoundingRadius() const;
+ void _updateRenderQueue(Ogre::RenderQueue* queue);
+ void setVisible(bool visible);
+ bool isVisible() const;
+
+ // Inherited from Ogre::RenderTargetListener
+ void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt);
+ void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt);
+ void preViewportUpdate(const Ogre::RenderTargetViewportEvent& evt);
+ void postViewportUpdate(const Ogre::RenderTargetViewportEvent& evt);
+ void viewportAdded(const Ogre::RenderTargetViewportEvent& evt);
+ void viewportRemoved(const Ogre::RenderTargetViewportEvent& evt);
+
+protected:
+
+ void destroyBuffers();
+
+ void resizeBuffers();
+
+ void localize(Ogre::Vector2& vertex);
+
+ bool isOutsideClip(const PixelRect& rect);
+
+ void drawQuad(const PixelRect& rect, const Ogre::FloatRect& texCoords, const Coloring& coloring);
+
+ void drawQuad(const Corners<Ogre::Vector2>& corners, const Ogre::FloatRect& texCoords, const Ogre::ColourValue& color);
+
+ void updateGeometry();
+};
+
+} // namespace
+#endif
Modified: trunk/python-ogre/environment.py
===================================================================
--- trunk/python-ogre/environment.py 2008-12-04 13:12:10 UTC (rev 826)
+++ trunk/python-ogre/environment.py 2008-12-05 07:18:28 UTC (rev 827)
@@ -1863,6 +1863,28 @@
descText = "MyGUI Interface System"
descLink = "http://sourceforge.net/projects/my-gui/"
+class canvas:
+ active = False
+ pythonModule = True
+ version="1.0"
+ name='canvas'
+ parent="ogre/gui"
+ cflags = ""
+ include_dirs = [ Config.PATH_Boost,
+ Config.PATH_INCLUDE_canvas
+ , Config.PATH_INCLUDE_Ogre
+ ,Config.PATH_INCLUDE_Ogre_Dependencies
+ ]
+ lib_dirs = [Config.PATH_LIB_Boost
+ ,Config.PATH_LIB_Ogre_OgreMain
+ , Config.PATH_LIB_Ogre_Dependencies
+ ]
+ CheckIncludes=[]
+ libs=[ boost.lib, 'OgreMain', 'freetype235']
+ ModuleName="canvas"
+ descText = "Canvas GUI System"
+ descLink = "http://www.ogre3d.org/phpBB2/viewtopic.php?t=41365&postdays=0&postorder=asc&start=0&sid=6578000180a935734beb03d548b900a4"
+
#######################################################################...
[truncated message content] |