Rigs of Rods 2026.01
Soft-body Physics Simulation
Loading...
Searching...
No Matches
PropertyMaps.cpp
Go to the documentation of this file.
1/*-------------------------------------------------------------------------------------
2Copyright (c) 2006 John Judnich
3
4This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.
5Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
61. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
72. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
83. This notice may not be removed or altered from any source distribution.
9-------------------------------------------------------------------------------------*/
10
11#include <OgreRoot.h>
12#include <OgrePrerequisites.h>
13#include <OgrePixelFormat.h>
14#include <OgreTexture.h>
15#include <OgreTextureManager.h>
16#include <OgreHardwarePixelBuffer.h>
17#include <OgreRenderSystem.h>
18#include <OgreString.h>
19#include <OgreStringConverter.h>
20
21#include "PropertyMaps.h"
22#include "PagedGeometry.h"
23
24using namespace Ogre;
25
26namespace Forests {
27
28std::map<String, DensityMap*> DensityMap::selfList;
29
30DensityMap *DensityMap::load(const String &fileName, MapChannel channel)
31{
32 //Load image
33 TexturePtr map = TextureManager::getSingleton().load(fileName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, 0);
34
35 //Copy image to pixelbox
36 return load(map, channel);
37}
38
39DensityMap *DensityMap::load(TexturePtr texture, MapChannel channel)
40{
41 const String key = texture->getName() + StringConverter::toString((int)channel);
42
43 std::map<String, DensityMap*>::iterator i;
44 i = selfList.find(key);
45
46 DensityMap *m;
47 if (i != selfList.end())
48 m = i->second;
49 else
50 m = new DensityMap(texture, channel);
51
52 ++(m->refCount);
53 return m;
54}
55
57{
58 --refCount;
59 if (refCount == 0)
60 delete this;
61}
62
64{
65 assert(pixels);
66 delete[] static_cast<uint8*>(pixels->data);
67 delete pixels;
68
69 //Remove self from selfList
70 selfList.erase(selfKey);
71}
72
73DensityMap::DensityMap(TexturePtr map, MapChannel channel)
74{
75 assert(map.isNull() == false);
77
78 //Add self to selfList
79 selfKey = map->getName() + StringConverter::toString((int)channel);
80 selfList.insert(std::pair<String, DensityMap*>(selfKey, this));
81 refCount = 0;
82
83 //Get the texture buffer
84 HardwarePixelBufferSharedPtr buff = map->getBuffer();
85
86 //Prepare a PixelBox (8-bit greyscale) to receive the density values
87 pixels = new PixelBox(Box(0, 0, buff->getWidth(), buff->getHeight()), PF_BYTE_L);
88 pixels->data = new uint8[pixels->getConsecutiveSize()];
89
90 if (channel == CHANNEL_COLOR){
91 //Copy to the greyscale density map directly if no channel extraction is necessary
92 buff->blitToMemory(*pixels);
93 } else {
94 //If channel extraction is necessary, first convert to a PF_R8G8B8A8 format PixelBox
95 //This is necessary for the code below to properly extract the desired channel
96 PixelBox tmpPixels(Box(0, 0, buff->getWidth(), buff->getHeight()), PF_R8G8B8A8);
97 tmpPixels.data = new uint8[tmpPixels.getConsecutiveSize()];
98 buff->blitToMemory(tmpPixels);
99
100 //Pick out a channel from the pixel buffer
101 size_t channelOffset;
102 switch (channel){
103 case CHANNEL_RED: channelOffset = 3; break;
104 case CHANNEL_GREEN: channelOffset = 2; break;
105 case CHANNEL_BLUE: channelOffset = 1; break;
106 case CHANNEL_ALPHA: channelOffset = 0; break;
107 default: OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Invalid channel", "GrassLayer::setDensityMap()"); break;
108 }
109
110 //And copy that channel into the density map
111 uint8 *inputPtr = (uint8*)tmpPixels.data + channelOffset;
112 uint8 *outputPtr = (uint8*)pixels->data;
113 uint8 *outputEndPtr = outputPtr + pixels->getConsecutiveSize();
114 while (outputPtr != outputEndPtr){
115 *outputPtr++ = *inputPtr;
116 inputPtr += 4;
117 }
118
119 //Finally, delete the temporary PF_R8G8B8A8 pixel buffer
120 delete[] static_cast<uint8*>(tmpPixels.data);
121 }
122}
123
124
125//Returns the density map value at the given location
126//Make sure a density map exists before calling this.
127Ogre::Real DensityMap::_getDensityAt_Unfiltered(Ogre::Real x, Ogre::Real z, const TRect<Real> &mapBounds)
128{
129 assert(pixels);
130
131 // Early out if the coordinates are outside map bounds.
132 if(x < mapBounds.left || x >= mapBounds.right || z < mapBounds.top || z >= mapBounds.bottom)
133 return 0.f;
134
135 size_t mapWidth = pixels->getWidth(), mapHeight = pixels->getHeight();
136
137/* not needed anymore
138#if OGRE_PLATFORM != OGRE_PLATFORM_APPLE
139 // Patch incorrect PixelBox::getWidth() in OpenGL mode
140 if (Root::getSingleton().getRenderSystem()->getName() == "OpenGL Rendering Subsystem")
141 --mapWidth;
142#endif //OGRE_PLATFORM_APPLE
143*/
144
145 size_t xindex = size_t(mapWidth * (x - mapBounds.left) / mapBounds.width());
146 size_t zindex = size_t(mapHeight * (z - mapBounds.top) / mapBounds.height());
147
148 uint8 *data = reinterpret_cast<uint8*>(pixels->data);
149 return data[mapWidth * zindex + xindex] * 0.00392157f; // 1/255.0f;
150}
151
152//Returns the density map value at the given location with bilinear filtering
153//Make sure a density map exists before calling this.
154Ogre::Real DensityMap::_getDensityAt_Bilinear(Ogre::Real x, Ogre::Real z, const TRect<Ogre::Real> &mapBounds)
155{
156 assert(pixels);
157
158 // Early out if the coordinates are outside map bounds.
159 if(x < mapBounds.left || x >= mapBounds.right || z < mapBounds.top || z >= mapBounds.bottom)
160 return 0.f;
161
162 uint32 mapWidth = (uint32)pixels->getWidth();
163 uint32 mapHeight = (uint32)pixels->getHeight();
164
165/* not needed anymore
166#if OGRE_PLATFORM != OGRE_PLATFORM_APPLE
167 //Patch incorrect PixelBox::getWidth() in OpenGL mode
168 if (Root::getSingleton().getRenderSystem()->getName() == "OpenGL Rendering Subsystem")
169 --mapWidth;
170#endif //OGRE_PLATFORM_APPLE
171*/
172
173 Ogre::Real xIndexFloat = (mapWidth * (x - mapBounds.left) / mapBounds.width()) - 0.5f;
174 Ogre::Real zIndexFloat = (mapHeight * (z - mapBounds.top) / mapBounds.height()) - 0.5f;
175
176 uint32 xIndex = (uint32)xIndexFloat;
177 uint32 zIndex = (uint32)zIndexFloat;
178 if (xIndex < 0 || zIndex < 0 || xIndex >= mapWidth-1 || zIndex >= mapHeight-1)
179 return 0.0f;
180
181 Ogre::Real xRatio = xIndexFloat - xIndex;
182 Ogre::Real xRatioInv = 1.f - xRatio;
183 Ogre::Real zRatio = zIndexFloat - zIndex;
184 Ogre::Real zRatioInv = 1.f - zRatio;
185
186 uint8 *data = (uint8*)pixels->data;
187
188 Ogre::Real val11 = data[mapWidth * zIndex + xIndex] * 0.0039215686274509803921568627451f;
189 Ogre::Real val21 = data[mapWidth * zIndex + xIndex + 1] * 0.0039215686274509803921568627451f;
190 Ogre::Real val12 = data[mapWidth * ++zIndex + xIndex] * 0.0039215686274509803921568627451f;
191 Ogre::Real val22 = data[mapWidth * zIndex + xIndex + 1] * 0.0039215686274509803921568627451f;
192
193 Ogre::Real val1 = xRatioInv * val11 + xRatio * val21;
194 Ogre::Real val2 = xRatioInv * val12 + xRatio * val22;
195
196 return zRatioInv * val1 + zRatio * val2;
197}
198
199
200
201//----------------------------------------------------------------------------------------------
202
203std::map<String, ColorMap*> ColorMap::selfList;
204
205ColorMap *ColorMap::load(const String &fileName, MapChannel channel)
206{
207 //Load image
208 TexturePtr map = TextureManager::getSingleton().load(fileName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
209
210 //Copy image to pixelbox
211 return load(map, channel);
212}
213
214ColorMap *ColorMap::load(TexturePtr texture, MapChannel channel)
215{
216 const String key = texture->getName() + StringConverter::toString((int)channel);
217
218 std::map<String, ColorMap*>::iterator i;
219 i = selfList.find(key);
220
221 ColorMap *m;
222 if (i != selfList.end())
223 m = i->second;
224 else
225 m = new ColorMap(texture, channel);
226
227 ++(m->refCount);
228 return m;
229}
230
232{
233 --refCount;
234 if (refCount == 0)
235 delete this;
236}
237
239{
240 assert(pixels);
241 delete[] static_cast<uint8*>(pixels->data);
242 delete pixels;
243
244 //Remove self from selfList
245 selfList.erase(selfKey);
246}
247
248ColorMap::ColorMap(TexturePtr map, MapChannel channel)
249{
250 assert(map.isNull() == false);
252
253 //Add self to selfList
254 selfKey = map->getName() + StringConverter::toString((int)channel);
255 selfList.insert(std::pair<String, ColorMap*>(selfKey, this));
256 refCount = 0;
257
258 //Get the texture buffer
259 HardwarePixelBufferSharedPtr buff = map->getBuffer();
260
261 //Prepare a PixelBox (24-bit RGB) to receive the color values
262 VertexElementType format = Root::getSingleton().getRenderSystem()->getColourVertexElementType();
263 switch (format){
264 case VET_COLOUR_ARGB:
265 //DirectX9
266 pixels = new PixelBox(Box(0, 0, buff->getWidth(), buff->getHeight()), PF_A8R8G8B8);
267 break;
268 case VET_COLOUR_ABGR:
269 //OpenGL
270 pixels = new PixelBox(Box(0, 0, buff->getWidth(), buff->getHeight()), PF_A8B8G8R8);
271 //Patch for Ogre's incorrect blitToMemory() when copying from PF_L8 in OpenGL
272 if (buff->getFormat() == PF_L8)
273 channel = CHANNEL_RED;
274 break;
275 default:
276 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Unknown RenderSystem color format", "GrassLayer::setColorMap()");
277 break;
278 }
279
280 pixels->data = new uint8[pixels->getConsecutiveSize()];
281
282 if (channel == CHANNEL_COLOR){
283 //Copy to the color map directly if no channel extraction is necessary
284 buff->blitToMemory(*pixels);
285 } else {
286 //If channel extraction is necessary, first convert to a PF_R8G8B8A8 format PixelBox
287 //This is necessary for the code below to properly extract the desired channel
288 PixelBox tmpPixels(Box(0, 0, buff->getWidth(), buff->getHeight()), PF_R8G8B8A8);
289 tmpPixels.data = new uint8[tmpPixels.getConsecutiveSize()];
290 buff->blitToMemory(tmpPixels);
291
292 //Pick out a channel from the pixel buffer
293 size_t channelOffset;
294 switch (channel){
295 case CHANNEL_RED: channelOffset = 3; break;
296 case CHANNEL_GREEN: channelOffset = 2; break;
297 case CHANNEL_BLUE: channelOffset = 1; break;
298 case CHANNEL_ALPHA: channelOffset = 0; break;
299 default: OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Invalid channel", "ColorMap::ColorMap()"); break;
300 }
301
302 //And copy that channel into the density map
303 uint8 *inputPtr = (uint8*)tmpPixels.data + channelOffset;
304 uint8 *outputPtr = (uint8*)pixels->data;
305 uint8 *outputEndPtr = outputPtr + pixels->getConsecutiveSize();
306 while (outputPtr != outputEndPtr){
307 *outputPtr++ = *inputPtr;
308 *outputPtr++ = *inputPtr;
309 *outputPtr++ = *inputPtr;
310 *outputPtr++ = 0xFF; //Full alpha
311 inputPtr += 4;
312 }
313
314 //Finally, delete the temporary PF_R8G8B8A8 pixel buffer
315 delete[] static_cast<uint8*>(tmpPixels.data);
316 }
317}
318
319//Returns the color map value at the given location
320uint32 ColorMap::_getColorAt(Ogre::Real x, Ogre::Real z, const TRect<Real> &mapBounds)
321{
322 assert(pixels);
323
324 // Early out if the coordinates are outside map bounds.
325 if(x < mapBounds.left || x >= mapBounds.right || z < mapBounds.top || z >= mapBounds.bottom)
326 {
327 return 0xFFFFFFFF;
328 }
329
330 uint32 mapWidth = (uint32)pixels->getWidth();
331 uint32 mapHeight = (uint32)pixels->getHeight();
332
333 uint32 xindex = uint32(mapWidth * (x - mapBounds.left) / mapBounds.width());
334 uint32 zindex = uint32(mapHeight * (z - mapBounds.top) / mapBounds.height());
335
336 uint32 *data = (uint32*)pixels->data;
337 return data[mapWidth * zindex + xindex];
338}
339
340uint32 ColorMap::_interpolateColor(uint32 color1, uint32 color2, Ogre::Real ratio, Ogre::Real ratioInv)
341{
342 uint8 a1 = (color1 & 0xFF);
343 uint8 b1 = (color1 >> 8 & 0xFF);
344 uint8 c1 = (color1 >> 16 & 0xFF);
345 uint8 d1 = (color1 >> 24 & 0xFF);
346
347 uint8 a2 = (color2 & 0xFF);
348 uint8 b2 = (color2 >> 8 & 0xFF);
349 uint8 c2 = (color2 >> 16 & 0xFF);
350 uint8 d2 = (color2 >> 24 & 0xFF);
351
352 uint8 a = uint8(ratioInv * a1 + ratio * a2);
353 uint8 b = uint8(ratioInv * b1 + ratio * b2);
354 uint8 c = uint8(ratioInv * c1 + ratio * c2);
355 uint8 d = uint8(ratioInv * d1 + ratio * d2);
356
357 return a | (b << 8) | (c << 16) | (d << 24);
358}
359
360uint32 ColorMap::_getColorAt_Bilinear(Ogre::Real x, Ogre::Real z, const TRect<Real> &mapBounds)
361{
362 assert(pixels);
363
364 // Early out if the coordinates are outside map bounds.
365 if(x < mapBounds.left || x >= mapBounds.right || z < mapBounds.top || z >= mapBounds.bottom)
366 {
367 return 0xFFFFFFFF;
368 }
369
370 uint32 mapWidth = (uint32)pixels->getWidth();
371 uint32 mapHeight = (uint32)pixels->getHeight();
372 Ogre::Real xIndexFloat = (mapWidth * (x - mapBounds.left) / mapBounds.width()) - 0.5f;
373 Ogre::Real zIndexFloat = (mapHeight * (z - mapBounds.top) / mapBounds.height()) - 0.5f;
374
375 uint32 xIndex = (uint32)xIndexFloat;
376 uint32 zIndex = (uint32)zIndexFloat;
377 if (xIndex < 0 || zIndex < 0 || xIndex > mapWidth-1 || zIndex > mapHeight-1)
378 return 0xFFFFFFFF;
379
380 Ogre::Real xRatio = xIndexFloat - xIndex;
381 Ogre::Real xRatioInv = 1.f - xRatio;
382 Ogre::Real zRatio = zIndexFloat - zIndex;
383 Ogre::Real zRatioInv = 1.f - zRatio;
384
385 uint32 *data = (uint32*)pixels->data;
386
387 uint32 val11 = data[mapWidth * zIndex + xIndex];
388 uint32 val21 = data[mapWidth * zIndex + xIndex + 1];
389 uint32 val12 = data[mapWidth * ++zIndex + xIndex];
390 uint32 val22 = data[mapWidth * zIndex + xIndex + 1];
391
392 uint32 val1 = _interpolateColor(val11, val21, xRatio, xRatioInv);
393 uint32 val2 = _interpolateColor(val12, val22, xRatio, xRatioInv);
394
395 uint32 val = _interpolateColor(val1, val2, zRatio, zRatioInv);
396
397 return val;
398}
399}
A 2D greyscale image that is assigned to a certain region of your world to represent color levels.
Ogre::PixelBox * pixels
ColorMap(Ogre::TexturePtr map, MapChannel channel)
Ogre::String selfKey
static ColorMap * load(const Ogre::String &fileName, MapChannel channel=CHANNEL_COLOR)
Ogre::uint32 _getColorAt_Bilinear(Ogre::Real x, Ogre::Real z, const Ogre::TRect< Ogre::Real > &mapBounds)
Ogre::uint32 _getColorAt(Ogre::Real x, Ogre::Real z, const Ogre::TRect< Ogre::Real > &mapBounds)
Ogre::TRect< Ogre::Real > mapBounds
static std::map< Ogre::String, ColorMap * > selfList
Ogre::uint32 refCount
Ogre::uint32 _interpolateColor(Ogre::uint32 color1, Ogre::uint32 color2, Ogre::Real ratio, Ogre::Real ratioInv)
Ogre::Real _getDensityAt_Bilinear(Ogre::Real x, Ogre::Real z, const Ogre::TRect< Ogre::Real > &mapBounds)
static std::map< Ogre::String, DensityMap * > selfList
Ogre::PixelBox * pixels
DensityMap(Ogre::TexturePtr texture, MapChannel channel)
static DensityMap * load(const Ogre::String &fileName, MapChannel channel=CHANNEL_COLOR)
Ogre::uint32 refCount
Ogre::Real _getDensityAt_Unfiltered(Ogre::Real x, Ogre::Real z, const Ogre::TRect< Ogre::Real > &mapBounds)
Ogre::String selfKey
@ MAPFILTER_BILINEAR
Use bilinear filtering - slower, but will appear less blocky.
MapChannel
Specifies which color channel(s) to extract from an image.
@ CHANNEL_GREEN
Use only the image's green color channel.
@ CHANNEL_BLUE
Use only the image's blue color channel.
@ CHANNEL_ALPHA
Use only the image's alpha channel.
@ CHANNEL_RED
Use only the image's red color channel.
@ CHANNEL_COLOR
Use the image's full RGB color information.