Legends-of-Azeroth-Pandaria-5.4.8
309 строк · 11.5 Кб
1/*
2* This file is part of the Pandaria 5.4.8 Project. See THANKS file for Copyright information
3*
4* This program is free software; you can redistribute it and/or modify it
5* under the terms of the GNU General Public License as published by the
6* Free Software Foundation; either version 2 of the License, or (at your
7* option) any later version.
8*
9* This program is distributed in the hope that it will be useful, but WITHOUT
10* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12* more details.
13*
14* You should have received a copy of the GNU General Public License along
15* with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#include "BoundingIntervalHierarchy.h"
19
20#ifdef _MSC_VER
21#define isnan _isnan
22#else
23#define isnan std::isnan
24#endif
25
26void BIH::buildHierarchy(std::vector<uint32> &tempTree, buildData &dat, BuildStats &stats)
27{
28// create space for the first node
29tempTree.push_back(uint32(3 << 30)); // dummy leaf
30tempTree.insert(tempTree.end(), 2, 0);
31//tempTree.add(0);
32
33// seed bbox
34AABound gridBox = { bounds.low(), bounds.high() };
35AABound nodeBox = gridBox;
36// seed subdivide function
37subdivide(0, dat.numPrims - 1, tempTree, dat, gridBox, nodeBox, 0, 1, stats);
38}
39
40void BIH::subdivide(int left, int right, std::vector<uint32> &tempTree, buildData &dat, AABound &gridBox, AABound &nodeBox, int nodeIndex, int depth, BuildStats &stats)
41{
42if ((right - left + 1) <= dat.maxPrims || depth >= MAX_STACK_SIZE)
43{
44// write leaf node
45stats.updateLeaf(depth, right - left + 1);
46createNode(tempTree, nodeIndex, left, right);
47return;
48}
49// calculate extents
50int axis = -1, prevAxis, rightOrig;
51float clipL = G3D::fnan(), clipR = G3D::fnan(), prevClip = G3D::fnan();
52float split = G3D::fnan(), prevSplit;
53bool wasLeft = true;
54while (true)
55{
56prevAxis = axis;
57prevSplit = split;
58// perform quick consistency checks
59G3D::Vector3 d( gridBox.hi - gridBox.lo );
60if (d.x < 0 || d.y < 0 || d.z < 0)
61throw std::logic_error("negative node extents");
62for (int i = 0; i < 3; i++)
63{
64if (nodeBox.hi[i] < gridBox.lo[i] || nodeBox.lo[i] > gridBox.hi[i])
65{
66//UI.printError(Module.ACCEL, "Reached tree area in error - discarding node with: %d objects", right - left + 1);
67throw std::logic_error("invalid node overlap");
68}
69}
70// find longest axis
71axis = d.primaryAxis();
72split = 0.5f * (gridBox.lo[axis] + gridBox.hi[axis]);
73// partition L/R subsets
74clipL = -G3D::inf();
75clipR = G3D::inf();
76rightOrig = right; // save this for later
77float nodeL = G3D::inf();
78float nodeR = -G3D::inf();
79for (int i = left; i <= right;)
80{
81int obj = dat.indices[i];
82float minb = dat.primBound[obj].low()[axis];
83float maxb = dat.primBound[obj].high()[axis];
84float center = (minb + maxb) * 0.5f;
85if (center <= split)
86{
87// stay left
88i++;
89if (clipL < maxb)
90clipL = maxb;
91}
92else
93{
94// move to the right most
95int t = dat.indices[i];
96dat.indices[i] = dat.indices[right];
97dat.indices[right] = t;
98right--;
99if (clipR > minb)
100clipR = minb;
101}
102nodeL = std::min(nodeL, minb);
103nodeR = std::max(nodeR, maxb);
104}
105// check for empty space
106if (nodeL > nodeBox.lo[axis] && nodeR < nodeBox.hi[axis])
107{
108float nodeBoxW = nodeBox.hi[axis] - nodeBox.lo[axis];
109float nodeNewW = nodeR - nodeL;
110// node box is too big compare to space occupied by primitives?
111if (1.3f * nodeNewW < nodeBoxW)
112{
113stats.updateBVH2();
114int nextIndex = tempTree.size();
115// allocate child
116tempTree.push_back(0);
117tempTree.push_back(0);
118tempTree.push_back(0);
119// write bvh2 clip node
120stats.updateInner();
121tempTree[nodeIndex + 0] = (axis << 30) | (1 << 29) | nextIndex;
122tempTree[nodeIndex + 1] = floatToRawIntBits(nodeL);
123tempTree[nodeIndex + 2] = floatToRawIntBits(nodeR);
124// update nodebox and recurse
125nodeBox.lo[axis] = nodeL;
126nodeBox.hi[axis] = nodeR;
127subdivide(left, rightOrig, tempTree, dat, gridBox, nodeBox, nextIndex, depth + 1, stats);
128return;
129}
130}
131// ensure we are making progress in the subdivision
132if (right == rightOrig)
133{
134// all left
135if (prevAxis == axis && G3D::fuzzyEq(prevSplit, split)) {
136// we are stuck here - create a leaf
137stats.updateLeaf(depth, right - left + 1);
138createNode(tempTree, nodeIndex, left, right);
139return;
140}
141if (clipL <= split) {
142// keep looping on left half
143gridBox.hi[axis] = split;
144prevClip = clipL;
145wasLeft = true;
146continue;
147}
148gridBox.hi[axis] = split;
149prevClip = G3D::fnan();
150}
151else if (left > right)
152{
153// all right
154right = rightOrig;
155if (prevAxis == axis && G3D::fuzzyEq(prevSplit, split)) {
156// we are stuck here - create a leaf
157stats.updateLeaf(depth, right - left + 1);
158createNode(tempTree, nodeIndex, left, right);
159return;
160}
161if (clipR >= split) {
162// keep looping on right half
163gridBox.lo[axis] = split;
164prevClip = clipR;
165wasLeft = false;
166continue;
167}
168gridBox.lo[axis] = split;
169prevClip = G3D::fnan();
170}
171else
172{
173// we are actually splitting stuff
174if (prevAxis != -1 && !isnan(prevClip))
175{
176// second time through - lets create the previous split
177// since it produced empty space
178int nextIndex = tempTree.size();
179// allocate child node
180tempTree.push_back(0);
181tempTree.push_back(0);
182tempTree.push_back(0);
183if (wasLeft) {
184// create a node with a left child
185// write leaf node
186stats.updateInner();
187tempTree[nodeIndex + 0] = (prevAxis << 30) | nextIndex;
188tempTree[nodeIndex + 1] = floatToRawIntBits(prevClip);
189tempTree[nodeIndex + 2] = floatToRawIntBits(G3D::inf());
190} else {
191// create a node with a right child
192// write leaf node
193stats.updateInner();
194tempTree[nodeIndex + 0] = (prevAxis << 30) | (nextIndex - 3);
195tempTree[nodeIndex + 1] = floatToRawIntBits(-G3D::inf());
196tempTree[nodeIndex + 2] = floatToRawIntBits(prevClip);
197}
198// count stats for the unused leaf
199depth++;
200stats.updateLeaf(depth, 0);
201// now we keep going as we are, with a new nodeIndex:
202nodeIndex = nextIndex;
203}
204break;
205}
206}
207// compute index of child nodes
208int nextIndex = tempTree.size();
209// allocate left node
210int nl = right - left + 1;
211int nr = rightOrig - (right + 1) + 1;
212if (nl > 0) {
213tempTree.push_back(0);
214tempTree.push_back(0);
215tempTree.push_back(0);
216} else
217nextIndex -= 3;
218// allocate right node
219if (nr > 0) {
220tempTree.push_back(0);
221tempTree.push_back(0);
222tempTree.push_back(0);
223}
224// write leaf node
225stats.updateInner();
226tempTree[nodeIndex + 0] = (axis << 30) | nextIndex;
227tempTree[nodeIndex + 1] = floatToRawIntBits(clipL);
228tempTree[nodeIndex + 2] = floatToRawIntBits(clipR);
229// prepare L/R child boxes
230AABound gridBoxL(gridBox), gridBoxR(gridBox);
231AABound nodeBoxL(nodeBox), nodeBoxR(nodeBox);
232gridBoxL.hi[axis] = gridBoxR.lo[axis] = split;
233nodeBoxL.hi[axis] = clipL;
234nodeBoxR.lo[axis] = clipR;
235// recurse
236if (nl > 0)
237subdivide(left, right, tempTree, dat, gridBoxL, nodeBoxL, nextIndex, depth + 1, stats);
238else
239stats.updateLeaf(depth + 1, 0);
240if (nr > 0)
241subdivide(right + 1, rightOrig, tempTree, dat, gridBoxR, nodeBoxR, nextIndex + 3, depth + 1, stats);
242else
243stats.updateLeaf(depth + 1, 0);
244}
245
246bool BIH::writeToFile(FILE* wf) const
247{
248uint32 treeSize = tree.size();
249uint32 check=0, count;
250check += fwrite(&bounds.low(), sizeof(float), 3, wf);
251check += fwrite(&bounds.high(), sizeof(float), 3, wf);
252check += fwrite(&treeSize, sizeof(uint32), 1, wf);
253check += fwrite(&tree[0], sizeof(uint32), treeSize, wf);
254count = objects.size();
255check += fwrite(&count, sizeof(uint32), 1, wf);
256check += fwrite(&objects[0], sizeof(uint32), count, wf);
257return check == (3 + 3 + 2 + treeSize + count);
258}
259
260bool BIH::readFromFile(FILE* rf)
261{
262uint32 treeSize;
263G3D::Vector3 lo, hi;
264uint32 check=0, count=0;
265check += fread(&lo, sizeof(float), 3, rf);
266check += fread(&hi, sizeof(float), 3, rf);
267bounds = G3D::AABox(lo, hi);
268check += fread(&treeSize, sizeof(uint32), 1, rf);
269tree.resize(treeSize);
270check += fread(&tree[0], sizeof(uint32), treeSize, rf);
271check += fread(&count, sizeof(uint32), 1, rf);
272objects.resize(count); // = new uint32[nObjects];
273check += fread(&objects[0], sizeof(uint32), count, rf);
274return uint64(check) == uint64(3 + 3 + 1 + 1 + uint64(treeSize) + uint64(count));
275}
276
277void BIH::BuildStats::updateLeaf(int depth, int n)
278{
279numLeaves++;
280minDepth = std::min(depth, minDepth);
281maxDepth = std::max(depth, maxDepth);
282sumDepth += depth;
283minObjects = std::min(n, minObjects);
284maxObjects = std::max(n, maxObjects);
285sumObjects += n;
286int nl = std::min(n, 5);
287++numLeavesN[nl];
288}
289
290void BIH::BuildStats::printStats()
291{
292printf("Tree stats:\n");
293printf(" * Nodes: %d\n", numNodes);
294printf(" * Leaves: %d\n", numLeaves);
295printf(" * Objects: min %d\n", minObjects);
296printf(" avg %.2f\n", (float) sumObjects / numLeaves);
297printf(" avg(n>0) %.2f\n", (float) sumObjects / (numLeaves - numLeavesN[0]));
298printf(" max %d\n", maxObjects);
299printf(" * Depth: min %d\n", minDepth);
300printf(" avg %.2f\n", (float) sumDepth / numLeaves);
301printf(" max %d\n", maxDepth);
302printf(" * Leaves w/: N=0 %3d%%\n", 100 * numLeavesN[0] / numLeaves);
303printf(" N=1 %3d%%\n", 100 * numLeavesN[1] / numLeaves);
304printf(" N=2 %3d%%\n", 100 * numLeavesN[2] / numLeaves);
305printf(" N=3 %3d%%\n", 100 * numLeavesN[3] / numLeaves);
306printf(" N=4 %3d%%\n", 100 * numLeavesN[4] / numLeaves);
307printf(" N>4 %3d%%\n", 100 * numLeavesN[5] / numLeaves);
308printf(" * BVH2 nodes: %d (%3d%%)\n", numBVH2, 100 * numBVH2 / (numNodes + numLeaves - 2 * numBVH2));
309}
310