PageRenderTime 52ms CodeModel.GetById 26ms app.highlight 21ms RepoModel.GetById 1ms 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
  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
 28
 29#ifndef LL_PRIM_LINK_INFO_H
 30#define LL_PRIM_LINK_INFO_H
 31
 32// system includes
 33#include <iostream>
 34#include <map>
 35#include <list>
 36#include <vector>
 37
 38// common includes
 39#include "stdtypes.h"
 40#include "v3math.h"
 41#include "llquaternion.h"
 42#include "llsphere.h"
 43
 44
 45const F32 MAX_OBJECT_SPAN = 54.f;		// max distance from outside edge of an object to the farthest edge
 46const F32 OBJECT_SPAN_BONUS = 2.f;		// infinitesimally small prims can always link up to this distance
 47const S32 MAX_PRIMS_PER_OBJECT = 256;
 48
 49
 50template < typename DATA_TYPE >
 51class LLPrimLinkInfo
 52{
 53public:
 54	LLPrimLinkInfo();
 55	LLPrimLinkInfo( DATA_TYPE data, const LLSphere& sphere );
 56	~LLPrimLinkInfo();
 57
 58	void set( DATA_TYPE data, const LLSphere& sphere );
 59	void append( DATA_TYPE data, const LLSphere& sphere );
 60	void getData( std::list< DATA_TYPE >& data_list ) const;
 61	F32 getDiameter() const;
 62	LLVector3 getCenter() const;
 63
 64	// returns 'true' if this info can link with other_info
 65	bool canLink( const LLPrimLinkInfo< DATA_TYPE >& other_info );
 66
 67	S32 getPrimCount() const { return mDataMap.size(); }
 68
 69	void mergeLinkableSet( typename std::list< LLPrimLinkInfo < DATA_TYPE > >& unlinked );
 70
 71	void transform(const LLVector3& position, const LLQuaternion& rotation);
 72
 73private:
 74	// returns number of merges made
 75	S32 merge(LLPrimLinkInfo< DATA_TYPE >& other_info);
 76
 77	// returns number of collapses made
 78	static S32 collapse(typename std::list< LLPrimLinkInfo < DATA_TYPE > >& unlinked );
 79
 80	void computeBoundingSphere();
 81
 82	// Internal utility to encapsulate the link rules
 83	F32 get_max_linkable_span(const LLSphere& first, const LLSphere& second);
 84	F32 get_span(const LLSphere& first, const LLSphere& second);
 85
 86private:
 87	std::map< DATA_TYPE, LLSphere > mDataMap;
 88	LLSphere mBoundingSphere;
 89};
 90
 91
 92
 93template < typename DATA_TYPE >
 94LLPrimLinkInfo< DATA_TYPE >::LLPrimLinkInfo()
 95:	mBoundingSphere( LLVector3(0.f, 0.f, 0.f), 0.f )
 96{
 97}
 98
 99template < typename DATA_TYPE >
100LLPrimLinkInfo< DATA_TYPE >::LLPrimLinkInfo( DATA_TYPE data, const LLSphere& sphere)
101:	mBoundingSphere(sphere)
102{
103	mDataMap[data] = sphere;
104}
105
106template < typename DATA_TYPE >
107LLPrimLinkInfo< DATA_TYPE >::~LLPrimLinkInfo()
108{
109	mDataMap.clear();
110}
111
112template < typename DATA_TYPE >
113void LLPrimLinkInfo< DATA_TYPE>::set( DATA_TYPE data, const LLSphere& sphere )
114{
115	if (!mDataMap.empty())
116	{
117		mDataMap.clear();
118	}
119	mDataMap[data] = sphere;
120	mBoundingSphere = sphere;
121}
122
123template < typename DATA_TYPE >
124void LLPrimLinkInfo< DATA_TYPE>::append( DATA_TYPE data, const LLSphere& sphere )
125{
126	mDataMap[data] = sphere;
127	if (!mBoundingSphere.contains(sphere))
128	{
129		computeBoundingSphere();
130	}
131}
132
133template < typename DATA_TYPE >
134void LLPrimLinkInfo< DATA_TYPE >::getData( std::list< DATA_TYPE >& data_list) const
135{
136	typename std::map< DATA_TYPE, LLSphere >::const_iterator map_itr;
137	for (map_itr = mDataMap.begin(); map_itr != mDataMap.end(); ++map_itr)
138	{
139		data_list.push_back(map_itr->first);
140	}
141}
142
143template < typename DATA_TYPE >
144F32 LLPrimLinkInfo< DATA_TYPE >::getDiameter() const
145{ 
146	return 2.f * mBoundingSphere.getRadius();
147}
148
149template < typename DATA_TYPE >
150LLVector3 LLPrimLinkInfo< DATA_TYPE >::getCenter() const
151{ 
152	return mBoundingSphere.getCenter(); 
153}
154
155template < typename DATA_TYPE >
156F32 LLPrimLinkInfo< DATA_TYPE >::get_max_linkable_span(const LLSphere& first, const LLSphere& second)
157{
158	F32 max_span = 3.f * (first.getRadius() + second.getRadius()) + OBJECT_SPAN_BONUS;
159	if (max_span > MAX_OBJECT_SPAN)
160	{
161		max_span = MAX_OBJECT_SPAN;
162	}
163
164	return max_span;
165}
166
167template < typename DATA_TYPE >
168F32 LLPrimLinkInfo< DATA_TYPE >::get_span(const LLSphere& first, const LLSphere& second)
169{
170	F32 span = (first.getCenter() - second.getCenter()).length()
171				+ first.getRadius() + second.getRadius();
172	return span;
173}
174
175// static
176// returns 'true' if this info can link with any part of other_info
177template < typename DATA_TYPE >
178bool LLPrimLinkInfo< DATA_TYPE >::canLink(const LLPrimLinkInfo& other_info)
179{
180	F32 max_span = get_max_linkable_span(mBoundingSphere, other_info.mBoundingSphere);
181
182	F32 span = get_span(mBoundingSphere, other_info.mBoundingSphere);
183	
184	if (span <= max_span)
185	{
186		// The entire other_info fits inside the max span.
187		return TRUE;
188	}
189	else if (span > max_span + 2.f * other_info.mBoundingSphere.getRadius())
190	{
191		// there is no way any piece of other_info could link with this one
192		return FALSE;
193	}
194
195	// there may be a piece of other_info that is linkable
196	typename std::map< DATA_TYPE, LLSphere >::const_iterator map_itr;
197	for (map_itr = other_info.mDataMap.begin(); map_itr != other_info.mDataMap.end(); ++map_itr)
198	{
199		const LLSphere& other_sphere = (*map_itr).second;
200		max_span = get_max_linkable_span(mBoundingSphere, other_sphere);
201
202		span = get_span(mBoundingSphere, other_sphere);
203
204		if (span <= max_span)
205		{
206			// found one piece that is linkable
207			return TRUE;
208		}
209	}
210	return FALSE;
211}
212
213// merges elements of 'unlinked' 
214// returns number of links made (NOT final prim count, NOR linked prim count)
215// and removes any linkable infos from 'unlinked' 
216template < typename DATA_TYPE >
217void LLPrimLinkInfo< DATA_TYPE >::mergeLinkableSet(std::list< LLPrimLinkInfo< DATA_TYPE > > & unlinked)
218{
219	bool linked_something = true;
220	while (linked_something)
221	{
222		linked_something = false;
223
224		typename std::list< LLPrimLinkInfo< DATA_TYPE > >::iterator other_itr = unlinked.begin();
225		while ( other_itr != unlinked.end()
226			   && getPrimCount() < MAX_PRIMS_PER_OBJECT )
227		{
228			S32 merge_count = merge(*other_itr);
229			if (merge_count > 0)
230			{
231				linked_something = true;
232			}
233			if (0 == (*other_itr).getPrimCount())
234			{
235				unlinked.erase(other_itr++);
236			}
237			else
238			{
239				++other_itr;
240			}
241		}
242		if (!linked_something
243			&& unlinked.size() > 1)
244		{
245			S32 collapse_count = collapse(unlinked);
246			if (collapse_count > 0)
247			{
248				linked_something = true;
249			}
250		}
251	}
252}
253
254// transforms all of the spheres into a new reference frame
255template < typename DATA_TYPE >
256void LLPrimLinkInfo< DATA_TYPE >::transform(const LLVector3& position, const LLQuaternion& rotation)
257{
258	typename std::map< DATA_TYPE, LLSphere >::iterator map_itr;
259	for (map_itr = mDataMap.begin(); map_itr != mDataMap.end(); ++map_itr)
260	{
261		(*map_itr).second.setCenter((*map_itr).second.getCenter() * rotation + position);
262	}
263	mBoundingSphere.setCenter(mBoundingSphere.getCenter() * rotation + position);
264}
265
266// private
267// returns number of links made
268template < typename DATA_TYPE >
269S32 LLPrimLinkInfo< DATA_TYPE >::merge(LLPrimLinkInfo& other_info)
270{
271	S32 link_count = 0;
272
273//	F32 other_radius = other_info.mBoundingSphere.getRadius();
274//	other_info.computeBoundingSphere();
275//	if ( other_radius != other_info.mBoundingSphere.getRadius() )
276//	{
277//		llinfos << "Other bounding sphere changed!!" << llendl;
278//	}
279
280//	F32 this_radius = mBoundingSphere.getRadius();
281//	computeBoundingSphere();
282//	if ( this_radius != mBoundingSphere.getRadius() )
283//	{
284//		llinfos << "This bounding sphere changed!!" << llendl;
285//	}
286
287
288	F32 max_span = get_max_linkable_span(mBoundingSphere, other_info.mBoundingSphere);
289
290	//  F32 center_dist = (mBoundingSphere.getCenter() - other_info.mBoundingSphere.getCenter()).length();
291	//	llinfos << "objects are " << center_dist << "m apart" << llendl;
292	F32 span = get_span(mBoundingSphere, other_info.mBoundingSphere);
293
294	F32 span_limit = max_span + (2.f * other_info.mBoundingSphere.getRadius());
295	if (span > span_limit)
296	{
297		// there is no way any piece of other_info could link with this one
298		// llinfos << "span too large:  " << span << " vs. " << span_limit << llendl;
299		return 0;
300	}
301
302	bool completely_linkable = (span <= max_span) ? true : false;
303
304	typename std::map< DATA_TYPE, LLSphere >::iterator map_itr = other_info.mDataMap.begin();
305	while (map_itr != other_info.mDataMap.end()
306			&& getPrimCount() < MAX_PRIMS_PER_OBJECT )
307	{
308		DATA_TYPE other_data = (*map_itr).first;
309		LLSphere& other_sphere = (*map_itr).second;
310
311		if (!completely_linkable)
312		{
313			max_span = get_max_linkable_span(mBoundingSphere, other_sphere);
314	
315			F32 span = get_span(mBoundingSphere, other_sphere);
316
317			if (span > max_span)
318			{
319				++map_itr;
320				continue;
321			}
322		}
323
324		mDataMap[other_data] = other_sphere;
325		++link_count;
326
327		if (!mBoundingSphere.contains(other_sphere) )
328		{
329			computeBoundingSphere();
330		}
331
332		// remove from the other info
333		other_info.mDataMap.erase(map_itr++);
334	}
335
336	if (link_count > 0 && other_info.getPrimCount() > 0)
337	{
338		other_info.computeBoundingSphere();
339	}
340	return link_count;
341}
342
343// links any linkable elements of unlinked
344template < typename DATA_TYPE >
345S32 LLPrimLinkInfo< DATA_TYPE >::collapse(std::list< LLPrimLinkInfo< DATA_TYPE > > & unlinked)
346{ 
347	S32 link_count = 0;
348	bool linked_something = true;
349	while (linked_something)
350	{
351		linked_something = false;
352
353		typename std::list< LLPrimLinkInfo< DATA_TYPE > >::iterator this_itr = unlinked.begin();
354		typename std::list< LLPrimLinkInfo< DATA_TYPE > >::iterator other_itr = this_itr;
355		++other_itr;
356		while ( other_itr != unlinked.end() )
357			   
358		{
359			S32 merge_count = (*this_itr).merge(*other_itr);
360			if (merge_count > 0)
361			{
362				linked_something = true;
363				link_count += merge_count;
364			}
365			if (0 == (*other_itr).getPrimCount())
366			{
367				unlinked.erase(other_itr++);
368			}
369			else
370			{
371				++other_itr;
372			}
373		}
374	}
375	return link_count;
376}
377
378
379template < typename DATA_TYPE >
380void LLPrimLinkInfo< DATA_TYPE >::computeBoundingSphere()
381{ 
382	std::vector< LLSphere > sphere_list;
383	typename std::map< DATA_TYPE, LLSphere >::const_iterator map_itr;
384	for (map_itr = mDataMap.begin(); map_itr != mDataMap.end(); ++map_itr)
385	{
386		sphere_list.push_back(map_itr->second);
387	}
388	mBoundingSphere = LLSphere::getBoundingSphere(sphere_list);
389}
390
391
392#endif
393