1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "precipitation_clip_grid.h"
25 using namespace NLMISC
;
29 //CHeightGrid HeightGrid;
32 extern UVisualCollisionManager
*CollisionManager
;
39 // ***********************************************************************************
40 void CHeightGrid::tileAdded(const CTileAddedInfo &infos)
42 // insert in point grid
43 _TileInfos[infos.TileID] = infos;
45 corners[0].set(infos.Corners[0].x, infos.Corners[0].y);
46 corners[1].set(infos.Corners[1].x, infos.Corners[1].y);
47 corners[2].set(infos.Corners[2].x, infos.Corners[2].y);
48 addTri(corners, infos.Center.z);
49 corners[0].set(infos.Corners[0].x, infos.Corners[0].y);
50 corners[1].set(infos.Corners[2].x, infos.Corners[2].y);
51 corners[2].set(infos.Corners[3].x, infos.Corners[3].y);
52 addTri(corners, infos.Center.z);
55 // ***********************************************************************************
56 void CHeightGrid::tileRemoved(uint64 id)
58 CHashMap<uint64, CTileAddedInfo>::iterator it = _TileInfos.find(id);
59 nlassert(it != _TileInfos.end());
61 const CTileAddedInfo &infos = it->second;
62 corners[0].set(infos.Corners[0].x, infos.Corners[0].y);
63 corners[1].set(infos.Corners[1].x, infos.Corners[1].y);
64 corners[2].set(infos.Corners[2].x, infos.Corners[2].y);
65 removeTri(corners, infos.Center.z);
66 corners[0].set(infos.Corners[0].x, infos.Corners[0].y);
67 corners[1].set(infos.Corners[2].x, infos.Corners[2].y);
68 corners[2].set(infos.Corners[3].x, infos.Corners[3].y);
69 removeTri(corners, infos.Center.z);
72 // ***********************************************************************************
73 void CHeightGrid::addTri(const CVector2f corners[3], float z)
75 _Tri.Vertices.resize(3);
76 _Tri.Vertices[0] = corners[0];
77 _Tri.Vertices[1] = corners[1];
78 _Tri.Vertices[2] = corners[2];
80 _Tri.computeBorders(_Rasters, minY);
81 if (_Rasters.empty()) return;
82 sint numRasters = _Rasters.size();
83 CHeightGridWrapped::CGridElem ge;
85 for(sint y = 0; y < numRasters; ++y)
88 const CPolygon2D::TRaster &r = _Rasters[y];
89 for (ge.X = r.first; ge.X <= r.second; ++ge.X)
91 _ZGridWrapped.insert(ge);
92 if (ge.X >= _PosX && ge.X < _PosX + (sint) _GridSize &&
93 ge.Y >= _PosY && ge.Y < _PosY + (sint) _GridSize
96 _ZGrid(ge.X - _PosX, ge.Y - _PosY) = std::max(z, _ZGrid(ge.X - _PosX, ge.Y - _PosY));
102 // ***********************************************************************************
103 void CHeightGrid::removeTri(const CVector2f corners[3], float z)
105 _Tri.Vertices.resize(3);
106 _Tri.Vertices[0] = corners[0];
107 _Tri.Vertices[1] = corners[1];
108 _Tri.Vertices[2] = corners[2];
110 _Tri.computeBorders(_Rasters, minY);
111 if (_Rasters.empty()) return;
112 sint numRasters = _Rasters.size();
113 CHeightGridWrapped::CGridElem ge;
115 for(sint y = 0; y < numRasters; ++y)
118 const CPolygon2D::TRaster &r = _Rasters[y];
119 for (ge.X = r.first; ge.X <= r.second; ++ge.X)
121 _ZGridWrapped.remove(ge);
126 // ***********************************************************************************
127 CHeightGrid::CHeightGrid()
131 _MinZ = HEIGHT_GRID_MIN_Z;
141 // ***********************************************************************************
142 void CHeightGrid::init(float cellSize, uint heightGridSize, uint wrappedHeightGridSize, float minZ)
144 nlassert(cellSize > 0.f);
145 nlassert(heightGridSize > 0);
146 nlassert(NLMISC::isPowerOf2(heightGridSize));
147 nlassert(NLMISC::isPowerOf2(wrappedHeightGridSize));
148 _ZGrid.init(heightGridSize, heightGridSize, minZ);
149 _ZGridWrapped.init(wrappedHeightGridSize, cellSize);
151 _CellSize = cellSize;
152 _GridSize = heightGridSize;
153 _InvCellSize = 1.f / _CellSize;
157 // ***********************************************************************************
158 void CHeightGrid::updateBBox()
160 _BBox.setMinMax(CVector(_PosX * _CellSize, _PosY * _CellSize, _MinZ),
161 CVector((_PosX + _GridSize) * _CellSize, (_PosY + _GridSize) * _CellSize, -_MinZ));
164 // ***********************************************************************************
165 void CHeightGrid::update(const CVector &newPos)
167 if (_CellSize == 0.f) return;
168 sint newX = (sint) floorf(newPos.x / _CellSize) - (_GridSize >> 1);
169 sint newY = (sint) floorf(newPos.y / _CellSize) - (_GridSize >> 1);
170 if (newX == _PosX && newY == _PosY) return;
171 // compute displacement of the grid
172 sint offsetX = _PosX - newX;
173 sint offsetY = _PosY - newY;
174 // compute parts of the grid that have been discarded
175 _ZGrid.getDiscardRects(offsetX, offsetY, _UpdateRects);
176 for(uint k = 0; k < _UpdateRects.size(); ++k)
178 discardRect(_UpdateRects[k]);
180 _ZGrid.move(offsetX, offsetY);
182 // compute parts of the grid that must be updated
183 _ZGrid.getUpdateRects(offsetX, offsetY, _UpdateRects);
186 for(uint k = 0; k < _UpdateRects.size(); ++k)
188 updateRect(_UpdateRects[k]);
193 // ***********************************************************************************
194 void CHeightGrid::addCollisionMesh(const UVisualCollisionManager::CMeshInstanceColInfo &colMesh)
196 const std::vector<CVector> &vertices = colMesh.Mesh.getVertices();
197 _CurrMeshVertices.resize(vertices.size());
198 std::vector<CVector>::const_iterator src, srcEnd;
199 std::vector<CVector>::iterator dest;
200 srcEnd = _CurrMeshVertices.end();
201 dest = _CurrMeshVertices.begin();
202 // transform vertices in world
203 for (src = vertices.begin(); src != srcEnd; ++ src)
205 *dest = *colMesh.WorldMatrix * *src;
208 std::vector<uint16> tris = colMesh.Mesh.getTriangles();
209 uint triSize = tris.size();
211 // Insert tri in the grid
212 // Because of low resolution, only a few tri will actually be inserted
213 while (currVert != triSize)
215 const CVector &v0 = _CurrMeshVertices[tris[currVert]];
216 const CVector &v1 = _CurrMeshVertices[tris[currVert + 1]];
217 const CVector &v2 = _CurrMeshVertices[tris[currVert + 2]];
218 // project corners in 2D
219 CVector2f corners[3];
220 corners[0].set(v0.x, v0.y);
221 corners[1].set(v1.x, v1.y);
222 corners[2].set(v2.x, v2.y);
223 addTri(corners, maxof(v0.z, v1.z, v2.z));
226 _Meshs[colMesh.ID] = colMesh;
229 // ***********************************************************************************
230 void CHeightGrid::removeCollisionMesh(uint id)
232 TColMeshMap::iterator it = _Meshs.find(id);
233 if (it == _Meshs.end()) return;
234 const std::vector<CVector> &vertices = it->second.Mesh.getVertices();
235 _CurrMeshVertices.resize(vertices.size());
236 std::vector<CVector>::const_iterator src, srcEnd;
237 std::vector<CVector>::iterator dest;
238 srcEnd = vertices.end();
239 dest = _CurrMeshVertices.begin();
240 // transform vertices in world
241 const CMatrix &worldMat = *(it->second.WorldMatrix);
242 for (src = vertices.begin(); src != srcEnd; ++ src)
244 *dest = worldMat * *src;
247 std::vector<uint16> tris = it->second.Mesh.getTriangles();
248 uint triSize = tris.size();
250 while (currVert != triSize)
252 const CVector v0 = _CurrMeshVertices[tris[currVert]];
253 const CVector v1 = _CurrMeshVertices[tris[currVert + 1]];
254 const CVector v2 = _CurrMeshVertices[tris[currVert + 2]];
255 // project corners in 2D
256 CVector2f corners[3];
257 corners[0].set(v0.x, v0.y);
258 corners[1].set(v1.x, v1.y);
259 corners[2].set(v2.x, v2.y);
260 removeTri(corners, maxof(v0.z, v1.z, v2.z));
267 // ***********************************************************************************
268 void CHeightGrid::updateRect(const NLMISC::CRect &rect)
270 // add incoming meshs into the quad grid
272 bbox.setMinMax(CVector(rect.X * _CellSize, rect.Y * _CellSize, _MinZ), CVector((rect.X + rect.Width) * _CellSize, (rect.Y + rect.Height) * _CellSize, - _MinZ));
273 CollisionManager->getMeshs(bbox, _UpdateMeshs);
274 for(uint k = 0; k < _UpdateMeshs.size(); ++k)
276 if (_Meshs.count(_UpdateMeshs[k].ID) == 0)
278 // not already inserted
279 addCollisionMesh(_UpdateMeshs[k]);
282 // Update height grid from the values in the quad grid
283 for (uint y = (uint) rect.Y; y < (uint) (rect.Y + rect.Height); ++y)
285 for (uint x = (uint) rect.X; x < (uint) (rect.X + rect.Width); ++x)
292 // ***********************************************************************************
293 void CHeightGrid::discardRect(const CRect &rect)
295 // remove meshs that are totally out of the grid
297 bbox.setMinMax(CVector(rect.X * _CellSize, rect.Y * _CellSize, _MinZ), CVector((rect.X + rect.Width) * _CellSize, (rect.Y + rect.Width) * _CellSize, - _MinZ));
298 CollisionManager->getMeshs(bbox, _UpdateMeshs);
299 for(uint k = 0; k < _UpdateMeshs.size(); ++k)
301 if (!_UpdateMeshs[k].WorldBBox->intersect(_BBox))
303 removeCollisionMesh(_UpdateMeshs[k].ID); // remove mesh (no-op if already removed)
308 // ***********************************************************************************
309 void CHeightGrid::updateCell(sint px, sint py)
311 sint worldX = px + _PosX;
312 sint worldY = py + _PosY;
314 const CHeightGridWrapped::TGridElemList &pl = _ZGridWrapped.getGridElemList(worldX, worldY);
315 for(CHeightGridWrapped::TGridElemList::const_iterator it = pl.begin(); it != pl.end(); ++it)
317 const CHeightGridWrapped::CGridElem &ge = *it;
318 if (ge.X == worldX && ge.Y == worldY)
320 z = std::max(z, ge.Z);
327 // ***********************************************************************************
328 void CHeightGrid::display(NL3D::UDriver &drv) const
330 extern UCamera MainCam;
331 drv.setModelMatrix(CMatrix::Identity);
332 drv.setViewMatrix(MainCam.getMatrix().inverted());
333 drv.setFrustum(MainCam.getFrustum());
334 UMaterial m = drv.createMaterial();
336 m.setColor(CRGBA::Red);
337 for (sint y = _PosY; y < (sint) (_PosY + _GridSize - 1); ++y)
339 for (sint x = _PosX; x < (sint) (_PosX + _GridSize - 1); ++x)
341 float z0 = _ZGrid(x - _PosX, y - _PosY);
342 float z1 = _ZGrid(x + 1 - _PosX, y - _PosY);
343 float z2 = _ZGrid(x + 1 - _PosX, y + 1 - _PosY);
344 float z3 = _ZGrid(x - _PosX, y + 1 - _PosY);
347 CVector pos0 = gridCoordToWorld(x, y) + z0 * CVector::K;
348 CVector pos1 = gridCoordToWorld(x + 1, y) + z1 * CVector::K;
349 CVector pos2 = gridCoordToWorld(x + 1, y + 1) + z2 * CVector::K;
350 CVector pos3 = gridCoordToWorld(x, y + 1) + z3 * CVector::K;
351 drv.drawLine(CLine(pos0, pos1), m);
352 drv.drawLine(CLine(pos1, pos2), m);
353 drv.drawLine(CLine(pos2, pos3), m);
354 drv.drawLine(CLine(pos3, pos0), m);
357 m.setColor(CRGBA::Green);
358 // draw dots of the point grid
359 //for (sint y = 0; y < (sint) _PointGrid.getSize(); ++y)
361 // for (sint x = 0; x < (sint) _PointGrid.getSize(); ++x)
363 // const CPointGrid::TPointList &pl = _PointGrid.getPointList(x ,y);
364 // for(CPointGrid::TPointList::const_iterator it = pl.begin(); it != pl.end(); ++it)
366 // drv.drawLine(CLine(*it, *it + CVector::K), m);
371 drv.deleteMaterial(m);
372 // info : check max size of vectors
373 nlwarning("Max list length = %d", (int) _ZGridWrapped.getListMaxLength());
380 // *********************************************************************************
381 CHeightGridWrapped::CHeightGridWrapped()
388 // *********************************************************************************
389 uint CHeightGridWrapped::getListMaxLength() const
392 for(CArray2D<TGridElemList>::const_iterator it = _Grid.begin(); it != _Grid.end(); ++it)
394 sizeMax = std::max(sizeMax, (uint) it->size());
399 // *********************************************************************************
400 void CHeightGridWrapped::init(uint size, float cellSize)
402 nlassert(cellSize > 0.f)
403 nlassert(NLMISC::isPowerOf2(size));
404 uint sizePower= NLMISC::getPowerOf2(size);
405 _SizeMask = (1 << sizePower) - 1;
406 _CellSize = cellSize;
407 _InvCellSize = 1.f / _CellSize;
408 _Grid.init(size, size);
412 //=====================================================================
413 CPrecipitationClipGrid::CPrecipitationClipGrid()
419 //=====================================================================
420 void CPrecipitationClipGrid::initGrid(uint size
, float gridEltSizeX
, float gridEltSizeY
)
422 if (gridEltSizeX
<= 0.f
|| gridEltSizeY
<= 0.f
|| size
== 0)
428 _Grid
.resize((size
+ 1) * (size
+ 1));
431 _EltSizeX
= gridEltSizeX
;
432 _EltSizeY
= gridEltSizeY
;
436 //=====================================================================
437 void CPrecipitationClipGrid::updateGrid(const NLMISC::CVector
&/* userPos */, NLPACS::UGlobalRetriever
* /* gr */)
443 if (_EltSizeX == 0.f) return;
444 sint newX = (sint) floorf(userPos.x / _EltSizeX) - (_Size >> 1);
445 sint newY = (sint) floorf(userPos.y / _EltSizeY) - (_Size >> 1);
449 #if defined(NL_CPU_INTEL) && defined(NL_DEBUG)
451 CSimpleClock::init();
454 // recompute the whole grid
455 updateGridPart(newX, newY, 0, 0, _Size + 1, _Size + 1, gr);
456 #if defined(NL_CPU_INTEL) && defined(NL_DEBUG)
458 // display number of millisecond needed for the update
459 double freq = (double) CSystemInfo::getProcessorFrequency();
460 double msPerTick = 1000 / (double) freq;
461 nldebug("Updated precipitation clip grid : time = %.2f ms", (float) (clock.getNumTicks() * msPerTick));
462 // display the height in the clip grid
472 if (newX == _XPos && newY == _YPos)
474 return; // the grid hasn't changed its pos
478 sint offsetX = newX - _XPos;
479 sint offsetY = newY - _YPos;
481 moveGrid(- offsetX, - offsetY);
482 // complete new positions
484 #if defined(NL_CPU_INTEL) && defined(NL_DEBUG)
486 CSimpleClock::init();
490 // Update right or left part.
491 if (newX > _XPos) // moved right ?
493 // the width to update
494 uint width = std::min((uint) offsetX, _Size + 1);
495 // the grid moved top or bottom, exclude this part
496 sint height = _Size + 1 - abs(offsetY);
499 // complete column on the right
500 updateGridPart(newX + _Size + 1 - width, newY - offsetY, _Size + 1 - width, std::max(-offsetY, 0), width, height, gr);
503 else if (newX < _XPos) // moved left ?
505 // the width to update
506 uint width = std::min((uint) (- offsetX), _Size + 1);
507 // the grid moved top or bottom, exclude
508 sint height = _Size + 1 - abs(offsetY);
511 // complete column on the right
512 updateGridPart(newX, newY - offsetY, 0, std::max(-offsetY, 0), width, height, gr);
516 // update top or bottom part
519 sint height = std::min((uint) offsetY, _Size + 1);
520 updateGridPart(newX, newY + _Size + 1 - height, 0, _Size + 1 - height, _Size + 1, height, gr);
525 sint height = std::min((uint) (- offsetY), _Size + 1);
526 updateGridPart(newX, newY, 0, 0, _Size + 1, height, gr);
529 #if defined(NL_CPU_INTEL) && defined(NL_DEBUG)
531 // display number of millisecond needed for the update
532 double freq = (double) CSystemInfo::getProcessorFrequency();
533 double msPerTick = 1000 / (double) freq;
534 nldebug("Updated precipitation clip grid : time = %.2f ms", (float) (clock.getNumTicks() * msPerTick));
535 // display the height in the clip grid
545 //=====================================================================
546 void CPrecipitationClipGrid::printGridValues() const
548 for(uint k
= 0; k
<= _Size
; ++k
)
551 for(uint l
= 0; l
<= _Size
; ++l
)
553 TGrid::const_iterator gridIt
= getGridIt(_Grid
, l
, k
, _Size
);
554 outStr
+= toString("%5d%c ", (uint
) gridIt
->MeanHeight
, l
== _Size
? ' ' : ',');
556 nlinfo(outStr
.c_str());
560 //=====================================================================
561 void CPrecipitationClipGrid::moveGrid(sint offsetX
, sint offsetY
)
563 static TGrid otherGrid
; // the grid is likely to be rather small so it's ok to keep it static
564 otherGrid
.resize(_Grid
.size());
565 // get start pos in the source
568 // compute position in source & size
572 width
= (_Size
+ 1) - offsetX
;
577 width
= (_Size
+ 1) - srcX
;
582 height
= (_Size
+ 1) - offsetY
;
587 height
= (_Size
+ 1) - srcY
;
589 if (width
> 0 && height
> 0)
591 TGrid::const_iterator srcIt
= getGridIt(_Grid
, srcX
, srcY
, _Size
);
592 TGrid::iterator dstIt
= getGridIt(otherGrid
, srcX
+ offsetX
, srcY
+ offsetY
, _Size
);
595 // copy one row of the grid
596 std::copy(srcIt
, srcIt
+ width
, dstIt
);
597 // go to next row for source & destination
598 srcIt
+= (_Size
+ 1);
599 dstIt
+= (_Size
+ 1);
602 _Grid
.swap(otherGrid
); // replace previous grid
606 //=====================================================================
607 const CPrecipitationClipGrid::CGridPoint
*CPrecipitationClipGrid::get(sint x
, sint y
) const
612 if ((uint
) gx
> (_Size
+ 1) || (uint
) gy
> (_Size
+ 1)) return NULL
;
613 return &(*getGridIt(_Grid
, gx
, gy
, _Size
));
616 //=====================================================================
617 void CPrecipitationClipGrid::clear()
627 //=====================================================================
628 void CPrecipitationClipGrid::updateGridPart(sint worldX
, sint worldY
, uint gridX
, uint gridY
, uint width
, uint height
, NLPACS::UGlobalRetriever
*gr
)
630 nlassert(gridX
<= _Size
);
631 nlassert(gridY
<= _Size
);
632 nlassert(gridX
+ width
>= gridX
&& gridX
+ width
<= _Size
+ 1);
633 nlassert(gridY
+ height
>= gridY
&& gridY
+ height
<= _Size
+ 1);
634 NLMISC::CVector
worldPos(worldX
* _EltSizeX
, worldY
* _EltSizeY
, 10000.f
);
635 TGrid::iterator dest
= getGridIt(_Grid
, gridX
, gridY
, _Size
);
637 for (uint y
= 0; y
< height
; ++y
)
639 TGrid::iterator currDest
= dest
;
640 NLMISC::CVector currWorldPos
= worldPos
;
642 for (uint x
= 0; x
< width
; ++x
)
646 currDest
->Clipped
= true;
647 currDest
->MeanHeight
= 0.f
;
651 // build a global position
652 NLPACS::UGlobalPosition gpos
= gr
->retrievePosition(currWorldPos
, 20000.f
);
653 if (gpos
.InstanceId
!= -1)
655 // is it an interior ?
656 if (gr
->isInterior(gpos
))
658 currDest
->Clipped
= true;
659 currDest
->MeanHeight
= 0.f
;
663 // get mean height at this point
664 currDest
->Clipped
= false;
665 currDest
->MeanHeight
= gr
->getMeanHeight(gpos
);
670 currDest
->MeanHeight
= 0.f
;
674 currWorldPos
.x
+= _EltSizeX
;
678 currWorldPos
.y
+= _EltSizeY
;
682 //=====================================================================
683 void CPrecipitationClipGrid::display(NL3D::UDriver
&drv
) const
685 // get render context
686 CMatrix modelMat
= drv
.getModelMatrix();
687 CMatrix viewMat
= drv
.getViewMatrix();
688 CFrustum f
= drv
.getFrustum();
690 drv
.setMatrixMode2D(CFrustum(0, 800, 600, 0, 0, 1, false));
692 const uint stepX
= 16;
693 const uint stepY
= 16;
694 for (uint y
= 0; y
< _Size
+ 1; ++y
)
696 for (uint x
= 0; x
< _Size
+ 1; ++x
)
698 TGrid::const_iterator gridPoint
= getGridIt(_Grid
, x
, y
, _Size
);
699 CRGBA col
= gridPoint
->Clipped
? CRGBA::Red
: CRGBA::White
;
700 drv
.drawLine((float) (x
* stepX
- 1), (float) (y
* stepY
), (float) (x
* stepX
+ 1), (float) (y
* stepY
), col
);
701 drv
.drawLine((float) (x
* stepX
), (float) (y
* stepY
- 1), (float) (x
* stepX
), (float) (y
* stepY
+ 1), col
);
705 // restore render context
706 drv
.setModelMatrix(modelMat
);
707 drv
.setViewMatrix(viewMat
);