Resolve "Toggle Free Look with Hotkey"
[ryzomcore.git] / ryzom / client / src / precipitation_clip_grid.cpp
blob5ad3910d72f74b60b966f53468de8ab1bca2948b
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
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.
8 //
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/>.
20 #include "stdpch.h"
22 #include "precipitation_clip_grid.h"
25 using namespace NLMISC;
26 using namespace NL3D;
29 //CHeightGrid HeightGrid;
32 extern UVisualCollisionManager *CollisionManager;
33 /////////////////
34 // CHeightGrid //
35 /////////////////
39 // ***********************************************************************************
40 void CHeightGrid::tileAdded(const CTileAddedInfo &infos)
42 // insert in point grid
43 _TileInfos[infos.TileID] = infos;
44 CVector2f corners[3];
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());
60 CVector2f corners[3];
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];
79 sint minY;
80 _Tri.computeBorders(_Rasters, minY);
81 if (_Rasters.empty()) return;
82 sint numRasters = _Rasters.size();
83 CHeightGridWrapped::CGridElem ge;
84 ge.Z = z;
85 for(sint y = 0; y < numRasters; ++y)
87 ge.Y = y + minY;
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];
109 sint minY;
110 _Tri.computeBorders(_Rasters, minY);
111 if (_Rasters.empty()) return;
112 sint numRasters = _Rasters.size();
113 CHeightGridWrapped::CGridElem ge;
114 ge.Z = z;
115 for(sint y = 0; y < numRasters; ++y)
117 ge.Y = y + minY;
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()
129 _CellSize = 0.f;
130 _GridSize = 0;
131 _MinZ = HEIGHT_GRID_MIN_Z;
132 _PosX = 0;
133 _PosY = 0;
134 _SizeMask = 0;
135 _InvCellSize = 1.f;
136 updateBBox();
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);
150 _MinZ = minZ;
151 _CellSize = cellSize;
152 _GridSize = heightGridSize;
153 _InvCellSize = 1.f / _CellSize;
154 updateBBox();
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);
181 updateBBox();
182 // compute parts of the grid that must be updated
183 _ZGrid.getUpdateRects(offsetX, offsetY, _UpdateRects);
184 _PosX = newX;
185 _PosY = newY;
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;
206 ++ dest;
208 std::vector<uint16> tris = colMesh.Mesh.getTriangles();
209 uint triSize = tris.size();
210 uint currVert = 0;
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));
224 currVert += 3;
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;
245 ++ dest;
247 std::vector<uint16> tris = it->second.Mesh.getTriangles();
248 uint triSize = tris.size();
249 uint currVert = 0;
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));
261 currVert += 3;
263 _Meshs.erase(it);
267 // ***********************************************************************************
268 void CHeightGrid::updateRect(const NLMISC::CRect &rect)
270 // add incoming meshs into the quad grid
271 CAABBox bbox;
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)
287 updateCell(x, y);
292 // ***********************************************************************************
293 void CHeightGrid::discardRect(const CRect &rect)
295 // remove meshs that are totally out of the grid
296 CAABBox bbox;
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;
313 float z = _MinZ;
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);
323 _ZGrid(px, py) = 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();
335 m.initUnlit();
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);
346 CVector pos[4];
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)
362 // {
363 // const CPointGrid::TPointList &pl = _PointGrid.getPointList(x ,y);
364 // for(CPointGrid::TPointList::const_iterator it = pl.begin(); it != pl.end(); ++it)
365 // {
366 // drv.drawLine(CLine(*it, *it + CVector::K), m);
367 // }
368 // }
371 drv.deleteMaterial(m);
372 // info : check max size of vectors
373 nlwarning("Max list length = %d", (int) _ZGridWrapped.getListMaxLength());
376 ////////////////
377 // CPointGrid //
378 ////////////////
380 // *********************************************************************************
381 CHeightGridWrapped::CHeightGridWrapped()
383 _CellSize = 0.f;
384 _SizeMask = 0;
385 _InvCellSize = 1.f;
388 // *********************************************************************************
389 uint CHeightGridWrapped::getListMaxLength() const
391 uint sizeMax = 0;
392 for(CArray2D<TGridElemList>::const_iterator it = _Grid.begin(); it != _Grid.end(); ++it)
394 sizeMax = std::max(sizeMax, (uint) it->size());
396 return sizeMax;
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()
415 clear();
416 touch();
419 //=====================================================================
420 void CPrecipitationClipGrid::initGrid(uint size, float gridEltSizeX, float gridEltSizeY)
422 if (gridEltSizeX <= 0.f || gridEltSizeY <= 0.f || size == 0)
424 clear();
425 return;
427 _Grid.clear();
428 _Grid.resize((size + 1) * (size + 1));
429 _XPos = 0;
430 _YPos = 0;
431 _EltSizeX = gridEltSizeX;
432 _EltSizeY = gridEltSizeY;
433 _Size = size;
436 //=====================================================================
437 void CPrecipitationClipGrid::updateGrid(const NLMISC::CVector &/* userPos */, NLPACS::UGlobalRetriever * /* gr */)
439 // temp
440 return;
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);
447 if (_Touched)
449 #if defined(NL_CPU_INTEL) && defined(NL_DEBUG)
450 CSimpleClock clock;
451 CSimpleClock::init();
452 clock.start();
453 #endif
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)
457 clock.stop();
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
463 printGridValues();
464 #endif
465 // update pos
466 _XPos = newX;
467 _YPos = newY;
468 _Touched = false;
469 return;
472 if (newX == _XPos && newY == _YPos)
474 return; // the grid hasn't changed its pos
477 // move the grid
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)
485 CSimpleClock clock;
486 CSimpleClock::init();
487 clock.start();
488 #endif
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);
497 if (height > 0)
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);
509 if (height > 0)
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
517 if (newY > _YPos)
519 sint height = std::min((uint) offsetY, _Size + 1);
520 updateGridPart(newX, newY + _Size + 1 - height, 0, _Size + 1 - height, _Size + 1, height, gr);
522 else
523 if (newY < _YPos)
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)
530 clock.stop();
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
536 printGridValues();
537 #endif
539 // update pos
540 _XPos = newX;
541 _YPos = newY;
545 //=====================================================================
546 void CPrecipitationClipGrid::printGridValues() const
548 for(uint k = 0; k <= _Size; ++k)
550 std::string outStr;
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
566 uint srcX, srcY;
567 sint width, height;
568 // compute position in source & size
569 if (offsetX > 0)
571 srcX = 0;
572 width = (_Size + 1) - offsetX;
574 else
576 srcX = -offsetX;
577 width = (_Size + 1) - srcX;
579 if (offsetY > 0)
581 srcY = 0;
582 height = (_Size + 1) - offsetY;
584 else
586 srcY = -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);
601 while (--height);
602 _Grid.swap(otherGrid); // replace previous grid
606 //=====================================================================
607 const CPrecipitationClipGrid::CGridPoint *CPrecipitationClipGrid::get(sint x, sint y) const
609 // pos in the grid
610 sint gx = x - _XPos;
611 sint gy = y - _YPos;
612 if ((uint) gx > (_Size + 1) || (uint) gy > (_Size + 1)) return NULL;
613 return &(*getGridIt(_Grid, gx, gy, _Size));
616 //=====================================================================
617 void CPrecipitationClipGrid::clear()
619 _XPos = 0;
620 _YPos = 0;
621 _Size = 0;
622 _EltSizeX = 0;
623 _EltSizeY = 0;
624 _Grid.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);
636 // fill each row
637 for (uint y = 0; y < height; ++y)
639 TGrid::iterator currDest = dest;
640 NLMISC::CVector currWorldPos = worldPos;
641 // fill a row
642 for (uint x = 0; x < width; ++x)
644 if (!gr)
646 currDest->Clipped = true;
647 currDest->MeanHeight = 0.f;
649 else
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;
661 else
663 // get mean height at this point
664 currDest->Clipped = false;
665 currDest->MeanHeight = gr->getMeanHeight(gpos);
668 else
670 currDest->MeanHeight = 0.f;
673 ++ currDest;
674 currWorldPos.x += _EltSizeX;
676 // move to next row
677 dest += (_Size + 1);
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);
708 drv.setFrustum(f);