Merge branch 'master' into llwebprofile
This commit is contained in:
27
README
27
README
@@ -9,15 +9,30 @@
|
||||
Sin-gu-la-ri-ty (noun) - a distinctive feature, a uniqueness; a point at which
|
||||
continuity breaks up; a point in history at which machine becomes smarter than
|
||||
humanity and/or fuses with it indivisively; or simply a cool sounding word with
|
||||
my initials in it :)
|
||||
the initials S.G. in it :)
|
||||
|
||||
Singularity Viewer is a Second Life protocol compatible client application. It
|
||||
can be used to access Second LIfe service as well as a number of other such as
|
||||
those based upon OpenSim plattform. It is directly based upon source code of
|
||||
Ascent Viewer by Balseraph Software Group, which is in turn based upon source
|
||||
code released by Linden Lab, with contributions from various sources.
|
||||
Singularity Viewer is a SecondLife(tm) protocol compatible client application.
|
||||
It can be used to access SecondLife services as well as a number of others such
|
||||
as those based upon the OpenSim platform.
|
||||
|
||||
Singulariy is maintained by a small group of volunteers who can be contacted
|
||||
both, in-world (SingularityViewer group) as well on IRC (#SingularityViewer
|
||||
@ FreeNode). Bug requests and features requests can be submitted through our
|
||||
Issue Tracket (http://code.google.com/p/singularity-viewer/issues/list or from
|
||||
the viewer menu: Help --> Bug Reporting --> Singularity Issue Tracker...)
|
||||
|
||||
|
||||
As this Readme grows out of date, please refer to
|
||||
|
||||
http://www.singularityviewer.org/about
|
||||
|
||||
|
||||
00000000011111111112222222222333333333344444444445555555555666666666677777777778
|
||||
12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
|
||||
History
|
||||
|
||||
The Singularity viewer was started by Siana Gearz in November 2010 by forking it
|
||||
of the Ascent Viewer, by Balseraph Software Group, which in turn was based upon
|
||||
source code released by Linden Lab.
|
||||
|
||||
|
||||
@@ -248,6 +248,7 @@ Celierra Darling
|
||||
VWR-6975
|
||||
Cron Stardust
|
||||
VWR-10579
|
||||
STORM-1919
|
||||
Cypren Christenson
|
||||
SNOW-129
|
||||
SNOW-140
|
||||
|
||||
@@ -418,6 +418,7 @@ void cleanupCurl(void)
|
||||
if (CurlMultiHandle::getTotalMultiHandles() != 0)
|
||||
llwarns << "Not all CurlMultiHandle objects were destroyed!" << llendl;
|
||||
AIStateMachine::flush();
|
||||
clearCommandQueue();
|
||||
Stats::print();
|
||||
ssl_cleanup();
|
||||
|
||||
@@ -491,8 +492,6 @@ void Stats::print(void)
|
||||
// Even more strict, BufferedCurlEasyRequest may not be created directly either, only as
|
||||
// base class of ThreadSafeBufferedCurlEasyRequest.
|
||||
llassert(BufferedCurlEasyRequest_count == ThreadSafeBufferedCurlEasyRequest_count);
|
||||
// Each AICurlEasyRequestStateMachine is responsible for exactly one easy handle.
|
||||
llassert(easy_handles >= AICurlEasyRequest_count);
|
||||
// Each AICurlEasyRequestStateMachine has one AICurlEasyRequest member.
|
||||
llassert(AICurlEasyRequest_count >= AICurlEasyRequestStateMachine_count);
|
||||
// AIFIXME: is this really always the case? And why?
|
||||
@@ -1148,12 +1147,16 @@ void CurlEasyRequest::set_timeout_opts(void)
|
||||
setopt(CURLOPT_TIMEOUT, mTimeoutPolicy->getCurlTransaction());
|
||||
}
|
||||
|
||||
void CurlEasyRequest::create_timeout_object(ThreadSafeBufferedCurlEasyRequest* lockobj)
|
||||
void CurlEasyRequest::create_timeout_object(void)
|
||||
{
|
||||
ThreadSafeBufferedCurlEasyRequest* lockobj = NULL;
|
||||
#if defined(CWDEBUG) || defined(DEBUG_CURLIO)
|
||||
lockobj = static_cast<BufferedCurlEasyRequest*>(this)->get_lockobj();
|
||||
#endif
|
||||
mTimeout = new curlthread::HTTPTimeout(mTimeoutPolicy, lockobj);
|
||||
}
|
||||
|
||||
LLPointer<curlthread::HTTPTimeout>& CurlEasyRequest::get_timeout_object(ThreadSafeBufferedCurlEasyRequest* lockobj)
|
||||
LLPointer<curlthread::HTTPTimeout>& CurlEasyRequest::get_timeout_object(void)
|
||||
{
|
||||
if (mTimeoutIsOrphan)
|
||||
{
|
||||
@@ -1162,7 +1165,7 @@ LLPointer<curlthread::HTTPTimeout>& CurlEasyRequest::get_timeout_object(ThreadSa
|
||||
}
|
||||
else
|
||||
{
|
||||
create_timeout_object(lockobj);
|
||||
create_timeout_object();
|
||||
}
|
||||
return mTimeout;
|
||||
}
|
||||
|
||||
@@ -56,12 +56,17 @@ PerHostRequestQueuePtr PerHostRequestQueue::instance(std::string const& hostname
|
||||
//static
|
||||
void PerHostRequestQueue::release(PerHostRequestQueuePtr& instance)
|
||||
{
|
||||
if (instance->lastone())
|
||||
if (instance->exactly_two_left()) // Being 'instance' and the one in sInstanceMap.
|
||||
{
|
||||
// The viewer can be have left main() we can't access the global sInstanceMap anymore.
|
||||
if (LLApp::isStopped())
|
||||
{
|
||||
return;
|
||||
}
|
||||
instance_map_wat instance_map_w(sInstanceMap);
|
||||
// It is possible that 'lastone' is not up to date anymore.
|
||||
// It is possible that 'exactly_two_left' is not up to date anymore.
|
||||
// Therefore, recheck the condition now that we have locked sInstanceMap.
|
||||
if (!instance->lastone())
|
||||
if (!instance->exactly_two_left())
|
||||
{
|
||||
// Some other thread added this host in the meantime.
|
||||
return;
|
||||
|
||||
@@ -118,7 +118,7 @@ class PerHostRequestQueue {
|
||||
class RefCountedThreadSafePerHostRequestQueue : public threadsafe_PerHostRequestQueue {
|
||||
public:
|
||||
RefCountedThreadSafePerHostRequestQueue(void) : mReferenceCount(0) { }
|
||||
bool lastone(void) const { llassert(mReferenceCount >= 2); return mReferenceCount == 2; }
|
||||
bool exactly_two_left(void) const { return mReferenceCount == 2; }
|
||||
|
||||
private:
|
||||
// Used by PerHostRequestQueuePtr. Object is deleted when reference count reaches zero.
|
||||
|
||||
@@ -119,6 +119,7 @@ inline CURLMcode check_multi_code(CURLMcode code) { AICurlInterface::Stats::mult
|
||||
bool curlThreadIsRunning(void);
|
||||
void wakeUpCurlThread(void);
|
||||
void stopCurlThread(void);
|
||||
void clearCommandQueue(void);
|
||||
|
||||
#define DECLARE_SETOPT(param_type) \
|
||||
CURLcode setopt(CURLoption option, param_type parameter)
|
||||
@@ -316,7 +317,7 @@ class CurlEasyRequest : public CurlEasyHandle {
|
||||
static CURLcode curlCtxCallback(CURL* curl, void* sslctx, void* parm);
|
||||
|
||||
// Called from get_timeout_object and httptimeout.
|
||||
void create_timeout_object(ThreadSafeBufferedCurlEasyRequest* lockobj);
|
||||
void create_timeout_object(void);
|
||||
|
||||
public:
|
||||
// Set default options that we want applied to all curl easy handles.
|
||||
@@ -374,9 +375,9 @@ class CurlEasyRequest : public CurlEasyHandle {
|
||||
std::string const& getLowercaseHostname(void) const { return mLowercaseHostname; }
|
||||
// Called by CurlSocketInfo to allow access to the last (after a redirect) HTTPTimeout object related to this request.
|
||||
// This creates mTimeout (unless mTimeoutIsOrphan is set in which case it adopts the orphan).
|
||||
LLPointer<curlthread::HTTPTimeout>& get_timeout_object(ThreadSafeBufferedCurlEasyRequest* lockobj);
|
||||
LLPointer<curlthread::HTTPTimeout>& get_timeout_object(void);
|
||||
// Accessor for mTimeout with optional creation of orphaned object (if lockobj != NULL).
|
||||
LLPointer<curlthread::HTTPTimeout>& httptimeout(ThreadSafeBufferedCurlEasyRequest* lockobj = NULL) { if (lockobj && !mTimeout) create_timeout_object(lockobj); return mTimeout; }
|
||||
LLPointer<curlthread::HTTPTimeout>& httptimeout(void) { if (!mTimeout) { create_timeout_object(); mTimeoutIsOrphan = true; } return mTimeout; }
|
||||
// Return true if no data has been received on the latest socket (if any) for too long.
|
||||
bool has_stalled(void) const { return mTimeout && mTimeout->has_stalled(); }
|
||||
|
||||
|
||||
@@ -775,7 +775,7 @@ CurlSocketInfo::CurlSocketInfo(MultiHandle& multi_handle, CURL* easy, curl_socke
|
||||
// CurlSocketInfo objects for a request and we need upload_finished() to be called on the HTTPTimeout
|
||||
// object related to THIS CurlSocketInfo.
|
||||
AICurlEasyRequest_wat easy_request_w(*lockobj);
|
||||
mTimeout = easy_request_w->get_timeout_object(lockobj);
|
||||
mTimeout = easy_request_w->get_timeout_object();
|
||||
}
|
||||
|
||||
CurlSocketInfo::~CurlSocketInfo()
|
||||
@@ -1065,6 +1065,10 @@ void AICurlThread::wakeup_thread(void)
|
||||
DoutEntering(dc::curl, "AICurlThread::wakeup_thread");
|
||||
llassert(is_main_thread());
|
||||
|
||||
// If we are already exiting the viewer then return immediately.
|
||||
if (!mRunning)
|
||||
return;
|
||||
|
||||
// Try if curl thread is still awake and if so, pass the new commands directly.
|
||||
if (mWakeUpMutex.tryLock())
|
||||
{
|
||||
@@ -1609,7 +1613,9 @@ CURLMcode MultiHandle::remove_easy_request(addedEasyRequests_type::iterator cons
|
||||
ThreadSafeBufferedCurlEasyRequest* lockobj = iter->get_ptr().get();
|
||||
#endif
|
||||
mAddedEasyRequests.erase(iter);
|
||||
#if CWDEBUG
|
||||
Dout(dc::curl, "MultiHandle::remove_easy_request: Removed AICurlEasyRequest " << (void*)lockobj << "; now processing " << mAddedEasyRequests.size() << " easy handles.");
|
||||
#endif
|
||||
|
||||
// Attempt to add a queued request, if any.
|
||||
PerHostRequestQueue_wat(*per_host)->add_queued_to(this);
|
||||
@@ -1971,6 +1977,10 @@ void HTTPTimeout::done(AICurlEasyRequest_wat const& curlEasyRequest_w, CURLcode
|
||||
DoutCurl("done: mStalled set to -1");
|
||||
}
|
||||
|
||||
// Libcurl uses GetTickCount on windows, with a resolution of 10 to 16 ms.
|
||||
// As a result, we can not assume that namelookup_time == 0 has a special meaning.
|
||||
#define LOWRESTIMER LL_WINDOWS
|
||||
|
||||
void HTTPTimeout::print_diagnostics(CurlEasyRequest const* curl_easy_request, char const* eff_url)
|
||||
{
|
||||
llwarns << "Request to \"" << curl_easy_request->getLowercaseHostname() << "\" timed out for " << curl_easy_request->getTimeoutPolicy()->name() << llendl;
|
||||
@@ -1981,8 +1991,15 @@ void HTTPTimeout::print_diagnostics(CurlEasyRequest const* curl_easy_request, ch
|
||||
curl_easy_request->getinfo(CURLINFO_APPCONNECT_TIME, &appconnect_time);
|
||||
curl_easy_request->getinfo(CURLINFO_PRETRANSFER_TIME, &pretransfer_time);
|
||||
curl_easy_request->getinfo(CURLINFO_STARTTRANSFER_TIME, &starttransfer_time);
|
||||
if (namelookup_time == 0)
|
||||
if (namelookup_time == 0
|
||||
#if LOWRESTIMER
|
||||
&& connect_time == 0
|
||||
#endif
|
||||
)
|
||||
{
|
||||
#if LOWRESTIMER
|
||||
llinfos << "Hostname seems to have been still in the DNS cache." << llendl;
|
||||
#else
|
||||
llwarns << "Huh? Curl returned CURLE_OPERATION_TIMEDOUT, but DNS lookup did not occur according to timings. Expected CURLE_COULDNT_RESOLVE_PROXY or CURLE_COULDNT_RESOLVE_HOST!" << llendl;
|
||||
llassert(connect_time == 0);
|
||||
llassert(appconnect_time == 0);
|
||||
@@ -1990,17 +2007,26 @@ void HTTPTimeout::print_diagnostics(CurlEasyRequest const* curl_easy_request, ch
|
||||
llassert(starttransfer_time == 0);
|
||||
// Fatal error for diagnostics.
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
// If namelookup_time is less than 500 microseconds, then it's very likely just a DNS cache lookup.
|
||||
else if (namelookup_time < 500e-6)
|
||||
{
|
||||
#if LOWRESTIMER
|
||||
llinfos << "Hostname was most likely still in DNS cache (or lookup occured in under ~10ms)." << llendl;
|
||||
#else
|
||||
llinfos << "Hostname was still in DNS cache." << llendl;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
llwarns << "DNS lookup of " << curl_easy_request->getLowercaseHostname() << " took " << namelookup_time << " seconds." << llendl;
|
||||
llinfos << "DNS lookup of " << curl_easy_request->getLowercaseHostname() << " took " << namelookup_time << " seconds." << llendl;
|
||||
}
|
||||
if (connect_time == 0)
|
||||
if (connect_time == 0
|
||||
#if LOWRESTIMER
|
||||
&& namelookup_time > 0 // connect_time, when set, is namelookup_time + something.
|
||||
#endif
|
||||
)
|
||||
{
|
||||
llwarns << "Huh? Curl returned CURLE_OPERATION_TIMEDOUT, but connection did not occur according to timings. Expected CURLE_COULDNT_CONNECT!" << llendl;
|
||||
llassert(appconnect_time == 0);
|
||||
@@ -2010,16 +2036,21 @@ void HTTPTimeout::print_diagnostics(CurlEasyRequest const* curl_easy_request, ch
|
||||
return;
|
||||
}
|
||||
// If connect_time is almost equal to namelookup_time, then it was just set because it was already connected.
|
||||
if (connect_time - namelookup_time <= 1e-6)
|
||||
if (connect_time - namelookup_time <= 1e-5)
|
||||
{
|
||||
#if LOWRESTIMER // Assuming 10ms resolution.
|
||||
llinfos << "The socket was most likely already connected (or you connected to a proxy with a connect time of under ~10 ms)." << llendl;
|
||||
#else
|
||||
llinfos << "The socket was already connected (to remote or proxy)." << llendl;
|
||||
#endif
|
||||
// I'm assuming that the SSL/TLS handshake can be measured with a low res timer.
|
||||
if (appconnect_time == 0)
|
||||
{
|
||||
llwarns << "The SSL/TLS handshake never occurred according to the timings!" << llendl;
|
||||
return;
|
||||
}
|
||||
// If appconnect_time is almost equal to connect_time, then it was just set because this is a connection re-use.
|
||||
if (appconnect_time - connect_time <= 1e-6)
|
||||
if (appconnect_time - connect_time <= 1e-5)
|
||||
{
|
||||
llinfos << "Connection with HTTP server was already established; this was a re-used connection." << llendl;
|
||||
}
|
||||
@@ -2043,7 +2074,7 @@ void HTTPTimeout::print_diagnostics(CurlEasyRequest const* curl_easy_request, ch
|
||||
llwarns << "The transfer never happened because there was too much in the pipeline (apparently)." << llendl;
|
||||
return;
|
||||
}
|
||||
else if (pretransfer_time - appconnect_time >= 1e-6)
|
||||
else if (pretransfer_time - appconnect_time >= 1e-5)
|
||||
{
|
||||
llinfos << "Apparently there was a delay, due to waits in line for the pipeline, of " << (pretransfer_time - appconnect_time) << " seconds before the transfer began." << llendl;
|
||||
}
|
||||
@@ -2123,10 +2154,14 @@ void stopCurlThread(void)
|
||||
ms_sleep(10);
|
||||
}
|
||||
Dout(dc::curl, "Curl thread" << (curlThreadIsRunning() ? " not" : "") << " stopped after " << ((100 - count) * 10) << "ms.");
|
||||
// Clear the command queue, for a cleaner cleanup.
|
||||
}
|
||||
}
|
||||
|
||||
void clearCommandQueue(void)
|
||||
{
|
||||
// Clear the command queue now in order to avoid the global deinitialization order fiasco.
|
||||
command_queue_wat command_queue_w(command_queue);
|
||||
command_queue_w->clear();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -2240,11 +2275,8 @@ size_t BufferedCurlEasyRequest::curlReadCallback(char* data, size_t size, size_t
|
||||
S32 bytes = size * nmemb; // The maximum amount to read.
|
||||
self_w->mLastRead = self_w->getInput()->readAfter(sChannels.out(), self_w->mLastRead, (U8*)data, bytes);
|
||||
self_w->mRequestTransferedBytes += bytes; // Accumulate data sent to the server.
|
||||
// Timeout administration. Note that it can happen that we get here
|
||||
// before the socket callback has been called, because the silly libcurl
|
||||
// writes headers without informing us. In that case it's OK to create
|
||||
// the Timeout object on the fly, so pass lockobj.
|
||||
if (self_w->httptimeout(lockobj)->data_sent(bytes))
|
||||
// Timeout administration.
|
||||
if (self_w->httptimeout()->data_sent(bytes))
|
||||
{
|
||||
// Transfer timed out. Return CURL_READFUNC_ABORT which will abort with error CURLE_ABORTED_BY_CALLBACK.
|
||||
return CURL_READFUNC_ABORT;
|
||||
@@ -2337,10 +2369,10 @@ size_t BufferedCurlEasyRequest::curlHeaderCallback(char* data, size_t size, size
|
||||
#if defined(CWDEBUG) || defined(DEBUG_CURLIO)
|
||||
int debug_callback(CURL*, curl_infotype infotype, char* buf, size_t size, void* user_ptr)
|
||||
{
|
||||
BufferedCurlEasyRequest* request = (BufferedCurlEasyRequest*)user_ptr;
|
||||
|
||||
#ifdef CWDEBUG
|
||||
using namespace ::libcwd;
|
||||
|
||||
BufferedCurlEasyRequest* request = (BufferedCurlEasyRequest*)user_ptr;
|
||||
std::ostringstream marker;
|
||||
marker << (void*)request->get_lockobj();
|
||||
libcw_do.push_marker();
|
||||
|
||||
@@ -624,7 +624,7 @@ void debug_curl_easy_reset(CURL* handle)
|
||||
|
||||
CURLcode debug_curl_easy_setopt(CURL* handle, CURLoption option, ...)
|
||||
{
|
||||
CURLcode ret;
|
||||
CURLcode ret = CURLE_UNKNOWN_OPTION; // Suppress compiler warning.
|
||||
va_list ap;
|
||||
union param_type {
|
||||
long along;
|
||||
@@ -841,7 +841,7 @@ CURLMcode debug_curl_multi_remove_handle(CURLM* multi_handle, CURL* easy_handle)
|
||||
|
||||
CURLMcode debug_curl_multi_setopt(CURLM* multi_handle, CURLMoption option, ...)
|
||||
{
|
||||
CURLMcode ret;
|
||||
CURLMcode ret = CURLM_UNKNOWN_OPTION; // Suppress compiler warning.
|
||||
va_list ap;
|
||||
union param_type {
|
||||
long along;
|
||||
|
||||
@@ -71,7 +71,7 @@ void LLStyle::drawControl(ControlElement element, const QStyleOption *option, QP
|
||||
QPlastiqueStyle::drawControl(element, &localOption, painter, widget);
|
||||
return;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -1381,74 +1381,28 @@ LLQuaternion LLManipRotate::dragConstrained( S32 x, S32 y )
|
||||
BOOL hit = getMousePointOnPlaneAgent(projected_mouse, x, y, snap_plane_center, constraint_axis);
|
||||
projected_mouse -= snap_plane_center;
|
||||
|
||||
S32 snap_plane = 0;
|
||||
|
||||
F32 dot = cam_to_snap_plane * constraint_axis;
|
||||
if (llabs(dot) < 0.01f)
|
||||
{
|
||||
// looking at ring edge on, project onto view plane and check if mouse is past ring
|
||||
getMousePointOnPlaneAgent(projected_mouse, x, y, snap_plane_center, cam_to_snap_plane);
|
||||
projected_mouse -= snap_plane_center;
|
||||
dot = projected_mouse * constraint_axis;
|
||||
if (projected_mouse * constraint_axis > 0)
|
||||
{
|
||||
snap_plane = 1;
|
||||
}
|
||||
projected_mouse -= dot * constraint_axis;
|
||||
}
|
||||
else if (dot > 0.f)
|
||||
{
|
||||
// look for mouse position outside and in front of snap circle
|
||||
if (hit && projected_mouse.magVec() > SNAP_GUIDE_INNER_RADIUS * mRadiusMeters && projected_mouse * cam_to_snap_plane < 0.f)
|
||||
{
|
||||
snap_plane = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// look for mouse position inside or in back of snap circle
|
||||
if (projected_mouse.magVec() < SNAP_GUIDE_INNER_RADIUS * mRadiusMeters || projected_mouse * cam_to_snap_plane > 0.f || !hit)
|
||||
{
|
||||
snap_plane = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (snap_plane == 0)
|
||||
{
|
||||
// try other plane
|
||||
snap_plane_center = (center - (constraint_axis * mRadiusMeters * 0.5f));
|
||||
if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
|
||||
{
|
||||
cam_to_snap_plane.setVec(1.f, 0.f, 0.f);
|
||||
}
|
||||
else
|
||||
{
|
||||
cam_to_snap_plane = snap_plane_center - gAgentCamera.getCameraPositionAgent();
|
||||
cam_to_snap_plane.normVec();
|
||||
}
|
||||
|
||||
hit = getMousePointOnPlaneAgent(projected_mouse, x, y, snap_plane_center, constraint_axis);
|
||||
projected_mouse -= snap_plane_center;
|
||||
|
||||
dot = cam_to_snap_plane * constraint_axis;
|
||||
if (gSavedSettings.getBOOL("SnapEnabled")) {
|
||||
S32 snap_plane = 0;
|
||||
|
||||
F32 dot = cam_to_snap_plane * constraint_axis;
|
||||
if (llabs(dot) < 0.01f)
|
||||
{
|
||||
// looking at ring edge on, project onto view plane and check if mouse is past ring
|
||||
getMousePointOnPlaneAgent(projected_mouse, x, y, snap_plane_center, cam_to_snap_plane);
|
||||
projected_mouse -= snap_plane_center;
|
||||
dot = projected_mouse * constraint_axis;
|
||||
if (projected_mouse * constraint_axis < 0)
|
||||
if (projected_mouse * constraint_axis > 0)
|
||||
{
|
||||
snap_plane = 2;
|
||||
snap_plane = 1;
|
||||
}
|
||||
projected_mouse -= dot * constraint_axis;
|
||||
}
|
||||
else if (dot < 0.f)
|
||||
else if (dot > 0.f)
|
||||
{
|
||||
// look for mouse position outside and in front of snap circle
|
||||
if (hit && projected_mouse.magVec() > SNAP_GUIDE_INNER_RADIUS * mRadiusMeters && projected_mouse * cam_to_snap_plane < 0.f)
|
||||
{
|
||||
snap_plane = 2;
|
||||
snap_plane = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1456,78 +1410,136 @@ LLQuaternion LLManipRotate::dragConstrained( S32 x, S32 y )
|
||||
// look for mouse position inside or in back of snap circle
|
||||
if (projected_mouse.magVec() < SNAP_GUIDE_INNER_RADIUS * mRadiusMeters || projected_mouse * cam_to_snap_plane > 0.f || !hit)
|
||||
{
|
||||
snap_plane = 2;
|
||||
snap_plane = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (snap_plane > 0)
|
||||
{
|
||||
LLVector3 cam_at_axis;
|
||||
if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
|
||||
|
||||
if (snap_plane == 0)
|
||||
{
|
||||
cam_at_axis.setVec(1.f, 0.f, 0.f);
|
||||
// try other plane
|
||||
snap_plane_center = (center - (constraint_axis * mRadiusMeters * 0.5f));
|
||||
if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
|
||||
{
|
||||
cam_to_snap_plane.setVec(1.f, 0.f, 0.f);
|
||||
}
|
||||
else
|
||||
{
|
||||
cam_to_snap_plane = snap_plane_center - gAgentCamera.getCameraPositionAgent();
|
||||
cam_to_snap_plane.normVec();
|
||||
}
|
||||
|
||||
hit = getMousePointOnPlaneAgent(projected_mouse, x, y, snap_plane_center, constraint_axis);
|
||||
projected_mouse -= snap_plane_center;
|
||||
|
||||
dot = cam_to_snap_plane * constraint_axis;
|
||||
if (llabs(dot) < 0.01f)
|
||||
{
|
||||
// looking at ring edge on, project onto view plane and check if mouse is past ring
|
||||
getMousePointOnPlaneAgent(projected_mouse, x, y, snap_plane_center, cam_to_snap_plane);
|
||||
projected_mouse -= snap_plane_center;
|
||||
dot = projected_mouse * constraint_axis;
|
||||
if (projected_mouse * constraint_axis < 0)
|
||||
{
|
||||
snap_plane = 2;
|
||||
}
|
||||
projected_mouse -= dot * constraint_axis;
|
||||
}
|
||||
else if (dot < 0.f)
|
||||
{
|
||||
// look for mouse position outside and in front of snap circle
|
||||
if (hit && projected_mouse.magVec() > SNAP_GUIDE_INNER_RADIUS * mRadiusMeters && projected_mouse * cam_to_snap_plane < 0.f)
|
||||
{
|
||||
snap_plane = 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// look for mouse position inside or in back of snap circle
|
||||
if (projected_mouse.magVec() < SNAP_GUIDE_INNER_RADIUS * mRadiusMeters || projected_mouse * cam_to_snap_plane > 0.f || !hit)
|
||||
{
|
||||
snap_plane = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cam_at_axis = snap_plane_center - gAgentCamera.getCameraPositionAgent();
|
||||
cam_at_axis.normVec();
|
||||
}
|
||||
|
||||
// first, project mouse onto screen plane at point tangent to rotation radius.
|
||||
getMousePointOnPlaneAgent(projected_mouse, x, y, snap_plane_center, cam_at_axis);
|
||||
// project that point onto rotation plane
|
||||
projected_mouse -= snap_plane_center;
|
||||
projected_mouse -= projected_vec(projected_mouse, constraint_axis);
|
||||
|
||||
F32 mouse_lateral_dist = llmin(SNAP_GUIDE_INNER_RADIUS * mRadiusMeters, projected_mouse.magVec());
|
||||
F32 mouse_depth = SNAP_GUIDE_INNER_RADIUS * mRadiusMeters;
|
||||
if (llabs(mouse_lateral_dist) > 0.01f)
|
||||
{
|
||||
mouse_depth = sqrtf((SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) * (SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) -
|
||||
(mouse_lateral_dist * mouse_lateral_dist));
|
||||
}
|
||||
LLVector3 projected_camera_at = cam_at_axis - projected_vec(cam_at_axis, constraint_axis);
|
||||
projected_mouse -= mouse_depth * projected_camera_at;
|
||||
|
||||
if (!mInSnapRegime)
|
||||
{
|
||||
mSmoothRotate = TRUE;
|
||||
}
|
||||
mInSnapRegime = TRUE;
|
||||
// 0 to 360 deg
|
||||
F32 mouse_angle = fmodf(atan2(projected_mouse * axis1, projected_mouse * axis2) * RAD_TO_DEG + 360.f, 360.f);
|
||||
|
||||
F32 relative_mouse_angle = fmodf(mouse_angle + (SNAP_ANGLE_DETENTE / 2), SNAP_ANGLE_INCREMENT);
|
||||
//fmodf(llround(mouse_angle * RAD_TO_DEG, 7.5f) + 360.f, 360.f);
|
||||
|
||||
LLVector3 object_axis;
|
||||
getObjectAxisClosestToMouse(object_axis);
|
||||
object_axis = object_axis * first_object_node->mSavedRotation;
|
||||
|
||||
// project onto constraint plane
|
||||
object_axis = object_axis - (object_axis * getConstraintAxis()) * getConstraintAxis();
|
||||
object_axis.normVec();
|
||||
|
||||
if (relative_mouse_angle < SNAP_ANGLE_DETENTE)
|
||||
if (snap_plane > 0)
|
||||
{
|
||||
F32 quantized_mouse_angle = mouse_angle - (relative_mouse_angle - (SNAP_ANGLE_DETENTE * 0.5f));
|
||||
angle = (quantized_mouse_angle * DEG_TO_RAD) - atan2(object_axis * axis1, object_axis * axis2);
|
||||
LLVector3 cam_at_axis;
|
||||
if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
|
||||
{
|
||||
cam_at_axis.setVec(1.f, 0.f, 0.f);
|
||||
}
|
||||
else
|
||||
{
|
||||
cam_at_axis = snap_plane_center - gAgentCamera.getCameraPositionAgent();
|
||||
cam_at_axis.normVec();
|
||||
}
|
||||
|
||||
// first, project mouse onto screen plane at point tangent to rotation radius.
|
||||
getMousePointOnPlaneAgent(projected_mouse, x, y, snap_plane_center, cam_at_axis);
|
||||
// project that point onto rotation plane
|
||||
projected_mouse -= snap_plane_center;
|
||||
projected_mouse -= projected_vec(projected_mouse, constraint_axis);
|
||||
|
||||
F32 mouse_lateral_dist = llmin(SNAP_GUIDE_INNER_RADIUS * mRadiusMeters, projected_mouse.magVec());
|
||||
F32 mouse_depth = SNAP_GUIDE_INNER_RADIUS * mRadiusMeters;
|
||||
if (llabs(mouse_lateral_dist) > 0.01f)
|
||||
{
|
||||
mouse_depth = sqrtf((SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) * (SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) -
|
||||
(mouse_lateral_dist * mouse_lateral_dist));
|
||||
}
|
||||
LLVector3 projected_camera_at = cam_at_axis - projected_vec(cam_at_axis, constraint_axis);
|
||||
projected_mouse -= mouse_depth * projected_camera_at;
|
||||
|
||||
if (!mInSnapRegime)
|
||||
{
|
||||
mSmoothRotate = TRUE;
|
||||
}
|
||||
mInSnapRegime = TRUE;
|
||||
// 0 to 360 deg
|
||||
F32 mouse_angle = fmodf(atan2(projected_mouse * axis1, projected_mouse * axis2) * RAD_TO_DEG + 360.f, 360.f);
|
||||
|
||||
F32 relative_mouse_angle = fmodf(mouse_angle + (SNAP_ANGLE_DETENTE / 2), SNAP_ANGLE_INCREMENT);
|
||||
//fmodf(llround(mouse_angle * RAD_TO_DEG, 7.5f) + 360.f, 360.f);
|
||||
|
||||
LLVector3 object_axis;
|
||||
getObjectAxisClosestToMouse(object_axis);
|
||||
object_axis = object_axis * first_object_node->mSavedRotation;
|
||||
|
||||
// project onto constraint plane
|
||||
object_axis = object_axis - (object_axis * getConstraintAxis()) * getConstraintAxis();
|
||||
object_axis.normVec();
|
||||
|
||||
if (relative_mouse_angle < SNAP_ANGLE_DETENTE)
|
||||
{
|
||||
F32 quantized_mouse_angle = mouse_angle - (relative_mouse_angle - (SNAP_ANGLE_DETENTE * 0.5f));
|
||||
angle = (quantized_mouse_angle * DEG_TO_RAD) - atan2(object_axis * axis1, object_axis * axis2);
|
||||
}
|
||||
else
|
||||
{
|
||||
angle = (mouse_angle * DEG_TO_RAD) - atan2(object_axis * axis1, object_axis * axis2);
|
||||
}
|
||||
return LLQuaternion( -angle, constraint_axis );
|
||||
}
|
||||
else
|
||||
{
|
||||
angle = (mouse_angle * DEG_TO_RAD) - atan2(object_axis * axis1, object_axis * axis2);
|
||||
if (mInSnapRegime)
|
||||
{
|
||||
mSmoothRotate = TRUE;
|
||||
}
|
||||
mInSnapRegime = FALSE;
|
||||
}
|
||||
return LLQuaternion( -angle, constraint_axis );
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
if (mInSnapRegime)
|
||||
{
|
||||
mSmoothRotate = TRUE;
|
||||
}
|
||||
mInSnapRegime = FALSE;
|
||||
|
||||
}
|
||||
|
||||
if (!mInSnapRegime)
|
||||
{
|
||||
LLVector3 up_from_axis = mCenterToCamNorm % constraint_axis;
|
||||
up_from_axis.normVec();
|
||||
LLVector3 cur_intersection;
|
||||
|
||||
Reference in New Issue
Block a user