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