PageRenderTime 144ms CodeModel.GetById 1ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/llprimitive/llprimlinkinfo.h

https://bitbucket.org/lindenlab/viewer-beta/
C++ Header | 393 lines | 267 code | 64 blank | 62 comment | 40 complexity | 4355a5e6b139f7f821a773598a83e17b MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llprimlinkinfo.h
  3. * @author andrew@lindenlab.com
  4. * @brief A template for determining which prims in a set are linkable
  5. *
  6. * $LicenseInfo:firstyear=2007&license=viewerlgpl$
  7. * Second Life Viewer Source Code
  8. * Copyright (C) 2010, Linden Research, Inc.
  9. *
  10. * This library is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU Lesser General Public
  12. * License as published by the Free Software Foundation;
  13. * version 2.1 of the License only.
  14. *
  15. * This library is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  18. * Lesser General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU Lesser General Public
  21. * License along with this library; if not, write to the Free Software
  22. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  23. *
  24. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  25. * $/LicenseInfo$
  26. */
  27. #ifndef LL_PRIM_LINK_INFO_H
  28. #define LL_PRIM_LINK_INFO_H
  29. // system includes
  30. #include <iostream>
  31. #include <map>
  32. #include <list>
  33. #include <vector>
  34. // common includes
  35. #include "stdtypes.h"
  36. #include "v3math.h"
  37. #include "llquaternion.h"
  38. #include "llsphere.h"
  39. const F32 MAX_OBJECT_SPAN = 54.f; // max distance from outside edge of an object to the farthest edge
  40. const F32 OBJECT_SPAN_BONUS = 2.f; // infinitesimally small prims can always link up to this distance
  41. const S32 MAX_PRIMS_PER_OBJECT = 256;
  42. template < typename DATA_TYPE >
  43. class LLPrimLinkInfo
  44. {
  45. public:
  46. LLPrimLinkInfo();
  47. LLPrimLinkInfo( DATA_TYPE data, const LLSphere& sphere );
  48. ~LLPrimLinkInfo();
  49. void set( DATA_TYPE data, const LLSphere& sphere );
  50. void append( DATA_TYPE data, const LLSphere& sphere );
  51. void getData( std::list< DATA_TYPE >& data_list ) const;
  52. F32 getDiameter() const;
  53. LLVector3 getCenter() const;
  54. // returns 'true' if this info can link with other_info
  55. bool canLink( const LLPrimLinkInfo< DATA_TYPE >& other_info );
  56. S32 getPrimCount() const { return mDataMap.size(); }
  57. void mergeLinkableSet( typename std::list< LLPrimLinkInfo < DATA_TYPE > >& unlinked );
  58. void transform(const LLVector3& position, const LLQuaternion& rotation);
  59. private:
  60. // returns number of merges made
  61. S32 merge(LLPrimLinkInfo< DATA_TYPE >& other_info);
  62. // returns number of collapses made
  63. static S32 collapse(typename std::list< LLPrimLinkInfo < DATA_TYPE > >& unlinked );
  64. void computeBoundingSphere();
  65. // Internal utility to encapsulate the link rules
  66. F32 get_max_linkable_span(const LLSphere& first, const LLSphere& second);
  67. F32 get_span(const LLSphere& first, const LLSphere& second);
  68. private:
  69. std::map< DATA_TYPE, LLSphere > mDataMap;
  70. LLSphere mBoundingSphere;
  71. };
  72. template < typename DATA_TYPE >
  73. LLPrimLinkInfo< DATA_TYPE >::LLPrimLinkInfo()
  74. : mBoundingSphere( LLVector3(0.f, 0.f, 0.f), 0.f )
  75. {
  76. }
  77. template < typename DATA_TYPE >
  78. LLPrimLinkInfo< DATA_TYPE >::LLPrimLinkInfo( DATA_TYPE data, const LLSphere& sphere)
  79. : mBoundingSphere(sphere)
  80. {
  81. mDataMap[data] = sphere;
  82. }
  83. template < typename DATA_TYPE >
  84. LLPrimLinkInfo< DATA_TYPE >::~LLPrimLinkInfo()
  85. {
  86. mDataMap.clear();
  87. }
  88. template < typename DATA_TYPE >
  89. void LLPrimLinkInfo< DATA_TYPE>::set( DATA_TYPE data, const LLSphere& sphere )
  90. {
  91. if (!mDataMap.empty())
  92. {
  93. mDataMap.clear();
  94. }
  95. mDataMap[data] = sphere;
  96. mBoundingSphere = sphere;
  97. }
  98. template < typename DATA_TYPE >
  99. void LLPrimLinkInfo< DATA_TYPE>::append( DATA_TYPE data, const LLSphere& sphere )
  100. {
  101. mDataMap[data] = sphere;
  102. if (!mBoundingSphere.contains(sphere))
  103. {
  104. computeBoundingSphere();
  105. }
  106. }
  107. template < typename DATA_TYPE >
  108. void LLPrimLinkInfo< DATA_TYPE >::getData( std::list< DATA_TYPE >& data_list) const
  109. {
  110. typename std::map< DATA_TYPE, LLSphere >::const_iterator map_itr;
  111. for (map_itr = mDataMap.begin(); map_itr != mDataMap.end(); ++map_itr)
  112. {
  113. data_list.push_back(map_itr->first);
  114. }
  115. }
  116. template < typename DATA_TYPE >
  117. F32 LLPrimLinkInfo< DATA_TYPE >::getDiameter() const
  118. {
  119. return 2.f * mBoundingSphere.getRadius();
  120. }
  121. template < typename DATA_TYPE >
  122. LLVector3 LLPrimLinkInfo< DATA_TYPE >::getCenter() const
  123. {
  124. return mBoundingSphere.getCenter();
  125. }
  126. template < typename DATA_TYPE >
  127. F32 LLPrimLinkInfo< DATA_TYPE >::get_max_linkable_span(const LLSphere& first, const LLSphere& second)
  128. {
  129. F32 max_span = 3.f * (first.getRadius() + second.getRadius()) + OBJECT_SPAN_BONUS;
  130. if (max_span > MAX_OBJECT_SPAN)
  131. {
  132. max_span = MAX_OBJECT_SPAN;
  133. }
  134. return max_span;
  135. }
  136. template < typename DATA_TYPE >
  137. F32 LLPrimLinkInfo< DATA_TYPE >::get_span(const LLSphere& first, const LLSphere& second)
  138. {
  139. F32 span = (first.getCenter() - second.getCenter()).length()
  140. + first.getRadius() + second.getRadius();
  141. return span;
  142. }
  143. // static
  144. // returns 'true' if this info can link with any part of other_info
  145. template < typename DATA_TYPE >
  146. bool LLPrimLinkInfo< DATA_TYPE >::canLink(const LLPrimLinkInfo& other_info)
  147. {
  148. F32 max_span = get_max_linkable_span(mBoundingSphere, other_info.mBoundingSphere);
  149. F32 span = get_span(mBoundingSphere, other_info.mBoundingSphere);
  150. if (span <= max_span)
  151. {
  152. // The entire other_info fits inside the max span.
  153. return TRUE;
  154. }
  155. else if (span > max_span + 2.f * other_info.mBoundingSphere.getRadius())
  156. {
  157. // there is no way any piece of other_info could link with this one
  158. return FALSE;
  159. }
  160. // there may be a piece of other_info that is linkable
  161. typename std::map< DATA_TYPE, LLSphere >::const_iterator map_itr;
  162. for (map_itr = other_info.mDataMap.begin(); map_itr != other_info.mDataMap.end(); ++map_itr)
  163. {
  164. const LLSphere& other_sphere = (*map_itr).second;
  165. max_span = get_max_linkable_span(mBoundingSphere, other_sphere);
  166. span = get_span(mBoundingSphere, other_sphere);
  167. if (span <= max_span)
  168. {
  169. // found one piece that is linkable
  170. return TRUE;
  171. }
  172. }
  173. return FALSE;
  174. }
  175. // merges elements of 'unlinked'
  176. // returns number of links made (NOT final prim count, NOR linked prim count)
  177. // and removes any linkable infos from 'unlinked'
  178. template < typename DATA_TYPE >
  179. void LLPrimLinkInfo< DATA_TYPE >::mergeLinkableSet(std::list< LLPrimLinkInfo< DATA_TYPE > > & unlinked)
  180. {
  181. bool linked_something = true;
  182. while (linked_something)
  183. {
  184. linked_something = false;
  185. typename std::list< LLPrimLinkInfo< DATA_TYPE > >::iterator other_itr = unlinked.begin();
  186. while ( other_itr != unlinked.end()
  187. && getPrimCount() < MAX_PRIMS_PER_OBJECT )
  188. {
  189. S32 merge_count = merge(*other_itr);
  190. if (merge_count > 0)
  191. {
  192. linked_something = true;
  193. }
  194. if (0 == (*other_itr).getPrimCount())
  195. {
  196. unlinked.erase(other_itr++);
  197. }
  198. else
  199. {
  200. ++other_itr;
  201. }
  202. }
  203. if (!linked_something
  204. && unlinked.size() > 1)
  205. {
  206. S32 collapse_count = collapse(unlinked);
  207. if (collapse_count > 0)
  208. {
  209. linked_something = true;
  210. }
  211. }
  212. }
  213. }
  214. // transforms all of the spheres into a new reference frame
  215. template < typename DATA_TYPE >
  216. void LLPrimLinkInfo< DATA_TYPE >::transform(const LLVector3& position, const LLQuaternion& rotation)
  217. {
  218. typename std::map< DATA_TYPE, LLSphere >::iterator map_itr;
  219. for (map_itr = mDataMap.begin(); map_itr != mDataMap.end(); ++map_itr)
  220. {
  221. (*map_itr).second.setCenter((*map_itr).second.getCenter() * rotation + position);
  222. }
  223. mBoundingSphere.setCenter(mBoundingSphere.getCenter() * rotation + position);
  224. }
  225. // private
  226. // returns number of links made
  227. template < typename DATA_TYPE >
  228. S32 LLPrimLinkInfo< DATA_TYPE >::merge(LLPrimLinkInfo& other_info)
  229. {
  230. S32 link_count = 0;
  231. // F32 other_radius = other_info.mBoundingSphere.getRadius();
  232. // other_info.computeBoundingSphere();
  233. // if ( other_radius != other_info.mBoundingSphere.getRadius() )
  234. // {
  235. // llinfos << "Other bounding sphere changed!!" << llendl;
  236. // }
  237. // F32 this_radius = mBoundingSphere.getRadius();
  238. // computeBoundingSphere();
  239. // if ( this_radius != mBoundingSphere.getRadius() )
  240. // {
  241. // llinfos << "This bounding sphere changed!!" << llendl;
  242. // }
  243. F32 max_span = get_max_linkable_span(mBoundingSphere, other_info.mBoundingSphere);
  244. // F32 center_dist = (mBoundingSphere.getCenter() - other_info.mBoundingSphere.getCenter()).length();
  245. // llinfos << "objects are " << center_dist << "m apart" << llendl;
  246. F32 span = get_span(mBoundingSphere, other_info.mBoundingSphere);
  247. F32 span_limit = max_span + (2.f * other_info.mBoundingSphere.getRadius());
  248. if (span > span_limit)
  249. {
  250. // there is no way any piece of other_info could link with this one
  251. // llinfos << "span too large: " << span << " vs. " << span_limit << llendl;
  252. return 0;
  253. }
  254. bool completely_linkable = (span <= max_span) ? true : false;
  255. typename std::map< DATA_TYPE, LLSphere >::iterator map_itr = other_info.mDataMap.begin();
  256. while (map_itr != other_info.mDataMap.end()
  257. && getPrimCount() < MAX_PRIMS_PER_OBJECT )
  258. {
  259. DATA_TYPE other_data = (*map_itr).first;
  260. LLSphere& other_sphere = (*map_itr).second;
  261. if (!completely_linkable)
  262. {
  263. max_span = get_max_linkable_span(mBoundingSphere, other_sphere);
  264. F32 span = get_span(mBoundingSphere, other_sphere);
  265. if (span > max_span)
  266. {
  267. ++map_itr;
  268. continue;
  269. }
  270. }
  271. mDataMap[other_data] = other_sphere;
  272. ++link_count;
  273. if (!mBoundingSphere.contains(other_sphere) )
  274. {
  275. computeBoundingSphere();
  276. }
  277. // remove from the other info
  278. other_info.mDataMap.erase(map_itr++);
  279. }
  280. if (link_count > 0 && other_info.getPrimCount() > 0)
  281. {
  282. other_info.computeBoundingSphere();
  283. }
  284. return link_count;
  285. }
  286. // links any linkable elements of unlinked
  287. template < typename DATA_TYPE >
  288. S32 LLPrimLinkInfo< DATA_TYPE >::collapse(std::list< LLPrimLinkInfo< DATA_TYPE > > & unlinked)
  289. {
  290. S32 link_count = 0;
  291. bool linked_something = true;
  292. while (linked_something)
  293. {
  294. linked_something = false;
  295. typename std::list< LLPrimLinkInfo< DATA_TYPE > >::iterator this_itr = unlinked.begin();
  296. typename std::list< LLPrimLinkInfo< DATA_TYPE > >::iterator other_itr = this_itr;
  297. ++other_itr;
  298. while ( other_itr != unlinked.end() )
  299. {
  300. S32 merge_count = (*this_itr).merge(*other_itr);
  301. if (merge_count > 0)
  302. {
  303. linked_something = true;
  304. link_count += merge_count;
  305. }
  306. if (0 == (*other_itr).getPrimCount())
  307. {
  308. unlinked.erase(other_itr++);
  309. }
  310. else
  311. {
  312. ++other_itr;
  313. }
  314. }
  315. }
  316. return link_count;
  317. }
  318. template < typename DATA_TYPE >
  319. void LLPrimLinkInfo< DATA_TYPE >::computeBoundingSphere()
  320. {
  321. std::vector< LLSphere > sphere_list;
  322. typename std::map< DATA_TYPE, LLSphere >::const_iterator map_itr;
  323. for (map_itr = mDataMap.begin(); map_itr != mDataMap.end(); ++map_itr)
  324. {
  325. sphere_list.push_back(map_itr->second);
  326. }
  327. mBoundingSphere = LLSphere::getBoundingSphere(sphere_list);
  328. }
  329. #endif