1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2014-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "screenshot_islands.h"
22 #include <game_share/scenario_entry_points.h>
24 #include <game_share/season.h>
25 #include <game_share/dir_light_setup.h>
26 #include <game_share/bmp4image.h>
28 #include <nel/misc/path.h>
29 #include <nel/misc/file.h>
30 #include <nel/misc/config_file.h>
31 #include <nel/misc/big_file.h>
32 #include <nel/misc/i18n.h>
33 #include <nel/misc/progress_callback.h>
34 #include <nel/misc/random.h>
35 #include <nel/misc/common.h>
36 #include <nel/misc/wang_hash.h>
37 #include <nel/3d/u_material.h>
39 #include <nel/3d/u_driver.h>
40 #include <nel/3d/u_scene.h>
41 #include <nel/3d/u_landscape.h>
42 #include <nel/3d/u_camera.h>
43 #include <nel/3d/landscapeig_manager.h>
44 #include <nel/3d/u_material.h>
46 #include <nel/georges/u_form_loader.h>
47 #include <nel/georges/u_form.h>
48 #include <nel/georges/u_form_elm.h>
51 #include <ai_share/world_map.h>
53 #include <nel/3d/material.h>
58 using namespace NLMISC
;
61 using namespace EGSPD
;
62 using namespace NLGEORGES
;
63 using namespace RYAI_MAP_CRUNCH
;
67 UDriver
*driver
= NULL
;
68 CLandscapeIGManager LandscapeIGManager
;
71 uint ScreenShotHeight
;
73 UMaterial sceneMaterial
;
78 const TBufferEntry InteriorValue
= std::numeric_limits
<TBufferEntry
>::max()-1;
79 const TBufferEntry ValueBorder
= std::numeric_limits
<TBufferEntry
>::max()-2;
80 const uint32 BigValue
= 15*5;
81 const float limitValue
= 200.0;
83 //-------------------------------------------------------------------------------------------------
84 CScreenshotIslands::CScreenshotIslands()
86 _BackColor
= CRGBA(255, 255, 255, 255);
89 //-------------------------------------------------------------------------------------------------
90 void CScreenshotIslands::init()
93 driver
= UDriver::createDriver(0, true);
96 sceneMaterial
= driver
->createMaterial();
97 sceneMaterial
.getObjectPtr()->setLighting(true);
98 sceneMaterial
.getObjectPtr()->setSpecular(CRGBA(255, 255, 255, 255));
99 sceneMaterial
.getObjectPtr()->setShininess(50);
100 sceneMaterial
.getObjectPtr()->setDiffuse(CRGBA(100, 100, 100, 255));
101 sceneMaterial
.getObjectPtr()->setEmissive(CRGBA(25, 25, 25, 255));
103 // load and parse the configfile
105 cf
.load("island_screenshots.cfg");
107 // get the value of searchPaths
108 CConfigFile::CVar
* searchPaths
= cf
.getVarPtr("SearchPaths");
111 for(int i
= 0; i
< searchPaths
->size(); i
++)
113 CPath::addSearchPath(searchPaths
->asString(i
).c_str(), true, false);
116 CPath::remapExtension("dds", "tga", true);
117 CPath::remapExtension("dds", "png", true);
119 // get the scenario entry points file
120 CConfigFile::CVar
* epFile
= cf
.getVarPtr("CompleteIslandsFile");
123 _CompleteIslandsFile
= epFile
->asString();
126 // get the out directory path
127 CConfigFile::CVar
* outDir
= cf
.getVarPtr("OutDir");
130 _OutDirectory
= outDir
->asString();
133 // get the vegetation option
134 CConfigFile::CVar
* veget
= cf
.getVarPtr("Vegetation");
137 _Vegetation
= veget
->asBool();
140 // get the vegetation option
141 CConfigFile::CVar
* inverseZTest
= cf
.getVarPtr("InverseZTest");
144 _InverseZTest
= inverseZTest
->asBool();
147 // get list of continents
148 CConfigFile::CVar
* continents
= cf
.getVarPtr("Continents");
149 vector
<string
> continentsName(continents
->size());
150 for(int i
= 0; i
< continents
->size(); i
++)
152 continentsName
[i
] = continents
->asString(i
);
155 // get continents data (light, coarseMesh,...)
156 UFormLoader
* formLoader
;
157 for(uint i
=0; i
<continentsName
.size(); i
++)
159 string georgeFileName
= continentsName
[i
]+".continent";
161 formLoader
= UFormLoader::createLoader();
162 CSmartPtr
<UForm
> form
= formLoader
->loadForm(CPath::lookup(georgeFileName
).c_str());
165 CContinentData continentData
;
167 UFormElm
&formRoot
= form
->getRootNode();
170 if(formRoot
.getNodeByName(&elm
, "LightLandscapeDay") && elm
)
172 CDirLightSetup landscapeLightDay
;
173 landscapeLightDay
.build(*elm
);
174 continentData
.Ambiant
= landscapeLightDay
.Ambiant
;
175 continentData
.Diffuse
= landscapeLightDay
.Diffuse
;
177 if(continentsName
[i
]=="r2_jungle" || continentsName
[i
]=="r2_forest" || continentsName
[i
]=="r2_roots")
179 continentData
.Ambiant
= CRGBA(255, 255, 255, 255);
180 continentData
.Diffuse
= CRGBA(255, 255, 255, 255);
184 formRoot
.getValueByName(continentData
.IGFile
, "LandscapeIG");
185 string zoneMin
, zoneMax
;
186 formRoot
.getValueByName(zoneMin
, "ZoneMin");
187 formRoot
.getValueByName(zoneMax
, "ZoneMax");
189 getPosFromZoneName(zoneMin
, continentData
.ZoneMin
);
190 getPosFromZoneName(zoneMax
, continentData
.ZoneMax
);
193 if(formRoot
.getValueByName(filename
, "Ecosystem"))
195 UFormLoader
*formLoaderEco
= UFormLoader::createLoader();
199 CSmartPtr
<UForm
> formEco
= formLoaderEco
->loadForm(filename
.c_str());
204 UFormElm
&formRootEco
= formEco
->getRootNode();
207 formRootEco
.getValueByName(continentData
.SmallBank
, "SmallBank");
210 formRootEco
.getValueByName(continentData
.FarBank
, "FarBank");
212 // Coarse mesh texture.
213 formRootEco
.getValueByName(continentData
.CoarseMeshMap
, "CoarseMeshMap");
217 nlwarning("CScreenshotIslands::init : Can't load form %s.", filename
.c_str());
219 UFormLoader::releaseLoader(formLoaderEco
);
223 _ContinentsData
[continentsName
[i
]] = continentData
;
225 UFormLoader::releaseLoader(formLoader
);
232 searchIslandsBorders();
235 CConfigFile::CVar
* seasonSuffixes
= cf
.getVarPtr("SeasonSuffixes");
238 for(uint i
= 0; i
< (uint
)seasonSuffixes
->size(); i
++)
240 _SeasonSuffixes
.push_back(seasonSuffixes
->asString(i
));
244 // get the meter size in pixels
245 CConfigFile::CVar
* meterSize
= cf
.getVarPtr("MeterPixelSize");
248 _MeterPixelSize
= meterSize
->asInt();
252 //-------------------------------------------------------------------------------------------------
253 bool CScreenshotIslands::getPosFromZoneName(const std::string
&name
, NLMISC::CVector2f
&dest
)
257 nlwarning ("getPosFromZoneName(): empty name, can't getPosFromZoneName");
261 static std::string zoneName
;
262 static string xStr
, yStr
;
265 zoneName
= CFile::getFilenameWithoutExtension(name
);
267 while(zoneName
[i
] != '_')
269 if(!::isdigit(zoneName
[i
])) return false;
270 yStr
+= zoneName
[i
]; ++i
;
271 if(i
== zoneName
.size())
275 while(i
< zoneName
.size())
277 if(!::isalpha(zoneName
[i
])) return false;
278 xStr
+= (char) ::toupper(zoneName
[i
]); ++i
;
280 if(xStr
.size() != 2) return false;
281 dest
.x
= 160.f
* ((xStr
[0] - 'A') * 26 + (xStr
[1] - 'A'));
282 dest
.y
= 160.f
* -atoi(yStr
.c_str());
286 //-------------------------------------------------------------------------------------------------
287 void CScreenshotIslands::searchIslandsBorders()
289 vector
<string
> filenames
;
290 list
<string
> zonelFiles
;
292 map
< CVector2f
, bool> islandsMap
;
294 TContinentsData::iterator
itCont(_ContinentsData
.begin()), lastCont(_ContinentsData
.end());
295 for( ; itCont
!= lastCont
; ++itCont
)
297 // for each continent we recover a map of zonel files whith position of
298 // left/bottom point of each zone for keys
302 string bnpFileName
= itCont
->first
+ ".bnp";
303 CBigFile::getInstance().list(bnpFileName
.c_str(), filenames
); // FIXME FIXME NOT READING FROM BNP!
305 for(uint i
=0; i
<filenames
.size(); i
++)
307 if(CFile::getExtension(filenames
[i
]) == "zonel")
309 zonelFiles
.push_back(filenames
[i
]);
313 list
<string
>::iterator
itZonel(zonelFiles
.begin()), lastZonel(zonelFiles
.end());
314 for( ; itZonel
!= lastZonel
; ++itZonel
)
317 getPosFromZoneName(*itZonel
, position
);
319 islandsMap
[position
] = true;
322 // search for island borders
323 CContinentData
& continent
= itCont
->second
;
324 list
< string
>::const_iterator
itIsland(continent
.Islands
.begin()), lastIsland(continent
.Islands
.end());
325 for( ; itIsland
!= lastIsland
; ++itIsland
)
327 if(_IslandsData
.find(itIsland
->c_str()) != _IslandsData
.end())
329 const CProximityZone
& islandData
= _IslandsData
[itIsland
->c_str()];
331 sint32 xmin
= islandData
.getBoundXMin();
332 sint32 xmax
= islandData
.getBoundXMax();
333 sint32 ymin
= islandData
.getBoundYMin();
334 sint32 ymax
= islandData
.getBoundYMax();
336 sint32 width
= xmax
-xmin
;
337 sint32 height
= ymax
-ymin
;
339 sint32 zonelXMin
= ((uint
)(xmin
/160)) * 160;
340 sint32 zonelYMin
= ((uint
)(ymin
/160) - 1) * 160;
341 sint32 zonelXMax
= ((uint
)(xmax
/160)) * 160;
342 sint32 zonelYMax
= ((uint
)(ymax
/160) - 1) * 160;
344 list
< CVector2f
> leftBorders
, rightBorders
, bottomBorders
, topBorders
;
346 // search for left and right borders on lines
347 for(sint32 y
= zonelYMin
; y
<=zonelYMax
; y
+=160 )
350 CVector2f
vec((float)x
, (float)y
);
351 bool lastZoneFull
= (islandsMap
.find(vec
) != islandsMap
.end());
352 bool currentZoneFull
;
356 vec
= CVector2f((float)x
, (float)y
);
357 currentZoneFull
= (islandsMap
.find(vec
) != islandsMap
.end());
359 if(lastZoneFull
&& !currentZoneFull
&& vec
.x
-1 >= xmin
)
361 rightBorders
.push_back(CVector2f(vec
.x
-1, vec
.y
));
363 else if(!lastZoneFull
&& currentZoneFull
)
365 leftBorders
.push_back(vec
);
368 lastZoneFull
= currentZoneFull
;
372 // search for bottom and top borders on columns
373 for(sint32 x
= zonelXMin
; x
<=zonelXMax
; x
+=160 )
376 CVector2f
vec((float)x
, (float)y
);
377 bool lastZoneFull
= (islandsMap
.find(vec
) != islandsMap
.end());
378 bool currentZoneFull
;
382 vec
= CVector2f((float)x
, (float)y
);
383 currentZoneFull
= (islandsMap
.find(vec
) != islandsMap
.end());
385 if(lastZoneFull
&& !currentZoneFull
&& vec
.y
-1 >= ymin
)
387 topBorders
.push_back(CVector2f(vec
.x
, vec
.y
-1));
389 else if(!lastZoneFull
&& currentZoneFull
)
391 bottomBorders
.push_back(vec
);
394 lastZoneFull
= currentZoneFull
;
398 _BorderIslands
[*itIsland
+ "/right"] = rightBorders
;
399 _BorderIslands
[*itIsland
+ "/left"] = leftBorders
;
400 _BorderIslands
[*itIsland
+ "/bottom"] = bottomBorders
;
401 _BorderIslands
[*itIsland
+ "/top"] = topBorders
;
407 //-------------------------------------------------------------------------------------------------
408 void CScreenshotIslands::attenuateIslandBorders(const std::string
& islandName
, CBitmap
& islandBitmap
,
409 const CProximityZone
& islandData
)
411 list
< CVector2f
> leftBorders
, rightBorders
, bottomBorders
, topBorders
;
412 rightBorders
= _BorderIslands
[islandName
+ "/right"];
413 leftBorders
= _BorderIslands
[islandName
+ "/left"];
414 bottomBorders
= _BorderIslands
[islandName
+ "/bottom"];
415 topBorders
= _BorderIslands
[islandName
+ "/top"];
417 sint32 xmin
= islandData
.getBoundXMin();
418 sint32 xmax
= islandData
.getBoundXMax();
419 sint32 ymin
= islandData
.getBoundYMin();
420 sint32 ymax
= islandData
.getBoundYMax();
422 sint32 width
= xmax
-xmin
;
423 sint32 height
= ymax
-ymin
;
424 uint8
*dest
= &(islandBitmap
.getPixels(0)[0]);
426 list
< CVector2f
>::iterator itBorder
;
428 for(itBorder
=leftBorders
.begin(); itBorder
!=leftBorders
.end(); itBorder
++)
430 const CVector2f initPoint
= *itBorder
;
431 sint32 x
= (sint32
)initPoint
.x
- xmin
;
432 sint32 y
= (sint32
)initPoint
.y
- ymin
;
433 sint32 maxBorder
= 160;
441 while(y
<(inity
+maxBorder
) && y
<(sint32
)height
)
443 double noiseValue
= (1+cos(((y
-inity
)*2*Pi
)/maxBorder
))*5;
444 double evalNoise
= 10 + noiseValue
;
445 double diffAlpha
= 255/evalNoise
;
447 CRGBA color
= islandBitmap
.getPixelColor(x
, height
-y
-1);
448 sint32 currentX
= x
-1;
450 while((currentX
>=x
-evalNoise
) && currentX
>=0)
452 uint8
*pixel
= &(islandBitmap
.getPixels(0)[((height
-y
-1)*width
+ currentX
)*4]);
453 uint alpha
= (uint
)(255-diffAlpha
*(x
-currentX
));
454 uint invAlpha
= 255-alpha
;
456 *pixel
= (uint8
) (((invAlpha
* *pixel
) + (alpha
* color
.R
)) >> 8);
457 *(pixel
+ 1) = (uint8
) (((invAlpha
* *(pixel
+ 1)) + (alpha
* color
.G
)) >> 8);
458 *(pixel
+ 2) = (uint8
) (((invAlpha
* *(pixel
+ 2)) + (alpha
* color
.B
)) >> 8);
459 *(pixel
+ 3) = (uint8
) 255;
467 for(itBorder
=rightBorders
.begin(); itBorder
!=rightBorders
.end(); itBorder
++)
469 const CVector2f initPoint
= *itBorder
;
470 sint32 x
= (sint32
)initPoint
.x
- xmin
;
471 sint32 y
= (sint32
)initPoint
.y
- ymin
;
472 sint32 maxBorder
= 160;
480 while(y
<(inity
+maxBorder
) && y
<(sint32
)height
)
482 double noiseValue
= (1+cos(((y
-inity
)*2*Pi
)/maxBorder
))*5;
483 double evalNoise
= 10 + noiseValue
;
484 double diffAlpha
= 255/evalNoise
;
486 CRGBA color
= islandBitmap
.getPixelColor(x
, height
-y
-1);
487 sint32 currentX
= x
+1;
489 while((currentX
<=x
+evalNoise
) && currentX
<width
)
491 uint8
*pixel
= &(islandBitmap
.getPixels(0)[((height
-y
-1)*width
+ currentX
)*4]);
492 uint alpha
= (uint
)(255-diffAlpha
*(currentX
-x
));
493 uint invAlpha
= 255-alpha
;
495 *pixel
= (uint8
) (((invAlpha
* *pixel
) + (alpha
* color
.R
)) >> 8);
496 *(pixel
+ 1) = (uint8
) (((invAlpha
* *(pixel
+ 1)) + (alpha
* color
.G
)) >> 8);
497 *(pixel
+ 2) = (uint8
) (((invAlpha
* *(pixel
+ 2)) + (alpha
* color
.B
)) >> 8);
498 *(pixel
+ 3) = (uint8
) 255;
507 for(itBorder
=bottomBorders
.begin(); itBorder
!=bottomBorders
.end(); itBorder
++)
509 const CVector2f initPoint
= *itBorder
;
510 sint32 x
= (sint32
)initPoint
.x
- xmin
;
511 sint32 y
= (sint32
)initPoint
.y
- ymin
;
512 sint32 maxBorder
= 160;
520 while(x
<(initx
+maxBorder
) && x
<(sint32
)width
)
522 double noiseValue
= (1+cos(((x
-initx
)*2*Pi
)/maxBorder
))*5;
523 double evalNoise
= 10 + noiseValue
;
524 double diffAlpha
= 255/evalNoise
;
526 CRGBA color
= islandBitmap
.getPixelColor(x
, height
-y
-1);
527 sint32 currentY
= y
-1;
529 while((currentY
>=y
-evalNoise
) && currentY
>=0)
531 uint8
*pixel
= &(islandBitmap
.getPixels(0)[((height
-currentY
-1)*width
+ x
)*4]);
532 uint alpha
= (uint
)(255-diffAlpha
*(y
-currentY
));
533 uint invAlpha
= 255-alpha
;
535 *pixel
= (uint8
) (((invAlpha
* *pixel
) + (alpha
* color
.R
)) >> 8);
536 *(pixel
+ 1) = (uint8
) (((invAlpha
* *(pixel
+ 1)) + (alpha
* color
.G
)) >> 8);
537 *(pixel
+ 2) = (uint8
) (((invAlpha
* *(pixel
+ 2)) + (alpha
* color
.B
)) >> 8);
538 *(pixel
+ 3) = (uint8
) 255;
547 for(itBorder
=topBorders
.begin(); itBorder
!=topBorders
.end(); itBorder
++)
549 const CVector2f initPoint
= *itBorder
;
550 sint32 x
= (sint32
)initPoint
.x
- xmin
;
551 sint32 y
= (sint32
)initPoint
.y
- ymin
;
552 sint32 maxBorder
= 160;
560 while(x
<(initx
+maxBorder
) && x
<(sint32
)width
)
562 double noiseValue
= (1+cos(((x
-initx
)*2*Pi
)/maxBorder
))*5;
563 double evalNoise
= 10 + noiseValue
;
564 double diffAlpha
= 255/evalNoise
;
566 CRGBA color
= islandBitmap
.getPixelColor(x
, height
-y
-1);
567 sint32 currentY
= y
+1;
569 while((currentY
<=y
+evalNoise
) && currentY
<height
)
571 uint8
*pixel
= &(islandBitmap
.getPixels(0)[((height
-currentY
-1)*width
+ x
)*4]);
572 uint alpha
= (uint
)(255-diffAlpha
*(currentY
-y
));
573 uint invAlpha
= 255-alpha
;
575 *pixel
= (uint8
) (((invAlpha
* *pixel
) + (alpha
* color
.R
)) >> 8);
576 *(pixel
+ 1) = (uint8
) (((invAlpha
* *(pixel
+ 1)) + (alpha
* color
.G
)) >> 8);
577 *(pixel
+ 2) = (uint8
) (((invAlpha
* *(pixel
+ 2)) + (alpha
* color
.B
)) >> 8);
578 *(pixel
+ 3) = (uint8
) 255;
588 //-------------------------------------------------------------------------------------------------
589 void CScreenshotIslands::buildScreenshots()
592 buildIslandsTextures();
595 //-------------------------------------------------------------------------------------------------
596 void CScreenshotIslands::writeProximityBufferToTgaFile(const std::string
& fileName
,const TBuffer
& buffer
,uint32 scanWidth
,uint32 scanHeight
)
598 uint imageWidth
= (scanWidth
); // (scanWidth+15)&~15;
599 uint imageHeight
= (scanHeight
);
601 CTGAImageGrey tgaImage
;
602 tgaImage
.setup((uint16
)imageWidth
, (uint16
)imageHeight
, fileName
, 0, 0);
603 for (uint32 y
=0;y
<scanHeight
;++y
)
605 for (uint32 x
=0; x
<scanWidth
; ++x
)
607 uint32 value
= buffer
[y
*scanWidth
+x
];
608 tgaImage
.set(x
, (value
>255*5)?255:value
/5);
610 tgaImage
.writeLine();
614 //-------------------------------------------------------------------------------------------------
615 void CScreenshotIslands::processProximityBuffer(TBuffer
& inputBuffer
, uint32 lineLength
, TBuffer
& resultBuffer
)
617 // a couple of constants to control the range over which our degressive filter is to be applied
618 const uint32 smallValue
= 2*5;
620 float a
= 5*((255.0 - limitValue
)/(float(100-BigValue
)));
621 float b
= (float)(limitValue
*5 - a
*BigValue
);
623 // determine numer of lines in the buffer...
624 uint32 numLines
= inputBuffer
.size()/ lineLength
;
626 // clear out the result buffer and reset all values to 5*255, remembering that this is the correct value for the image edges
627 resultBuffer
.clear();
628 resultBuffer
.resize(inputBuffer
.size(),(TBufferEntry
)5*255);
630 for (uint32 y
=1;y
<numLines
-1;++y
)
632 uint32 lineOffset
= y
* lineLength
;
633 for (uint32 x
=1;x
<lineLength
-1;++x
)
635 uint32 offset
= lineOffset
+x
;
637 uint32 value
=(uint32
)inputBuffer
[offset
];
639 // apply a clip and cosine function
641 if (value<smallValue) value=0;
642 else if (value>BigValue) value=5*255;
643 else value= (uint32)(((1.0-cos(Pi*(float(value-smallValue)/(float)(BigValue-smallValue))))/2.0)*float(5*255));
646 if (value
==ValueBorder
);
647 else if ((value
>=0) && (value
<smallValue
)) value
=0;
648 else if (value
>BigValue
)
650 if(value
==InteriorValue
)
652 value
= (uint
)(5*limitValue
);
656 value
= (uint
)(a
*value
+b
);
657 if(value
> 5*255) value
= 5*255;
660 else if((value
>=smallValue
) && (value
<=BigValue
))
662 value
= (uint32
)(((1.0-cos(Pi
*(float(value
-smallValue
)/(float)(BigValue
-smallValue
))))/2.0)*float(5*limitValue
));
665 // store the value into the result buffer
666 resultBuffer
[offset
]= (TBufferEntry
)value
;
670 // modify inputBuffer to store "bigValue" limit
671 for (uint32 y
=1;y
<numLines
-1;++y
)
673 uint32 lineOffset
= y
* lineLength
;
674 for (uint32 x
=1;x
<lineLength
-1;++x
)
676 uint32 offset
= lineOffset
+x
;
678 uint32 value
=(uint32
)inputBuffer
[offset
];
680 if(value
==BigValue
) value
= 255*5;
683 inputBuffer
[offset
]= (TBufferEntry
)value
;
689 for (uint32 y=0;y<numLines;++y)
691 uint32 lineOffset= y* lineLength;
693 for (uint32 x=0;x<lineLength;++x)
695 uint32 offset = lineOffset+x;
696 uint16 value = resultBuffer[offset];
698 if(value==ValueBorder)
700 resultBuffer[offset]= (TBufferEntry)(5*limitValue);
705 uint16 nextValue = resultBuffer[offset+1];
706 uint16 prevValue = (TBufferEntry)(5*limitValue);
707 if(nextValue!=(TBufferEntry)(5*limitValue))
710 while((count<x+7) && (count<lineLength-1) && ((nextValue=resultBuffer[lineOffset+count])!=0)
711 && nextValue!=(TBufferEntry)(5*limitValue) && (nextValue!=ValueBorder))
713 uint16 newValue = (TBufferEntry)(prevValue+5*7);
714 if(newValue < nextValue)
716 resultBuffer[lineOffset+count] = newValue;
719 prevValue = newValue;
731 uint16 nextValue = resultBuffer[offset-1];
732 uint16 prevValue = (TBufferEntry)(5*limitValue);
733 if(nextValue!=(TBufferEntry)(5*limitValue))
736 while((count>x-7) && (count>0) && ((nextValue=resultBuffer[lineOffset+count])!=0)
737 && nextValue!=(TBufferEntry)(5*limitValue) && (nextValue!=ValueBorder))
739 uint16 newValue = (TBufferEntry)(prevValue+5*7);
740 if(newValue < nextValue)
742 resultBuffer[lineOffset+count] = newValue;
745 prevValue = newValue;
755 for (uint32 x=0;x<lineLength;++x)
757 // setup start and end offsets marking first and last 'zero' value pixels in the column
758 uint32 startOffset=x, endOffset=x+(numLines-1)*lineLength;
760 for (uint32 offset=startOffset; offset<=endOffset; offset+=lineLength)
762 uint16 value = resultBuffer[offset];
764 if(value==ValueBorder)
766 resultBuffer[offset]= (TBufferEntry)(5*limitValue);
769 if(offset+lineLength<=endOffset)
771 uint16 nextValue = resultBuffer[offset+lineLength];
772 uint16 prevValue = (TBufferEntry)(5*limitValue);
773 if(nextValue!=(TBufferEntry)(5*limitValue))
775 uint32 count = offset+lineLength;
776 while((count<offset+7*lineLength) && (count<=endOffset) &&
777 ((nextValue=resultBuffer[count])!=0) && nextValue!=(TBufferEntry)(5*limitValue) && (nextValue!=ValueBorder))
779 uint16 newValue = (TBufferEntry)(prevValue+5*7);
780 if(newValue < nextValue)
782 resultBuffer[count] = newValue;
785 prevValue = newValue;
789 offset = count-lineLength;
795 if(offset-lineLength>=startOffset)
797 uint16 nextValue = resultBuffer[offset-lineLength];
798 uint16 prevValue = (TBufferEntry)(5*limitValue);
799 if(nextValue!=(TBufferEntry)(5*limitValue))
801 uint32 count = offset-lineLength;
802 while((count>offset-7*lineLength) && (count>=startOffset) &&
803 ((nextValue=resultBuffer[count])!=0) && nextValue!=(TBufferEntry)(5*limitValue) && (nextValue!=ValueBorder))
805 uint16 newValue = (TBufferEntry)(prevValue+5*7);
806 if(newValue < nextValue)
808 resultBuffer[count] = newValue;
811 prevValue = newValue;
821 //-----------------------------------------------------------------------------
822 // search for pixels of borders
823 map
< CVector2f
, bool > bordersPixels
;
824 for (uint32 y
=0;y
<numLines
;++y
)
826 uint32 lineOffset
= y
* lineLength
;
828 for (uint32 x
=0;x
<lineLength
;++x
)
830 uint32 offset
= lineOffset
+x
;
831 uint16 value
= resultBuffer
[offset
];
833 if(value
==ValueBorder
)
835 bordersPixels
[CVector2f((float)x
, (float)y
)] = true;
836 resultBuffer
[offset
] = (TBufferEntry
)(5*limitValue
);
841 //-----------------------------------------------------------------------------
842 // search for global borders
843 // search on lines for top and bottom borders
844 map
< CVector2f
, uint32
> leftBorders
, rightBorders
, bottomBorders
, topBorders
;
845 for (uint32 y
=0;y
<numLines
;++y
)
847 uint32 lineOffset
= y
* lineLength
;
849 bool lastValue
= false;
850 CVector2f firstPixelBorder
;
851 firstPixelBorder
.set(0.f
, 0.f
);
852 uint32 nbPixelsBorder
= 0;
854 for (uint32 x
=0;x
<lineLength
;++x
)
856 bool value
= (bordersPixels
.find(CVector2f((float)x
, (float)y
))!=bordersPixels
.end());
862 firstPixelBorder
= CVector2f((float)x
, (float)y
);
869 if(nbPixelsBorder
!=1) //column instead of line
871 bool top
=false, bottom
=false;
874 for(uint32 xc
=(uint32
)firstPixelBorder
.x
; xc
<(uint32
)(firstPixelBorder
.x
+nbPixelsBorder
); xc
++)
876 if(resultBuffer
[(y
-1)*lineLength
+xc
]==(TBufferEntry
)(5*255))
886 for(uint32 xc
=(uint32
)firstPixelBorder
.x
; xc
<(uint32
)(firstPixelBorder
.x
+nbPixelsBorder
); xc
++)
888 if(resultBuffer
[(y
+1)*lineLength
+xc
]==(TBufferEntry
)(5*255))
898 topBorders
[firstPixelBorder
] =nbPixelsBorder
;
902 bottomBorders
[firstPixelBorder
] =nbPixelsBorder
;
910 // search on columns for left and right borders
911 for (uint32 x
=0;x
<lineLength
;++x
)
913 bool lastValue
= false;
914 CVector2f firstPixelBorder
;
915 firstPixelBorder
.set(0.f
, 0.f
);
916 uint32 nbPixelsBorder
= 0;
918 for(uint32 y
=0; y
<numLines
; y
++)
920 bool value
= (bordersPixels
.find(CVector2f((float)x
, (float)y
))!=bordersPixels
.end());
926 firstPixelBorder
= CVector2f((float)x
, (float)y
);
933 if(nbPixelsBorder
!=1) //line instead of column
940 for(uint32 yc
=(uint32
)firstPixelBorder
.y
; yc
<(uint32
)(firstPixelBorder
.y
+nbPixelsBorder
); yc
++)
942 if(resultBuffer
[yc
*lineLength
+x
-1]==(TBufferEntry
)(5*255))
952 for(uint32 yc
=(uint32
)firstPixelBorder
.y
; yc
<(uint32
)(firstPixelBorder
.y
+nbPixelsBorder
); yc
++)
954 if(resultBuffer
[yc
*lineLength
+x
+1]==(TBufferEntry
)(5*255))
964 leftBorders
[firstPixelBorder
] =nbPixelsBorder
;
968 rightBorders
[firstPixelBorder
] =nbPixelsBorder
;
976 //-----------------------------------------------------------------------------
978 // bottom and top borders (lines)
979 for (uint32 y
=0;y
<numLines
;++y
)
981 uint32 lineOffset
= y
* lineLength
;
983 for (uint32 x
=0;x
<lineLength
;++x
)
985 uint32 offset
= lineOffset
+x
;
986 CVector2f
firstPixelBorder((float)x
, (float)y
);
989 if(bottomBorders
.find(CVector2f((float)x
, (float)y
))!=bottomBorders
.end())
991 uint32 nbPixelsBorder
= bottomBorders
[firstPixelBorder
];
993 for(xc
=(uint32
)firstPixelBorder
.x
; xc
<(uint32
)(firstPixelBorder
.x
+nbPixelsBorder
); xc
++)
995 uint nbZones
= (uint
)(nbPixelsBorder
/160)+1;
996 uint period
= (uint
)(nbPixelsBorder
/(2*nbZones
));
997 double noiseValue
= (1-cos(((xc
-firstPixelBorder
.x
)*Pi
)/period
))*5;
998 double evalNoise
= 7 + noiseValue
;
999 double diffAlpha
= (255.0-limitValue
)/evalNoise
;
1002 while((yc
>=(uint32
)(y
-evalNoise
)) && yc
>=0)
1004 uint16 newValue
= (TBufferEntry
)(5*(limitValue
+ diffAlpha
*(y
-yc
)));
1005 uint16 currentValue
= (TBufferEntry
)resultBuffer
[yc
*lineLength
+xc
];
1006 if(newValue
<currentValue
)
1007 resultBuffer
[yc
*lineLength
+xc
] = (TBufferEntry
)(5*(limitValue
+ diffAlpha
*(y
-yc
)));
1015 if(topBorders
.find(CVector2f((float)x
, (float)y
))!=topBorders
.end())
1017 uint32 nbPixelsBorder
= topBorders
[firstPixelBorder
];
1019 for(xc
=(uint32
)firstPixelBorder
.x
; xc
<=(uint32
)(firstPixelBorder
.x
+nbPixelsBorder
); xc
++)
1021 uint nbZones
= (uint
)(nbPixelsBorder
/160)+1;
1022 uint period
= (uint
)(nbPixelsBorder
/(2*nbZones
));
1023 double noiseValue
= (1-cos(((xc
-firstPixelBorder
.x
)*Pi
)/period
))*5;
1024 double evalNoise
= 7 + noiseValue
;
1025 double diffAlpha
= (255.0-limitValue
)/evalNoise
;
1028 while((yc
<=(uint32
)(y
+evalNoise
)) && yc
<numLines
)
1030 uint16 newValue
= (TBufferEntry
)(5*(limitValue
+ diffAlpha
*(yc
-y
)));
1031 uint16 currentValue
= (TBufferEntry
)resultBuffer
[yc
*lineLength
+xc
];
1032 if(newValue
<currentValue
)
1033 resultBuffer
[yc
*lineLength
+xc
] = (TBufferEntry
)(5*(limitValue
+ diffAlpha
*(yc
-y
)));
1042 // left and right borders (columns)
1043 for (uint32 x
=0;x
<lineLength
;++x
)
1045 for (uint32 y
=0; y
<numLines
; y
++)
1047 CVector2f
firstPixelBorder((float)x
, (float)y
);
1050 if(leftBorders
.find(CVector2f((float)x
, (float)y
))!=leftBorders
.end())
1052 uint32 nbPixelsBorder
= leftBorders
[firstPixelBorder
];
1054 for(yc
=(uint32
)firstPixelBorder
.y
; yc
<(uint32
)(firstPixelBorder
.y
+nbPixelsBorder
); yc
++)
1056 uint nbZones
= (uint
)(nbPixelsBorder
/160)+1;
1057 uint period
= (uint
)(nbPixelsBorder
/(2*nbZones
));
1058 double noiseValue
= (1-cos(((yc
-firstPixelBorder
.y
)*Pi
)/period
))*5;
1059 double evalNoise
= 7 + noiseValue
;
1060 double diffAlpha
= (255.0-limitValue
)/evalNoise
;
1063 while((xc
>=(uint32
)(x
-evalNoise
)) && xc
>=0)
1065 uint16 newValue
= (TBufferEntry
)(5*(limitValue
+ diffAlpha
*(x
-xc
)));
1066 uint16 currentValue
= (TBufferEntry
)resultBuffer
[yc
*lineLength
+xc
];
1067 if(newValue
<currentValue
)
1068 resultBuffer
[yc
*lineLength
+xc
] = (TBufferEntry
)(5*(limitValue
+ diffAlpha
*(x
-xc
)));
1076 if(rightBorders
.find(CVector2f((float)x
, (float)y
))!=rightBorders
.end())
1078 uint32 nbPixelsBorder
= rightBorders
[firstPixelBorder
];
1080 for(yc
=(uint32
)firstPixelBorder
.y
; yc
<=(uint32
)(firstPixelBorder
.y
+nbPixelsBorder
); yc
++)
1082 uint nbZones
= (uint
)(nbPixelsBorder
/160)+1;
1083 uint period
= (uint
)(nbPixelsBorder
/(2*nbZones
));
1084 double noiseValue
= (1-cos(((yc
-firstPixelBorder
.y
)*Pi
)/period
))*5;
1085 double evalNoise
= 7 + noiseValue
;
1086 double diffAlpha
= (255.0-limitValue
)/evalNoise
;
1089 while((xc
<=(uint32
)(x
+evalNoise
)) && xc
<lineLength
)
1091 uint16 newValue
= (TBufferEntry
)(5*(limitValue
+ diffAlpha
*(xc
-x
)));
1092 uint16 currentValue
= (TBufferEntry
)resultBuffer
[yc
*lineLength
+xc
];
1093 if(newValue
<currentValue
)
1094 resultBuffer
[yc
*lineLength
+xc
] = (TBufferEntry
)(5*(limitValue
+ diffAlpha
*(xc
-x
)));
1104 //--------------------------------------------------------------------------------
1105 void CScreenshotIslands::loadIslands()
1108 map
< string
, CVector2f
> islands
;
1109 CScenarioEntryPoints scenarioEntryPoints
= CScenarioEntryPoints::getInstance();
1111 scenarioEntryPoints
.loadFromFile();
1112 const CScenarioEntryPoints::TEntryPoints
& entryPoints
= scenarioEntryPoints
.getEntryPoints();
1114 CScenarioEntryPoints::TEntryPoints::const_iterator
entry(entryPoints
.begin()), entryPoint(entryPoints
.end());
1115 for( ; entry
!= entryPoint
; ++entry
)
1117 islands
[entry
->Island
] = CVector2f((float)entry
->X
, (float)entry
->Y
);
1120 // search islands of each continent
1121 map
< string
, CVector2f
>::iterator
itIsland(islands
.begin()), lastIsland(islands
.end());
1122 for( ; itIsland
!= lastIsland
; ++itIsland
)
1124 const CVector2f
& entryPoint
= itIsland
->second
;
1126 // search continent of this island
1127 TContinentsData::iterator
itCont(_ContinentsData
.begin()), lastCont(_ContinentsData
.end());
1128 for( ; itCont
!= lastCont
; ++itCont
)
1130 CContinentData
& continent
= itCont
->second
;
1131 CVector2f zoneMax
= continent
.ZoneMax
;
1132 CVector2f zoneMin
= continent
.ZoneMin
;
1134 if((zoneMin
.x
<= entryPoint
.x
) && (entryPoint
.x
<= zoneMax
.x
)
1135 && (zoneMax
.y
<= entryPoint
.y
) && (entryPoint
.y
<= zoneMin
.y
))
1137 continent
.Islands
.push_back(itIsland
->first
);
1143 // search data of each island
1144 TContinentsData::iterator
itCont(_ContinentsData
.begin()), lastCont(_ContinentsData
.end());
1145 for( ; itCont
!= lastCont
; ++itCont
)
1147 string aiFileName
= itCont
->first
+"_0.cwmap2";
1149 const CContinentData
& continent
= itCont
->second
;
1151 CProximityMapBuffer continentBuffer
;
1152 continentBuffer
.load(CPath::lookup(aiFileName
));
1154 CProximityMapBuffer::TZones zones
;
1155 continentBuffer
.calculateZones(zones
);
1157 for (uint32 i
=0;i
<zones
.size();++i
)
1160 continentBuffer
.generateZoneProximityMap(zones
[i
], zoneBuffer
);
1162 TBuffer cleanBuffer
;
1163 processProximityBuffer(zoneBuffer
, zones
[i
].getZoneWidth(), cleanBuffer
);
1166 list
< string
>::const_iterator
itIsland(continent
.Islands
.begin()), lastIsland(continent
.Islands
.end());
1167 for( ; itIsland
!= lastIsland
; ++itIsland
)
1169 const CVector2f
& entryPoint
= islands
[*itIsland
];
1170 sint32 xmin
= zones
[i
].getBoundXMin();
1171 sint32 xmax
= zones
[i
].getBoundXMax();
1172 sint32 ymin
= zones
[i
].getBoundYMin();
1173 sint32 ymax
= zones
[i
].getBoundYMax();
1175 if((xmin
<= entryPoint
.x
) && (entryPoint
.x
<= xmax
)
1176 && (ymin
<= entryPoint
.y
) && (entryPoint
.y
<= ymax
))
1178 fileName
= _OutDirectory
+ "/" + *itIsland
+ "_prox.tga";
1179 _IslandsData
[*itIsland
] = zones
[i
];
1184 // write the processed proximity map to an output file
1185 if(!fileName
.empty())
1187 writeProximityBufferToTgaFile(fileName
, cleanBuffer
, zones
[i
].getZoneWidth(), zones
[i
].getZoneHeight());
1188 _TempFileNames
.push_back(fileName
);
1190 fileName
= _OutDirectory
+ "/" + *itIsland
+ "_limit.tga";
1191 writeProximityBufferToTgaFile(fileName
, zoneBuffer
, zones
[i
].getZoneWidth(), zones
[i
].getZoneHeight());
1192 _TempFileNames
.push_back(fileName
);
1196 nlinfo("Zone of island not found, tga not build");
1202 CScenarioEntryPoints::TCompleteIslands
completeIslands(entryPoints
.size());
1204 uint completeIslandsNb
= 0;
1205 for(uint e
=0; e
<entryPoints
.size(); e
++)
1207 const CScenarioEntryPoints::CEntryPoint
& entry
= entryPoints
[e
];
1209 CScenarioEntryPoints::CCompleteIsland completeIsland
;
1210 completeIsland
.Island
= entry
.Island
;
1211 completeIsland
.Package
= entry
.Package
;
1213 for(itCont
=_ContinentsData
.begin(); itCont
!=_ContinentsData
.end(); ++itCont
)
1215 list
< string
>::const_iterator
itIsland(itCont
->second
.Islands
.begin()), lastIsland(itCont
->second
.Islands
.end());
1216 for( ; itIsland
!= lastIsland
; ++itIsland
)
1218 if(*itIsland
== entry
.Island
)
1220 completeIsland
.Continent
= CSString(itCont
->first
);
1221 if(_IslandsData
.find(entry
.Island
)!=_IslandsData
.end())
1223 completeIsland
.XMin
= _IslandsData
[entry
.Island
].getBoundXMin();
1224 completeIsland
.YMin
= _IslandsData
[entry
.Island
].getBoundYMin();
1225 completeIsland
.XMax
= _IslandsData
[entry
.Island
].getBoundXMax();
1226 completeIsland
.YMax
= _IslandsData
[entry
.Island
].getBoundYMax();
1227 completeIslands
[completeIslandsNb
] = completeIsland
;
1228 completeIslandsNb
++;
1235 completeIslands
.resize(completeIslandsNb
);
1237 CScenarioEntryPoints::getInstance().saveXMLFile(completeIslands
, _CompleteIslandsFile
);
1240 //--------------------------------------------------------------------------------
1242 void CScreenshotIslands::getBuffer(UScene
* scene
, ULandscape
* landscape
, CBitmap
&btm
)
1245 if (ScreenShotWidth
&& ScreenShotHeight
)
1247 UCamera camera
= scene
->getCam();
1249 // Destination image
1251 btm
.resize(ScreenShotWidth
, ScreenShotHeight
, CBitmap::RGBA
);
1253 uint windowWidth
= driver
->getWindowWidth();
1254 uint windowHeight
= driver
->getWindowHeight();
1257 uint bottom
= min(windowHeight
, ScreenShotHeight
);
1258 for (top
=0; top
<ScreenShotHeight
; top
+=windowHeight
)
1261 uint right
= std::min(windowWidth
, ScreenShotWidth
);
1262 for(left
=0; left
<ScreenShotWidth
; left
+=windowWidth
)
1264 driver
->clearBuffers(_BackColor
);
1266 // store initial frustum and viewport
1267 CFrustum Frustum
= scene
->getCam().getFrustum();
1268 CViewport Viewport
= scene
->getViewport();
1270 // Build a new frustum
1271 CFrustum frustumPart
;
1272 frustumPart
.Left
= Frustum
.Left
+(Frustum
.Right
-Frustum
.Left
)*((float)left
/(float)ScreenShotWidth
);
1273 frustumPart
.Right
= Frustum
.Left
+(Frustum
.Right
-Frustum
.Left
)*((float)right
/(float)ScreenShotWidth
);
1274 frustumPart
.Top
= ceil(Frustum
.Top
+(Frustum
.Bottom
-Frustum
.Top
)*((float)top
/(float)ScreenShotHeight
));
1275 frustumPart
.Bottom
= ceil(Frustum
.Top
+(Frustum
.Bottom
-Frustum
.Top
)*((float)bottom
/(float)ScreenShotHeight
));
1276 frustumPart
.Near
= Frustum
.Near
;
1277 frustumPart
.Far
= Frustum
.Far
;
1278 frustumPart
.Perspective
= Frustum
.Perspective
;
1280 // Build a new viewport
1282 viewport
.init(0, 0, (float)(right
-left
)/windowWidth
,
1283 (float)(bottom
-top
)/windowHeight
);
1285 // Activate all this
1286 scene
->getCam().setFrustum(frustumPart
);
1287 scene
->setViewport(viewport
);
1289 scene
->setMaxSkeletonsInNotCLodForm(1000000);
1290 scene
->setPolygonBalancingMode(UScene::PolygonBalancingOff
);
1294 // render scene with inversed ZBuffer test (keep greater distances)
1295 driver
->setColorMask(false, false, false, false);
1296 sceneMaterial
.setZFunc(UMaterial::less
);
1298 // initialize ZBuffer with leak value
1299 driver
->setMatrixMode2D11();
1301 quad
.V0
= CVector(0.0, 0.0, 0.0);
1302 quad
.V1
= CVector(1.0, 0.0, 0.0);
1303 quad
.V2
= CVector(1.0, 1.0, 0.0);
1304 quad
.V3
= CVector(0.0, 1.0, 0.0);
1306 driver
->drawQuad(quad
, sceneMaterial
);
1307 driver
->setMatrixMode3D(camera
);
1308 driver
->setColorMask(true, true, true, true);
1310 scene
->enableElementRender(UScene::FilterWater
, false);
1315 // display vegetables with normal ZBuffer test
1316 if(_InverseZTest
&& _Vegetation
)
1318 scene
->enableElementRender(UScene::FilterWater
, false);
1319 scene
->enableElementRender(UScene::FilterLandscape
, false);
1320 scene
->enableElementRender(UScene::FilterWater
, true);
1322 scene
->enableElementRender(UScene::FilterLandscape
, true);
1326 driver
->getBuffer(dest
);
1327 btm
.blit(dest
, 0, windowHeight
-(bottom
-top
), right
-left
, bottom
-top
, left
, top
);
1330 scene
->getCam().setFrustum(Frustum
);
1331 scene
->setViewport(Viewport
);
1334 driver
->swapBuffers();
1337 right
= std::min(right
+windowWidth
, ScreenShotWidth
);
1341 bottom
= std::min(bottom
+windowHeight
, ScreenShotHeight
);
1346 driver
->getBuffer(btm
);
1352 void CScreenshotIslands::buildIslandsTextures()
1357 // Create the window with config file values
1358 driver
->setDisplay(UDriver::CMode(512, 512, 32, true));
1361 UScene
* scene
= driver
->createScene(true);
1362 scene
->animate(CTime::ticksToSecond(CTime::getPerformanceTime()));
1363 scene
->setMaxSkeletonsInNotCLodForm(1000000);
1364 scene
->setPolygonBalancingMode(UScene::PolygonBalancingOff
);
1367 UCamera camera
= scene
->getCam();
1368 camera
.setTransformMode(UTransformable::DirectMatrix
);
1370 // Create and load landscape
1371 ULandscape
* landscape
= scene
->createLandscape();
1372 landscape
->setThreshold(0.0005);
1373 landscape
->setTileNear(10000);
1376 landscape
->setZFunc(UMaterial::greaterequal
);
1380 landscape
->setZFunc(UMaterial::less
);
1383 //Iteration on seasons
1384 list
< string
>::iterator
itSeason(_SeasonSuffixes
.begin()), lastSeason(_SeasonSuffixes
.end());
1385 for( ; itSeason
!= lastSeason
; ++itSeason
)
1387 string seasonSuffix
= *itSeason
;
1391 if (seasonSuffix
== "_sp") season
= CSeason::Spring
;
1392 else if (seasonSuffix
== "_su") season
= CSeason::Summer
;
1393 else if (seasonSuffix
== "_au") season
= CSeason::Autumn
;
1394 else if (seasonSuffix
== "_wi") season
= CSeason::Winter
;
1398 nlwarning("Unknown season suffix %s, skipping...", seasonSuffix
.c_str());
1402 // Iterations on Continents
1403 TContinentsData::iterator
itCont(_ContinentsData
.begin()), lastCont(_ContinentsData
.end());
1404 for( ; itCont
!= lastCont
; ++itCont
)
1406 const CContinentData
& continent
= itCont
->second
;
1409 landscape
->setupStaticLight(continent
.Diffuse
, continent
.Ambiant
, 1.0f
);
1411 string coarseMeshFile
= continent
.CoarseMeshMap
;
1412 string coarseMeshWithoutExt
= CFile::getFilenameWithoutExtension(coarseMeshFile
);
1413 string coarseMeshExt
= CFile::getExtension(coarseMeshFile
);
1414 coarseMeshFile
= coarseMeshWithoutExt
+ seasonSuffix
+ "." + coarseMeshExt
;
1415 nldebug("Coarse mesh texture: '%s'", coarseMeshFile
.c_str());
1416 scene
->setCoarseMeshManagerTexture(coarseMeshFile
.c_str());
1418 // Load the landscape
1419 string farBank
= continent
.FarBank
;
1420 string farBankWithoutExt
= CFile::getFilenameWithoutExtension(farBank
);
1421 string farBankExt
= CFile::getExtension(farBank
);
1422 farBank
= farBankWithoutExt
+ seasonSuffix
+ "." + farBankExt
;
1423 landscape
->loadBankFiles(continent
.SmallBank
, farBank
);
1426 LandscapeIGManager
.initIG(scene
, continent
.IGFile
, driver
, season
, NULL
);
1428 // Iterations on Islands
1429 list
< string
>::const_iterator
itIsland(continent
.Islands
.begin()), lastIsland(continent
.Islands
.end());
1430 for( ; itIsland
!= lastIsland
; ++itIsland
)
1434 if(_IslandsData
.find(itIsland
->c_str()) != _IslandsData
.end())
1436 const CProximityZone
& islandData
= _IslandsData
[itIsland
->c_str()];
1438 sint32 xmin
= islandData
.getBoundXMin();
1439 sint32 xmax
= islandData
.getBoundXMax();
1440 sint32 ymin
= islandData
.getBoundYMin();
1441 sint32 ymax
= islandData
.getBoundYMax();
1443 float width
= (float)(xmax
-xmin
);
1444 float height
= (float)(ymax
-ymin
);
1445 ScreenShotWidth
= (uint
)(width
*_MeterPixelSize
);
1446 ScreenShotHeight
= (uint
)(height
*_MeterPixelSize
);
1448 // position in island center
1449 float posx
= ((float)(xmax
+xmin
))/2;
1450 float posy
= ((float)(ymax
+ymin
))/2;
1451 CVector
entryPos(posx
, posy
, 400);
1454 CMatrix startCamMatrix
;
1455 startCamMatrix
.setPos(entryPos
);
1456 startCamMatrix
.rotateX(-(float)Pi
/2);
1457 camera
.setMatrix(startCamMatrix
);
1458 camera
.setFrustum(width
, height
, -10000.0f
, 10000.0f
, false);
1461 landscape
->postfixTileFilename(seasonSuffix
.c_str());
1466 vector
<string
> zonesAdded
;
1467 vector
<string
> zonesRemoved
;
1468 IProgressCallback progress
;
1469 landscape
->refreshAllZonesAround(camera
.getMatrix().getPos(), 2000, zonesAdded
, zonesRemoved
, progress
);
1472 LandscapeIGManager
.unloadArrayZoneIG(zonesRemoved
);
1473 LandscapeIGManager
.loadArrayZoneIG(zonesAdded
);
1475 vector
<string
>::iterator
itName(zonesAdded
.begin()), lastName(zonesAdded
.end());
1476 for( ; itName
!= lastName
; ++itName
)
1478 UInstanceGroup
* instanceGr
= LandscapeIGManager
.getIG(*itName
);
1481 uint nbInst
= instanceGr
->getNumInstance();
1482 for(uint i
=0; i
<instanceGr
->getNumInstance(); i
++)
1484 instanceGr
->setCoarseMeshDist(i
, 100000);
1485 instanceGr
->setDistMax(i
, 100000);
1490 scene
->animate(CTime::ticksToSecond(CTime::getPerformanceTime()));
1492 // Clear all buffers
1493 driver
->clearBuffers(_BackColor
);
1497 // render scene with inversed ZBuffer test (keep greater distances)
1498 driver
->setColorMask(false, false, false, false);
1499 sceneMaterial
.setZFunc(UMaterial::less
);
1501 // initialize ZBuffer with leak value
1502 driver
->setMatrixMode2D11();
1504 quad
.V0
= CVector(0.0, 0.0, 0.0);
1505 quad
.V1
= CVector(1.0, 0.0, 0.0);
1506 quad
.V2
= CVector(1.0, 1.0, 0.0);
1507 quad
.V3
= CVector(0.0, 1.0, 0.0);
1509 driver
->drawQuad(quad
, sceneMaterial
);
1510 driver
->setMatrixMode3D(camera
);
1511 driver
->setColorMask(true, true, true, true);
1513 scene
->enableElementRender(UScene::FilterWater
, false);
1518 // display vegetables with normal ZBuffer test
1519 if(_InverseZTest
&& _Vegetation
)
1521 scene
->enableElementRender(UScene::FilterLandscape
, false);
1522 scene
->enableElementRender(UScene::FilterWater
, true);
1524 scene
->enableElementRender(UScene::FilterLandscape
, true);
1529 driver
->swapBuffers();
1531 // Pump user input messages
1532 driver
->EventServer
.pump();
1539 CBitmap islandBitmap
;
1540 getBuffer(scene
, landscape
, islandBitmap
);
1542 buildBackTextureHLS(*itIsland
, islandBitmap
);
1546 // create srcennshot bitmap of full island
1547 CBitmap islandBitmap
;
1548 getBuffer(scene
, landscape
, islandBitmap
);
1550 attenuateIslandBorders(*itIsland
, islandBitmap
, islandData
);
1552 // load proximity bitmap
1554 std::string proxFileName
= _OutDirectory
+ "/" + *itIsland
+ "_prox.tga";
1555 CIFile
proxFS(proxFileName
.c_str());
1556 proxBitmap
.load(proxFS
);
1558 // resize proximity bitmap
1560 int newWidth
= islandBitmap
.getWidth();
1561 int newHeight
= islandBitmap
.getHeight();
1562 tempBitmap
.resize(newWidth
, newHeight
, islandBitmap
.PixelFormat
);
1564 //tempBitmap.blit(proxBitmap, 0, 0, newWidth, newHeight, 0, 0);
1566 const uint8
*prox
= &(proxBitmap
.getPixels(0)[0]);
1567 uint8
*temp
= &(tempBitmap
.getPixels(0)[0]);
1568 for (uint y
= 0; y
< newHeight
; ++y
)
1569 for (uint x
= 0; x
< newWidth
; ++x
)
1571 uint ys
= (y
* proxBitmap
.getHeight()) / newHeight
;
1572 uint xs
= (x
* proxBitmap
.getWidth()) / newWidth
;
1573 uint addr
= ((y
* newWidth
) + x
) * 4;
1574 uint addrs
= ((ys
* proxBitmap
.getWidth()) + xs
) * 4;
1575 temp
[addr
] = prox
[addrs
];
1576 temp
[addr
+1] = prox
[addrs
+1];
1577 temp
[addr
+2] = prox
[addrs
+2];
1578 temp
[addr
+3] = prox
[addrs
+3];
1583 proxBitmap
.resize(newWidth
, newHeight
, proxBitmap
.PixelFormat
);
1584 proxBitmap
.swap(tempBitmap
);
1586 //proxBitmap.resample(newWidth, newHeight);
1589 // create final bitmap
1591 bitmapDest
.resize(islandBitmap
.getWidth(), islandBitmap
.getHeight(), islandBitmap
.PixelFormat
);
1594 // mix black and full island bitmaps with blend factor of proximity bitmap pixels
1595 uint numPix
= islandBitmap
.getWidth() * islandBitmap
.getHeight();
1597 const uint8
*alphaProx
= &(proxBitmap
.getPixels(0)[0]);
1598 const uint8
*srcIsland
= &(islandBitmap
.getPixels(0)[0]);
1599 uint8
*dest
= &(bitmapDest
.getPixels(0)[0]);
1602 const uint8
*srcBack
= &(_BackBitmap
.getPixels(0)[0]);
1604 uint8
*endDest
= dest
+ (numPix
<< 2);
1608 uint invblendFact
= (uint
) alphaProx
[0];
1609 uint blendFact
= 256 - invblendFact
;
1611 // blend 4 component at each pass
1612 *dest
= (uint8
) (((blendFact
* *srcIsland
) + (invblendFact
* *srcBack
)) >> 8);
1613 *(dest
+ 1) = (uint8
) (((blendFact
* *(srcIsland
+ 1)) + (invblendFact
* *(srcBack
+ 1))) >> 8);
1614 *(dest
+ 2) = (uint8
) (((blendFact
* *(srcIsland
+ 2)) + (invblendFact
* *(srcBack
+ 2))) >> 8);
1615 *(dest
+ 3) = (uint8
) 255;
1617 alphaProx
= alphaProx
+ 4;
1618 srcIsland
= srcIsland
+ 4;
1621 srcBack
= srcBack
+ 4;
1623 while(dest
!= endDest
);
1626 // create tga file of avoidable place in island
1627 string textureName
= _OutDirectory
+ "/" + *itIsland
+ seasonSuffix
+ ".tga";
1629 CBitmap bitmapLittle
;
1630 bitmapLittle
.resize(bitmapDest
.getWidth(), bitmapDest
.getHeight(), bitmapDest
.PixelFormat
);
1631 bitmapLittle
= bitmapDest
;
1632 if(!isPowerOf2(bitmapDest
.getWidth()) || !isPowerOf2(bitmapDest
.getHeight()) )
1634 uint pow2w
= NLMISC::raiseToNextPowerOf2(bitmapDest
.getWidth());
1635 uint pow2h
= NLMISC::raiseToNextPowerOf2(bitmapDest
.getHeight());
1636 CBitmap enlargedBitmap
;
1637 enlargedBitmap
.resize(pow2w
, pow2h
, bitmapDest
.PixelFormat
);
1639 enlargedBitmap
.blit(&bitmapDest
, 0, 0);
1641 bitmapDest
.swap(enlargedBitmap
);
1644 COFile
fsDest(textureName
.c_str());
1645 bitmapDest
.writeTGA(fsDest
,32);
1649 bitmapLittle
.resample(bitmapLittle
.getWidth() / 20, bitmapLittle
.getHeight() / 20);
1650 if (!isPowerOf2(bitmapLittle
.getWidth()) || !isPowerOf2(bitmapLittle
.getHeight()))
1652 uint pow2w
= NLMISC::raiseToNextPowerOf2(bitmapLittle
.getWidth());
1653 uint pow2h
= NLMISC::raiseToNextPowerOf2(bitmapLittle
.getHeight());
1654 CBitmap enlargedBitmap
;
1655 enlargedBitmap
.resize(pow2w
, pow2h
, bitmapLittle
.PixelFormat
);
1657 enlargedBitmap
.blit(&bitmapLittle
, 0, 0);
1659 bitmapLittle
.swap(enlargedBitmap
);
1662 textureName
= _OutDirectory
+ "/" + *itIsland
+ seasonSuffix
+ "_little.tga";
1663 COFile
fsLittle(textureName
.c_str());
1664 bitmapLittle
.writeTGA(fsLittle
,32);
1666 _BackColor
= CRGBA(255, 255, 255, 255);
1672 LandscapeIGManager
.reset();
1673 landscape
->removeAllZones();
1677 // remove proximity tga
1678 list
<string
>::iterator
itProx(_TempFileNames
.begin()), lastProx(_TempFileNames
.end());
1679 for( ; itProx
!= lastProx
; ++itProx
)
1681 CFile::deleteFile(*itProx
);
1685 //--------------------------------------------------------------------------------
1686 inline bool RGB2HSV(const CRGBA
& rgba
, uint
& Hue
, uint
& Sat
, uint
& Val
)
1688 double Min_
, Max_
, Delta
, H
, S
, V
;
1690 Min_
= min(min(rgba
.R
, rgba
.G
), rgba
.B
);
1691 Max_
= max(max(rgba
.R
, rgba
.G
), rgba
.B
);
1692 Delta
= ( Max_
- Min_
);
1696 S
= 255.0*Delta
/Max_
;
1711 H
= (rgba
.G
- rgba
.B
) / Delta
;
1713 else if(rgba
.G
== Max_
)
1715 H
= 2.0 + (rgba
.B
- rgba
.R
) / Delta
;
1719 H
= 4.0 + (rgba
.R
- rgba
.G
) / Delta
;
1728 Hue
= (uint
)H
; // Hue -> 0..360
1729 Sat
= (uint
)S
* 100 / 255; // Saturation -> 0..100 %
1730 Val
= (uint
)V
* 100 / 255; // Value - > 0..100 %
1735 //-------------------------------------------------------------------------------------------------
1736 inline bool infHLS(const CRGBA
& rgba1
, const CRGBA
& rgba2
)
1738 uint h1
, s1
, v1
, h2
, s2
, v2
;
1739 RGB2HSV(rgba1
, h1
, s1
, v1
);
1740 RGB2HSV(rgba2
, h2
, s2
, v2
);
1756 //-------------------------------------------------------------------------------------------------
1757 void CScreenshotIslands::buildBackTextureHLS(const std::string
& islandName
, const CBitmap
& islandBitmap
)
1759 // load limit bitmap
1761 std::string limFileName
= _OutDirectory
+ "/" + islandName
+ "_limit.tga";
1763 CIFile
limFS(limFileName
.c_str());
1764 limBitmap
.load(limFS
);
1766 list
< CRGBA
> limitPixels
;
1768 // search for colors of limit pixels
1769 for(uint x
=0; x
<islandBitmap
.getWidth(); x
++)
1771 for(uint y
=0; y
<islandBitmap
.getHeight(); y
++)
1773 CRGBA lim
= limBitmap
.getPixelColor(x
, y
);
1774 if((lim
== CRGBA::White
) && (islandBitmap
.getPixelColor(x
, y
)!=CRGBA::White
))
1776 limitPixels
.push_back(islandBitmap
.getPixelColor(x
, y
));
1782 list
< CRGBA
> sortedHLS
;
1783 list
< CRGBA
>::iterator itCol
, itHLS
;
1784 bool inserted
= false;
1785 for(itCol
=limitPixels
.begin(); itCol
!=limitPixels
.end(); itCol
++)
1788 for(itHLS
=sortedHLS
.begin(); itHLS
!=sortedHLS
.end(); ++itHLS
)
1790 if(infHLS(*itCol
, *itHLS
))
1792 sortedHLS
.insert(itHLS
, *itCol
);
1797 if(inserted
==false) sortedHLS
.push_back(*itCol
);
1801 // keep more filled eighth of circle
1802 nlassert(!sortedHLS
.empty()); // If it crashes here, you may be missing .zonel's.
1803 itHLS
= sortedHLS
.begin();
1805 RGB2HSV(*itHLS
, h
, s
, v
);
1806 list
< CRGBA
> currentList
, maxList
;
1808 for(uint i
=0; i
<8; i
++)
1810 while(itHLS
!=sortedHLS
.end() && h
<i
*45)
1812 currentList
.push_back(*itHLS
);
1813 RGB2HSV(*itHLS
, h
, s
, v
);
1817 if(currentList
.size() > maxList
.size())
1820 maxList
= currentList
;
1821 currentList
.clear();
1825 vector
< CRGBA
> sortedColors(maxList
.size());
1827 CRGBA
lastColor(0, 0, 0, 0);
1829 uint maxColorNb
= 0;
1830 uint currentColorNb
= 0;
1831 for(itHLS
=maxList
.begin(); itHLS
!=maxList
.end(); ++itHLS
)
1833 if(lastColor
==*itHLS
)
1842 if(currentColorNb
>maxColorNb
)
1844 maxColorNb
= currentColorNb
;
1850 RGB2HSV(*itHLS
, h
, s
, v
);
1851 if(v
>25 && v
<75 && s
>25 && s
<75)
1853 sortedColors
[colorsNb
] = *itHLS
;
1861 for(itHLS
=maxList
.begin(); itHLS
!=maxList
.end(); ++itHLS
)
1863 sortedColors
[colorsNb
] = *itHLS
;
1868 sortedColors
.resize(colorsNb
);
1870 _BackBitmap
.resize(islandBitmap
.getWidth(), islandBitmap
.getHeight(), islandBitmap
.PixelFormat
);
1872 if(sortedColors
.size()!=0)
1874 _BackColor
= maxColor
;
1876 std::string islandNameLwr
= toLowerAscii(islandName
);
1878 for (ptrdiff_t i
= 0; i
< (ptrdiff_t)islandNameLwr
.size(); ++i
)
1879 seed
+= wangHash(seed
^ islandNameLwr
[i
]);
1881 uint8
* backPixels
= &(_BackBitmap
.getPixels(0)[0]);
1884 for(uint x
=0; x
<_BackBitmap
.getWidth(); x
++)
1886 for(uint y
=0; y
<_BackBitmap
.getHeight(); y
++, i
++)
1888 sint32 randomVal
= wangHash(seed
^ i
) % colorsNb
;
1889 const CRGBA
& color
= sortedColors
[randomVal
];
1891 *backPixels
= (uint8
) color
.R
;
1892 *(backPixels
+ 1) = (uint8
) color
.G
;
1893 *(backPixels
+ 2) = (uint8
) color
.B
;
1894 *(backPixels
+ 3) = (uint8
) 255;
1896 backPixels
= backPixels
+4;
1904 HLSBitmap.resize(640, sortedColors.size()*4, islandBitmap.PixelFormat);
1906 uint8 * hlsPixels = &(HLSBitmap.getPixels(0)[0]);
1908 for(uint i=0; i < sortedColors.size(); i++)
1913 *hlsPixels = (uint8) sortedColors[i].R;
1914 *(hlsPixels + 1) = (uint8) sortedColors[i].G;
1915 *(hlsPixels + 2) = (uint8) sortedColors[i].B;
1916 *(hlsPixels + 3) = (uint8) sortedColors[i].A;
1918 hlsPixels = hlsPixels+4;
1924 string textureName = _OutDirectory + "/" + islandName + "_HLS2.tga";
1925 COFile fsHLS(textureName.c_str());
1926 HLSBitmap.writeTGA(fsHLS,32);
1931 //--------------------------------------------------------------------------------------------------------------
1932 //--------------------------------------------------------------------------------------------------------------
1934 //-------------------------------------------------------------------------------------------------
1935 // methods CProximityMapBuffer
1936 //-------------------------------------------------------------------------------------------------
1938 void CProximityMapBuffer::load(const std::string
& name
)
1940 // load the AI collision map file
1945 // lookup the map bounds
1946 CMapPosition min
, max
;
1947 worldMap
.getBounds(min
, max
);
1949 // calculate a handful of constants relating to the bounds of the image...
1950 _ScanWidth
= max
.x()-min
.x();
1951 _ScanHeight
= max
.y()-min
.y();
1953 _YOffset
= (sint16
)min
.y();
1955 // redimension buffer to correct size
1956 _Buffer
.resize(_ScanWidth
*_ScanHeight
);
1958 // setup a position variable to mark the start point of each line
1959 CMapPosition
scanpos(min
.x(),min
.y());
1961 // iterate over the scan area looking for points that are accessible
1962 for (uint32 y
=0; y
<_ScanHeight
; ++y
, scanpos
= scanpos
.getStepN())
1964 CMapPosition
pos(scanpos
);
1966 // scan a line of the map
1967 for (uint32 x
=0; x
<_ScanWidth
; ++x
, pos
= pos
.getStepE())
1969 bool isAccessible
= false;
1970 // if the cell pointer is NULL it means that the 16x16 cell in question is inaccessible
1971 if (worldMap
.getRootCellCst(pos
) != NULL
)
1973 // run through the surfaces in the cell looking for a match for this position (may be as many as 3 surfaces per cell max)
1974 for (uint32 ns
=0; ns
<3; ++ns
)
1976 isAccessible
|= worldMap
.getSafeWorldPosition(pos
, CSlot(ns
)).isValid();
1979 // setup the next pixel in the output buffers...
1980 _Buffer
[y
*_ScanWidth
+x
]= (isAccessible
? 0:std::numeric_limits
<TBufferEntry
>::max());
1985 //-------------------------------------------------------------------------------------------------
1986 void CProximityMapBuffer::calculateZones(TZones
& zones
)
1988 // clear out the result buffer before starting work
1991 // setup a container to hold the accessible points within this buffer
1992 typedef std::set
<uint32
> TAccessiblePoints
;
1993 TAccessiblePoints accessiblePoints
;
1995 // start by building the set of all accessible points
1996 for (uint32 i
=0;i
<_Buffer
.size();++i
)
1999 accessiblePoints
.insert(i
);
2002 // while there are still points remaining in the set we must have another zone to process
2003 while (!accessiblePoints
.empty())
2005 // append a new zone to the zones vector and get a refference to it
2006 zones
.push_back( CProximityZone(_ScanWidth
,_ScanHeight
,_XOffset
,_YOffset
) );
2007 CProximityZone
& theZone
= zones
.back();
2009 // setup a todo list representing points that are part of the surface that we are dealing with
2010 // that haven't yet been treated to check for neighbours, etc
2011 std::vector
<uint32
> todo
;
2013 // get hold of the first point in the accessilbe points set and push it onto the todo list
2014 todo
.push_back(*accessiblePoints
.begin());
2015 accessiblePoints
.erase(todo
.back());
2017 // while we have more points to deal with ...
2018 while (!todo
.empty())
2020 // pop the next point off the todo list
2021 uint32 thePoint
= todo
.back();
2024 // add the point to the zone
2025 theZone
.add(thePoint
);
2027 // a little macro for the code to perform for each movement test...
2028 #define TEST_MOVE(xoffs,yoffs)\
2030 TAccessiblePoints::iterator it= accessiblePoints.find(thePoint+xoffs+_ScanWidth*yoffs);\
2031 if (it!=accessiblePoints.end())\
2033 todo.push_back(*it);\
2034 accessiblePoints.erase(it);\
2044 // NW, NE, WS, SE moves
2054 nlinfo("Found %u zones",zones
.size());
2057 //-------------------------------------------------------------------------------------------------
2058 void CProximityMapBuffer::_prepareBufferForZoneProximityMap(const CProximityZone
& zone
,TBuffer
& zoneBuffer
,TOffsetsVector
& accessiblePoints
)
2060 // the length of runs that we consider too short to deal with...
2061 const uint32 shortRunLength
=5;
2063 // redimention and initialise the zone buffer
2064 uint32 zoneWidth
= zone
.getZoneWidth();
2065 uint32 zoneHeight
= zone
.getZoneHeight();
2067 zoneBuffer
.resize(zoneWidth
*zoneHeight
, std::numeric_limits
<TBufferEntry
>::max());
2069 // setup the buffer's accessible points and prime vects[0] with the set of accessible points in the zone buffer
2070 for (uint32 i
=0;i
<zone
.getOffsets().size();++i
)
2072 // lookup the next offset in the zone's offsets vector and remap to a zone-relative offset
2073 uint32 zoneOffset
= zone
.remapOffset(zone
.getOffsets()[i
]);
2074 // flag the appropriate entry in the zoneBuffer as 'distance=0'
2075 zoneBuffer
[zoneOffset
]= 0;
2076 // add the zone offset to the accessible points vector
2077 accessiblePoints
.push_back(zoneOffset
);
2080 // run through the zone buffer looking for points that are surrounded that we can just throw out...
2081 // start by flagging all points that belong to a short run in the y direction
2082 for (uint32 i
=0;i
<zoneWidth
;++i
)
2084 // setup start and end offsets marking first and last 'zero' value pixels in the column
2085 uint32 startOffset
=i
, endOffset
=i
+(zoneHeight
-1)*zoneWidth
;
2086 for (; startOffset
<endOffset
&& zoneBuffer
[startOffset
]!=0; startOffset
+= zoneWidth
) {}
2087 for (; endOffset
>startOffset
&& zoneBuffer
[endOffset
]!=0; endOffset
-= zoneWidth
) {}
2089 for (uint32 offset
=startOffset
, marker
=startOffset
;offset
<=endOffset
;offset
+=zoneWidth
)
2091 // see if this is an accessible position
2092 if (zoneBuffer
[offset
]!=0)
2094 zoneBuffer
[offset
]= InteriorValue
;
2096 if(offset
-1>=startOffset
&& zoneBuffer
[offset
-1] == std::numeric_limits
<TBufferEntry
>::max())
2098 zoneBuffer
[offset
-1] = ValueBorder
;
2100 if(offset
+1<=endOffset
&& zoneBuffer
[offset
+1] == std::numeric_limits
<TBufferEntry
>::max())
2102 zoneBuffer
[offset
+1] = ValueBorder
;
2108 // continue by dealing with all points that belong to a short run in the x direction
2109 for (uint32 i
=0;i
<zoneHeight
;++i
)
2111 // setup start and end offsets marking first and last 'zero' value pixels in the column
2112 uint32 startOffset
= i
*zoneWidth
;
2113 uint32 endOffset
= startOffset
+zoneWidth
-1;
2115 uint32 startOffsetInit
= startOffset
;
2116 uint32 endOffsetInit
= endOffset
;
2118 for (; startOffset
<endOffset
&& zoneBuffer
[startOffset
]!=0; ++startOffset
) {}
2119 for (; endOffset
>startOffset
&& zoneBuffer
[endOffset
]!=0; --endOffset
) {}
2121 for (uint32 offset
=startOffset
, marker
=startOffset
;offset
<=endOffset
;++offset
)
2123 // see if this is an accessible position
2124 if (zoneBuffer
[offset
]!=0)
2126 zoneBuffer
[offset
]= InteriorValue
;
2128 if(offset
>zoneWidth
&& zoneBuffer
[offset
-zoneWidth
] == std::numeric_limits
<TBufferEntry
>::max())
2130 zoneBuffer
[offset
-zoneWidth
] = ValueBorder
;
2132 if(offset
+zoneWidth
<zoneHeight
*zoneWidth
&& zoneBuffer
[offset
+zoneWidth
] == std::numeric_limits
<TBufferEntry
>::max())
2134 zoneBuffer
[offset
+zoneWidth
] = ValueBorder
;
2141 //-------------------------------------------------------------------------------------------------
2142 void CProximityMapBuffer::generateZoneProximityMap(const CProximityZone
& zone
,TBuffer
& zoneBuffer
)
2144 // a set of vectors to hold sets of points that need to be treated
2145 TOffsetsVector vects
[16];
2146 // a counter that should always contain sum of all vects[i].size()
2147 uint32 entriesToTreat
= 0;
2149 // setup the buffer's accessible points and prime vects[0] with the set of accessible points in the zone buffer
2150 _prepareBufferForZoneProximityMap(zone
, zoneBuffer
, vects
[0]);
2151 entriesToTreat
= vects
[0].size();
2153 // lookup the buffer dimentions
2154 uint32 zoneWidth
= zone
.getZoneWidth();
2155 uint32 zoneHeight
= zone
.getZoneHeight();
2157 // for dist=0 to ? treat points with distance 'dist' from centre, iterating until all vects are empty
2158 for (TBufferEntry dist
=0; entriesToTreat
!=0; ++dist
)
2160 // setup refference to the vector that we are supposed to be iterating over for this dist
2161 TOffsetsVector
&vect
= vects
[dist
&15];
2163 // iterate over contents of points for this distance, treating NSWE neighbours
2164 for(TOffsetsVector::iterator it
=vect
.begin(); it
!=vect
.end(); ++it
)
2168 // deal with the case where this point has already been refferenced via a better route
2169 if (zoneBuffer
[val
]<dist
|| (zoneBuffer
[val
]==InteriorValue
&& dist
> BigValue
)
2170 || (zoneBuffer
[val
]==ValueBorder
&& dist
> BigValue
))
2173 // write the new distance into this buffer entry
2174 zoneBuffer
[val
]=dist
;
2176 // decompose into x and y in order to manage identification of neighbour cells correctly
2177 uint32 x
= val
% zoneWidth
;
2178 uint32 y
= val
/ zoneWidth
;
2180 #define TEST_MOVE(xoffs,yoffs,newDist)\
2182 if (((uint32)(x+xoffs)<zoneWidth) && ((uint32)(y+yoffs)<zoneHeight))\
2184 uint32 newVal= val+xoffs+(yoffs*zoneWidth);\
2185 bool isInterior = ((zoneBuffer[newVal] == InteriorValue && newDist > BigValue) || (zoneBuffer[newVal] == ValueBorder && newDist > BigValue));\
2186 if (zoneBuffer[newVal] > newDist && !isInterior)\
2188 zoneBuffer[newVal] = newDist;\
2189 vects[newDist & 15].push_back(newVal);\
2196 TEST_MOVE( 0, 1,dist
+5);
2197 TEST_MOVE( 0,-1,dist
+5);
2198 TEST_MOVE( 1, 0,dist
+5);
2199 TEST_MOVE(-1, 0,dist
+5);
2201 // NW, NE, WS, SE moves
2202 TEST_MOVE( 1, 1,dist
+7);
2203 TEST_MOVE(-1, 1,dist
+7);
2204 TEST_MOVE( 1,-1,dist
+7);
2205 TEST_MOVE(-1,-1,dist
+7);
2207 // NNW, NNE, SSW, SSE moves
2208 TEST_MOVE( 1, 2,dist
+11);
2209 TEST_MOVE(-1, 2,dist
+11);
2210 TEST_MOVE( 1,-2,dist
+11);
2211 TEST_MOVE(-1,-2,dist
+11);
2213 // WNW, WSW, ENE, ESE moves
2214 TEST_MOVE( 2, 1,dist
+11);
2215 TEST_MOVE(-2, 1,dist
+11);
2216 TEST_MOVE( 2,-1,dist
+11);
2217 TEST_MOVE(-2,-1,dist
+11);
2222 // clear out the vector
2223 entriesToTreat
-= vect
.size();
2228 //-------------------------------------------------------------------------------------------------
2229 const TBuffer
& CProximityMapBuffer::getBuffer() const
2234 //-------------------------------------------------------------------------------------------------
2235 uint32
CProximityMapBuffer::getScanHeight() const
2240 //-------------------------------------------------------------------------------------------------
2241 uint32
CProximityMapBuffer::getScanWidth() const
2246 //-----------------------------------------------------------------------------------------
2247 //-----------------------------------------------------------------------------------------
2249 //-------------------------------------------------------------------------------------------------
2250 // methods CProximityZone
2251 //-------------------------------------------------------------------------------------------------
2253 CProximityZone::CProximityZone(uint32 scanWidth
,uint32 scanHeight
,sint32 xOffset
, sint32 yOffset
)
2255 _ScanWidth
= scanWidth
;
2256 _ScanHeight
= scanHeight
;
2260 _MaxOffset
= scanWidth
* scanHeight
-1;
2262 _XMin
= std::numeric_limits
<uint32
>::max();
2263 _YMin
= std::numeric_limits
<uint32
>::max();
2270 //-------------------------------------------------------------------------------------------------
2271 bool CProximityZone::add(uint32 offset
)
2273 // make sure the requested point is in the zone
2274 if (offset
>_MaxOffset
)
2277 // calculate the x and y coordinates of the point
2278 uint32 y
= offset
/ _ScanWidth
;
2279 uint32 x
= offset
% _ScanWidth
;
2281 // update the bounding coordinates for this zone
2282 if (x
<_XMin
) _XMin
= x
;
2283 if (x
>_XMax
) _XMax
= x
;
2284 if (y
<_YMin
) _YMin
= y
;
2285 if (y
>_YMax
) _YMax
= y
;
2287 // add the point to the vector of points
2288 _Offsets
.push_back(offset
);
2292 //-------------------------------------------------------------------------------------------------
2293 const CProximityZone::TOffsets
& CProximityZone::getOffsets() const
2298 //-------------------------------------------------------------------------------------------------
2299 uint32
CProximityZone::getZoneWidth() const
2301 return getZoneXMax()- getZoneXMin() +1;
2304 //-------------------------------------------------------------------------------------------------
2305 uint32
CProximityZone::getZoneHeight() const
2307 return getZoneYMax()- getZoneYMin() +1;
2310 //-------------------------------------------------------------------------------------------------
2311 sint32
CProximityZone::getZoneXMin() const
2313 return _XMin
-_BorderPixels
;
2316 //-------------------------------------------------------------------------------------------------
2317 sint32
CProximityZone::getZoneYMin() const
2319 return _YMin
-_BorderPixels
;
2322 //-------------------------------------------------------------------------------------------------
2323 uint32
CProximityZone::getZoneXMax() const
2325 return _XMax
+_BorderPixels
;
2328 //-------------------------------------------------------------------------------------------------
2329 uint32
CProximityZone::getZoneYMax() const
2331 return _YMax
+_BorderPixels
;
2334 //-------------------------------------------------------------------------------------------------
2335 uint32
CProximityZone::getBoundXMin() const
2337 return _XMin
+_XOffset
-_BorderPixels
;
2340 //-------------------------------------------------------------------------------------------------
2341 uint32
CProximityZone::getBoundYMin() const
2343 return _YMin
+_YOffset
-_BorderPixels
;
2346 //-------------------------------------------------------------------------------------------------
2347 uint32
CProximityZone::getBoundXMax() const
2349 return _XMax
+_XOffset
+_BorderPixels
;
2352 //-------------------------------------------------------------------------------------------------
2353 uint32
CProximityZone::getBoundYMax() const
2355 return _YMax
+_YOffset
+_BorderPixels
;
2358 //-------------------------------------------------------------------------------------------------
2359 uint32
CProximityZone::remapOffset(uint32 bufferOffset
) const
2361 // decompose input coordinates into x and y parts
2362 uint32 bufferX
= bufferOffset
% _ScanWidth
;
2363 uint32 bufferY
= bufferOffset
/ _ScanWidth
;
2365 // remap the offset from a _Buffer-relative offset to a zone-relative offset
2366 return bufferX
-getZoneXMin()+ (bufferY
-getZoneYMin())*getZoneWidth();