[Python-ogre-commit] SF.net SVN: python-ogre: [408] trunk/python-ogre
Brought to you by:
andy_miller,
roman_yakovenko
From: <and...@us...> - 2007-10-05 04:16:05
|
Revision: 408 http://python-ogre.svn.sourceforge.net/python-ogre/?rev=408&view=rev Author: andy_miller Date: 2007-10-04 21:16:07 -0700 (Thu, 04 Oct 2007) Log Message: ----------- Initial version of Editable Terrain wrapper -- thanks Dermont Updated QuickGUI Modified Paths: -------------- trunk/python-ogre/PythonOgreConfig_nt.py trunk/python-ogre/PythonOgreConfig_posix.py trunk/python-ogre/SConstruct trunk/python-ogre/ThirdParty/quickgui/QuickGUIBorder.cpp trunk/python-ogre/ThirdParty/quickgui/QuickGUIBorder.h trunk/python-ogre/ThirdParty/quickgui/QuickGUIButton.cpp trunk/python-ogre/ThirdParty/quickgui/QuickGUIButton.h trunk/python-ogre/ThirdParty/quickgui/QuickGUIComboBox.cpp trunk/python-ogre/ThirdParty/quickgui/QuickGUIComboBox.h trunk/python-ogre/ThirdParty/quickgui/QuickGUIHorizontalScrollBar.cpp trunk/python-ogre/ThirdParty/quickgui/QuickGUIHorizontalScrollBar.h trunk/python-ogre/ThirdParty/quickgui/QuickGUIHorizontalTrackBar.cpp trunk/python-ogre/ThirdParty/quickgui/QuickGUIHorizontalTrackBar.h trunk/python-ogre/ThirdParty/quickgui/QuickGUIImage.cpp trunk/python-ogre/ThirdParty/quickgui/QuickGUIImage.h trunk/python-ogre/ThirdParty/quickgui/QuickGUILabel.cpp trunk/python-ogre/ThirdParty/quickgui/QuickGUILabel.h trunk/python-ogre/ThirdParty/quickgui/QuickGUIList.cpp trunk/python-ogre/ThirdParty/quickgui/QuickGUIList.h trunk/python-ogre/ThirdParty/quickgui/QuickGUIListItem.cpp trunk/python-ogre/ThirdParty/quickgui/QuickGUIListItem.h trunk/python-ogre/ThirdParty/quickgui/QuickGUIManager.cpp trunk/python-ogre/ThirdParty/quickgui/QuickGUIManager.h trunk/python-ogre/ThirdParty/quickgui/QuickGUIMenu.cpp trunk/python-ogre/ThirdParty/quickgui/QuickGUIMenu.h trunk/python-ogre/ThirdParty/quickgui/QuickGUIMenuList.cpp trunk/python-ogre/ThirdParty/quickgui/QuickGUIMenuList.h trunk/python-ogre/ThirdParty/quickgui/QuickGUINStateButton.cpp trunk/python-ogre/ThirdParty/quickgui/QuickGUINStateButton.h trunk/python-ogre/ThirdParty/quickgui/QuickGUIPanel.cpp trunk/python-ogre/ThirdParty/quickgui/QuickGUIPanel.h trunk/python-ogre/ThirdParty/quickgui/QuickGUIProgressBar.cpp trunk/python-ogre/ThirdParty/quickgui/QuickGUIProgressBar.h trunk/python-ogre/ThirdParty/quickgui/QuickGUIQuad.cpp trunk/python-ogre/ThirdParty/quickgui/QuickGUIQuad.h trunk/python-ogre/ThirdParty/quickgui/QuickGUIQuadContainer.cpp trunk/python-ogre/ThirdParty/quickgui/QuickGUIScrollPane.cpp trunk/python-ogre/ThirdParty/quickgui/QuickGUIScrollPane.h trunk/python-ogre/ThirdParty/quickgui/QuickGUISheet.cpp trunk/python-ogre/ThirdParty/quickgui/QuickGUISheet.h trunk/python-ogre/ThirdParty/quickgui/QuickGUISize.h trunk/python-ogre/ThirdParty/quickgui/QuickGUIText.cpp trunk/python-ogre/ThirdParty/quickgui/QuickGUIText.h trunk/python-ogre/ThirdParty/quickgui/QuickGUITextBox.cpp trunk/python-ogre/ThirdParty/quickgui/QuickGUITextBox.h trunk/python-ogre/ThirdParty/quickgui/QuickGUITitleBar.cpp trunk/python-ogre/ThirdParty/quickgui/QuickGUITitleBar.h trunk/python-ogre/ThirdParty/quickgui/QuickGUIVerticalScrollBar.cpp trunk/python-ogre/ThirdParty/quickgui/QuickGUIVerticalScrollBar.h trunk/python-ogre/ThirdParty/quickgui/QuickGUIVerticalTrackBar.cpp trunk/python-ogre/ThirdParty/quickgui/QuickGUIVerticalTrackBar.h trunk/python-ogre/ThirdParty/quickgui/QuickGUIWidget.cpp trunk/python-ogre/ThirdParty/quickgui/QuickGUIWidget.h trunk/python-ogre/ThirdParty/quickgui/QuickGUIWindow.cpp trunk/python-ogre/ThirdParty/quickgui/QuickGUIWindow.h trunk/python-ogre/environment.py trunk/python-ogre/setup.py Added Paths: ----------- trunk/python-ogre/ThirdParty/et/ trunk/python-ogre/ThirdParty/et/ETBrush.cpp trunk/python-ogre/ThirdParty/et/ETBrush.h trunk/python-ogre/ThirdParty/et/ETIndexHandler.cpp trunk/python-ogre/ThirdParty/et/ETLightmap.cpp trunk/python-ogre/ThirdParty/et/ETLoadSaveHeightmap.cpp trunk/python-ogre/ThirdParty/et/ETPrerequisites.h trunk/python-ogre/ThirdParty/et/ETSplattingManager.cpp trunk/python-ogre/ThirdParty/et/ETSplattingManager.h trunk/python-ogre/ThirdParty/et/ETTerrainInfo.cpp trunk/python-ogre/ThirdParty/et/ETTerrainInfo.h trunk/python-ogre/ThirdParty/et/ETTerrainManager.cpp trunk/python-ogre/ThirdParty/et/ETTerrainManager.h trunk/python-ogre/ThirdParty/et/ETTile.cpp trunk/python-ogre/ThirdParty/et/Impl/ trunk/python-ogre/ThirdParty/et/Impl/ETIndexHandler.h trunk/python-ogre/ThirdParty/et/Impl/ETOptions.h trunk/python-ogre/ThirdParty/et/Impl/ETTerrainImpl.h trunk/python-ogre/ThirdParty/et/Impl/ETTile.h trunk/python-ogre/code_generators/et/ trunk/python-ogre/code_generators/et/customization_data.py trunk/python-ogre/code_generators/et/generate_code.py trunk/python-ogre/code_generators/et/hand_made_wrappers.py trunk/python-ogre/code_generators/et/python_et.h trunk/python-ogre/code_generators/et/python_et_aliases.h trunk/python-ogre/code_generators/et/python_et_sizeof.h trunk/python-ogre/demos/et/ trunk/python-ogre/demos/et/CEGUI_framework.py trunk/python-ogre/demos/et/Demo_CEGUI_ET.py trunk/python-ogre/demos/et/SampleFramework.py trunk/python-ogre/demos/et/minimap.material trunk/python-ogre/demos/et/minimap.overlay trunk/python-ogre/demos/et/plugins.cfg trunk/python-ogre/demos/et/resources.cfg Modified: trunk/python-ogre/PythonOgreConfig_nt.py =================================================================== --- trunk/python-ogre/PythonOgreConfig_nt.py 2007-10-03 06:30:20 UTC (rev 407) +++ trunk/python-ogre/PythonOgreConfig_nt.py 2007-10-05 04:16:07 UTC (rev 408) @@ -41,6 +41,7 @@ PATH_betagui= os.path.join(PATH_THIRDPARTY,'betagui') PATH_ogredshow = os.path.join(PATH_THIRDPARTY,'dshow') PATH_plib = os.path.join(PATH_THIRDPARTY, 'plib') +PATH_et = os.path.join(PATH_THIRDPARTY, 'et') PATH_ogrevideoffmpeg = os.path.join(PATH_THIRDPARTY,'ffmpeg') PATH_NxOgre= os.path.join(BASE_DIR, 'nxogre/NxOgre') PATH_Bullet= os.path.join(BASE_DIR, 'bullet-2.62') Modified: trunk/python-ogre/PythonOgreConfig_posix.py =================================================================== --- trunk/python-ogre/PythonOgreConfig_posix.py 2007-10-03 06:30:20 UTC (rev 407) +++ trunk/python-ogre/PythonOgreConfig_posix.py 2007-10-05 04:16:07 UTC (rev 408) @@ -48,6 +48,8 @@ PATH_betagui= os.path.join(PATH_THIRDPARTY,'betagui') PATH_ogredshow = os.path.join(PATH_THIRDPARTY,'dshow') PATH_plib = os.path.join(PATH_THIRDPARTY, 'plib') +PATH_et = os.path.join(PATH_THIRDPARTY, 'et') + PATH_ogrevideoffmpeg = os.path.join(PATH_THIRDPARTY,'ffmpeg') PATH_NxOgre= os.path.join(BASE_DIR, 'nxogre/NxOgre') PATH_Bullet= os.path.join(BASE_DIR, 'bullet-2.62') Modified: trunk/python-ogre/SConstruct =================================================================== --- trunk/python-ogre/SConstruct 2007-10-03 06:30:20 UTC (rev 407) +++ trunk/python-ogre/SConstruct 2007-10-05 04:16:07 UTC (rev 408) @@ -91,11 +91,11 @@ possible_projects = ['ogre' , 'ois', 'ogrerefapp', 'ogrenewt', 'cegui', 'ode',\ 'ogreode', 'ogreal', 'quickgui', 'opcode', 'nxogre', 'bullet', 'physx', 'betagui','theora',\ 'ogrevideoffmpeg', 'ogredshow', 'plib', 'ogrebulletc', 'ogrebulletd', - 'ogreforests' ] # , 'raknet', 'navi', + 'ogreforests', 'et' ] # , 'raknet', 'navi', default_projects = ['ogre' , 'ois', 'ogrerefapp', 'ogrenewt', 'cegui', 'ode',\ 'ogreode', 'ogreal', 'quickgui', 'opcode', 'nxogre', 'bullet', 'physx', 'betagui','theora',\ 'ogrevideoffmpeg', 'ogredshow', 'plib', 'ogrebulletc', 'ogrebulletd', - 'ogreforests' ] # 'navi', + 'ogreforests', 'et' ] # 'navi', # This lets you call scons like: 'scons PROJECTS=ogre,cegui' opts = Options('custom.py') Added: trunk/python-ogre/ThirdParty/et/ETBrush.cpp =================================================================== --- trunk/python-ogre/ThirdParty/et/ETBrush.cpp (rev 0) +++ trunk/python-ogre/ThirdParty/et/ETBrush.cpp 2007-10-05 04:16:07 UTC (rev 408) @@ -0,0 +1,131 @@ +/* +EDITABLE TERRAIN MANAGER for Ogre +Copyright (C) 2007 Holger Frydrych <h.f...@gm...> + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +As a special exception, you may use this file as part of a free software +library without restriction. Specifically, if other files instantiate +templates or use macros or inline functions from this file, or you compile +this file and link it with other files to produce an executable, this +file does not by itself cause the resulting executable to be covered by +the GNU General Public License. This exception does not however +invalidate any other reasons why the executable file might be covered by +the GNU General Public License. +*/ + +#include "ETBrush.h" + +#include <OgreImage.h> +#include <OgreException.h> + +using namespace std; +using namespace Ogre; +using Ogre::uint; +using Ogre::ushort; + +namespace ET +{ + Brush::Brush() + : mWidth(0), mHeight(0), mBrushArray(0) + { + } + + Brush::Brush(const float* brush, size_t width, size_t height) + : mWidth(width), mHeight(height) + { + mBrushArray = new float[width*height]; + memcpy(mBrushArray, brush, width*height*sizeof(float)); + } + + Brush::Brush(const vector<float>& brush, size_t width, size_t height) + : mWidth(width), mHeight(height) + { + mBrushArray = new float[width*height]; + copy(brush.begin(), brush.end(), mBrushArray); + } + + Brush::Brush(const Brush& other) + : mWidth(other.mWidth), mHeight(other.mHeight) + { + mBrushArray = new float[mWidth*mHeight]; + memcpy(mBrushArray, other.mBrushArray, mWidth*mHeight*sizeof(float)); + } + + Brush::~Brush() + { + delete[] mBrushArray; + } + + + Brush& Brush::operator=(const Brush& other) + { + Brush tmp (other); + tmp.swap(*this); + return *this; + } + + void Brush::swap(Brush& other) + { + std::swap(mWidth, other.mWidth); + std::swap(mHeight, other.mHeight); + std::swap(mBrushArray, other.mBrushArray); + } + + Brush loadBrushFromImage(const Image& image) + { + size_t width = image.getWidth(); + size_t height = image.getHeight(); + vector<float> brush (width*height); + + // determine the bytes per pixel used in the image + int bpp = int(image.getSize() / (width*height)); + /*switch (image.getFormat()) + { + case PF_BYTE_A: bpp = 1; break; + case PF_BYTE_LA: case PF_L16: bpp = 2; break; + case PF_BYTE_RGB: case PF_BYTE_BGR: bpp = 3; break; + case PF_BYTE_RGBA: case PF_BYTE_BGRA: bpp = 4; break; + default: OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Don't know what to do with the given image format, sorry.", "loadBrushFromImage"); + }*/ + // from the bpp, calculate the relevant max value for one pixel + uint maxValue = (1 << (bpp*8)) - 1; + + // now fill the brush array + const uchar* imageData = image.getData(); + for (size_t i = 0; i < brush.size(); ++i) + { + uint val = 0; + memcpy(&val, imageData, bpp); + imageData += bpp; + brush[i] = float(val) / maxValue; + } + + return Brush(brush, width, height); + } + + + void saveBrushToImage(const Brush& brush, Image& image) + { + // save brush as a 16bit grayscale image + ushort* data = new ushort[brush.getWidth()*brush.getHeight()]; + for (size_t x = 0; x < brush.getWidth(); ++x) + for (size_t y = 0; y < brush.getHeight(); ++y) + data[y*brush.getWidth() + x] = ushort(brush.at(x, y) * 0xffff); + + // pass the data to the image, image takes over ownership + image.loadDynamicImage((uchar*)data, brush.getWidth(), brush.getHeight(), 1, PF_L16, true); + } +} Added: trunk/python-ogre/ThirdParty/et/ETBrush.h =================================================================== --- trunk/python-ogre/ThirdParty/et/ETBrush.h (rev 0) +++ trunk/python-ogre/ThirdParty/et/ETBrush.h 2007-10-05 04:16:07 UTC (rev 408) @@ -0,0 +1,94 @@ +#ifndef __ETBRUSH_H__ +#define __ETBRUSH_H__ + +/* +EDITABLE TERRAIN MANAGER for Ogre +Copyright (C) 2007 Holger Frydrych <h.f...@gm...> + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +As a special exception, you may use this file as part of a free software +library without restriction. Specifically, if other files instantiate +templates or use macros or inline functions from this file, or you compile +this file and link it with other files to produce an executable, this +file does not by itself cause the resulting executable to be covered by +the GNU General Public License. This exception does not however +invalidate any other reasons why the executable file might be covered by +the GNU General Public License. +*/ + +#include "ETPrerequisites.h" + +#include <vector> + +// forward declarations +namespace Ogre +{ + class Image; +} + + +namespace ET +{ + /** This class represents a brush used to deform terrain or edit splatting coverage */ + class _ETManagerExport Brush + { + public: + /** Default constructor */ + Brush(); + /** Constructs a brush from a given array of floats */ + Brush(const float* brush, size_t width, size_t height); + /** Constructs a brush from a given vector of floats */ + Brush(const std::vector<float>& brush, size_t width, size_t height); + /** Copy constructor */ + Brush(const Brush& other); + ~Brush(); + + /** Copy assignment */ + Brush& operator=(const Brush& other); + + size_t getWidth() const { return mWidth; } + size_t getHeight() const { return mHeight; } + + /** Access to the brush array */ + float& at(size_t x, size_t y) + { + return mBrushArray[x + y*mWidth]; + } + /** Const access to the brush array */ + const float at(size_t x, size_t y) const + { + return mBrushArray[x + y*mWidth]; + } + + /** Exception-safe swap function */ + void swap(Brush& other); + + private: + /** The actual brush array containing the brush values */ + float* mBrushArray; // would have used vector<float>, but gives warnings with dll export + /** The brush's dimensions */ + size_t mWidth, mHeight; + }; + + /** Loads a brush from a grayscale image */ + Brush _ETManagerExport loadBrushFromImage(const Ogre::Image& image); + + /** Saves a brush to a grayscale image */ + void _ETManagerExport saveBrushToImage(const Brush& brush, Ogre::Image& image); +} + + +#endif Added: trunk/python-ogre/ThirdParty/et/ETIndexHandler.cpp =================================================================== --- trunk/python-ogre/ThirdParty/et/ETIndexHandler.cpp (rev 0) +++ trunk/python-ogre/ThirdParty/et/ETIndexHandler.cpp 2007-10-05 04:16:07 UTC (rev 408) @@ -0,0 +1,257 @@ +/* +EDITABLE TERRAIN MANAGER for Ogre +Copyright (C) 2007 Holger Frydrych <h.f...@gm...> + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +As a special exception, you may use this file as part of a free software +library without restriction. Specifically, if other files instantiate +templates or use macros or inline functions from this file, or you compile +this file and link it with other files to produce an executable, this +file does not by itself cause the resulting executable to be covered by +the GNU General Public License. This exception does not however +invalidate any other reasons why the executable file might be covered by +the GNU General Public License. +*/ + +#include "Impl/ETIndexHandler.h" + +#include <OgreHardwareBufferManager.h> + +using namespace Ogre; +using Ogre::uint; +using Ogre::ushort; + +namespace ET +{ + namespace Impl + { + IndexHandler::IndexHandler(size_t tileSize, unsigned int maxLOD) + : mTileSize(tileSize), mIndexes(maxLOD) + { + } + + IndexHandler::~IndexHandler() + { + for (size_t i = 0; i < mIndexes.size(); ++i) + { + for (IndexMap::iterator it = mIndexes[i].begin(); it != mIndexes[i].end(); ++it) + delete it->second; + } + } + + IndexData* IndexHandler::requestIndexData(unsigned int lod, unsigned int neighbourState) + { + assert(lod < mIndexes.size() && "Requested unexpected LOD level"); + IndexData* data; + IndexMap::iterator it = mIndexes[lod].find(neighbourState); + if (it != mIndexes[lod].end()) + data = it->second; + else + { + data = createIndexes(lod, neighbourState); + mIndexes[lod].insert(IndexMap::value_type(neighbourState, data)); + } + return data; + } + + + unsigned short IndexHandler::index(size_t x, size_t z) const + { + return ushort(x + z * mTileSize); + } + + + IndexData* IndexHandler::createIndexes(unsigned int lod, unsigned int neighbourState) + { + unsigned int numIndexes = 0; + unsigned int step = 1 << lod; + + unsigned int northLOD = neighbourState >> 24; + unsigned int eastLOD = (neighbourState >> 16) & 0xFF; + unsigned int southLOD = (neighbourState >> 8) & 0xFF; + unsigned int westLOD = neighbourState & 0xFF; + unsigned int north = northLOD ? step : 0; + unsigned int east = eastLOD ? step : 0; + unsigned int south = southLOD ? step : 0; + unsigned int west = westLOD ? step : 0; + + size_t newLength = (mTileSize/step) * (mTileSize/step) * 2 * 2 * 2; + IndexData* indexData = new IndexData; + indexData->indexBuffer = HardwareBufferManager::getSingleton().createIndexBuffer( + HardwareIndexBuffer::IT_16BIT, newLength, HardwareBuffer::HBU_STATIC_WRITE_ONLY); + unsigned short* pIdx = static_cast<unsigned short*>(indexData->indexBuffer->lock( + 0, indexData->indexBuffer->getSizeInBytes(), HardwareBuffer::HBL_DISCARD)); + + // go over all vertices and combine them to triangles in trilist format. + // leave out the edges if we need to stitch those in case over lower LOD at the + // neighbour. + for (unsigned int j = north; j < mTileSize-1 - south; j += step) + { + for (unsigned int i = west; i < mTileSize-1 - east; i += step) + { + // triangles + *pIdx++ = index(i, j); + *pIdx++ = index(i, j+step); + *pIdx++ = index(i+step, j); + + *pIdx++ = index(i, j+step); + *pIdx++ = index(i+step, j+step); + *pIdx++ = index(i+step, j); + + numIndexes += 6; + } + } + + // stitching edges to neighbours where needed + if (northLOD) + numIndexes += stitchEdge(NORTH, lod, northLOD, westLOD > 0, eastLOD > 0, &pIdx); + if (eastLOD) + numIndexes += stitchEdge(EAST, lod, eastLOD, northLOD > 0, southLOD > 0, &pIdx); + if (southLOD) + numIndexes += stitchEdge(SOUTH, lod, southLOD, eastLOD > 0, westLOD > 0, &pIdx); + if (westLOD) + numIndexes += stitchEdge(WEST, lod, westLOD, southLOD > 0, northLOD > 0, &pIdx); + + indexData->indexBuffer->unlock(); + indexData->indexCount = numIndexes; + indexData->indexStart = 0; + + return indexData; + } + + + int IndexHandler::stitchEdge(int direction, unsigned int hiLOD, unsigned int loLOD, bool omitFirstTri, + bool omitLastTri, unsigned short** ppIdx) + { + assert(loLOD > hiLOD); + + // code taken from Ogre's TSM + + unsigned short* pIdx = *ppIdx; + + int step = 1 << hiLOD; + int superstep = 1 << loLOD; + int halfsuperstep = superstep >> 1; + int rowstep = 0; + size_t startx = 0, starty = 0, endx = 0; + bool horizontal = false; + switch (direction) + { + case NORTH: + startx = starty = 0; + endx = mTileSize - 1; + rowstep = step; + horizontal = true; + break; + + case SOUTH: + startx = starty = mTileSize-1; + endx = 0; + rowstep = -step; + step = -step; + superstep = -superstep; + halfsuperstep = -halfsuperstep; + horizontal = true; + break; + + case EAST: + startx = 0; + endx = mTileSize-1; + starty = mTileSize-1; + rowstep = -step; + horizontal = false; + break; + + case WEST: + startx = mTileSize-1; + endx = 0; + starty = 0; + rowstep = step; + step = -step; + superstep = -superstep; + halfsuperstep = -halfsuperstep; + horizontal = false; + break; + } + + unsigned int numIndexes = 0; + + for (size_t j = startx; j != endx; j += superstep) + { + int k; + for (k = 0; k != halfsuperstep; k += step) + { + size_t jk = j + k; + if (j != startx || k != 0 || !omitFirstTri) + { + if (horizontal) + { + *pIdx++ = index(j, starty); + *pIdx++ = index(jk, starty + rowstep); + *pIdx++ = index(jk + step, starty + rowstep); + } + else + { + *pIdx++ = index(starty, j); + *pIdx++ = index(starty+rowstep, jk); + *pIdx++ = index(starty+rowstep, jk+step); + } + numIndexes += 3; + } + } + + if (horizontal) + { + *pIdx++ = index(j, starty); + *pIdx++ = index(j+halfsuperstep, starty+rowstep); + *pIdx++ = index(j+superstep, starty); + } + else + { + *pIdx++ = index(starty, j); + *pIdx++ = index(starty+rowstep, j+halfsuperstep); + *pIdx++ = index(starty, j+superstep); + } + numIndexes += 3; + + for (k = halfsuperstep; k != superstep; k += step) + { + size_t jk = j + k; + if (j != endx - superstep || k != superstep - step || !omitLastTri) + { + if (horizontal) + { + *pIdx++ = index(j+superstep, starty); + *pIdx++ = index(jk, starty+rowstep); + *pIdx++ = index(jk+step, starty+rowstep); + } + else + { + *pIdx++ = index(starty, j+superstep); + *pIdx++ = index(starty+rowstep, jk); + *pIdx++ = index(starty+rowstep, jk+step); + } + numIndexes += 3; + } + } + } + + *ppIdx = pIdx; + + return numIndexes; + } + } +} Added: trunk/python-ogre/ThirdParty/et/ETLightmap.cpp =================================================================== --- trunk/python-ogre/ThirdParty/et/ETLightmap.cpp (rev 0) +++ trunk/python-ogre/ThirdParty/et/ETLightmap.cpp 2007-10-05 04:16:07 UTC (rev 408) @@ -0,0 +1,327 @@ +/* +EDITABLE TERRAIN MANAGER for Ogre +Copyright (C) 2007 Holger Frydrych <h.f...@gm...> + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +As a special exception, you may use this file as part of a free software +library without restriction. Specifically, if other files instantiate +templates or use macros or inline functions from this file, or you compile +this file and link it with other files to produce an executable, this +file does not by itself cause the resulting executable to be covered by +the GNU General Public License. This exception does not however +invalidate any other reasons why the executable file might be covered by +the GNU General Public License. +*/ + +#include "ETTerrainInfo.h" +#include <OgreImage.h> +#include <OgreColourValue.h> +#include <OgreVector3.h> +#include <OgreAxisAlignedBox.h> +#include <OgreException.h> + +using namespace Ogre; +using namespace std; + +namespace ET +{ + namespace Impl + { + /** Add terrain shadows to lightmap. */ + void addTerrainShadowsToLightmap(uchar* lightMap, const TerrainInfo& info, + size_t width, size_t height, const Vector3& lightDir, const ColourValue& ambient) + { + // algorithm for ray traced shadow map as described here: + // http://gpwiki.org/index.php/Faster_Ray_Traced_Terrain_Shadow_Maps + size_t i, j; + size_t *x, *z; + int iDir, jDir; + size_t iSize, jSize; + float lDirXAbs = fabs(lightDir.x); + float lDirZAbs = fabs(lightDir.z); + + // based on the direction of light, decide in which order to traverse + // to speed up calculations + if (lDirXAbs > lDirZAbs) + { + z = &i; + x = &j; + iSize = height; + jSize = width; + if (lightDir.x < 0) + { + j = jSize - 1; + jDir = -1; + } + else + { + j = 0; + jDir = 1; + } + if (lightDir.z < 0) + { + i = iSize - 1; + iDir = -1; + } + else + { + i = 0; + iDir = 1; + } + } + else + { + x = &i; + z = &j; + jSize = height; + iSize = width; + if (lightDir.x < 0) + { + i = iSize - 1; + iDir = -1; + } + else + { + i = 0; + iDir = 1; + } + if (lightDir.z < 0) + { + j = jSize - 1; + jDir = -1; + } + else + { + j = 0; + jDir = 1; + } + } + + // calculate the step size to use + AxisAlignedBox extents = info.getExtents(); + Vector3 pos = extents.getMinimum(); + Vector3 step = extents.getMaximum() - extents.getMinimum(); + step.x /= width; + step.z /= height; + + float* flagMap = new float[width*height]; + memset(flagMap, 0, width*height*sizeof(float)); + + while (1) + { + while (1) + { + // travel along terrain until we: + // (1) intersect another point + // (2) find another point with previous collision data + // (3) reach the edge of the map + float px = *x; + float pz = *z; + size_t index = (*z) * width + (*x); + + // travel along ray + while (1) + { + px -= lightDir.x; + pz -= lightDir.z; + + // check if we've reached the boundary + if (px < 0 || px >= width || pz < 0 || pz >= height) + { + flagMap[index] = -1.0f; + break; + } + + // calculate interpolated values + int x0 = (int)floor(px); + int x1 = (int)ceil(px); + int z0 = (int)floor(pz); + int z1 = (int)ceil(pz); + + float du = px - x0; + float dv = pz - z0; + float invdu = 1.0 - du; + float invdv = 1.0 - dv; + float w0 = invdu * invdv; + float w1 = invdu * dv; + float w2 = du * invdv; + float w3 = du * dv; + + // get interpolated height at position + Vector3 curPos = pos + Vector3(px*step.x, 0, pz*step.z); + float ipHeight = info.getHeightAt(curPos.x, curPos.z) - pos.y; + + // compute interpolated flagmap value + float pixels[4]; + pixels[0] = flagMap[z0*width+x0]; + pixels[1] = flagMap[z1*width+x0]; + pixels[2] = flagMap[z0*width+x1]; + pixels[3] = flagMap[z1*width+x1]; + float ipFlag = w0*pixels[0] + w1*pixels[1] + w2*pixels[2] + w3*pixels[3]; + + // get distance from original point to current point + float realXDist = (px - *x) * step.x; + float realZDist = (pz - *z) * step.z; + float distance = sqrt(realXDist*realXDist + realZDist*realZDist); + + // calculate ray height at current point + float height = info.getHeightAt(pos.x + (*x)*step.x, pos.z + (*z)*step.z) - pos.y - lightDir.y*distance; + + // check intersection with either terrain or flagMap + // if ipHeight < ipFlag check against flagMap value + float val = (ipHeight < ipFlag ? ipFlag : ipHeight); + if (height < val) + { + // point in shadow + flagMap[index] = val - height; + lightMap[index*3+0] = (uchar) (255*ambient.r); + lightMap[index*3+1] = (uchar) (255*ambient.g); + lightMap[index*3+2] = (uchar) (255*ambient.b); + break; + } + + // check if pixel we moved to is unshadowed + // since the flagMap value is interpolated, we use an epsilon value to check + // if it's close enough to -1 to indicate non-shadow + const float epsilon = 0.5f; + if (ipFlag < -1.0f+epsilon && ipFlag > -1.0f-epsilon) + { + flagMap[index] = -1.0f; + break; + } + } + + // update inner loop + j += jDir; + if (j >= jSize) // due to size_t, if j < 0, will wrap around and be > jSize ;) + break; + } + + // reset inner loop starting point + if (jDir < 0) + j = jSize-1; + else + j = 0; + + // update outer loop variable + i += iDir; + if (i >= iSize) + break; + + } + + delete[] flagMap; + } + + + void boxFilterLightmap(uchar* lightMap, size_t width, size_t height) + { + // this box filter assigns to a pixel the average of itself and all + // surrounding pixels in a 5x5 grid + for (size_t i = 0; i < width; ++i) + { + for (size_t j = 0; j < height; ++j) + { + int col[3] = {0, 0, 0}; + // sum up all colours from 5x5 grid around the current pixel + int cnt = 0; + for (int x = -1; x <= 1; ++x) + { + if ((int)i+x < 0 || i+x >= width) + continue; + for (int y = -1; y <= 1; ++y) + { + if ((int)j+y < 0 || j+y >= height) + continue; + size_t index = (i+x + (j+y)*width)*3; + col[0] += lightMap[index+0]; + col[1] += lightMap[index+1]; + col[2] += lightMap[index+2]; + ++cnt; + } + } + // building average + col[0] /= cnt; + col[1] /= cnt; + col[2] /= cnt; + // write back + size_t index = (i + j*width)*3; + lightMap[index+0] = (uchar)col[0]; + lightMap[index+1] = (uchar)col[1]; + lightMap[index+2] = (uchar)col[2]; + } + } + } + } + + + + void createTerrainLightmap(const TerrainInfo& info, Image& image, + size_t width, size_t height, Vector3 lightDir, const ColourValue& lightCol, + const ColourValue& ambient, bool shadowed) + { + lightDir.normalise(); + + // calculate lightmap by multiplying light dir with terrain normals + + // calculate the step size to use + AxisAlignedBox extents = info.getExtents(); + Vector3 startPos = extents.getMinimum(); + Vector3 step = extents.getMaximum() - extents.getMinimum(); + step.x /= width; + step.z /= height; + Vector3 pos = startPos; + + uchar* lightMap = new uchar[width*height * 3]; + memset(lightMap, 255, width*height*3); + + for (size_t z = 0; z < height; ++z) + { + for (size_t x = 0; x < width; ++x) + { + size_t index = (z * width + x)*3; + // calculate diffuse light from light source + Vector3 norm = info.getNormalAt(pos.x, pos.z); + float l = std::max(0.0f, -lightDir.dotProduct(norm)); + + ColourValue v = ambient; + v.r = std::min(1.0f, v.r+l*lightCol.r); + v.g = std::min(1.0f, v.g+l*lightCol.g); + v.b = std::min(1.0f, v.b+l*lightCol.b); + lightMap[index+0] = (uchar) (255*v.r); + lightMap[index+1] = (uchar) (255*v.g); + lightMap[index+2] = (uchar) (255*v.b); + + pos.x += step.x; + } + pos.x = startPos.x; + pos.z += step.z; + } + + if (shadowed && (lightDir.x != 0 || lightDir.z != 0)) + { + // add terrain shadows + Impl::addTerrainShadowsToLightmap(lightMap, info, width, height, lightDir, ambient); + } + + // use a box filter to smoothen the lightmap + Impl::boxFilterLightmap(lightMap, width, height); + + // save lightmap to image + image.loadDynamicImage(lightMap, width, height, 1, PF_BYTE_RGB, true); + // ownership of lightMap was transfered to image, don't need to delete + } +} Added: trunk/python-ogre/ThirdParty/et/ETLoadSaveHeightmap.cpp =================================================================== --- trunk/python-ogre/ThirdParty/et/ETLoadSaveHeightmap.cpp (rev 0) +++ trunk/python-ogre/ThirdParty/et/ETLoadSaveHeightmap.cpp 2007-10-05 04:16:07 UTC (rev 408) @@ -0,0 +1,167 @@ +/* +EDITABLE TERRAIN MANAGER for Ogre +Copyright (C) 2007 Holger Frydrych <h.f...@gm...> + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +As a special exception, you may use this file as part of a free software +library without restriction. Specifically, if other files instantiate +templates or use macros or inline functions from this file, or you compile +this file and link it with other files to produce an executable, this +file does not by itself cause the resulting executable to be covered by +the GNU General Public License. This exception does not however +invalidate any other reasons why the executable file might be covered by +the GNU General Public License. +*/ + +#include "ETTerrainInfo.h" + +#include <OgreDataStream.h> +#include <OgreImage.h> +#include <OgreException.h> + +#include <iostream> + +using namespace Ogre; +using namespace std; +using Ogre::uint; +using Ogre::ushort; + +namespace ET +{ + void loadHeightmapFromImage(TerrainInfo& info, const Image& image) + { + uint bpp = 0; + bool flip = false; + + switch (image.getFormat()) + { + case PF_BYTE_A: case PF_BYTE_L: + bpp = 1; break; + case PF_BYTE_LA: case PF_L16: + bpp = 2; break; + case PF_BYTE_RGB: + bpp = 3; break; + case PF_BYTE_BGR: + bpp = 3; flip = true; break; + case PF_BYTE_RGBA: + bpp = 4; break; + case PF_BYTE_BGRA: + bpp = 4; flip = true; break; + default: + OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Can't use the given image's format.", "loadHeightmapFromImage"); + } + + size_t size = image.getWidth() * image.getHeight(); + unsigned int maxVal = (1 << (bpp*8)) - 1; + vector<float> data (size); + const uchar* imageData = image.getData(); + + for (size_t i = 0; i < size; ++i) + { + uchar read[4] = {0, 0, 0, 0}; + // TODO: Make this big endian aware/compatible + memcpy(read, imageData, bpp); + imageData += bpp; + if (flip) + swap(read[0], read[2]); + unsigned int val = * ((unsigned int*)read); + data[i] = float(val) / maxVal; + } + + info.setHeightmap(image.getWidth(), image.getHeight(), data); + } + + + void saveHeightmapToImage(const TerrainInfo& info, Ogre::Image& image, unsigned int bpp) + { + PixelFormat pf; + // decide on the image format to use + switch (bpp) + { + case 1: + pf = PF_BYTE_L; break; + case 2: + pf = PF_L16; break; + case 3: + pf = PF_BYTE_RGB; break; + case 4: + pf = PF_BYTE_RGBA; break; + default: + OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Bpp must be between 1 and 4.", "saveHeightmapToImage"); + } + + uint maxVal = (1 << (bpp*8)) - 1; + + uchar* data = new uchar[info.getWidth()*info.getHeight()*bpp]; + uchar* pos = data; + + // fill data array + for (size_t j = 0; j < info.getHeight(); ++j) + { + for (size_t i = 0; i < info.getWidth(); ++i) + { + uint val = uint (maxVal * info.at(i, j)); + memcpy(pos, &val, bpp); + pos += bpp; + } + } + + image.loadDynamicImage(data, info.getWidth(), info.getHeight(), 1, pf, true); + // given ownership of data to image + } + + + + + void loadHeightmapFromRawData(TerrainInfo& info, DataStream& stream, size_t width, size_t height) + { + size_t size = width*height; + size_t bpp = stream.size() / size; + if (bpp < 1 || bpp > 4 || stream.size() % size != 0) + OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Size of the given data stream does not match with specified dimensions.", "loadHeightmapFromRawData"); + + unsigned int maxVal = (1 << (bpp*8)) - 1; + vector<float> data (size); + + for (size_t i = 0; i < size; ++i) + { + unsigned int val = 0; + // TODO: What about big endian compatibility? + stream.read((void*)&val, bpp); + data[i] = float(val) / maxVal; + } + + info.setHeightmap(width, height, data); + } + + + void saveHeightmapToRawData(const TerrainInfo& info, ostream& stream, uint bpp) + { + if (bpp < 1 || bpp > 4) + OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Bpp must be between 1 and 4.", "saveHeightmapToRawData"); + + uint maxVal = (1 << (bpp*8)) - 1; + for (size_t j = 0; j < info.getHeight(); ++j) + { + for (size_t i = 0; i < info.getWidth(); ++i) + { + uint val = (uint) (maxVal * info.at(i, j)); + stream.write(reinterpret_cast<char*>(&val), bpp); + } + } + } + +} Added: trunk/python-ogre/ThirdParty/et/ETPrerequisites.h =================================================================== --- trunk/python-ogre/ThirdParty/et/ETPrerequisites.h (rev 0) +++ trunk/python-ogre/ThirdParty/et/ETPrerequisites.h 2007-10-05 04:16:07 UTC (rev 408) @@ -0,0 +1,28 @@ +#ifndef __ETPREREQUISITES_H__ +#define __ETPREREQUISITES_H__ + +#include <OgrePlatform.h> + +#define _ETManagerExport + +// // #ifndef _ETManagerExport + +// // #if (OGRE_PLATFORM == OGRE_PLATFORM_WIN32 ) +// // # ifdef ET_MANAGER_EXPORTS +// // # define _ETManagerExport __declspec(dllexport) +// // # else +// // # if defined( __MINGW32__ ) +// // # define _ETManagerExport +// // # else +// // # define _ETManagerExport __declspec(dllimport) +// // # endif +// // # endif +// // #elif defined ( OGRE_GCC_VISIBILITY ) +// // # define _ETManagerExport __attribute__ ((visibility("default"))) +// // #else +// // # define _ETManagerExport +// // #endif + +// // #endif + +#endif Added: trunk/python-ogre/ThirdParty/et/ETSplattingManager.cpp =================================================================== --- trunk/python-ogre/ThirdParty/et/ETSplattingManager.cpp (rev 0) +++ trunk/python-ogre/ThirdParty/et/ETSplattingManager.cpp 2007-10-05 04:16:07 UTC (rev 408) @@ -0,0 +1,518 @@ +/* +EDITABLE TERRAIN MANAGER for Ogre +Copyright (C) 2007 Holger Frydrych <h.f...@gm...> + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +As a special exception, you may use this file as part of a free software +library without restriction. Specifically, if other files instantiate +templates or use macros or inline functions from this file, or you compile +this file and link it with other files to produce an executable, this +file does not by itself cause the resulting executable to be covered by +the GNU General Public License. This exception does not however +invalidate any other reasons why the executable file might be covered by +the GNU General Public License. +*/ + +#include "ETSplattingManager.h" +#include "ETBrush.h" + +#include <OgreResource.h> +#include <OgreImage.h> +#include <OgreTextureManager.h> +#include <OgreStringConverter.h> +#include <OgreHardwarePixelBuffer.h> +#include <OgreException.h> + +#include <OgreLogManager.h> +#include <sstream> + +using namespace Ogre; +using namespace std; +using Ogre::uint; +using Ogre::ushort; + + +namespace ET +{ + namespace Impl + { + /** Handles a single alpha coverage map texture */ + class CoverageMap : public ManualResourceLoader + { + public: + CoverageMap(const String& name, const String& group, uint width, uint height, int channels, bool black = true); + ~CoverageMap(); + + /** Retrieve coverage map from image. */ + void loadFromImage(const Image& image); + /** Save coverage map to image. */ + void saveToImage(Image& image); + + /** Get the map's value for texture index c at position (x, y) */ + uchar getValue(uint x, uint y, uint c) const; + /** Set the map's value for texture index c at position (x, y) */ + void setValue(uint x, uint y, uint c, uchar val); + + /** Copy the editing buffer into the texture's pixel buffer. */ + void updateTexture(); + + /** Implemented from ManualResourceLoader to support reloading of the coverage map. */ + void loadResource(Resource*); + + /** Texture resource name for this coverage map. */ + const String& getName() const; + + private: + PixelFormat getFormat(int channels); + int getChannels(PixelFormat format); + + uint mWidth, mHeight, mSize; + int mChannels; + uchar* mData; + TexturePtr mTexture; + }; + + + CoverageMap::CoverageMap(const String& name, const String& group, uint width, uint height, int channels, bool black) + : mWidth(width), mHeight(height), mChannels(channels), mSize(width*height*channels) + { + mData = new uchar[mSize]; + memset(mData, 0, mSize); + // the first channel of the first coverage map is set to full value so that + // terrain initially is rendered with the first splatting texture + if (!black) + for (uint i = 0; i < mSize; i += mChannels) + mData[i] = 255; + // create a manually managed texture resource + mTexture = TextureManager::getSingleton().createManual(name, group, TEX_TYPE_2D, + width, height, 1, 0, getFormat(mChannels), TU_DEFAULT, this); + } + + CoverageMap::~CoverageMap() + { + delete[] mData; + TextureManager::getSingleton().remove(mTexture->getName()); + } + + void CoverageMap::loadResource(Resource*) + { + // the texture has requested to (re)load, we just copy our edit buffer + // into the texture + mTexture->createInternalResources(); + updateTexture(); + } + + void CoverageMap::updateTexture() + { + // write the edit buffer into the texture's pixel buffer + HardwarePixelBufferSharedPtr buffer = mTexture->getBuffer(); + PixelBox pixelBox (mWidth, mHeight, 1, getFormat(mChannels), mData); + Image::Box imageBox (0, 0, mWidth, mHeight); + buffer->blitFromMemory(pixelBox, imageBox); + } + + const String& CoverageMap::getName() const + { + return mTexture->getName(); + } + + uchar CoverageMap::getValue(uint x, uint y, uint c) const + { + return mData[(y*mWidth + x)*mChannels + c]; + } + + void CoverageMap::setValue(uint x, uint y, uint c, uchar val) + { + mData[(y*mWidth + x)*mChannels + c] = val; + } + + + PixelFormat CoverageMap::getFormat(int channels) + { + switch (channels) + { + case 1: return PF_BYTE_A; + case 2: return PF_BYTE_LA; + case 3: return PF_BYTE_RGB; + case 4: return PF_BYTE_RGBA; + case -1: return PF_BYTE_A; + case -2: return PF_BYTE_LA; + case -3: return PF_BYTE_BGR; + case -4: return PF_BYTE_BGRA; + default: return PF_UNKNOWN; + } + } + + int CoverageMap::getChannels(PixelFormat format) + { + switch (format) + { + case PF_BYTE_A: return 1; + case PF_BYTE_LA: return 2; + case PF_BYTE_RGB: return 3; + case PF_BYTE_BGR: return -3; + case PF_BYTE_RGBA: return 4; + case PF_BYTE_BGRA: return -4; + default: return 0; + } + } + + void CoverageMap::loadFromImage(const Image& image) + { + if (image.getWidth() != mWidth || image.getHeight() != mHeight) + OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Given image doesn't conform to the used width and height.", "CoverageMap::loadFromImage"); + if (image.getFormat() != getFormat(mChannels) && image.getFormat() != getFormat(-mChannels)) + OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Given image is of invalid pixel format.", "CoverageMap::loadFromImage"); + + memcpy(mData, image.getData(), image.getSize()); + if (getChannels(image.getFormat()) <= -3) + { + // need RGB(A), but given BGR(A) so invert + for (uint i = 0; i < mSize; i += mChannels) + swap(mData[i], mData[i+2]); + } + + updateTexture(); + } + + void CoverageMap::saveToImage(Image& image) + { + image.loadDynamicImage(mData, mWidth, mHeight, 1, getFormat(mChannels)); + } + + + + struct SplattingImpl + { + String baseName; + String group; + uint width, height; + uint channels; + uint numTextures; + uint numMaps; + + typedef vector<Impl::CoverageMap*> MapList; + MapList maps; + + void paint(uint texture, uint x, uint y, float edit) + { + uint map = texture / channels; + uint channel = texture % channels; + int val = maps[map]->getValue(x, y, channel) + (int) (255.0 * edit); + if (val > 255) + val = 255; + if (val < 0) + val = 0; + maps[map]->setValue(x, y, channel, val); + + balance(x, y, texture, val); + } + + void balance(uint x, uint y, uint texture, int val) + { + // this method ensures that the values at (x, y) of all channels in all maps sum up to 255, + // otherwise the terrain will get over- or underlighted at that position + int sum = 0; + for (uint i = 0; i < numMaps; ++i) + { + for (uint j = 0; j < channels; ++j) + { + // skip the texture we painted with, otherwise we'd be + // undoing the change + if (i * channels + j == texture) + continue; + sum += maps[i]->getValue(x, y, j); + } + } + + if (sum == 0) + { + // all other textures are 0, so set selected texture to full value + maps[texture/channels]->setValue(x, y, texture%channels, 255); + return; + } + + // reduce/add all other channels as necessary + int diff = sum - (255 - val); + for (uint i = 0; i < numMaps; ++i) + { + for (uint j = 0; j < channels; ++j) + { + // skip the texture we painted with, otherwise we'd be + // undoing the change + if (i * channels + j == texture) + continue; + uchar v = maps[i]->getValue(x, y, j); + v -= (uchar) floor(0.5 + diff * (float(v) / sum)); + maps[i]->setValue(x, y, j, v); + } + } + } + + void updateTextures() + { + // update all map textures + for (uint i = 0; i < numMaps; ++i) + maps[i]->updateTexture(); + } + + + // helper function for createBaseTexture + float interpolateWeight(size_t x, size_t y, size_t maxX, size_t maxY, size_t channel) + { + // get base position and interpolation + float realPosX = float(x) * width / maxX; + float realPosY = float(y) * height / maxY; + uint posX = (uint)realPosX, posY = (uint)realPosY; + float interpX = realPosX - posX, interpY = realPosY - posY; + // adjust if at borders + if (posX == width-1) + { + --posX; + interpX = 1.0f; + } + if (posY == height-1) + { + --posY; + interpY = 1.0f; + } + float interpXi = 1.0f-interpX, interpYi = 1.0f-interpY; + size_t m = channel/channels; + uint c = (uint) (channel%channels); + + float val = maps[m]->getValue(posX, posY, c) * interpXi * interpYi; + val += maps[m]->getValue(posX+1, posY, c) * interpX * interpYi; + val += maps[m]->getValue(posX+1, posY+1, c) * interpX * interpY; + val += maps[m]->getValue(posX, posY+1, c) * interpXi * interpY; + val /= 255; + return val; + } + + }; + + } + + + + + SplattingManager::SplattingManager(const string& baseName, const string& group, uint width, uint height, uint channels) + { + if (channels < 1 || channels > 4) + OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Number of channels per texture must be between 1 and 4", "SplattingManager::SplattingManager"); + + mImpl = new Impl::SplattingImpl(); + mImpl->baseName = baseName; + mImpl->group = group; + mImpl->width = width; + mImpl->height = height; + mImpl->channels = channels; + mImpl->numTextures = 0; + mImpl->numMaps = 0; + } + + SplattingManager::~SplattingManager() + { + for (uint i = 0; i < mImpl->numMaps; ++i) + delete mImpl->maps[i]; + delete mImpl; + } + + void SplattingManager::setNumTextures(uint numTextures) + { + // the number of maps needed depends on the number of channels per texture + if (numTextures == 0) + setNumMaps(0); + else + setNumMaps((numTextures-1) / mImpl->channels + 1); + } + + uint SplattingManager::getNumTextures() const + { + return mImpl->numTextures; + } + + void SplattingManager::setNumMaps(uint numMaps) + { + mImpl->numMaps = numMaps; + mImpl->numTextures = mImpl->numMaps * mImpl->channels; + + // add maps if we don't have enough + for (size_t i = mImpl->maps.size(); i <= mImpl->numMaps; ++i) + { + mImpl->maps.push_back(new Impl::CoverageMap(mImpl->baseName+StringConverter::toString(i), + mImpl->group, mImpl->width, mImpl->height, mImpl->channels, i != 0)); + } + + // remove maps if there are too many + for (size_t i = mImpl->maps.size(); i > mImpl->numMaps; --i) + { + delete *mImpl->maps.rbegin(); + mImpl->maps.pop_back(); + } + } + + uint SplattingManager::getNumMaps() const + { + return mImpl->numMaps; + } + + NameList SplattingManager::getMapTextureNames() const + { + NameList names; + for (size_t i = 0; i < mImpl->maps.size(); ++i) + names.push_back(mImpl->maps[i]->getName()); + return names; + } + + void SplattingManager::loadMapFromImage(uint mapNum, const Image& image) + { + mImpl->maps[mapNum]->loadFromImage(image); + } + + void SplattingManager::saveMapToImage(uint mapNum, Image& image) + { + mImpl->maps[mapNum]->saveToImage(image); + } + + + void SplattingManager::paint(uint textureNum, int x, int y, const Brush& brush, float intensity) + { + // positions given are supposed to be the mid of the brush + // so adjust accordingly + x -= (int)brush.getWidth()/2; + y -= (int)brush.getHeight()/2; + + // iterate over all fields of the brush array and apply them to the map textures + // if they lie within the bounds + for (size_t i = 0; i < brush.getWidth(); ++i) + { + int posX = x + (int)i; + if (posX < 0 || posX >= (int)mImpl->width) + continue; + for (size_t j = 0; j < brush.getHeight(); ++j) + { + int posY = y + (int)j; + if (posY < 0 || posY >= (int)mImpl->height) + continue; + + mImpl->paint(textureNum, (uint)posX, (uint)posY, brush.at(i, j) * intensity); + } + } + + // finally, update the textures + mImpl->updateTextures(); + } + + + void SplattingManager::createColourMap(Image& image, const ColourList& colours) + { + if (colours.size() > mImpl->numTextures) + OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Given more colours than texture channels available.", __FUNCTION__); + + uchar* data = new uchar[mImpl->width*mImpl->height*3]; + + for (size_t y = 0; y < mImpl->height; ++y) + { + for (size_t x = 0; x < mImpl->width; ++x) + { + ColourValue val (0, 0, 0); + for (size_t i = 0; i < colours.size(); ++i) + { + size_t m = i / mImpl->channels; + uint t = (uint) (i % mImpl->channels); + val += colours[i] * (float(mImpl->maps[m]->getValue((uint)x, (uint)y, t)) / 255); + } + + size_t pos = (x + y * mImpl->width) * 3; + data[pos+0] = uchar(255*val.r); + data[pos+1] = uchar(255*val.g); + data[pos+2] = uchar(255*val.b); + } + } + + image.loadDynamicImage(data, mImpl->width, mImpl->height, 1, PF_BYTE_RGB, true); + } + + + + void SplattingManager::createBaseTexture(Image& image, size_t width, size_t height, + ImageList textures, float repeatX, float repeatZ) + { + if (textures.size() > mImpl->numTextures) + OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Given more textures than texture channels available.", "ET::SplattingManager::createBaseTexture"); + + // first resize the textures according to the desired output size and the repeat values + ushort scaleWidth = (ushort) (width / repeatX); + ushort scaleHeight = (ushort) (height / repeatZ); + for (ImageList::iterator it = textures.begin(); it != textures.end(); ++it) + it->resize(scaleWidth, scaleHeight); + + // create the buffer to hold our generated base texture + uchar* data = new uchar[width*height*3]; + size_t pos = 0; + for (size_t y = 0; y < height; ++y) + { + for (size_t x = 0; x < width; ++x) + { + ColourValue val (0,0,0); + int texX = (int) (x % scaleWidth); + int texY = (int) (y % scaleHeight); + for (size_t t = 0; t < textures.size(); ++t) + { + // get interpolated part of this texture at the current pixel + float weight = mImpl->interpolateWeight(x, y, width, height, t); + // get colour value of the texture image + ColourValue col = textures[t].getColourAt(texX, texY, 0); + // add to the pixel colour level + val += weight*col; + } + + // write colour to our buffer + data[pos+0] = uchar(255*val.r); + data[pos+1] = uchar(255*val.g); + data[pos+2] = uchar(255*val.b); + pos += 3; + } + } + + image.loadDynamicImage(data, width, height, 1, PF_BYTE_RGB, true); + } + + + Image createMinimap(const Image& colourMap, const Image& lightMap) + { + if (colourMap.getWidth() != lightMap.getWidth() || colourMap.getHeight() != lightMap.getHeight()) + OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Images must have the same dimensions.", __FUNCTION__); + + uchar* data = new uchar[colourMap.getWidth()*colourMap.getHeight()*3]; + + for (size_t y = 0; y < colourMap.getWidth(); ++y) + { + for (size_t x = 0; x < colourMap.getHeight(); ++x) + { + ColourValue val = const_cast<Image&>(colourMap).getColourAt((uint)x, (uint)y, 0) * const_cast<Image&>(lightMap).getColourAt((uint)x, (uint)y, 0); + size_t pos = (x + y*colourMap.getWidth()) * 3; + data[pos+0] = uchar(255*val.r); + data[pos+1] = uchar(255*val.g); + data[pos+2] = uchar(255*val.b); + } + } + + Image image; + image.loadDynamicImage(data, colourMap.getWidth(), colourMap.getHeight(), 1, PF_BYTE_RGB, true); + return image; + } +} Added: trunk/python-ogre/ThirdParty/et/ETSplattingManager.h =================================================================== --- trunk/python-ogre/ThirdParty/et/ETSplattingManager.h (rev 0) +++ trunk/python-ogre/ThirdParty/et/ETSplattingManager.h 2007-10-05 04:16:07 UTC (rev 408) @@ -0,0 +1,133 @@ +#ifndef __ETSPLATTINGMANAGER_H__ +#define __ETSPLATTINGMANAGER_H__ + +/* +EDITABLE TERRAIN MANAGER for Ogre +Copyright (C) 2007 Holger Frydrych <h.f...@gm...> + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +As a special exception, you may use this file as part of a free software +library without restriction. Specifically, if other files instantiate +templates or use macros or inline functions from this file, or you compile +this file and link it with other files to produce an executable, this +file does not by itself cause the resulting executable to be covered by +the GNU General Public License. This exception does not however +invalidate any other reasons why the executable file might be covered by +the GNU General Public License. +*/ + +#include "ETPrerequisites.h" + +#include "OgreColourValue.h" +#include "OgreImage.h... [truncated message content] |