PageRenderTime 50ms CodeModel.GetById 2ms app.highlight 44ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/newview/llphysicsshapebuilderutil.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 210 lines | 145 code | 21 blank | 44 comment | 62 complexity | 5408be36b062de9c2165ee614b8a0a09 MD5 | raw file
  1/** 
  2 * @file llphysicsshapebuilder.cpp
  3 * @brief Generic system to convert LL(Physics)VolumeParams to physics shapes
  4 *
  5 * $LicenseInfo:firstyear=2001&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 "llviewerprecompiledheaders.h"
 28
 29#include "llphysicsshapebuilderutil.h"
 30
 31/* static */
 32void LLPhysicsShapeBuilderUtil::determinePhysicsShape( const LLPhysicsVolumeParams& volume_params, const LLVector3& scale, PhysicsShapeSpecification& specOut )
 33{
 34	const LLProfileParams& profile_params = volume_params.getProfileParams();
 35	const LLPathParams& path_params = volume_params.getPathParams();
 36
 37	specOut.mScale = scale;
 38
 39	const F32 avgScale = ( scale[VX] + scale[VY] + scale[VZ] )/3.0f;	
 40
 41	// count the scale elements that are small
 42	S32 min_size_counts = 0;
 43	for (S32 i = 0; i < 3; ++i)
 44	{
 45		if (scale[i] < SHAPE_BUILDER_CONVEXIFICATION_SIZE)
 46		{
 47			++min_size_counts;
 48		}
 49	}
 50
 51	const bool profile_complete = ( profile_params.getBegin() <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale ) &&
 52		( profile_params.getEnd() >= (1.0f - SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale) );
 53
 54	const bool path_complete =	( path_params.getBegin() <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale ) && 
 55		( path_params.getEnd() >= (1.0f - SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale) );
 56
 57	const bool simple_params = ( volume_params.getHollow() <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_HOLLOW/avgScale )
 58		&& ( fabs(path_params.getShearX()) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_SHEAR/avgScale )
 59		&& ( fabs(path_params.getShearY()) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_SHEAR/avgScale )
 60		&& ( !volume_params.isMeshSculpt() && !volume_params.isSculpt() );
 61
 62	if (simple_params && profile_complete)
 63	{
 64		// Try to create an implicit shape or convexified
 65		bool no_taper = ( fabs(path_params.getScaleX() - 1.0f) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_TAPER/avgScale )
 66			&& ( fabs(path_params.getScaleY() - 1.0f) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_TAPER/avgScale );
 67
 68		bool no_twist = ( fabs(path_params.getTwistBegin()) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_TWIST/avgScale )
 69			&& ( fabs(path_params.getTwistEnd()) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_TWIST/avgScale);
 70
 71		// Box 
 72		if(
 73			( profile_params.getCurveType() == LL_PCODE_PROFILE_SQUARE )
 74			&& ( path_params.getCurveType() == LL_PCODE_PATH_LINE )
 75			&& no_taper
 76			&& no_twist
 77			)
 78		{
 79			specOut.mType = PhysicsShapeSpecification::BOX;
 80			if ( path_complete )
 81			{
 82				return;
 83			}
 84			else
 85			{
 86				// Side lengths
 87				specOut.mScale[VX] = llmax( scale[VX], SHAPE_BUILDER_MIN_GEOMETRY_SIZE );
 88				specOut.mScale[VY] = llmax( scale[VY], SHAPE_BUILDER_MIN_GEOMETRY_SIZE );
 89				specOut.mScale[VZ] = llmax( scale[VZ] * (path_params.getEnd() - path_params.getBegin()), SHAPE_BUILDER_MIN_GEOMETRY_SIZE );
 90
 91				specOut.mCenter.set( 0.f, 0.f, 0.5f * scale[VZ] * ( path_params.getEnd() + path_params.getBegin() - 1.0f ) );
 92				return;
 93			}
 94		}
 95
 96		// Sphere 
 97		if(		path_complete
 98			&& ( profile_params.getCurveType() == LL_PCODE_PROFILE_CIRCLE_HALF )
 99			&& ( path_params.getCurveType() == LL_PCODE_PATH_CIRCLE )
100			&& ( fabs(volume_params.getTaper()) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_TAPER/avgScale )
101			&& no_twist
102			)
103		{
104			if (   ( scale[VX] == scale[VZ] )
105				&& ( scale[VY] == scale[VZ] ) )
106			{
107				// perfect sphere
108				specOut.mType	= PhysicsShapeSpecification::SPHERE;
109				specOut.mScale  = scale;
110				return;
111			}
112			else if (min_size_counts > 1)
113			{
114				// small or narrow sphere -- we can boxify
115				for (S32 i=0; i<3; ++i)
116				{
117					if (specOut.mScale[i] < SHAPE_BUILDER_CONVEXIFICATION_SIZE)
118					{
119						// reduce each small dimension size to split the approximation errors
120						specOut.mScale[i] *= 0.75f;
121					}
122				}
123				specOut.mType  = PhysicsShapeSpecification::BOX;
124				return;
125			}
126		}
127
128		// Cylinder 
129		if(	   (scale[VX] == scale[VY])
130			&& ( profile_params.getCurveType() == LL_PCODE_PROFILE_CIRCLE )
131			&& ( path_params.getCurveType() == LL_PCODE_PATH_LINE )
132			&& ( volume_params.getBeginS() <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale )
133			&& ( volume_params.getEndS() >= (1.0f - SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale) )
134			&& no_taper
135			)
136		{
137			if (min_size_counts > 1)
138			{
139				// small or narrow sphere -- we can boxify
140				for (S32 i=0; i<3; ++i)
141				{
142					if (specOut.mScale[i] < SHAPE_BUILDER_CONVEXIFICATION_SIZE)
143					{
144						// reduce each small dimension size to split the approximation errors
145						specOut.mScale[i] *= 0.75f;
146					}
147				}
148
149				specOut.mType = PhysicsShapeSpecification::BOX;
150			}
151			else
152			{
153				specOut.mType = PhysicsShapeSpecification::CYLINDER;
154				F32 length = (volume_params.getPathParams().getEnd() - volume_params.getPathParams().getBegin()) * scale[VZ];
155
156				specOut.mScale[VY] = specOut.mScale[VX];
157				specOut.mScale[VZ] = length;
158				// The minus one below fixes the fact that begin and end range from 0 to 1 not -1 to 1.
159				specOut.mCenter.set( 0.f, 0.f, 0.5f * (volume_params.getPathParams().getBegin() + volume_params.getPathParams().getEnd() - 1.f) * scale[VZ] );
160			}
161
162			return;
163		}
164	}
165
166	if (	(min_size_counts == 3 )
167		// Possible dead code here--who wants to take it out?
168		||	(path_complete
169				&& profile_complete
170				&& ( path_params.getCurveType() == LL_PCODE_PATH_LINE ) 
171				&& (min_size_counts > 1 ) ) 
172		)
173	{
174		// it isn't simple but
175		// we might be able to convexify this shape if the path and profile are complete
176		// or the path is linear and both path and profile are complete --> we can boxify it
177		specOut.mType = PhysicsShapeSpecification::BOX;
178		specOut.mScale = scale;
179		return;
180	}
181
182	// Special case for big, very thin objects - bump the small dimensions up to the COLLISION_TOLERANCE
183	if (min_size_counts == 1		// One dimension is small
184		&& avgScale > 3.f)			//  ... but others are fairly large
185	{
186		for (S32 i = 0; i < 3; ++i)
187		{
188			specOut.mScale[i] = llmax( specOut.mScale[i], COLLISION_TOLERANCE );
189		}
190	}
191
192	if ( volume_params.shouldForceConvex() )
193	{
194		specOut.mType = PhysicsShapeSpecification::USER_CONVEX;
195	}	
196	// Make a simpler convex shape if we can.
197	else if (volume_params.isConvex()			// is convex
198			|| min_size_counts > 1 )			// two or more small dimensions
199	{
200		specOut.mType = PhysicsShapeSpecification::PRIM_CONVEX;
201	}
202	else if ( volume_params.isSculpt() ) // Is a sculpt of any kind (mesh or legacy)
203	{
204		specOut.mType = volume_params.isMeshSculpt() ? PhysicsShapeSpecification::USER_MESH : PhysicsShapeSpecification::SCULPT;
205	}
206	else // Resort to mesh 
207	{
208		specOut.mType = PhysicsShapeSpecification::PRIM_MESH;
209	}
210}