PageRenderTime 42ms CodeModel.GetById 13ms app.highlight 25ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llmath/llvolumeoctree.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 256 lines | 171 code | 50 blank | 35 comment | 24 complexity | 445b2a5470c559fd5afcd02590f697c0 MD5 | raw file
  1/** 
  2
  3 * @file llvolumeoctree.cpp
  4 *
  5 * $LicenseInfo:firstyear=2002&license=viewerlgpl$
  6 * Second Life Viewer Source Code
  7 * Copyright (C) 2010, Linden Research, Inc.
  8 * 
  9 * This library is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU Lesser General Public
 11 * License as published by the Free Software Foundation;
 12 * version 2.1 of the License only.
 13 * 
 14 * This library is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17 * Lesser General Public License for more details.
 18 * 
 19 * You should have received a copy of the GNU Lesser General Public
 20 * License along with this library; if not, write to the Free Software
 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 22 * 
 23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 24 * $/LicenseInfo$
 25 */
 26
 27#include "llvolumeoctree.h"
 28#include "llvector4a.h"
 29
 30BOOL LLLineSegmentBoxIntersect(const LLVector4a& start, const LLVector4a& end, const LLVector4a& center, const LLVector4a& size)
 31{
 32	LLVector4a fAWdU;
 33	LLVector4a dir;
 34	LLVector4a diff;
 35
 36	dir.setSub(end, start);
 37	dir.mul(0.5f);
 38
 39	diff.setAdd(end,start);
 40	diff.mul(0.5f);
 41	diff.sub(center);
 42	fAWdU.setAbs(dir); 
 43
 44	LLVector4a rhs;
 45	rhs.setAdd(size, fAWdU);
 46
 47	LLVector4a lhs;
 48	lhs.setAbs(diff);
 49
 50	U32 grt = lhs.greaterThan(rhs).getGatheredBits();
 51
 52	if (grt & 0x7)
 53	{
 54		return false;
 55	}
 56	
 57	LLVector4a f;
 58	f.setCross3(dir, diff);
 59	f.setAbs(f);
 60
 61	LLVector4a v0, v1;
 62
 63	v0 = _mm_shuffle_ps(size, size,_MM_SHUFFLE(3,0,0,1));
 64	v1 = _mm_shuffle_ps(fAWdU, fAWdU, _MM_SHUFFLE(3,1,2,2));
 65	lhs.setMul(v0, v1);
 66
 67	v0 = _mm_shuffle_ps(size, size, _MM_SHUFFLE(3,1,2,2));
 68	v1 = _mm_shuffle_ps(fAWdU, fAWdU, _MM_SHUFFLE(3,0,0,1));
 69	rhs.setMul(v0, v1);
 70	rhs.add(lhs);
 71	
 72	grt = f.greaterThan(rhs).getGatheredBits();
 73
 74	return (grt & 0x7) ? false : true;
 75}
 76
 77
 78LLVolumeOctreeListener::LLVolumeOctreeListener(LLOctreeNode<LLVolumeTriangle>* node)
 79{
 80	node->addListener(this);
 81}
 82
 83LLVolumeOctreeListener::~LLVolumeOctreeListener()
 84{
 85
 86}
 87	
 88void LLVolumeOctreeListener::handleChildAddition(const LLOctreeNode<LLVolumeTriangle>* parent, 
 89	LLOctreeNode<LLVolumeTriangle>* child)
 90{
 91	new LLVolumeOctreeListener(child);
 92}
 93
 94
 95LLOctreeTriangleRayIntersect::LLOctreeTriangleRayIntersect(const LLVector4a& start, const LLVector4a& dir, 
 96							   const LLVolumeFace* face, F32* closest_t,
 97							   LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal)
 98   : mFace(face),
 99     mStart(start),
100	 mDir(dir),
101	 mIntersection(intersection),
102	 mTexCoord(tex_coord),
103	 mNormal(normal),
104	 mBinormal(bi_normal),
105	 mClosestT(closest_t),
106	 mHitFace(false)
107{
108	mEnd.setAdd(mStart, mDir);
109}
110
111void LLOctreeTriangleRayIntersect::traverse(const LLOctreeNode<LLVolumeTriangle>* node)
112{
113	LLVolumeOctreeListener* vl = (LLVolumeOctreeListener*) node->getListener(0);
114
115	/*const F32* start = mStart.getF32();
116	const F32* end = mEnd.getF32();
117	const F32* center = vl->mBounds[0].getF32();
118	const F32* size = vl->mBounds[1].getF32();*/
119
120	//if (LLLineSegmentBoxIntersect(mStart, mEnd, vl->mBounds[0], vl->mBounds[1]))
121	if (LLLineSegmentBoxIntersect(mStart.getF32ptr(), mEnd.getF32ptr(), vl->mBounds[0].getF32ptr(), vl->mBounds[1].getF32ptr()))
122	{
123		node->accept(this);
124		for (S32 i = 0; i < node->getChildCount(); ++i)
125		{
126			traverse(node->getChild(i));
127		}
128	}
129}
130
131void LLOctreeTriangleRayIntersect::visit(const LLOctreeNode<LLVolumeTriangle>* node)
132{
133	for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter = 
134			node->getData().begin(); iter != node->getData().end(); ++iter)
135	{
136		const LLVolumeTriangle* tri = *iter;
137
138		F32 a, b, t;
139		
140		if (LLTriangleRayIntersect(*tri->mV[0], *tri->mV[1], *tri->mV[2],
141				mStart, mDir, a, b, t))
142		{
143			if ((t >= 0.f) &&      // if hit is after start
144				(t <= 1.f) &&      // and before end
145				(t < *mClosestT))   // and this hit is closer
146			{
147				*mClosestT = t;
148				mHitFace = true;
149
150				if (mIntersection != NULL)
151				{
152					LLVector4a intersect = mDir;
153					intersect.mul(*mClosestT);
154					intersect.add(mStart);
155					mIntersection->set(intersect.getF32ptr());
156				}
157
158
159				if (mTexCoord != NULL)
160				{
161					LLVector2* tc = (LLVector2*) mFace->mTexCoords;
162					*mTexCoord = ((1.f - a - b)  * tc[tri->mIndex[0]] +
163						a              * tc[tri->mIndex[1]] +
164						b              * tc[tri->mIndex[2]]);
165
166				}
167
168				if (mNormal != NULL)
169				{
170					LLVector4* norm = (LLVector4*) mFace->mNormals;
171
172					*mNormal    = ((1.f - a - b)  * LLVector3(norm[tri->mIndex[0]]) + 
173						a              * LLVector3(norm[tri->mIndex[1]]) +
174						b              * LLVector3(norm[tri->mIndex[2]]));
175				}
176
177				if (mBinormal != NULL)
178				{
179					LLVector4* binormal = (LLVector4*) mFace->mBinormals;
180					*mBinormal = ((1.f - a - b)  * LLVector3(binormal[tri->mIndex[0]]) + 
181							a              * LLVector3(binormal[tri->mIndex[1]]) +
182							b              * LLVector3(binormal[tri->mIndex[2]]));
183				}
184			}
185		}
186	}
187}
188
189const LLVector4a& LLVolumeTriangle::getPositionGroup() const
190{
191	return mPositionGroup;
192}
193
194const F32& LLVolumeTriangle::getBinRadius() const
195{
196	return mRadius;
197}
198
199
200//TEST CODE
201
202void LLVolumeOctreeValidate::visit(const LLOctreeNode<LLVolumeTriangle>* branch)
203{
204	LLVolumeOctreeListener* node = (LLVolumeOctreeListener*) branch->getListener(0);
205
206	//make sure bounds matches extents
207	LLVector4a& min = node->mExtents[0];
208	LLVector4a& max = node->mExtents[1];
209
210	LLVector4a& center = node->mBounds[0];
211	LLVector4a& size = node->mBounds[1];
212
213	LLVector4a test_min, test_max;
214	test_min.setSub(center, size);
215	test_max.setAdd(center, size);
216
217	if (!test_min.equals3(min, 0.001f) ||
218		!test_max.equals3(max, 0.001f))
219	{
220		llerrs << "Bad bounding box data found." << llendl;
221	}
222
223	test_min.sub(LLVector4a(0.001f));
224	test_max.add(LLVector4a(0.001f));
225
226	for (U32 i = 0; i < branch->getChildCount(); ++i)
227	{
228		LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(i)->getListener(0);
229
230		//make sure all children fit inside this node
231		if (child->mExtents[0].lessThan(test_min).areAnySet(LLVector4Logical::MASK_XYZ) ||
232			child->mExtents[1].greaterThan(test_max).areAnySet(LLVector4Logical::MASK_XYZ))
233		{
234			llerrs << "Child protrudes from bounding box." << llendl;
235		}
236	}
237
238	//children fit, check data
239	for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter = branch->getData().begin(); 
240			iter != branch->getData().end(); ++iter)
241	{
242		const LLVolumeTriangle* tri = *iter;
243
244		//validate triangle
245		for (U32 i = 0; i < 3; i++)
246		{
247			if (tri->mV[i]->greaterThan(test_max).areAnySet(LLVector4Logical::MASK_XYZ) ||
248				tri->mV[i]->lessThan(test_min).areAnySet(LLVector4Logical::MASK_XYZ))
249			{
250				llerrs << "Triangle protrudes from node." << llendl;
251			}
252		}
253	}
254}
255
256