2
0

blTerrainSystem.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "lighting/basic/blTerrainSystem.h"
  24. #include "core/bitVector.h"
  25. #include "lighting/common/shadowVolumeBSP.h"
  26. #include "lighting/lightingInterfaces.h"
  27. #include "terrain/terrData.h"
  28. #include "lighting/basic/basicLightManager.h"
  29. #include "lighting/common/sceneLighting.h"
  30. #include "gfx/bitmap/gBitmap.h"
  31. #include "collision/collision.h"
  32. extern SceneLighting* gLighting;
  33. struct blTerrainChunk : public PersistInfo::PersistChunk
  34. {
  35. typedef PersistInfo::PersistChunk Parent;
  36. blTerrainChunk();
  37. ~blTerrainChunk();
  38. GBitmap *mLightmap;
  39. bool read(Stream &);
  40. bool write(Stream &);
  41. };
  42. //------------------------------------------------------------------------------
  43. // Class SceneLighting::TerrainChunk
  44. //------------------------------------------------------------------------------
  45. blTerrainChunk::blTerrainChunk()
  46. {
  47. mChunkType = PersistChunk::TerrainChunkType;
  48. mLightmap = NULL;
  49. }
  50. blTerrainChunk::~blTerrainChunk()
  51. {
  52. if(mLightmap)
  53. delete mLightmap;
  54. }
  55. //------------------------------------------------------------------------------
  56. bool blTerrainChunk::read(Stream & stream)
  57. {
  58. if(!Parent::read(stream))
  59. return(false);
  60. mLightmap = new GBitmap();
  61. return mLightmap->readBitmap("png",stream);
  62. }
  63. bool blTerrainChunk::write(Stream & stream)
  64. {
  65. if(!Parent::write(stream))
  66. return(false);
  67. if(!mLightmap)
  68. return(false);
  69. if(!mLightmap->writeBitmap("png",stream))
  70. return(false);
  71. return(true);
  72. }
  73. class blTerrainProxy : public SceneLighting::ObjectProxy
  74. {
  75. protected:
  76. typedef ObjectProxy Parent;
  77. BitVector mShadowMask;
  78. ShadowVolumeBSP * mShadowVolume;
  79. LinearColorF * mLightmap;
  80. /// The dimension of the lightmap in pixels.
  81. const U32 mLightMapSize;
  82. /// The dimension of the terrain height map sample array.
  83. const U32 mTerrainBlockSize;
  84. LinearColorF *sgBakedLightmap;
  85. Vector<LightInfo *> sgLights;
  86. bool sgMarkStaticShadow(void *terrainproxy, SceneObject *sceneobject, LightInfo *light);
  87. //void postLight(bool lastLight);
  88. void lightVector(LightInfo *);
  89. struct SquareStackNode
  90. {
  91. U8 mLevel;
  92. U16 mClipFlags;
  93. Point2I mPos;
  94. };
  95. S32 testSquare(const Point3F &, const Point3F &, S32, F32, const Vector<PlaneF> &);
  96. bool markObjectShadow(ObjectProxy *);
  97. bool sgIsCorrectStaticObjectType(SceneObject *obj);
  98. inline LinearColorF _getValue( S32 row, S32 column );
  99. public:
  100. blTerrainProxy(SceneObject * obj);
  101. ~blTerrainProxy();
  102. TerrainBlock * operator->() {return(static_cast<TerrainBlock*>(static_cast<SceneObject*>(mObj)));}
  103. TerrainBlock * getObject() {return(static_cast<TerrainBlock*>(static_cast<SceneObject*>(mObj)));}
  104. bool getShadowedSquares(const Vector<PlaneF> &, Vector<U16> &);
  105. // lighting
  106. void init();
  107. bool preLight(LightInfo *);
  108. void light(LightInfo *);
  109. // persist
  110. U32 getResourceCRC();
  111. bool setPersistInfo(PersistInfo::PersistChunk *);
  112. bool getPersistInfo(PersistInfo::PersistChunk *);
  113. virtual bool supportsShadowVolume();
  114. virtual void getClipPlanes(Vector<PlaneF>& planes);
  115. virtual void addToShadowVolume(ShadowVolumeBSP * shadowVolume, LightInfo * light, S32 level);
  116. // events
  117. //virtual void processTGELightProcessEvent(U32 curr, U32 max, LightInfo* currlight);
  118. //virtual void processSGObjectProcessEvent(LightInfo* currLight);
  119. };
  120. //-------------------------------------------------------------------------------
  121. // Class SceneLighting::TerrainProxy:
  122. //-------------------------------------------------------------------------------
  123. blTerrainProxy::blTerrainProxy( SceneObject *obj ) :
  124. Parent( obj ),
  125. mLightMapSize( getObject()->getLightMapSize() ),
  126. mShadowVolume( NULL ),
  127. mTerrainBlockSize( getObject()->getBlockSize() ),
  128. mLightmap( NULL ),
  129. sgBakedLightmap( NULL )
  130. {
  131. }
  132. blTerrainProxy::~blTerrainProxy()
  133. {
  134. delete [] mLightmap;
  135. }
  136. //-------------------------------------------------------------------------------
  137. void blTerrainProxy::init()
  138. {
  139. mLightmap = new LinearColorF[ mLightMapSize * mLightMapSize ];
  140. dMemset(mLightmap, 0, mLightMapSize * mLightMapSize * sizeof(LinearColorF));
  141. mShadowMask.setSize( mTerrainBlockSize * mTerrainBlockSize );
  142. }
  143. bool blTerrainProxy::preLight(LightInfo * light)
  144. {
  145. if(!bool(mObj))
  146. return(false);
  147. if(light->getType() != LightInfo::Vector)
  148. return(false);
  149. mShadowMask.clear();
  150. return(true);
  151. }
  152. inline LinearColorF blTerrainProxy::_getValue( S32 row, S32 column )
  153. {
  154. while( row < 0 )
  155. row += mLightMapSize;
  156. row = row % mLightMapSize;
  157. while( column < 0 )
  158. column += mLightMapSize;
  159. column = column % mLightMapSize;
  160. U32 offset = row * mLightMapSize + column;
  161. return mLightmap[offset];
  162. }
  163. bool blTerrainProxy::markObjectShadow(ObjectProxy * proxy)
  164. {
  165. if (!proxy->supportsShadowVolume())
  166. return false;
  167. // setup the clip planes
  168. Vector<PlaneF> clipPlanes;
  169. proxy->getClipPlanes(clipPlanes);
  170. Vector<U16> shadowList;
  171. if(!getShadowedSquares(clipPlanes, shadowList))
  172. return(false);
  173. // set the correct bit
  174. for(U32 i = 0; i < shadowList.size(); i++)
  175. mShadowMask.set(shadowList[i]);
  176. return(true);
  177. }
  178. void blTerrainProxy::light(LightInfo * light)
  179. {
  180. // If we don't have terrain or its not a directional
  181. // light then skip processing.
  182. TerrainBlock * terrain = getObject();
  183. if ( !terrain || light->getType() != LightInfo::Vector )
  184. return;
  185. S32 time = Platform::getRealMilliseconds();
  186. // reset
  187. mShadowVolume = new ShadowVolumeBSP;
  188. // build interior shadow volume
  189. for(ObjectProxy ** itr = gLighting->mLitObjects.begin(); itr != gLighting->mLitObjects.end(); itr++)
  190. {
  191. ObjectProxy* objproxy = *itr;
  192. if (markObjectShadow(objproxy))
  193. objproxy->addToShadowVolume(mShadowVolume, light, SceneLighting::SHADOW_DETAIL);
  194. }
  195. lightVector(light);
  196. // set the lightmap...
  197. terrain->clearLightMap();
  198. // Blur...
  199. F32 kernel[3][3] = { {1, 2, 1},
  200. {2, 3, 2},
  201. {1, 2, 1} };
  202. F32 modifier = 1;
  203. F32 divisor = 0;
  204. for( U32 i=0; i<3; i++ )
  205. {
  206. for( U32 j=0; j<3; j++ )
  207. {
  208. if( i==1 && j==1 )
  209. {
  210. kernel[i][j] = 1 + kernel[i][j] * modifier;
  211. }
  212. else
  213. {
  214. kernel[i][j] = kernel[i][j] * modifier;
  215. }
  216. divisor += kernel[i][j];
  217. }
  218. }
  219. for( U32 i=0; i < mLightMapSize; i++ )
  220. {
  221. for( U32 j=0; j < mLightMapSize; j++ )
  222. {
  223. LinearColorF val;
  224. val = _getValue( i-1, j-1 ) * kernel[0][0];
  225. val += _getValue( i-1, j ) * kernel[0][1];
  226. val += _getValue( i-1, j+1 ) * kernel[0][2];
  227. val += _getValue( i, j-1 ) * kernel[1][0];
  228. val += _getValue( i, j ) * kernel[1][1];
  229. val += _getValue( i, j+1 ) * kernel[1][2];
  230. val += _getValue( i+1, j-1 ) * kernel[2][0];
  231. val += _getValue( i+1, j ) * kernel[2][1];
  232. val += _getValue( i+1, j+1 ) * kernel[2][2];
  233. U32 edge = 0;
  234. if( j == 0 || j == mLightMapSize - 1 )
  235. edge++;
  236. if( i == 0 || i == mLightMapSize - 1 )
  237. edge++;
  238. if( !edge )
  239. val = val / divisor;
  240. else
  241. val = mLightmap[ i * mLightMapSize + j ];
  242. // clamp values
  243. mLightmap[ i * mLightMapSize + j ]= val;
  244. }
  245. }
  246. // And stuff it into the texture...
  247. GBitmap *terrLightMap = terrain->getLightMap();
  248. for(U32 y = 0; y < mLightMapSize; y++)
  249. {
  250. for(U32 x = 0; x < mLightMapSize; x++)
  251. {
  252. ColorI color(255, 255, 255, 255);
  253. color.red = mLightmap[x + y * mLightMapSize].red * 255;
  254. color.green = mLightmap[x + y * mLightMapSize].green * 255;
  255. color.blue = mLightmap[x + y * mLightMapSize].blue * 255;
  256. terrLightMap->setColor(x, y, color);
  257. }
  258. }
  259. /*
  260. // This handles matching up the outer edges of the terrain
  261. // lightmap when it has neighbors
  262. if (!terrain->isTiling())
  263. {
  264. for (S32 y = 0; y < terrLightMap->getHeight(); y++)
  265. {
  266. ColorI c;
  267. if (terrain->getFile()->mEdgeTerrainFiles[0])
  268. {
  269. terrLightMap->getColor(terrLightMap->getWidth()-1,y,c);
  270. terrLightMap->setColor(0,y,c);
  271. terrLightMap->setColor(1,y,c);
  272. }
  273. else
  274. {
  275. terrLightMap->getColor(0,y,c);
  276. terrLightMap->setColor(terrLightMap->getWidth()-1,y,c);
  277. terrLightMap->setColor(terrLightMap->getWidth()-2,y,c);
  278. }
  279. }
  280. for (S32 x = 0; x < terrLightMap->getHeight(); x++)
  281. {
  282. ColorI c;
  283. if (terrain->getFile()->mEdgeTerrainFiles[1])
  284. {
  285. terrLightMap->getColor(x,terrLightMap->getHeight()-1,c);
  286. terrLightMap->setColor(x,0,c);
  287. terrLightMap->setColor(x,1,c);
  288. }
  289. else
  290. {
  291. terrLightMap->getColor(x,0,c);
  292. terrLightMap->setColor(x,terrLightMap->getHeight()-1,c);
  293. terrLightMap->setColor(x,terrLightMap->getHeight()-2,c);
  294. }
  295. }
  296. }
  297. */
  298. delete mShadowVolume;
  299. Con::printf(" = terrain lit in %3.3f seconds", (Platform::getRealMilliseconds()-time)/1000.f);
  300. }
  301. //------------------------------------------------------------------------------
  302. S32 blTerrainProxy::testSquare(const Point3F & min, const Point3F & max, S32 mask, F32 expand, const Vector<PlaneF> & clipPlanes)
  303. {
  304. expand = 0;
  305. S32 retMask = 0;
  306. Point3F minPoint, maxPoint;
  307. for(S32 i = 0; i < clipPlanes.size(); i++)
  308. {
  309. if(mask & (1 << i))
  310. {
  311. if(clipPlanes[i].x > 0)
  312. {
  313. maxPoint.x = max.x;
  314. minPoint.x = min.x;
  315. }
  316. else
  317. {
  318. maxPoint.x = min.x;
  319. minPoint.x = max.x;
  320. }
  321. if(clipPlanes[i].y > 0)
  322. {
  323. maxPoint.y = max.y;
  324. minPoint.y = min.y;
  325. }
  326. else
  327. {
  328. maxPoint.y = min.y;
  329. minPoint.y = max.y;
  330. }
  331. if(clipPlanes[i].z > 0)
  332. {
  333. maxPoint.z = max.z;
  334. minPoint.z = min.z;
  335. }
  336. else
  337. {
  338. maxPoint.z = min.z;
  339. minPoint.z = max.z;
  340. }
  341. F32 maxDot = mDot(maxPoint, clipPlanes[i]);
  342. F32 minDot = mDot(minPoint, clipPlanes[i]);
  343. F32 planeD = clipPlanes[i].d;
  344. if(maxDot <= -(planeD + expand))
  345. return(U16(-1));
  346. if(minDot <= -planeD)
  347. retMask |= (1 << i);
  348. }
  349. }
  350. return(retMask);
  351. }
  352. bool blTerrainProxy::getShadowedSquares(const Vector<PlaneF> & clipPlanes, Vector<U16> & shadowList)
  353. {
  354. TerrainBlock *terrain = getObject();
  355. if ( !terrain )
  356. return false;
  357. // TODO: Fix me for variable terrain sizes!
  358. return true;
  359. /*
  360. SquareStackNode stack[TerrainBlock::BlockShift * 4];
  361. stack[0].mLevel = TerrainBlock::BlockShift;
  362. stack[0].mClipFlags = 0xff;
  363. stack[0].mPos.set(0,0);
  364. U32 stackSize = 1;
  365. Point3F blockPos;
  366. terrain->getTransform().getColumn(3, &blockPos);
  367. S32 squareSize = terrain->getSquareSize();
  368. F32 floatSquareSize = (F32)squareSize;
  369. bool marked = false;
  370. // push through all the levels of the quadtree
  371. while(stackSize)
  372. {
  373. SquareStackNode * node = &stack[stackSize - 1];
  374. S32 clipFlags = node->mClipFlags;
  375. Point2I pos = node->mPos;
  376. GridSquare * sq = terrain->findSquare(node->mLevel, pos);
  377. Point3F minPoint, maxPoint;
  378. minPoint.set(squareSize * pos.x + blockPos.x,
  379. squareSize * pos.y + blockPos.y,
  380. fixedToFloat(sq->minHeight));
  381. maxPoint.set(minPoint.x + (squareSize << node->mLevel),
  382. minPoint.y + (squareSize << node->mLevel),
  383. fixedToFloat(sq->maxHeight));
  384. // test the square against the current level
  385. if(clipFlags)
  386. {
  387. clipFlags = testSquare(minPoint, maxPoint, clipFlags, floatSquareSize, clipPlanes);
  388. if(clipFlags == U16(-1))
  389. {
  390. stackSize--;
  391. continue;
  392. }
  393. }
  394. // shadowed?
  395. if(node->mLevel == 0)
  396. {
  397. marked = true;
  398. shadowList.push_back(pos.x + (pos.y << TerrainBlock::BlockShift));
  399. stackSize--;
  400. continue;
  401. }
  402. // setup the next level of squares
  403. U8 nextLevel = node->mLevel - 1;
  404. S32 squareHalfSize = 1 << nextLevel;
  405. for(U32 i = 0; i < 4; i++)
  406. {
  407. node[i].mLevel = nextLevel;
  408. node[i].mClipFlags = clipFlags;
  409. }
  410. node[3].mPos = pos;
  411. node[2].mPos.set(pos.x + squareHalfSize, pos.y);
  412. node[1].mPos.set(pos.x, pos.y + squareHalfSize);
  413. node[0].mPos.set(pos.x + squareHalfSize, pos.y + squareHalfSize);
  414. stackSize += 3;
  415. }
  416. return marked;
  417. */
  418. }
  419. void blTerrainProxy::lightVector(LightInfo * light)
  420. {
  421. // Grab our terrain object
  422. TerrainBlock* terrain = getObject();
  423. if (!terrain)
  424. return;
  425. // Get the direction to the light (the inverse of the direction
  426. // the light is pointing)
  427. Point3F lightDir = -light->getDirection();
  428. lightDir.normalize();
  429. // Get the ratio between the light map pixel and world space (used below)
  430. F32 lmTerrRatio = (F32)mTerrainBlockSize / (F32) mLightMapSize;
  431. lmTerrRatio *= terrain->getSquareSize();
  432. U32 i = 0;
  433. for (U32 y = 0; y < mLightMapSize; y++)
  434. {
  435. for (U32 x = 0; x < mLightMapSize; x++)
  436. {
  437. // Get the relative pixel position and scale it
  438. // by the ratio between lightmap and world space
  439. Point2F pixelPos(x, y);
  440. pixelPos *= lmTerrRatio;
  441. // Start with a default normal of straight up
  442. Point3F normal(0.0f, 0.0f, 1.0f);
  443. // Try to get the actual normal from the terrain.
  444. // Note: this won't change the default normal if
  445. // it can't find a normal.
  446. terrain->getNormal(pixelPos, &normal);
  447. // The terrain lightmap only contains shadows.
  448. F32 shadowed = 0.0f;
  449. // Get the height at the lightmap pixel's position
  450. F32 height = 0.0f;
  451. terrain->getHeight(pixelPos, &height);
  452. // Calculate the 3D position of the pixel
  453. Point3F pixelPos3F(pixelPos.x, pixelPos.y, height);
  454. // Translate that position by the terrain's transform
  455. terrain->getTransform().mulP(pixelPos3F);
  456. // Offset slighting along the normal so that we don't
  457. // raycast into ourself
  458. pixelPos3F += (normal * 0.1f);
  459. // Calculate the light's position.
  460. // If it is a vector light like the sun (no position
  461. // just direction) then translate along that direction
  462. // a reasonable distance to get a point sufficiently
  463. // far away
  464. Point3F lightPos = light->getPosition();
  465. if(light->getType() == LightInfo::Vector)
  466. {
  467. lightPos = 1000.f * lightDir;
  468. lightPos = pixelPos3F + lightPos;
  469. }
  470. // Cast a ray from the world space position of the lightmap pixel to the light source.
  471. // If we hit something then we are in shadow. This allows us to be shadowed by anything
  472. // that supports a castRay operation.
  473. RayInfo info;
  474. if(terrain->getContainer()->castRay(pixelPos3F, lightPos, STATIC_COLLISION_TYPEMASK, &info))
  475. {
  476. // Shadow the pixel.
  477. shadowed = 1.0f;
  478. }
  479. // Set the final lightmap color.
  480. mLightmap[i++] += LinearColorF::WHITE * mClampF( 1.0f - shadowed, 0.0f, 1.0f );
  481. }
  482. }
  483. }
  484. //--------------------------------------------------------------------------
  485. U32 blTerrainProxy::getResourceCRC()
  486. {
  487. TerrainBlock * terrain = getObject();
  488. if(!terrain)
  489. return(0);
  490. return(terrain->getCRC());
  491. }
  492. //--------------------------------------------------------------------------
  493. bool blTerrainProxy::setPersistInfo(PersistInfo::PersistChunk * info)
  494. {
  495. if(!Parent::setPersistInfo(info))
  496. return(false);
  497. blTerrainChunk * chunk = dynamic_cast<blTerrainChunk*>(info);
  498. AssertFatal(chunk, "blTerrainProxy::setPersistInfo: invalid info chunk!");
  499. TerrainBlock * terrain = getObject();
  500. if(!terrain || !terrain->getLightMap())
  501. return(false);
  502. terrain->setLightMap( new GBitmap( *chunk->mLightmap) );
  503. return(true);
  504. }
  505. bool blTerrainProxy::getPersistInfo(PersistInfo::PersistChunk * info)
  506. {
  507. if(!Parent::getPersistInfo(info))
  508. return(false);
  509. blTerrainChunk * chunk = dynamic_cast<blTerrainChunk*>(info);
  510. AssertFatal(chunk, "blTerrainProxy::getPersistInfo: invalid info chunk!");
  511. TerrainBlock * terrain = getObject();
  512. if(!terrain || !terrain->getLightMap())
  513. return(false);
  514. if(chunk->mLightmap) delete chunk->mLightmap;
  515. chunk->mLightmap = new GBitmap(*terrain->getLightMap());
  516. return(true);
  517. }
  518. bool blTerrainProxy::supportsShadowVolume()
  519. {
  520. return false;
  521. }
  522. void blTerrainProxy::getClipPlanes(Vector<PlaneF>& planes)
  523. {
  524. }
  525. void blTerrainProxy::addToShadowVolume(ShadowVolumeBSP * shadowVolume, LightInfo * light, S32 level)
  526. {
  527. }
  528. void blTerrainSystem::init()
  529. {
  530. }
  531. U32 blTerrainSystem::addObjectType()
  532. {
  533. return TerrainObjectType;
  534. }
  535. SceneLighting::ObjectProxy* blTerrainSystem::createObjectProxy(SceneObject* obj, SceneLighting::ObjectProxyList* sceneObjects)
  536. {
  537. if ((obj->getTypeMask() & TerrainObjectType) != 0)
  538. return new blTerrainProxy(obj);
  539. else
  540. return NULL;
  541. }
  542. PersistInfo::PersistChunk* blTerrainSystem::createPersistChunk(const U32 chunkType)
  543. {
  544. if (chunkType == PersistInfo::PersistChunk::TerrainChunkType)
  545. return new blTerrainChunk();
  546. else
  547. return NULL;
  548. }
  549. bool blTerrainSystem::createPersistChunkFromProxy(SceneLighting::ObjectProxy* objproxy, PersistInfo::PersistChunk **ret)
  550. {
  551. if (dynamic_cast<blTerrainProxy*>(objproxy) != NULL)
  552. {
  553. *ret = new blTerrainChunk();
  554. return true;
  555. }
  556. return false;
  557. }
  558. // Given a ray, this will return the color from the lightmap of this object, return true if handled
  559. bool blTerrainSystem::getColorFromRayInfo(const RayInfo & collision, LinearColorF& result) const
  560. {
  561. TerrainBlock *terrain = dynamic_cast<TerrainBlock *>(collision.object);
  562. if (!terrain)
  563. return false;
  564. Point2F uv;
  565. F32 terrainlength = (F32)terrain->getBlockSize();
  566. Point3F pos = terrain->getPosition();
  567. uv.x = (collision.point.x - pos.x) / terrainlength;
  568. uv.y = (collision.point.y - pos.y) / terrainlength;
  569. // similar to x = x & width...
  570. uv.x = uv.x - F32(U32(uv.x));
  571. uv.y = uv.y - F32(U32(uv.y));
  572. const GBitmap* lightmap = terrain->getLightMap();
  573. if (!lightmap)
  574. return false;
  575. result = lightmap->sampleTexel(uv.x, uv.y);
  576. // terrain lighting is dim - look into this (same thing done in shaders)...
  577. result *= 2.0f;
  578. return true;
  579. }