1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
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/>.
19 #include "nel/3d/packed_world.h"
21 #include "nel/misc/grid_traversal.h"
24 using namespace NLMISC
;
34 // *************************************************************************************************
35 void CPackedWorld::build(std::vector
<TPackedZoneBaseSPtr
> &packedZones
)
39 if (packedZones
.empty()) return;
41 nlassert(packedZones
[0]);
42 box
= packedZones
[0]->Box
;
43 for(uint k
= 1; k
< packedZones
.size(); ++k
)
45 nlassert(packedZones
[k
]);
46 box
.extend(packedZones
[k
]->Box
.getMin());
47 box
.extend(packedZones
[k
]->Box
.getMax());
50 _ZoneMinX
= (sint32
) floorf(box
.getMin().x
/ 160.f
);
51 _ZoneMinY
= (sint32
) floorf(box
.getMin().y
/ 160.f
);
53 sint32 zoneMaxX
= (sint32
) floorf(box
.getMax().x
/ 160.f
);
54 sint32 zoneMaxY
= (sint32
) floorf(box
.getMax().y
/ 160.f
);
56 _ZoneGrid
.init(zoneMaxX
- _ZoneMinX
+ 1, zoneMaxY
- _ZoneMinY
+ 1);
57 _Zones
.resize(packedZones
.size());
59 for(uint k
= 0; k
< packedZones
.size(); ++k
)
62 zi
.Zone
= packedZones
[k
];
63 zi
.RaytraceCounter
= 0;
65 sint zoneMinX
= (sint
) floorf(packedZones
[k
]->Box
.getMin().x
/ 160.f
) - (sint
) _ZoneMinX
;
66 sint zoneMinY
= (sint
) floorf(packedZones
[k
]->Box
.getMin().y
/ 160.f
) - (sint
) _ZoneMinY
;
67 sint zoneMaxX
= (sint
) floorf(packedZones
[k
]->Box
.getMax().x
/ 160.f
) - (sint
) _ZoneMinX
;
68 sint zoneMaxY
= (sint
) floorf(packedZones
[k
]->Box
.getMax().y
/ 160.f
) - (sint
) _ZoneMinY
;
69 for (sint y
= zoneMinY
; y
<= zoneMaxY
; ++y
)
72 if (y
>= (sint
) _ZoneGrid
.getHeight()) break;
73 for (sint x
= zoneMinX
; x
<= zoneMaxX
; ++x
)
76 if (x
>= (sint
) _ZoneGrid
.getWidth()) break;
77 _ZoneGrid(x
, y
).IDs
.push_back((uint32
) k
);
81 _RaytraceCounter
= std::numeric_limits
<uint32
>::max();
84 // *************************************************************************************************
85 bool CPackedWorld::raytrace(const NLMISC::CVector
&start
, const NLMISC::CVector
&end
, CVector
&inter
, std::vector
<NLMISC::CTriangle
> *testedTriangles
/*= NULL*/, NLMISC::CVector
*normal
)
87 if (_ZoneGrid
.empty()) return false;
89 float bestDist
= FLT_MAX
;
90 CVector
bestNormal(CVector::Null
);
91 CVector currEnd
= end
;
93 if (_RaytraceCounter
== std::numeric_limits
<uint32
>::max())
95 for(uint k
= 0; k
< _Zones
.size(); ++k
)
97 _Zones
[k
].RaytraceCounter
= 0;
101 CVector2f
start2f(start
.x
/ 160.f
, start
.y
/ 160.f
);
102 CVector2f
dir2f((end
.x
- start
.x
) / 160.f
, (end
.y
- start
.y
) / 160.f
);
103 CGridTraversal::startTraverse(start2f
, currX
, currY
);
106 sint x
= currX
- (sint
) _ZoneMinX
;
107 sint y
= currY
- (sint
) _ZoneMinY
;
110 if (x
>= (sint
) _ZoneGrid
.getWidth()) continue;
111 if (y
>= (sint
) _ZoneGrid
.getHeight()) continue;
112 std::vector
<uint32
> &currZoneList
= _ZoneGrid(x
, y
).IDs
;
113 for(uint k
= 0; k
< currZoneList
.size(); ++k
)
115 if (_Zones
[currZoneList
[k
]].RaytraceCounter
!= _RaytraceCounter
) // already visited
117 NLMISC::CVector normalTmp
;
118 if (_Zones
[currZoneList
[k
]].Zone
->raytrace(start
, currEnd
, currInter
, testedTriangles
, &normalTmp
))
120 float dist
= (currInter
- start
).norm();
123 bestNormal
= normalTmp
;
126 currEnd
= currInter
; // during search, just seek hit that are nearest
129 _Zones
[currZoneList
[k
]].RaytraceCounter
= _RaytraceCounter
;
132 if (bestDist
!= FLT_MAX
)
136 *normal
= bestNormal
;
141 while (CGridTraversal::traverse(start2f
, dir2f
, currX
, currY
));
145 // *************************************************************************************************
146 void CPackedWorld::getZones(std::vector
<TPackedZoneBaseSPtr
> &zones
)
149 for(uint k
= 0; k
< _Zones
.size(); ++k
)
151 zones
.push_back(_Zones
[k
].Zone
);
155 // *************************************************************************************************
156 void CPackedWorld::serialZoneNames(NLMISC::IStream
&f
)
159 f
.serialCheck(NELID("OWPA"));
160 f
.serialCont(ZoneNames
);
163 // *************************************************************************************************
164 void CPackedWorld::serial(NLMISC::IStream
&f
)
167 f
.serialCont(_Zones
);
173 // *************************************************************************************************
174 void CPackedWorld::select(const NLMISC::CPolygon2D
&poly
, std::vector
<NLMISC::CTriangle
> &selectedTriangles
) const
176 selectedTriangles
.clear();
177 // compute covered zones
178 NLMISC::CPolygon2D zonePoly
= poly
;
179 for (uint k
= 0; k
< zonePoly
.Vertices
.size(); ++k
)
181 zonePoly
.Vertices
[k
].x
= zonePoly
.Vertices
[k
].x
/ 160.f
- (float) _ZoneMinX
;
182 zonePoly
.Vertices
[k
].y
= zonePoly
.Vertices
[k
].y
/ 160.f
- (float) _ZoneMinY
;
184 NLMISC::CPolygon2D::TRasterVect borders
;
186 zonePoly
.computeOuterBorders(borders
, minY
);
187 for (sint y
= minY
; y
< (sint
) (minY
+ borders
.size()); ++y
)
189 if (y
< 0 || y
>= (sint
) _ZoneGrid
.getHeight()) continue;
190 for (sint x
= borders
[y
- minY
].first
; x
<= borders
[y
- minY
].second
; ++x
)
192 if (x
< 0 || x
>= (sint
) _ZoneGrid
.getWidth()) continue;
194 const CZoneIndexList
&zil
= _ZoneGrid(x
, y
);
195 for (uint k
= 0; k
< zil
.IDs
.size(); ++k
)
197 _Zones
[zil
.IDs
[k
]].Zone
->appendSelection(poly
, selectedTriangles
);