1 /* 2 ----------------------------------------------------------------------------- 3 This source file is part of OGRE 4 (Object-oriented Graphics Rendering Engine) 5 For the latest info, see http://www.ogre3d.org/ 6 7 Copyright (c) 2000-2013 Torus Knot Software Ltd 8 9 Permission is hereby granted, free of charge, to any person obtaining a copy 10 of this software and associated documentation files (the "Software"), to deal 11 in the Software without restriction, including without limitation the rights 12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 copies of the Software, and to permit persons to whom the Software is 14 furnished to do so, subject to the following conditions: 15 16 The above copyright notice and this permission notice shall be included in 17 all copies or substantial portions of the Software. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 THE SOFTWARE. 26 ----------------------------------------------------------------------------- 27 */ 28 #include "OgreTerrainLayerBlendMap.h" 29 #include "OgreHardwarePixelBuffer.h" 30 #include "OgreTerrain.h" 31 #include "OgreImage.h" 32 33 #if OGRE_COMPILER == OGRE_COMPILER_MSVC 34 // we do lots of conversions here, casting them all is tedious & cluttered, we know what we're doing 35 # pragma warning (disable : 4244) 36 #endif 37 38 namespace Ogre 39 { 40 //--------------------------------------------------------------------- TerrainLayerBlendMap(Terrain * parent,uint8 layerIndex,HardwarePixelBuffer * buf)41 TerrainLayerBlendMap::TerrainLayerBlendMap(Terrain* parent, uint8 layerIndex, 42 HardwarePixelBuffer* buf) 43 : mParent(parent) 44 , mLayerIdx(layerIndex) 45 , mChannel((layerIndex-1) % 4) 46 , mDirty(false) 47 , mBuffer(buf) 48 , mData(0) 49 { 50 mData = static_cast<float*>(OGRE_MALLOC(mBuffer->getWidth() * mBuffer->getHeight() * sizeof(float), MEMCATEGORY_RESOURCE)); 51 52 // we know which of RGBA we need to look at, now find it in the format 53 // because we can't guarantee what precise format the RS gives us 54 unsigned char rgbaShift[4]; 55 PixelFormat fmt = mBuffer->getFormat(); 56 PixelUtil::getBitShifts(fmt, rgbaShift); 57 mChannelOffset = rgbaShift[mChannel] / 8; // /8 to convert to bytes 58 #if OGRE_ENDIAN == OGRE_ENDIAN_BIG 59 // invert (dealing bytewise) 60 mChannelOffset = PixelUtil::getNumElemBytes(fmt) - mChannelOffset - 1; 61 #endif 62 download(); 63 64 } 65 //--------------------------------------------------------------------- ~TerrainLayerBlendMap()66 TerrainLayerBlendMap::~TerrainLayerBlendMap() 67 { 68 OGRE_FREE(mData, MEMCATEGORY_RESOURCE); 69 mData = 0; 70 } 71 //--------------------------------------------------------------------- download()72 void TerrainLayerBlendMap::download() 73 { 74 float* pDst = mData; 75 // Download data 76 Image::Box box(0, 0, mBuffer->getWidth(), mBuffer->getHeight()); 77 uint8* pSrc = static_cast<uint8*>(mBuffer->lock(box, HardwareBuffer::HBL_READ_ONLY).data); 78 pSrc += mChannelOffset; 79 size_t srcInc = PixelUtil::getNumElemBytes(mBuffer->getFormat()); 80 for (size_t y = box.top; y < box.bottom; ++y) 81 { 82 for (size_t x = box.left; x < box.right; ++x) 83 { 84 *pDst++ = static_cast<float>(*pSrc) / 255.0f; 85 pSrc += srcInc; 86 } 87 } 88 mBuffer->unlock(); 89 90 } 91 //--------------------------------------------------------------------- convertWorldToUVSpace(const Vector3 & worldPos,Real * outX,Real * outY)92 void TerrainLayerBlendMap::convertWorldToUVSpace(const Vector3& worldPos, Real *outX, Real* outY) 93 { 94 Vector3 terrainSpace; 95 mParent->getTerrainPosition(worldPos, &terrainSpace); 96 *outX = terrainSpace.x; 97 *outY = 1.0f - terrainSpace.y; 98 } 99 //--------------------------------------------------------------------- convertUVToWorldSpace(Real x,Real y,Vector3 * outWorldPos)100 void TerrainLayerBlendMap::convertUVToWorldSpace(Real x, Real y, Vector3* outWorldPos) 101 { 102 mParent->getPosition(x, 1.0f - y, 0, outWorldPos); 103 } 104 //--------------------------------------------------------------------- convertUVToImageSpace(Real x,Real y,size_t * outX,size_t * outY)105 void TerrainLayerBlendMap::convertUVToImageSpace(Real x, Real y, size_t* outX, size_t* outY) 106 { 107 *outX = (unsigned long)(x * (mBuffer->getWidth() - 1)); 108 *outY = (unsigned long)(y * (mBuffer->getHeight() - 1)); 109 } 110 //--------------------------------------------------------------------- convertImageToUVSpace(size_t x,size_t y,Real * outX,Real * outY)111 void TerrainLayerBlendMap::convertImageToUVSpace(size_t x, size_t y, Real* outX, Real* outY) 112 { 113 *outX = x / (Real)(mBuffer->getWidth() - 1); 114 *outY = y / (Real)(mBuffer->getHeight() - 1); 115 } 116 //--------------------------------------------------------------------- convertImageToTerrainSpace(size_t x,size_t y,Real * outX,Real * outY)117 void TerrainLayerBlendMap::convertImageToTerrainSpace(size_t x, size_t y, Real* outX, Real* outY) 118 { 119 convertImageToUVSpace(x, y, outX, outY); 120 *outY = 1.0f - *outY; 121 } 122 //--------------------------------------------------------------------- convertTerrainToImageSpace(Real x,Real y,size_t * outX,size_t * outY)123 void TerrainLayerBlendMap::convertTerrainToImageSpace(Real x, Real y, size_t* outX, size_t* outY) 124 { 125 convertUVToImageSpace(x, 1.0f - y, outX, outY); 126 } 127 //--------------------------------------------------------------------- getBlendValue(size_t x,size_t y)128 float TerrainLayerBlendMap::getBlendValue(size_t x, size_t y) 129 { 130 return *(mData + y * mBuffer->getWidth() + x); 131 } 132 //--------------------------------------------------------------------- setBlendValue(size_t x,size_t y,float val)133 void TerrainLayerBlendMap::setBlendValue(size_t x, size_t y, float val) 134 { 135 *(mData + y * mBuffer->getWidth() + x) = val; 136 dirtyRect(Rect(x, y, x+1, y+1)); 137 138 } 139 //--------------------------------------------------------------------- getBlendPointer()140 float* TerrainLayerBlendMap::getBlendPointer() 141 { 142 return mData; 143 } 144 //--------------------------------------------------------------------- dirty()145 void TerrainLayerBlendMap::dirty() 146 { 147 Rect rect; 148 rect.top = 0; rect.bottom = mBuffer->getHeight(); 149 rect.left = 0; rect.right = mBuffer->getWidth(); 150 dirtyRect(rect); 151 152 } 153 //--------------------------------------------------------------------- dirtyRect(const Rect & rect)154 void TerrainLayerBlendMap::dirtyRect(const Rect& rect) 155 { 156 if (mDirty) 157 { 158 mDirtyBox.left = std::min(mDirtyBox.left, static_cast<uint32>(rect.left)); 159 mDirtyBox.top = std::min(mDirtyBox.top, static_cast<uint32>(rect.top)); 160 mDirtyBox.right = std::max(mDirtyBox.right, static_cast<uint32>(rect.right)); 161 mDirtyBox.bottom = std::max(mDirtyBox.bottom, static_cast<uint32>(rect.bottom)); 162 } 163 else 164 { 165 mDirtyBox.left = static_cast<uint32>(rect.left); 166 mDirtyBox.right = static_cast<uint32>(rect.right); 167 mDirtyBox.top = static_cast<uint32>(rect.top); 168 mDirtyBox.bottom = static_cast<uint32>(rect.bottom); 169 mDirty = true; 170 } 171 } 172 //--------------------------------------------------------------------- update()173 void TerrainLayerBlendMap::update() 174 { 175 if (mData && mDirty) 176 { 177 // Upload data 178 float* pSrcBase = mData + mDirtyBox.top * mBuffer->getWidth() + mDirtyBox.left; 179 uint8* pDstBase = static_cast<uint8*>(mBuffer->lock(mDirtyBox, HardwarePixelBuffer::HBL_NORMAL).data); 180 pDstBase += mChannelOffset; 181 size_t dstInc = PixelUtil::getNumElemBytes(mBuffer->getFormat()); 182 for (size_t y = 0; y < mDirtyBox.getHeight(); ++y) 183 { 184 float* pSrc = pSrcBase + y * mBuffer->getWidth(); 185 uint8* pDst = pDstBase + y * mBuffer->getWidth() * dstInc; 186 for (size_t x = 0; x < mDirtyBox.getWidth(); ++x) 187 { 188 *pDst = static_cast<uint8>(*pSrc++ * 255); 189 pDst += dstInc; 190 } 191 } 192 mBuffer->unlock(); 193 194 mDirty = false; 195 196 // make sure composite map is updated 197 // mDirtyBox is in image space, convert to terrain units 198 Rect compositeMapRect; 199 float blendToTerrain = (float)mParent->getSize() / (float)mBuffer->getWidth(); 200 compositeMapRect.left = (long)(mDirtyBox.left * blendToTerrain); 201 compositeMapRect.right = (long)(mDirtyBox.right * blendToTerrain + 1); 202 compositeMapRect.top = (long)((mBuffer->getHeight() - mDirtyBox.bottom) * blendToTerrain); 203 compositeMapRect.bottom = (long)((mBuffer->getHeight() - mDirtyBox.top) * blendToTerrain + 1); 204 mParent->_dirtyCompositeMapRect(compositeMapRect); 205 mParent->updateCompositeMapWithDelay(); 206 207 } 208 } 209 //--------------------------------------------------------------------- blit(const PixelBox & src,const Box & dstBox)210 void TerrainLayerBlendMap::blit(const PixelBox &src, const Box &dstBox) 211 { 212 const PixelBox* srcBox = &src; 213 214 if (srcBox->getWidth() != dstBox.getWidth() || srcBox->getHeight() != dstBox.getHeight()) 215 { 216 // we need to rescale src to dst size first (also confvert format) 217 void* tmpData = OGRE_MALLOC(dstBox.getWidth() * dstBox.getHeight(), MEMCATEGORY_GENERAL); 218 srcBox = OGRE_NEW PixelBox(dstBox.getWidth(), dstBox.getHeight(), 1, PF_L8, tmpData); 219 220 Image::scale(src, *srcBox); 221 } 222 223 // pixel conversion 224 PixelBox dstMemBox(dstBox, PF_L8, mData); 225 PixelUtil::bulkPixelConversion(*srcBox, dstMemBox); 226 227 if (srcBox != &src) 228 { 229 // free temp 230 OGRE_FREE(srcBox->data, MEMCATEGORY_GENERAL); 231 OGRE_DELETE srcBox; 232 srcBox = 0; 233 } 234 235 Rect dRect(dstBox.left, dstBox.top, dstBox.right, dstBox.bottom); 236 dirtyRect(dRect); 237 238 } 239 //--------------------------------------------------------------------- blit(const PixelBox & src)240 void TerrainLayerBlendMap::blit(const PixelBox &src) 241 { 242 blit(src, Box(0,0,0,mBuffer->getWidth(),mBuffer->getHeight(),1)); 243 } 244 //--------------------------------------------------------------------- loadImage(const Image & img)245 void TerrainLayerBlendMap::loadImage(const Image& img) 246 { 247 blit(img.getPixelBox()); 248 } 249 //--------------------------------------------------------------------- loadImage(DataStreamPtr & stream,const String & ext)250 void TerrainLayerBlendMap::loadImage(DataStreamPtr& stream, const String& ext) 251 { 252 Image img; 253 img.load(stream, ext); 254 loadImage(img); 255 } 256 //--------------------------------------------------------------------- loadImage(const String & filename,const String & groupName)257 void TerrainLayerBlendMap::loadImage(const String& filename, const String& groupName) 258 { 259 Image img; 260 img.load(filename, groupName); 261 loadImage(img); 262 } 263 264 265 } 266 267