1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 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/>.
24 #include "nel/3d/packed_zone.h"
25 #include "nel/3d/driver.h"
26 #include "nel/3d/material.h"
28 #include "nel/misc/matrix.h"
29 #include "nel/misc/polygon.h"
30 #include "nel/misc/path.h"
31 #include "nel/misc/grid_traversal.h"
32 #include "nel/misc/bit_mem_stream.h"
39 using namespace NLMISC
;
48 #define PACKED_COL_RANGE 4095
55 uint Rel0NumBits
; // 2 for - 2 .. + 1 range
56 uint Rel1NumBits
; // 4 for - 8 .. + 7 range
57 uint Rel2NumBits
; // 8 for - 128 .. + 127 range
58 uint AbsNumBits
; // num bits for absolute value
60 void serialPackedVector16(std::vector
<uint16
> &v
, NLMISC::IStream
&f
, const CFormat
&format
);
64 // format is stored as 2 bits at each entry
67 Rel0
= 0, // - 2 .. + 1 range
68 Rel1
= 1, // - 8 .. + 7 range
69 Rel2
= 2, // - 128 .. + 127 range
70 AbsOrRLE
= 3 // full precision absolute value
73 std::vector
<sint32
> _LastDeltas
;
76 uint _Count
[4]; // statistics
77 uint _Repeated
[4]; // statistics
80 void bufferizeDelta(uint32 tag
, sint32 delta
, CBitMemStream
&bits
);
81 void flush(CBitMemStream
&bits
);
82 void writeSimpleValue(CBitMemStream
&bits
, sint32 delta
);
83 void readSimpleValue(uint32 tag
, std::vector
<uint16
> &v
, CBitMemStream
&bits
);
84 static sint32
getMax(uint numBits
)
86 return (uint32
) ((1 << (numBits
- 1)) - 1);
88 static sint32
getMin(uint numBits
)
90 return (uint32
) (0xfffffffe << (numBits
- 2));
92 static void extendSign(uint numBits
, uint32
&value
)
94 if (value
& (1 << (numBits
- 1)))
96 value
|= (uint32
) (0xfffffffe << (numBits
- 1));
101 // ********************************************************************************************
102 void CVectorPacker::writeSimpleValue(CBitMemStream
&bits
, sint32 delta
)
104 uint32 croppedDelta
= (uint32
) delta
;
109 bits
.serial(croppedDelta
, _Format
.Rel0NumBits
);
114 bits
.serial(croppedDelta
, _Format
.Rel1NumBits
);
119 bits
.serial(croppedDelta
, _Format
.Rel2NumBits
);
124 // not a delta but a value ...
125 uint32 value
= (uint16
) delta
;
126 bits
.serial(value
, _Format
.AbsNumBits
);
133 if (_LastTag
== AbsOrRLE
)
135 //nlwarning("writing simple value %d (tag = %d)", (int) (uint16) delta, (int) _LastTag);
139 //nlwarning("writing simple delta %d (tag = %d)", (int) delta, (int) _LastTag);
144 // ********************************************************************************************
145 void CVectorPacker::readSimpleValue(uint32 tag
, std::vector
<uint16
> &v
, CBitMemStream
&bits
)
151 bits
.serial(croppedDelta
, _Format
.Rel0NumBits
);
152 extendSign(_Format
.Rel0NumBits
, croppedDelta
);
153 v
[_ReadIndex
] = (uint16
) (v
[_ReadIndex
- 1] + (sint16
) croppedDelta
);
156 bits
.serial(croppedDelta
, _Format
.Rel1NumBits
);
157 extendSign(_Format
.Rel1NumBits
, croppedDelta
);
158 v
[_ReadIndex
] = (uint16
) (v
[_ReadIndex
- 1] + (sint16
) croppedDelta
);
161 bits
.serial(croppedDelta
, _Format
.Rel2NumBits
);
162 extendSign(_Format
.Rel2NumBits
, croppedDelta
);
163 v
[_ReadIndex
] = (uint16
) (v
[_ReadIndex
- 1] + (sint16
) croppedDelta
);
169 //nlwarning("reading simple delta %d (tag = %d)", (int) (v[_ReadIndex] - v[_ReadIndex - 1]), (int) tag);
173 // ********************************************************************************************
174 void CVectorPacker::flush(CBitMemStream
&bits
)
176 if (_LastDeltas
.empty()) return;
177 if (_LastDeltas
.size() > 4)
179 // put a 'repeat tag'
180 uint32 repeatTag
= AbsOrRLE
;
181 bits
.serial(repeatTag
, 2);
183 bits
.serial(isRLE
, 1);
184 bits
.serial(_LastTag
, 2);
185 nlassert(_LastDeltas
.size() <= 255);
186 uint8 length
= (uint8
)_LastDeltas
.size();
187 //nlwarning("begin RLE, length = %d, tag = %d", (int) length, (int) repeatTag);
189 for(uint k
= 0; k
< _LastDeltas
.size(); ++k
)
191 writeSimpleValue(bits
, _LastDeltas
[k
]);
194 ++_Repeated
[_LastTag
];
198 // flush separate values
199 for(uint k
= 0; k
< _LastDeltas
.size(); ++k
)
201 //nlwarning("write single value tag %d", (int) _LastTag);
202 bits
.serial(_LastTag
, 2);
203 if (_LastTag
== (uint32
) AbsOrRLE
)
206 bits
.serial(isRLE
, 1);
208 writeSimpleValue(bits
, _LastDeltas
[k
]);
214 // ********************************************************************************************
215 void CVectorPacker::bufferizeDelta(uint32 tag
, sint32 delta
, CBitMemStream
&bits
)
217 if (tag
!= _LastTag
|| _LastDeltas
.size() == 255)
222 _LastDeltas
.push_back(delta
);
225 // ********************************************************************************************
226 void CVectorPacker::serialPackedVector16(std::vector
<uint16
> &v
,NLMISC::IStream
&f
, const CFormat
&format
)
231 CBitMemStream
bits(true);
232 std::vector
<uint8
> datas
;
234 bits
.fill(&datas
[0], (uint32
)datas
.size());
235 uint32 numValues
= 0;
236 bits
.serial(numValues
);
239 while (_ReadIndex
!= numValues
)
244 bits
.serial(value
, _Format
.AbsNumBits
);
245 v
[0] = (uint16
) value
;
246 //nlwarning("v[0] = %d", (int) v[0]);
253 //nlwarning("read tag %d", (int) tag);
260 readSimpleValue(tag
, v
, bits
);
264 // serial one more bit to see if there's RLE here
266 bits
.serial(isRLE
, 1);
270 bits
.serial(repeatTag
, 2);
273 //nlwarning("begin RLE, length = %d", (int) length);
274 for(uint l
= 0; l
< length
; ++l
)
281 readSimpleValue(repeatTag
, v
, bits
);
285 bits
.serial(value
, _Format
.AbsNumBits
);
286 v
[_ReadIndex
] = (uint16
) value
;
287 //nlwarning("reading abs 16 value : %d", (int) v[_ReadIndex]);
291 throw NLMISC::EInvalidDataStream();
300 bits
.serial(value
, _Format
.AbsNumBits
);
301 v
[_ReadIndex
] = (uint16
) value
;
302 //nlwarning("reading abs 16 value : %d", (int) v[_ReadIndex]);
316 _Count
[AbsOrRLE
] = 0;
320 _Repeated
[AbsOrRLE
] = 0;
322 CBitMemStream
bits(false);
323 uint32 numValues
= (uint32
)v
.size();
324 bits
.serial(numValues
);
325 _LastTag
= std::numeric_limits
<uint32
>::max();
327 for(uint k
= 0; k
< v
.size(); ++k
)
332 bits
.serial(value
, _Format
.AbsNumBits
);
333 //nlwarning("v[0] = %d", (int) v[0]);
337 sint32 delta
= v
[k
] - v
[k
- 1];
338 if (delta
>= getMin(_Format
.Rel0NumBits
) && delta
<= getMax(_Format
.Rel0NumBits
))
340 bufferizeDelta(Rel0
, delta
, bits
);
342 else if (delta
>= getMin(_Format
.Rel1NumBits
) && delta
<= getMax(_Format
.Rel1NumBits
))
344 bufferizeDelta(Rel1
, delta
, bits
);
346 else if (delta
>= getMin(_Format
.Rel2NumBits
) && delta
<= getMax(_Format
.Rel2NumBits
))
348 bufferizeDelta(Rel2
, delta
, bits
);
352 bufferizeDelta(AbsOrRLE
, v
[k
], bits
); // absolute value here ...
357 std::vector
<uint8
> datas(bits
.buffer(), bits
.buffer() + bits
.length());
360 if (_Count[Rel0] != 0 || _Count[Rel1] != 0 || _Count[Rel2] != 0 || _Count[AbsOrRLE] != 0)
362 nlwarning("count0 = %d", _Count[Rel0]);
363 nlwarning("count1 = %d", _Count[Rel1]);
364 nlwarning("count2 = %d", _Count[Rel2]);
365 nlwarning("countAbs = %d", _Count[AbsOrRLE]);
367 nlwarning("repeat 0 = %d", _Repeated[Rel0]);
368 nlwarning("repeat 1 = %d", _Repeated[Rel1]);
369 nlwarning("repeat 2 = %d", _Repeated[Rel2]);
370 nlwarning("repeat Abs = %d", _Repeated[AbsOrRLE]);
379 // helper function : serialize a uint16 vector
380 void serialPackedVector16(std::vector
<uint16
> &v
, NLMISC::IStream
&f
)
382 CVectorPacker packer
;
383 CVectorPacker::CFormat format
;
384 format
.Rel0NumBits
= 2;
385 format
.Rel1NumBits
= 4;
386 format
.Rel2NumBits
= 8;
387 format
.AbsNumBits
= 16;
388 packer
.serialPackedVector16(v
, f
, format
);
393 uint num = std::min((uint) v.size(), (uint) 1000);
394 for(uint k = 0; k < num; ++k)
396 nlwarning("[%d] = %d", (int) k, (int) v[k]);
404 void serialPackedVector12(std::vector
<uint16
> &v
, NLMISC::IStream
&f
)
406 CVectorPacker packer
;
407 CVectorPacker::CFormat format
;
408 format
.Rel0NumBits
= 2;
409 format
.Rel1NumBits
= 6;
410 format
.Rel2NumBits
= 9;
411 format
.AbsNumBits
= 12;
412 packer
.serialPackedVector16(v
, f
, format
);
417 uint num = std::min((uint) v.size(), (uint) 1000);
418 for(uint k = 0; k < num; ++k)
420 nlwarning("[%d] = %d", (int) k, (int) v[k]);
427 // some function to ease writing of some primitives into a vertex buffer
428 static inline void pushVBLine2D(NLMISC::CVector
*&dest
, const NLMISC::CVector
&v0
, const NLMISC::CVector
&v1
)
444 static inline void pushVBTri2D(NLMISC::CVector
*&dest
, const NLMISC::CTriangle
&tri
)
461 static inline void pushVBQuad2D(NLMISC::CVector
*&dest
, const NLMISC::CQuad
&quad
)
481 static inline void pushVBQuad(NLMISC::CVector
*&dest
, const NLMISC::CQuad
&quad
)
490 // compute rasters union.
491 static void computeRastersUnion(const CPolygon2D::TRasterVect
&inRaster0
, CPolygon2D::TRasterVect
&inRaster1
, sint minY0
, sint minY1
,
492 CPolygon2D::TRasterVect
&outRaster
, sint
&finalMinY
)
494 if (inRaster0
.empty())
496 if (inRaster1
.empty())
502 outRaster
= inRaster1
;
506 else if (inRaster1
.empty())
508 outRaster
= inRaster0
;
512 nlassert(&outRaster
!= &inRaster0
);
513 nlassert(&outRaster
!= &inRaster1
);
514 finalMinY
= std::min(minY0
, minY1
);
515 sint maxY
= std::max(minY0
+ (sint
) inRaster0
.size(), minY1
+ (sint
) inRaster1
.size());
516 outRaster
.resize(maxY
- finalMinY
);
517 for(sint y
= 0; y
< (sint
) outRaster
.size(); ++y
)
519 outRaster
[y
].first
= INT_MAX
;
520 outRaster
[y
].second
= INT_MIN
;
521 sint raster0Y
= y
+ finalMinY
- minY0
;
522 if (raster0Y
>= 0 && raster0Y
< (sint
) inRaster0
.size())
524 //if (inRaster0[raster0Y].second >= inRaster0[raster0Y].first)
526 outRaster
[y
].first
= std::min(outRaster
[y
].first
, inRaster0
[raster0Y
].first
);
527 outRaster
[y
].second
= std::max(outRaster
[y
].second
, inRaster0
[raster0Y
].second
);
530 sint raster1Y
= y
+ finalMinY
- minY1
;
531 if (raster1Y
>= 0 && raster1Y
< (sint
) inRaster1
.size())
533 //if (inRaster1[raster1Y].second >= inRaster1[raster1Y].first)
535 outRaster
[y
].first
= std::min(outRaster
[y
].first
, inRaster1
[raster1Y
].first
);
536 outRaster
[y
].second
= std::max(outRaster
[y
].second
, inRaster1
[raster1Y
].second
);
542 static void addQuadToSilhouette(const CVector
&v0
, const CVector
&v1
, const CVector
&v2
, CVector
&v3
, CPolygon2D::TRasterVect
&sil
, sint
&minY
, float cellSize
)
544 static CPolygon2D quad
;
545 quad
.Vertices
.resize(4);
546 quad
.Vertices
[0] = v0
/ cellSize
;
547 quad
.Vertices
[1] = v1
/ cellSize
;
548 quad
.Vertices
[2] = v2
/ cellSize
;
549 quad
.Vertices
[3] = v3
/ cellSize
;
551 static CPolygon2D::TRasterVect newQuad
;
552 static CPolygon2D::TRasterVect result
;
555 quad
.computeOuterBorders(newQuad
, newMinY
);
556 computeRastersUnion(sil
, newQuad
, minY
, newMinY
, result
, resultMinY
);
561 uint16
CPackedZone16::UndefIndex
= 0xffff;
563 // ***************************************************************************************
564 CPackedZone16::CPackedZone16()
567 _Origin
= CVector::Null
;
570 // ***************************************************************************************
571 void CPackedZone32::unpackTri(const CPackedTri
&src
, CVector dest
[3]) const
573 // TODO: add 'multiply-add' operator
574 dest
[0].set(Verts
[src
.V0
].X
* _PackedLocalToWorld
.x
+ _Origin
.x
,
575 Verts
[src
.V0
].Y
* _PackedLocalToWorld
.y
+ _Origin
.y
,
576 Verts
[src
.V0
].Z
* _PackedLocalToWorld
.z
+ _Origin
.z
);
577 dest
[1].set(Verts
[src
.V1
].X
* _PackedLocalToWorld
.x
+ _Origin
.x
,
578 Verts
[src
.V1
].Y
* _PackedLocalToWorld
.y
+ _Origin
.y
,
579 Verts
[src
.V1
].Z
* _PackedLocalToWorld
.z
+ _Origin
.z
);
580 dest
[2].set(Verts
[src
.V2
].X
* _PackedLocalToWorld
.x
+ _Origin
.x
,
581 Verts
[src
.V2
].Y
* _PackedLocalToWorld
.y
+ _Origin
.y
,
582 Verts
[src
.V2
].Z
* _PackedLocalToWorld
.z
+ _Origin
.z
);
586 uint32
CPackedZone32::UndefIndex
= 0xffffffff;
588 // ***************************************************************************************
589 CPackedZone32::CPackedZone32()
592 _Origin
= CVector::Null
;
595 // ***************************************************************************************
596 void CPackedZone32::serial(NLMISC::IStream
&f
)
602 f
.serialCont(TriLists
);
606 f
.serial(_WorldToLocal
);
611 _PackedLocalToWorld
.set(1.f
/ (_WorldToLocal
.x
* (float) PACKED_COL_RANGE
),
612 1.f
/ (_WorldToLocal
.y
* (float) PACKED_COL_RANGE
),
613 1.f
/ (_WorldToLocal
.z
* (float) PACKED_COL_RANGE
));
617 // used by CPackedZone::build
620 const CShapeInfo
*SI
;
624 // ***************************************************************************************
625 void CPackedZone32::build(std::vector
<const CTessFace
*> &leaves
,
627 std::vector
<CInstanceGroup
*> igs
,
628 const TShapeCache
&shapeCache
,
629 const NLMISC::CAABBox
&baseZoneBBox
,
634 nlassert(cellSize
> 0);
639 if (leaves
.empty()) return;
640 for(uint k
= 0; k
< leaves
.size(); ++k
)
644 Box
.setMinMax(leaves
[k
]->VBase
->EndPos
, leaves
[k
]->VBase
->EndPos
);
645 Box
.extend(leaves
[k
]->VLeft
->EndPos
);
646 Box
.extend(leaves
[k
]->VRight
->EndPos
);
650 Box
.extend(leaves
[k
]->VBase
->EndPos
);
651 Box
.extend(leaves
[k
]->VLeft
->EndPos
);
652 Box
.extend(leaves
[k
]->VRight
->EndPos
);
655 CAABBox landBBox
= Box
;
656 landBBox
.extend(baseZoneBBox
.getMin());
657 landBBox
.extend(baseZoneBBox
.getMax());
658 // list of instances that contribute to that zone
659 std::vector
<CZoneInstance
> instances
;
660 // extends with instances that intersect the land bbox with respect to x/y
661 for(uint k
= 0; k
< igs
.size(); ++k
)
663 if (!igs
[k
]) continue;
664 for(uint l
= 0; l
< igs
[k
]->getNumInstance(); ++l
)
666 CMatrix instanceMatrix
;
667 igs
[k
]->getInstanceMatrix(l
, instanceMatrix
);
668 if (NLMISC::toLowerAscii(NLMISC::CFile::getExtension(igs
[k
]->getShapeName(l
))) == "pacs_prim") continue;
669 std::string stdShapeName
= standardizeShapeName(igs
[k
]->getShapeName(l
));
670 TShapeCache::const_iterator it
= shapeCache
.find(stdShapeName
);
671 if (it
!= shapeCache
.end())
673 CAABBox xformBBox
= CAABBox::transformAABBox(instanceMatrix
, it
->second
.LocalBBox
);
674 if (xformBBox
.getMin().x
< landBBox
.getMax().x
&&
675 xformBBox
.getMin().y
< landBBox
.getMax().y
&&
676 xformBBox
.getMax().y
>= landBBox
.getMin().y
&&
677 xformBBox
.getMax().x
>= landBBox
.getMin().x
)
679 Box
.extend(xformBBox
.getMin());
680 Box
.extend(xformBBox
.getMax());
682 zi
.SI
= &(it
->second
);
683 zi
.WorldMat
= instanceMatrix
;
684 instances
.push_back(zi
);
691 Box.extend(Box.getMin() + CVector(- delta, - delta, - delta));
692 Box.extend(Box.getMax() + CVector(delta, delta, delta));*/
694 CVector cornerMin
= Box
.getMin();
695 CVector cornerMax
= Box
.getMax();
697 uint width
= (uint
) ceilf((cornerMax
.x
- cornerMin
.x
) / cellSize
);
698 uint height
= (uint
) ceilf((cornerMax
.y
- cornerMin
.y
) / cellSize
);
699 float depth
= cornerMax
.z
- cornerMin
.z
;
700 if (width
== 0 || height
== 0) return;
701 Grid
.init(width
, height
, UndefIndex
);
703 TVertexGrid vertexGrid
; // grid for fast sharing of vertices
704 TTriListGrid triListGrid
; // grid for list of tris per grid cell (before packing in a single vector)
705 vertexGrid
.init(width
, height
);
706 triListGrid
.init(width
, height
);
710 _WorldToLocal
.x
= 1.f
/ (width
* cellSize
);
711 _WorldToLocal
.y
= 1.f
/ (height
* cellSize
);
712 _WorldToLocal
.z
= depth
!= 0 ? 1.f
/ depth
: 0.f
;
714 for(uint k
= 0; k
< leaves
.size(); ++k
)
717 tri
.V0
= leaves
[k
]->VBase
->EndPos
;
718 tri
.V1
= leaves
[k
]->VLeft
->EndPos
;
719 tri
.V2
= leaves
[k
]->VRight
->EndPos
;
720 addTri(tri
, vertexGrid
, triListGrid
);
723 for(uint k
= 0; k
< instances
.size(); ++k
)
725 addInstance(*instances
[k
].SI
, instances
[k
].WorldMat
, vertexGrid
, triListGrid
);
728 for (uint y
= 0; y
< height
; ++y
)
730 for (uint x
= 0; x
< width
; ++x
)
732 if (!triListGrid(x
, y
).empty())
734 Grid(x
, y
) = (uint32
)TriLists
.size();
735 std::copy(triListGrid(x
, y
).begin(), triListGrid(x
, y
).end(), std::back_inserter(TriLists
));
736 TriLists
.push_back(UndefIndex
); // mark the end of the list
744 _PackedLocalToWorld
.set(1.f
/ (_WorldToLocal
.x
* (float) PACKED_COL_RANGE
),
745 1.f
/ (_WorldToLocal
.y
* (float) PACKED_COL_RANGE
),
746 1.f
/ (_WorldToLocal
.z
* (float) PACKED_COL_RANGE
));
747 // reorder vertices by distance for better compression : start with first vertex then found closest vertex
750 std::vector<uint32> triRemapping(Verts.size());
751 std::vector<uint32> vertRemapping(Verts.size());
752 std::vector<uint32> todo(Verts.size());
753 for(uint k = 0; k < Verts.size(); ++k)
757 CPackedVertex lastPos;
758 for(uint k = 0; k < Verts.size(); ++k)
760 // find vertex with closest dist
768 uint32 bestDist = INT_MAX;
769 for(uint l = 0; l < todo.size(); ++l)
771 uint32 dist = (uint32) abs((sint32) Verts[todo[l]].X - (sint32) lastPos.X)
772 + (uint32) abs((sint32) Verts[todo[l]].Y - (sint32) lastPos.Y)
773 + (uint32) abs((sint32) Verts[todo[l]].Z - (sint32) lastPos.Z);
781 lastPos = Verts[todo[best]];
782 vertRemapping[k] = todo[best];
783 triRemapping[todo[best]] = k;
784 todo[best] = todo[todo.size() - 1];
788 for(uint k = 0; k < Tris.size(); ++k)
790 Tris[k].V0 = triRemapping[Tris[k].V0];
791 Tris[k].V1 = triRemapping[Tris[k].V1];
792 Tris[k].V2 = triRemapping[Tris[k].V2];
795 std::vector<CPackedVertex> remappedVerts(Verts.size());
796 for(uint k = 0; k < Verts.size(); ++k)
798 remappedVerts[k] = Verts[vertRemapping[k]];
800 Verts.swap(remappedVerts);
801 /////////////////////////////////////////////////////////////////////
803 triRemapping.resize(Tris.size());
804 std::vector<uint32> triListRemapping(Tris.size());
806 todo.resize(Tris.size());
807 for(uint k = 0; k < Tris.size(); ++k)
811 uint32 lastIndex = 0;
812 for(uint k = 0; k < Tris.size(); ++k)
815 uint32 bestScore = INT_MAX;
816 for(uint l = 0; l < todo.size(); ++l)
818 uint32 score = abs(Tris[todo[l]].V0 - lastIndex) +
819 abs(Tris[todo[l]].V1 - Tris[todo[l]].V0) +
820 abs(Tris[todo[l]].V2 - Tris[todo[l]].V1);
821 if (score < bestScore)
827 lastIndex = Tris[todo[best]].V2;
828 triRemapping[k] = todo[best];
829 triListRemapping[todo[best]] = k;
830 todo[best] = todo[todo.size() - 1];
834 for(uint k = 0; k < TriLists.size(); ++k)
836 if (TriLists[k] != std::numeric_limits<uint32>::max())
838 TriLists[k] = triListRemapping[TriLists[k]];
842 std::vector<CPackedTri> remappedTris(Tris.size());
843 for(uint k = 0; k < Tris.size(); ++k)
845 remappedTris[k] = Tris[triRemapping[k]];
847 Tris.swap(remappedTris);
850 // reorder tri lists for better compression
851 std::vector
<uint32
>::iterator firstIt
= TriLists
.begin();
852 std::vector
<uint32
>::iterator currIt
= firstIt
;
853 std::vector
<uint32
>::iterator lastIt
= TriLists
.end();
855 while (currIt
!= lastIt
)
857 if (*currIt
== UndefIndex
)
859 std::sort(firstIt
, currIt
);
861 if (currIt
== lastIt
) break;
870 /*int vertsSize = sizeof(CPackedVertex) * Verts.size();
871 int trisSize = sizeof(CPackedTri) * Tris.size();
872 int triListSize = sizeof(uint32) * TriLists.size();
873 int gridSize = sizeof(uint32) * Grid.getWidth() * Grid.getHeight();
875 /*printf("Verts Size = %d\n", vertsSize);
876 printf("Tris Size = %d\n", trisSize);
877 printf("Tri List Size = %d\n", triListSize);
878 printf("Grid size = %d\n", gridSize);
879 printf("Total = %d\n", vertsSize + trisSize + triListSize + gridSize);*/
882 // ***************************************************************************************
883 void CPackedZone32::addTri(const CTriangle
&tri
, TVertexGrid
&vertexGrid
, TTriListGrid
&triListGrid
)
886 pt
.V0
= allocVertex(tri
.V0
, vertexGrid
);
887 pt
.V1
= allocVertex(tri
.V1
, vertexGrid
);
888 pt
.V2
= allocVertex(tri
.V2
, vertexGrid
);
891 static CPolygon2D::TRasterVect rasters
;
892 static CPolygon2D polyTri
;
894 polyTri
.Vertices
.resize(3);
896 polyTri
.Vertices
[0].set((tri
.V0
.x
- _Origin
.x
) / CellSize
, (tri
.V0
.y
- _Origin
.y
) / CellSize
);
897 polyTri
.Vertices
[1].set((tri
.V1
.x
- _Origin
.x
) / CellSize
, (tri
.V1
.y
- _Origin
.y
) / CellSize
);
898 polyTri
.Vertices
[2].set((tri
.V2
.x
- _Origin
.x
) / CellSize
, (tri
.V2
.y
- _Origin
.y
) / CellSize
);
900 polyTri
.computeOuterBorders(rasters
, minY
);
901 if (rasters
.empty()) return;
904 for (sint y
= 0; y
< (sint
) rasters
.size(); ++y
)
906 sint gridY
= y
+ minY
;
907 if (gridY
< 0) continue;
908 if (gridY
>= (sint
) triListGrid
.getHeight()) break;
909 for (sint x
= rasters
[y
].first
; x
<= rasters
[y
].second
; ++x
)
912 if (x
>= (sint
) triListGrid
.getWidth()) break;
913 triListGrid(x
, gridY
).push_back((uint32
)Tris
.size() - 1);
920 // ***************************************************************************************
921 uint32
CPackedZone32::allocVertex(const CVector
&src
, TVertexGrid
&vertexGrid
)
923 CVector
local((src
.x
- _Origin
.x
) * _WorldToLocal
.x
,
924 (src
.y
- _Origin
.y
) * _WorldToLocal
.y
,
925 (src
.z
- _Origin
.z
) * _WorldToLocal
.z
);
926 sint x
= (sint
) (local
.x
* vertexGrid
.getWidth());
927 sint y
= (sint
) (local
.y
* vertexGrid
.getHeight());
928 if (x
== (sint
) vertexGrid
.getWidth()) x
= (sint
) vertexGrid
.getWidth() - 1;
929 if (y
== (sint
) vertexGrid
.getHeight()) y
= (sint
) vertexGrid
.getHeight() - 1;
932 sint32 ix
= (sint32
) (local
.x
* PACKED_COL_RANGE
);
933 sint32 iy
= (sint32
) (local
.y
* PACKED_COL_RANGE
);
934 sint32 iz
= (sint32
) (local
.z
* PACKED_COL_RANGE
);
935 clamp(ix
, 0, PACKED_COL_RANGE
);
936 clamp(iy
, 0, PACKED_COL_RANGE
);
937 clamp(iz
, 0, PACKED_COL_RANGE
);
942 std::list
<uint32
> &vertList
= vertexGrid(x
, y
);
943 for(std::list
<uint32
>::iterator it
= vertexGrid(x
, y
).begin(); it
!= vertexGrid(x
, y
).end(); ++it
)
945 if (Verts
[*it
] == pv
) return *it
; // exists already
949 // create a new vertex
951 vertList
.push_front((uint32
)Verts
.size() - 1);
952 return (uint32
)Verts
.size() - 1;
955 // ***************************************************************************************
956 void CPackedZone32::render(CVertexBuffer
&vb
, IDriver
&drv
, CMaterial
&material
, CMaterial
&wiredMaterial
, const CMatrix
&camMat
, uint batchSize
, const CVector localFrustCorners
[8])
958 if (Tris
.empty()) return;
959 IDriver::TPolygonMode oldPolygonMode
= drv
.getPolygonMode();
961 CVector frustCorners
[8];
962 for(uint k
= 0; k
< sizeofarray(frustCorners
); ++k
)
964 frustCorners
[k
] = camMat
* localFrustCorners
[k
];
965 frustCorners
[k
].x
-= _Origin
.x
;
966 frustCorners
[k
].y
-= _Origin
.y
;
968 // project frustum on x/y plane to see where to test polys
970 static CPolygon2D::TRasterVect silhouette
;
972 addQuadToSilhouette(frustCorners
[0], frustCorners
[1], frustCorners
[2], frustCorners
[3], silhouette
, minY
, CellSize
);
973 addQuadToSilhouette(frustCorners
[1], frustCorners
[5], frustCorners
[6], frustCorners
[2], silhouette
, minY
, CellSize
);
974 addQuadToSilhouette(frustCorners
[4], frustCorners
[5], frustCorners
[6], frustCorners
[7], silhouette
, minY
, CellSize
);
975 addQuadToSilhouette(frustCorners
[0], frustCorners
[4], frustCorners
[7], frustCorners
[3], silhouette
, minY
, CellSize
);
976 addQuadToSilhouette(frustCorners
[0], frustCorners
[1], frustCorners
[5], frustCorners
[4], silhouette
, minY
, CellSize
);
977 addQuadToSilhouette(frustCorners
[3], frustCorners
[7], frustCorners
[6], frustCorners
[2], silhouette
, minY
, CellSize
);
980 CVertexBufferReadWrite vba
;
981 vb
.setNumVertices(batchSize
* 3);
983 CVector
*dest
= vba
.getVertexCoordPointer(0);
984 const CVector
*endDest
= dest
+ batchSize
* 3;
985 for(sint y
= 0; y
< (sint
) silhouette
.size(); ++y
)
987 sint gridY
= y
+ minY
;
988 if (gridY
< 0) continue;
989 if (gridY
>= (sint
) Grid
.getHeight()) continue;
990 sint minX
= silhouette
[y
].first
;
991 sint maxX
= silhouette
[y
].second
;
992 for (sint x
= minX
; x
<= maxX
; ++x
)
995 if (x
>= (sint
) Grid
.getWidth()) break;
996 uint32 triRefIndex
= Grid(x
, gridY
);
997 if (triRefIndex
== UndefIndex
) continue;
1000 uint32 triIndex
= TriLists
[triRefIndex
];
1001 if (triIndex
== UndefIndex
) break; // end of list
1002 unpackTri(Tris
[triIndex
], dest
);
1004 if (dest
== endDest
)
1008 drv
.setPolygonMode(IDriver::Filled
);
1009 drv
.activeVertexBuffer(vb
);
1010 drv
.renderRawTriangles(material
, 0, batchSize
);
1011 drv
.setPolygonMode(IDriver::Line
);
1012 //drv.renderRawTriangles(wiredMaterial, 0, batchSize);
1013 // reclaim a new batch
1014 vb
.setNumVertices(batchSize
* 3);
1016 dest
= vba
.getVertexCoordPointer(0);
1017 endDest
= dest
+ batchSize
* 3;
1024 uint numRemainingTris
= batchSize
- (uint
)((endDest
- dest
) / 3);
1025 if (numRemainingTris
)
1027 drv
.setPolygonMode(IDriver::Filled
);
1028 drv
.activeVertexBuffer(vb
);
1029 drv
.renderRawTriangles(material
, 0, numRemainingTris
);
1030 drv
.setPolygonMode(IDriver::Line
);
1031 //drv.renderRawTriangles(wiredMaterial, 0, numRemainingTris);
1034 drv
.setPolygonMode(oldPolygonMode
);
1037 // ***************************************************************************************
1038 void CPackedZone32::addInstance(const CShapeInfo
&si
, const NLMISC::CMatrix
&matrix
, TVertexGrid
&vertexGrid
, TTriListGrid
&triListGrid
)
1040 for(uint k
= 0; k
< si
.Tris
.size(); ++k
)
1043 si
.Tris
[k
].applyMatrix(matrix
, worldTri
);
1044 addTri(worldTri
, vertexGrid
, triListGrid
);
1048 // ***************************************************************************************
1049 CSmartPtr
<CPackedZone16
> CPackedZone32::buildPackedZone16()
1051 if (Verts
.size() > 65535) return NULL
;
1052 if (Tris
.size() > 65534) return NULL
; // NB : not 65534 here because -1 is used to mark the end of a list
1053 if (TriLists
.size() > 65534) return NULL
;
1055 CSmartPtr
<CPackedZone16
> dest
= new CPackedZone16
;
1057 dest
->Verts
= Verts
;
1058 dest
->Tris
.resize(Tris
.size());
1059 for(uint k
= 0; k
< Tris
.size(); ++k
)
1061 dest
->Tris
[k
].V0
= (uint16
) Tris
[k
].V0
;
1062 dest
->Tris
[k
].V1
= (uint16
) Tris
[k
].V1
;
1063 dest
->Tris
[k
].V2
= (uint16
) Tris
[k
].V2
;
1065 dest
->TriLists
.resize(TriLists
.size());
1066 for(uint k
= 0; k
< TriLists
.size(); ++k
)
1068 dest
->TriLists
[k
] = (uint16
) TriLists
[k
];
1070 dest
->CellSize
= CellSize
;
1071 dest
->Grid
.init(Grid
.getWidth(), Grid
.getHeight());
1072 for (sint y
= 0; y
< (sint
) Grid
.getHeight(); ++y
)
1074 for (sint x
= 0; x
< (sint
) Grid
.getWidth(); ++x
)
1076 dest
->Grid(x
, y
) = (uint16
) Grid(x
, y
);
1079 dest
->_Origin
= _Origin
;
1080 dest
->_WorldToLocal
= _WorldToLocal
;
1081 dest
->ZoneX
= ZoneX
;
1082 dest
->ZoneY
= ZoneY
;
1084 dest
->_PackedLocalToWorld
.set(1.f
/ (dest
->_WorldToLocal
.x
* (float) PACKED_COL_RANGE
),
1085 1.f
/ (dest
->_WorldToLocal
.y
* (float) PACKED_COL_RANGE
),
1086 1.f
/ (dest
->_WorldToLocal
.z
* (float) PACKED_COL_RANGE
));
1091 // ***************************************************************************************
1092 void CPackedZone16::serial(NLMISC::IStream
&f
)
1096 std::vector
<uint16
> datas
;
1100 serialPackedVector12(datas
, f
);
1101 Verts
.resize(datas
.size() / 3);
1102 for(uint k
= 0; k
< Verts
.size(); ++k
)
1104 Verts
[k
].X
= datas
[k
];
1105 Verts
[k
].Y
= datas
[Verts
.size() + k
];
1106 Verts
[k
].Z
= datas
[2 * Verts
.size() + k
];
1109 serialPackedVector16(datas
, f
);
1110 Tris
.resize(datas
.size() / 3);
1111 for(uint k
= 0; k
< Tris
.size(); ++k
)
1113 Tris
[k
].V0
= datas
[3 * k
];
1114 Tris
[k
].V1
= datas
[3 * k
+ 1];
1115 Tris
[k
].V2
= datas
[3 * k
+ 2];
1118 serialPackedVector16(TriLists
, f
);
1120 uint16 width
= (uint16
) Grid
.getWidth();
1121 uint16 height
= (uint16
) Grid
.getHeight();
1122 f
.serial(width
, height
);
1123 Grid
.init(width
, height
);
1124 serialPackedVector16(datas
, f
);
1125 if ((uint
) datas
.size() != (uint
) width
* (uint
) height
)
1127 throw NLMISC::EInvalidDataStream();
1129 std::copy(datas
.begin(), datas
.end(), Grid
.begin());
1134 datas
.resize(Verts
.size() * 3);
1135 for(uint k
= 0; k
< Verts
.size(); ++k
)
1137 datas
[k
] = Verts
[k
].X
;
1138 datas
[Verts
.size() + k
] = Verts
[k
].Y
;
1139 datas
[2 * Verts
.size() + k
] = Verts
[k
].Z
;
1141 //nlwarning("serial verts");
1142 serialPackedVector12(datas
, f
);
1144 datas
.resize(Tris
.size() * 3);
1145 for(uint k
= 0; k
< Tris
.size(); ++k
)
1147 datas
[3 * k
] = Tris
[k
].V0
;
1148 datas
[3 * k
+ 1] = Tris
[k
].V1
;
1149 datas
[3 * k
+ 2] = Tris
[k
].V2
;
1151 //nlwarning("serial tris");
1152 serialPackedVector16(datas
, f
);
1154 //nlwarning("serial tri lists");
1155 serialPackedVector16(TriLists
, f
);
1157 uint16 width
= (uint16
) Grid
.getWidth();
1158 uint16 height
= (uint16
) Grid
.getHeight();
1159 f
.serial(width
, height
);
1160 datas
.resize((uint
) width
* (uint
) height
);
1161 std::copy(Grid
.begin(), Grid
.end(), datas
.begin());
1162 //nlwarning("serial grid");
1163 serialPackedVector16(datas
, f
);
1167 f
.serial(_WorldToLocal
);
1173 _PackedLocalToWorld
.set(1.f
/ (_WorldToLocal
.x
* (float) PACKED_COL_RANGE
),
1174 1.f
/ (_WorldToLocal
.y
* (float) PACKED_COL_RANGE
),
1175 1.f
/ (_WorldToLocal
.z
* (float) PACKED_COL_RANGE
));
1179 // ***************************************************************************************
1180 void CPackedZone16::render(CVertexBuffer
&vb
, IDriver
&drv
, CMaterial
&material
, CMaterial
&wiredMaterial
, const CMatrix
&camMat
, uint batchSize
, const CVector localFrustCorners
[8])
1182 if (Tris
.empty()) return;
1183 IDriver::TPolygonMode oldPolygonMode
= drv
.getPolygonMode();
1184 CVector frustCorners
[8];
1185 for(uint k
= 0; k
< sizeofarray(frustCorners
); ++k
)
1187 frustCorners
[k
] = camMat
* localFrustCorners
[k
];
1188 frustCorners
[k
].x
-= _Origin
.x
;
1189 frustCorners
[k
].y
-= _Origin
.y
;
1191 // project frustum on x/y plane to see where to test polys
1192 sint minY
= INT_MAX
;
1193 static CPolygon2D::TRasterVect silhouette
;
1195 addQuadToSilhouette(frustCorners
[0], frustCorners
[1], frustCorners
[2], frustCorners
[3], silhouette
, minY
, CellSize
);
1196 addQuadToSilhouette(frustCorners
[1], frustCorners
[5], frustCorners
[6], frustCorners
[2], silhouette
, minY
, CellSize
);
1197 addQuadToSilhouette(frustCorners
[4], frustCorners
[5], frustCorners
[6], frustCorners
[7], silhouette
, minY
, CellSize
);
1198 addQuadToSilhouette(frustCorners
[0], frustCorners
[4], frustCorners
[7], frustCorners
[3], silhouette
, minY
, CellSize
);
1199 addQuadToSilhouette(frustCorners
[0], frustCorners
[1], frustCorners
[5], frustCorners
[4], silhouette
, minY
, CellSize
);
1200 addQuadToSilhouette(frustCorners
[3], frustCorners
[7], frustCorners
[6], frustCorners
[2], silhouette
, minY
, CellSize
);
1203 CVertexBufferReadWrite vba
;
1204 vb
.setNumVertices(batchSize
* 3);
1206 CVector
*dest
= vba
.getVertexCoordPointer(0);
1207 const CVector
*endDest
= dest
+ batchSize
* 3;
1208 for(sint y
= 0; y
< (sint
) silhouette
.size(); ++y
)
1210 sint gridY
= y
+ minY
;
1211 if (gridY
< 0) continue;
1212 if (gridY
>= (sint
) Grid
.getHeight()) continue;
1213 sint minX
= silhouette
[y
].first
;
1214 sint maxX
= silhouette
[y
].second
;
1215 for (sint x
= minX
; x
<= maxX
; ++x
)
1217 if (x
< 0) continue;
1218 if (x
>= (sint
) Grid
.getWidth()) break;
1219 uint32 triRefIndex
= Grid(x
, gridY
);
1220 if (triRefIndex
== UndefIndex
) continue;
1223 uint16 triIndex
= TriLists
[triRefIndex
];
1224 if (triIndex
== UndefIndex
) break; // end of list
1225 unpackTri(Tris
[triIndex
], dest
);
1227 if (dest
== endDest
)
1231 drv
.setPolygonMode(IDriver::Filled
);
1232 drv
.activeVertexBuffer(vb
);
1233 drv
.renderRawTriangles(material
, 0, batchSize
);
1234 drv
.setPolygonMode(IDriver::Line
);
1235 //drv.renderRawTriangles(wiredMaterial, 0, batchSize);
1236 // reclaim a new batch
1237 vb
.setNumVertices(batchSize
* 3);
1239 dest
= vba
.getVertexCoordPointer(0);
1240 endDest
= dest
+ batchSize
* 3;
1247 uint numRemainingTris
= batchSize
- (uint
)((endDest
- dest
) / 3);
1248 if (numRemainingTris
)
1250 drv
.setPolygonMode(IDriver::Filled
);
1251 drv
.activeVertexBuffer(vb
);
1252 drv
.renderRawTriangles(material
, 0, numRemainingTris
);
1253 drv
.setPolygonMode(IDriver::Line
);
1254 //drv.renderRawTriangles(wiredMaterial, 0, numRemainingTris);
1257 drv
.setPolygonMode(oldPolygonMode
);
1264 // ***************************************************************************************
1265 void CPackedZone16::unpackTri(const CPackedTri16
&src
, CVector dest
[3]) const
1267 // yes this is ugly code duplication of CPackedZone16::unpackTri but this code is temporary anyway...
1268 // TODO: add 'multiply-add' operator
1269 dest
[0].set(Verts
[src
.V0
].X
* _PackedLocalToWorld
.x
+ _Origin
.x
,
1270 Verts
[src
.V0
].Y
* _PackedLocalToWorld
.y
+ _Origin
.y
,
1271 Verts
[src
.V0
].Z
* _PackedLocalToWorld
.z
+ _Origin
.z
);
1272 dest
[1].set(Verts
[src
.V1
].X
* _PackedLocalToWorld
.x
+ _Origin
.x
,
1273 Verts
[src
.V1
].Y
* _PackedLocalToWorld
.y
+ _Origin
.y
,
1274 Verts
[src
.V1
].Z
* _PackedLocalToWorld
.z
+ _Origin
.z
);
1275 dest
[2].set(Verts
[src
.V2
].X
* _PackedLocalToWorld
.x
+ _Origin
.x
,
1276 Verts
[src
.V2
].Y
* _PackedLocalToWorld
.y
+ _Origin
.y
,
1277 Verts
[src
.V2
].Z
* _PackedLocalToWorld
.z
+ _Origin
.z
);
1281 // raytrace code, common to CPackedZone32 & CPackedZone16
1282 template <class T
> bool raytrace(T
&packedZone
, const NLMISC::CVector
&start
, const NLMISC::CVector
&end
, NLMISC::CVector
&inter
, std::vector
<CTriangle
> *testedTriangles
= NULL
, NLMISC::CVector
*normal
= NULL
)
1284 if (packedZone
.Grid
.empty()) return false;
1285 CVector2f
start2f((start
.x
- packedZone
.Box
.getMin().x
) / packedZone
.CellSize
, (start
.y
- packedZone
.Box
.getMin().y
) / packedZone
.CellSize
);
1286 CVector2f
dir2f((end
.x
- start
.x
) / packedZone
.CellSize
, (end
.y
- start
.y
) / packedZone
.CellSize
);
1288 CGridTraversal::startTraverse(start2f
, x
, y
);
1291 if (x
< 0) continue;
1292 if (x
>= (sint
) packedZone
.Grid
.getWidth()) continue;
1293 if (y
< 0) continue;
1294 if (y
>= (sint
) packedZone
.Grid
.getHeight()) continue;
1295 typename
T::TIndexType triListIndex
= packedZone
.Grid(x
, y
);
1296 if (triListIndex
!= T::UndefIndex
)
1300 float bestInterDist
= FLT_MAX
;
1301 CVector
bestNormal(0.f
, 0.f
, 0.f
);
1305 packedZone
.unpackTri(packedZone
.Tris
[packedZone
.TriLists
[triListIndex
]], &tri
.V0
);
1306 if (testedTriangles
)
1308 testedTriangles
->push_back(tri
);
1310 triPlane
.make(tri
.V0
, tri
.V1
, tri
.V2
);
1311 if (tri
.intersect(start
, end
, currInter
, triPlane
))
1313 float dist
= (currInter
- start
).norm();
1314 if (dist
< bestInterDist
)
1316 bestInterDist
= dist
;
1318 bestNormal
.set(triPlane
.a
, triPlane
.b
, triPlane
.c
);
1323 while (packedZone
.TriLists
[triListIndex
] != T::UndefIndex
);
1324 if (bestInterDist
!= FLT_MAX
)
1328 *normal
= bestNormal
.normed();
1334 while(CGridTraversal::traverse(start2f
, dir2f
, x
, y
));
1338 // ***************************************************************************************
1339 bool CPackedZone32::raytrace(const NLMISC::CVector
&start
, const NLMISC::CVector
&end
, NLMISC::CVector
&inter
, std::vector
<CTriangle
> *testedTriangles
/*= NULL*/, NLMISC::CVector
*normal
/*= NULL*/) const
1341 return NL3D::raytrace(*this, start
, end
, inter
, testedTriangles
, normal
);
1344 // ***************************************************************************************
1345 bool CPackedZone16::raytrace(const NLMISC::CVector
&start
, const NLMISC::CVector
&end
, NLMISC::CVector
&inter
, std::vector
<CTriangle
> *testedTriangles
/*= NULL*/, NLMISC::CVector
*normal
/*= NULL*/) const
1347 return NL3D::raytrace(*this, start
, end
, inter
, testedTriangles
, normal
);
1350 // ***************************************************************************************
1351 void CPackedZone16::appendSelection(const NLMISC::CPolygon2D
&poly
, std::vector
<NLMISC::CTriangle
> &selectedTriangles
) const
1353 // compute covered zones
1354 NLMISC::CPolygon2D localPoly
= poly
;
1355 for (uint k
= 0; k
< localPoly
.Vertices
.size(); ++k
)
1357 localPoly
.Vertices
[k
].x
= (localPoly
.Vertices
[k
].x
- Box
.getMin().x
) / CellSize
;
1358 localPoly
.Vertices
[k
].y
= (localPoly
.Vertices
[k
].y
- Box
.getMin().y
) / CellSize
;
1360 NLMISC::CPolygon2D::TRasterVect borders
;
1362 localPoly
.computeOuterBorders(borders
, minY
);
1365 std::vector
<bool> done(Tris
.size(), false); // avoid double insertion
1367 for (sint y
= minY
; y
< (sint
) (minY
+ borders
.size()); ++y
)
1369 if (y
< 0 || y
>= (sint
) Grid
.getHeight()) continue;
1370 for (sint x
= borders
[y
- minY
].first
; x
<= borders
[y
- minY
].second
; ++x
)
1372 if (x
< 0 || x
>= (sint
) Grid
.getWidth()) continue;
1374 if (Grid(x
, y
) != UndefIndex
)
1376 uint16 currTriIndex
= Grid(x
, y
);
1377 while (TriLists
[currTriIndex
] != UndefIndex
)
1379 if (!done
[TriLists
[currTriIndex
]])
1381 unpackTri(Tris
[TriLists
[currTriIndex
]], &newTri
.V0
);
1382 selectedTriangles
.push_back(newTri
);
1383 done
[TriLists
[currTriIndex
]] = true;
1393 // ***************************************************************************************
1394 void CPackedZone32::appendSelection(const NLMISC::CPolygon2D
&poly
, std::vector
<NLMISC::CTriangle
> &selectedTriangles
) const
1396 // TODO nico : factorize with CPackedZone16::appendSelection
1397 selectedTriangles
.clear();
1398 // compute covered zones
1399 NLMISC::CPolygon2D localPoly
= poly
;
1400 for (uint k
= 0; k
< localPoly
.Vertices
.size(); ++k
)
1402 localPoly
.Vertices
[k
].x
= (localPoly
.Vertices
[k
].x
- Box
.getMin().x
) / CellSize
;
1403 localPoly
.Vertices
[k
].y
= (localPoly
.Vertices
[k
].y
- Box
.getMin().y
) / CellSize
;
1405 NLMISC::CPolygon2D::TRasterVect borders
;
1407 localPoly
.computeOuterBorders(borders
, minY
);
1410 std::vector
<bool> done(Tris
.size(), false); // avoid double insertion
1412 for (sint y
= minY
; y
< (sint
) (minY
+ borders
.size()); ++y
)
1414 if (y
< 0 || y
>= (sint
) Grid
.getHeight()) continue;
1415 for (sint x
= borders
[y
- minY
].first
; x
<= borders
[y
- minY
].second
; ++x
)
1417 if (x
< 0 || x
>= (sint
) Grid
.getWidth()) continue;
1419 if (Grid(x
, y
) != UndefIndex
)
1421 uint32 currTriIndex
= Grid(x
, y
);
1422 while (TriLists
[currTriIndex
] != UndefIndex
)
1424 if (!done
[TriLists
[currTriIndex
]])
1426 unpackTri(Tris
[TriLists
[currTriIndex
]], &newTri
.V0
);
1427 selectedTriangles
.push_back(newTri
);
1428 done
[TriLists
[currTriIndex
]] = true;