Compare commits
108 Commits
1.7.3
...
meshupload
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5c8e436401 | ||
|
|
4d805da6ac | ||
|
|
085800f6e0 | ||
|
|
1934fc9bd4 | ||
|
|
8c1848b487 | ||
|
|
8edb10fb88 | ||
|
|
8aecc49456 | ||
|
|
b8919c21d8 | ||
|
|
9203b24eb9 | ||
|
|
8584e6da4c | ||
|
|
1d673df1bd | ||
|
|
b3adf71ed7 | ||
|
|
7ba0b6482c | ||
|
|
e99175444f | ||
|
|
d5ed31ca9b | ||
|
|
1c8027b1e6 | ||
|
|
ebac80b5b7 | ||
|
|
c528a15e95 | ||
|
|
6dc4a60724 | ||
|
|
f6785c399d | ||
|
|
237f84cde0 | ||
|
|
485ad8e645 | ||
|
|
a1fa43850b | ||
|
|
5e799b1f81 | ||
|
|
0296812e88 | ||
|
|
d8c846288e | ||
|
|
dd1e9a68d4 | ||
|
|
21860ded90 | ||
|
|
48113f8506 | ||
|
|
db7155666d | ||
|
|
b758014ebc | ||
|
|
18816ae146 | ||
|
|
dc106c5442 | ||
|
|
aa3228be76 | ||
|
|
c2ce72ed94 | ||
|
|
a6c2d256c6 | ||
|
|
8bc05f6d15 | ||
|
|
3091d9c847 | ||
|
|
d1de4d53fe | ||
|
|
c08c2a55e5 | ||
|
|
188e42ee4a | ||
|
|
f606477ae5 | ||
|
|
5250b218c5 | ||
|
|
909247a179 | ||
|
|
e7dea2714e | ||
|
|
db17b93156 | ||
|
|
e622e03d2a | ||
|
|
5b0597ea47 | ||
|
|
5f3ca7fda0 | ||
|
|
85855ecd85 | ||
|
|
cbfd31a576 | ||
|
|
c9954cf14e | ||
|
|
7ca974f731 | ||
|
|
54771409d6 | ||
|
|
7aa95debf1 | ||
|
|
f178de2ff8 | ||
|
|
2d9402fd2d | ||
|
|
10c19731b3 | ||
|
|
8889f6b837 | ||
|
|
ca746f3b47 | ||
|
|
9f7e81cec2 | ||
|
|
bc3ad59dd5 | ||
|
|
979adcd6e2 | ||
|
|
c5c1294d7d | ||
|
|
0ce91ce5ed | ||
|
|
b76cb36c0f | ||
|
|
8346ce4cd8 | ||
|
|
e565341e90 | ||
|
|
1b2c0ba02b | ||
|
|
cbbe678f9e | ||
|
|
5efcc7186e | ||
|
|
d188ecae70 | ||
|
|
d71210e942 | ||
|
|
9c20139ae8 | ||
|
|
da19e770a2 | ||
|
|
5e7acb9f3a | ||
|
|
6d379448be | ||
|
|
79763aacf7 | ||
|
|
e7ef9eff4f | ||
|
|
9e2049c463 | ||
|
|
8aa7113480 | ||
|
|
b1b9172f28 | ||
|
|
3a691e0c23 | ||
|
|
e7f4fc7107 | ||
|
|
ac60260da2 | ||
|
|
364cf1ec73 | ||
|
|
297c386b16 | ||
|
|
152a3685fa | ||
|
|
bb7464a975 | ||
|
|
9c1237ca05 | ||
|
|
69e0738096 | ||
|
|
cadf654fae | ||
|
|
0b31537bfe | ||
|
|
776a977824 | ||
|
|
5cf091b8b2 | ||
|
|
bea4bc6a1a | ||
|
|
9596514c79 | ||
|
|
5ada2d4b6f | ||
|
|
dd15b9234f | ||
|
|
d03d145be4 | ||
|
|
1083d7e0ef | ||
|
|
cdaa4b4e99 | ||
|
|
295fcb53b0 | ||
|
|
389c35e08e | ||
|
|
003aa6a4eb | ||
|
|
f9d205b869 | ||
|
|
e08afcb963 | ||
|
|
5e71d9578f |
@@ -663,7 +663,7 @@
|
||||
<boolean>false</boolean>
|
||||
|
||||
<key>RequestTextureDownload</key>
|
||||
<boolean>false</boolean>
|
||||
<boolean>true</boolean>
|
||||
|
||||
<key>EventQueueGet</key>
|
||||
<boolean>false</boolean>
|
||||
@@ -715,6 +715,9 @@
|
||||
|
||||
<key>FetchLib2</key>
|
||||
<boolean>true</boolean>
|
||||
|
||||
<key>UploadBakedTexture</key>
|
||||
<boolean>true</boolean>
|
||||
</map>
|
||||
|
||||
<key>messageBans</key>
|
||||
|
||||
@@ -30,7 +30,7 @@ include(BuildVersion)
|
||||
|
||||
include(UnixInstall)
|
||||
|
||||
set (DISABLE_FATAL_WARNINGS TRUE)
|
||||
set (DISABLE_FATAL_WARNINGS CACHE BOOL TRUE)
|
||||
|
||||
if (NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE Release CACHE STRING
|
||||
@@ -48,10 +48,14 @@ add_custom_target(prepare DEPENDS ${prepare_depends})
|
||||
add_subdirectory(cmake)
|
||||
add_subdirectory(${LIBS_OPEN_PREFIX}aistatemachine)
|
||||
add_subdirectory(${LIBS_OPEN_PREFIX}llaudio)
|
||||
add_subdirectory(${LIBS_OPEN_PREFIX}llappearance)
|
||||
add_subdirectory(${LIBS_OPEN_PREFIX}llcharacter)
|
||||
add_subdirectory(${LIBS_OPEN_PREFIX}llcommon)
|
||||
add_subdirectory(${LIBS_OPEN_PREFIX}llimage)
|
||||
add_subdirectory(${LIBS_OPEN_PREFIX}libopenjpeg)
|
||||
add_subdirectory(${LIBS_OPEN_PREFIX}libhacd)
|
||||
add_subdirectory(${LIBS_OPEN_PREFIX}libndhacd)
|
||||
add_subdirectory(${LIBS_OPEN_PREFIX}libpathing)
|
||||
add_subdirectory(${LIBS_OPEN_PREFIX}llimagej2coj)
|
||||
add_subdirectory(${LIBS_OPEN_PREFIX}llinventory)
|
||||
add_subdirectory(${LIBS_OPEN_PREFIX}llmath)
|
||||
|
||||
@@ -19,6 +19,7 @@ include_directories(
|
||||
|
||||
set(aistatemachine_SOURCE_FILES
|
||||
aistatemachine.cpp
|
||||
aistatemachinethread.cpp
|
||||
aitimer.cpp
|
||||
)
|
||||
|
||||
@@ -26,6 +27,7 @@ set(aistatemachine_HEADER_FILES
|
||||
CMakeLists.txt
|
||||
|
||||
aistatemachine.h
|
||||
aistatemachinethread.h
|
||||
aitimer.h
|
||||
)
|
||||
|
||||
|
||||
@@ -176,7 +176,7 @@ void AIStateMachine::idle(state_type current_run_state)
|
||||
// About thread safeness:
|
||||
//
|
||||
// The main thread initializes a statemachine and calls run, so a statemachine
|
||||
// runs in the main thread. However, it is allowed that a state calls idle()
|
||||
// runs in the main thread. However, it is allowed that a state calls idle(current_state)
|
||||
// and then allows one or more other threads to call cont() upon some
|
||||
// event (only once, of course, as idle() has to be called before cont()
|
||||
// can be called again-- and a non-main thread is not allowed to call idle()).
|
||||
|
||||
@@ -264,7 +264,7 @@ class AIStateMachine {
|
||||
//! Halt the state machine until cont() is called (not thread-safe).
|
||||
void idle(void);
|
||||
|
||||
//! Halt the state machine until cont() is called, provided it is still in 'cur_run_state'.
|
||||
//! Halt the state machine until cont() is called, provided it is still in 'current_run_state'.
|
||||
void idle(state_type current_run_state);
|
||||
|
||||
//! Temporarily halt the state machine.
|
||||
|
||||
197
indra/aistatemachine/aistatemachinethread.cpp
Normal file
197
indra/aistatemachine/aistatemachinethread.cpp
Normal file
@@ -0,0 +1,197 @@
|
||||
/**
|
||||
* @file aistatemachinethread.cpp
|
||||
* @brief Implementation of AIStateMachineThread
|
||||
*
|
||||
* Copyright (c) 2013, Aleric Inglewood.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution.
|
||||
*
|
||||
* CHANGELOG
|
||||
* and additional copyright holders.
|
||||
*
|
||||
* 23/01/2013
|
||||
* Initial version, written by Aleric Inglewood @ SL
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
#include "aistatemachinethread.h"
|
||||
|
||||
class AIStateMachineThreadBase::Thread : public LLThread {
|
||||
private:
|
||||
LLPointer<AIThreadImpl> mImpl;
|
||||
bool mNeedCleanup;
|
||||
public:
|
||||
Thread(AIThreadImpl* impl) :
|
||||
#ifdef LL_DEBUG
|
||||
LLThread(impl->getName()),
|
||||
#else
|
||||
LLThread("AIStateMachineThreadBase::Thread"),
|
||||
#endif
|
||||
mImpl(impl) { }
|
||||
protected:
|
||||
/*virtual*/ void run(void)
|
||||
{
|
||||
mNeedCleanup = mImpl->thread_done(mImpl->run());
|
||||
}
|
||||
/*virtual*/ void terminated(void)
|
||||
{
|
||||
mStatus = STOPPED;
|
||||
if (mNeedCleanup)
|
||||
{
|
||||
// The state machine that started us has disappeared! Clean up ourselves.
|
||||
|
||||
// This is OK now because in our case nobody is watching us and having set
|
||||
// the status to STOPPED didn't change anything really, although it will
|
||||
// prevent LLThread::shutdown from blocking a whole minute and then calling
|
||||
// apr_thread_exit to never return! Normally, the LLThread might be deleted
|
||||
// immediately (by the main thread) after setting mStatus to STOPPED.
|
||||
Thread::completed(this);
|
||||
}
|
||||
}
|
||||
public:
|
||||
// TODO: Implement a thread pool. For now, just create a new one every time.
|
||||
static Thread* allocate(AIThreadImpl* impl) { return new Thread(impl); }
|
||||
static void completed(Thread* threadp) { delete threadp; }
|
||||
};
|
||||
|
||||
// MAIN THREAD
|
||||
|
||||
char const* AIStateMachineThreadBase::state_str_impl(state_type run_state) const
|
||||
{
|
||||
switch(run_state)
|
||||
{
|
||||
AI_CASE_RETURN(start_thread);
|
||||
AI_CASE_RETURN(wait_stopped);
|
||||
}
|
||||
return "UNKNOWN STATE";
|
||||
}
|
||||
|
||||
void AIStateMachineThreadBase::initialize_impl(void)
|
||||
{
|
||||
mThread = NULL;
|
||||
mAbort = false;
|
||||
set_state(start_thread);
|
||||
}
|
||||
|
||||
void AIStateMachineThreadBase::multiplex_impl(void)
|
||||
{
|
||||
switch(mRunState)
|
||||
{
|
||||
case start_thread:
|
||||
mThread = Thread::allocate(mImpl);
|
||||
// Set next state.
|
||||
set_state(wait_stopped);
|
||||
idle(wait_stopped); // Wait till the thread returns.
|
||||
mThread->start();
|
||||
break;
|
||||
case wait_stopped:
|
||||
if (!mThread->isStopped())
|
||||
break;
|
||||
// We're done!
|
||||
//
|
||||
// We can only get here when AIThreadImpl::done called cont(), (very
|
||||
// shortly after which it will be STOPPED), which means we need to do
|
||||
// the clean up of the thread.
|
||||
// Also, the thread has really stopped now, so it's safe to delete it.
|
||||
//
|
||||
// Clean up the thread.
|
||||
Thread::completed(mThread);
|
||||
mThread = NULL; // Stop abort_impl() from doing anything.
|
||||
if (mAbort)
|
||||
abort();
|
||||
else
|
||||
finish();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void AIStateMachineThreadBase::abort_impl(void)
|
||||
{
|
||||
if (mThread)
|
||||
{
|
||||
// If this AIStateMachineThreadBase still exists then the first base class of
|
||||
// AIStateMachineThread<THREAD_IMPL>, LLPointer<THREAD_IMPL>, also still exists
|
||||
// and therefore mImpl is valid.
|
||||
bool need_cleanup = mImpl->state_machine_done(mThread); // Signal the fact that we aborted.
|
||||
if (need_cleanup)
|
||||
{
|
||||
// This is an unlikely race condition. We have been aborted by our parent,
|
||||
// but at the same time the thread finished!
|
||||
// We can only get here when AIThreadImpl::thread_done already returned
|
||||
// (VERY shortly after the thread will stop (if not already)).
|
||||
// Just go into a tight loop while waiting for that, when it is safe
|
||||
// to clean up the thread.
|
||||
while (!mThread->isStopped())
|
||||
{
|
||||
mThread->yield();
|
||||
}
|
||||
Thread::completed(mThread);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The thread is still happily running (and will clean up itself).
|
||||
// Lets make sure we're not flooded with this situation.
|
||||
llwarns << "Thread state machine aborted while the thread is still running. That is a waste of CPU and should be avoided." << llendl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool AIThreadImpl::state_machine_done(LLThread* threadp)
|
||||
{
|
||||
StateMachineThread_wat state_machine_thread_w(mStateMachineThread);
|
||||
AIStateMachineThreadBase* state_machine_thread = *state_machine_thread_w;
|
||||
bool need_cleanup = !state_machine_thread;
|
||||
if (!need_cleanup)
|
||||
{
|
||||
// If state_machine_thread is non-NULL, then AIThreadImpl::thread_done wasnt called yet
|
||||
// (or at least didn't return yet) which means the thread is still running.
|
||||
// Try telling the thread that it can stop.
|
||||
threadp->setQuitting();
|
||||
// Finally, mark that we are NOT going to do the cleanup by setting mStateMachineThread to NULL.
|
||||
*state_machine_thread_w = NULL;
|
||||
}
|
||||
return need_cleanup;
|
||||
}
|
||||
|
||||
// AIStateMachineThread THREAD
|
||||
|
||||
bool AIThreadImpl::thread_done(bool result)
|
||||
{
|
||||
StateMachineThread_wat state_machine_thread_w(mStateMachineThread);
|
||||
AIStateMachineThreadBase* state_machine_thread = *state_machine_thread_w;
|
||||
bool need_cleanup = !state_machine_thread;
|
||||
if (!need_cleanup)
|
||||
{
|
||||
// If state_machine_thread is non-NULL then AIThreadImpl::abort_impl wasn't called,
|
||||
// which means the state machine still exists. In fact, it should be in the waiting() state.
|
||||
// It can also happen that the state machine is being aborted right now (but it will still exist).
|
||||
// (Note that waiting() and running() aren't strictly thread-safe (we should really lock
|
||||
// mSetStateLock here) but by first calling waiting() and then running(), and assuming that
|
||||
// changing an int from the value 1 to the value 2 is atomic, this will work since the
|
||||
// only possible transition is from waiting to not running).
|
||||
llassert(state_machine_thread->waiting() || !state_machine_thread->running());
|
||||
state_machine_thread->schedule_abort(!result);
|
||||
// Note that if the state machine is not running (being aborted, ie - hanging in abort_impl
|
||||
// waiting for the lock on mStateMachineThread) then this is simply ignored.
|
||||
state_machine_thread->cont();
|
||||
// Finally, mark that we are NOT going to do the cleanup by setting mStateMachineThread to NULL.
|
||||
*state_machine_thread_w = NULL;
|
||||
}
|
||||
return need_cleanup;
|
||||
}
|
||||
|
||||
229
indra/aistatemachine/aistatemachinethread.h
Normal file
229
indra/aistatemachine/aistatemachinethread.h
Normal file
@@ -0,0 +1,229 @@
|
||||
/**
|
||||
* @file aistatemachinethread.h
|
||||
* @brief Run code in a thread.
|
||||
*
|
||||
* Copyright (c) 2013, Aleric Inglewood.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution.
|
||||
*
|
||||
* CHANGELOG
|
||||
* and additional copyright holders.
|
||||
*
|
||||
* 23/01/2013
|
||||
* Initial version, written by Aleric Inglewood @ SL
|
||||
*/
|
||||
|
||||
#ifndef AISTATEMACHINETHREAD_H
|
||||
#define AISTATEMACHINETHREAD_H
|
||||
|
||||
#include "aistatemachine.h"
|
||||
#include "llthread.h"
|
||||
#include "aithreadsafe.h"
|
||||
|
||||
#ifdef EXAMPLE_CODE // undefined
|
||||
|
||||
class HelloWorldThread : public AIThreadImpl {
|
||||
private:
|
||||
bool mStdErr; // input
|
||||
bool mSuccess; // output
|
||||
|
||||
public:
|
||||
// Constructor.
|
||||
HelloWorldThread(void) : AIThreadImpl("HelloWorldThread"), // MAIN THREAD
|
||||
mStdErr(false), mSuccess(false) { }
|
||||
|
||||
// Some initialization function (if needed).
|
||||
void init(bool err) { mStdErr = err; } // MAIN THREAD
|
||||
// Read back output.
|
||||
bool successful(void) const { return mSuccess; }
|
||||
|
||||
// Mandatory signature.
|
||||
/*virtual*/ bool run(void) // NEW THREAD
|
||||
{
|
||||
if (mStdErr)
|
||||
std::cerr << "Hello world" << std::endl;
|
||||
else
|
||||
std::cout << "Hello world" << std::endl;
|
||||
mSuccess = true;
|
||||
return true; // true = finish, false = abort.
|
||||
}
|
||||
};
|
||||
|
||||
// The states of this state machine.
|
||||
enum hello_world_state_type {
|
||||
HelloWorld_start = AIStateMachine::max_state,
|
||||
HelloWorld_done
|
||||
};
|
||||
|
||||
// The statemachine class (this is almost a template).
|
||||
class HelloWorld : public AIStateMachine {
|
||||
private:
|
||||
AIStateMachineThread<HelloWorldThread> mHelloWorld;
|
||||
bool mErr;
|
||||
|
||||
public:
|
||||
HelloWorld() : mErr(false) { }
|
||||
|
||||
// Print to stderr or stdout?
|
||||
void init(bool err) { mErr = err; }
|
||||
|
||||
protected:
|
||||
// Call finish() (or abort()), not delete.
|
||||
/*virtual*/ ~HelloWorld() { }
|
||||
|
||||
// Handle initializing the object.
|
||||
/*virtual*/ void initialize_impl(void);
|
||||
|
||||
// Handle mRunState.
|
||||
/*virtual*/ void multiplex_impl(void);
|
||||
|
||||
// Handle aborting from current bs_run state.
|
||||
/*virtual*/ void abort_impl(void) { }
|
||||
|
||||
// Handle cleaning up from initialization (or post abort) state.
|
||||
/*virtual*/ void finish_impl(void)
|
||||
{
|
||||
// Kill object by default.
|
||||
// This can be overridden by calling run() from the callback function.
|
||||
kill();
|
||||
}
|
||||
|
||||
// Implemenation of state_str for run states.
|
||||
/*virtual*/ char const* state_str_impl(state_type run_state) const
|
||||
{
|
||||
switch(run_state)
|
||||
{
|
||||
AI_CASE_RETURN(HelloWorld_start);
|
||||
AI_CASE_RETURN(HelloWorld_done);
|
||||
}
|
||||
return "UNKNOWN STATE";
|
||||
}
|
||||
};
|
||||
|
||||
// The actual implementation of this statemachine starts here!
|
||||
|
||||
void HelloWorld::initialize_impl(void)
|
||||
{
|
||||
mHelloWorld->init(mErr); // Initialize the thread object.
|
||||
set_state(HelloWorld_start);
|
||||
}
|
||||
|
||||
void HelloWorld::multiplex_impl(void)
|
||||
{
|
||||
switch (mRunState)
|
||||
{
|
||||
case HelloWorld_start:
|
||||
{
|
||||
mHelloWorld.run(this, HelloWorld_done); // Run HelloWorldThread and set the state of 'this' to HelloWorld_done when finished.
|
||||
idle(HelloWorld_start); // Always go idle after starting a thread!
|
||||
break;
|
||||
}
|
||||
case HelloWorld_done:
|
||||
{
|
||||
// We're done. Lets also abort when the thread reported no success.
|
||||
if (mHelloWorld->successful()) // Read output/result of thread object.
|
||||
finish();
|
||||
else
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // EXAMPLE CODE
|
||||
|
||||
class AIStateMachineThreadBase;
|
||||
|
||||
// Derive from this to implement the code that must run in another thread.
|
||||
class AIThreadImpl : public LLThreadSafeRefCount {
|
||||
private:
|
||||
template<typename THREAD_IMPL> friend struct AIStateMachineThread;
|
||||
typedef AIAccess<AIStateMachineThreadBase*> StateMachineThread_wat;
|
||||
AIThreadSafeSimpleDC<AIStateMachineThreadBase*> mStateMachineThread;
|
||||
|
||||
public:
|
||||
virtual bool run(void) = 0;
|
||||
bool thread_done(bool result);
|
||||
bool state_machine_done(LLThread* threadp);
|
||||
|
||||
#ifdef LL_DEBUG
|
||||
private:
|
||||
char const* mName;
|
||||
protected:
|
||||
AIThreadImpl(char const* name = "AIStateMachineThreadBase::Thread") : mName(name) { }
|
||||
public:
|
||||
char const* getName(void) const { return mName; }
|
||||
#endif
|
||||
};
|
||||
|
||||
// The base class for statemachine threads.
|
||||
class AIStateMachineThreadBase : public AIStateMachine {
|
||||
private:
|
||||
// The actual thread (derived from LLThread).
|
||||
class Thread;
|
||||
|
||||
// The states of this state machine.
|
||||
enum thread_state_type {
|
||||
start_thread = AIStateMachine::max_state, // Start the thread (if necessary create it first).
|
||||
wait_stopped // Wait till the thread is stopped.
|
||||
};
|
||||
|
||||
protected:
|
||||
AIStateMachineThreadBase(AIThreadImpl* impl) : mImpl(impl) { }
|
||||
|
||||
private:
|
||||
// Handle initializing the object.
|
||||
/*virtual*/ void initialize_impl(void);
|
||||
|
||||
// Handle mRunState.
|
||||
/*virtual*/ void multiplex_impl(void);
|
||||
|
||||
// Handle aborting from current bs_run state.
|
||||
/*virtual*/ void abort_impl(void);
|
||||
|
||||
// Handle cleaning up from initialization (or post abort) state.
|
||||
/*virtual*/ void finish_impl(void) { }
|
||||
|
||||
// Implemenation of state_str for run states.
|
||||
/*virtual*/ char const* state_str_impl(state_type run_state) const;
|
||||
|
||||
private:
|
||||
Thread* mThread; // The thread that the code is run in.
|
||||
AIThreadImpl* mImpl; // Pointer to the implementation code that needs to be run in the thread.
|
||||
bool mAbort; // (Inverse of) return value of AIThreadImpl::run(). Only valid in state wait_stopped.
|
||||
|
||||
public:
|
||||
void schedule_abort(bool do_abort) { mAbort = do_abort; }
|
||||
|
||||
};
|
||||
|
||||
// The state machine that runs T::run() in a thread.
|
||||
// THREAD_IMPL Must be derived from AIThreadImpl.
|
||||
template<typename THREAD_IMPL>
|
||||
struct AIStateMachineThread : public LLPointer<THREAD_IMPL>, public AIStateMachineThreadBase {
|
||||
// Constructor.
|
||||
AIStateMachineThread(void) :
|
||||
LLPointer<THREAD_IMPL>(new THREAD_IMPL),
|
||||
AIStateMachineThreadBase(LLPointer<THREAD_IMPL>::get())
|
||||
{
|
||||
*AIThreadImpl::StateMachineThread_wat(static_cast<AIThreadImpl*>(LLPointer<THREAD_IMPL>::get())->mStateMachineThread) = this;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -23,28 +23,32 @@ set(CMAKE_CONFIGURATION_TYPES "RelWithDebInfo;Release;Debug" CACHE STRING
|
||||
# Platform-specific compilation flags.
|
||||
|
||||
if (WINDOWS)
|
||||
# Various libs are compiler specific, generate some variables here we can just use
|
||||
# when we require them instead of reimplementing the test each time.
|
||||
if (MSVC10)
|
||||
set(MSVC_DIR 10.0)
|
||||
set(MSVC_SUFFIX 100)
|
||||
endif (MSVC10)
|
||||
|
||||
# Remove default /Zm1000 flag that cmake inserts
|
||||
string (REPLACE "/Zm1000" " " CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
|
||||
|
||||
# Don't build DLLs.
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /Od /Zi /MDd /MP /arch:SSE2"
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /Od /Zi /MDd /MP"
|
||||
CACHE STRING "C++ compiler debug options" FORCE)
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO
|
||||
"${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Od /Zi /MD /MP /arch:SSE2"
|
||||
"${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Od /Zi /MD /MP"
|
||||
CACHE STRING "C++ compiler release-with-debug options" FORCE)
|
||||
set(CMAKE_CXX_FLAGS_RELEASE
|
||||
"${CMAKE_CXX_FLAGS_RELEASE} ${LL_CXX_FLAGS} /O2 /Zi /MD /MP /arch:SSE2 /fp:fast"
|
||||
"${CMAKE_CXX_FLAGS_RELEASE} ${LL_CXX_FLAGS} /O2 /Zi /MD /MP /fp:fast -D_SECURE_STL=0 -D_HAS_ITERATOR_DEBUGGING=0"
|
||||
CACHE STRING "C++ compiler release options" FORCE)
|
||||
set(CMAKE_C_FLAGS_RELEASE
|
||||
"${CMAKE_C_FLAGS_RELEASE} ${LL_C_FLAGS} /O2 /Zi /MD /MP /arch:SSE2 /fp:fast"
|
||||
"${CMAKE_C_FLAGS_RELEASE} ${LL_C_FLAGS} /O2 /Zi /MD /MP /fp:fast"
|
||||
CACHE STRING "C compiler release options" FORCE)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /LARGEADDRESSAWARE")
|
||||
|
||||
if(NOT CMAKE_EXE_LINKER_FLAGS_RELEASE MATCHES LARGEADDRESSAWARE)
|
||||
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LARGEADDRESSAWARE")
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_STANDARD_LIBRARIES "")
|
||||
set(CMAKE_C_STANDARD_LIBRARIES "")
|
||||
|
||||
@@ -57,54 +61,25 @@ if (WINDOWS)
|
||||
/W3
|
||||
/c
|
||||
/Zc:forScope
|
||||
/Zc:wchar_t-
|
||||
/nologo
|
||||
/Oy-
|
||||
/arch:SSE2
|
||||
)
|
||||
|
||||
|
||||
# configure win32 API for windows XP+ compatibility
|
||||
set(WINVER "0x0501" CACHE STRING "Win32 API Target version (see http://msdn.microsoft.com/en-us/library/aa383745%28v=VS.85%29.aspx)")
|
||||
add_definitions("/DWINVER=${WINVER}" "/D_WIN32_WINNT=${WINVER}")
|
||||
|
||||
if(MSVC80 OR MSVC90 OR MSVC10)
|
||||
set(CMAKE_CXX_FLAGS_RELEASE
|
||||
"${CMAKE_CXX_FLAGS_RELEASE} -D_SECURE_STL=0 -D_HAS_ITERATOR_DEBUGGING=0"
|
||||
CACHE STRING "C++ compiler release options" FORCE)
|
||||
set(CMAKE_C_FLAGS_RELEASE
|
||||
"${CMAKE_C_FLAGS_RELEASE}" CACHE STRING "C compiler release options" FORCE)
|
||||
add_definitions(
|
||||
/Zc:wchar_t-
|
||||
)
|
||||
endif (MSVC80 OR MSVC90 OR MSVC10)
|
||||
|
||||
# Are we using the crummy Visual Studio KDU build workaround?
|
||||
if (NOT DISABLE_FATAL_WARNINGS)
|
||||
add_definitions(/WX)
|
||||
endif (NOT DISABLE_FATAL_WARNINGS)
|
||||
|
||||
# Various libs are compiler specific, generate some variables here we can just use
|
||||
# when we require them instead of reimplementing the test each time.
|
||||
|
||||
if (MSVC71)
|
||||
set(MSVC_DIR 7.1)
|
||||
set(MSVC_SUFFIX 71)
|
||||
elseif (MSVC80)
|
||||
set(MSVC_DIR 8.0)
|
||||
set(MSVC_SUFFIX 80)
|
||||
elseif (MSVC90)
|
||||
set(MSVC_DIR 9.0)
|
||||
set(MSVC_SUFFIX 90)
|
||||
elseif (MSVC10)
|
||||
set(MSVC_DIR 10.0)
|
||||
set(MSVC_SUFFIX 100)
|
||||
endif (MSVC71)
|
||||
|
||||
if (MSVC10)
|
||||
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /MANIFEST:NO")
|
||||
SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /MANIFEST:NO")
|
||||
SET(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /MANIFEST:NO")
|
||||
endif(MSVC10)
|
||||
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /MANIFEST:NO")
|
||||
SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /MANIFEST:NO")
|
||||
SET(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /MANIFEST:NO")
|
||||
|
||||
|
||||
endif (WINDOWS)
|
||||
|
||||
set (GCC_EXTRA_OPTIMIZATIONS "-ffast-math")
|
||||
|
||||
@@ -36,11 +36,13 @@ set(cmake_SOURCE_FILES
|
||||
FMOD.cmake
|
||||
FMODEX.cmake
|
||||
FreeType.cmake
|
||||
GLOD.cmake
|
||||
GStreamer010Plugin.cmake
|
||||
GooglePerfTools.cmake
|
||||
Hunspell.cmake
|
||||
JPEG.cmake
|
||||
LLAddBuildTest.cmake
|
||||
LLAppearance.cmake
|
||||
LLAudio.cmake
|
||||
LLCharacter.cmake
|
||||
LLCommon.cmake
|
||||
@@ -54,6 +56,7 @@ set(cmake_SOURCE_FILES
|
||||
LLMessage.cmake
|
||||
LLPlugin.cmake
|
||||
LLPrimitive.cmake
|
||||
LLPhysicsExtensions.cmake
|
||||
LLQtWebkit.cmake
|
||||
LLRender.cmake
|
||||
LLScene.cmake
|
||||
|
||||
46
indra/cmake/Colladadom.cmake
Normal file
46
indra/cmake/Colladadom.cmake
Normal file
@@ -0,0 +1,46 @@
|
||||
# -*- cmake -*-
|
||||
|
||||
include(Prebuilt)
|
||||
|
||||
set(COLLADADOM_FIND_QUIETLY OFF)
|
||||
set(COLLADADOM_FIND_REQUIRED ON)
|
||||
|
||||
if (STANDALONE)
|
||||
include (FindColladadom)
|
||||
else (STANDALONE)
|
||||
use_prebuilt_binary(colladadom)
|
||||
|
||||
if (NOT WINDOWS)
|
||||
use_prebuilt_binary(pcre)
|
||||
endif (NOT WINDOWS)
|
||||
|
||||
if (NOT DARWIN AND NOT WINDOWS)
|
||||
use_prebuilt_binary(libxml)
|
||||
endif (NOT DARWIN AND NOT WINDOWS)
|
||||
|
||||
set(COLLADADOM_INCLUDE_DIRS
|
||||
${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/collada
|
||||
${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/collada/1.4
|
||||
)
|
||||
|
||||
if (WINDOWS)
|
||||
add_definitions(-DDOM_DYNAMIC)
|
||||
set(COLLADADOM_LIBRARIES
|
||||
debug libcollada14dom22-d
|
||||
optimized libcollada14dom22
|
||||
debug libboost_filesystem-vc100-mt-gd-1_45.lib
|
||||
optimized libboost_filesystem-vc100-mt-1_45.lib
|
||||
debug libboost_system-vc100-mt-gd-1_45.lib
|
||||
optimized libboost_system-vc100-mt-1_45.lib
|
||||
)
|
||||
else (WINDOWS)
|
||||
set(COLLADADOM_LIBRARIES
|
||||
collada14dom
|
||||
minizip
|
||||
xml2
|
||||
pcrecpp
|
||||
pcre
|
||||
)
|
||||
endif (WINDOWS)
|
||||
endif (STANDALONE)
|
||||
|
||||
@@ -31,6 +31,8 @@ set(debug_files
|
||||
libapriconv-1.dll
|
||||
libeay32.dll
|
||||
ssleay32.dll
|
||||
libcollada14dom22-d.dll
|
||||
glod.dll
|
||||
)
|
||||
|
||||
copy_if_different(
|
||||
@@ -210,6 +212,8 @@ set(release_files
|
||||
libapriconv-1.dll
|
||||
libeay32.dll
|
||||
ssleay32.dll
|
||||
libcollada14dom22.dll
|
||||
glod.dll
|
||||
)
|
||||
|
||||
if(FMODEX)
|
||||
|
||||
31
indra/cmake/FindColladadom.cmake
Normal file
31
indra/cmake/FindColladadom.cmake
Normal file
@@ -0,0 +1,31 @@
|
||||
# -*- cmake -*-
|
||||
|
||||
# - Find collada14dom
|
||||
# Find the colladadom version 1.4 includes and library
|
||||
# This module defines
|
||||
# COLLADADOM_FOUND, System has libcollada14dom.so.
|
||||
# COLLADADOM_INCLUDE_DIRS - The collada include directories.
|
||||
# COLLADADOM_LIBRARIES - The libraries needed to use libcollada14dom.
|
||||
# COLLADADOM_DEFINITIONS - Compiler switches required for using libcollada14dom.
|
||||
|
||||
FIND_PACKAGE(PkgConfig)
|
||||
PKG_CHECK_MODULES(PC_COLLADADOM collada)
|
||||
SET(COLLADADOM_DEFINITIONS ${PC_COLLADADOM_CFLAGS_OTHER})
|
||||
|
||||
FIND_PATH(COLLADADOM_INCLUDE_DIR dae.h
|
||||
HINTS ${PC_COLLADADOM_INCLUDE_DIR} ${PC_COLLADADOM_INCLUDE_DIRS}
|
||||
PATH_SUFFIXES collada)
|
||||
|
||||
FIND_LIBRARY(COLLADADOM_LIBRARY
|
||||
NAMES libcollada14dom.so
|
||||
HINTS ${PC_COLLADADOM_LIBDIR} ${PC_COLLADADOM_LIBRARY_DIRS}
|
||||
PATHS /usr/lib /usr/local/lib)
|
||||
|
||||
SET(COLLADADOM_LIBRARIES ${COLLADADOM_LIBRARY})
|
||||
SET(COLLADADOM_INCLUDE_DIRS ${COLLADADOM_INCLUDE_DIR} ${COLLADADOM_INCLUDE_DIR}/1.4)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(COLLADADOM DEFAULT_MSG
|
||||
COLLADADOM_LIBRARY COLLADADOM_INCLUDE_DIR)
|
||||
|
||||
MARK_AS_ADVANCED(COLLADADOM_LIBRARY COLLADADOM_INCLUDE_DIR)
|
||||
32
indra/cmake/FindGLOD.cmake
Normal file
32
indra/cmake/FindGLOD.cmake
Normal file
@@ -0,0 +1,32 @@
|
||||
# -*- cmake -*-
|
||||
|
||||
# - Find GLOD
|
||||
# Find the GLOD includes and library
|
||||
# This module defines
|
||||
# GLOD_FOUND, System has libglod.so.
|
||||
# GLOD_INCLUDE_DIRS - The GLOD include directories.
|
||||
# GLOD_LIBRARIES - The libraries needed to use libglod.
|
||||
# GLOD_DEFINITIONS - Compiler switches required for using libglod.
|
||||
|
||||
FIND_PACKAGE(PkgConfig)
|
||||
PKG_CHECK_MODULES(PC_GLOD glod)
|
||||
SET(GLOD_DEFINITIONS ${PC_GLOD_CFLAGS_OTHER})
|
||||
|
||||
FIND_PATH(GLOD_INCLUDE_DIR glod/glod.h
|
||||
HINTS ${PC_GLOD_INCLUDE_DIR} ${PC_GLOD_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
FIND_LIBRARY(GLOD_LIBRARY
|
||||
NAMES libGLOD.so
|
||||
HINTS ${PC_GLOD_LIBDIR} ${PC_GLOD_LIBRARY_DIRS}
|
||||
PATHS /usr/lib /usr/local/lib)
|
||||
|
||||
SET(GLOD_LIBRARIES ${GLOD_LIBRARY})
|
||||
SET(GLOD_INCLUDE_DIRS ${GLOD_INCLUDE_DIR})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(GLOD DEFAULT_MSG
|
||||
GLOD_LIBRARY GLOD_INCLUDE_DIR)
|
||||
|
||||
MARK_AS_ADVANCED(GLOD_LIBRARY GLOD_INCLUDE_DIR)
|
||||
|
||||
13
indra/cmake/GLOD.cmake
Normal file
13
indra/cmake/GLOD.cmake
Normal file
@@ -0,0 +1,13 @@
|
||||
# -*- cmake -*-
|
||||
include(Prebuilt)
|
||||
|
||||
set(GLOD_FIND_QUIETLY OFF)
|
||||
set(GLOD_FIND_REQUIRED ON)
|
||||
|
||||
if (STANDALONE)
|
||||
include(FindGLOD)
|
||||
else (STANDALONE)
|
||||
use_prebuilt_binary(GLOD)
|
||||
set(GLOD_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include)
|
||||
set(GLOD_LIBRARIES glod)
|
||||
endif (STANDALONE)
|
||||
11
indra/cmake/LLAppearance.cmake
Normal file
11
indra/cmake/LLAppearance.cmake
Normal file
@@ -0,0 +1,11 @@
|
||||
# -*- cmake -*-
|
||||
|
||||
include(Variables)
|
||||
|
||||
set(LLAPPEARANCE_INCLUDE_DIRS
|
||||
${LIBS_OPEN_DIR}/llappearance
|
||||
)
|
||||
|
||||
set(LLAPPEARANCE_LIBRARIES llappearance)
|
||||
|
||||
|
||||
7
indra/cmake/LLPhysicsExtensions.cmake
Normal file
7
indra/cmake/LLPhysicsExtensions.cmake
Normal file
@@ -0,0 +1,7 @@
|
||||
# -*- cmake -*-
|
||||
|
||||
set(LLPHYSICSEXTENSIONS_LIBRARIES nd_hacdConvexDecomposition hacd nd_Pathing )
|
||||
set(LLPHYSICSEXTENSIONS_INCLUDE_DIRS ${LIBS_OPEN_DIR}/libndhacd )
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,22 @@
|
||||
# -*- cmake -*-
|
||||
|
||||
set(LLPRIMITIVE_INCLUDE_DIRS
|
||||
${LIBS_OPEN_DIR}/llprimitive
|
||||
)
|
||||
include(Colladadom)
|
||||
|
||||
set(LLPRIMITIVE_INCLUDE_DIRS
|
||||
${LIBS_OPEN_DIR}/llprimitive
|
||||
${COLLADADOM_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
if (WINDOWS)
|
||||
set(LLPRIMITIVE_LIBRARIES
|
||||
debug llprimitive
|
||||
optimized llprimitive
|
||||
${COLLADADOM_LIBRARIES}
|
||||
)
|
||||
else (WINDOWS)
|
||||
set(LLPRIMITIVE_LIBRARIES
|
||||
llprimitive
|
||||
${COLLADADOM_LIBRARIES}
|
||||
)
|
||||
endif (WINDOWS)
|
||||
|
||||
set(LLPRIMITIVE_LIBRARIES llprimitive)
|
||||
|
||||
@@ -473,26 +473,11 @@ class DarwinSetup(UnixSetup):
|
||||
|
||||
class WindowsSetup(PlatformSetup):
|
||||
gens = {
|
||||
'vc71' : {
|
||||
'gen' : r'Visual Studio 7 .NET 2003',
|
||||
'ver' : r'7.1'
|
||||
},
|
||||
'vc80' : {
|
||||
'gen' : r'Visual Studio 8 2005',
|
||||
'ver' : r'8.0'
|
||||
},
|
||||
'vc90' : {
|
||||
'gen' : r'Visual Studio 9 2008',
|
||||
'ver' : r'9.0'
|
||||
},
|
||||
'vc100' : {
|
||||
'gen' : r'Visual Studio 10',
|
||||
'ver' : r'10.0'
|
||||
}
|
||||
}
|
||||
gens['vs2003'] = gens['vc71']
|
||||
gens['vs2005'] = gens['vc80']
|
||||
gens['vs2008'] = gens['vc90']
|
||||
gens['vs2010'] = gens['vc100']
|
||||
|
||||
search_path = r'C:\windows'
|
||||
@@ -505,21 +490,21 @@ class WindowsSetup(PlatformSetup):
|
||||
|
||||
def _get_generator(self):
|
||||
if self._generator is None:
|
||||
for version in 'vc80 vc90 vc100 vc71'.split():
|
||||
for version in 'vc100'.split():
|
||||
if self.find_visual_studio(version):
|
||||
self._generator = version
|
||||
print 'Building with ', self.gens[version]['gen']
|
||||
break
|
||||
else:
|
||||
print >> sys.stderr, 'Cannot find a Visual Studio installation, testing for express editions'
|
||||
for version in 'vc80 vc90 vc100 vc71'.split():
|
||||
for version in 'vc100'.split():
|
||||
if self.find_visual_studio_express(version):
|
||||
self._generator = version
|
||||
self.using_express = True
|
||||
print 'Building with ', self.gens[version]['gen'] , "Express edition"
|
||||
break
|
||||
else:
|
||||
for version in 'vc80 vc90 vc100 vc71'.split():
|
||||
for version in 'vc100'.split():
|
||||
if self.find_visual_studio_express_single(version):
|
||||
self._generator = version
|
||||
self.using_express = True
|
||||
@@ -768,8 +753,7 @@ Options:
|
||||
-m32 | -m64 build architecture (32-bit or 64-bit)
|
||||
-N | --no-distcc disable use of distcc
|
||||
-G | --generator=NAME generator name
|
||||
Windows: VC71 or VS2003 (default), VC80 (VS2005)
|
||||
VC90 (VS2008), or VC100 (VS2010)
|
||||
Windows: VC100 (VS2010) (default)
|
||||
Mac OS X: Xcode (default), Unix Makefiles
|
||||
Linux: Unix Makefiles (default), KDevelop3
|
||||
-p | --project=NAME set the root project name. (Doesn't effect makefiles)
|
||||
|
||||
13
indra/libhacd/CMakeLists.txt
Normal file
13
indra/libhacd/CMakeLists.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
cmake_minimum_required(VERSION 2.6.4)
|
||||
|
||||
project(libhacd CXX C)
|
||||
include(00-Common)
|
||||
|
||||
file (GLOB SOURCE_FILES *.cpp )
|
||||
file (GLOB INCLUDE_FILES *.h )
|
||||
|
||||
IF(WINDOWS)
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
ENDIF(WINDOWS)
|
||||
|
||||
add_library(hacd ${SOURCE_FILES} ${INCLUDE_FILES})
|
||||
85
indra/libhacd/hacdCircularList.h
Normal file
85
indra/libhacd/hacdCircularList.h
Normal file
@@ -0,0 +1,85 @@
|
||||
/* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
|
||||
All rights reserved.
|
||||
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#ifndef HACD_CIRCULAR_LIST_H
|
||||
#define HACD_CIRCULAR_LIST_H
|
||||
#include <stdlib.h>
|
||||
#include "hacdVersion.h"
|
||||
#include "hacdMicroAllocator.h"
|
||||
namespace HACD
|
||||
{
|
||||
//! CircularListElement class.
|
||||
template < typename T > class CircularListElement
|
||||
{
|
||||
public:
|
||||
T & GetData() { return m_data; }
|
||||
const T & GetData() const { return m_data; }
|
||||
CircularListElement<T> * & GetNext() { return m_next; }
|
||||
CircularListElement<T> * & GetPrev() { return m_prev; }
|
||||
const CircularListElement<T> * & GetNext() const { return m_next; }
|
||||
const CircularListElement<T> * & GetPrev() const { return m_prev; }
|
||||
//! Constructor
|
||||
CircularListElement(const T & data) {m_data = data;}
|
||||
CircularListElement(void){}
|
||||
//! Destructor
|
||||
~CircularListElement(void){}
|
||||
private:
|
||||
T m_data;
|
||||
CircularListElement<T> * m_next;
|
||||
CircularListElement<T> * m_prev;
|
||||
|
||||
CircularListElement(const CircularListElement & rhs);
|
||||
};
|
||||
|
||||
|
||||
//! CircularList class.
|
||||
template < typename T > class CircularList
|
||||
{
|
||||
public:
|
||||
HeapManager * const GetHeapManager() const { return m_heapManager;}
|
||||
void SetHeapManager(HeapManager * const heapManager) { m_heapManager = heapManager;}
|
||||
CircularListElement<T> * & GetHead() { return m_head;}
|
||||
const CircularListElement<T> * GetHead() const { return m_head;}
|
||||
bool IsEmpty() const { return (m_size == 0);}
|
||||
size_t GetSize() const { return m_size; }
|
||||
const T & GetData() const { return m_head->GetData(); }
|
||||
T & GetData() { return m_head->GetData();}
|
||||
bool Delete() ;
|
||||
bool Delete(CircularListElement<T> * element);
|
||||
CircularListElement<T> * Add(const T * data = 0);
|
||||
CircularListElement<T> * Add(const T & data);
|
||||
bool Next();
|
||||
bool Prev();
|
||||
void Clear() { while(Delete());};
|
||||
const CircularList& operator=(const CircularList& rhs);
|
||||
//! Constructor
|
||||
CircularList(HeapManager * heapManager)
|
||||
{
|
||||
m_head = 0;
|
||||
m_size = 0;
|
||||
m_heapManager = heapManager;
|
||||
}
|
||||
CircularList(const CircularList& rhs);
|
||||
//! Destructor
|
||||
virtual ~CircularList(void) {Clear();};
|
||||
private:
|
||||
CircularListElement<T> * m_head; //!< a pointer to the head of the circular list
|
||||
size_t m_size; //!< number of element in the circular list
|
||||
HeapManager * m_heapManager;
|
||||
|
||||
};
|
||||
}
|
||||
#include "hacdCircularList.inl"
|
||||
#endif
|
||||
230
indra/libhacd/hacdCircularList.inl
Normal file
230
indra/libhacd/hacdCircularList.inl
Normal file
@@ -0,0 +1,230 @@
|
||||
#pragma once
|
||||
#ifndef HACD_CIRCULAR_LIST_INL
|
||||
#define HACD_CIRCULAR_LIST_INL
|
||||
#include <stdlib.h>
|
||||
#include "hacdVersion.h"
|
||||
namespace HACD
|
||||
{
|
||||
template < typename T >
|
||||
inline bool CircularList<T>::Delete(CircularListElement<T> * element)
|
||||
{
|
||||
if (!element)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (m_size > 1)
|
||||
{
|
||||
CircularListElement<T> * next = element->GetNext();
|
||||
CircularListElement<T> * prev = element->GetPrev();
|
||||
if (m_heapManager)
|
||||
{
|
||||
element->~CircularListElement<T>();
|
||||
heap_free(m_heapManager, element);
|
||||
}
|
||||
else
|
||||
{
|
||||
delete element;
|
||||
}
|
||||
m_size--;
|
||||
if (element == m_head)
|
||||
{
|
||||
m_head = next;
|
||||
}
|
||||
next->GetPrev() = prev;
|
||||
prev->GetNext() = next;
|
||||
return true;
|
||||
}
|
||||
else if (m_size == 1)
|
||||
{
|
||||
if (m_heapManager)
|
||||
{
|
||||
element->~CircularListElement<T>();
|
||||
heap_free(m_heapManager, m_head);
|
||||
}
|
||||
else
|
||||
{
|
||||
delete m_head;
|
||||
}
|
||||
m_size--;
|
||||
m_head = 0;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
inline bool CircularList<T>::Delete()
|
||||
{
|
||||
if (m_size > 1)
|
||||
{
|
||||
CircularListElement<T> * next = m_head->GetNext();
|
||||
CircularListElement<T> * prev = m_head->GetPrev();
|
||||
if (m_heapManager)
|
||||
{
|
||||
m_head->~CircularListElement<T>();
|
||||
heap_free(m_heapManager, m_head);
|
||||
}
|
||||
else
|
||||
{
|
||||
delete m_head;
|
||||
}
|
||||
m_size--;
|
||||
m_head = next;
|
||||
next->GetPrev() = prev;
|
||||
prev->GetNext() = next;
|
||||
return true;
|
||||
}
|
||||
else if (m_size == 1)
|
||||
{
|
||||
if (m_heapManager)
|
||||
{
|
||||
m_head->~CircularListElement<T>();
|
||||
heap_free(m_heapManager, m_head);
|
||||
}
|
||||
else
|
||||
{
|
||||
delete m_head;
|
||||
}
|
||||
m_size--;
|
||||
m_head = 0;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
template < typename T >
|
||||
inline CircularListElement<T> * CircularList<T>::Add(const T * data)
|
||||
{
|
||||
if (m_size == 0)
|
||||
{
|
||||
if (data)
|
||||
{
|
||||
if (m_heapManager)
|
||||
{
|
||||
m_head = static_cast< CircularListElement<T> * > (heap_malloc(m_heapManager, sizeof(CircularListElement<T>)));
|
||||
m_head->GetData().Initialize();
|
||||
m_head->GetData() = (*data);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_head = new CircularListElement<T>(*data);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_heapManager)
|
||||
{
|
||||
m_head = static_cast< CircularListElement<T> * > (heap_malloc(m_heapManager, sizeof(CircularListElement<T>)));
|
||||
m_head->GetData().Initialize();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_head = new CircularListElement<T>();
|
||||
}
|
||||
}
|
||||
m_head->GetNext() = m_head->GetPrev() = m_head;
|
||||
}
|
||||
else
|
||||
{
|
||||
CircularListElement<T> * next = m_head->GetNext();
|
||||
CircularListElement<T> * element = m_head;
|
||||
if (data)
|
||||
{
|
||||
if (m_heapManager)
|
||||
{
|
||||
m_head = static_cast< CircularListElement<T> * > (heap_malloc(m_heapManager, sizeof(CircularListElement<T>)));
|
||||
m_head->GetData().Initialize();
|
||||
m_head->GetData() = (*data);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_head = new CircularListElement<T>(*data);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_heapManager)
|
||||
{
|
||||
m_head = static_cast< CircularListElement<T> * > (heap_malloc(m_heapManager, sizeof(CircularListElement<T>)));
|
||||
m_head->GetData().Initialize();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_head = new CircularListElement<T>();
|
||||
}
|
||||
}
|
||||
m_head->GetNext() = next;
|
||||
m_head->GetPrev() = element;
|
||||
element->GetNext() = m_head;
|
||||
next->GetPrev() = m_head;
|
||||
}
|
||||
m_size++;
|
||||
return m_head;
|
||||
}
|
||||
template < typename T >
|
||||
inline CircularListElement<T> * CircularList<T>::Add(const T & data)
|
||||
{
|
||||
const T * pData = &data;
|
||||
return Add(pData);
|
||||
}
|
||||
template < typename T >
|
||||
inline bool CircularList<T>::Next()
|
||||
{
|
||||
if (m_size == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
m_head = m_head->GetNext();
|
||||
return true;
|
||||
}
|
||||
template < typename T >
|
||||
inline bool CircularList<T>::Prev()
|
||||
{
|
||||
if (m_size == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
m_head = m_head->GetPrev();
|
||||
return true;
|
||||
}
|
||||
template < typename T >
|
||||
inline CircularList<T>::CircularList(const CircularList& rhs)
|
||||
{
|
||||
if (rhs.m_size > 0)
|
||||
{
|
||||
CircularListElement<T> * current = rhs.m_head;
|
||||
do
|
||||
{
|
||||
current = current->GetNext();
|
||||
Add(current->GetData());
|
||||
}
|
||||
while ( current != rhs.m_head );
|
||||
}
|
||||
}
|
||||
template < typename T >
|
||||
inline const CircularList<T>& CircularList<T>::operator=(const CircularList& rhs)
|
||||
{
|
||||
if (&rhs != this)
|
||||
{
|
||||
Clear();
|
||||
m_heapManager = rhs.m_heapManager;
|
||||
if (rhs.m_size > 0)
|
||||
{
|
||||
CircularListElement<T> * current = rhs.m_head;
|
||||
do
|
||||
{
|
||||
current = current->GetNext();
|
||||
Add(current->GetData());
|
||||
}
|
||||
while ( current != rhs.m_head );
|
||||
}
|
||||
}
|
||||
return (*this);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
278
indra/libhacd/hacdGraph.cpp
Normal file
278
indra/libhacd/hacdGraph.cpp
Normal file
@@ -0,0 +1,278 @@
|
||||
/* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
|
||||
All rights reserved.
|
||||
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "hacdGraph.h"
|
||||
namespace HACD
|
||||
{
|
||||
|
||||
GraphEdge::GraphEdge()
|
||||
{
|
||||
m_v1 = -1;
|
||||
m_v2 = -1;
|
||||
m_name = -1;
|
||||
m_error = 0;
|
||||
m_concavity = 0;
|
||||
m_deleted = false;
|
||||
#ifdef HACD_PRECOMPUTE_CHULLS
|
||||
m_convexHull = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
GraphVertex::GraphVertex()
|
||||
{
|
||||
m_convexHull = 0;
|
||||
m_name = -1;
|
||||
m_cc = -1;
|
||||
m_concavity = 0;
|
||||
m_surf = 0;
|
||||
m_deleted = false;
|
||||
}
|
||||
|
||||
bool GraphVertex::DeleteEdge(long name)
|
||||
{
|
||||
return m_edges.Erase(name);
|
||||
}
|
||||
|
||||
Graph::Graph()
|
||||
{
|
||||
m_nV = 0;
|
||||
m_nE = 0;
|
||||
m_nCCs = 0;
|
||||
}
|
||||
|
||||
Graph::~Graph()
|
||||
{
|
||||
}
|
||||
|
||||
void Graph::Allocate(size_t nV, size_t nE)
|
||||
{
|
||||
m_nV = nV;
|
||||
m_edges.reserve(nE);
|
||||
m_vertices.resize(nV);
|
||||
for(size_t i = 0; i < nV; i++)
|
||||
{
|
||||
m_vertices[i].m_name = static_cast<long>(i);
|
||||
}
|
||||
}
|
||||
|
||||
long Graph::AddVertex()
|
||||
{
|
||||
size_t name = m_vertices.size();
|
||||
m_vertices.resize(name+1);
|
||||
m_vertices[name].m_name = static_cast<long>(name);
|
||||
m_nV++;
|
||||
return static_cast<long>(name);
|
||||
}
|
||||
|
||||
long Graph::AddEdge(long v1, long v2)
|
||||
{
|
||||
size_t name = m_edges.size();
|
||||
m_edges.push_back(GraphEdge());
|
||||
m_edges[name].m_name = static_cast<long>(name);
|
||||
m_edges[name].m_v1 = v1;
|
||||
m_edges[name].m_v2 = v2;
|
||||
m_vertices[v1].AddEdge(static_cast<long>(name));
|
||||
m_vertices[v2].AddEdge(static_cast<long>(name));
|
||||
m_nE++;
|
||||
return static_cast<long>(name);
|
||||
}
|
||||
|
||||
bool Graph::DeleteEdge(long name)
|
||||
{
|
||||
if (name < static_cast<long>(m_edges.size()))
|
||||
{
|
||||
long v1 = m_edges[name].m_v1;
|
||||
long v2 = m_edges[name].m_v2;
|
||||
m_edges[name].m_deleted = true;
|
||||
m_vertices[v1].DeleteEdge(name);
|
||||
m_vertices[v2].DeleteEdge(name);
|
||||
m_nE--;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool Graph::DeleteVertex(long name)
|
||||
{
|
||||
if (name < static_cast<long>(m_vertices.size()))
|
||||
{
|
||||
m_vertices[name].m_deleted = true;
|
||||
m_vertices[name].m_edges.Clear();
|
||||
m_vertices[name].m_ancestors = std::vector<long>();
|
||||
delete m_vertices[name].m_convexHull;
|
||||
m_vertices[name].m_distPoints.Clear();
|
||||
m_vertices[name].m_boudaryEdges.Clear();
|
||||
m_vertices[name].m_convexHull = 0;
|
||||
m_nV--;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool Graph::EdgeCollapse(long v1, long v2)
|
||||
{
|
||||
long edgeToDelete = GetEdgeID(v1, v2);
|
||||
if (edgeToDelete >= 0)
|
||||
{
|
||||
// delete the edge (v1, v2)
|
||||
DeleteEdge(edgeToDelete);
|
||||
// add v2 to v1 ancestors
|
||||
m_vertices[v1].m_ancestors.push_back(v2);
|
||||
// add v2's ancestors to v1's ancestors
|
||||
m_vertices[v1].m_ancestors.insert(m_vertices[v1].m_ancestors.begin(),
|
||||
m_vertices[v2].m_ancestors.begin(),
|
||||
m_vertices[v2].m_ancestors.end());
|
||||
// update adjacency information
|
||||
SArray<long, SARRAY_DEFAULT_MIN_SIZE> & v1Edges = m_vertices[v1].m_edges;
|
||||
long b = -1;
|
||||
long idEdge;
|
||||
for(size_t ed = 0; ed < m_vertices[v2].m_edges.Size(); ++ed)
|
||||
{
|
||||
idEdge = m_vertices[v2].m_edges[ed];
|
||||
if (m_edges[idEdge].m_v1 == v2)
|
||||
{
|
||||
b = m_edges[idEdge].m_v2;
|
||||
}
|
||||
else
|
||||
{
|
||||
b = m_edges[idEdge].m_v1;
|
||||
}
|
||||
if (GetEdgeID(v1, b) >= 0)
|
||||
{
|
||||
m_edges[idEdge].m_deleted = true;
|
||||
m_vertices[b].DeleteEdge(idEdge);
|
||||
m_nE--;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_edges[idEdge].m_v1 = v1;
|
||||
m_edges[idEdge].m_v2 = b;
|
||||
v1Edges.Insert(idEdge);
|
||||
}
|
||||
}
|
||||
// delete the vertex v2
|
||||
DeleteVertex(v2);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
long Graph::GetEdgeID(long v1, long v2) const
|
||||
{
|
||||
if (v1 < static_cast<long>(m_vertices.size()) && !m_vertices[v1].m_deleted)
|
||||
{
|
||||
long idEdge;
|
||||
for(size_t ed = 0; ed < m_vertices[v1].m_edges.Size(); ++ed)
|
||||
{
|
||||
idEdge = m_vertices[v1].m_edges[ed];
|
||||
if ( (m_edges[idEdge].m_v1 == v2) ||
|
||||
(m_edges[idEdge].m_v2 == v2) )
|
||||
{
|
||||
return m_edges[idEdge].m_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Graph::Print() const
|
||||
{
|
||||
std::cout << "-----------------------------" << std::endl;
|
||||
std::cout << "vertices (" << m_nV << ")" << std::endl;
|
||||
for (size_t v = 0; v < m_vertices.size(); ++v)
|
||||
{
|
||||
const GraphVertex & currentVertex = m_vertices[v];
|
||||
if (!m_vertices[v].m_deleted)
|
||||
{
|
||||
|
||||
std::cout << currentVertex.m_name << "\t";
|
||||
long idEdge;
|
||||
for(size_t ed = 0; ed < currentVertex.m_edges.Size(); ++ed)
|
||||
{
|
||||
idEdge = currentVertex.m_edges[ed];
|
||||
std::cout << "(" << m_edges[idEdge].m_v1 << "," << m_edges[idEdge].m_v2 << ") ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "vertices (" << m_nE << ")" << std::endl;
|
||||
for (size_t e = 0; e < m_edges.size(); ++e)
|
||||
{
|
||||
const GraphEdge & currentEdge = m_edges[e];
|
||||
if (!m_edges[e].m_deleted)
|
||||
{
|
||||
std::cout << currentEdge.m_name << "\t("
|
||||
<< m_edges[e].m_v1 << ","
|
||||
<< m_edges[e].m_v2 << ") "<< std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
void Graph::Clear()
|
||||
{
|
||||
m_vertices.clear();
|
||||
m_edges.clear();
|
||||
m_nV = 0;
|
||||
m_nE = 0;
|
||||
}
|
||||
|
||||
long Graph::ExtractCCs()
|
||||
{
|
||||
// all CCs to -1
|
||||
for (size_t v = 0; v < m_vertices.size(); ++v)
|
||||
{
|
||||
if (!m_vertices[v].m_deleted)
|
||||
{
|
||||
m_vertices[v].m_cc = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// we get the CCs
|
||||
m_nCCs = 0;
|
||||
long v2 = -1;
|
||||
long idEdge;
|
||||
std::vector<long> temp;
|
||||
for (size_t v = 0; v < m_vertices.size(); ++v)
|
||||
{
|
||||
if (!m_vertices[v].m_deleted && m_vertices[v].m_cc == -1)
|
||||
{
|
||||
m_vertices[v].m_cc = static_cast<long>(m_nCCs);
|
||||
temp.clear();
|
||||
temp.push_back(m_vertices[v].m_name);
|
||||
while (temp.size())
|
||||
{
|
||||
long vertex = temp[temp.size()-1];
|
||||
temp.pop_back();
|
||||
for(size_t ed = 0; ed < m_vertices[vertex].m_edges.Size(); ++ed)
|
||||
{
|
||||
idEdge = m_vertices[vertex].m_edges[ed];
|
||||
if (m_edges[idEdge].m_v1 == vertex)
|
||||
{
|
||||
v2 = m_edges[idEdge].m_v2;
|
||||
}
|
||||
else
|
||||
{
|
||||
v2 = m_edges[idEdge].m_v1;
|
||||
}
|
||||
if ( !m_vertices[v2].m_deleted && m_vertices[v2].m_cc == -1)
|
||||
{
|
||||
m_vertices[v2].m_cc = static_cast<long>(m_nCCs);
|
||||
temp.push_back(v2);
|
||||
}
|
||||
}
|
||||
}
|
||||
m_nCCs++;
|
||||
}
|
||||
}
|
||||
return static_cast<long>(m_nCCs);
|
||||
}
|
||||
}
|
||||
118
indra/libhacd/hacdGraph.h
Normal file
118
indra/libhacd/hacdGraph.h
Normal file
@@ -0,0 +1,118 @@
|
||||
/* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
|
||||
All rights reserved.
|
||||
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#ifndef HACD_GRAPH_H
|
||||
#define HACD_GRAPH_H
|
||||
#include "hacdVersion.h"
|
||||
#include "hacdVector.h"
|
||||
#include "hacdICHull.h"
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include "hacdSArray.h"
|
||||
//#define HACD_PRECOMPUTE_CHULLS
|
||||
|
||||
namespace HACD
|
||||
{
|
||||
class GraphVertex;
|
||||
class GraphEdge;
|
||||
class Graph;
|
||||
class HACD;
|
||||
|
||||
class GraphVertex
|
||||
{
|
||||
public:
|
||||
bool AddEdge(long name)
|
||||
{
|
||||
m_edges.Insert(name);
|
||||
return true;
|
||||
}
|
||||
bool DeleteEdge(long name);
|
||||
GraphVertex();
|
||||
~GraphVertex(){ delete m_convexHull;};
|
||||
private:
|
||||
long m_name;
|
||||
long m_cc;
|
||||
SArray<long, SARRAY_DEFAULT_MIN_SIZE> m_edges;
|
||||
bool m_deleted;
|
||||
std::vector<long> m_ancestors;
|
||||
SArray<DPoint, SARRAY_DEFAULT_MIN_SIZE> m_distPoints;
|
||||
|
||||
Real m_concavity;
|
||||
double m_surf;
|
||||
ICHull * m_convexHull;
|
||||
SArray<unsigned long long, SARRAY_DEFAULT_MIN_SIZE> m_boudaryEdges;
|
||||
|
||||
|
||||
friend class GraphEdge;
|
||||
friend class Graph;
|
||||
friend class HACD;
|
||||
};
|
||||
|
||||
class GraphEdge
|
||||
{
|
||||
public:
|
||||
GraphEdge();
|
||||
~GraphEdge()
|
||||
{
|
||||
#ifdef HACD_PRECOMPUTE_CHULLS
|
||||
delete m_convexHull;
|
||||
#endif
|
||||
};
|
||||
private:
|
||||
long m_name;
|
||||
long m_v1;
|
||||
long m_v2;
|
||||
double m_concavity;
|
||||
Real m_error;
|
||||
#ifdef HACD_PRECOMPUTE_CHULLS
|
||||
ICHull * m_convexHull;
|
||||
#endif
|
||||
bool m_deleted;
|
||||
|
||||
friend class GraphVertex;
|
||||
friend class Graph;
|
||||
friend class HACD;
|
||||
};
|
||||
|
||||
class Graph
|
||||
{
|
||||
public:
|
||||
size_t GetNEdges() const { return m_nE;}
|
||||
size_t GetNVertices() const { return m_nV;}
|
||||
bool EdgeCollapse(long v1, long v2);
|
||||
long AddVertex();
|
||||
long AddEdge(long v1, long v2);
|
||||
bool DeleteEdge(long name);
|
||||
bool DeleteVertex(long name);
|
||||
long GetEdgeID(long v1, long v2) const;
|
||||
void Clear();
|
||||
void Print() const;
|
||||
long ExtractCCs();
|
||||
|
||||
Graph();
|
||||
virtual ~Graph();
|
||||
void Allocate(size_t nV, size_t nE);
|
||||
|
||||
private:
|
||||
size_t m_nCCs;
|
||||
size_t m_nV;
|
||||
size_t m_nE;
|
||||
std::vector<GraphEdge> m_edges;
|
||||
std::vector<GraphVertex> m_vertices;
|
||||
|
||||
friend class HACD;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
1142
indra/libhacd/hacdHACD.cpp
Normal file
1142
indra/libhacd/hacdHACD.cpp
Normal file
File diff suppressed because it is too large
Load Diff
330
indra/libhacd/hacdHACD.h
Normal file
330
indra/libhacd/hacdHACD.h
Normal file
@@ -0,0 +1,330 @@
|
||||
/* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
|
||||
All rights reserved.
|
||||
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#ifndef HACD_HACD_H
|
||||
#define HACD_HACD_H
|
||||
#include "hacdVersion.h"
|
||||
#include "hacdVector.h"
|
||||
#include "hacdGraph.h"
|
||||
#include "hacdICHull.h"
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
|
||||
namespace HACD
|
||||
{
|
||||
const double sc_pi = 3.14159265;
|
||||
class HACD;
|
||||
|
||||
// just to be able to set the capcity of the container
|
||||
|
||||
template<class _Ty, class _Container = std::vector<_Ty>, class _Pr = std::less<typename _Container::value_type> >
|
||||
class reservable_priority_queue: public std::priority_queue<_Ty, _Container, _Pr>
|
||||
{
|
||||
typedef typename std::priority_queue<_Ty, _Container, _Pr>::size_type size_type;
|
||||
public:
|
||||
reservable_priority_queue(size_type capacity = 0) { reserve(capacity); };
|
||||
void reserve(size_type capacity) { this->c.reserve(capacity); }
|
||||
size_type capacity() const { return this->c.capacity(); }
|
||||
};
|
||||
|
||||
//! priority queque element
|
||||
class HACD;
|
||||
class GraphEdgePriorityQueue
|
||||
{
|
||||
public:
|
||||
//! Constructor
|
||||
//! @param name edge's id
|
||||
//! @param priority edge's priority
|
||||
GraphEdgePriorityQueue(long name, Real priority)
|
||||
{
|
||||
m_name = name;
|
||||
m_priority = priority;
|
||||
}
|
||||
//! Destructor
|
||||
~GraphEdgePriorityQueue(void){}
|
||||
private:
|
||||
long m_name; //!< edge name
|
||||
Real m_priority; //!< priority
|
||||
//! Operator < for GraphEdgePQ
|
||||
friend bool operator<(const GraphEdgePriorityQueue & lhs, const GraphEdgePriorityQueue & rhs);
|
||||
//! Operator > for GraphEdgePQ
|
||||
friend bool operator>(const GraphEdgePriorityQueue & lhs, const GraphEdgePriorityQueue & rhs);
|
||||
friend class HACD;
|
||||
};
|
||||
inline bool operator<(const GraphEdgePriorityQueue & lhs, const GraphEdgePriorityQueue & rhs)
|
||||
{
|
||||
return (lhs.m_priority<rhs.m_priority);
|
||||
}
|
||||
inline bool operator>(const GraphEdgePriorityQueue & lhs, const GraphEdgePriorityQueue & rhs)
|
||||
{
|
||||
return lhs.m_priority>rhs.m_priority;
|
||||
}
|
||||
class ICallback
|
||||
{
|
||||
public:
|
||||
virtual void operator()( char const *aMsg, double aProgress, double aConcavity, size_t aVertices) = 0;
|
||||
};
|
||||
|
||||
typedef ICallback* CallBackFunction;
|
||||
|
||||
//! Provides an implementation of the Hierarchical Approximate Convex Decomposition (HACD) technique described in "A Simple and Efficient Approach for 3D Mesh Approximate Convex Decomposition" Game Programming Gems 8 - Chapter 2.8, p.202. A short version of the chapter was published in ICIP09 and is available at ftp://ftp.elet.polimi.it/users/Stefano.Tubaro/ICIP_USB_Proceedings_v2/pdfs/0003501.pdf
|
||||
class HACD
|
||||
{
|
||||
public:
|
||||
//! Gives the targeted number of triangles of the decimated mesh
|
||||
//! @return targeted number of triangles of the decimated mesh
|
||||
size_t GetTargetNTrianglesDecimatedMesh() const { return m_targetNTrianglesDecimatedMesh;}
|
||||
//! Sets the targeted number of triangles of the decimated mesh
|
||||
//! @param targeted number of triangles of the decimated mesh
|
||||
void SetNTargetTrianglesDecimatedMesh(size_t targetNTrianglesDecimatedMesh) { m_targetNTrianglesDecimatedMesh = targetNTrianglesDecimatedMesh;}
|
||||
//! Gives the triangles partitionas an array of size m_nTriangles where the i-th element specifies the cluster to which belong the i-th triangle
|
||||
//! @return triangles partition
|
||||
const long * const GetPartition() const { return m_partition;}
|
||||
//! Sets the scale factor
|
||||
//! @param scale scale factor
|
||||
void SetScaleFactor(double scale) { m_scale = scale;}
|
||||
//! Gives the scale factor
|
||||
//! @return scale factor
|
||||
const double GetScaleFactor() const { return m_scale;}
|
||||
//! Sets the threshold to detect small clusters. The threshold is expressed as a percentage of the total mesh surface (default 0.25%)
|
||||
//! @param smallClusterThreshold threshold to detect small clusters
|
||||
void SetSmallClusterThreshold(double smallClusterThreshold) { m_smallClusterThreshold = smallClusterThreshold;}
|
||||
//! Gives the threshold to detect small clusters. The threshold is expressed as a percentage of the total mesh surface (default 0.25%)
|
||||
//! @return threshold to detect small clusters
|
||||
const double GetSmallClusterThreshold() const { return m_smallClusterThreshold;}
|
||||
//! Sets the call-back function
|
||||
//! @param callBack pointer to the call-back function
|
||||
void SetCallBack(CallBackFunction callBack) { m_callBack = callBack;}
|
||||
//! Gives the call-back function
|
||||
//! @return pointer to the call-back function
|
||||
const CallBackFunction GetCallBack() const { return m_callBack;}
|
||||
|
||||
//! Specifies whether faces points should be added when computing the concavity
|
||||
//! @param addFacesPoints true = faces points should be added
|
||||
void SetAddFacesPoints(bool addFacesPoints) { m_addFacesPoints = addFacesPoints;}
|
||||
//! Specifies wheter faces points should be added when computing the concavity
|
||||
//! @return true = faces points should be added
|
||||
const bool GetAddFacesPoints() const { return m_addFacesPoints;}
|
||||
//! Specifies whether extra points should be added when computing the concavity
|
||||
//! @param addExteraDistPoints true = extra points should be added
|
||||
void SetAddExtraDistPoints(bool addExtraDistPoints) { m_addExtraDistPoints = addExtraDistPoints;}
|
||||
//! Specifies wheter extra points should be added when computing the concavity
|
||||
//! @return true = extra points should be added
|
||||
const bool GetAddExtraDistPoints() const { return m_addExtraDistPoints;}
|
||||
//! Sets the points of the input mesh (Remark: the input points will be scaled and shifted. Use DenormalizeData() to invert those operations)
|
||||
//! @param points pointer to the input points
|
||||
void SetPoints(Vec3<Real> * points) { m_points = points;}
|
||||
//! Gives the points of the input mesh (Remark: the input points will be scaled and shifted. Use DenormalizeData() to invert those operations)
|
||||
//! @return pointer to the input points
|
||||
const Vec3<Real> * GetPoints() const { return m_points;}
|
||||
//! Gives the points of the decimated mesh
|
||||
//! @return pointer to the decimated mesh points
|
||||
const Vec3<Real> * GetDecimatedPoints() const { return m_pointsDecimated;}
|
||||
//! Gives the triangles in the decimated mesh
|
||||
//! @return pointer to the decimated mesh triangles
|
||||
const Vec3<long> * GetDecimatedTriangles() const { return m_trianglesDecimated;}
|
||||
//! Gives the number of points in the decimated mesh.
|
||||
//! @return number of points the decimated mesh mesh
|
||||
const size_t GetNDecimatedPoints() const { return m_nPointsDecimated;}
|
||||
//! Gives the number of triangles in the decimated mesh.
|
||||
//! @return number of triangles the decimated mesh
|
||||
const size_t GetNDecimatedTriangles() const { return m_nTrianglesDecimated;}
|
||||
//! Sets the triangles of the input mesh.
|
||||
//! @param triangles points pointer to the input points
|
||||
void SetTriangles(Vec3<long> * triangles) { m_triangles = triangles;}
|
||||
//! Gives the triangles in the input mesh
|
||||
//! @return pointer to the input triangles
|
||||
const Vec3<long> * GetTriangles() const { return m_triangles;}
|
||||
//! Sets the number of points in the input mesh.
|
||||
//! @param nPoints number of points the input mesh
|
||||
void SetNPoints(size_t nPoints) { m_nPoints = nPoints;}
|
||||
//! Gives the number of points in the input mesh.
|
||||
//! @return number of points the input mesh
|
||||
const size_t GetNPoints() const { return m_nPoints;}
|
||||
//! Sets the number of triangles in the input mesh.
|
||||
//! @param nTriangles number of triangles in the input mesh
|
||||
void SetNTriangles(size_t nTriangles) { m_nTriangles = nTriangles;}
|
||||
//! Gives the number of triangles in the input mesh.
|
||||
//! @return number of triangles the input mesh
|
||||
const size_t GetNTriangles() const { return m_nTriangles;}
|
||||
//! Sets the minimum number of clusters to be generated.
|
||||
//! @param nClusters minimum number of clusters
|
||||
void SetNClusters(size_t nClusters) { m_nMinClusters = nClusters;}
|
||||
//! Gives the number of generated clusters.
|
||||
//! @return number of generated clusters
|
||||
const size_t GetNClusters() const { return m_nClusters;}
|
||||
//! Sets the maximum allowed concavity.
|
||||
//! @param concavity maximum concavity
|
||||
void SetConcavity(double concavity) { m_concavity = concavity;}
|
||||
//! Gives the maximum allowed concavity.
|
||||
//! @return maximum concavity
|
||||
double GetConcavity() const { return m_concavity;}
|
||||
//! Sets the maximum allowed distance to get CCs connected.
|
||||
//! @param concavity maximum distance to get CCs connected
|
||||
void SetConnectDist(double ccConnectDist) { m_ccConnectDist = ccConnectDist;}
|
||||
//! Gives the maximum allowed distance to get CCs connected.
|
||||
//! @return maximum distance to get CCs connected
|
||||
double GetConnectDist() const { return m_ccConnectDist;}
|
||||
//! Sets the volume weight.
|
||||
//! @param beta volume weight
|
||||
void SetVolumeWeight(double beta) { m_beta = beta;}
|
||||
//! Gives the volume weight.
|
||||
//! @return volume weight
|
||||
double GetVolumeWeight() const { return m_beta;}
|
||||
//! Sets the compacity weight (i.e. parameter alpha in ftp://ftp.elet.polimi.it/users/Stefano.Tubaro/ICIP_USB_Proceedings_v2/pdfs/0003501.pdf).
|
||||
//! @param alpha compacity weight
|
||||
void SetCompacityWeight(double alpha) { m_alpha = alpha;}
|
||||
//! Gives the compacity weight (i.e. parameter alpha in ftp://ftp.elet.polimi.it/users/Stefano.Tubaro/ICIP_USB_Proceedings_v2/pdfs/0003501.pdf).
|
||||
//! @return compacity weight
|
||||
double GetCompacityWeight() const { return m_alpha;}
|
||||
//! Sets the maximum number of vertices for each generated convex-hull.
|
||||
//! @param nVerticesPerCH maximum # vertices per CH
|
||||
void SetNVerticesPerCH(size_t nVerticesPerCH) { m_nVerticesPerCH = nVerticesPerCH;}
|
||||
//! Gives the maximum number of vertices for each generated convex-hull.
|
||||
//! @return maximum # vertices per CH
|
||||
const size_t GetNVerticesPerCH() const { return m_nVerticesPerCH;}
|
||||
//! Gives the number of vertices for the cluster number numCH.
|
||||
//! @return number of vertices
|
||||
size_t GetNPointsCH(size_t numCH) const;
|
||||
//! Gives the number of triangles for the cluster number numCH.
|
||||
//! @param numCH cluster's number
|
||||
//! @return number of triangles
|
||||
size_t GetNTrianglesCH(size_t numCH) const;
|
||||
//! Gives the vertices and the triangles of the cluster number numCH.
|
||||
//! @param numCH cluster's number
|
||||
//! @param points pointer to the vector of points to be filled
|
||||
//! @param triangles pointer to the vector of triangles to be filled
|
||||
//! @return true if sucess
|
||||
bool GetCH(size_t numCH, Vec3<Real> * const points, Vec3<long> * const triangles);
|
||||
//! Computes the HACD decomposition.
|
||||
//! @param fullCH specifies whether to generate convex-hulls with a full or limited (i.e. < m_nVerticesPerCH) number of vertices
|
||||
//! @param exportDistPoints specifies wheter distance points should ne exported or not (used only for debugging).
|
||||
//! @return true if sucess
|
||||
bool Compute(bool fullCH=false, bool exportDistPoints=false);
|
||||
#if 0
|
||||
//! Saves the generated convex-hulls in a VRML 2.0 file.
|
||||
//! @param fileName the output file name
|
||||
//! @param uniColor specifies whether the different convex-hulls should have the same color or not
|
||||
//! @param numCluster specifies the cluster to be saved, if numCluster < 0 export all clusters
|
||||
//! @return true if sucess
|
||||
bool Save(const char * fileName, bool uniColor, long numCluster=-1) const;
|
||||
#endif
|
||||
//! Shifts and scales to the data to have all the coordinates between 0.0 and 1000.0.
|
||||
void NormalizeData();
|
||||
//! Inverse the operations applied by NormalizeData().
|
||||
void DenormalizeData();
|
||||
//! Destructor.
|
||||
~HACD(void);
|
||||
|
||||
private:
|
||||
//! Constructor.
|
||||
HACD(HeapManager * heapManager = 0);
|
||||
|
||||
//! Gives the edge index.
|
||||
//! @param a first vertex id
|
||||
//! @param b second vertex id
|
||||
//! @return edge's index
|
||||
static unsigned long long GetEdgeIndex(unsigned long long a, unsigned long long b)
|
||||
{
|
||||
if (a > b) return (a << 32) + b;
|
||||
else return (b << 32) + a;
|
||||
}
|
||||
//! Computes the concavity of a cluster.
|
||||
//! @param ch the cluster's convex-hull
|
||||
//! @param distPoints the cluster's points
|
||||
//! @return cluster's concavity
|
||||
double Concavity(ICHull & ch, std::map<long, DPoint> & distPoints);
|
||||
//! Computes the perimeter of a cluster.
|
||||
//! @param triIndices the cluster's triangles
|
||||
//! @param distPoints the cluster's points
|
||||
//! @return cluster's perimeter
|
||||
double ComputePerimeter(const std::vector<long> & triIndices) const;
|
||||
//! Creates the Graph by associating to each mesh triangle a vertex in the graph and to each couple of adjacent triangles an edge in the graph.
|
||||
void CreateGraph();
|
||||
//! Initializes the graph costs and computes the vertices normals
|
||||
void InitializeDualGraph();
|
||||
//! Computes the cost of an edge
|
||||
//! @param e edge's id
|
||||
void ComputeEdgeCost(size_t e);
|
||||
//! Initializes the priority queue
|
||||
//! @param fast specifies whether fast mode is used
|
||||
//! @return true if success
|
||||
bool InitializePriorityQueue();
|
||||
//! Cleans the intersection between convex-hulls
|
||||
void CleanClusters();
|
||||
//! Computes convex-hulls from partition information
|
||||
//! @param fullCH specifies whether to generate convex-hulls with a full or limited (i.e. < m_nVerticesPerCH) number of vertices
|
||||
void ComputeConvexHulls(bool fullCH);
|
||||
//! Simplifies the graph
|
||||
//! @param fast specifies whether fast mode is used
|
||||
void Simplify();
|
||||
|
||||
private:
|
||||
Vec3<long> * m_trianglesDecimated; //>! pointer the triangles array
|
||||
Vec3<Real> * m_pointsDecimated; //>! pointer the points array
|
||||
Vec3<long> * m_triangles; //>! pointer the triangles array
|
||||
Vec3<Real> * m_points; //>! pointer the points array
|
||||
Vec3<Real> * m_facePoints; //>! pointer to the faces points array
|
||||
Vec3<Real> * m_faceNormals; //>! pointer to the faces normals array
|
||||
Vec3<Real> * m_normals; //>! pointer the normals array
|
||||
Vec3<Real> * m_extraDistPoints; //>! pointer to the faces points array
|
||||
Vec3<Real> * m_extraDistNormals; //>! pointer to the faces normals array
|
||||
size_t m_nTrianglesDecimated; //>! number of triangles in the original mesh
|
||||
size_t m_nPointsDecimated; //>! number of vertices in the original mesh
|
||||
size_t m_nTriangles; //>! number of triangles in the original mesh
|
||||
size_t m_nPoints; //>! number of vertices in the original mesh
|
||||
size_t m_nClusters; //>! number of clusters
|
||||
size_t m_nMinClusters; //>! minimum number of clusters
|
||||
double m_ccConnectDist; //>! maximum allowed distance to connect CCs
|
||||
double m_concavity; //>! maximum concavity
|
||||
double m_alpha; //>! compacity weigth
|
||||
double m_beta; //>! volume weigth
|
||||
double m_gamma; //>! computation cost
|
||||
double m_diag; //>! length of the BB diagonal
|
||||
double m_scale; //>! scale factor used for NormalizeData() and DenormalizeData()
|
||||
double m_flatRegionThreshold; //>! threshhold to control the contirbution of flat regions concavity (default 1% of m_scale)
|
||||
double m_smallClusterThreshold; //>! threshhold to detect small clusters (default 0.25% of the total mesh surface)
|
||||
double m_area; //>! surface area
|
||||
Vec3<Real> m_barycenter; //>! barycenter of the mesh
|
||||
std::vector< long > m_cVertices; //>! array of vertices each belonging to a different cluster
|
||||
ICHull * m_convexHulls; //>! convex-hulls associated with the final HACD clusters
|
||||
Graph m_graph; //>! simplification graph
|
||||
size_t m_nVerticesPerCH; //>! maximum number of vertices per convex-hull
|
||||
reservable_priority_queue<GraphEdgePriorityQueue,
|
||||
std::vector<GraphEdgePriorityQueue>,
|
||||
std::greater<std::vector<GraphEdgePriorityQueue>::value_type> > m_pqueue; //!> priority queue
|
||||
HACD(const HACD & rhs);
|
||||
CallBackFunction m_callBack; //>! call-back function
|
||||
long * m_partition; //>! array of size m_nTriangles where the i-th element specifies the cluster to which belong the i-th triangle
|
||||
size_t m_targetNTrianglesDecimatedMesh; //>! specifies the target number of triangles in the decimated mesh. If set to 0 no decimation is applied.
|
||||
HeapManager * m_heapManager; //>! Heap Manager
|
||||
bool m_addFacesPoints; //>! specifies whether to add faces points or not
|
||||
bool m_addExtraDistPoints; //>! specifies whether to add extra points for concave shapes or not
|
||||
|
||||
friend HACD * const CreateHACD(HeapManager * heapManager = 0);
|
||||
friend void DestroyHACD(HACD * const hacd);
|
||||
};
|
||||
inline HACD * const CreateHACD(HeapManager * heapManager)
|
||||
{
|
||||
return new HACD(heapManager);
|
||||
}
|
||||
inline void DestroyHACD(HACD * const hacd)
|
||||
{
|
||||
delete hacd;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
1004
indra/libhacd/hacdICHull.cpp
Normal file
1004
indra/libhacd/hacdICHull.cpp
Normal file
File diff suppressed because it is too large
Load Diff
133
indra/libhacd/hacdICHull.h
Normal file
133
indra/libhacd/hacdICHull.h
Normal file
@@ -0,0 +1,133 @@
|
||||
/* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
|
||||
All rights reserved.
|
||||
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#ifndef HACD_ICHULL_H
|
||||
#define HACD_ICHULL_H
|
||||
#include "hacdVersion.h"
|
||||
#include "hacdManifoldMesh.h"
|
||||
#include "hacdVector.h"
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "hacdMicroAllocator.h"
|
||||
|
||||
namespace HACD
|
||||
{
|
||||
class DPoint;
|
||||
class HACD;
|
||||
//! Incremental Convex Hull algorithm (cf. http://maven.smith.edu/~orourke/books/ftp.html ).
|
||||
enum ICHullError
|
||||
{
|
||||
ICHullErrorOK = 0,
|
||||
ICHullErrorCoplanarPoints,
|
||||
ICHullErrorNoVolume,
|
||||
ICHullErrorInconsistent,
|
||||
ICHullErrorNotEnoughPoints
|
||||
};
|
||||
class ICHull
|
||||
{
|
||||
public:
|
||||
static const double sc_eps;
|
||||
//!
|
||||
HeapManager * const GetHeapManager() const { return m_heapManager;}
|
||||
//!
|
||||
void SetHeapManager(HeapManager * const heapManager)
|
||||
{
|
||||
m_heapManager = heapManager;
|
||||
m_mesh.SetHeapManager(m_heapManager);
|
||||
}
|
||||
//!
|
||||
bool IsFlat() { return m_isFlat;}
|
||||
//!
|
||||
std::map<long, DPoint> * GetDistPoints() const { return m_distPoints;}
|
||||
//!
|
||||
void SetDistPoints(std::map<long, DPoint> * distPoints) { m_distPoints = distPoints;}
|
||||
//! Returns the computed mesh
|
||||
TMMesh & GetMesh() { return m_mesh;}
|
||||
//! Add one point to the convex-hull
|
||||
bool AddPoint(const Vec3<Real> & point) {return AddPoints(&point, 1);}
|
||||
//! Add one point to the convex-hull
|
||||
bool AddPoint(const Vec3<Real> & point, long id);
|
||||
//! Add points to the convex-hull
|
||||
bool AddPoints(const Vec3<Real> * points, size_t nPoints);
|
||||
bool AddPoints(std::vector< Vec3<Real> > points);
|
||||
//!
|
||||
ICHullError Process();
|
||||
//!
|
||||
ICHullError Process(unsigned long nPointsCH);
|
||||
//!
|
||||
double ComputeVolume();
|
||||
//!
|
||||
double ComputeArea();
|
||||
//!
|
||||
bool IsInside(const Vec3<Real> & pt0, const double eps = 0.0);
|
||||
//!
|
||||
double ComputeDistance(long name, const Vec3<Real> & pt, const Vec3<Real> & normal, bool & insideHull, bool updateIncidentPoints);
|
||||
//!
|
||||
const ICHull & operator=(ICHull & rhs);
|
||||
|
||||
//! Constructor
|
||||
ICHull(HeapManager * const heapManager=0);
|
||||
//! Destructor
|
||||
virtual ~ICHull(void) {};
|
||||
|
||||
private:
|
||||
//! DoubleTriangle builds the initial double triangle. It first finds 3 noncollinear points and makes two faces out of them, in opposite order. It then finds a fourth point that is not coplanar with that face. The vertices are stored in the face structure in counterclockwise order so that the volume between the face and the point is negative. Lastly, the 3 newfaces to the fourth point are constructed and the data structures are cleaned up.
|
||||
ICHullError DoubleTriangle();
|
||||
//! MakeFace creates a new face structure from three vertices (in ccw order). It returns a pointer to the face.
|
||||
CircularListElement<TMMTriangle> * MakeFace(CircularListElement<TMMVertex> * v0,
|
||||
CircularListElement<TMMVertex> * v1,
|
||||
CircularListElement<TMMVertex> * v2,
|
||||
CircularListElement<TMMTriangle> * fold);
|
||||
//!
|
||||
CircularListElement<TMMTriangle> * MakeConeFace(CircularListElement<TMMEdge> * e, CircularListElement<TMMVertex> * v);
|
||||
//!
|
||||
bool ProcessPoint();
|
||||
//!
|
||||
bool ComputePointVolume(double &totalVolume, bool markVisibleFaces);
|
||||
//!
|
||||
bool FindMaxVolumePoint();
|
||||
//!
|
||||
bool CleanEdges();
|
||||
//!
|
||||
bool CleanVertices(unsigned long & addedPoints);
|
||||
//!
|
||||
bool CleanTriangles();
|
||||
//!
|
||||
bool CleanUp(unsigned long & addedPoints);
|
||||
//!
|
||||
bool MakeCCW(CircularListElement<TMMTriangle> * f,
|
||||
CircularListElement<TMMEdge> * e,
|
||||
CircularListElement<TMMVertex> * v);
|
||||
void Clear();
|
||||
private:
|
||||
static const long sc_dummyIndex;
|
||||
static const double sc_distMin;
|
||||
TMMesh m_mesh;
|
||||
std::vector<CircularListElement<TMMEdge> *> m_edgesToDelete;
|
||||
std::vector<CircularListElement<TMMEdge> *> m_edgesToUpdate;
|
||||
std::vector<CircularListElement<TMMTriangle> *> m_trianglesToDelete;
|
||||
std::map<long, DPoint> * m_distPoints;
|
||||
// CircularListElement<TMMVertex> * m_dummyVertex;
|
||||
Vec3<Real> m_normal;
|
||||
bool m_isFlat;
|
||||
HeapManager * m_heapManager;
|
||||
|
||||
ICHull(const ICHull & rhs);
|
||||
|
||||
friend class HACD;
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
604
indra/libhacd/hacdManifoldMesh.cpp
Normal file
604
indra/libhacd/hacdManifoldMesh.cpp
Normal file
@@ -0,0 +1,604 @@
|
||||
/* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
|
||||
All rights reserved.
|
||||
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "hacdManifoldMesh.h"
|
||||
using namespace std;
|
||||
|
||||
|
||||
namespace HACD
|
||||
{
|
||||
Material::Material(void)
|
||||
{
|
||||
m_diffuseColor.X() = 0.5;
|
||||
m_diffuseColor.Y() = 0.5;
|
||||
m_diffuseColor.Z() = 0.5;
|
||||
m_specularColor.X() = 0.5;
|
||||
m_specularColor.Y() = 0.5;
|
||||
m_specularColor.Z() = 0.5;
|
||||
m_ambientIntensity = 0.4;
|
||||
m_emissiveColor.X() = 0.0;
|
||||
m_emissiveColor.Y() = 0.0;
|
||||
m_emissiveColor.Z() = 0.0;
|
||||
m_shininess = 0.4;
|
||||
m_transparency = 0.0;
|
||||
}
|
||||
|
||||
TMMVertex::TMMVertex(void)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
void TMMVertex::Initialize()
|
||||
{
|
||||
m_name = 0;
|
||||
m_id = 0;
|
||||
m_duplicate = 0;
|
||||
m_onHull = false;
|
||||
m_tag = false;
|
||||
}
|
||||
|
||||
TMMVertex::~TMMVertex(void)
|
||||
{
|
||||
}
|
||||
TMMEdge::TMMEdge(void)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
void TMMEdge::Initialize()
|
||||
{
|
||||
m_id = 0;
|
||||
m_triangles[0] = m_triangles[1] = m_newFace = 0;
|
||||
m_vertices[0] = m_vertices[1] = 0;
|
||||
}
|
||||
TMMEdge::~TMMEdge(void)
|
||||
{
|
||||
}
|
||||
void TMMTriangle::Initialize()
|
||||
{
|
||||
m_id = 0;
|
||||
for(int i = 0; i < 3; i++)
|
||||
{
|
||||
m_edges[i] = 0;
|
||||
m_vertices[0] = 0;
|
||||
}
|
||||
m_visible = false;
|
||||
m_incidentPoints.Initialize();
|
||||
}
|
||||
TMMTriangle::TMMTriangle(void)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
TMMTriangle::~TMMTriangle(void)
|
||||
{
|
||||
}
|
||||
TMMesh::TMMesh(HeapManager * const heapManager):
|
||||
m_vertices(heapManager),
|
||||
m_edges(heapManager),
|
||||
m_triangles(heapManager)
|
||||
{
|
||||
m_barycenter = Vec3<Real>(0,0,0);
|
||||
m_diag = 1;
|
||||
m_heapManager = heapManager;
|
||||
}
|
||||
TMMesh::~TMMesh(void)
|
||||
{
|
||||
}
|
||||
|
||||
void TMMesh::Print()
|
||||
{
|
||||
size_t nV = m_vertices.GetSize();
|
||||
std::cout << "-----------------------------" << std::endl;
|
||||
std::cout << "vertices (" << nV << ")" << std::endl;
|
||||
for(size_t v = 0; v < nV; v++)
|
||||
{
|
||||
const TMMVertex & currentVertex = m_vertices.GetData();
|
||||
std::cout << currentVertex.m_id << ", "
|
||||
<< currentVertex.m_pos.X() << ", "
|
||||
<< currentVertex.m_pos.Y() << ", "
|
||||
<< currentVertex.m_pos.Z() << std::endl;
|
||||
m_vertices.Next();
|
||||
}
|
||||
|
||||
|
||||
size_t nE = m_edges.GetSize();
|
||||
std::cout << "edges (" << nE << ")" << std::endl;
|
||||
for(size_t e = 0; e < nE; e++)
|
||||
{
|
||||
const TMMEdge & currentEdge = m_edges.GetData();
|
||||
const CircularListElement<TMMVertex> * v0 = currentEdge.m_vertices[0];
|
||||
const CircularListElement<TMMVertex> * v1 = currentEdge.m_vertices[1];
|
||||
const CircularListElement<TMMTriangle> * f0 = currentEdge.m_triangles[0];
|
||||
const CircularListElement<TMMTriangle> * f1 = currentEdge.m_triangles[1];
|
||||
|
||||
std::cout << "-> (" << v0->GetData().m_name << ", " << v1->GetData().m_name << ")" << std::endl;
|
||||
std::cout << "-> F0 (" << f0->GetData().m_vertices[0]->GetData().m_name << ", "
|
||||
<< f0->GetData().m_vertices[1]->GetData().m_name << ", "
|
||||
<< f0->GetData().m_vertices[2]->GetData().m_name <<")" << std::endl;
|
||||
std::cout << "-> F1 (" << f1->GetData().m_vertices[0]->GetData().m_name << ", "
|
||||
<< f1->GetData().m_vertices[1]->GetData().m_name << ", "
|
||||
<< f1->GetData().m_vertices[2]->GetData().m_name << ")" << std::endl;
|
||||
m_edges.Next();
|
||||
}
|
||||
size_t nT = m_triangles.GetSize();
|
||||
std::cout << "triangles (" << nT << ")" << std::endl;
|
||||
for(size_t t = 0; t < nT; t++)
|
||||
{
|
||||
const TMMTriangle & currentTriangle = m_triangles.GetData();
|
||||
const CircularListElement<TMMVertex> * v0 = currentTriangle.m_vertices[0];
|
||||
const CircularListElement<TMMVertex> * v1 = currentTriangle.m_vertices[1];
|
||||
const CircularListElement<TMMVertex> * v2 = currentTriangle.m_vertices[2];
|
||||
const CircularListElement<TMMEdge> * e0 = currentTriangle.m_edges[0];
|
||||
const CircularListElement<TMMEdge> * e1 = currentTriangle.m_edges[1];
|
||||
const CircularListElement<TMMEdge> * e2 = currentTriangle.m_edges[2];
|
||||
|
||||
std::cout << "-> (" << v0->GetData().m_name << ", " << v1->GetData().m_name << ", "<< v2->GetData().m_name << ")" << std::endl;
|
||||
|
||||
std::cout << "-> E0 (" << e0->GetData().m_vertices[0]->GetData().m_name << ", "
|
||||
<< e0->GetData().m_vertices[1]->GetData().m_name << ")" << std::endl;
|
||||
std::cout << "-> E1 (" << e1->GetData().m_vertices[0]->GetData().m_name << ", "
|
||||
<< e1->GetData().m_vertices[1]->GetData().m_name << ")" << std::endl;
|
||||
std::cout << "-> E2 (" << e2->GetData().m_vertices[0]->GetData().m_name << ", "
|
||||
<< e2->GetData().m_vertices[1]->GetData().m_name << ")" << std::endl;
|
||||
m_triangles.Next();
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
bool TMMesh::Save(const char *fileName)
|
||||
{
|
||||
std::ofstream fout(fileName);
|
||||
std::cout << "Saving " << fileName << std::endl;
|
||||
if (SaveVRML2(fout))
|
||||
{
|
||||
fout.close();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool TMMesh::SaveVRML2(std::ofstream &fout)
|
||||
{
|
||||
return SaveVRML2(fout, Material());
|
||||
}
|
||||
bool TMMesh::SaveVRML2(std::ofstream &fout, const Material & material)
|
||||
{
|
||||
if (fout.is_open())
|
||||
{
|
||||
size_t nV = m_vertices.GetSize();
|
||||
size_t nT = m_triangles.GetSize();
|
||||
fout <<"#VRML V2.0 utf8" << std::endl;
|
||||
fout <<"" << std::endl;
|
||||
fout <<"# Vertices: " << nV << std::endl;
|
||||
fout <<"# Triangles: " << nT << std::endl;
|
||||
fout <<"" << std::endl;
|
||||
fout <<"Group {" << std::endl;
|
||||
fout <<" children [" << std::endl;
|
||||
fout <<" Shape {" << std::endl;
|
||||
fout <<" appearance Appearance {" << std::endl;
|
||||
fout <<" material Material {" << std::endl;
|
||||
fout <<" diffuseColor " << material.m_diffuseColor.X() << " "
|
||||
<< material.m_diffuseColor.Y() << " "
|
||||
<< material.m_diffuseColor.Z() << std::endl;
|
||||
fout <<" ambientIntensity " << material.m_ambientIntensity << std::endl;
|
||||
fout <<" specularColor " << material.m_specularColor.X() << " "
|
||||
<< material.m_specularColor.Y() << " "
|
||||
<< material.m_specularColor.Z() << std::endl;
|
||||
fout <<" emissiveColor " << material.m_emissiveColor.X() << " "
|
||||
<< material.m_emissiveColor.Y() << " "
|
||||
<< material.m_emissiveColor.Z() << std::endl;
|
||||
fout <<" shininess " << material.m_shininess << std::endl;
|
||||
fout <<" transparency " << material.m_transparency << std::endl;
|
||||
fout <<" }" << std::endl;
|
||||
fout <<" }" << std::endl;
|
||||
fout <<" geometry IndexedFaceSet {" << std::endl;
|
||||
fout <<" ccw TRUE" << std::endl;
|
||||
fout <<" solid TRUE" << std::endl;
|
||||
fout <<" convex TRUE" << std::endl;
|
||||
if (GetNVertices() > 0) {
|
||||
fout <<" coord DEF co Coordinate {" << std::endl;
|
||||
fout <<" point [" << std::endl;
|
||||
for(size_t v = 0; v < nV; v++)
|
||||
{
|
||||
TMMVertex & currentVertex = m_vertices.GetData();
|
||||
fout <<" " << currentVertex.m_pos.X() << " "
|
||||
<< currentVertex.m_pos.Y() << " "
|
||||
<< currentVertex.m_pos.Z() << "," << std::endl;
|
||||
currentVertex.m_id = v;
|
||||
m_vertices.Next();
|
||||
}
|
||||
fout <<" ]" << std::endl;
|
||||
fout <<" }" << std::endl;
|
||||
}
|
||||
if (GetNTriangles() > 0) {
|
||||
fout <<" coordIndex [ " << std::endl;
|
||||
for(size_t f = 0; f < nT; f++)
|
||||
{
|
||||
TMMTriangle & currentTriangle = m_triangles.GetData();
|
||||
fout <<" " << currentTriangle.m_vertices[0]->GetData().m_id << ", "
|
||||
<< currentTriangle.m_vertices[1]->GetData().m_id << ", "
|
||||
<< currentTriangle.m_vertices[2]->GetData().m_id << ", -1," << std::endl;
|
||||
m_triangles.Next();
|
||||
}
|
||||
fout <<" ]" << std::endl;
|
||||
}
|
||||
fout <<" }" << std::endl;
|
||||
fout <<" }" << std::endl;
|
||||
fout <<" ]" << std::endl;
|
||||
fout <<"}" << std::endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
void TMMesh::GetIFS(Vec3<Real> * const points, Vec3<long> * const triangles)
|
||||
{
|
||||
size_t nV = m_vertices.GetSize();
|
||||
size_t nT = m_triangles.GetSize();
|
||||
|
||||
for(size_t v = 0; v < nV; v++)
|
||||
{
|
||||
points[v] = m_vertices.GetData().m_pos;
|
||||
m_vertices.GetData().m_id = v;
|
||||
m_vertices.Next();
|
||||
}
|
||||
for(size_t f = 0; f < nT; f++)
|
||||
{
|
||||
TMMTriangle & currentTriangle = m_triangles.GetData();
|
||||
triangles[f].X() = static_cast<long>(currentTriangle.m_vertices[0]->GetData().m_id);
|
||||
triangles[f].Y() = static_cast<long>(currentTriangle.m_vertices[1]->GetData().m_id);
|
||||
triangles[f].Z() = static_cast<long>(currentTriangle.m_vertices[2]->GetData().m_id);
|
||||
m_triangles.Next();
|
||||
}
|
||||
}
|
||||
void TMMesh::Clear()
|
||||
{
|
||||
m_vertices.Clear();
|
||||
m_edges.Clear();
|
||||
m_triangles.Clear();
|
||||
}
|
||||
void TMMesh::Copy(TMMesh & mesh)
|
||||
{
|
||||
Clear();
|
||||
// updating the id's
|
||||
size_t nV = mesh.m_vertices.GetSize();
|
||||
size_t nE = mesh. m_edges.GetSize();
|
||||
size_t nT = mesh.m_triangles.GetSize();
|
||||
for(size_t v = 0; v < nV; v++)
|
||||
{
|
||||
mesh.m_vertices.GetData().m_id = v;
|
||||
mesh.m_vertices.Next();
|
||||
}
|
||||
for(size_t e = 0; e < nE; e++)
|
||||
{
|
||||
mesh.m_edges.GetData().m_id = e;
|
||||
mesh.m_edges.Next();
|
||||
|
||||
}
|
||||
for(size_t f = 0; f < nT; f++)
|
||||
{
|
||||
mesh.m_triangles.GetData().m_id = f;
|
||||
mesh.m_triangles.Next();
|
||||
}
|
||||
// copying data
|
||||
m_vertices = mesh.m_vertices;
|
||||
m_edges = mesh.m_edges;
|
||||
m_triangles = mesh.m_triangles;
|
||||
m_heapManager = mesh.m_heapManager;
|
||||
|
||||
// generating mapping
|
||||
CircularListElement<TMMVertex> ** vertexMap = new CircularListElement<TMMVertex> * [nV];
|
||||
CircularListElement<TMMEdge> ** edgeMap = new CircularListElement<TMMEdge> * [nE];
|
||||
CircularListElement<TMMTriangle> ** triangleMap = new CircularListElement<TMMTriangle> * [nT];
|
||||
for(size_t v = 0; v < nV; v++)
|
||||
{
|
||||
vertexMap[v] = m_vertices.GetHead();
|
||||
m_vertices.Next();
|
||||
}
|
||||
for(size_t e = 0; e < nE; e++)
|
||||
{
|
||||
edgeMap[e] = m_edges.GetHead();
|
||||
m_edges.Next();
|
||||
}
|
||||
for(size_t f = 0; f < nT; f++)
|
||||
{
|
||||
triangleMap[f] = m_triangles.GetHead();
|
||||
m_triangles.Next();
|
||||
}
|
||||
|
||||
// updating pointers
|
||||
for(size_t v = 0; v < nV; v++)
|
||||
{
|
||||
if (vertexMap[v]->GetData().m_duplicate)
|
||||
{
|
||||
vertexMap[v]->GetData().m_duplicate = edgeMap[vertexMap[v]->GetData().m_duplicate->GetData().m_id];
|
||||
}
|
||||
}
|
||||
for(size_t e = 0; e < nE; e++)
|
||||
{
|
||||
if (edgeMap[e]->GetData().m_newFace)
|
||||
{
|
||||
edgeMap[e]->GetData().m_newFace = triangleMap[edgeMap[e]->GetData().m_newFace->GetData().m_id];
|
||||
}
|
||||
if (nT > 0)
|
||||
{
|
||||
for(int f = 0; f < 2; f++)
|
||||
{
|
||||
if (edgeMap[e]->GetData().m_triangles[f])
|
||||
{
|
||||
edgeMap[e]->GetData().m_triangles[f] = triangleMap[edgeMap[e]->GetData().m_triangles[f]->GetData().m_id];
|
||||
}
|
||||
}
|
||||
}
|
||||
for(int v = 0; v < 2; v++)
|
||||
{
|
||||
if (edgeMap[e]->GetData().m_vertices[v])
|
||||
{
|
||||
edgeMap[e]->GetData().m_vertices[v] = vertexMap[edgeMap[e]->GetData().m_vertices[v]->GetData().m_id];
|
||||
}
|
||||
}
|
||||
}
|
||||
for(size_t f = 0; f < nT; f++)
|
||||
{
|
||||
if (nE > 0)
|
||||
{
|
||||
for(int e = 0; e < 3; e++)
|
||||
{
|
||||
if (triangleMap[f]->GetData().m_edges[e])
|
||||
{
|
||||
triangleMap[f]->GetData().m_edges[e] = edgeMap[triangleMap[f]->GetData().m_edges[e]->GetData().m_id];
|
||||
}
|
||||
}
|
||||
}
|
||||
for(int v = 0; v < 3; v++)
|
||||
{
|
||||
if (triangleMap[f]->GetData().m_vertices[v])
|
||||
{
|
||||
triangleMap[f]->GetData().m_vertices[v] = vertexMap[triangleMap[f]->GetData().m_vertices[v]->GetData().m_id];
|
||||
}
|
||||
}
|
||||
}
|
||||
delete [] vertexMap;
|
||||
delete [] edgeMap;
|
||||
delete [] triangleMap;
|
||||
|
||||
}
|
||||
long IntersectRayTriangle(const Vec3<double> & P0, const Vec3<double> & dir,
|
||||
const Vec3<double> & V0, const Vec3<double> & V1,
|
||||
const Vec3<double> & V2, double &t)
|
||||
{
|
||||
const double EPS = 1e-9;
|
||||
const double EPS1 = 1e-6;
|
||||
t = 0.0;
|
||||
Vec3<double> edge1, edge2, edge3;
|
||||
double det;
|
||||
edge1 = V1 - V2;
|
||||
edge2 = V2 - V0;
|
||||
Vec3<double> pvec = dir ^ edge2;
|
||||
det = edge1 * pvec;
|
||||
if (det < EPS && det > -EPS)
|
||||
return 0;
|
||||
Vec3<double> tvec = P0 - V0;
|
||||
Vec3<double> qvec = tvec ^ edge1;
|
||||
t = (edge2 * qvec) / det;
|
||||
if (t < 0.0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
edge3 = V0 - V1;
|
||||
Vec3<double> I(P0 + t * dir);
|
||||
Vec3<double> s0 = (I-V0) ^ edge3;
|
||||
Vec3<double> s1 = (I-V1) ^ edge1;
|
||||
Vec3<double> s2 = (I-V2) ^ edge2;
|
||||
|
||||
Vec3<double> normal = edge1 ^ edge2;
|
||||
double diff = normal.GetNorm() - s0.GetNorm() - s1.GetNorm() - s2.GetNorm();
|
||||
|
||||
if (diff < EPS1 && diff > -EPS1)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool IntersectLineLine(const Vec3<double> & p1, const Vec3<double> & p2,
|
||||
const Vec3<double> & p3, const Vec3<double> & p4,
|
||||
Vec3<double> & pa, Vec3<double> & pb,
|
||||
double & mua, double & mub)
|
||||
{
|
||||
Vec3<double> p13,p43,p21;
|
||||
double d1343,d4321,d1321,d4343,d2121;
|
||||
double numer,denom;
|
||||
|
||||
p13.X() = p1.X() - p3.X();
|
||||
p13.Y() = p1.Y() - p3.Y();
|
||||
p13.Z() = p1.Z() - p3.Z();
|
||||
p43.X() = p4.X() - p3.X();
|
||||
p43.Y() = p4.Y() - p3.Y();
|
||||
p43.Z() = p4.Z() - p3.Z();
|
||||
if (p43.X()==0.0 && p43.Y()==0.0 && p43.Z()==0.0)
|
||||
return false;
|
||||
p21.X() = p2.X() - p1.X();
|
||||
p21.Y() = p2.Y() - p1.Y();
|
||||
p21.Z() = p2.Z() - p1.Z();
|
||||
if (p21.X()==0.0 && p21.Y()==0.0 && p21.Z()==0.0)
|
||||
return false;
|
||||
|
||||
d1343 = p13.X() * p43.X() + p13.Y() * p43.Y() + p13.Z() * p43.Z();
|
||||
d4321 = p43.X() * p21.X() + p43.Y() * p21.Y() + p43.Z() * p21.Z();
|
||||
d1321 = p13.X() * p21.X() + p13.Y() * p21.Y() + p13.Z() * p21.Z();
|
||||
d4343 = p43.X() * p43.X() + p43.Y() * p43.Y() + p43.Z() * p43.Z();
|
||||
d2121 = p21.X() * p21.X() + p21.Y() * p21.Y() + p21.Z() * p21.Z();
|
||||
|
||||
denom = d2121 * d4343 - d4321 * d4321;
|
||||
if (denom==0.0)
|
||||
return false;
|
||||
numer = d1343 * d4321 - d1321 * d4343;
|
||||
|
||||
mua = numer / denom;
|
||||
mub = (d1343 + d4321 * (mua)) / d4343;
|
||||
|
||||
pa.X() = p1.X() + mua * p21.X();
|
||||
pa.Y() = p1.Y() + mua * p21.Y();
|
||||
pa.Z() = p1.Z() + mua * p21.Z();
|
||||
pb.X() = p3.X() + mub * p43.X();
|
||||
pb.Y() = p3.Y() + mub * p43.Y();
|
||||
pb.Z() = p3.Z() + mub * p43.Z();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
long IntersectRayTriangle2(const Vec3<double> & P0, const Vec3<double> & dir,
|
||||
const Vec3<double> & V0, const Vec3<double> & V1,
|
||||
const Vec3<double> & V2, double &r)
|
||||
{
|
||||
Vec3<double> u, v, n; // triangle vectors
|
||||
Vec3<double> w0, w; // ray vectors
|
||||
double a, b; // params to calc ray-plane intersect
|
||||
|
||||
// get triangle edge vectors and plane normal
|
||||
u = V1 - V0;
|
||||
v = V2 - V0;
|
||||
n = u ^ v; // cross product
|
||||
if (n.GetNorm() == 0.0) // triangle is degenerate
|
||||
return -1; // do not deal with this case
|
||||
|
||||
w0 = P0 - V0;
|
||||
a = - n * w0;
|
||||
b = n * dir;
|
||||
if (fabs(b) <= 0.0) { // ray is parallel to triangle plane
|
||||
if (a == 0.0) // ray lies in triangle plane
|
||||
return 2;
|
||||
else return 0; // ray disjoint from plane
|
||||
}
|
||||
|
||||
// get intersect point of ray with triangle plane
|
||||
r = a / b;
|
||||
if (r < 0.0) // ray goes away from triangle
|
||||
return 0; // => no intersect
|
||||
// for a segment, also test if (r > 1.0) => no intersect
|
||||
|
||||
Vec3<double> I = P0 + r * dir; // intersect point of ray and plane
|
||||
|
||||
// is I inside T?
|
||||
double uu, uv, vv, wu, wv, D;
|
||||
uu = u * u;
|
||||
uv = u * v;
|
||||
vv = v * v;
|
||||
w = I - V0;
|
||||
wu = w * u;
|
||||
wv = w * v;
|
||||
D = uv * uv - uu * vv;
|
||||
|
||||
// get and test parametric coords
|
||||
double s, t;
|
||||
s = (uv * wv - vv * wu) / D;
|
||||
if (s < 0.0 || s > 1.0) // I is outside T
|
||||
return 0;
|
||||
t = (uv * wu - uu * wv) / D;
|
||||
if (t < 0.0 || (s + t) > 1.0) // I is outside T
|
||||
return 0;
|
||||
return 1; // I is in T
|
||||
}
|
||||
|
||||
|
||||
bool TMMesh::CheckConsistancy()
|
||||
{
|
||||
size_t nE = m_edges.GetSize();
|
||||
size_t nT = m_triangles.GetSize();
|
||||
for(size_t e = 0; e < nE; e++)
|
||||
{
|
||||
for(int f = 0; f < 2; f++)
|
||||
{
|
||||
if (!m_edges.GetHead()->GetData().m_triangles[f])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
m_edges.Next();
|
||||
}
|
||||
|
||||
for(size_t f = 0; f < nT; f++)
|
||||
{
|
||||
for(int e = 0; e < 3; e++)
|
||||
{
|
||||
int found = 0;
|
||||
for(int k = 0; k < 2; k++)
|
||||
{
|
||||
if (m_triangles.GetHead()->GetData().m_edges[e]->GetData().m_triangles[k] == m_triangles.GetHead())
|
||||
{
|
||||
found++;
|
||||
}
|
||||
}
|
||||
if (found != 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
m_triangles.Next();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
bool TMMesh::Normalize()
|
||||
{
|
||||
size_t nV = m_vertices.GetSize();
|
||||
if (nV == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
m_barycenter = m_vertices.GetHead()->GetData().m_pos;
|
||||
Vec3<Real> min = m_barycenter;
|
||||
Vec3<Real> max = m_barycenter;
|
||||
Real x, y, z;
|
||||
for(size_t v = 1; v < nV; v++)
|
||||
{
|
||||
m_barycenter += m_vertices.GetHead()->GetData().m_pos;
|
||||
x = m_vertices.GetHead()->GetData().m_pos.X();
|
||||
y = m_vertices.GetHead()->GetData().m_pos.Y();
|
||||
z = m_vertices.GetHead()->GetData().m_pos.Z();
|
||||
if ( x < min.X()) min.X() = x;
|
||||
else if ( x > max.X()) max.X() = x;
|
||||
if ( y < min.Y()) min.Y() = y;
|
||||
else if ( y > max.Y()) max.Y() = y;
|
||||
if ( z < min.Z()) min.Z() = z;
|
||||
else if ( z > max.Z()) max.Z() = z;
|
||||
m_vertices.Next();
|
||||
}
|
||||
m_barycenter /= static_cast<Real>(nV);
|
||||
m_diag = static_cast<Real>(0.001 * (max-min).GetNorm());
|
||||
const Real invDiag = static_cast<Real>(1.0 / m_diag);
|
||||
if (m_diag != 0.0)
|
||||
{
|
||||
for(size_t v = 0; v < nV; v++)
|
||||
{
|
||||
m_vertices.GetHead()->GetData().m_pos = (m_vertices.GetHead()->GetData().m_pos - m_barycenter) * invDiag;
|
||||
m_vertices.Next();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool TMMesh::Denormalize()
|
||||
{
|
||||
size_t nV = m_vertices.GetSize();
|
||||
if (nV == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (m_diag != 0.0)
|
||||
{
|
||||
for(size_t v = 0; v < nV; v++)
|
||||
{
|
||||
m_vertices.GetHead()->GetData().m_pos = m_vertices.GetHead()->GetData().m_pos * m_diag + m_barycenter;
|
||||
m_vertices.Next();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
269
indra/libhacd/hacdManifoldMesh.h
Normal file
269
indra/libhacd/hacdManifoldMesh.h
Normal file
@@ -0,0 +1,269 @@
|
||||
/* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
|
||||
All rights reserved.
|
||||
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
|
||||
All rights reserved.
|
||||
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#ifndef HACD_MANIFOLD_MESH_H
|
||||
#define HACD_MANIFOLD_MESH_H
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include "hacdVersion.h"
|
||||
#include "hacdCircularList.h"
|
||||
#include "hacdVector.h"
|
||||
#include "hacdSArray.h"
|
||||
#include <set>
|
||||
#include "hacdMicroAllocator.h"
|
||||
namespace HACD
|
||||
{
|
||||
class TMMTriangle;
|
||||
class TMMEdge;
|
||||
class TMMesh;
|
||||
class ICHull;
|
||||
class HACD;
|
||||
|
||||
class DPoint
|
||||
{
|
||||
public:
|
||||
DPoint(long name=0, Real dist=0, bool computed=false, bool distOnly=false)
|
||||
:m_name(name),
|
||||
m_dist(dist),
|
||||
m_computed(computed),
|
||||
m_distOnly(distOnly){};
|
||||
~DPoint(){};
|
||||
private:
|
||||
long m_name;
|
||||
Real m_dist;
|
||||
bool m_computed;
|
||||
bool m_distOnly;
|
||||
friend class TMMTriangle;
|
||||
friend class TMMesh;
|
||||
friend class GraphVertex;
|
||||
friend class GraphEdge;
|
||||
friend class Graph;
|
||||
friend class ICHull;
|
||||
friend class HACD;
|
||||
};
|
||||
|
||||
//! Vertex data structure used in a triangular manifold mesh (TMM).
|
||||
class TMMVertex
|
||||
{
|
||||
public:
|
||||
void Initialize();
|
||||
TMMVertex(void);
|
||||
~TMMVertex(void);
|
||||
|
||||
private:
|
||||
Vec3<Real> m_pos;
|
||||
long m_name;
|
||||
size_t m_id;
|
||||
CircularListElement<TMMEdge> * m_duplicate; // pointer to incident cone edge (or NULL)
|
||||
bool m_onHull;
|
||||
bool m_tag;
|
||||
TMMVertex(const TMMVertex & rhs);
|
||||
|
||||
friend class HACD;
|
||||
friend class ICHull;
|
||||
friend class TMMesh;
|
||||
friend class TMMTriangle;
|
||||
friend class TMMEdge;
|
||||
};
|
||||
|
||||
//! Edge data structure used in a triangular manifold mesh (TMM).
|
||||
class TMMEdge
|
||||
{
|
||||
public:
|
||||
void Initialize();
|
||||
TMMEdge(void);
|
||||
~TMMEdge(void);
|
||||
private:
|
||||
size_t m_id;
|
||||
CircularListElement<TMMTriangle> * m_triangles[2];
|
||||
CircularListElement<TMMVertex> * m_vertices[2];
|
||||
CircularListElement<TMMTriangle> * m_newFace;
|
||||
|
||||
|
||||
TMMEdge(const TMMEdge & rhs);
|
||||
|
||||
friend class HACD;
|
||||
friend class ICHull;
|
||||
friend class TMMTriangle;
|
||||
friend class TMMVertex;
|
||||
friend class TMMesh;
|
||||
};
|
||||
|
||||
//! Triangle data structure used in a triangular manifold mesh (TMM).
|
||||
class TMMTriangle
|
||||
{
|
||||
public:
|
||||
void Initialize();
|
||||
TMMTriangle(void);
|
||||
~TMMTriangle(void);
|
||||
private:
|
||||
size_t m_id;
|
||||
CircularListElement<TMMEdge> * m_edges[3];
|
||||
CircularListElement<TMMVertex> * m_vertices[3];
|
||||
SArray<long, SARRAY_DEFAULT_MIN_SIZE> m_incidentPoints;
|
||||
bool m_visible;
|
||||
|
||||
TMMTriangle(const TMMTriangle & rhs);
|
||||
|
||||
friend class HACD;
|
||||
friend class ICHull;
|
||||
friend class TMMesh;
|
||||
friend class TMMVertex;
|
||||
friend class TMMEdge;
|
||||
};
|
||||
|
||||
class Material
|
||||
{
|
||||
public:
|
||||
Material(void);
|
||||
~Material(void){}
|
||||
// private:
|
||||
Vec3<double> m_diffuseColor;
|
||||
double m_ambientIntensity;
|
||||
Vec3<double> m_specularColor;
|
||||
Vec3<double> m_emissiveColor;
|
||||
double m_shininess;
|
||||
double m_transparency;
|
||||
|
||||
friend class TMMesh;
|
||||
friend class HACD;
|
||||
};
|
||||
|
||||
//! triangular manifold mesh data structure.
|
||||
class TMMesh
|
||||
{
|
||||
public:
|
||||
//!
|
||||
HeapManager * const GetHeapManager() const { return m_heapManager;}
|
||||
//!
|
||||
void SetHeapManager(HeapManager * const heapManager)
|
||||
{
|
||||
m_heapManager = heapManager;
|
||||
m_vertices.SetHeapManager(m_heapManager);
|
||||
m_edges.SetHeapManager(m_heapManager);
|
||||
m_triangles.SetHeapManager(m_heapManager);
|
||||
}
|
||||
//! Returns the number of vertices>
|
||||
inline size_t GetNVertices() const { return m_vertices.GetSize();}
|
||||
//! Returns the number of edges
|
||||
inline size_t GetNEdges() const { return m_edges.GetSize();}
|
||||
//! Returns the number of triangles
|
||||
inline size_t GetNTriangles() const { return m_triangles.GetSize();}
|
||||
//! Returns the vertices circular list
|
||||
inline const CircularList<TMMVertex> & GetVertices() const { return m_vertices;}
|
||||
//! Returns the edges circular list
|
||||
inline const CircularList<TMMEdge> & GetEdges() const { return m_edges;}
|
||||
//! Returns the triangles circular list
|
||||
inline const CircularList<TMMTriangle> & GetTriangles() const { return m_triangles;}
|
||||
//! Returns the vertices circular list
|
||||
inline CircularList<TMMVertex> & GetVertices() { return m_vertices;}
|
||||
//! Returns the edges circular list
|
||||
inline CircularList<TMMEdge> & GetEdges() { return m_edges;}
|
||||
//! Returns the triangles circular list
|
||||
inline CircularList<TMMTriangle> & GetTriangles() { return m_triangles;}
|
||||
//! Add vertex to the mesh
|
||||
CircularListElement<TMMVertex> * AddVertex() {return m_vertices.Add();}
|
||||
//! Add vertex to the mesh
|
||||
CircularListElement<TMMEdge> * AddEdge() {return m_edges.Add();}
|
||||
//! Add vertex to the mesh
|
||||
CircularListElement<TMMTriangle> * AddTriangle() {return m_triangles.Add();}
|
||||
//! Print mesh information
|
||||
void Print();
|
||||
//!
|
||||
void GetIFS(Vec3<Real> * const points, Vec3<long> * const triangles);
|
||||
#if 0
|
||||
//! Save mesh
|
||||
bool Save(const char *fileName);
|
||||
//! Save mesh to VRML 2.0 format
|
||||
bool SaveVRML2(std::ofstream &fout);
|
||||
//! Save mesh to VRML 2.0 format
|
||||
bool SaveVRML2(std::ofstream &fout, const Material & material);
|
||||
#endif
|
||||
//!
|
||||
void Clear();
|
||||
//!
|
||||
void Copy(TMMesh & mesh);
|
||||
//!
|
||||
bool CheckConsistancy();
|
||||
//!
|
||||
bool Normalize();
|
||||
//!
|
||||
bool Denormalize();
|
||||
//! Constructor
|
||||
TMMesh(HeapManager * const heapManager);
|
||||
//! Destructor
|
||||
virtual ~TMMesh(void);
|
||||
|
||||
private:
|
||||
CircularList<TMMVertex> m_vertices;
|
||||
CircularList<TMMEdge> m_edges;
|
||||
CircularList<TMMTriangle> m_triangles;
|
||||
Real m_diag; //>! length of the BB diagonal
|
||||
Vec3<Real> m_barycenter; //>! barycenter of the mesh
|
||||
HeapManager * m_heapManager;
|
||||
|
||||
// not defined
|
||||
TMMesh(const TMMesh & rhs);
|
||||
friend class ICHull;
|
||||
friend class HACD;
|
||||
};
|
||||
//! IntersectRayTriangle(): intersect a ray with a 3D triangle
|
||||
//! Input: a ray R, and a triangle T
|
||||
//! Output: *I = intersection point (when it exists)
|
||||
//! 0 = disjoint (no intersect)
|
||||
//! 1 = intersect in unique point I1
|
||||
long IntersectRayTriangle( const Vec3<double> & P0, const Vec3<double> & dir,
|
||||
const Vec3<double> & V0, const Vec3<double> & V1,
|
||||
const Vec3<double> & V2, double &t);
|
||||
|
||||
// intersect_RayTriangle(): intersect a ray with a 3D triangle
|
||||
// Input: a ray R, and a triangle T
|
||||
// Output: *I = intersection point (when it exists)
|
||||
// Return: -1 = triangle is degenerate (a segment or point)
|
||||
// 0 = disjoint (no intersect)
|
||||
// 1 = intersect in unique point I1
|
||||
// 2 = are in the same plane
|
||||
long IntersectRayTriangle2(const Vec3<double> & P0, const Vec3<double> & dir,
|
||||
const Vec3<double> & V0, const Vec3<double> & V1,
|
||||
const Vec3<double> & V2, double &r);
|
||||
|
||||
/*
|
||||
Calculate the line segment PaPb that is the shortest route between
|
||||
two lines P1P2 and P3P4. Calculate also the values of mua and mub where
|
||||
Pa = P1 + mua (P2 - P1)
|
||||
Pb = P3 + mub (P4 - P3)
|
||||
Return FALSE if no solution exists.
|
||||
*/
|
||||
bool IntersectLineLine(const Vec3<double> & p1, const Vec3<double> & p2,
|
||||
const Vec3<double> & p3, const Vec3<double> & p4,
|
||||
Vec3<double> & pa, Vec3<double> & pb,
|
||||
double & mua, double &mub);
|
||||
}
|
||||
#endif
|
||||
684
indra/libhacd/hacdMeshDecimator.cpp
Normal file
684
indra/libhacd/hacdMeshDecimator.cpp
Normal file
@@ -0,0 +1,684 @@
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <stdlib.h>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include "hacdMeshDecimator.h"
|
||||
|
||||
namespace HACD
|
||||
{
|
||||
MeshDecimator::MeshDecimator(void)
|
||||
{
|
||||
m_triangles = 0;
|
||||
m_points = 0;
|
||||
m_nPoints = 0;
|
||||
m_nInitialTriangles = 0;
|
||||
m_nVertices = 0;
|
||||
m_nTriangles = 0;
|
||||
m_nEdges = 0;
|
||||
m_trianglesTags = 0;
|
||||
m_ecolManifoldConstraint = true;
|
||||
m_callBack = 0;
|
||||
}
|
||||
|
||||
MeshDecimator::~MeshDecimator(void)
|
||||
{
|
||||
ReleaseMemory();
|
||||
}
|
||||
void MeshDecimator::ReleaseMemory()
|
||||
{
|
||||
delete [] m_trianglesTags;
|
||||
std::vector< MDVertex > emptyVertices(0);
|
||||
m_vertices.swap(emptyVertices);
|
||||
std::vector<MDEdge> emptyEdges(0);
|
||||
m_edges.swap(emptyEdges);
|
||||
m_pqueue = std::priority_queue<
|
||||
MDEdgePriorityQueue,
|
||||
std::vector<MDEdgePriorityQueue>,
|
||||
std::less<MDEdgePriorityQueue> >();
|
||||
m_triangles = 0;
|
||||
m_points = 0;
|
||||
m_nPoints = 0;
|
||||
m_nInitialTriangles = 0;
|
||||
m_nVertices = 0;
|
||||
m_nTriangles = 0;
|
||||
m_nEdges = 0;
|
||||
m_trianglesTags = 0;
|
||||
}
|
||||
void MeshDecimator::Initialize(size_t nVertices, size_t nTriangles, Vec3<Float> * points, Vec3<long> * triangles)
|
||||
{
|
||||
m_nVertices = nVertices;
|
||||
m_nTriangles = nTriangles;
|
||||
m_nInitialTriangles = nTriangles;
|
||||
m_points = points;
|
||||
m_nPoints = nVertices;
|
||||
m_triangles = triangles;
|
||||
m_trianglesTags = new bool[m_nTriangles];
|
||||
m_edges.reserve(3*m_nTriangles);
|
||||
m_vertices.resize(m_nVertices);
|
||||
for(size_t v = 0; v < m_nVertices; ++v)
|
||||
{
|
||||
m_vertices[v].m_tag = true;
|
||||
}
|
||||
long tri[3];
|
||||
MDEdge edge;
|
||||
edge.m_tag = true;
|
||||
edge.m_onBoundary = true;
|
||||
long nEdges = 0;
|
||||
long idEdge;
|
||||
long nTris = static_cast<long>(m_nTriangles);
|
||||
for(long t = 0; t < nTris; ++t)
|
||||
{
|
||||
tri[0] = m_triangles[t].X();
|
||||
tri[1] = m_triangles[t].Y();
|
||||
tri[2] = m_triangles[t].Z();
|
||||
m_trianglesTags[t] = true;
|
||||
for(int k = 0; k < 3; ++k)
|
||||
{
|
||||
edge.m_v1 = tri[k];
|
||||
edge.m_v2 = tri[(k+1)%3];
|
||||
m_vertices[edge.m_v1].m_triangles.Insert(t);
|
||||
idEdge = GetEdge(edge.m_v1, edge.m_v2);
|
||||
if (idEdge == -1)
|
||||
{
|
||||
m_edges.push_back(edge);
|
||||
m_vertices[edge.m_v1].m_edges.Insert(nEdges);
|
||||
m_vertices[edge.m_v2].m_edges.Insert(nEdges);
|
||||
++nEdges;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_edges[idEdge].m_onBoundary = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_nEdges = static_cast<size_t>(nEdges);
|
||||
for(size_t v = 0; v < m_nVertices; ++v)
|
||||
{
|
||||
m_vertices[v].m_onBoundary = false;
|
||||
for(size_t itE = 0; itE < m_vertices[v].m_edges.Size(); ++itE)
|
||||
{
|
||||
idEdge = m_vertices[v].m_edges[itE];
|
||||
if (m_edges[idEdge].m_onBoundary)
|
||||
{
|
||||
m_vertices[v].m_onBoundary = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
long MeshDecimator::GetTriangle(long v1, long v2, long v3) const
|
||||
{
|
||||
long i, j, k;
|
||||
long idTriangle;
|
||||
for(size_t it = 0; it < m_vertices[v1].m_triangles.Size(); ++it)
|
||||
{
|
||||
idTriangle = m_vertices[v1].m_triangles[it];
|
||||
i = m_triangles[idTriangle].X();
|
||||
j = m_triangles[idTriangle].Y();
|
||||
k = m_triangles[idTriangle].Z();
|
||||
if ( (i==v1 && j==v2 && k==v3) || (i==v1 && j==v3 && k==v2) ||
|
||||
(i==v2 && j==v1 && k==v3) || (i==v2 && j==v3 && k==v1) ||
|
||||
(i==v3 && j==v2 && k==v1) || (i==v3 && j==v1 && k==v2) )
|
||||
{
|
||||
return idTriangle;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
long MeshDecimator::GetEdge(long v1, long v2) const
|
||||
{
|
||||
long idEdge;
|
||||
for(size_t it = 0; it < m_vertices[v1].m_edges.Size(); ++it)
|
||||
{
|
||||
idEdge = m_vertices[v1].m_edges[it];
|
||||
if ( (m_edges[idEdge].m_v1==v1 && m_edges[idEdge].m_v2==v2) ||
|
||||
(m_edges[idEdge].m_v1==v2 && m_edges[idEdge].m_v2==v1) )
|
||||
{
|
||||
return idEdge;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
void MeshDecimator::EdgeCollapse(long v1, long v2)
|
||||
{
|
||||
long u, w;
|
||||
int shift;
|
||||
long idTriangle;
|
||||
for(size_t itT = 0; itT < m_vertices[v2].m_triangles.Size(); ++itT)
|
||||
{
|
||||
idTriangle = m_vertices[v2].m_triangles[itT];
|
||||
if (m_triangles[idTriangle].X() == v2)
|
||||
{
|
||||
shift = 0;
|
||||
u = m_triangles[idTriangle].Y();
|
||||
w = m_triangles[idTriangle].Z();
|
||||
}
|
||||
else if (m_triangles[idTriangle].Y() == v2)
|
||||
{
|
||||
shift = 1;
|
||||
u = m_triangles[idTriangle].X();
|
||||
w = m_triangles[idTriangle].Z();
|
||||
}
|
||||
else
|
||||
{
|
||||
shift = 2;
|
||||
u = m_triangles[idTriangle].X();
|
||||
w = m_triangles[idTriangle].Y();
|
||||
}
|
||||
|
||||
if ((u == v1) || (w == v1))
|
||||
{
|
||||
m_trianglesTags[idTriangle] = false;
|
||||
m_vertices[u].m_triangles.Erase(idTriangle);
|
||||
m_vertices[w].m_triangles.Erase(idTriangle);
|
||||
m_nTriangles--;
|
||||
}
|
||||
else if (GetTriangle(v1, u, w) == -1)
|
||||
{
|
||||
m_vertices[v1].m_triangles.Insert(idTriangle);
|
||||
m_triangles[idTriangle][shift] = v1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_trianglesTags[idTriangle] = false;
|
||||
m_vertices[u].m_triangles.Erase(idTriangle);
|
||||
m_vertices[w].m_triangles.Erase(idTriangle);
|
||||
m_nTriangles--;
|
||||
}
|
||||
}
|
||||
long idEdge;
|
||||
for(size_t itE = 0; itE < m_vertices[v2].m_edges.Size(); ++itE)
|
||||
{
|
||||
idEdge = m_vertices[v2].m_edges[itE];
|
||||
w = (m_edges[idEdge].m_v1 == v2)? m_edges[idEdge].m_v2 : m_edges[idEdge].m_v1;
|
||||
if (w==v1)
|
||||
{
|
||||
m_edges[idEdge].m_tag = false;
|
||||
m_vertices[w].m_edges.Erase(idEdge);
|
||||
m_nEdges--;
|
||||
}
|
||||
else if ( GetEdge(v1, w) == -1)
|
||||
{
|
||||
if (m_edges[idEdge].m_v1 == v2) m_edges[idEdge].m_v1 = v1;
|
||||
else m_edges[idEdge].m_v2 = v1;
|
||||
m_vertices[v1].m_edges.Insert(idEdge);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_edges[idEdge].m_tag = false;
|
||||
m_vertices[w].m_edges.Erase(idEdge);
|
||||
m_nEdges--;
|
||||
}
|
||||
}
|
||||
m_vertices[v2].m_tag = false;
|
||||
m_nVertices--;
|
||||
// update boundary edges
|
||||
SArray<long, 64> incidentVertices;
|
||||
incidentVertices.PushBack(v1);
|
||||
for(size_t itE = 0; itE < m_vertices[v1].m_edges.Size(); ++itE)
|
||||
{
|
||||
incidentVertices.PushBack((m_edges[idEdge].m_v1!= v1)?m_edges[idEdge].m_v1:m_edges[idEdge].m_v2);
|
||||
idEdge = m_vertices[v1].m_edges[itE];
|
||||
m_edges[idEdge].m_onBoundary = (IsBoundaryEdge(m_edges[idEdge].m_v1, m_edges[idEdge].m_v2) != -1);
|
||||
}
|
||||
// update boundary vertices
|
||||
long idVertex;
|
||||
for(size_t itV = 0; itV < incidentVertices.Size(); ++itV)
|
||||
{
|
||||
idVertex = incidentVertices[itV];
|
||||
m_vertices[idVertex].m_onBoundary = false;
|
||||
for(size_t itE = 0; itE < m_vertices[idVertex].m_edges.Size(); ++itE)
|
||||
{
|
||||
idEdge = m_vertices[idVertex].m_edges[itE];
|
||||
if (m_edges[idEdge].m_onBoundary)
|
||||
{
|
||||
m_vertices[idVertex].m_onBoundary = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
long MeshDecimator::IsBoundaryEdge(long v1, long v2) const
|
||||
{
|
||||
long commonTri = -1;
|
||||
long itTriangle1, itTriangle2;
|
||||
for(size_t itT1 = 0; itT1 < m_vertices[v1].m_triangles.Size(); ++itT1)
|
||||
{
|
||||
itTriangle1 = m_vertices[v1].m_triangles[itT1];
|
||||
for(size_t itT2 = 0; itT2 < m_vertices[v2].m_triangles.Size(); ++itT2)
|
||||
{
|
||||
itTriangle2 = m_vertices[v2].m_triangles[itT2];
|
||||
if (itTriangle1 == itTriangle2)
|
||||
{
|
||||
if (commonTri == -1)
|
||||
{
|
||||
commonTri = itTriangle1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return commonTri;
|
||||
}
|
||||
bool MeshDecimator::IsBoundaryVertex(long v) const
|
||||
{
|
||||
long idEdge;
|
||||
for(size_t itE = 0; itE < m_vertices[v].m_edges.Size(); ++itE)
|
||||
{
|
||||
idEdge = m_vertices[v].m_edges[itE];
|
||||
if ( IsBoundaryEdge(m_edges[idEdge].m_v1, m_edges[idEdge].m_v2) != -1) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void MeshDecimator::GetMeshData(Vec3<Float> * points, Vec3<long> * triangles) const
|
||||
{
|
||||
long * map = new long [m_nPoints];
|
||||
long counter = 0;
|
||||
for (size_t v = 0; v < m_nPoints; ++v)
|
||||
{
|
||||
if ( m_vertices[v].m_tag )
|
||||
{
|
||||
points[counter] = m_points[v];
|
||||
map[v] = counter++;
|
||||
}
|
||||
}
|
||||
counter = 0;
|
||||
for (size_t t = 0; t < m_nInitialTriangles; ++t)
|
||||
{
|
||||
if ( m_trianglesTags[t] )
|
||||
{
|
||||
triangles[counter].X() = map[m_triangles[t].X()];
|
||||
triangles[counter].Y() = map[m_triangles[t].Y()];
|
||||
triangles[counter].Z() = map[m_triangles[t].Z()];
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
delete [] map;
|
||||
}
|
||||
|
||||
void MeshDecimator::InitializeQEM()
|
||||
{
|
||||
Vec3<Float> coordMin = m_points[0];
|
||||
Vec3<Float> coordMax = m_points[0];
|
||||
Vec3<Float> coord;
|
||||
for (size_t p = 1; p < m_nPoints ; ++p)
|
||||
{
|
||||
coord = m_points[p];
|
||||
if (coordMin.X() > coord.X()) coordMin.X() = coord.X();
|
||||
if (coordMin.Y() > coord.Y()) coordMin.Y() = coord.Y();
|
||||
if (coordMin.Z() > coord.Z()) coordMin.Z() = coord.Z();
|
||||
if (coordMax.X() < coord.X()) coordMax.X() = coord.X();
|
||||
if (coordMax.Y() < coord.Y()) coordMax.Y() = coord.Y();
|
||||
if (coordMax.Z() < coord.Z()) coordMax.Z() = coord.Z();
|
||||
}
|
||||
coordMax -= coordMin;
|
||||
m_diagBB = coordMax.GetNorm();
|
||||
|
||||
long i, j, k;
|
||||
Vec3<Float> n;
|
||||
Float d = 0;
|
||||
Float area = 0;
|
||||
for(size_t v = 0; v < m_nPoints; ++v)
|
||||
{
|
||||
memset(m_vertices[v].m_Q, 0, 10 * sizeof(Float));
|
||||
long idTriangle;
|
||||
for(size_t itT = 0; itT < m_vertices[v].m_triangles.Size(); ++itT)
|
||||
{
|
||||
idTriangle = m_vertices[v].m_triangles[itT];
|
||||
i = m_triangles[idTriangle].X();
|
||||
j = m_triangles[idTriangle].Y();
|
||||
k = m_triangles[idTriangle].Z();
|
||||
n = (m_points[j] - m_points[i])^(m_points[k] - m_points[i]);
|
||||
area = n.GetNorm();
|
||||
n.Normalize();
|
||||
d = - (m_points[v] * n);
|
||||
m_vertices[v].m_Q[0] += area * (n.X() * n.X());
|
||||
m_vertices[v].m_Q[1] += area * (n.X() * n.Y());
|
||||
m_vertices[v].m_Q[2] += area * (n.X() * n.Z());
|
||||
m_vertices[v].m_Q[3] += area * (n.X() * d);
|
||||
m_vertices[v].m_Q[4] += area * (n.Y() * n.Y());
|
||||
m_vertices[v].m_Q[5] += area * (n.Y() * n.Z());
|
||||
m_vertices[v].m_Q[6] += area * (n.Y() * d);
|
||||
m_vertices[v].m_Q[7] += area * (n.Z() * n.Z());
|
||||
m_vertices[v].m_Q[8] += area * (n.Z() * d);
|
||||
m_vertices[v].m_Q[9] += area * (d * d);
|
||||
}
|
||||
}
|
||||
Vec3<Float> u1, u2;
|
||||
const Float w = static_cast<Float>(1000);
|
||||
long t, v1, v2, v3;
|
||||
for(size_t e = 0; e < m_edges.size(); ++e)
|
||||
{
|
||||
v1 = m_edges[e].m_v1;
|
||||
v2 = m_edges[e].m_v2;
|
||||
t = IsBoundaryEdge(v1, v2);
|
||||
if (t != -1)
|
||||
{
|
||||
if (m_triangles[t].X() != v1 && m_triangles[t].X() != v2) v3 = m_triangles[t].X();
|
||||
else if (m_triangles[t].Y() != v1 && m_triangles[t].Y() != v2) v3 = m_triangles[t].Y();
|
||||
else v3 = m_triangles[t].Z();
|
||||
u1 = m_points[v2] - m_points[v1];
|
||||
u2 = m_points[v3] - m_points[v1];
|
||||
area = w * (u1^u2).GetNorm();
|
||||
u1.Normalize();
|
||||
n = u2 - (u2 * u1) * u1;
|
||||
n.Normalize();
|
||||
|
||||
d = - (m_points[v1] * n);
|
||||
m_vertices[v1].m_Q[0] += area * (n.X() * n.X());
|
||||
m_vertices[v1].m_Q[1] += area * (n.X() * n.Y());
|
||||
m_vertices[v1].m_Q[2] += area * (n.X() * n.Z());
|
||||
m_vertices[v1].m_Q[3] += area * (n.X() * d);
|
||||
m_vertices[v1].m_Q[4] += area * (n.Y() * n.Y());
|
||||
m_vertices[v1].m_Q[5] += area * (n.Y() * n.Z());
|
||||
m_vertices[v1].m_Q[6] += area * (n.Y() * d);
|
||||
m_vertices[v1].m_Q[7] += area * (n.Z() * n.Z());
|
||||
m_vertices[v1].m_Q[8] += area * (n.Z() * d);
|
||||
m_vertices[v1].m_Q[9] += area * (d * d);
|
||||
|
||||
d = - (m_points[v2] * n);
|
||||
m_vertices[v2].m_Q[0] += area * (n.X() * n.X());
|
||||
m_vertices[v2].m_Q[1] += area * (n.X() * n.Y());
|
||||
m_vertices[v2].m_Q[2] += area * (n.X() * n.Z());
|
||||
m_vertices[v2].m_Q[3] += area * (n.X() * d);
|
||||
m_vertices[v2].m_Q[4] += area * (n.Y() * n.Y());
|
||||
m_vertices[v2].m_Q[5] += area * (n.Y() * n.Z());
|
||||
m_vertices[v2].m_Q[6] += area * (n.Y() * d);
|
||||
m_vertices[v2].m_Q[7] += area * (n.Z() * n.Z());
|
||||
m_vertices[v2].m_Q[8] += area * (n.Z() * d);
|
||||
m_vertices[v2].m_Q[9] += area * (d * d);
|
||||
}
|
||||
}
|
||||
}
|
||||
void MeshDecimator::InitializePriorityQueue()
|
||||
{
|
||||
double progressOld = -1.0;
|
||||
double progress = 0.0;
|
||||
char msg[1024];
|
||||
double ptgStep = 1.0;
|
||||
long v1, v2;
|
||||
MDEdgePriorityQueue pqEdge;
|
||||
size_t nE = m_edges.size();
|
||||
for(size_t e = 0; e < nE; ++e)
|
||||
{
|
||||
progress = e * 100.0 / nE;
|
||||
if (fabs(progress-progressOld) > ptgStep && m_callBack)
|
||||
{
|
||||
sprintf(msg, "%3.2f %% \t \t \r", progress);
|
||||
(*m_callBack)(msg, progress, 0.0, m_nVertices);
|
||||
progressOld = progress;
|
||||
}
|
||||
|
||||
if (m_edges[e].m_tag)
|
||||
{
|
||||
v1 = m_edges[e].m_v1;
|
||||
v2 = m_edges[e].m_v2;
|
||||
if ( (!m_ecolManifoldConstraint) || (ManifoldConstraint(v1, v2)))
|
||||
{
|
||||
pqEdge.m_qem = m_edges[e].m_qem = ComputeEdgeCost(v1, v2, m_edges[e].m_pos);
|
||||
pqEdge.m_name = static_cast<long>(e);
|
||||
m_pqueue.push(pqEdge);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
double MeshDecimator::ComputeEdgeCost(long v1, long v2, Vec3<Float> & newPos) const
|
||||
{
|
||||
double Q[10];
|
||||
double M[12];
|
||||
Vec3<double> pos;
|
||||
for(int i = 0; i < 10; ++i) Q[i] = m_vertices[v1].m_Q[i] + m_vertices[v2].m_Q[i];
|
||||
M[0] = Q[0]; // (0, 0)
|
||||
M[1] = Q[1]; // (0, 1)
|
||||
M[2] = Q[2]; // (0, 2)
|
||||
M[3] = Q[3]; // (0, 3)
|
||||
M[4] = Q[1]; // (1, 0)
|
||||
M[5] = Q[4]; // (1, 1)
|
||||
M[6] = Q[5]; // (1, 2)
|
||||
M[7] = Q[6]; // (1, 3)
|
||||
M[8] = Q[2]; // (2, 0)
|
||||
M[9] = Q[5]; // (2, 1)
|
||||
M[10] = Q[7]; // (2, 2);
|
||||
M[11] = Q[8]; // (2, 3);
|
||||
double det = M[0] * M[5] * M[10] + M[1] * M[6] * M[8] + M[2] * M[4] * M[9]
|
||||
- M[0] * M[6] * M[9] - M[1] * M[4] * M[10]- M[2] * M[5] * M[8];
|
||||
if (det != 0.0)
|
||||
{
|
||||
double d = 1.0 / det;
|
||||
pos.X() = d * (M[1]*M[7]*M[10] + M[2]*M[5]*M[11] + M[3]*M[6]*M[9]
|
||||
-M[1]*M[6]*M[11] - M[2]*M[7]*M[9] - M[3]*M[5]*M[10]);
|
||||
pos.Y() = d * (M[0]*M[6]*M[11] + M[2]*M[7]*M[8] + M[3]*M[4]*M[10]
|
||||
-M[0]*M[7]*M[10] - M[2]*M[4]*M[11] - M[3]*M[6]*M[8]);
|
||||
pos.Z() = d * (M[0]*M[7]*M[9] + M[1]*M[4]*M[11] + M[3]*M[5]*M[8]
|
||||
-M[0]*M[5]*M[11] - M[1]*M[7]*M[8] - M[3]*M[4]*M[9]);
|
||||
newPos.X() = static_cast<Float>(pos.X());
|
||||
newPos.Y() = static_cast<Float>(pos.Y());
|
||||
newPos.Z() = static_cast<Float>(pos.Z());
|
||||
}
|
||||
else
|
||||
{
|
||||
const Float w = static_cast<Float>(0.5f);
|
||||
newPos = w * m_points[v1] + w * m_points[v2];
|
||||
pos.X() = static_cast<double>(newPos.X());
|
||||
pos.Y() = static_cast<double>(newPos.Y());
|
||||
pos.Z() = static_cast<double>(newPos.Z());
|
||||
}
|
||||
|
||||
double qem = pos.X() * (Q[0] * pos.X() + Q[1] * pos.Y() + Q[2] * pos.Z() + Q[3]) +
|
||||
pos.Y() * (Q[1] * pos.X() + Q[4] * pos.Y() + Q[5] * pos.Z() + Q[6]) +
|
||||
pos.Z() * (Q[2] * pos.X() + Q[5] * pos.Y() + Q[7] * pos.Z() + Q[8]) +
|
||||
(Q[3] * pos.X() + Q[6] * pos.Y() + Q[8] * pos.Z() + Q[9]) ;
|
||||
|
||||
Vec3<Float> d1;
|
||||
Vec3<Float> d2;
|
||||
Vec3<Float> n1;
|
||||
Vec3<Float> n2;
|
||||
Vec3<Float> oldPosV1 = m_points[v1];
|
||||
Vec3<Float> oldPosV2 = m_points[v2];
|
||||
|
||||
SArray<long, SARRAY_DEFAULT_MIN_SIZE> triangles = m_vertices[v1].m_triangles;
|
||||
long idTriangle;
|
||||
for(size_t itT = 0; itT < m_vertices[v2].m_triangles.Size(); ++itT)
|
||||
{
|
||||
idTriangle = m_vertices[v2].m_triangles[itT];
|
||||
triangles.Insert(idTriangle);
|
||||
}
|
||||
long a[3];
|
||||
for(size_t itT = 0; itT != triangles.Size(); ++itT)
|
||||
{
|
||||
idTriangle = triangles[itT];
|
||||
a[0] = m_triangles[idTriangle].X();
|
||||
a[1] = m_triangles[idTriangle].Y();
|
||||
a[2] = m_triangles[idTriangle].Z();
|
||||
|
||||
d1 = m_points[a[1]] - m_points[a[0]];
|
||||
d2 = m_points[a[2]] - m_points[a[0]];
|
||||
n1 = d1^d2;
|
||||
|
||||
m_points[v1] = newPos;
|
||||
m_points[v2] = newPos;
|
||||
|
||||
d1 = m_points[a[1]] - m_points[a[0]];
|
||||
d2 = m_points[a[2]] - m_points[a[0]];
|
||||
n2 = d1^d2;
|
||||
|
||||
m_points[v1] = oldPosV1;
|
||||
m_points[v2] = oldPosV2;
|
||||
|
||||
n1.Normalize();
|
||||
n2.Normalize();
|
||||
if (n1*n2 < 0.0)
|
||||
{
|
||||
return std::numeric_limits<double>::max();
|
||||
}
|
||||
}
|
||||
if ( m_ecolManifoldConstraint && !ManifoldConstraint(v1, v2))
|
||||
{
|
||||
return std::numeric_limits<double>::max();
|
||||
}
|
||||
return qem;
|
||||
}
|
||||
bool MeshDecimator::ManifoldConstraint(long v1, long v2) const
|
||||
{
|
||||
std::set<long> vertices;
|
||||
long a, b;
|
||||
long idEdge1;
|
||||
long idEdge2;
|
||||
long idEdgeV1V2;
|
||||
for(size_t itE1 = 0; itE1 < m_vertices[v1].m_edges.Size(); ++itE1)
|
||||
{
|
||||
idEdge1 = m_vertices[v1].m_edges[itE1];
|
||||
a = (m_edges[idEdge1].m_v1 == v1) ? m_edges[idEdge1].m_v2 : m_edges[idEdge1].m_v1;
|
||||
vertices.insert(a);
|
||||
if (a != v2)
|
||||
{
|
||||
for(size_t itE2 = 0; itE2 < m_vertices[v2].m_edges.Size(); ++itE2)
|
||||
{
|
||||
idEdge2 = m_vertices[v2].m_edges[itE2];
|
||||
b = (m_edges[idEdge2].m_v1 == v2) ? m_edges[idEdge2].m_v2 : m_edges[idEdge2].m_v1;
|
||||
vertices.insert(b);
|
||||
if ( a==b )
|
||||
{
|
||||
if (GetTriangle(v1, v2, a) == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
idEdgeV1V2 = idEdge1;
|
||||
}
|
||||
}
|
||||
if (vertices.size() <= 4 || ( m_vertices[v1].m_onBoundary && m_vertices[v2].m_onBoundary && !m_edges[idEdgeV1V2].m_onBoundary))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool MeshDecimator::EdgeCollapse(double & qem)
|
||||
{
|
||||
MDEdgePriorityQueue currentEdge;
|
||||
long v1, v2;
|
||||
bool done = false;
|
||||
do
|
||||
{
|
||||
done = false;
|
||||
if (m_pqueue.size() == 0)
|
||||
{
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentEdge = m_pqueue.top();
|
||||
m_pqueue.pop();
|
||||
}
|
||||
}
|
||||
while ( (!m_edges[currentEdge.m_name].m_tag) || (m_edges[currentEdge.m_name].m_qem != currentEdge.m_qem));
|
||||
|
||||
if (done) return false;
|
||||
v1 = m_edges[currentEdge.m_name].m_v1;
|
||||
v2 = m_edges[currentEdge.m_name].m_v2;
|
||||
|
||||
qem = currentEdge.m_qem;
|
||||
EdgeCollapse(v1, v2);
|
||||
m_points[v1] = m_edges[currentEdge.m_name].m_pos ;
|
||||
for(int k = 0; k < 10; k++) m_vertices[v1].m_Q[k] += m_vertices[v2].m_Q[k];
|
||||
|
||||
// Update priority queue
|
||||
long idEdge;
|
||||
long a, b;
|
||||
SArray<long, SARRAY_DEFAULT_MIN_SIZE> incidentVertices;
|
||||
for(size_t itE = 0; itE < m_vertices[v1].m_edges.Size(); ++itE)
|
||||
{
|
||||
idEdge = m_vertices[v1].m_edges[itE];
|
||||
a = m_edges[idEdge].m_v1;
|
||||
b = m_edges[idEdge].m_v2;
|
||||
incidentVertices.PushBack((a != v1)?a:b);
|
||||
MDEdgePriorityQueue pqEdge;
|
||||
pqEdge.m_qem = m_edges[idEdge].m_qem = ComputeEdgeCost(a, b, m_edges[idEdge].m_pos);
|
||||
pqEdge.m_name = idEdge;
|
||||
m_pqueue.push(pqEdge);
|
||||
}
|
||||
long idVertex;
|
||||
for(size_t itV = 0; itV< incidentVertices.Size(); ++itV)
|
||||
{
|
||||
idVertex = incidentVertices[itV];
|
||||
for(size_t itE = 0; itE < m_vertices[idVertex].m_edges.Size(); ++itE)
|
||||
{
|
||||
idEdge = m_vertices[idVertex].m_edges[itE];
|
||||
a = m_edges[idEdge].m_v1;
|
||||
b = m_edges[idEdge].m_v2;
|
||||
if ( a!=v1 && b!=v1)
|
||||
{
|
||||
MDEdgePriorityQueue pqEdge;
|
||||
pqEdge.m_qem = m_edges[idEdge].m_qem = ComputeEdgeCost(a, b, m_edges[idEdge].m_pos);
|
||||
pqEdge.m_name = idEdge;
|
||||
m_pqueue.push(pqEdge);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool MeshDecimator::Decimate(size_t targetNVertices, size_t targetNTriangles, double targetError)
|
||||
{
|
||||
double qem = 0.0;
|
||||
double progressOld = -1.0;
|
||||
double progress = 0.0;
|
||||
char msg[1024];
|
||||
double ptgStep = 1.0;
|
||||
|
||||
if (m_callBack)
|
||||
{
|
||||
std::ostringstream msg;
|
||||
msg << "+ Mesh" << std::endl;
|
||||
msg << "\t # vertices \t" << m_nPoints << std::endl;
|
||||
msg << "\t # triangles \t" << m_nTriangles << std::endl;
|
||||
msg << "+ Parameters" << std::endl;
|
||||
msg << "\t target # of vertices \t" << targetNVertices << std::endl;
|
||||
msg << "\t target # of triangles \t" << targetNTriangles << std::endl;
|
||||
msg << "\t QEM \t" << targetError << std::endl;
|
||||
(*m_callBack)(msg.str().c_str(), 0.0, 0.0, m_nPoints);
|
||||
}
|
||||
|
||||
if (m_callBack) (*m_callBack)("+ Initialize QEM \n", 0.0, 0.0, m_nPoints);
|
||||
InitializeQEM();
|
||||
if (m_callBack) (*m_callBack)("+ Initialize priority queue \n", 0.0, 0.0, m_nPoints);
|
||||
InitializePriorityQueue();
|
||||
if (m_callBack) (*m_callBack)("+ Simplification \n", 0.0, 0.0, m_nPoints);
|
||||
double invDiag2 = 1.0 / (m_diagBB * m_diagBB);
|
||||
while((m_pqueue.size() > 0) &&
|
||||
(m_nEdges > 0) &&
|
||||
(m_nVertices > targetNVertices) &&
|
||||
(m_nTriangles > targetNTriangles) &&
|
||||
(qem < targetError))
|
||||
{
|
||||
progress = 100.0 - m_nVertices * 100.0 / m_nPoints;
|
||||
if (fabs(progress-progressOld) > ptgStep && m_callBack)
|
||||
{
|
||||
sprintf(msg, "%3.2f %% V = %lu \t QEM = %f \t \t \r", progress, static_cast<unsigned long>(m_nVertices), sqrt(qem));
|
||||
(*m_callBack)(msg, progress, qem, m_nVertices);
|
||||
progressOld = progress;
|
||||
}
|
||||
if (!EdgeCollapse(qem)) break;
|
||||
qem *= invDiag2;
|
||||
}
|
||||
if (m_callBack)
|
||||
{
|
||||
std::ostringstream msg;
|
||||
msg << "+ Simplification output" << std::endl;
|
||||
msg << "\t # vertices \t" << m_nVertices << std::endl;
|
||||
msg << "\t # triangles \t" << m_nTriangles << std::endl;
|
||||
msg << "\t QEM \t" << qem << std::endl;
|
||||
(*m_callBack)(msg.str().c_str(), 100.0, qem, m_nVertices);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
116
indra/libhacd/hacdMeshDecimator.h
Normal file
116
indra/libhacd/hacdMeshDecimator.h
Normal file
@@ -0,0 +1,116 @@
|
||||
/* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
|
||||
All rights reserved.
|
||||
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#ifndef HACD_MESH_DECEMATOR_H
|
||||
#define HACD_MESH_DECEMATOR_H
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
#include "hacdVersion.h"
|
||||
#include "hacdVector.h"
|
||||
#include "hacdSArray.h"
|
||||
#include "hacdHACD.h"
|
||||
|
||||
namespace HACD
|
||||
{
|
||||
typedef double Float;
|
||||
struct MDVertex
|
||||
{
|
||||
SArray<long, SARRAY_DEFAULT_MIN_SIZE> m_edges;
|
||||
SArray<long, SARRAY_DEFAULT_MIN_SIZE> m_triangles;
|
||||
Float m_Q[10];
|
||||
// 0 1 2 3
|
||||
// 4 5 6
|
||||
// 7 8
|
||||
// 9
|
||||
bool m_tag;
|
||||
bool m_onBoundary;
|
||||
};
|
||||
|
||||
struct MDEdge
|
||||
{
|
||||
long m_v1;
|
||||
long m_v2;
|
||||
double m_qem;
|
||||
Vec3<Float> m_pos;
|
||||
bool m_onBoundary;
|
||||
bool m_tag;
|
||||
};
|
||||
struct MDEdgePriorityQueue
|
||||
{
|
||||
long m_name;
|
||||
double m_qem;
|
||||
inline friend bool operator<(const MDEdgePriorityQueue & lhs, const MDEdgePriorityQueue & rhs) { return (lhs.m_qem > rhs.m_qem);}
|
||||
inline friend bool operator>(const MDEdgePriorityQueue & lhs, const MDEdgePriorityQueue & rhs) { return (lhs.m_qem < rhs.m_qem);}
|
||||
};
|
||||
|
||||
class MeshDecimator
|
||||
{
|
||||
public:
|
||||
//! Sets the call-back function
|
||||
//! @param callBack pointer to the call-back function
|
||||
void SetCallBack(CallBackFunction callBack) { m_callBack = callBack;}
|
||||
//! Gives the call-back function
|
||||
//! @return pointer to the call-back function
|
||||
const CallBackFunction GetCallBack() const { return m_callBack;}
|
||||
|
||||
inline void SetEColManifoldConstraint(bool ecolManifoldConstraint) { m_ecolManifoldConstraint = ecolManifoldConstraint; }
|
||||
inline size_t GetNVertices()const {return m_nVertices;};
|
||||
inline size_t GetNTriangles() const {return m_nTriangles;};
|
||||
inline size_t GetNEdges() const {return m_nEdges;};
|
||||
void GetMeshData(Vec3<Float> * points, Vec3<long> * triangles) const;
|
||||
void ReleaseMemory();
|
||||
void Initialize(size_t nVertices, size_t nTriangles,
|
||||
Vec3<Float> * points,
|
||||
Vec3<long> * triangles);
|
||||
bool Decimate(size_t targetNVertices = 100,
|
||||
size_t targetNTriangles = 0,
|
||||
double targetError = std::numeric_limits<double>::max());
|
||||
|
||||
MeshDecimator(void);
|
||||
~MeshDecimator(void);
|
||||
private :
|
||||
void EdgeCollapse(long v1, long v2);
|
||||
long GetTriangle(long v1, long v2, long v3) const;
|
||||
long GetEdge(long v1, long v2) const;
|
||||
long IsBoundaryEdge(long v1, long v2) const;
|
||||
bool IsBoundaryVertex(long v) const;
|
||||
void InitializePriorityQueue();
|
||||
void InitializeQEM();
|
||||
bool ManifoldConstraint(long v1, long v2) const;
|
||||
double ComputeEdgeCost(long v1, long v2, Vec3<Float> & pos) const;
|
||||
bool EdgeCollapse(double & error);
|
||||
private:
|
||||
Vec3<long> * m_triangles;
|
||||
Vec3<Float> * m_points;
|
||||
size_t m_nPoints;
|
||||
size_t m_nInitialTriangles;
|
||||
size_t m_nVertices;
|
||||
size_t m_nTriangles;
|
||||
size_t m_nEdges;
|
||||
double m_diagBB;
|
||||
std::vector<MDVertex> m_vertices;
|
||||
std::vector<MDEdge> m_edges;
|
||||
std::priority_queue<
|
||||
MDEdgePriorityQueue,
|
||||
std::vector<MDEdgePriorityQueue>,
|
||||
std::less<MDEdgePriorityQueue> > m_pqueue;
|
||||
CallBackFunction m_callBack; //>! call-back function
|
||||
bool * m_trianglesTags;
|
||||
bool m_ecolManifoldConstraint;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
993
indra/libhacd/hacdMicroAllocator.cpp
Normal file
993
indra/libhacd/hacdMicroAllocator.cpp
Normal file
@@ -0,0 +1,993 @@
|
||||
#include "hacdMicroAllocator.h"
|
||||
|
||||
/*!
|
||||
**
|
||||
** Copyright (c) 2009 by John W. Ratcliff mailto:jratcliffscarab@gmail.com
|
||||
**
|
||||
** If you find this code useful or you are feeling particularily generous I would
|
||||
** ask that you please go to http://www.amillionpixels.us and make a donation
|
||||
** to Troy DeMolay.
|
||||
**
|
||||
**
|
||||
** If you wish to contact me you can use the following methods:
|
||||
**
|
||||
** Skype ID: jratcliff63367
|
||||
** email: jratcliffscarab@gmail.com
|
||||
**
|
||||
**
|
||||
** The MIT license:
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
** of this software and associated documentation files (the "Software"), to deal
|
||||
** in the Software without restriction, including without limitation the rights
|
||||
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
** copies of the Software, and to permit persons to whom the Software is furnished
|
||||
** to do so, subject to the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included in all
|
||||
** copies or substantial portions of the Software.
|
||||
|
||||
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
** WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
** CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include <new>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) || defined(LINUX)
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
|
||||
#pragma warning(disable:4100)
|
||||
|
||||
namespace HACD
|
||||
{
|
||||
|
||||
//==================================================================================
|
||||
class MemMutex
|
||||
{
|
||||
public:
|
||||
MemMutex(void);
|
||||
~MemMutex(void);
|
||||
|
||||
public:
|
||||
// Blocking Lock.
|
||||
void Lock(void);
|
||||
|
||||
// Unlock.
|
||||
void Unlock(void);
|
||||
|
||||
private:
|
||||
#if defined(_WIN32) || defined(_XBOX)
|
||||
CRITICAL_SECTION m_Mutex;
|
||||
#elif defined(__APPLE__) || defined(LINUX)
|
||||
pthread_mutex_t m_Mutex;
|
||||
#endif
|
||||
};
|
||||
|
||||
//==================================================================================
|
||||
MemMutex::MemMutex(void)
|
||||
{
|
||||
#if defined(_WIN32) || defined(_XBOX)
|
||||
InitializeCriticalSection(&m_Mutex);
|
||||
#elif defined(__APPLE__) || defined(LINUX)
|
||||
pthread_mutexattr_t mta;
|
||||
pthread_mutexattr_init(&mta);
|
||||
pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_RECURSIVE);
|
||||
pthread_mutex_init(&m_Mutex, &mta);
|
||||
pthread_mutexattr_destroy(&mta);
|
||||
#endif
|
||||
}
|
||||
|
||||
//==================================================================================
|
||||
MemMutex::~MemMutex(void)
|
||||
{
|
||||
#if defined(_WIN32) || defined(_XBOX)
|
||||
DeleteCriticalSection(&m_Mutex);
|
||||
#elif defined(__APPLE__) || defined(LINUX)
|
||||
pthread_mutex_destroy(&m_Mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
//==================================================================================
|
||||
// Blocking Lock.
|
||||
//==================================================================================
|
||||
void MemMutex::Lock(void)
|
||||
{
|
||||
#if defined(_WIN32) || defined(_XBOX)
|
||||
EnterCriticalSection(&m_Mutex);
|
||||
#elif defined(__APPLE__) || defined(LINUX)
|
||||
pthread_mutex_lock(&m_Mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
//==================================================================================
|
||||
// Unlock.
|
||||
//==================================================================================
|
||||
void MemMutex::Unlock(void)
|
||||
{
|
||||
#if defined(_WIN32) || defined(_XBOX)
|
||||
LeaveCriticalSection(&m_Mutex);
|
||||
#elif defined(__APPLE__) || defined(LINUX)
|
||||
pthread_mutex_unlock(&m_Mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct ChunkHeader
|
||||
{
|
||||
ChunkHeader *mNextChunk;
|
||||
};
|
||||
|
||||
// interface to add and remove new chunks to the master list.
|
||||
class MicroChunkUpdate
|
||||
{
|
||||
public:
|
||||
virtual void addMicroChunk(NxU8 *memStart,NxU8 *memEnd,MemoryChunk *chunk) = 0;
|
||||
virtual void removeMicroChunk(MemoryChunk *chunk) = 0;
|
||||
};
|
||||
|
||||
class MemoryHeader
|
||||
{
|
||||
public:
|
||||
MemoryHeader *mNext;
|
||||
};
|
||||
|
||||
// a single fixed size chunk for micro-allocations.
|
||||
class MemoryChunk
|
||||
{
|
||||
public:
|
||||
MemoryChunk(void)
|
||||
{
|
||||
mData = 0;
|
||||
mDataEnd = 0;
|
||||
mUsedCount = 0;
|
||||
mFreeList = 0;
|
||||
mMyHeap = false;
|
||||
mChunkSize = 0;
|
||||
}
|
||||
|
||||
NxU8 * init(NxU8 *chunkBase,NxU32 chunkSize,NxU32 maxChunks)
|
||||
{
|
||||
mChunkSize = chunkSize;
|
||||
mData = chunkBase;
|
||||
mDataEnd = mData+(chunkSize*maxChunks);
|
||||
mFreeList = (MemoryHeader *) mData;
|
||||
MemoryHeader *scan = mFreeList;
|
||||
NxU8 *data = mData;
|
||||
data+=chunkSize;
|
||||
for (NxU32 i=0; i<(maxChunks-1); i++)
|
||||
{
|
||||
MemoryHeader *next = (MemoryHeader *)data;
|
||||
scan->mNext = next;
|
||||
data+=chunkSize;
|
||||
scan = next;
|
||||
}
|
||||
scan->mNext = 0;
|
||||
return mDataEnd;
|
||||
}
|
||||
|
||||
inline void * allocate(MicroHeap *heap,NxU32 chunkSize,NxU32 maxChunks,MicroChunkUpdate *update)
|
||||
{
|
||||
void *ret = 0;
|
||||
|
||||
if ( mData == 0 )
|
||||
{
|
||||
mMyHeap = true;
|
||||
mData = (NxU8 *)heap->micro_malloc( chunkSize * maxChunks );
|
||||
init(mData,chunkSize,maxChunks);
|
||||
update->addMicroChunk(mData,mDataEnd,this);
|
||||
}
|
||||
if ( mFreeList )
|
||||
{
|
||||
mUsedCount++;
|
||||
ret = mFreeList;
|
||||
mFreeList = mFreeList->mNext;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline void deallocate(void *p,MicroHeap *heap,MicroChunkUpdate *update)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
assert(mUsedCount);
|
||||
NxU8 *s = (NxU8 *)p;
|
||||
assert( s >= mData && s < mDataEnd );
|
||||
#endif
|
||||
MemoryHeader *mh = mFreeList;
|
||||
mFreeList = (MemoryHeader *)p;
|
||||
mFreeList->mNext = mh;
|
||||
mUsedCount--;
|
||||
if ( mUsedCount == 0 && mMyHeap ) // free the heap back to the application if we are done with this.
|
||||
{
|
||||
update->removeMicroChunk(this);
|
||||
heap->micro_free(mData);
|
||||
mMyHeap = false;
|
||||
mData = 0;
|
||||
mDataEnd = 0;
|
||||
mFreeList = 0;
|
||||
}
|
||||
}
|
||||
|
||||
NxU32 getChunkSize(void) const { return mChunkSize; };
|
||||
|
||||
bool isInside(const NxU8 *p) const
|
||||
{
|
||||
return p>=mData && p < mDataEnd;
|
||||
}
|
||||
|
||||
private:
|
||||
bool mMyHeap;
|
||||
NxU8 *mData;
|
||||
NxU8 *mDataEnd;
|
||||
NxU32 mUsedCount;
|
||||
MemoryHeader *mFreeList;
|
||||
NxU32 mChunkSize;
|
||||
};
|
||||
|
||||
#define DEFAULT_CHUNKS 32
|
||||
|
||||
class MemoryChunkChunk
|
||||
{
|
||||
public:
|
||||
MemoryChunkChunk(void)
|
||||
{
|
||||
mNext = 0;
|
||||
mChunkSize = 0;
|
||||
mMaxChunks = 0;
|
||||
}
|
||||
|
||||
~MemoryChunkChunk(void)
|
||||
{
|
||||
}
|
||||
|
||||
inline void * allocate(MemoryChunk *¤t,MicroChunkUpdate *update)
|
||||
{
|
||||
void *ret = 0;
|
||||
|
||||
MemoryChunkChunk *scan = this;
|
||||
while ( scan && ret == 0 )
|
||||
{
|
||||
for (NxU32 i=0; i<DEFAULT_CHUNKS; i++)
|
||||
{
|
||||
ret = scan->mChunks[i].allocate(mHeap,mChunkSize,mMaxChunks,update);
|
||||
if ( ret )
|
||||
{
|
||||
current = &scan->mChunks[i];
|
||||
scan = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( scan )
|
||||
scan = scan->mNext;
|
||||
}
|
||||
|
||||
if ( !ret )
|
||||
{
|
||||
MemoryChunkChunk *mcc = (MemoryChunkChunk *)mHeap->micro_malloc( sizeof(MemoryChunkChunk) );
|
||||
new ( mcc ) MemoryChunkChunk;
|
||||
MemoryChunkChunk *onext = mNext;
|
||||
mNext = mcc;
|
||||
mcc->mNext = onext;
|
||||
ret = mcc->mChunks[0].allocate(mHeap,mChunkSize,mMaxChunks,update);
|
||||
current = &mcc->mChunks[0];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
NxU8 * init(NxU8 *chunkBase,NxU32 fixedSize,NxU32 chunkSize,MemoryChunk *¤t,MicroHeap *heap)
|
||||
{
|
||||
mHeap = heap;
|
||||
mChunkSize = chunkSize;
|
||||
mMaxChunks = fixedSize/chunkSize;
|
||||
current = &mChunks[0];
|
||||
chunkBase = mChunks[0].init(chunkBase,chunkSize,mMaxChunks);
|
||||
return chunkBase;
|
||||
}
|
||||
|
||||
MicroHeap *mHeap;
|
||||
NxU32 mChunkSize;
|
||||
NxU32 mMaxChunks;
|
||||
MemoryChunkChunk *mNext;
|
||||
MemoryChunk mChunks[DEFAULT_CHUNKS];
|
||||
};
|
||||
|
||||
class FixedMemory
|
||||
{
|
||||
public:
|
||||
FixedMemory(void)
|
||||
{
|
||||
mCurrent = 0;
|
||||
}
|
||||
|
||||
void * allocate(MicroChunkUpdate *update)
|
||||
{
|
||||
void *ret = mCurrent->allocate(mChunks.mHeap,mChunks.mChunkSize,mChunks.mMaxChunks,update);
|
||||
if ( ret == 0 )
|
||||
{
|
||||
ret = mChunks.allocate(mCurrent,update);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
NxU8 * init(NxU8 *chunkBase,NxU32 chunkSize,NxU32 fixedSize,MicroHeap *heap)
|
||||
{
|
||||
mMemBegin = chunkBase;
|
||||
mMemEnd = chunkBase+fixedSize;
|
||||
mChunks.init(chunkBase,fixedSize,chunkSize,mCurrent,heap);
|
||||
return mMemEnd;
|
||||
}
|
||||
|
||||
NxU8 *mMemBegin;
|
||||
NxU8 *mMemEnd;
|
||||
MemoryChunk *mCurrent; // the current memory chunk we are operating in.
|
||||
MemoryChunkChunk mChunks; // the collection of all memory chunks used.
|
||||
};
|
||||
|
||||
class MicroChunk
|
||||
{
|
||||
public:
|
||||
|
||||
void set(NxU8 *memStart,NxU8 *memEnd,MemoryChunk *mc)
|
||||
{
|
||||
mMemStart = memStart;
|
||||
mMemEnd = memEnd;
|
||||
mChunk = mc;
|
||||
mPad = 0;
|
||||
}
|
||||
|
||||
inline bool inside(const NxU8 *p) const
|
||||
{
|
||||
return p >= mMemStart && p < mMemEnd;
|
||||
}
|
||||
|
||||
NxU8 *mMemStart;
|
||||
NxU8 *mMemEnd;
|
||||
MemoryChunk *mChunk;
|
||||
NxU8 *mPad; // padding to make it 16 byte aligned.
|
||||
};
|
||||
|
||||
class MyMicroAllocator : public MicroAllocator, public MicroChunkUpdate, public MemMutex
|
||||
{
|
||||
public:
|
||||
MyMicroAllocator(MicroHeap *heap,void *baseMem,NxU32 initialSize,NxU32 chunkSize)
|
||||
{
|
||||
mLastMicroChunk = 0;
|
||||
mMicroChunks = 0;
|
||||
mMicroChunkCount = 0;
|
||||
mMaxMicroChunks = 0;
|
||||
mHeap = heap;
|
||||
mChunkSize = chunkSize;
|
||||
|
||||
// 0 through 8 bytes
|
||||
for (NxU32 i=0; i<=8; i++)
|
||||
{
|
||||
mFixedAllocators[i] = &mAlloc[0];
|
||||
}
|
||||
|
||||
// 9 through 16 bytes
|
||||
for (NxU32 i=9; i<=16; i++)
|
||||
{
|
||||
mFixedAllocators[i] = &mAlloc[1];
|
||||
}
|
||||
|
||||
// 17 through 32 bytes
|
||||
for (NxU32 i=17; i<=32; i++)
|
||||
{
|
||||
mFixedAllocators[i] = &mAlloc[2];
|
||||
}
|
||||
|
||||
// 33 through 64
|
||||
for (NxU32 i=33; i<=64; i++)
|
||||
{
|
||||
mFixedAllocators[i] = &mAlloc[3];
|
||||
}
|
||||
|
||||
// 65 through 128
|
||||
for (NxU32 i=65; i<=128; i++)
|
||||
{
|
||||
mFixedAllocators[i] = &mAlloc[4];
|
||||
}
|
||||
|
||||
// 129 through 255
|
||||
for (NxU32 i=129; i<257; i++)
|
||||
{
|
||||
mFixedAllocators[i] = &mAlloc[5];
|
||||
}
|
||||
|
||||
mBaseMem = (NxU8 *)baseMem;
|
||||
mBaseMemEnd = mBaseMem+initialSize;
|
||||
|
||||
NxU8 *chunkBase = (NxU8 *)baseMem+sizeof(MyMicroAllocator);
|
||||
|
||||
|
||||
chunkBase+=32;
|
||||
NxU64 ptr = (NxU64)chunkBase;
|
||||
ptr = ptr>>4;
|
||||
ptr = ptr<<4; // make sure it is 16 byte aligned.
|
||||
chunkBase = (NxU8 *)ptr;
|
||||
|
||||
mChunkStart = chunkBase;
|
||||
chunkBase = mAlloc[0].init(chunkBase,8,chunkSize,heap);
|
||||
chunkBase = mAlloc[1].init(chunkBase,16,chunkSize,heap);
|
||||
chunkBase = mAlloc[2].init(chunkBase,32,chunkSize,heap);
|
||||
chunkBase = mAlloc[3].init(chunkBase,64,chunkSize,heap);
|
||||
chunkBase = mAlloc[4].init(chunkBase,128,chunkSize,heap);
|
||||
chunkBase = mAlloc[5].init(chunkBase,256,chunkSize,heap);
|
||||
mChunkEnd = chunkBase;
|
||||
|
||||
assert(chunkBase <= mBaseMemEnd );
|
||||
|
||||
}
|
||||
|
||||
~MyMicroAllocator(void)
|
||||
{
|
||||
if ( mMicroChunks )
|
||||
{
|
||||
mHeap->micro_free(mMicroChunks);
|
||||
}
|
||||
}
|
||||
|
||||
virtual NxU32 getChunkSize(MemoryChunk *chunk)
|
||||
{
|
||||
return chunk ? chunk->getChunkSize() : 0;
|
||||
}
|
||||
|
||||
// we have to steal one byte out of every allocation to record the size, so we can efficiently de-allocate it later.
|
||||
virtual void * malloc(size_t size)
|
||||
{
|
||||
void *ret = 0;
|
||||
Lock();
|
||||
assert( size <= 256 );
|
||||
if ( size <= 256 )
|
||||
{
|
||||
ret = mFixedAllocators[size]->allocate(this);
|
||||
}
|
||||
Unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
virtual void free(void *p,MemoryChunk *chunk)
|
||||
{
|
||||
Lock();
|
||||
chunk->deallocate(p,mHeap,this);
|
||||
Unlock();
|
||||
}
|
||||
|
||||
// perform a binary search on the sorted list of chunks.
|
||||
MemoryChunk * binarySearchMicroChunks(const NxU8 *p)
|
||||
{
|
||||
MemoryChunk *ret = 0;
|
||||
|
||||
NxU32 low = 0;
|
||||
NxU32 high = mMicroChunkCount;
|
||||
|
||||
while ( low != high )
|
||||
{
|
||||
NxU32 mid = (high-low)/2+low;
|
||||
MicroChunk &chunk = mMicroChunks[mid];
|
||||
if ( chunk.inside(p))
|
||||
{
|
||||
mLastMicroChunk = &chunk;
|
||||
ret = chunk.mChunk;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( p > chunk.mMemEnd )
|
||||
{
|
||||
low = mid+1;
|
||||
}
|
||||
else
|
||||
{
|
||||
high = mid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
virtual MemoryChunk * isMicroAlloc(const void *p) // returns true if this pointer is handled by the micro-allocator.
|
||||
{
|
||||
MemoryChunk *ret = 0;
|
||||
|
||||
Lock();
|
||||
|
||||
const NxU8 *s = (const NxU8 *)p;
|
||||
|
||||
if ( s >= mChunkStart && s < mChunkEnd )
|
||||
{
|
||||
NxU32 index = (NxU32)(s-mChunkStart)/mChunkSize;
|
||||
assert(index>=0 && index < 6 );
|
||||
ret = &mAlloc[index].mChunks.mChunks[0];
|
||||
assert( ret->isInside(s) );
|
||||
}
|
||||
else if ( mMicroChunkCount )
|
||||
{
|
||||
if ( mLastMicroChunk && mLastMicroChunk->inside(s) )
|
||||
{
|
||||
ret = mLastMicroChunk->mChunk;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( mMicroChunkCount >= 4 )
|
||||
{
|
||||
ret = binarySearchMicroChunks(s);
|
||||
#ifdef _DEBUG
|
||||
if (ret )
|
||||
{
|
||||
assert( ret->isInside(s) );
|
||||
}
|
||||
else
|
||||
{
|
||||
for (NxU32 i=0; i<mMicroChunkCount; i++)
|
||||
{
|
||||
assert( !mMicroChunks[i].inside(s) );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
for (NxU32 i=0; i<mMicroChunkCount; i++)
|
||||
{
|
||||
if ( mMicroChunks[i].inside(s) )
|
||||
{
|
||||
ret = mMicroChunks[i].mChunk;
|
||||
assert( ret->isInside(s) );
|
||||
mLastMicroChunk = &mMicroChunks[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
if ( ret )
|
||||
assert( ret->isInside(s) );
|
||||
#endif
|
||||
Unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
MicroHeap * getMicroHeap(void) const { return mHeap; };
|
||||
|
||||
void allocateMicroChunks(void)
|
||||
{
|
||||
if ( mMaxMicroChunks == 0 )
|
||||
{
|
||||
mMaxMicroChunks = 64; // initial reserve.
|
||||
mMicroChunks = (MicroChunk *)mHeap->micro_malloc( sizeof(MicroChunk)*mMaxMicroChunks );
|
||||
}
|
||||
else
|
||||
{
|
||||
mMaxMicroChunks*=2;
|
||||
mMicroChunks = (MicroChunk *)mHeap->micro_realloc( mMicroChunks, sizeof(MicroChunk)*mMaxMicroChunks);
|
||||
}
|
||||
}
|
||||
|
||||
// perform an insertion sort of the new chunk.
|
||||
virtual void addMicroChunk(NxU8 *memStart,NxU8 *memEnd,MemoryChunk *chunk)
|
||||
{
|
||||
if ( mMicroChunkCount >= mMaxMicroChunks )
|
||||
{
|
||||
allocateMicroChunks();
|
||||
}
|
||||
|
||||
bool inserted = false;
|
||||
for (NxU32 i=0; i<mMicroChunkCount; i++)
|
||||
{
|
||||
if ( memEnd < mMicroChunks[i].mMemStart )
|
||||
{
|
||||
for (NxU32 j=mMicroChunkCount; j>i; j--)
|
||||
{
|
||||
mMicroChunks[j] = mMicroChunks[j-1];
|
||||
}
|
||||
mMicroChunks[i].set( memStart, memEnd, chunk );
|
||||
mLastMicroChunk = &mMicroChunks[i];
|
||||
mMicroChunkCount++;
|
||||
inserted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( !inserted )
|
||||
{
|
||||
mMicroChunks[mMicroChunkCount].set(memStart,memEnd,chunk);
|
||||
mLastMicroChunk = &mMicroChunks[mMicroChunkCount];
|
||||
mMicroChunkCount++;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void removeMicroChunk(MemoryChunk *chunk)
|
||||
{
|
||||
mLastMicroChunk = 0;
|
||||
#ifdef _DEBUG
|
||||
bool removed = false;
|
||||
#endif
|
||||
for (NxU32 i=0; i<mMicroChunkCount; i++)
|
||||
{
|
||||
if ( mMicroChunks[i].mChunk == chunk )
|
||||
{
|
||||
mMicroChunkCount--;
|
||||
for (NxU32 j=i; j<mMicroChunkCount; j++)
|
||||
{
|
||||
mMicroChunks[j] = mMicroChunks[j+1];
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
removed = true;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
assert(removed);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void * inline_malloc(size_t size)
|
||||
{
|
||||
Lock();
|
||||
void *ret = mFixedAllocators[size]->allocate(this);
|
||||
Unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline void inline_free(void *p,MemoryChunk *chunk) // free relative to previously located MemoryChunk
|
||||
{
|
||||
Lock();
|
||||
chunk->deallocate(p,mHeap,this);
|
||||
Unlock();
|
||||
}
|
||||
|
||||
inline MemoryChunk * inline_isMicroAlloc(const void *p) // returns pointer to the chunk this memory belongs to, or null if not a micro-allocated block.
|
||||
{
|
||||
MemoryChunk *ret = 0;
|
||||
|
||||
Lock();
|
||||
|
||||
const NxU8 *s = (const NxU8 *)p;
|
||||
|
||||
if ( s >= mChunkStart && s < mChunkEnd )
|
||||
{
|
||||
NxU32 index = (NxU32)(s-mChunkStart)/mChunkSize;
|
||||
assert(index>=0 && index < 6 );
|
||||
ret = &mAlloc[index].mChunks.mChunks[0];
|
||||
}
|
||||
else if ( mMicroChunkCount )
|
||||
{
|
||||
if ( mLastMicroChunk && mLastMicroChunk->inside(s) )
|
||||
{
|
||||
ret = mLastMicroChunk->mChunk;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( mMicroChunkCount >= 4 )
|
||||
{
|
||||
ret = binarySearchMicroChunks(s);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (NxU32 i=0; i<mMicroChunkCount; i++)
|
||||
{
|
||||
if ( mMicroChunks[i].inside(s) )
|
||||
{
|
||||
ret = mMicroChunks[i].mChunk;
|
||||
mLastMicroChunk = &mMicroChunks[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
MicroHeap *mHeap;
|
||||
NxU8 *mBaseMem;
|
||||
NxU8 *mBaseMemEnd;
|
||||
FixedMemory *mFixedAllocators[257];
|
||||
NxU32 mChunkSize;
|
||||
NxU8 *mChunkStart;
|
||||
NxU8 *mChunkEnd;
|
||||
|
||||
NxU32 mMaxMicroChunks;
|
||||
NxU32 mMicroChunkCount;
|
||||
MicroChunk *mLastMicroChunk;
|
||||
MicroChunk *mMicroChunks;
|
||||
|
||||
FixedMemory mAlloc[6];
|
||||
};
|
||||
|
||||
|
||||
MicroAllocator *createMicroAllocator(MicroHeap *heap,NxU32 chunkSize)
|
||||
{
|
||||
NxU32 initialSize = chunkSize*6+sizeof(MyMicroAllocator)+32;
|
||||
void *baseMem = heap->micro_malloc(initialSize);
|
||||
MyMicroAllocator *mc = (MyMicroAllocator *)baseMem;
|
||||
new ( mc ) MyMicroAllocator(heap,baseMem,initialSize,chunkSize);
|
||||
return static_cast< MicroAllocator *>(mc);
|
||||
}
|
||||
|
||||
void releaseMicroAllocator(MicroAllocator *m)
|
||||
{
|
||||
MyMicroAllocator *mc = static_cast< MyMicroAllocator *>(m);
|
||||
MicroHeap *mh = mc->getMicroHeap();
|
||||
mc->~MyMicroAllocator();
|
||||
mh->micro_free(mc);
|
||||
}
|
||||
|
||||
class MyHeapManager : public MicroHeap, public HeapManager
|
||||
{
|
||||
public:
|
||||
MyHeapManager(NxU32 defaultChunkSize)
|
||||
{
|
||||
mMicro = createMicroAllocator(this,defaultChunkSize);
|
||||
}
|
||||
|
||||
~MyHeapManager(void)
|
||||
{
|
||||
releaseMicroAllocator(mMicro);
|
||||
}
|
||||
|
||||
// heap allocations used by the micro allocator.
|
||||
virtual void * micro_malloc(size_t size)
|
||||
{
|
||||
return ::malloc(size);
|
||||
}
|
||||
|
||||
virtual void micro_free(void *p)
|
||||
{
|
||||
return ::free(p);
|
||||
}
|
||||
|
||||
virtual void * micro_realloc(void *oldMem,size_t newSize)
|
||||
{
|
||||
return ::realloc(oldMem,newSize);
|
||||
}
|
||||
|
||||
virtual void * heap_malloc(size_t size)
|
||||
{
|
||||
void *ret;
|
||||
|
||||
if ( size <= 256 ) // micro allocator only handles allocations between 0 and 256 bytes in length.
|
||||
{
|
||||
ret = mMicro->malloc(size);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = ::malloc(size);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
virtual void heap_free(void *p)
|
||||
{
|
||||
MemoryChunk *chunk = mMicro->isMicroAlloc(p);
|
||||
if ( chunk )
|
||||
{
|
||||
mMicro->free(p,chunk);
|
||||
}
|
||||
else
|
||||
{
|
||||
::free(p);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void * heap_realloc(void *oldMem,size_t newSize)
|
||||
{
|
||||
void *ret = 0;
|
||||
|
||||
MemoryChunk *chunk = mMicro->isMicroAlloc(oldMem);
|
||||
if ( chunk )
|
||||
{
|
||||
ret = heap_malloc(newSize);
|
||||
NxU32 oldSize = chunk->getChunkSize();
|
||||
if ( oldSize < newSize )
|
||||
{
|
||||
memcpy(ret,oldMem,oldSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(ret,oldMem,newSize);
|
||||
}
|
||||
mMicro->free(oldMem,chunk);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = ::realloc(oldMem,newSize);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline void * inline_heap_malloc(size_t size)
|
||||
{
|
||||
return size<=256 ? ((MyMicroAllocator *)mMicro)->inline_malloc(size) : ::malloc(size);
|
||||
}
|
||||
|
||||
inline void inline_heap_free(void *p)
|
||||
{
|
||||
MemoryChunk *chunk = ((MyMicroAllocator *)mMicro)->inline_isMicroAlloc(p);
|
||||
if ( chunk )
|
||||
{
|
||||
((MyMicroAllocator *)mMicro)->inline_free(p,chunk);
|
||||
}
|
||||
else
|
||||
{
|
||||
::free(p);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
MicroAllocator *mMicro;
|
||||
};
|
||||
|
||||
|
||||
HeapManager * createHeapManager(NxU32 defaultChunkSize)
|
||||
{
|
||||
MyHeapManager *m = (MyHeapManager *)::malloc(sizeof(MyHeapManager));
|
||||
new ( m ) MyHeapManager(defaultChunkSize);
|
||||
return static_cast< HeapManager *>(m);
|
||||
}
|
||||
|
||||
void releaseHeapManager(HeapManager *heap)
|
||||
{
|
||||
MyHeapManager *m = static_cast< MyHeapManager *>(heap);
|
||||
m->~MyHeapManager();
|
||||
free(m);
|
||||
}
|
||||
|
||||
|
||||
#define TEST_SIZE 63
|
||||
#define TEST_ALLOC_COUNT 8192
|
||||
#define TEST_RUN 40000000
|
||||
#define TEST_INLINE 1
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#pragma comment(lib,"winmm.lib")
|
||||
#else
|
||||
static NxU32 timeGetTime(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
|
||||
void performUnitTests(void)
|
||||
{
|
||||
void *allocs[TEST_ALLOC_COUNT];
|
||||
for (NxU32 i=0; i<TEST_ALLOC_COUNT; i++)
|
||||
{
|
||||
allocs[i] = 0;
|
||||
}
|
||||
|
||||
|
||||
HeapManager *hm = createHeapManager(65536*32);
|
||||
|
||||
|
||||
{
|
||||
|
||||
NxU32 stime = timeGetTime();
|
||||
srand(0);
|
||||
|
||||
|
||||
for (NxU32 i=0; i<TEST_RUN; i++)
|
||||
{
|
||||
NxU32 index = rand()&(TEST_ALLOC_COUNT-1);
|
||||
if ( allocs[index] )
|
||||
{
|
||||
#if TEST_INLINE
|
||||
heap_free(hm, allocs[index] );
|
||||
#else
|
||||
hm->heap_free( allocs[index] );
|
||||
#endif
|
||||
allocs[index] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
NxU32 asize = (rand()&TEST_SIZE);
|
||||
if ( (rand()&127)==0) asize+=256; // one out of every 15 allocs is larger than 256 bytes.
|
||||
#if TEST_INLINE
|
||||
allocs[index] = heap_malloc(hm,asize);
|
||||
#else
|
||||
allocs[index] = hm->heap_malloc(asize);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
for (NxU32 i=0; i<TEST_ALLOC_COUNT; i++)
|
||||
{
|
||||
if ( allocs[i] )
|
||||
{
|
||||
#if TEST_INLINE
|
||||
heap_free(hm,allocs[i] );
|
||||
#else
|
||||
hm->heap_free(allocs[i] );
|
||||
#endif
|
||||
allocs[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
NxU32 etime = timeGetTime();
|
||||
printf("Micro allocation test took %d milliseconds.\r\n", etime - stime );
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
NxU32 stime = timeGetTime();
|
||||
srand(0);
|
||||
|
||||
|
||||
for (NxU32 i=0; i<TEST_RUN; i++)
|
||||
{
|
||||
NxU32 index = rand()&(TEST_ALLOC_COUNT-1);
|
||||
if ( allocs[index] )
|
||||
{
|
||||
::free( allocs[index] );
|
||||
allocs[index] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
NxU32 asize = (rand()&TEST_SIZE);
|
||||
if ( (rand()&127)==0) asize+=256; // one out of every 15 allocs is larger than 256 bytes.
|
||||
allocs[index] = ::malloc(asize);
|
||||
}
|
||||
}
|
||||
|
||||
for (NxU32 i=0; i<TEST_ALLOC_COUNT; i++)
|
||||
{
|
||||
if ( allocs[i] )
|
||||
{
|
||||
::free(allocs[i] );
|
||||
allocs[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
NxU32 etime = timeGetTime();
|
||||
printf("Standard malloc/free test took %d milliseconds.\r\n", etime - stime );
|
||||
|
||||
}
|
||||
|
||||
releaseHeapManager(hm);
|
||||
}
|
||||
|
||||
void * heap_malloc(HeapManager *hm,size_t size)
|
||||
{
|
||||
return ((MyHeapManager *)hm)->inline_heap_malloc(size);
|
||||
}
|
||||
|
||||
void heap_free(HeapManager *hm,void *p)
|
||||
{
|
||||
((MyHeapManager *)hm)->inline_heap_free(p);
|
||||
}
|
||||
|
||||
void * heap_realloc(HeapManager *hm,void *oldMem,size_t newSize)
|
||||
{
|
||||
return hm->heap_realloc(oldMem,newSize);
|
||||
}
|
||||
|
||||
}; // end of namespace
|
||||
204
indra/libhacd/hacdMicroAllocator.h
Normal file
204
indra/libhacd/hacdMicroAllocator.h
Normal file
@@ -0,0 +1,204 @@
|
||||
#ifndef MICRO_ALLOCATOR_H
|
||||
|
||||
#define MICRO_ALLOCATOR_H
|
||||
|
||||
/*!
|
||||
**
|
||||
** Copyright (c) 2009 by John W. Ratcliff mailto:jratcliffscarab@gmail.com
|
||||
**
|
||||
** If you find this code useful or you are feeling particularily generous I would
|
||||
** ask that you please go to http://www.amillionpixels.us and make a donation
|
||||
** to Troy DeMolay.
|
||||
**
|
||||
** If you wish to contact me you can use the following methods:
|
||||
**
|
||||
** Skype ID: jratcliff63367
|
||||
** email: jratcliffscarab@gmail.com
|
||||
**
|
||||
**
|
||||
** The MIT license:
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
** of this software and associated documentation files (the "Software"), to deal
|
||||
** in the Software without restriction, including without limitation the rights
|
||||
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
** copies of the Software, and to permit persons to whom the Software is furnished
|
||||
** to do so, subject to the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included in all
|
||||
** copies or substantial portions of the Software.
|
||||
|
||||
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
** WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
** CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
// This code snippet provides a high speed micro-allocator.
|
||||
//
|
||||
// The concept is that you reserve an initial bank of memory for small allocations. Ideally a megabyte or two.
|
||||
// The amount of memory reserved is equal to chunkSize*6
|
||||
//
|
||||
// All micro-allocations are split into 6 seperate pools.
|
||||
// They are: 0-8 bytes
|
||||
// 9-32 bytes
|
||||
// 33-64 bytes
|
||||
// 65-128 bytes
|
||||
// 129-256 bytes
|
||||
//
|
||||
// On creation of the micro-allocation system you preserve a certiain amount of memory for each of these banks.
|
||||
//
|
||||
// The user provides a heap interface to callback for additional memory as needed.
|
||||
//
|
||||
// In most cases allocations are order-N and frees are order-N as well.
|
||||
//
|
||||
// The larger a buffer you provide, the closer to 'order-N' the allocator behaves.
|
||||
//
|
||||
// This kind of a micro-allocator is ideal for use with STL as it does many tiny allocations.
|
||||
// All allocations are 16 byte aligned (with the exception of the 8 byte allocations, which are 8 byte aligned every other one).
|
||||
//
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef WIN32
|
||||
typedef __int64 NxI64;
|
||||
typedef signed int NxI32;
|
||||
typedef signed short NxI16;
|
||||
typedef signed char NxI8;
|
||||
|
||||
typedef unsigned __int64 NxU64;
|
||||
typedef unsigned int NxU32;
|
||||
typedef unsigned short NxU16;
|
||||
typedef unsigned char NxU8;
|
||||
|
||||
typedef float NxF32;
|
||||
typedef double NxF64;
|
||||
|
||||
#elif __gnu_linux__
|
||||
typedef long long NxI64;
|
||||
typedef signed int NxI32;
|
||||
typedef signed short NxI16;
|
||||
typedef signed char NxI8;
|
||||
|
||||
typedef unsigned long long NxU64;
|
||||
typedef unsigned int NxU32;
|
||||
typedef unsigned short NxU16;
|
||||
typedef unsigned char NxU8;
|
||||
|
||||
typedef float NxF32;
|
||||
typedef double NxF64;
|
||||
|
||||
#elif __APPLE__
|
||||
typedef long long NxI64;
|
||||
typedef signed int NxI32;
|
||||
typedef signed short NxI16;
|
||||
typedef signed char NxI8;
|
||||
|
||||
typedef unsigned long long NxU64;
|
||||
typedef unsigned int NxU32;
|
||||
typedef unsigned short NxU16;
|
||||
typedef unsigned char NxU8;
|
||||
|
||||
typedef float NxF32;
|
||||
typedef double NxF64;
|
||||
|
||||
#elif __CELLOS_LV2__
|
||||
typedef long long NxI64;
|
||||
typedef signed int NxI32;
|
||||
typedef signed short NxI16;
|
||||
typedef signed char NxI8;
|
||||
|
||||
typedef unsigned long long NxU64;
|
||||
typedef unsigned int NxU32;
|
||||
typedef unsigned short NxU16;
|
||||
typedef unsigned char NxU8;
|
||||
|
||||
typedef float NxF32;
|
||||
typedef double NxF64;
|
||||
|
||||
#elif _XBOX
|
||||
typedef __int64 NxI64;
|
||||
typedef signed int NxI32;
|
||||
typedef signed short NxI16;
|
||||
typedef signed char NxI8;
|
||||
|
||||
typedef unsigned __int64 NxU64;
|
||||
typedef unsigned int NxU32;
|
||||
typedef unsigned short NxU16;
|
||||
typedef unsigned char NxU8;
|
||||
|
||||
typedef float NxF32;
|
||||
typedef double NxF64;
|
||||
|
||||
#elif defined(__PPCGEKKO__)
|
||||
typedef long long NxI64;
|
||||
typedef signed int NxI32;
|
||||
typedef signed short NxI16;
|
||||
typedef signed char NxI8;
|
||||
|
||||
typedef unsigned long long NxU64;
|
||||
typedef unsigned int NxU32;
|
||||
typedef unsigned short NxU16;
|
||||
|
||||
typedef float NxF32;
|
||||
typedef double NxF64;
|
||||
|
||||
#else
|
||||
#error Unknown platform!
|
||||
#endif
|
||||
|
||||
|
||||
namespace HACD
|
||||
{
|
||||
|
||||
// user provided heap allocator
|
||||
class MicroHeap
|
||||
{
|
||||
public:
|
||||
virtual void * micro_malloc(size_t size) = 0;
|
||||
virtual void micro_free(void *p) = 0;
|
||||
virtual void * micro_realloc(void *oldMen,size_t newSize) = 0;
|
||||
};
|
||||
|
||||
class MemoryChunk;
|
||||
|
||||
class MicroAllocator
|
||||
{
|
||||
public:
|
||||
virtual void * malloc(size_t size) = 0;
|
||||
virtual void free(void *p,MemoryChunk *chunk) = 0; // free relative to previously located MemoryChunk
|
||||
virtual MemoryChunk * isMicroAlloc(const void *p) = 0; // returns pointer to the chunk this memory belongs to, or null if not a micro-allocated block.
|
||||
virtual NxU32 getChunkSize(MemoryChunk *chunk) = 0;
|
||||
};
|
||||
|
||||
MicroAllocator *createMicroAllocator(MicroHeap *heap,NxU32 chunkSize=32768); // initial chunk size 32k per block.
|
||||
void releaseMicroAllocator(MicroAllocator *m);
|
||||
|
||||
class HeapManager
|
||||
{
|
||||
public:
|
||||
virtual void * heap_malloc(size_t size) = 0;
|
||||
virtual void heap_free(void *p) = 0;
|
||||
virtual void * heap_realloc(void *oldMem,size_t newSize) = 0;
|
||||
};
|
||||
|
||||
|
||||
// creates a heap manager that uses micro-allocations for all allocations < 256 bytes and standard malloc/free for anything larger.
|
||||
HeapManager * createHeapManager(NxU32 defaultChunkSize=32768);
|
||||
void releaseHeapManager(HeapManager *heap);
|
||||
|
||||
// about 10% faster than using the virtual interface, inlines the functions as much as possible.
|
||||
void * heap_malloc(HeapManager *hm,size_t size);
|
||||
void heap_free(HeapManager *hm,void *p);
|
||||
void * heap_realloc(HeapManager *hm,void *oldMem,size_t newSize);
|
||||
|
||||
void performUnitTests(void);
|
||||
|
||||
//
|
||||
|
||||
}; // end of namespace
|
||||
|
||||
#endif
|
||||
280
indra/libhacd/hacdRaycastMesh.cpp
Normal file
280
indra/libhacd/hacdRaycastMesh.cpp
Normal file
@@ -0,0 +1,280 @@
|
||||
/* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
|
||||
All rights reserved.
|
||||
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "hacdRaycastMesh.h"
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
#include <limits>
|
||||
#include "hacdManifoldMesh.h"
|
||||
namespace HACD
|
||||
{
|
||||
bool BBox::Raycast(const Vec3<Float> & origin, const Vec3<Float> & dir, Float & distMin) const
|
||||
{
|
||||
Vec3<Float> d = m_max - m_min;
|
||||
Float r2 = 0.25 * (d.X()*d.X()+d.Y()*d.Y()+d.Z()*d.Z());
|
||||
Vec3<Float> c = 0.5 * m_max + 0.5 * m_min;
|
||||
Vec3<Float> u = (c-origin);
|
||||
Vec3<Float> a = u - (u * dir) * dir;
|
||||
Float dist2 = (a.X()*a.X()+a.Y()*a.Y()+a.Z()*a.Z());
|
||||
distMin = (u.X()*u.X()+u.Y()*u.Y()+u.Z()*u.Z());
|
||||
if ( distMin > r2 ) // origin outside the sphere of center c and radius r
|
||||
{
|
||||
distMin = sqrt(distMin) - sqrt(r2); // the distance to any point inside the sphere is higher than |origin - c| - r
|
||||
}
|
||||
else
|
||||
{
|
||||
distMin = 0.0;
|
||||
}
|
||||
if (dist2 > r2) return false;
|
||||
return true;
|
||||
}
|
||||
void RMNode::ComputeBB()
|
||||
{
|
||||
if (m_triIDs.Size() == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Vec3<long> * const triangles = m_rm->m_triangles;
|
||||
Vec3<Float> * const vertices = m_rm->m_vertices;
|
||||
const Float minFloat = std::numeric_limits<Float>::min();
|
||||
const Float maxFloat = std::numeric_limits<Float>::max();
|
||||
m_bBox.m_max = Vec3<Float>(minFloat, minFloat, minFloat);
|
||||
m_bBox.m_min = Vec3<Float>(maxFloat, maxFloat, maxFloat);
|
||||
Float x, y, z;
|
||||
long v, f;
|
||||
for(size_t id = 0; id < m_triIDs.Size(); ++id)
|
||||
{
|
||||
f = m_triIDs[id];
|
||||
for(size_t k = 0; k < 3; ++k)
|
||||
{
|
||||
v = triangles[f][k];
|
||||
x = vertices[v].X();
|
||||
y = vertices[v].Y();
|
||||
z = vertices[v].Z();
|
||||
if ( x < m_bBox.m_min.X()) m_bBox.m_min.X() = x;
|
||||
if ( x > m_bBox.m_max.X()) m_bBox.m_max.X() = x;
|
||||
if ( y < m_bBox.m_min.Y()) m_bBox.m_min.Y() = y;
|
||||
if ( y > m_bBox.m_max.Y()) m_bBox.m_max.Y() = y;
|
||||
if ( z < m_bBox.m_min.Z()) m_bBox.m_min.Z() = z;
|
||||
if ( z > m_bBox.m_max.Z()) m_bBox.m_max.Z() = z;
|
||||
}
|
||||
}
|
||||
}
|
||||
void RaycastMesh::ComputeBB()
|
||||
{
|
||||
if (m_nVertices == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_bBox.m_min = m_vertices[0];
|
||||
m_bBox.m_max = m_vertices[0];
|
||||
Float x, y, z;
|
||||
for (size_t v = 1; v < m_nVertices ; v++)
|
||||
{
|
||||
x = m_vertices[v].X();
|
||||
y = m_vertices[v].Y();
|
||||
z = m_vertices[v].Z();
|
||||
if ( x < m_bBox.m_min.X()) m_bBox.m_min.X() = x;
|
||||
else if ( x > m_bBox.m_max.X()) m_bBox.m_max.X() = x;
|
||||
if ( y < m_bBox.m_min.Y()) m_bBox.m_min.Y() = y;
|
||||
else if ( y > m_bBox.m_max.Y()) m_bBox.m_max.Y() = y;
|
||||
if ( z < m_bBox.m_min.Z()) m_bBox.m_min.Z() = z;
|
||||
else if ( z > m_bBox.m_max.Z()) m_bBox.m_max.Z() = z;
|
||||
}
|
||||
}
|
||||
void RaycastMesh::Initialize(size_t nVertices, size_t nTriangles,
|
||||
Vec3<Float> * vertices, Vec3<long> * triangles,
|
||||
size_t maxDepth, size_t minLeafSize, Float minAxisSize)
|
||||
{
|
||||
m_triangles = triangles;
|
||||
m_vertices = vertices;
|
||||
m_nVertices = nVertices;
|
||||
m_nTriangles = nTriangles;
|
||||
delete [] m_nodes;
|
||||
m_nNodes = 0;
|
||||
m_nMaxNodes = 0;
|
||||
for(size_t k = 0; k < maxDepth; k++)
|
||||
{
|
||||
m_nMaxNodes += (1 << maxDepth);
|
||||
}
|
||||
m_nodes = new RMNode[m_nMaxNodes];
|
||||
RMNode & root = m_nodes[AddNode()];
|
||||
root.m_triIDs.Resize(nTriangles);
|
||||
for(size_t t = 0; t < m_nTriangles; ++t) root.m_triIDs.PushBack(t);
|
||||
root.m_rm = this;
|
||||
root.m_id = 0;
|
||||
root.Create(0, maxDepth, minLeafSize, minAxisSize);
|
||||
}
|
||||
RaycastMesh::RaycastMesh(void)
|
||||
{
|
||||
m_triangles = 0;
|
||||
m_vertices = 0;
|
||||
m_nVertices = 0;
|
||||
m_nTriangles = 0;
|
||||
m_nodes = 0;
|
||||
m_nNodes = 0;
|
||||
m_nMaxNodes = 0;
|
||||
}
|
||||
RaycastMesh::~RaycastMesh(void)
|
||||
{
|
||||
delete [] m_nodes;
|
||||
}
|
||||
void RMNode::Create(size_t depth, size_t maxDepth, size_t minLeafSize, Float minAxisSize)
|
||||
{
|
||||
ComputeBB();
|
||||
Vec3<Float> d = m_bBox.m_max - m_bBox.m_min;
|
||||
Float maxDiff = std::max<Float>(d.X(), std::max<Float>(d.Y(), d.Z()));
|
||||
RMSplitAxis split;
|
||||
if (d.X() == maxDiff) split = RMSplitAxis_X;
|
||||
else if (d.Y() == maxDiff) split = RMSplitAxis_Y;
|
||||
else split = RMSplitAxis_Z;
|
||||
|
||||
if (depth == maxDepth || minLeafSize >= m_triIDs.Size() || maxDiff < minAxisSize)
|
||||
{
|
||||
m_leaf = true;
|
||||
return;
|
||||
}
|
||||
m_idLeft = m_rm->AddNode();
|
||||
m_idRight = m_rm->AddNode();
|
||||
RMNode & leftNode = m_rm->m_nodes[m_idLeft];
|
||||
RMNode & rightNode = m_rm->m_nodes[m_idRight];
|
||||
leftNode.m_id = m_idLeft;
|
||||
rightNode.m_id = m_idRight;
|
||||
leftNode.m_bBox = m_bBox;
|
||||
rightNode.m_bBox = m_bBox;
|
||||
leftNode.m_rm = m_rm;
|
||||
rightNode.m_rm = m_rm;
|
||||
|
||||
if ( split == RMSplitAxis_X)
|
||||
{
|
||||
leftNode.m_bBox.m_max.X() = leftNode.m_bBox.m_max.X() - d.X() * 0.5;
|
||||
rightNode.m_bBox.m_min.X() = leftNode.m_bBox.m_max.X();
|
||||
}
|
||||
else if ( split == RMSplitAxis_Y)
|
||||
{
|
||||
leftNode.m_bBox.m_max.Y() = leftNode.m_bBox.m_max.Y() - d.Y() * 0.5;
|
||||
rightNode.m_bBox.m_min.Y() = leftNode.m_bBox.m_max.Y();
|
||||
}
|
||||
else
|
||||
{
|
||||
leftNode.m_bBox.m_max.Z() = leftNode.m_bBox.m_max.Z() - d.Z() * 0.5;
|
||||
rightNode.m_bBox.m_min.Z() = leftNode.m_bBox.m_max.Z();
|
||||
}
|
||||
long f;
|
||||
long pts[3];
|
||||
long v;
|
||||
Vec3<long> * const triangles = m_rm->m_triangles;
|
||||
Vec3<Float> * const vertices = m_rm->m_vertices;
|
||||
leftNode.m_triIDs.Resize(m_triIDs.Size());
|
||||
rightNode.m_triIDs.Resize(m_triIDs.Size());
|
||||
bool found;
|
||||
for(size_t id = 0; id < m_triIDs.Size(); ++id)
|
||||
{
|
||||
f = m_triIDs[id];
|
||||
pts[0] = triangles[f].X();
|
||||
pts[1] = triangles[f].Y();
|
||||
pts[2] = triangles[f].Z();
|
||||
|
||||
found = false;
|
||||
for (int k = 0; k < 3; ++k)
|
||||
{
|
||||
v = pts[k];
|
||||
if ( vertices[v].X() <= leftNode.m_bBox.m_max.X() &&
|
||||
vertices[v].X() >= leftNode.m_bBox.m_min.X() &&
|
||||
vertices[v].Y() <= leftNode.m_bBox.m_max.Y() &&
|
||||
vertices[v].Y() >= leftNode.m_bBox.m_min.Y() &&
|
||||
vertices[v].Z() <= leftNode.m_bBox.m_max.Z() &&
|
||||
vertices[v].Z() >= leftNode.m_bBox.m_min.Z() )
|
||||
{
|
||||
leftNode.m_triIDs.PushBack(f);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
for (int k = 0; k < 3; ++k)
|
||||
{
|
||||
v = pts[k];
|
||||
if ( vertices[v].X() <= rightNode.m_bBox.m_max.X() &&
|
||||
vertices[v].X() >= rightNode.m_bBox.m_min.X() &&
|
||||
vertices[v].Y() <= rightNode.m_bBox.m_max.Y() &&
|
||||
vertices[v].Y() >= rightNode.m_bBox.m_min.Y() &&
|
||||
vertices[v].Z() <= rightNode.m_bBox.m_max.Z() &&
|
||||
vertices[v].Z() >= rightNode.m_bBox.m_min.Z() )
|
||||
{
|
||||
rightNode.m_triIDs.PushBack(f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
rightNode.Create(depth+1, maxDepth, minLeafSize, minAxisSize);
|
||||
leftNode.Create(depth+1, maxDepth, minLeafSize, minAxisSize);
|
||||
m_triIDs.Clear();
|
||||
}
|
||||
bool RaycastMesh::Raycast(const Vec3<Float> & from, const Vec3<Float> & dir, long & triID, Float & distance, Vec3<Real> & hitPoint, Vec3<Real> & hitNormal) const
|
||||
{
|
||||
distance = std::numeric_limits<Float>::max();
|
||||
if (m_nNodes == 0) return false;
|
||||
return m_nodes[0].Raycast(from, dir, triID, distance, hitPoint, hitNormal);
|
||||
}
|
||||
bool RMNode::Raycast(const Vec3<Float> & from, const Vec3<Float> & dir, long & triID, Float & distance, Vec3<Real> & hitPoint, Vec3<Real> & hitNormal) const
|
||||
{
|
||||
Float distToSphere;
|
||||
if (m_bBox.Raycast(from, dir, distToSphere) && (distToSphere < distance))
|
||||
{
|
||||
if (m_leaf)
|
||||
{
|
||||
long f, i1, j1, k1;
|
||||
Vec3<long> * const triangles = m_rm->m_triangles;
|
||||
Vec3<Float> * const vertices = m_rm->m_vertices;
|
||||
Vec3<Real> u1, v1, normal1;
|
||||
double dist = 0.0;
|
||||
long nhit = 0;
|
||||
bool ret = false;
|
||||
for(size_t id = 0; id < m_triIDs.Size(); ++id)
|
||||
{
|
||||
f = m_triIDs[id];
|
||||
i1 = triangles[f].X();
|
||||
j1 = triangles[f].Y();
|
||||
k1 = triangles[f].Z();
|
||||
u1 = vertices[j1] - vertices[i1];
|
||||
v1 = vertices[k1] - vertices[i1];
|
||||
normal1 = (u1 ^ v1);
|
||||
if (dir * normal1 > 0.0)
|
||||
{
|
||||
nhit = IntersectRayTriangle(from, dir, vertices[i1], vertices[j1], vertices[k1], dist);
|
||||
if (nhit==1 && distance>dist)
|
||||
{
|
||||
normal1.Normalize();
|
||||
hitNormal = normal1;
|
||||
hitPoint = from + dist * dir;
|
||||
distance = dist;
|
||||
triID = f;
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
bool ret1 = false;
|
||||
bool ret2 = false;
|
||||
if (m_idRight >= 0) ret1 = m_rm->m_nodes[m_idRight].Raycast(from, dir, triID, distance, hitPoint, hitNormal);
|
||||
if (m_idLeft >= 0) ret2 = m_rm->m_nodes[m_idLeft].Raycast(from, dir, triID, distance, hitPoint, hitNormal);
|
||||
return ret1 || ret2;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
97
indra/libhacd/hacdRaycastMesh.h
Normal file
97
indra/libhacd/hacdRaycastMesh.h
Normal file
@@ -0,0 +1,97 @@
|
||||
|
||||
|
||||
/* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
|
||||
All rights reserved.
|
||||
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef RAYCAST_MESH_H
|
||||
#define RAYCAST_MESH_H
|
||||
#include "hacdSArray.h"
|
||||
#include <vector>
|
||||
#include "hacdVersion.h"
|
||||
#include "hacdVector.h"
|
||||
#include "hacdSArray.h"
|
||||
|
||||
namespace HACD
|
||||
{
|
||||
typedef double Float;
|
||||
class RaycastMesh;
|
||||
class RMNode;
|
||||
class BBox
|
||||
{
|
||||
public:
|
||||
bool Raycast(const Vec3<Float> & origin, const Vec3<Float> & dir, Float & distance) const;
|
||||
BBox(void){}
|
||||
~BBox(void){}
|
||||
private:
|
||||
Vec3<Float> m_min;
|
||||
Vec3<Float> m_max;
|
||||
friend class RMNode;
|
||||
friend class RaycastMesh;
|
||||
};
|
||||
|
||||
enum RMSplitAxis
|
||||
{
|
||||
RMSplitAxis_X,
|
||||
RMSplitAxis_Y,
|
||||
RMSplitAxis_Z
|
||||
};
|
||||
class RMNode
|
||||
{
|
||||
public:
|
||||
void ComputeBB();
|
||||
bool Raycast(const Vec3<Float> & from, const Vec3<Float> & dir, long & triID, Float & distance, Vec3<Real> & hitPoint, Vec3<Real> & hitNormal) const;
|
||||
void Create(size_t depth, size_t maxDepth, size_t minLeafSize, Float minAxisSize);
|
||||
~RMNode(void){}
|
||||
RMNode(void)
|
||||
{
|
||||
m_idRight = m_idLeft = m_id = -1;
|
||||
m_rm = 0;
|
||||
m_leaf = false;
|
||||
}
|
||||
long m_id;
|
||||
long m_idLeft;
|
||||
long m_idRight;
|
||||
BBox m_bBox;
|
||||
SArray<long, SARRAY_DEFAULT_MIN_SIZE> m_triIDs;
|
||||
RaycastMesh * m_rm;
|
||||
bool m_leaf;
|
||||
};
|
||||
|
||||
class RaycastMesh
|
||||
{
|
||||
public:
|
||||
size_t GetNNodes() const { return m_nNodes;}
|
||||
size_t AddNode() { m_nNodes++; return m_nNodes-1; }
|
||||
void ComputeBB();
|
||||
bool Raycast(const Vec3<Float> & from, const Vec3<Float> & dir, long & triID, Float & distance, Vec3<Real> & hitPoint, Vec3<Real> & hitNormal) const;
|
||||
void Initialize(size_t nVertices, size_t nTriangles,
|
||||
Vec3<Float> * vertices, Vec3<long> * triangles,
|
||||
size_t maxDepth=15, size_t minLeafSize = 4, Float minAxisSize = 2.0);
|
||||
RaycastMesh(void);
|
||||
~RaycastMesh(void);
|
||||
private :
|
||||
|
||||
private:
|
||||
Vec3<long> * m_triangles;
|
||||
Vec3<Float> * m_vertices;
|
||||
size_t m_nVertices;
|
||||
size_t m_nTriangles;
|
||||
RMNode * m_nodes;
|
||||
BBox m_bBox;
|
||||
size_t m_nNodes;
|
||||
size_t m_nMaxNodes;
|
||||
friend class RMNode;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
154
indra/libhacd/hacdSArray.h
Normal file
154
indra/libhacd/hacdSArray.h
Normal file
@@ -0,0 +1,154 @@
|
||||
/* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
|
||||
All rights reserved.
|
||||
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#ifndef HACD_SARRAY_H
|
||||
#define HACD_SARRAY_H
|
||||
#include "hacdVersion.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#define SARRAY_DEFAULT_MIN_SIZE 16
|
||||
|
||||
namespace HACD
|
||||
{
|
||||
//! SArray.
|
||||
template < typename T, size_t N > class SArray
|
||||
{
|
||||
public:
|
||||
T & operator[](size_t i)
|
||||
{
|
||||
T * const data = Data();
|
||||
return data[i];
|
||||
}
|
||||
const T & operator[](size_t i) const
|
||||
{
|
||||
const T * const data = Data();
|
||||
return data[i];
|
||||
}
|
||||
size_t Size() const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
T * const Data()
|
||||
{
|
||||
return (m_maxSize == N)? m_data0 : m_data;
|
||||
}
|
||||
const T * const Data() const
|
||||
{
|
||||
return (m_maxSize == N)? m_data0 : m_data;
|
||||
}
|
||||
void Clear()
|
||||
{
|
||||
m_size = 0;
|
||||
delete [] m_data;
|
||||
m_data = 0;
|
||||
m_maxSize = N;
|
||||
}
|
||||
void PopBack()
|
||||
{
|
||||
--m_size;
|
||||
}
|
||||
void Resize(size_t size)
|
||||
{
|
||||
if (size > m_maxSize)
|
||||
{
|
||||
T * temp = new T[size];
|
||||
memcpy(temp, Data(), m_size*sizeof(T));
|
||||
delete [] m_data;
|
||||
m_data = temp;
|
||||
m_maxSize = size;
|
||||
}
|
||||
}
|
||||
void PushBack(const T & value)
|
||||
{
|
||||
if (m_size==m_maxSize)
|
||||
{
|
||||
size_t maxSize = (m_maxSize << 1);
|
||||
T * temp = new T[maxSize];
|
||||
memcpy(temp, Data(), m_maxSize*sizeof(T));
|
||||
delete [] m_data;
|
||||
m_data = temp;
|
||||
m_maxSize = maxSize;
|
||||
}
|
||||
T * const data = Data();
|
||||
data[m_size++] = value;
|
||||
}
|
||||
bool Find(const T & value, size_t & pos)
|
||||
{
|
||||
T * const data = Data();
|
||||
for(pos = 0; pos < m_size; ++pos)
|
||||
if (value == data[pos]) return true;
|
||||
return false;
|
||||
}
|
||||
bool Insert(const T & value)
|
||||
{
|
||||
size_t pos;
|
||||
if (Find(value, pos)) return false;
|
||||
PushBack(value);
|
||||
return true;
|
||||
}
|
||||
bool Erase(const T & value)
|
||||
{
|
||||
size_t pos;
|
||||
T * const data = Data();
|
||||
if (Find(value, pos))
|
||||
{
|
||||
for(size_t j = pos+1; j < m_size; ++j)
|
||||
data[j-1] = data[j];
|
||||
--m_size;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void operator=(const SArray & rhs)
|
||||
{
|
||||
if (m_maxSize < rhs.m_size)
|
||||
{
|
||||
delete [] m_data;
|
||||
m_maxSize = rhs.m_maxSize;
|
||||
m_data = new T[m_maxSize];
|
||||
}
|
||||
m_size = rhs.m_size;
|
||||
memcpy(Data(), rhs.Data(), m_size*sizeof(T));
|
||||
}
|
||||
void Initialize()
|
||||
{
|
||||
m_data = 0;
|
||||
m_size = 0;
|
||||
m_maxSize = N;
|
||||
}
|
||||
SArray(const SArray & rhs)
|
||||
{
|
||||
m_data = 0;
|
||||
m_size = 0;
|
||||
m_maxSize = N;
|
||||
*this = rhs;
|
||||
}
|
||||
SArray()
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
~SArray()
|
||||
{
|
||||
delete [] m_data;
|
||||
}
|
||||
private:
|
||||
T m_data0[N];
|
||||
T * m_data;
|
||||
size_t m_size;
|
||||
size_t m_maxSize;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
69
indra/libhacd/hacdVector.h
Normal file
69
indra/libhacd/hacdVector.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
|
||||
All rights reserved.
|
||||
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#ifndef HACD_VECTOR_H
|
||||
#define HACD_VECTOR_H
|
||||
#include <math.h>
|
||||
#include <iostream>
|
||||
#include "hacdVersion.h"
|
||||
|
||||
namespace HACD
|
||||
{
|
||||
typedef double Real;
|
||||
//! Vector dim 3.
|
||||
template < typename T > class Vec3
|
||||
{
|
||||
public:
|
||||
T & operator[](size_t i) { return m_data[i];}
|
||||
const T & operator[](size_t i) const { return m_data[i];}
|
||||
T & X();
|
||||
T & Y();
|
||||
T & Z();
|
||||
const T & X() const;
|
||||
const T & Y() const;
|
||||
const T & Z() const;
|
||||
void Normalize();
|
||||
T GetNorm() const;
|
||||
void operator= (const Vec3 & rhs);
|
||||
void operator+=(const Vec3 & rhs);
|
||||
void operator-=(const Vec3 & rhs);
|
||||
void operator-=(T a);
|
||||
void operator+=(T a);
|
||||
void operator/=(T a);
|
||||
void operator*=(T a);
|
||||
Vec3 operator^ (const Vec3 & rhs) const;
|
||||
T operator* (const Vec3 & rhs) const;
|
||||
Vec3 operator+ (const Vec3 & rhs) const;
|
||||
Vec3 operator- (const Vec3 & rhs) const;
|
||||
Vec3 operator- () const;
|
||||
Vec3 operator* (T rhs) const;
|
||||
Vec3 operator/ (T rhs) const;
|
||||
Vec3();
|
||||
Vec3(T a);
|
||||
Vec3(T x, T y, T z);
|
||||
Vec3(const Vec3 & rhs);
|
||||
/*virtual*/ ~Vec3(void);
|
||||
|
||||
private:
|
||||
T m_data[3];
|
||||
};
|
||||
template<typename T>
|
||||
const bool Colinear(const Vec3<T> & a, const Vec3<T> & b, const Vec3<T> & c);
|
||||
template<typename T>
|
||||
const T Volume(const Vec3<T> & a, const Vec3<T> & b, const Vec3<T> & c, const Vec3<T> & d);
|
||||
|
||||
}
|
||||
#include "hacdVector.inl" // template implementation
|
||||
#endif
|
||||
178
indra/libhacd/hacdVector.inl
Normal file
178
indra/libhacd/hacdVector.inl
Normal file
@@ -0,0 +1,178 @@
|
||||
#pragma once
|
||||
#ifndef HACD_VECTOR_INL
|
||||
#define HACD_VECTOR_INL
|
||||
namespace HACD
|
||||
{
|
||||
template <typename T>
|
||||
inline Vec3<T> operator*(T lhs, const Vec3<T> & rhs)
|
||||
{
|
||||
return Vec3<T>(lhs * rhs.X(), lhs * rhs.Y(), lhs * rhs.Z());
|
||||
}
|
||||
template <typename T>
|
||||
inline T & Vec3<T>::X()
|
||||
{
|
||||
return m_data[0];
|
||||
}
|
||||
template <typename T>
|
||||
inline T & Vec3<T>::Y()
|
||||
{
|
||||
return m_data[1];
|
||||
}
|
||||
template <typename T>
|
||||
inline T & Vec3<T>::Z()
|
||||
{
|
||||
return m_data[2];
|
||||
}
|
||||
template <typename T>
|
||||
inline const T & Vec3<T>::X() const
|
||||
{
|
||||
return m_data[0];
|
||||
}
|
||||
template <typename T>
|
||||
inline const T & Vec3<T>::Y() const
|
||||
{
|
||||
return m_data[1];
|
||||
}
|
||||
template <typename T>
|
||||
inline const T & Vec3<T>::Z() const
|
||||
{
|
||||
return m_data[2];
|
||||
}
|
||||
template <typename T>
|
||||
inline void Vec3<T>::Normalize()
|
||||
{
|
||||
T n = sqrt(m_data[0]*m_data[0]+m_data[1]*m_data[1]+m_data[2]*m_data[2]);
|
||||
if (n != 0.0) (*this) /= n;
|
||||
}
|
||||
template <typename T>
|
||||
inline T Vec3<T>::GetNorm() const
|
||||
{
|
||||
return sqrt(m_data[0]*m_data[0]+m_data[1]*m_data[1]+m_data[2]*m_data[2]);
|
||||
}
|
||||
template <typename T>
|
||||
inline void Vec3<T>::operator= (const Vec3 & rhs)
|
||||
{
|
||||
this->m_data[0] = rhs.m_data[0];
|
||||
this->m_data[1] = rhs.m_data[1];
|
||||
this->m_data[2] = rhs.m_data[2];
|
||||
}
|
||||
template <typename T>
|
||||
inline void Vec3<T>::operator+=(const Vec3 & rhs)
|
||||
{
|
||||
this->m_data[0] += rhs.m_data[0];
|
||||
this->m_data[1] += rhs.m_data[1];
|
||||
this->m_data[2] += rhs.m_data[2];
|
||||
}
|
||||
template <typename T>
|
||||
inline void Vec3<T>::operator-=(const Vec3 & rhs)
|
||||
{
|
||||
this->m_data[0] -= rhs.m_data[0];
|
||||
this->m_data[1] -= rhs.m_data[1];
|
||||
this->m_data[2] -= rhs.m_data[2];
|
||||
}
|
||||
template <typename T>
|
||||
inline void Vec3<T>::operator-=(T a)
|
||||
{
|
||||
this->m_data[0] -= a;
|
||||
this->m_data[1] -= a;
|
||||
this->m_data[2] -= a;
|
||||
}
|
||||
template <typename T>
|
||||
inline void Vec3<T>::operator+=(T a)
|
||||
{
|
||||
this->m_data[0] += a;
|
||||
this->m_data[1] += a;
|
||||
this->m_data[2] += a;
|
||||
}
|
||||
template <typename T>
|
||||
inline void Vec3<T>::operator/=(T a)
|
||||
{
|
||||
this->m_data[0] /= a;
|
||||
this->m_data[1] /= a;
|
||||
this->m_data[2] /= a;
|
||||
}
|
||||
template <typename T>
|
||||
inline void Vec3<T>::operator*=(T a)
|
||||
{
|
||||
this->m_data[0] *= a;
|
||||
this->m_data[1] *= a;
|
||||
this->m_data[2] *= a;
|
||||
}
|
||||
template <typename T>
|
||||
inline Vec3<T> Vec3<T>::operator^ (const Vec3<T> & rhs) const
|
||||
{
|
||||
return Vec3<T>(m_data[1] * rhs.m_data[2] - m_data[2] * rhs.m_data[1],
|
||||
m_data[2] * rhs.m_data[0] - m_data[0] * rhs.m_data[2],
|
||||
m_data[0] * rhs.m_data[1] - m_data[1] * rhs.m_data[0]);
|
||||
}
|
||||
template <typename T>
|
||||
inline T Vec3<T>::operator*(const Vec3<T> & rhs) const
|
||||
{
|
||||
return (m_data[0] * rhs.m_data[0] + m_data[1] * rhs.m_data[1] + m_data[2] * rhs.m_data[2]);
|
||||
}
|
||||
template <typename T>
|
||||
inline Vec3<T> Vec3<T>::operator+(const Vec3<T> & rhs) const
|
||||
{
|
||||
return Vec3<T>(m_data[0] + rhs.m_data[0],m_data[1] + rhs.m_data[1],m_data[2] + rhs.m_data[2]);
|
||||
}
|
||||
template <typename T>
|
||||
inline Vec3<T> Vec3<T>::operator-(const Vec3<T> & rhs) const
|
||||
{
|
||||
return Vec3<T>(m_data[0] - rhs.m_data[0],m_data[1] - rhs.m_data[1],m_data[2] - rhs.m_data[2]) ;
|
||||
}
|
||||
template <typename T>
|
||||
inline Vec3<T> Vec3<T>::operator-() const
|
||||
{
|
||||
return Vec3<T>(-m_data[0],-m_data[1],-m_data[2]) ;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline Vec3<T> Vec3<T>::operator*(T rhs) const
|
||||
{
|
||||
return Vec3<T>(rhs * this->m_data[0], rhs * this->m_data[1], rhs * this->m_data[2]);
|
||||
}
|
||||
template <typename T>
|
||||
inline Vec3<T> Vec3<T>::operator/ (T rhs) const
|
||||
{
|
||||
return Vec3<T>(m_data[0] / rhs, m_data[1] / rhs, m_data[2] / rhs);
|
||||
}
|
||||
template <typename T>
|
||||
inline Vec3<T>::Vec3(T a)
|
||||
{
|
||||
m_data[0] = m_data[1] = m_data[2] = a;
|
||||
}
|
||||
template <typename T>
|
||||
inline Vec3<T>::Vec3(T x, T y, T z)
|
||||
{
|
||||
m_data[0] = x;
|
||||
m_data[1] = y;
|
||||
m_data[2] = z;
|
||||
}
|
||||
template <typename T>
|
||||
inline Vec3<T>::Vec3(const Vec3 & rhs)
|
||||
{
|
||||
m_data[0] = rhs.m_data[0];
|
||||
m_data[1] = rhs.m_data[1];
|
||||
m_data[2] = rhs.m_data[2];
|
||||
}
|
||||
template <typename T>
|
||||
inline Vec3<T>::~Vec3(void){};
|
||||
|
||||
template <typename T>
|
||||
inline Vec3<T>::Vec3() {}
|
||||
|
||||
template<typename T>
|
||||
inline const bool Colinear(const Vec3<T> & a, const Vec3<T> & b, const Vec3<T> & c)
|
||||
{
|
||||
return ((c.Z() - a.Z()) * (b.Y() - a.Y()) - (b.Z() - a.Z()) * (c.Y() - a.Y()) == 0.0 /*EPS*/) &&
|
||||
((b.Z() - a.Z()) * (c.X() - a.X()) - (b.X() - a.X()) * (c.Z() - a.Z()) == 0.0 /*EPS*/) &&
|
||||
((b.X() - a.X()) * (c.Y() - a.Y()) - (b.Y() - a.Y()) * (c.X() - a.X()) == 0.0 /*EPS*/);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline const T Volume(const Vec3<T> & a, const Vec3<T> & b, const Vec3<T> & c, const Vec3<T> & d)
|
||||
{
|
||||
return (a-d) * ((b-d) ^ (c-d));
|
||||
}
|
||||
}
|
||||
#endif //HACD_VECTOR_INL
|
||||
20
indra/libhacd/hacdVersion.h
Normal file
20
indra/libhacd/hacdVersion.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
|
||||
All rights reserved.
|
||||
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#ifndef HACD_VERSION_H
|
||||
#define HACD_VERSION_H
|
||||
#define HACD_VERSION_MAJOR 0
|
||||
#define HACD_VERSION_MINOR 0
|
||||
#endif
|
||||
9
indra/libndhacd/CMakeLists.txt
Normal file
9
indra/libndhacd/CMakeLists.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
project(libndhacd)
|
||||
|
||||
include_directories(${LIBS_OPEN_DIR}/libhacd)
|
||||
|
||||
set (SOURCE_FILES LLConvexDecomposition.cpp nd_hacdConvexDecomposition.cpp nd_hacdStructs.cpp nd_hacdUtils.cpp nd_EnterExitTracer.cpp nd_StructTracer.cpp )
|
||||
file(GLOB HEADER_FILES *.h)
|
||||
|
||||
add_library( nd_hacdConvexDecomposition STATIC ${SOURCE_FILES} ${HEADER_FILES})
|
||||
|
||||
80
indra/libndhacd/LLConvexDecomposition.cpp
Normal file
80
indra/libndhacd/LLConvexDecomposition.cpp
Normal file
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* @file LLConvexDecomposition.cpp
|
||||
* @author falcon@lindenlab.com
|
||||
* @brief A stub implementation of LLConvexDecomposition interface
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#if defined(_WINDOWS)
|
||||
# include "windowsincludes.h"
|
||||
#endif
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
#include "nd_hacdConvexDecomposition.h"
|
||||
|
||||
#include "LLConvexDecomposition.h"
|
||||
|
||||
|
||||
/*static */bool LLConvexDecomposition::s_isInitialized = false;
|
||||
|
||||
/*static*/LLConvexDecomposition* LLConvexDecomposition::getInstance()
|
||||
{
|
||||
if ( !s_isInitialized )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return nd_hacdConvexDecomposition::getInstance();
|
||||
}
|
||||
}
|
||||
|
||||
/*static */LLCDResult LLConvexDecomposition::initSystem()
|
||||
{
|
||||
LLCDResult result = nd_hacdConvexDecomposition::initSystem();
|
||||
if ( result == LLCD_OK )
|
||||
{
|
||||
s_isInitialized = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*static */LLCDResult LLConvexDecomposition::initThread()
|
||||
{
|
||||
return nd_hacdConvexDecomposition::initThread();
|
||||
}
|
||||
|
||||
/*static */LLCDResult LLConvexDecomposition::quitThread()
|
||||
{
|
||||
return nd_hacdConvexDecomposition::quitThread();
|
||||
}
|
||||
|
||||
/*static */LLCDResult LLConvexDecomposition::quitSystem()
|
||||
{
|
||||
return nd_hacdConvexDecomposition::quitSystem();
|
||||
}
|
||||
|
||||
|
||||
231
indra/libndhacd/LLConvexDecomposition.h
Normal file
231
indra/libndhacd/LLConvexDecomposition.h
Normal file
@@ -0,0 +1,231 @@
|
||||
/**
|
||||
* @file LLConvexDecomposition.cpp
|
||||
* @brief LLConvexDecomposition interface definition
|
||||
*
|
||||
* $LicenseInfo:firstyear=2011&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2011, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_CONVEX_DECOMPOSITION
|
||||
#define LL_CONVEX_DECOMPOSITION
|
||||
|
||||
typedef int bool32;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#define LLCD_CALL __cdecl
|
||||
#else
|
||||
#define LLCD_CALL
|
||||
#endif
|
||||
|
||||
struct LLCDParam
|
||||
{
|
||||
enum LLCDParamType
|
||||
{
|
||||
LLCD_INVALID = 0,
|
||||
LLCD_INTEGER,
|
||||
LLCD_FLOAT,
|
||||
LLCD_BOOLEAN,
|
||||
LLCD_ENUM
|
||||
};
|
||||
|
||||
struct LLCDEnumItem
|
||||
{
|
||||
const char* mName;
|
||||
int mValue;
|
||||
};
|
||||
|
||||
union LLCDValue
|
||||
{
|
||||
float mFloat;
|
||||
int mIntOrEnumValue;
|
||||
bool32 mBool;
|
||||
};
|
||||
|
||||
union LLCDParamDetails
|
||||
{
|
||||
struct {
|
||||
LLCDValue mLow;
|
||||
LLCDValue mHigh;
|
||||
LLCDValue mDelta;
|
||||
} mRange;
|
||||
|
||||
struct {
|
||||
int mNumEnums;
|
||||
LLCDEnumItem* mEnumsArray;
|
||||
} mEnumValues;
|
||||
};
|
||||
|
||||
const char* mName;
|
||||
const char* mDescription;
|
||||
LLCDParamType mType;
|
||||
LLCDParamDetails mDetails;
|
||||
LLCDValue mDefault;
|
||||
int mStage;
|
||||
|
||||
// WARNING: Only the LLConvexDecomposition implementation
|
||||
// should change this value
|
||||
int mReserved;
|
||||
};
|
||||
|
||||
struct LLCDStageData
|
||||
{
|
||||
const char* mName;
|
||||
const char* mDescription;
|
||||
bool32 mSupportsCallback;
|
||||
};
|
||||
|
||||
struct LLCDMeshData
|
||||
{
|
||||
enum IndexType
|
||||
{
|
||||
INT_16,
|
||||
INT_32
|
||||
};
|
||||
|
||||
const float* mVertexBase;
|
||||
int mVertexStrideBytes;
|
||||
int mNumVertices;
|
||||
const void* mIndexBase;
|
||||
IndexType mIndexType;
|
||||
int mIndexStrideBytes;
|
||||
int mNumTriangles;
|
||||
};
|
||||
|
||||
struct LLCDHull
|
||||
{
|
||||
const float* mVertexBase;
|
||||
int mVertexStrideBytes;
|
||||
int mNumVertices;
|
||||
};
|
||||
|
||||
enum LLCDResult
|
||||
{
|
||||
LLCD_OK = 0,
|
||||
LLCD_UNKOWN_ERROR,
|
||||
LLCD_NULL_PTR,
|
||||
LLCD_INVALID_STAGE,
|
||||
LLCD_UNKNOWN_PARAM,
|
||||
LLCD_BAD_VALUE,
|
||||
LLCD_REQUEST_OUT_OF_RANGE,
|
||||
LLCD_INVALID_MESH_DATA,
|
||||
LLCD_INVALID_HULL_DATA,
|
||||
LLCD_STAGE_NOT_READY,
|
||||
LLCD_INVALID_THREAD,
|
||||
LLCD_NOT_IMPLEMENTED
|
||||
};
|
||||
|
||||
// This callback will receive a string describing the current subtask being performed
|
||||
// as well as a pair of numbers indicating progress. (The values should not be interpreted
|
||||
// as a completion percentage as 'current' may be greater than 'final'.)
|
||||
// If the callback returns zero, the decomposition will be terminated
|
||||
typedef int (LLCD_CALL *llcdCallbackFunc)(const char* description, int current, int final);
|
||||
|
||||
class LLConvexDecomposition
|
||||
{
|
||||
public:
|
||||
// Obtain a pointer to the actual implementation
|
||||
static LLConvexDecomposition* getInstance();
|
||||
|
||||
static LLCDResult initSystem();
|
||||
static LLCDResult initThread();
|
||||
static LLCDResult quitThread();
|
||||
static LLCDResult quitSystem();
|
||||
|
||||
// Generate a decomposition object handle
|
||||
virtual void genDecomposition(int& decomp) = 0;
|
||||
// Delete decomposition object handle
|
||||
virtual void deleteDecomposition(int decomp) = 0;
|
||||
// Bind given decomposition handle
|
||||
// Commands operate on currently bound decomposition
|
||||
virtual void bindDecomposition(int decomp) = 0;
|
||||
|
||||
// Sets *paramsOut to the address of the LLCDParam array and returns
|
||||
// the number of parameters
|
||||
virtual int getParameters(const LLCDParam** paramsOut) = 0;
|
||||
|
||||
|
||||
// Sets *stagesOut to the address of the LLCDStageData array and returns
|
||||
// the number of stages
|
||||
virtual int getStages(const LLCDStageData** stagesOut) = 0;
|
||||
|
||||
|
||||
// Set a parameter by name. Pass enum values as integers.
|
||||
virtual LLCDResult setParam(const char* name, float val) = 0;
|
||||
virtual LLCDResult setParam(const char* name, int val) = 0;
|
||||
virtual LLCDResult setParam(const char* name, bool val) = 0;
|
||||
|
||||
|
||||
// Set incoming mesh data. Data is copied to local buffers and will
|
||||
// persist until the next setMeshData call
|
||||
virtual LLCDResult setMeshData( const LLCDMeshData* data, bool vertex_based ) = 0;
|
||||
|
||||
|
||||
// Register a callback to be called periodically during the specified stage
|
||||
// See the typedef above for more information
|
||||
virtual LLCDResult registerCallback( int stage, llcdCallbackFunc callback ) = 0;
|
||||
|
||||
|
||||
// Execute the specified decomposition stage
|
||||
virtual LLCDResult executeStage(int stage) = 0;
|
||||
virtual LLCDResult buildSingleHull() = 0 ;
|
||||
|
||||
|
||||
// Gets the number of hulls generated by the specified decompositions stage
|
||||
virtual int getNumHullsFromStage(int stage) = 0;
|
||||
|
||||
|
||||
// Populates hullOut to reference the internal copy of the requested hull
|
||||
// The data will persist only until the next executeStage call for that stage.
|
||||
virtual LLCDResult getHullFromStage( int stage, int hull, LLCDHull* hullOut ) = 0;
|
||||
virtual LLCDResult getSingleHull( LLCDHull* hullOut ) = 0 ;
|
||||
|
||||
// TODO: Implement lock of some kind to disallow this call if data not yet ready
|
||||
// Populates the meshDataOut to reference the utility's copy of the mesh geometry
|
||||
// for the hull and stage specified.
|
||||
// You must copy this data if you want to continue using it after the next executeStage
|
||||
// call
|
||||
virtual LLCDResult getMeshFromStage( int stage, int hull, LLCDMeshData* meshDataOut) = 0;
|
||||
|
||||
|
||||
// Creates a mesh from hullIn and temporarily stores it internally in the utility.
|
||||
// The mesh data persists only until the next call to getMeshFromHull
|
||||
virtual LLCDResult getMeshFromHull( LLCDHull* hullIn, LLCDMeshData* meshOut ) = 0;
|
||||
|
||||
// Takes meshIn, generates a single convex hull from it, converts that to a mesh
|
||||
// stored internally, and populates meshOut to reference the internally stored data.
|
||||
// The data is persistent only until the next call to generateSingleHullMeshFromMesh
|
||||
virtual LLCDResult generateSingleHullMeshFromMesh( LLCDMeshData* meshIn, LLCDMeshData* meshOut) = 0;
|
||||
|
||||
//
|
||||
/// Debug
|
||||
virtual void loadMeshData(const char* fileIn, LLCDMeshData** meshDataOut) = 0;
|
||||
|
||||
virtual bool isFunctional()=0;
|
||||
|
||||
private:
|
||||
static bool s_isInitialized;
|
||||
};
|
||||
|
||||
// Pull in our trace interface
|
||||
#include "ndConvexDecomposition.h"
|
||||
|
||||
#endif //LL_CONVEX_DECOMPOSITION
|
||||
|
||||
148
indra/libndhacd/LLConvexDecompositionStubImpl.cpp
Normal file
148
indra/libndhacd/LLConvexDecompositionStubImpl.cpp
Normal file
@@ -0,0 +1,148 @@
|
||||
/**
|
||||
* @file LLConvexDecompositionStubImpl.cpp
|
||||
* @author falcon@lindenlab.com
|
||||
* @brief A stub implementation of LLConvexDecomposition
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include <memory>
|
||||
#include "LLConvexDecompositionStubImpl.h"
|
||||
|
||||
LLConvexDecomposition* LLConvexDecompositionImpl::getInstance()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LLCDResult LLConvexDecompositionImpl::initSystem()
|
||||
{
|
||||
return LLCD_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
LLCDResult LLConvexDecompositionImpl::initThread()
|
||||
{
|
||||
return LLCD_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
LLCDResult LLConvexDecompositionImpl::quitThread()
|
||||
{
|
||||
return LLCD_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
LLCDResult LLConvexDecompositionImpl::quitSystem()
|
||||
{
|
||||
return LLCD_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
void LLConvexDecompositionImpl::genDecomposition(int& decomp)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void LLConvexDecompositionImpl::deleteDecomposition(int decomp)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void LLConvexDecompositionImpl::bindDecomposition(int decomp)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
LLCDResult LLConvexDecompositionImpl::setParam(const char* name, float val)
|
||||
{
|
||||
return LLCD_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
LLCDResult LLConvexDecompositionImpl::setParam(const char* name, bool val)
|
||||
{
|
||||
return LLCD_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
LLCDResult LLConvexDecompositionImpl::setParam(const char* name, int val)
|
||||
{
|
||||
return LLCD_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
LLCDResult LLConvexDecompositionImpl::setMeshData( const LLCDMeshData* data, bool vertex_based )
|
||||
{
|
||||
return LLCD_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
LLCDResult LLConvexDecompositionImpl::registerCallback(int stage, llcdCallbackFunc callback )
|
||||
{
|
||||
return LLCD_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
LLCDResult LLConvexDecompositionImpl::buildSingleHull()
|
||||
{
|
||||
return LLCD_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
LLCDResult LLConvexDecompositionImpl::executeStage(int stage)
|
||||
{
|
||||
return LLCD_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
int LLConvexDecompositionImpl::getNumHullsFromStage(int stage)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
LLCDResult LLConvexDecompositionImpl::getSingleHull( LLCDHull* hullOut )
|
||||
{
|
||||
memset( hullOut, 0, sizeof(LLCDHull) );
|
||||
return LLCD_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
LLCDResult LLConvexDecompositionImpl::getHullFromStage( int stage, int hull, LLCDHull* hullOut )
|
||||
{
|
||||
memset( hullOut, 0, sizeof(LLCDHull) );
|
||||
return LLCD_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
LLCDResult LLConvexDecompositionImpl::getMeshFromStage( int stage, int hull, LLCDMeshData* meshDataOut )
|
||||
{
|
||||
memset( meshDataOut, 0, sizeof(LLCDMeshData) );
|
||||
return LLCD_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
LLCDResult LLConvexDecompositionImpl::getMeshFromHull( LLCDHull* hullIn, LLCDMeshData* meshOut )
|
||||
{
|
||||
memset( meshOut, 0, sizeof(LLCDMeshData) );
|
||||
return LLCD_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
LLCDResult LLConvexDecompositionImpl::generateSingleHullMeshFromMesh(LLCDMeshData* meshIn, LLCDMeshData* meshOut)
|
||||
{
|
||||
memset( meshOut, 0, sizeof(LLCDMeshData) );
|
||||
return LLCD_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
void LLConvexDecompositionImpl::loadMeshData(const char* fileIn, LLCDMeshData** meshDataOut)
|
||||
{
|
||||
static LLCDMeshData meshData;
|
||||
memset( &meshData, 0, sizeof(LLCDMeshData) );
|
||||
*meshDataOut = &meshData;
|
||||
}
|
||||
97
indra/libndhacd/LLConvexDecompositionStubImpl.h
Normal file
97
indra/libndhacd/LLConvexDecompositionStubImpl.h
Normal file
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* @file LLConvexDecompositionStubImpl.h
|
||||
* @author falcon@lindenlab.com
|
||||
* @brief A stub implementation of LLConvexDecomposition
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
|
||||
#ifndef LL_CONVEX_DECOMP_UTIL_H
|
||||
#define LL_CONVEX_DECOMP_UTIL_H
|
||||
|
||||
#include "LLConvexDecomposition.h"
|
||||
|
||||
class LLConvexDecompositionImpl : public LLConvexDecomposition
|
||||
{
|
||||
public:
|
||||
|
||||
virtual ~LLConvexDecompositionImpl() {}
|
||||
|
||||
static LLConvexDecomposition* getInstance();
|
||||
static LLCDResult initSystem();
|
||||
static LLCDResult initThread();
|
||||
static LLCDResult quitThread();
|
||||
static LLCDResult quitSystem();
|
||||
|
||||
// Generate a decomposition object handle
|
||||
void genDecomposition(int& decomp);
|
||||
// Delete decomposition object handle
|
||||
void deleteDecomposition(int decomp);
|
||||
// Bind given decomposition handle
|
||||
// Commands operate on currently bound decomposition
|
||||
void bindDecomposition(int decomp);
|
||||
|
||||
// Sets *paramsOut to the address of the LLCDParam array and returns
|
||||
// the length of the array
|
||||
int getParameters(const LLCDParam** paramsOut)
|
||||
{
|
||||
*paramsOut = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getStages(const LLCDStageData** stagesOut)
|
||||
{
|
||||
*stagesOut = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Set a parameter by name. Returns false if out of bounds or unsupported parameter
|
||||
LLCDResult setParam(const char* name, float val);
|
||||
LLCDResult setParam(const char* name, int val);
|
||||
LLCDResult setParam(const char* name, bool val);
|
||||
LLCDResult setMeshData( const LLCDMeshData* data, bool vertex_based );
|
||||
LLCDResult registerCallback(int stage, llcdCallbackFunc callback );
|
||||
|
||||
LLCDResult executeStage(int stage);
|
||||
LLCDResult buildSingleHull() ;
|
||||
|
||||
int getNumHullsFromStage(int stage);
|
||||
|
||||
LLCDResult getHullFromStage( int stage, int hull, LLCDHull* hullOut );
|
||||
LLCDResult getSingleHull( LLCDHull* hullOut ) ;
|
||||
|
||||
// TODO: Implement lock of some kind to disallow this call if data not yet ready
|
||||
LLCDResult getMeshFromStage( int stage, int hull, LLCDMeshData* meshDataOut);
|
||||
LLCDResult getMeshFromHull( LLCDHull* hullIn, LLCDMeshData* meshOut );
|
||||
|
||||
// For visualizing convex hull shapes in the viewer physics shape display
|
||||
LLCDResult generateSingleHullMeshFromMesh( LLCDMeshData* meshIn, LLCDMeshData* meshOut);
|
||||
|
||||
/// Debug
|
||||
void loadMeshData(const char* fileIn, LLCDMeshData** meshDataOut);
|
||||
|
||||
private:
|
||||
LLConvexDecompositionImpl() {}
|
||||
};
|
||||
|
||||
#endif //LL_CONVEX_DECOMP_UTIL_H
|
||||
58
indra/libndhacd/ndConvexDecomposition.h
Normal file
58
indra/libndhacd/ndConvexDecomposition.h
Normal file
@@ -0,0 +1,58 @@
|
||||
#ifndef ND_CONVEXDECOMPOSITION_H
|
||||
#define ND_CONVEXDECOMPOSITION_H
|
||||
|
||||
/**
|
||||
* copyright 2011 sl.nicky.ml@googlemail.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef ND_HASCONVEXDECOMP_TRACER
|
||||
#define ND_HASCONVEXDECOMP_TRACER
|
||||
#endif
|
||||
|
||||
class ndConvexDecompositionTracer
|
||||
{
|
||||
public:
|
||||
enum ETraceLevel
|
||||
{
|
||||
eNone = 0,
|
||||
eTraceFunctions = 0x1,
|
||||
eTraceData = 0x2,
|
||||
};
|
||||
|
||||
virtual ~ndConvexDecompositionTracer()
|
||||
{ }
|
||||
|
||||
virtual void trace( char const *a_strMsg ) = 0;
|
||||
|
||||
virtual void startTraceData( char const *a_strWhat) = 0;
|
||||
virtual void traceData( char const *a_strData ) = 0;
|
||||
virtual void endTraceData() = 0;
|
||||
|
||||
virtual int getLevel() = 0;
|
||||
|
||||
virtual void addref() = 0;
|
||||
virtual void release() = 0;
|
||||
};
|
||||
|
||||
class ndConvexDecompositionTracable
|
||||
{
|
||||
public:
|
||||
virtual void setTracer( ndConvexDecompositionTracer *) = 0;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
51
indra/libndhacd/nd_EnterExitTracer.cpp
Normal file
51
indra/libndhacd/nd_EnterExitTracer.cpp
Normal file
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* copyright 2011 sl.nicky.ml@googlemail.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "nd_EnterExitTracer.h"
|
||||
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
|
||||
void EnterExitTracer::doTrace( char const *aPrefix )
|
||||
{
|
||||
if( !mFunc || !mTracer )
|
||||
return;
|
||||
|
||||
if( ndConvexDecompositionTracer::eTraceFunctions == (mTracer->getLevel() & ndConvexDecompositionTracer::eTraceFunctions ) )
|
||||
return;
|
||||
|
||||
std::stringstream str;
|
||||
if( aPrefix )
|
||||
str << aPrefix;
|
||||
|
||||
str << mFunc;
|
||||
mTracer->trace( str.str().c_str() );
|
||||
}
|
||||
|
||||
EnterExitTracer::EnterExitTracer( char const *aFunc, ndConvexDecompositionTracer *aTracer )
|
||||
: mFunc( aFunc )
|
||||
, mTracer( aTracer )
|
||||
{
|
||||
doTrace( "enter: " );
|
||||
}
|
||||
|
||||
EnterExitTracer::~EnterExitTracer( )
|
||||
{
|
||||
doTrace( "exit: " );
|
||||
}
|
||||
|
||||
43
indra/libndhacd/nd_EnterExitTracer.h
Normal file
43
indra/libndhacd/nd_EnterExitTracer.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#ifndef ND_ENTEREXITTRACER_H
|
||||
#define ND_ENTEREXITTRACER_H
|
||||
|
||||
/**
|
||||
* copyright 2011 sl.nicky.ml@googlemail.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "ndConvexDecomposition.h"
|
||||
|
||||
class EnterExitTracer
|
||||
{
|
||||
char const *mFunc;
|
||||
ndConvexDecompositionTracer *mTracer;
|
||||
|
||||
void doTrace( char const *aPrefix );
|
||||
|
||||
public:
|
||||
EnterExitTracer( char const *aFunc, ndConvexDecompositionTracer *aTracer );
|
||||
~EnterExitTracer( );
|
||||
|
||||
};
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define TRACE_FUNC(ATRACER) EnterExitTracer oETTrace( __PRETTY_FUNCTION__, ATRACER );
|
||||
#else
|
||||
#define TRACE_FUNC(ATRACER) EnterExitTracer oETTrace( __FUNCTION__, ATRACER );
|
||||
#endif
|
||||
|
||||
#endif
|
||||
188
indra/libndhacd/nd_StructTracer.cpp
Normal file
188
indra/libndhacd/nd_StructTracer.cpp
Normal file
@@ -0,0 +1,188 @@
|
||||
/**
|
||||
* copyright 2011 sl.nicky.ml@googlemail.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "nd_StructTracer.h"
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace ndStructTracer
|
||||
{
|
||||
bool doTrace( ndConvexDecompositionTracer *aTracer )
|
||||
{
|
||||
if( !aTracer )
|
||||
return false;
|
||||
|
||||
return ndConvexDecompositionTracer::eTraceData == (aTracer->getLevel() & ndConvexDecompositionTracer::eTraceData) ;
|
||||
}
|
||||
|
||||
|
||||
template<typename T> void traceVecDbl( T const &aValue, ndConvexDecompositionTracer *aTracer )
|
||||
{
|
||||
stringstream str;
|
||||
str << fixed
|
||||
<< "\tX: " << aValue.X()
|
||||
<< " Y: " << aValue.Y()
|
||||
<< " Z: " << aValue.Z();
|
||||
|
||||
aTracer->traceData( str.str().c_str() );
|
||||
}
|
||||
|
||||
template< typename T> void traceVecDoubles( vector< T > const &aVertices, ndConvexDecompositionTracer *aTracer )
|
||||
{
|
||||
for( size_t i = 0; i < aVertices.size(); ++i )
|
||||
traceVecDbl( aVertices[i], aTracer );
|
||||
}
|
||||
|
||||
void traceVertices( vector< tVecDbl > const &aVertices, ndConvexDecompositionTracer *aTracer )
|
||||
{
|
||||
aTracer->traceData( "Triangles\n" );
|
||||
traceVecDoubles( aVertices, aTracer );
|
||||
}
|
||||
|
||||
void traceTriangles( vector< tVecLong > const &aTriangles, ndConvexDecompositionTracer *aTracer )
|
||||
{
|
||||
aTracer->traceData( "Vertices\n" );
|
||||
traceVecDoubles( aTriangles, aTracer );
|
||||
}
|
||||
|
||||
void trace( DecompData const &aData, ndConvexDecompositionTracer *aTracer )
|
||||
{
|
||||
if( !doTrace( aTracer ) )
|
||||
return;
|
||||
|
||||
aTracer->startTraceData("Hulls");
|
||||
|
||||
stringstream str;
|
||||
str << "Hulls: " << aData.mHulls.size();
|
||||
aTracer->traceData( str.str().c_str() );
|
||||
str.seekp(0);
|
||||
|
||||
for( size_t i = 0; i < aData.mHulls.size(); ++i )
|
||||
{
|
||||
str << "Hull #" << i;
|
||||
aTracer->traceData( str.str().c_str() );
|
||||
str.seekp(0);
|
||||
|
||||
DecompHull const &oHull( aData.mHulls[i] );
|
||||
traceVertices( oHull.mVertices, aTracer );
|
||||
traceTriangles( oHull.mTriangles, aTracer );
|
||||
}
|
||||
|
||||
aTracer->endTraceData();
|
||||
}
|
||||
|
||||
template< typename T> void traceVertex( T aX, T aY, T aZ, ndConvexDecompositionTracer *aTracer )
|
||||
{
|
||||
stringstream str;
|
||||
str << fixed
|
||||
<< "X: " << aX
|
||||
<< "Y: " << aY
|
||||
<< "Z: " << aZ;
|
||||
|
||||
aTracer->traceData( str.str().c_str() );
|
||||
}
|
||||
|
||||
template< typename T> void traceTriangle( void *& aPtr, int aStride, ndConvexDecompositionTracer *aTracer )
|
||||
{
|
||||
T *pData = reinterpret_cast< T* >(aPtr);
|
||||
long X( pData[0] ), Y( pData[1] ), Z( pData[2] );
|
||||
|
||||
traceVertex( X, Y, Z, aTracer );
|
||||
|
||||
pData += aStride;
|
||||
aPtr = pData;
|
||||
}
|
||||
|
||||
void traceVertices( int aNumVertices, float const *aVertices, int aStride, ndConvexDecompositionTracer *aTracer )
|
||||
{
|
||||
for( int i = 0; i < aNumVertices; ++i )
|
||||
{
|
||||
float X( aVertices[0] ), Y( aVertices[1] ), Z( aVertices[2] );
|
||||
traceVertex( X, Y, Z, aTracer );
|
||||
aVertices += aStride;
|
||||
}
|
||||
}
|
||||
|
||||
void traceTriangles( LLCDMeshData const *aData, ndConvexDecompositionTracer *aTracer )
|
||||
{
|
||||
int nCount = aData->mNumTriangles;
|
||||
int nStride = aData->mIndexStrideBytes;
|
||||
void *pData = const_cast<void*>( aData->mIndexBase );
|
||||
int nIndexType = aData->mIndexType;
|
||||
|
||||
if ( LLCDMeshData::INT_16 == nIndexType )
|
||||
nStride /= 2;
|
||||
else
|
||||
nStride /= 4;
|
||||
|
||||
for ( int i = 0; i < nCount; ++i )
|
||||
{
|
||||
if( LLCDMeshData::INT_16 == nIndexType )
|
||||
traceTriangle< hacdUINT16 >( pData, nStride, aTracer );
|
||||
else
|
||||
traceTriangle< hacdUINT32 >( pData, nStride, aTracer );
|
||||
}
|
||||
}
|
||||
|
||||
void trace( LLCDMeshData const *aData, bool aVertexBased, ndConvexDecompositionTracer *aTracer )
|
||||
{
|
||||
if( !doTrace( aTracer ) )
|
||||
return;
|
||||
|
||||
aTracer->startTraceData("LLCDMeshData");
|
||||
|
||||
string strVBased("true");
|
||||
if( !aVertexBased )
|
||||
strVBased = "false";
|
||||
|
||||
stringstream str;
|
||||
str << "LLCDMeshData vertex based: " << strVBased
|
||||
<< "# vertices " << aData->mNumVertices
|
||||
<< "# triangles " << aData->mNumTriangles;
|
||||
|
||||
aTracer->traceData( str.str().c_str() );
|
||||
|
||||
traceVertices( aData->mNumVertices, aData->mVertexBase, aData->mVertexStrideBytes/sizeof(float), aTracer );
|
||||
|
||||
if( !aVertexBased )
|
||||
traceTriangles( aData, aTracer );
|
||||
|
||||
aTracer->endTraceData();
|
||||
}
|
||||
|
||||
void trace( LLCDHull const *aData, ndConvexDecompositionTracer *aTracer )
|
||||
{
|
||||
if( !doTrace( aTracer ) )
|
||||
return;
|
||||
|
||||
aTracer->startTraceData("LLCDHull");
|
||||
|
||||
stringstream str;
|
||||
str << "LLCDHull # vertices " << aData->mNumVertices;
|
||||
|
||||
aTracer->traceData( str.str().c_str() );
|
||||
|
||||
traceVertices( aData->mNumVertices, aData->mVertexBase, aData->mVertexStrideBytes/sizeof(float), aTracer );
|
||||
|
||||
|
||||
aTracer->endTraceData();
|
||||
}
|
||||
};
|
||||
|
||||
34
indra/libndhacd/nd_StructTracer.h
Normal file
34
indra/libndhacd/nd_StructTracer.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#ifndef ND_STRUCTTRACER_H
|
||||
#define ND_STRUCTTRACER_H
|
||||
|
||||
/**
|
||||
* copyright 2011 sl.nicky.ml@googlemail.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#include "ndConvexDecomposition.h"
|
||||
#include "LLConvexDecomposition.h"
|
||||
#include "nd_hacdStructs.h"
|
||||
|
||||
namespace ndStructTracer
|
||||
{
|
||||
void trace( DecompData const &aData, ndConvexDecompositionTracer *aTracer );
|
||||
void trace( LLCDMeshData const *aData, bool aVertexBased, ndConvexDecompositionTracer *aTracer );
|
||||
void trace( LLCDHull const *aData, ndConvexDecompositionTracer *aTracer );
|
||||
};
|
||||
|
||||
#endif
|
||||
393
indra/libndhacd/nd_hacdConvexDecomposition.cpp
Normal file
393
indra/libndhacd/nd_hacdConvexDecomposition.cpp
Normal file
@@ -0,0 +1,393 @@
|
||||
/**
|
||||
* copyright 2011 sl.nicky.ml@googlemail.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <memory>
|
||||
#include "nd_hacdConvexDecomposition.h"
|
||||
|
||||
#include "nd_hacdDefines.h"
|
||||
#include "nd_hacdStructs.h"
|
||||
#include "nd_hacdUtils.h"
|
||||
#include "ndConvexDecomposition.h"
|
||||
#include "nd_EnterExitTracer.h"
|
||||
#include "nd_StructTracer.h"
|
||||
|
||||
LLCDStageData nd_hacdConvexDecomposition::mStages[1];
|
||||
|
||||
LLCDParam nd_hacdConvexDecomposition::mParams[4];
|
||||
LLCDParam::LLCDEnumItem nd_hacdConvexDecomposition::mMethods[1];
|
||||
LLCDParam::LLCDEnumItem nd_hacdConvexDecomposition::mQuality[1];
|
||||
LLCDParam::LLCDEnumItem nd_hacdConvexDecomposition::mSimplify[1];
|
||||
|
||||
LLConvexDecomposition* nd_hacdConvexDecomposition::getInstance()
|
||||
{
|
||||
static nd_hacdConvexDecomposition sImpl;
|
||||
return &sImpl;
|
||||
}
|
||||
|
||||
nd_hacdConvexDecomposition::nd_hacdConvexDecomposition()
|
||||
{
|
||||
mNextId = 0;
|
||||
mCurrentDecoder = 0;
|
||||
mSingleHullMeshFromMesh = new HACDDecoder();
|
||||
mTracer = 0;
|
||||
}
|
||||
|
||||
nd_hacdConvexDecomposition::~nd_hacdConvexDecomposition()
|
||||
{
|
||||
if( mTracer )
|
||||
mTracer->release();
|
||||
}
|
||||
|
||||
LLCDResult nd_hacdConvexDecomposition::initSystem()
|
||||
{
|
||||
memset( &mStages[0], 0, sizeof( mStages ) );
|
||||
memset( &mParams[0], 0, sizeof( mParams ) );
|
||||
memset( &mMethods[0], 0, sizeof( mMethods ) );
|
||||
memset( &mQuality[0], 0, sizeof( mQuality ) );
|
||||
memset( &mSimplify[0], 0, sizeof( mSimplify ) );
|
||||
|
||||
mStages[0].mName = "Decompose";
|
||||
mStages[0].mDescription = NULL;
|
||||
|
||||
mMethods[0].mName = "Default";
|
||||
mMethods[0].mValue = 0;
|
||||
|
||||
mQuality[0].mName = "Default";
|
||||
mQuality[0].mValue = 0;
|
||||
|
||||
mSimplify[0].mName = "None";
|
||||
mSimplify[0].mValue = 0;
|
||||
|
||||
mParams[0].mName = "nd_AlwaysNeedTriangles";
|
||||
mParams[0].mDescription = 0;
|
||||
mParams[0].mType = LLCDParam::LLCD_BOOLEAN;
|
||||
mParams[0].mDefault.mBool = true;
|
||||
|
||||
mParams[1].mName = "Method";
|
||||
mParams[1].mType = LLCDParam::LLCD_ENUM;
|
||||
mParams[1].mDetails.mEnumValues.mNumEnums = sizeof(mMethods)/sizeof(LLCDParam::LLCDEnumItem);
|
||||
mParams[1].mDetails.mEnumValues.mEnumsArray = mMethods;
|
||||
mParams[1].mDefault.mIntOrEnumValue = 0;
|
||||
|
||||
mParams[2].mName = "Decompose Quality";
|
||||
mParams[2].mType = LLCDParam::LLCD_ENUM;
|
||||
mParams[2].mDetails.mEnumValues.mNumEnums = sizeof(mQuality)/sizeof(LLCDParam::LLCDEnumItem);
|
||||
mParams[2].mDetails.mEnumValues.mEnumsArray = mQuality;
|
||||
mParams[2].mDefault.mIntOrEnumValue = 0;
|
||||
|
||||
mParams[3].mName = "Simplify Method";
|
||||
mParams[3].mType = LLCDParam::LLCD_ENUM;
|
||||
mParams[3].mDetails.mEnumValues.mNumEnums = sizeof(mSimplify)/sizeof(LLCDParam::LLCDEnumItem);
|
||||
mParams[3].mDetails.mEnumValues.mEnumsArray = mSimplify;
|
||||
mParams[3].mDefault.mIntOrEnumValue = 0;
|
||||
|
||||
return LLCD_OK;
|
||||
}
|
||||
|
||||
LLCDResult nd_hacdConvexDecomposition::initThread()
|
||||
{
|
||||
return LLCD_OK;
|
||||
}
|
||||
|
||||
LLCDResult nd_hacdConvexDecomposition::quitThread()
|
||||
{
|
||||
return LLCD_OK;
|
||||
}
|
||||
|
||||
LLCDResult nd_hacdConvexDecomposition::quitSystem()
|
||||
{
|
||||
return LLCD_OK;
|
||||
}
|
||||
|
||||
void nd_hacdConvexDecomposition::genDecomposition( int& decomp )
|
||||
{
|
||||
HACDDecoder *pGen = new HACDDecoder();
|
||||
decomp = mNextId;
|
||||
++mNextId;
|
||||
|
||||
mDecoders[ decomp ] = pGen;
|
||||
}
|
||||
|
||||
void nd_hacdConvexDecomposition::deleteDecomposition( int decomp )
|
||||
{
|
||||
delete mDecoders[ decomp ];
|
||||
mDecoders.erase( decomp );
|
||||
}
|
||||
|
||||
void nd_hacdConvexDecomposition::bindDecomposition( int decomp )
|
||||
{
|
||||
TRACE_FUNC( mTracer );
|
||||
mCurrentDecoder = decomp;
|
||||
}
|
||||
|
||||
LLCDResult nd_hacdConvexDecomposition::setParam( const char* name, float val )
|
||||
{
|
||||
TRACE_FUNC( mTracer );
|
||||
return LLCD_OK;
|
||||
}
|
||||
|
||||
LLCDResult nd_hacdConvexDecomposition::setParam( const char* name, bool val )
|
||||
{
|
||||
TRACE_FUNC( mTracer );
|
||||
return LLCD_OK;
|
||||
}
|
||||
|
||||
LLCDResult nd_hacdConvexDecomposition::setParam( const char* name, int val )
|
||||
{
|
||||
TRACE_FUNC( mTracer );
|
||||
return LLCD_OK;
|
||||
}
|
||||
|
||||
LLCDResult nd_hacdConvexDecomposition::setMeshData( const LLCDMeshData* data, bool vertex_based )
|
||||
{
|
||||
TRACE_FUNC( mTracer );
|
||||
ndStructTracer::trace( data, vertex_based, mTracer );
|
||||
|
||||
HACDDecoder *pC = mDecoders[ mCurrentDecoder ];
|
||||
return ::setMeshData( data, vertex_based, pC );
|
||||
}
|
||||
|
||||
LLCDResult nd_hacdConvexDecomposition::registerCallback( int stage, llcdCallbackFunc callback )
|
||||
{
|
||||
TRACE_FUNC( mTracer );
|
||||
if( mDecoders.end() == mDecoders.find( mCurrentDecoder ) )
|
||||
return LLCD_STAGE_NOT_READY;
|
||||
|
||||
HACDDecoder *pC = mDecoders[ mCurrentDecoder ];
|
||||
pC->mCallback = callback;
|
||||
|
||||
return LLCD_OK;
|
||||
}
|
||||
|
||||
LLCDResult nd_hacdConvexDecomposition::buildSingleHull()
|
||||
{
|
||||
TRACE_FUNC( mTracer );
|
||||
return LLCD_OK;
|
||||
}
|
||||
|
||||
LLCDResult nd_hacdConvexDecomposition::executeStage( int stage )
|
||||
{
|
||||
TRACE_FUNC( mTracer );
|
||||
if ( stage < 0 || stage >= NUM_STAGES )
|
||||
return LLCD_INVALID_STAGE;
|
||||
|
||||
HACDDecoder *pC = mDecoders[ mCurrentDecoder ];
|
||||
tHACD *pHACD = init( 1, MIN_NUMBER_OF_CLUSTERS, MAX_VERTICES_PER_HULL, CONNECT_DISTS[0], pC );
|
||||
|
||||
DecompData oRes = decompose( pHACD );
|
||||
ndStructTracer::trace( oRes, mTracer );
|
||||
|
||||
delete pHACD;
|
||||
|
||||
pC->mStages[ stage ] = oRes;
|
||||
|
||||
return LLCD_OK;
|
||||
}
|
||||
|
||||
int nd_hacdConvexDecomposition::getNumHullsFromStage( int stage )
|
||||
{
|
||||
TRACE_FUNC( mTracer );
|
||||
HACDDecoder *pC = mDecoders[ mCurrentDecoder ];
|
||||
|
||||
if ( !pC )
|
||||
return 0;
|
||||
|
||||
if ( stage < 0 || static_cast<size_t>(stage) >= pC->mStages.size() )
|
||||
return 0;
|
||||
|
||||
return pC->mStages[stage].mHulls.size();
|
||||
}
|
||||
|
||||
DecompData toSingleHull( HACDDecoder *aDecoder, LLCDResult &aRes, ndConvexDecompositionTracer *aTracer )
|
||||
{
|
||||
TRACE_FUNC( aTracer );
|
||||
aRes = LLCD_REQUEST_OUT_OF_RANGE;
|
||||
|
||||
for ( int i = 0; i < TO_SINGLE_HULL_TRIES; ++i )
|
||||
{
|
||||
tHACD *pHACD = init( CONCAVITY_FOR_SINGLE_HULL[i], 1, MAX_VERTICES_PER_HULL, CONNECT_DISTS[i], aDecoder );
|
||||
|
||||
DecompData oRes = decompose( pHACD );
|
||||
delete pHACD;
|
||||
|
||||
ndStructTracer::trace( oRes, aTracer );
|
||||
|
||||
if ( oRes.mHulls.size() == 1 )
|
||||
{
|
||||
aRes = LLCD_OK;
|
||||
return oRes;
|
||||
}
|
||||
}
|
||||
|
||||
return DecompData();
|
||||
}
|
||||
|
||||
LLCDResult nd_hacdConvexDecomposition::getSingleHull( LLCDHull* hullOut )
|
||||
{
|
||||
TRACE_FUNC( mTracer );
|
||||
HACDDecoder *pC = mDecoders[ mCurrentDecoder ];
|
||||
|
||||
memset( hullOut, 0, sizeof( LLCDHull ) );
|
||||
|
||||
LLCDResult res;
|
||||
|
||||
// Will already trace oRes
|
||||
DecompData oRes = ::toSingleHull( pC, res, mTracer );
|
||||
|
||||
if ( LLCD_OK != res || oRes.mHulls.size() != 1 )
|
||||
return res;
|
||||
|
||||
pC->mSingleHull = oRes.mHulls[0];
|
||||
pC->mSingleHull.toLLHull( hullOut );
|
||||
|
||||
return LLCD_OK;
|
||||
}
|
||||
|
||||
LLCDResult nd_hacdConvexDecomposition::getHullFromStage( int stage, int hull, LLCDHull* hullOut )
|
||||
{
|
||||
TRACE_FUNC( mTracer );
|
||||
HACDDecoder *pC = mDecoders[ mCurrentDecoder ];
|
||||
|
||||
memset( hullOut, 0, sizeof( LLCDHull ) );
|
||||
|
||||
if ( stage < 0 || static_cast<size_t>(stage) >= pC->mStages.size() )
|
||||
return LLCD_INVALID_STAGE;
|
||||
|
||||
DecompData &oData = pC->mStages[ stage ];
|
||||
|
||||
if ( hull < 0 ||static_cast<size_t>(hull) >= oData.mHulls.size() )
|
||||
return LLCD_REQUEST_OUT_OF_RANGE;
|
||||
|
||||
oData.mHulls[ hull ].toLLHull( hullOut );
|
||||
ndStructTracer::trace( hullOut, mTracer );
|
||||
|
||||
return LLCD_OK;
|
||||
}
|
||||
|
||||
LLCDResult nd_hacdConvexDecomposition::getMeshFromStage( int stage, int hull, LLCDMeshData* meshDataOut )
|
||||
{
|
||||
TRACE_FUNC( mTracer );
|
||||
HACDDecoder *pC = mDecoders[ mCurrentDecoder ];
|
||||
|
||||
memset( meshDataOut, 0, sizeof( LLCDHull ) );
|
||||
|
||||
if ( stage < 0 || static_cast<size_t>(stage) >= pC->mStages.size() )
|
||||
return LLCD_INVALID_STAGE;
|
||||
|
||||
DecompData &oData = pC->mStages[ stage ];
|
||||
|
||||
if ( hull < 0 || static_cast<size_t>(hull) >= oData.mHulls.size() )
|
||||
return LLCD_REQUEST_OUT_OF_RANGE;
|
||||
|
||||
oData.mHulls[ hull ].toLLMesh( meshDataOut );
|
||||
ndStructTracer::trace( meshDataOut, true, mTracer );
|
||||
return LLCD_OK;
|
||||
}
|
||||
|
||||
LLCDResult nd_hacdConvexDecomposition::getMeshFromHull( LLCDHull* hullIn, LLCDMeshData* meshOut )
|
||||
{
|
||||
TRACE_FUNC( mTracer );
|
||||
memset( meshOut, 0, sizeof( LLCDMeshData ) );
|
||||
|
||||
mMeshToHullVertices.clear();
|
||||
mMeshToHullTriangles.clear();
|
||||
|
||||
if( !hullIn || !hullIn->mVertexBase || !meshOut )
|
||||
return LLCD_NULL_PTR;
|
||||
if( hullIn->mVertexStrideBytes < 3*sizeof(float) || hullIn->mNumVertices < 3 )
|
||||
return LLCD_INVALID_HULL_DATA;
|
||||
|
||||
LLCDResult oRet = convertHullToMesh( hullIn, mMeshToHullVertices, mMeshToHullTriangles );
|
||||
|
||||
if( LLCD_OK != oRet )
|
||||
return oRet;
|
||||
|
||||
meshOut->mVertexStrideBytes = sizeof( float )*3;
|
||||
meshOut->mNumVertices = mMeshToHullVertices.size()/3;
|
||||
meshOut->mVertexBase = &mMeshToHullVertices[0];
|
||||
|
||||
meshOut->mIndexType = LLCDMeshData::INT_32;
|
||||
meshOut->mIndexStrideBytes = sizeof( hacdUINT32 ) * 3;
|
||||
meshOut->mNumTriangles = mMeshToHullTriangles.size()/3;
|
||||
meshOut->mIndexBase = &mMeshToHullTriangles[0];
|
||||
|
||||
return LLCD_OK;
|
||||
}
|
||||
|
||||
LLCDResult nd_hacdConvexDecomposition::generateSingleHullMeshFromMesh( LLCDMeshData* meshIn, LLCDMeshData* meshOut )
|
||||
{
|
||||
TRACE_FUNC( mTracer );
|
||||
memset( meshOut, 0, sizeof( LLCDMeshData ) );
|
||||
mSingleHullMeshFromMesh->clear();
|
||||
LLCDResult res = ::setMeshData( meshIn, meshIn->mNumVertices > 3, mSingleHullMeshFromMesh );
|
||||
|
||||
if ( LLCD_OK != res )
|
||||
return res;
|
||||
|
||||
// Will already trace oRes
|
||||
DecompData oRes = ::toSingleHull( mSingleHullMeshFromMesh, res, mTracer );
|
||||
|
||||
if ( LLCD_OK != res || oRes.mHulls.size() != 1 )
|
||||
return res;
|
||||
|
||||
mSingleHullMeshFromMesh->mSingleHull = oRes.mHulls[0];
|
||||
mSingleHullMeshFromMesh->mSingleHull.toLLMesh( meshOut );
|
||||
|
||||
return LLCD_OK;
|
||||
}
|
||||
|
||||
void nd_hacdConvexDecomposition::loadMeshData( const char* fileIn, LLCDMeshData** meshDataOut )
|
||||
{
|
||||
TRACE_FUNC( mTracer );
|
||||
static LLCDMeshData meshData;
|
||||
memset( &meshData, 0, sizeof( LLCDMeshData ) );
|
||||
*meshDataOut = &meshData;
|
||||
}
|
||||
|
||||
int nd_hacdConvexDecomposition::getParameters( const LLCDParam** paramsOut )
|
||||
{
|
||||
TRACE_FUNC( mTracer );
|
||||
*paramsOut = mParams;
|
||||
return sizeof(mParams)/sizeof(LLCDParam);
|
||||
}
|
||||
|
||||
int nd_hacdConvexDecomposition::getStages( const LLCDStageData** stagesOut )
|
||||
{
|
||||
TRACE_FUNC( mTracer );
|
||||
|
||||
*stagesOut = mStages;
|
||||
return sizeof(mStages)/sizeof(LLCDStageData);
|
||||
}
|
||||
|
||||
void nd_hacdConvexDecomposition::setTracer( ndConvexDecompositionTracer * aTracer)
|
||||
{
|
||||
if( mTracer )
|
||||
mTracer->release();
|
||||
|
||||
mTracer = aTracer;
|
||||
|
||||
if( mTracer )
|
||||
mTracer->addref();
|
||||
}
|
||||
|
||||
|
||||
bool nd_hacdConvexDecomposition::isFunctional()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
103
indra/libndhacd/nd_hacdConvexDecomposition.h
Normal file
103
indra/libndhacd/nd_hacdConvexDecomposition.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* copyright 2011 sl.nicky.ml@googlemail.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef ND_HACD_CONVEXDECOMP_H
|
||||
#define ND_HACD_CONVEXDECOMP_H
|
||||
|
||||
#include "LLConvexDecomposition.h"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
struct HACDDecoder;
|
||||
|
||||
class nd_hacdConvexDecomposition : public LLConvexDecomposition, public ndConvexDecompositionTracable
|
||||
{
|
||||
int mNextId;
|
||||
int mCurrentDecoder;
|
||||
std::map< int, HACDDecoder * > mDecoders;
|
||||
HACDDecoder *mSingleHullMeshFromMesh;
|
||||
|
||||
std::vector< float > mMeshToHullVertices;
|
||||
std::vector< int > mMeshToHullTriangles;
|
||||
|
||||
ndConvexDecompositionTracer *mTracer;
|
||||
|
||||
static LLCDStageData mStages[1];
|
||||
|
||||
static LLCDParam mParams[4];
|
||||
static LLCDParam::LLCDEnumItem mMethods[1];
|
||||
static LLCDParam::LLCDEnumItem mQuality[1];
|
||||
static LLCDParam::LLCDEnumItem mSimplify[1];
|
||||
|
||||
public:
|
||||
virtual ~nd_hacdConvexDecomposition();
|
||||
|
||||
static LLConvexDecomposition* getInstance();
|
||||
static LLCDResult initSystem();
|
||||
static LLCDResult initThread();
|
||||
static LLCDResult quitThread();
|
||||
static LLCDResult quitSystem();
|
||||
|
||||
// Generate a decomposition object handle
|
||||
void genDecomposition( int& decomp );
|
||||
// Delete decomposition object handle
|
||||
void deleteDecomposition( int decomp );
|
||||
// Bind given decomposition handle
|
||||
// Commands operate on currently bound decomposition
|
||||
void bindDecomposition( int decomp );
|
||||
|
||||
// Sets *paramsOut to the address of the LLCDParam array and returns
|
||||
// the length of the array
|
||||
int getParameters( const LLCDParam** paramsOut );
|
||||
int getStages( const LLCDStageData** stagesOut ) ;
|
||||
|
||||
// Set a parameter by name. Returns false if out of bounds or unsupported parameter
|
||||
LLCDResult setParam( const char* name, float val );
|
||||
LLCDResult setParam( const char* name, int val );
|
||||
LLCDResult setParam( const char* name, bool val );
|
||||
LLCDResult setMeshData( const LLCDMeshData* data, bool vertex_based );
|
||||
LLCDResult registerCallback( int stage, llcdCallbackFunc callback );
|
||||
|
||||
LLCDResult executeStage( int stage );
|
||||
LLCDResult buildSingleHull() ;
|
||||
|
||||
int getNumHullsFromStage( int stage );
|
||||
|
||||
LLCDResult getHullFromStage( int stage, int hull, LLCDHull* hullOut );
|
||||
LLCDResult getSingleHull( LLCDHull* hullOut ) ;
|
||||
|
||||
// TODO: Implement lock of some kind to disallow this call if data not yet ready
|
||||
LLCDResult getMeshFromStage( int stage, int hull, LLCDMeshData* meshDataOut );
|
||||
LLCDResult getMeshFromHull( LLCDHull* hullIn, LLCDMeshData* meshOut );
|
||||
|
||||
// For visualizing convex hull shapes in the viewer physics shape display
|
||||
LLCDResult generateSingleHullMeshFromMesh( LLCDMeshData* meshIn, LLCDMeshData* meshOut );
|
||||
|
||||
/// Debug
|
||||
void loadMeshData( const char* fileIn, LLCDMeshData** meshDataOut );
|
||||
|
||||
virtual void setTracer( ndConvexDecompositionTracer *);
|
||||
|
||||
virtual bool isFunctional();
|
||||
|
||||
private:
|
||||
nd_hacdConvexDecomposition();
|
||||
};
|
||||
|
||||
#endif
|
||||
46
indra/libndhacd/nd_hacdDefines.h
Normal file
46
indra/libndhacd/nd_hacdDefines.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* copyright 2011 sl.nicky.ml@googlemail.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef ND_HACD_DEFINES_H
|
||||
#define ND_HACD_DEFINES_H
|
||||
|
||||
#include "hacdHACD.h"
|
||||
|
||||
#define NUM_STAGES 1
|
||||
|
||||
typedef unsigned short hacdUINT16;
|
||||
typedef unsigned int hacdUINT32;
|
||||
|
||||
typedef HACD::HACD tHACD;
|
||||
typedef HACD::Vec3< double > tVecDbl;
|
||||
typedef HACD::Vec3< long > tVecLong;
|
||||
|
||||
typedef tVecLong ( *fFromIXX )( void const *&, int );
|
||||
|
||||
const int MAX_VERTICES_PER_HULL = 256; // see http://wiki.secondlife.com/wiki/Mesh/Mesh_physics
|
||||
const int MIN_NUMBER_OF_CLUSTERS = 1;
|
||||
|
||||
int const TO_SINGLE_HULL_TRIES = 10;
|
||||
|
||||
// Use a high value so HACD will generate just one hull. For now we use the same concavity for each run.
|
||||
int const CONCAVITY_FOR_SINGLE_HULL[ TO_SINGLE_HULL_TRIES ] = { 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000 };
|
||||
|
||||
// Max distance to connect CC. Increase this each run.
|
||||
double const CONNECT_DISTS[ TO_SINGLE_HULL_TRIES ] = { 30, 60, 120, 240, 480, 960, 1920, 3840, 7680, 10000 };
|
||||
|
||||
#endif
|
||||
107
indra/libndhacd/nd_hacdStructs.cpp
Normal file
107
indra/libndhacd/nd_hacdStructs.cpp
Normal file
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* copyright 2011 sl.nicky.ml@googlemail.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "nd_hacdStructs.h"
|
||||
#include "LLConvexDecomposition.h"
|
||||
|
||||
void DecompHull::clear()
|
||||
{
|
||||
mVertices.clear();
|
||||
mTriangles.clear();
|
||||
mLLVertices.clear();
|
||||
mLLTriangles.clear();
|
||||
}
|
||||
|
||||
void DecompHull::computeLLVertices()
|
||||
{
|
||||
if ( mLLVertices.size()*3 != mVertices.size() )
|
||||
{
|
||||
for ( size_t i = 0; i < mVertices.size(); ++i )
|
||||
{
|
||||
mLLVertices.push_back( static_cast<float>( mVertices[i].X() ) );
|
||||
mLLVertices.push_back( static_cast<float>( mVertices[i].Y() ) );
|
||||
mLLVertices.push_back( static_cast<float>( mVertices[i].Z() ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DecompHull::computeLLTriangles()
|
||||
{
|
||||
if ( mLLTriangles.size()*3 != mTriangles.size() )
|
||||
{
|
||||
for ( size_t i = 0; i < mTriangles.size(); ++i )
|
||||
{
|
||||
mLLTriangles.push_back( mTriangles[i].X() );
|
||||
mLLTriangles.push_back( mTriangles[i].Y() );
|
||||
mLLTriangles.push_back( mTriangles[i].Z() );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void DecompHull::toLLHull( LLCDHull *aHull )
|
||||
{
|
||||
computeLLVertices();
|
||||
|
||||
aHull->mVertexBase = &mLLVertices[0];
|
||||
aHull->mVertexStrideBytes = sizeof( float ) * 3;
|
||||
aHull->mNumVertices = mVertices.size();
|
||||
}
|
||||
|
||||
void DecompHull::toLLMesh( LLCDMeshData *aMesh )
|
||||
{
|
||||
computeLLVertices();
|
||||
computeLLTriangles();
|
||||
|
||||
aMesh->mIndexType = LLCDMeshData::INT_32;
|
||||
aMesh->mVertexBase = &mLLVertices[0];
|
||||
aMesh->mNumVertices = mVertices.size();
|
||||
aMesh->mVertexStrideBytes = sizeof( float ) * 3;
|
||||
|
||||
aMesh->mIndexBase = &mLLTriangles[0];
|
||||
aMesh->mIndexStrideBytes = sizeof( hacdUINT32 ) * 3;
|
||||
aMesh->mNumTriangles = mTriangles.size();
|
||||
}
|
||||
|
||||
void DecompData::clear()
|
||||
{
|
||||
mHulls.clear();
|
||||
}
|
||||
|
||||
HACDDecoder::HACDDecoder()
|
||||
{
|
||||
mStages.resize( NUM_STAGES );
|
||||
mCallback = 0;
|
||||
}
|
||||
|
||||
void HACDDecoder::clear()
|
||||
{
|
||||
mVertices.clear();
|
||||
mTriangles.clear();
|
||||
|
||||
for ( size_t i = 0; i < mStages.size(); ++i )
|
||||
mStages[i].clear();
|
||||
|
||||
mSingleHull.clear();
|
||||
|
||||
mCallback = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
77
indra/libndhacd/nd_hacdStructs.h
Normal file
77
indra/libndhacd/nd_hacdStructs.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* copyright 2011 sl.nicky.ml@googlemail.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef ND_HACD_DECOMPSTRUCTS_H
|
||||
#define ND_HACD_DECOMPSTRUCTS_H
|
||||
|
||||
#include "nd_hacdDefines.h"
|
||||
#include "hacdHACD.h"
|
||||
#include "LLConvexDecomposition.h"
|
||||
#include <vector>
|
||||
|
||||
struct LLCDHull;
|
||||
struct LLCDMeshData;
|
||||
|
||||
struct DecompHull
|
||||
{
|
||||
std::vector< tVecDbl > mVertices;
|
||||
std::vector< tVecLong > mTriangles;
|
||||
|
||||
std::vector< float > mLLVertices;
|
||||
std::vector< hacdUINT32 > mLLTriangles;
|
||||
|
||||
void clear();
|
||||
|
||||
void computeLLVertices();
|
||||
|
||||
void computeLLTriangles();
|
||||
|
||||
void toLLHull( LLCDHull *aHull );
|
||||
void toLLMesh( LLCDMeshData *aMesh );
|
||||
};
|
||||
|
||||
struct DecompData
|
||||
{
|
||||
std::vector< DecompHull > mHulls;
|
||||
|
||||
void clear();
|
||||
};
|
||||
|
||||
struct HACDDecoder: public HACD::ICallback
|
||||
{
|
||||
std::vector< tVecDbl > mVertices;
|
||||
std::vector< tVecLong > mTriangles;
|
||||
|
||||
std::vector< DecompData > mStages;
|
||||
DecompHull mSingleHull;
|
||||
|
||||
llcdCallbackFunc mCallback;
|
||||
|
||||
HACDDecoder();
|
||||
void clear();
|
||||
|
||||
virtual void operator()( char const *aMsg, double aProgress, double aConcavity, size_t aVertices)
|
||||
{
|
||||
if( mCallback )
|
||||
(*mCallback)(aMsg, static_cast<int>(aProgress), aVertices );
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
183
indra/libndhacd/nd_hacdUtils.cpp
Normal file
183
indra/libndhacd/nd_hacdUtils.cpp
Normal file
@@ -0,0 +1,183 @@
|
||||
/**
|
||||
* copyright 2011 sl.nicky.ml@googlemail.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "nd_hacdUtils.h"
|
||||
|
||||
tHACD* init( int nConcavity, int nClusters, int nMaxVerticesPerHull, double dMaxConnectDist, HACDDecoder *aData )
|
||||
{
|
||||
tHACD *pDec = HACD::CreateHACD(0);
|
||||
pDec->SetPoints( &aData->mVertices[0] );
|
||||
pDec->SetNPoints( aData->mVertices.size() );
|
||||
|
||||
if ( aData->mTriangles.size() )
|
||||
{
|
||||
pDec->SetTriangles( &aData->mTriangles[0] );
|
||||
pDec->SetNTriangles( aData->mTriangles.size() );
|
||||
}
|
||||
|
||||
pDec->SetCompacityWeight( 0.1f );
|
||||
pDec->SetVolumeWeight( 0 );
|
||||
pDec->SetNClusters( nClusters );
|
||||
pDec->SetAddExtraDistPoints( true );
|
||||
pDec->SetAddFacesPoints( true );
|
||||
pDec->SetNVerticesPerCH( nMaxVerticesPerHull );
|
||||
pDec->SetConcavity( nConcavity );
|
||||
pDec->SetConnectDist( dMaxConnectDist );
|
||||
|
||||
pDec->SetCallBack( aData );
|
||||
|
||||
return pDec;
|
||||
}
|
||||
|
||||
DecompData decompose( tHACD *aHACD )
|
||||
{
|
||||
aHACD->Compute();
|
||||
|
||||
DecompData oRet;
|
||||
|
||||
int nClusters = aHACD->GetNClusters();
|
||||
|
||||
for ( int i = 0; i < nClusters; ++i )
|
||||
{
|
||||
int nVertices = aHACD->GetNPointsCH( i );
|
||||
int nTriangles = aHACD->GetNTrianglesCH( i );
|
||||
DecompHull oHull;
|
||||
|
||||
oHull.mVertices.resize( nVertices );
|
||||
oHull.mTriangles.resize( nTriangles );
|
||||
aHACD->GetCH( i, &oHull.mVertices[0], &oHull.mTriangles[0] );
|
||||
|
||||
oRet.mHulls.push_back( oHull );
|
||||
}
|
||||
|
||||
return oRet;
|
||||
}
|
||||
|
||||
tVecLong fromI16( void const *& pPtr, int aStride )
|
||||
{
|
||||
hacdUINT16 const *pVal = reinterpret_cast< hacdUINT16 const * >( pPtr );
|
||||
tVecLong oRet( pVal[0], pVal[1], pVal[2] );
|
||||
pVal += aStride / 2;
|
||||
pPtr = pVal;
|
||||
return oRet;
|
||||
}
|
||||
|
||||
tVecLong fromI32( void const *& pPtr, int aStride )
|
||||
{
|
||||
hacdUINT32 const *pVal = reinterpret_cast< hacdUINT32 const * >( pPtr );
|
||||
tVecLong oRet( pVal[0], pVal[1], pVal[2] );
|
||||
pVal += aStride / 4;
|
||||
pPtr = pVal;
|
||||
return oRet;
|
||||
}
|
||||
|
||||
LLCDResult setMeshData( const LLCDMeshData* data, bool vertex_based, HACDDecoder *aDec )
|
||||
{
|
||||
if ( !data || !data->mVertexBase || ( data->mNumVertices < 3 ) || ( data->mVertexStrideBytes != 12 && data->mVertexStrideBytes != 16 ) )
|
||||
return LLCD_INVALID_MESH_DATA;
|
||||
|
||||
if ( !vertex_based && ( ( data->mNumTriangles < 1 ) || ! data->mIndexBase ) )
|
||||
return LLCD_INVALID_MESH_DATA;
|
||||
|
||||
aDec->clear();
|
||||
int nCount = data->mNumVertices;
|
||||
float const* pVertex = data->mVertexBase;
|
||||
int nStride = data->mVertexStrideBytes / sizeof( float );
|
||||
|
||||
for ( int i = 0; i < nCount; ++i )
|
||||
{
|
||||
tVecDbl oPt( pVertex[0], pVertex[1], pVertex[2] );
|
||||
aDec->mVertices.push_back( oPt );
|
||||
pVertex += nStride;
|
||||
}
|
||||
|
||||
if ( !vertex_based )
|
||||
{
|
||||
fFromIXX pFunc = 0;
|
||||
nCount = data->mNumTriangles;
|
||||
nStride = data->mIndexStrideBytes;
|
||||
void const *pData = data->mIndexBase;
|
||||
|
||||
if ( data->mIndexType == LLCDMeshData::INT_16 )
|
||||
pFunc = fromI16;
|
||||
else
|
||||
pFunc = fromI32;
|
||||
|
||||
for ( int i = 0; i < nCount; ++i )
|
||||
{
|
||||
tVecLong oVal( ( *pFunc )( pData, nStride ) );
|
||||
aDec->mTriangles.push_back( oVal );
|
||||
}
|
||||
}
|
||||
|
||||
return LLCD_OK;
|
||||
}
|
||||
|
||||
LLCDResult convertHullToMesh( const LLCDHull* aHull, std::vector< float > &aVerticesOut, std::vector< int > &aTrianglesOut )
|
||||
{
|
||||
if( !aHull || !aHull->mVertexBase )
|
||||
return LLCD_NULL_PTR;
|
||||
if( aHull->mVertexStrideBytes < 3*sizeof(float) || aHull->mNumVertices < 3 )
|
||||
return LLCD_INVALID_HULL_DATA;
|
||||
|
||||
HACD::ICHull oHull;
|
||||
|
||||
int nCount = aHull->mNumVertices;
|
||||
float const *pVertex = aHull->mVertexBase;
|
||||
int nStride = aHull->mVertexStrideBytes / sizeof( float );
|
||||
|
||||
std::vector< tVecDbl > vcPoints;
|
||||
|
||||
for ( int i = 0; i < nCount; ++i )
|
||||
{
|
||||
vcPoints.push_back( tVecDbl( pVertex[0], pVertex[1], pVertex[2] ) );
|
||||
pVertex += nStride;
|
||||
}
|
||||
|
||||
oHull.AddPoints( &vcPoints[0], vcPoints.size() );
|
||||
|
||||
HACD::ICHullError eErr = oHull.Process( MAX_VERTICES_PER_HULL );
|
||||
if( HACD::ICHullErrorOK != eErr )
|
||||
return LLCD_INVALID_HULL_DATA;
|
||||
|
||||
HACD::TMMesh &oMesh = oHull.GetMesh();
|
||||
|
||||
std::vector< tVecDbl > vPoints;
|
||||
std::vector< tVecLong > vTriangles;
|
||||
|
||||
vPoints.resize( oMesh.GetNVertices() );
|
||||
vTriangles.resize( oMesh.GetNTriangles() );
|
||||
|
||||
oMesh.GetIFS( &vPoints[0], &vTriangles[0] );
|
||||
|
||||
for( size_t i = 0; i < vPoints.size(); ++i )
|
||||
{
|
||||
aVerticesOut.push_back( static_cast<float>( vPoints[i].X() ) );
|
||||
aVerticesOut.push_back( static_cast<float>( vPoints[i].Y() ) );
|
||||
aVerticesOut.push_back( static_cast<float>( vPoints[i].Z() ) );
|
||||
}
|
||||
|
||||
for( size_t i = 0; i < vTriangles.size(); ++i )
|
||||
{
|
||||
aTrianglesOut.push_back( vTriangles[i].X() );
|
||||
aTrianglesOut.push_back( vTriangles[i].Y() );
|
||||
aTrianglesOut.push_back( vTriangles[i].Z() );
|
||||
}
|
||||
|
||||
return LLCD_OK;
|
||||
}
|
||||
34
indra/libndhacd/nd_hacdUtils.h
Normal file
34
indra/libndhacd/nd_hacdUtils.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* copyright 2011 sl.nicky.ml@googlemail.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef ND_HACD_UTILS_H
|
||||
#define ND_HACD_UTILS_H
|
||||
|
||||
#include "nd_hacdStructs.h"
|
||||
#include "LLConvexDecomposition.h"
|
||||
|
||||
tHACD* init( int nConcavity, int nClusters, int nMaxVerticesPerHull, double dMaxConnectDist, HACDDecoder *aData );
|
||||
DecompData decompose( tHACD *aHACD );
|
||||
|
||||
tVecLong fromI16( void *& pPtr, int aStride );
|
||||
tVecLong fromI32( void *& pPtr, int aStride );
|
||||
|
||||
LLCDResult setMeshData( const LLCDMeshData* data, bool vertex_based, HACDDecoder *aDec );
|
||||
LLCDResult convertHullToMesh( const LLCDHull* aHull, std::vector< float > &aVerticesOut, std::vector< int > &aTrianglesOut );
|
||||
|
||||
#endif
|
||||
59
indra/libndhacd/windowsincludes.h
Normal file
59
indra/libndhacd/windowsincludes.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* @file windowsincludes.h
|
||||
* @brief includes that need to be involved in the windows version of llconvexdecompositionstub
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
|
||||
// stdafx.h : include file for standard system include files,
|
||||
// or project specific include files that are used frequently, but
|
||||
// are changed infrequently
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
// Modify the following defines if you have to target a platform prior to the ones specified below.
|
||||
// Refer to MSDN for the latest info on corresponding values for different platforms.
|
||||
#ifndef WINVER // Allow use of features specific to Windows XP or later.
|
||||
#define WINVER 0x0501 // Change this to the appropriate value to target other versions of Windows.
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later.
|
||||
#define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows.
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32_WINDOWS // Allow use of features specific to Windows 98 or later.
|
||||
#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later.
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32_IE // Allow use of features specific to IE 6.0 or later.
|
||||
#define _WIN32_IE 0x0600 // Change this to the appropriate value to target other versions of IE.
|
||||
#endif
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
// Windows Header Files:
|
||||
#include <windows.h>
|
||||
|
||||
|
||||
|
||||
// TODO: reference additional headers your program requires here
|
||||
13
indra/libpathing/CMakeLists.txt
Normal file
13
indra/libpathing/CMakeLists.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
cmake_minimum_required(VERSION 2.6.4)
|
||||
|
||||
project(ndPathingLib CXX C)
|
||||
|
||||
if( MSVC )
|
||||
add_definitions(-D_HAS_ITERATOR_DEBUGGING=0 -D_SECURE_SCL=0 -D_CRT_SECURE_NO_WARNINGS=1)
|
||||
endif( MSVC )
|
||||
|
||||
file (GLOB SOURCE_FILES *.cpp )
|
||||
file (GLOB INCLUDE_FILES *.h )
|
||||
|
||||
add_library(nd_Pathing STATIC ${SOURCE_FILES} ${INCLUDE_FILES} )
|
||||
|
||||
89
indra/libpathing/llpathinglib.cpp
Normal file
89
indra/libpathing/llpathinglib.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
#include "llpathinglib.h"
|
||||
|
||||
void LLPathingLib::initSystem()
|
||||
{
|
||||
}
|
||||
|
||||
void LLPathingLib::quitSystem()
|
||||
{
|
||||
}
|
||||
|
||||
LLPathingLib* LLPathingLib::getInstance()
|
||||
{
|
||||
static LLPathingLib sObj;
|
||||
return &sObj;
|
||||
}
|
||||
|
||||
bool LLPathingLib::isFunctional()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void LLPathingLib::extractNavMeshSrcFromLLSD( std::vector< unsigned char > const &aMeshData, int aNavigation )
|
||||
{
|
||||
}
|
||||
|
||||
LLPathingLib::LLPLResult LLPathingLib::generatePath( PathingPacket const& )
|
||||
{
|
||||
return LLPL_NO_PATH;
|
||||
}
|
||||
|
||||
void LLPathingLib::cleanupResidual()
|
||||
{
|
||||
}
|
||||
|
||||
void LLPathingLib::stitchNavMeshes( )
|
||||
{
|
||||
}
|
||||
|
||||
void LLPathingLib::renderNavMesh( void )
|
||||
{
|
||||
}
|
||||
|
||||
void LLPathingLib::renderNavMeshShapesVBO( unsigned int aShapeTypeBitmask )
|
||||
{
|
||||
}
|
||||
|
||||
void LLPathingLib::renderPath()
|
||||
{
|
||||
}
|
||||
|
||||
void LLPathingLib::cleanupVBOManager()
|
||||
{
|
||||
}
|
||||
|
||||
void LLPathingLib::setNavMeshColors( NavMeshColors const &aColors )
|
||||
{
|
||||
}
|
||||
|
||||
void LLPathingLib::setNavMeshMaterialType( LLPLCharacterType aType )
|
||||
{
|
||||
}
|
||||
|
||||
void LLPathingLib::renderNavMeshEdges()
|
||||
{
|
||||
}
|
||||
|
||||
void LLPathingLib::renderPathBookend( LLRender&, LLPLRenderType )
|
||||
{
|
||||
}
|
||||
|
||||
void LLPathingLib::renderSimpleShapes( LLRender&, float )
|
||||
{
|
||||
}
|
||||
|
||||
void LLPathingLib::createPhysicsCapsuleRep( float, float, bool, LLUUID const& )
|
||||
{
|
||||
}
|
||||
|
||||
void LLPathingLib::cleanupPhysicsCapsuleRepResiduals()
|
||||
{
|
||||
}
|
||||
|
||||
void LLPathingLib::processNavMeshData()
|
||||
{
|
||||
}
|
||||
|
||||
void LLPathingLib::renderSimpleShapeCapsuleID( LLRender&, LLUUID const&, LLVector3 const&, LLQuaternion const& )
|
||||
{
|
||||
}
|
||||
181
indra/libpathing/llpathinglib.h
Normal file
181
indra/libpathing/llpathinglib.h
Normal file
@@ -0,0 +1,181 @@
|
||||
#ifndef LL_PATHINGLIB_H
|
||||
#define LL_PATHINGLIB_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#ifndef LL_V3MATH_H
|
||||
class LLVector3
|
||||
{
|
||||
public:
|
||||
float mV[3];
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef LL_V4COLORU_H
|
||||
class LLColor4U
|
||||
{
|
||||
public:
|
||||
unsigned char mV[4];
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef LL_LLUUID_H
|
||||
class LLUUID
|
||||
{
|
||||
public:
|
||||
unsigned char mData[16];
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef LLQUATERNION_H
|
||||
class LLQuaternion
|
||||
{
|
||||
public:
|
||||
double mQ[4];
|
||||
};
|
||||
#endif
|
||||
|
||||
class LLRender;
|
||||
|
||||
class LLPathingLib
|
||||
{
|
||||
public:
|
||||
enum LLPLResult
|
||||
{
|
||||
LLPL_NO_PATH,
|
||||
LLPL_PATH_GENERATED_OK,
|
||||
};
|
||||
|
||||
enum LLPLCharacterType
|
||||
{
|
||||
LLPL_CHARACTER_TYPE_NONE,
|
||||
LLPL_CHARACTER_TYPE_A,
|
||||
LLPL_CHARACTER_TYPE_B,
|
||||
LLPL_CHARACTER_TYPE_C,
|
||||
LLPL_CHARACTER_TYPE_D,
|
||||
};
|
||||
|
||||
enum LLShapeType
|
||||
{
|
||||
LLST_WalkableObjects = 1,
|
||||
LLST_ObstacleObjects = 2,
|
||||
LLST_MaterialPhantoms = 3,
|
||||
LLST_ExclusionPhantoms = 4,
|
||||
};
|
||||
|
||||
enum LLPLRenderType
|
||||
{
|
||||
LLPL_START,
|
||||
LLPL_END,
|
||||
};
|
||||
|
||||
struct Vector
|
||||
{
|
||||
double mX;
|
||||
double mY;
|
||||
double mZ;
|
||||
|
||||
Vector& operator=( LLVector3 const &aRHS )
|
||||
{
|
||||
mX = aRHS.mV[0];
|
||||
mY = aRHS.mV[1];
|
||||
mZ = aRHS.mV[2];
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator LLVector3() const
|
||||
{
|
||||
LLVector3 ret;
|
||||
ret.mV[0] = mX;
|
||||
ret.mV[1] = mY;
|
||||
ret.mV[2] = mZ;
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
struct PathingPacket
|
||||
{
|
||||
Vector mStartPointA;
|
||||
Vector mEndPointA;
|
||||
|
||||
Vector mStartPointB;
|
||||
Vector mEndPointB;
|
||||
|
||||
bool mHasPointA;
|
||||
bool mHasPointB;
|
||||
|
||||
double mCharacterWidth;
|
||||
LLPLCharacterType mCharacterType;
|
||||
};
|
||||
|
||||
struct NavMeshColor
|
||||
{
|
||||
unsigned char mR;
|
||||
unsigned char mG;
|
||||
unsigned char mB;
|
||||
unsigned char mAlpha;
|
||||
|
||||
NavMeshColor& operator=( LLColor4U const &aRHS )
|
||||
{
|
||||
mR = aRHS.mV[0];
|
||||
mG = aRHS.mV[1];
|
||||
mB = aRHS.mV[2];
|
||||
mAlpha = aRHS.mV[3];
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct NavMeshColors
|
||||
{
|
||||
NavMeshColor mWalkable;
|
||||
NavMeshColor mObstacle;
|
||||
NavMeshColor mMaterial;
|
||||
NavMeshColor mExclusion;
|
||||
NavMeshColor mConnectedEdge;
|
||||
NavMeshColor mBoundaryEdge;
|
||||
NavMeshColor mHeatColorBase;
|
||||
NavMeshColor mHeatColorMax;
|
||||
NavMeshColor mFaceColor;
|
||||
NavMeshColor mStarValid;
|
||||
NavMeshColor mStarInvalid;
|
||||
NavMeshColor mTestPath;
|
||||
NavMeshColor mWaterColor;
|
||||
};
|
||||
|
||||
static void initSystem();
|
||||
static void quitSystem();
|
||||
static LLPathingLib* getInstance();
|
||||
|
||||
bool isFunctional();
|
||||
|
||||
void extractNavMeshSrcFromLLSD( std::vector< unsigned char> const &aMeshData, int aNavigation );
|
||||
|
||||
LLPLResult generatePath( PathingPacket const& );
|
||||
void cleanupResidual();
|
||||
|
||||
void stitchNavMeshes( );
|
||||
|
||||
void renderNavMesh( void );
|
||||
void renderNavMeshShapesVBO( unsigned int aShapeTypeBitmask );
|
||||
void renderPath();
|
||||
void cleanupVBOManager();
|
||||
|
||||
void renderNavMeshEdges();
|
||||
void renderPathBookend( LLRender&, LLPLRenderType );
|
||||
|
||||
void setNavMeshColors( NavMeshColors const& );
|
||||
void setNavMeshMaterialType( LLPLCharacterType );
|
||||
|
||||
void renderSimpleShapes( LLRender&, float );
|
||||
|
||||
void createPhysicsCapsuleRep( float, float, bool, LLUUID const& );
|
||||
void cleanupPhysicsCapsuleRepResiduals();
|
||||
|
||||
void processNavMeshData();
|
||||
void renderSimpleShapeCapsuleID( LLRender&, LLUUID const&, LLVector3 const&, LLQuaternion const& );
|
||||
};
|
||||
|
||||
#endif
|
||||
10
indra/libpathing/llphysicsextensions.cpp
Normal file
10
indra/libpathing/llphysicsextensions.cpp
Normal file
@@ -0,0 +1,10 @@
|
||||
#include "llphysicsextensions.h"
|
||||
|
||||
void LLPhysicsExtensions::quitSystem()
|
||||
{
|
||||
}
|
||||
|
||||
bool LLPhysicsExtensions::isFunctional()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
12
indra/libpathing/llphysicsextensions.h
Normal file
12
indra/libpathing/llphysicsextensions.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef LLPYHSICS_EXTENSIONS_H
|
||||
#define LLPYHSICS_EXTENSIONS_H
|
||||
|
||||
class LLPhysicsExtensions
|
||||
{
|
||||
public:
|
||||
static void quitSystem();
|
||||
|
||||
bool isFunctional();
|
||||
};
|
||||
|
||||
#endif
|
||||
89
indra/llappearance/CMakeLists.txt
Normal file
89
indra/llappearance/CMakeLists.txt
Normal file
@@ -0,0 +1,89 @@
|
||||
# -*- cmake -*-
|
||||
|
||||
project(llappearance)
|
||||
|
||||
include(00-Common)
|
||||
include(LLCommon)
|
||||
include(LLCharacter)
|
||||
include(LLImage)
|
||||
include(LLInventory)
|
||||
include(LLMath)
|
||||
include(LLMessage)
|
||||
include(LLRender)
|
||||
include(LLVFS)
|
||||
include(LLWindow)
|
||||
include(LLXML)
|
||||
include(Linking)
|
||||
|
||||
include_directories(
|
||||
${LLCOMMON_INCLUDE_DIRS}
|
||||
${LLCHARACTER_INCLUDE_DIRS}
|
||||
${LLIMAGE_INCLUDE_DIRS}
|
||||
${LLINVENTORY_INCLUDE_DIRS}
|
||||
${LLMATH_INCLUDE_DIRS}
|
||||
${LLRENDER_INCLUDE_DIRS}
|
||||
${LLVFS_INCLUDE_DIRS}
|
||||
${LLWINDOW_INCLUDE_DIRS}
|
||||
${LLXML_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
set(llappearance_SOURCE_FILES
|
||||
llavatarappearance.cpp
|
||||
llavatarjoint.cpp
|
||||
llavatarjointmesh.cpp
|
||||
lldriverparam.cpp
|
||||
lllocaltextureobject.cpp
|
||||
llpolyskeletaldistortion.cpp
|
||||
llpolymesh.cpp
|
||||
llpolymorph.cpp
|
||||
lltexglobalcolor.cpp
|
||||
lltexlayer.cpp
|
||||
lltexlayerparams.cpp
|
||||
lltexturemanagerbridge.cpp
|
||||
llwearable.cpp
|
||||
llwearabledata.cpp
|
||||
llwearabletype.cpp
|
||||
llviewervisualparam.cpp
|
||||
llavatarappearancedefines.cpp
|
||||
)
|
||||
|
||||
set(llappearance_HEADER_FILES
|
||||
CMakeLists.txt
|
||||
|
||||
llavatarappearance.h
|
||||
llavatarjoint.h
|
||||
llavatarjointmesh.h
|
||||
lldriverparam.h
|
||||
lljointpickname.h
|
||||
lllocaltextureobject.h
|
||||
llpolyskeletaldistortion.h
|
||||
llpolymesh.h
|
||||
llpolymorph.h
|
||||
lltexglobalcolor.h
|
||||
lltexlayer.h
|
||||
lltexlayerparams.h
|
||||
lltexturemanagerbridge.h
|
||||
llwearable.h
|
||||
llwearabledata.h
|
||||
llwearabletype.h
|
||||
llviewervisualparam.h
|
||||
llavatarappearancedefines.h
|
||||
)
|
||||
|
||||
set_source_files_properties(${llappearance_HEADER_FILES}
|
||||
PROPERTIES HEADER_FILE_ONLY TRUE)
|
||||
|
||||
list(APPEND llappearance_SOURCE_FILES ${llappearance_HEADER_FILES})
|
||||
|
||||
add_library (llappearance ${llappearance_SOURCE_FILES})
|
||||
|
||||
target_link_libraries(llappearance
|
||||
${LLCHARACTER_LIBRARIES}
|
||||
${LLINVENTORY_LIBRARIES}
|
||||
${LLIMAGE_LIBRARIES}
|
||||
${LLRENDER_LIBRARIES}
|
||||
${LLVFS_LIBRARIES}
|
||||
${LLMATH_LIBRARIES}
|
||||
${LLXML_LIBRARIES}
|
||||
${LLCOMMON_LIBRARIES}
|
||||
)
|
||||
2020
indra/llappearance/llavatarappearance.cpp
Normal file
2020
indra/llappearance/llavatarappearance.cpp
Normal file
File diff suppressed because it is too large
Load Diff
452
indra/llappearance/llavatarappearance.h
Normal file
452
indra/llappearance/llavatarappearance.h
Normal file
@@ -0,0 +1,452 @@
|
||||
/**
|
||||
* @file llavatarappearance.h
|
||||
* @brief Declaration of LLAvatarAppearance class
|
||||
*
|
||||
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_AVATAR_APPEARANCE_H
|
||||
#define LL_AVATAR_APPEARANCE_H
|
||||
|
||||
#include "llcharacter.h"
|
||||
#include "llavatarappearancedefines.h"
|
||||
#include "llavatarjointmesh.h"
|
||||
#include "lldriverparam.h"
|
||||
#include "lltexlayer.h"
|
||||
#include "llviewervisualparam.h"
|
||||
#include "llxmltree.h"
|
||||
|
||||
class LLTexLayerSet;
|
||||
class LLTexGlobalColor;
|
||||
class LLTexGlobalColorInfo;
|
||||
class LLWearableData;
|
||||
class LLAvatarBoneInfo;
|
||||
class LLAvatarSkeletonInfo;
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// LLAvatarAppearance
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
class LLAvatarAppearance : public LLCharacter
|
||||
{
|
||||
LOG_CLASS(LLAvatarAppearance);
|
||||
|
||||
protected:
|
||||
struct LLAvatarXmlInfo;
|
||||
|
||||
/********************************************************************************
|
||||
** **
|
||||
** INITIALIZATION
|
||||
**/
|
||||
private:
|
||||
// Hide default constructor.
|
||||
LLAvatarAppearance() {}
|
||||
|
||||
public:
|
||||
LLAvatarAppearance(LLWearableData* wearable_data);
|
||||
virtual ~LLAvatarAppearance();
|
||||
|
||||
static void initClass(); // initializes static members
|
||||
static void cleanupClass(); // Cleanup data that's only init'd once per class.
|
||||
virtual void initInstance(); // Called after construction to initialize the instance.
|
||||
virtual BOOL loadSkeletonNode();
|
||||
BOOL loadMeshNodes();
|
||||
BOOL loadLayersets();
|
||||
|
||||
|
||||
/** Initialization
|
||||
** **
|
||||
*******************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
** **
|
||||
** INHERITED
|
||||
**/
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// LLCharacter interface and related
|
||||
//--------------------------------------------------------------------
|
||||
public:
|
||||
/*virtual*/ LLJoint* getCharacterJoint(U32 num);
|
||||
|
||||
/*virtual*/ const char* getAnimationPrefix() { return "avatar"; }
|
||||
/*virtual*/ LLVector3 getVolumePos(S32 joint_index, LLVector3& volume_offset);
|
||||
/*virtual*/ LLJoint* findCollisionVolume(U32 volume_id);
|
||||
/*virtual*/ S32 getCollisionVolumeID(std::string &name);
|
||||
/*virtual*/ LLPolyMesh* getHeadMesh();
|
||||
/*virtual*/ LLPolyMesh* getUpperBodyMesh();
|
||||
LLPolyMesh* getMesh( LLPolyMeshSharedData *shared_data );
|
||||
|
||||
typedef std::map<S32, std::string> lod_mesh_map_t;
|
||||
typedef std::map<std::string, lod_mesh_map_t> mesh_info_t;
|
||||
static void getMeshInfo(mesh_info_t* mesh_info);
|
||||
|
||||
/** Inherited
|
||||
** **
|
||||
*******************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
** **
|
||||
** STATE
|
||||
**/
|
||||
public:
|
||||
virtual bool isSelf() const { return false; } // True if this avatar is for this viewer's agent
|
||||
virtual BOOL isValid() const;
|
||||
virtual BOOL isUsingServerBakes() const = 0;
|
||||
virtual BOOL isUsingLocalAppearance() const = 0;
|
||||
virtual BOOL isEditingAppearance() const = 0;
|
||||
|
||||
bool isBuilt() const { return mIsBuilt; }
|
||||
|
||||
virtual std::string getFullname() const = 0;
|
||||
/** State
|
||||
** **
|
||||
*******************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
** **
|
||||
** SKELETON
|
||||
**/
|
||||
|
||||
protected:
|
||||
virtual LLAvatarJoint* createAvatarJoint() = 0;
|
||||
virtual LLAvatarJoint* createAvatarJoint(S32 joint_num) = 0;
|
||||
virtual LLAvatarJointMesh* createAvatarJointMesh() = 0;
|
||||
public:
|
||||
F32 getPelvisToFoot() const { return mPelvisToFoot; }
|
||||
/*virtual*/ LLJoint* getRootJoint() { return mRoot; }
|
||||
|
||||
LLVector3 mHeadOffset; // current head position
|
||||
LLAvatarJoint *mRoot;
|
||||
|
||||
typedef std::map<std::string, LLJoint*> joint_map_t;
|
||||
joint_map_t mJointMap;
|
||||
|
||||
void computeBodySize();
|
||||
|
||||
|
||||
protected:
|
||||
static BOOL parseSkeletonFile(const std::string& filename);
|
||||
virtual void buildCharacter();
|
||||
virtual BOOL loadAvatar();
|
||||
virtual void bodySizeChanged() = 0;
|
||||
|
||||
BOOL setupBone(const LLAvatarBoneInfo* info, LLJoint* parent, S32 ¤t_volume_num, S32 ¤t_joint_num);
|
||||
BOOL allocateCharacterJoints(U32 num);
|
||||
BOOL buildSkeleton(const LLAvatarSkeletonInfo *info);
|
||||
protected:
|
||||
void clearSkeleton();
|
||||
BOOL mIsBuilt; // state of deferred character building
|
||||
typedef std::vector<LLAvatarJoint*> avatar_joint_list_t;
|
||||
avatar_joint_list_t mSkeleton;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Pelvis height adjustment members.
|
||||
//--------------------------------------------------------------------
|
||||
public:
|
||||
LLVector3 mBodySize;
|
||||
protected:
|
||||
F32 mPelvisToFoot;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Cached pointers to well known joints
|
||||
//--------------------------------------------------------------------
|
||||
public:
|
||||
LLJoint* mPelvisp;
|
||||
LLJoint* mTorsop;
|
||||
LLJoint* mChestp;
|
||||
LLJoint* mNeckp;
|
||||
LLJoint* mHeadp;
|
||||
LLJoint* mSkullp;
|
||||
LLJoint* mEyeLeftp;
|
||||
LLJoint* mEyeRightp;
|
||||
LLJoint* mHipLeftp;
|
||||
LLJoint* mHipRightp;
|
||||
LLJoint* mKneeLeftp;
|
||||
LLJoint* mKneeRightp;
|
||||
LLJoint* mAnkleLeftp;
|
||||
LLJoint* mAnkleRightp;
|
||||
LLJoint* mFootLeftp;
|
||||
LLJoint* mFootRightp;
|
||||
LLJoint* mWristLeftp;
|
||||
LLJoint* mWristRightp;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// XML parse tree
|
||||
//--------------------------------------------------------------------
|
||||
protected:
|
||||
static LLXmlTree sXMLTree; // avatar config file
|
||||
static LLXmlTree sSkeletonXMLTree; // avatar skeleton file
|
||||
|
||||
static LLAvatarSkeletonInfo* sAvatarSkeletonInfo;
|
||||
static LLAvatarXmlInfo* sAvatarXmlInfo;
|
||||
|
||||
|
||||
/** Skeleton
|
||||
** **
|
||||
*******************************************************************************/
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
** **
|
||||
** RENDERING
|
||||
**/
|
||||
public:
|
||||
BOOL mIsDummy; // for special views
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Morph masks
|
||||
//--------------------------------------------------------------------
|
||||
public:
|
||||
void addMaskedMorph(LLAvatarAppearanceDefines::EBakedTextureIndex index, LLVisualParam* morph_target, BOOL invert, std::string layer);
|
||||
virtual void applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components, LLAvatarAppearanceDefines::EBakedTextureIndex index = LLAvatarAppearanceDefines::BAKED_NUM_INDICES) = 0;
|
||||
|
||||
/** Rendering
|
||||
** **
|
||||
*******************************************************************************/
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Composites
|
||||
//--------------------------------------------------------------------
|
||||
public:
|
||||
virtual void invalidateComposite(LLTexLayerSet* layerset, BOOL upload_result) = 0;
|
||||
|
||||
/********************************************************************************
|
||||
** **
|
||||
** MESHES
|
||||
**/
|
||||
|
||||
public:
|
||||
virtual void updateMeshTextures() = 0;
|
||||
virtual void dirtyMesh() = 0; // Dirty the avatar mesh
|
||||
protected:
|
||||
virtual void dirtyMesh(S32 priority) = 0; // Dirty the avatar mesh, with priority
|
||||
|
||||
protected:
|
||||
typedef std::multimap<std::string, LLPolyMesh*> polymesh_map_t;
|
||||
polymesh_map_t mPolyMeshes;
|
||||
avatar_joint_list_t mMeshLOD;
|
||||
|
||||
/** Meshes
|
||||
** **
|
||||
*******************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
** **
|
||||
** APPEARANCE
|
||||
**/
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Clothing colors (convenience functions to access visual parameters)
|
||||
//--------------------------------------------------------------------
|
||||
public:
|
||||
void setClothesColor(LLAvatarAppearanceDefines::ETextureIndex te, const LLColor4& new_color, BOOL upload_bake);
|
||||
LLColor4 getClothesColor(LLAvatarAppearanceDefines::ETextureIndex te);
|
||||
static BOOL teToColorParams(LLAvatarAppearanceDefines::ETextureIndex te, U32 *param_name);
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Global colors
|
||||
//--------------------------------------------------------------------
|
||||
public:
|
||||
LLColor4 getGlobalColor(const std::string& color_name ) const;
|
||||
virtual void onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL upload_bake) = 0;
|
||||
protected:
|
||||
LLTexGlobalColor* mTexSkinColor;
|
||||
LLTexGlobalColor* mTexHairColor;
|
||||
LLTexGlobalColor* mTexEyeColor;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Visibility
|
||||
//--------------------------------------------------------------------
|
||||
public:
|
||||
static LLColor4 getDummyColor();
|
||||
/** Appearance
|
||||
** **
|
||||
*******************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
** **
|
||||
** WEARABLES
|
||||
**/
|
||||
|
||||
public:
|
||||
LLWearableData* getWearableData() { return mWearableData; }
|
||||
const LLWearableData* getWearableData() const { return mWearableData; }
|
||||
virtual BOOL isTextureDefined(LLAvatarAppearanceDefines::ETextureIndex te, U32 index = 0 ) const = 0;
|
||||
virtual BOOL isWearingWearableType(LLWearableType::EType type ) const;
|
||||
|
||||
private:
|
||||
LLWearableData* mWearableData;
|
||||
|
||||
/********************************************************************************
|
||||
** **
|
||||
** BAKED TEXTURES
|
||||
**/
|
||||
public:
|
||||
LLTexLayerSet* getAvatarLayerSet(LLAvatarAppearanceDefines::EBakedTextureIndex baked_index) const;
|
||||
|
||||
protected:
|
||||
virtual LLTexLayerSet* createTexLayerSet() = 0;
|
||||
|
||||
protected:
|
||||
class LLMaskedMorph;
|
||||
typedef std::deque<LLMaskedMorph *> morph_list_t;
|
||||
struct BakedTextureData
|
||||
{
|
||||
LLUUID mLastTextureID;
|
||||
LLTexLayerSet* mTexLayerSet; // Only exists for self
|
||||
bool mIsLoaded;
|
||||
bool mIsUsed;
|
||||
LLAvatarAppearanceDefines::ETextureIndex mTextureIndex;
|
||||
U32 mMaskTexName;
|
||||
// Stores pointers to the joint meshes that this baked texture deals with
|
||||
avatar_joint_mesh_list_t mJointMeshes;
|
||||
morph_list_t mMaskedMorphs;
|
||||
};
|
||||
typedef std::vector<BakedTextureData> bakedtexturedata_vec_t;
|
||||
bakedtexturedata_vec_t mBakedTextureDatas;
|
||||
|
||||
/********************************************************************************
|
||||
** **
|
||||
** PHYSICS
|
||||
**/
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Collision volumes
|
||||
//--------------------------------------------------------------------
|
||||
public:
|
||||
S32 mNumCollisionVolumes;
|
||||
LLAvatarJointCollisionVolume* mCollisionVolumes;
|
||||
protected:
|
||||
BOOL allocateCollisionVolumes(U32 num);
|
||||
|
||||
/** Physics
|
||||
** **
|
||||
*******************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
** **
|
||||
** SUPPORT CLASSES
|
||||
**/
|
||||
|
||||
struct LLAvatarXmlInfo
|
||||
{
|
||||
LLAvatarXmlInfo();
|
||||
~LLAvatarXmlInfo();
|
||||
|
||||
BOOL parseXmlSkeletonNode(LLXmlTreeNode* root);
|
||||
BOOL parseXmlMeshNodes(LLXmlTreeNode* root);
|
||||
BOOL parseXmlColorNodes(LLXmlTreeNode* root);
|
||||
BOOL parseXmlLayerNodes(LLXmlTreeNode* root);
|
||||
BOOL parseXmlDriverNodes(LLXmlTreeNode* root);
|
||||
BOOL parseXmlMorphNodes(LLXmlTreeNode* root);
|
||||
|
||||
struct LLAvatarMeshInfo
|
||||
{
|
||||
typedef std::pair<LLViewerVisualParamInfo*,BOOL> morph_info_pair_t; // LLPolyMorphTargetInfo stored here
|
||||
typedef std::vector<morph_info_pair_t> morph_info_list_t;
|
||||
|
||||
LLAvatarMeshInfo() : mLOD(0), mMinPixelArea(.1f) {}
|
||||
~LLAvatarMeshInfo()
|
||||
{
|
||||
morph_info_list_t::iterator iter;
|
||||
for (iter = mPolyMorphTargetInfoList.begin(); iter != mPolyMorphTargetInfoList.end(); iter++)
|
||||
{
|
||||
delete iter->first;
|
||||
}
|
||||
mPolyMorphTargetInfoList.clear();
|
||||
}
|
||||
|
||||
std::string mType;
|
||||
S32 mLOD;
|
||||
std::string mMeshFileName;
|
||||
std::string mReferenceMeshName;
|
||||
F32 mMinPixelArea;
|
||||
morph_info_list_t mPolyMorphTargetInfoList;
|
||||
};
|
||||
typedef std::vector<LLAvatarMeshInfo*> mesh_info_list_t;
|
||||
mesh_info_list_t mMeshInfoList;
|
||||
|
||||
typedef std::vector<LLViewerVisualParamInfo*> skeletal_distortion_info_list_t; // LLPolySkeletalDistortionInfo stored here
|
||||
skeletal_distortion_info_list_t mSkeletalDistortionInfoList;
|
||||
|
||||
struct LLAvatarAttachmentInfo
|
||||
{
|
||||
LLAvatarAttachmentInfo()
|
||||
: mGroup(-1), mAttachmentID(-1), mPieMenuSlice(-1), mVisibleFirstPerson(FALSE),
|
||||
mIsHUDAttachment(FALSE), mHasPosition(FALSE), mHasRotation(FALSE) {}
|
||||
std::string mName;
|
||||
std::string mJointName;
|
||||
LLVector3 mPosition;
|
||||
LLVector3 mRotationEuler;
|
||||
S32 mGroup;
|
||||
S32 mAttachmentID;
|
||||
S32 mPieMenuSlice;
|
||||
BOOL mVisibleFirstPerson;
|
||||
BOOL mIsHUDAttachment;
|
||||
BOOL mHasPosition;
|
||||
BOOL mHasRotation;
|
||||
};
|
||||
typedef std::vector<LLAvatarAttachmentInfo*> attachment_info_list_t;
|
||||
attachment_info_list_t mAttachmentInfoList;
|
||||
|
||||
LLTexGlobalColorInfo *mTexSkinColorInfo;
|
||||
LLTexGlobalColorInfo *mTexHairColorInfo;
|
||||
LLTexGlobalColorInfo *mTexEyeColorInfo;
|
||||
|
||||
typedef std::vector<LLTexLayerSetInfo*> layer_info_list_t;
|
||||
layer_info_list_t mLayerInfoList;
|
||||
|
||||
typedef std::vector<LLDriverParamInfo*> driver_info_list_t;
|
||||
driver_info_list_t mDriverInfoList;
|
||||
|
||||
struct LLAvatarMorphInfo
|
||||
{
|
||||
LLAvatarMorphInfo()
|
||||
: mInvert(FALSE) {}
|
||||
std::string mName;
|
||||
std::string mRegion;
|
||||
std::string mLayer;
|
||||
BOOL mInvert;
|
||||
};
|
||||
|
||||
typedef std::vector<LLAvatarMorphInfo*> morph_info_list_t;
|
||||
morph_info_list_t mMorphMaskInfoList;
|
||||
};
|
||||
|
||||
|
||||
class LLMaskedMorph
|
||||
{
|
||||
public:
|
||||
LLMaskedMorph(LLVisualParam *morph_target, BOOL invert, std::string layer);
|
||||
|
||||
LLVisualParam *mMorphTarget;
|
||||
BOOL mInvert;
|
||||
std::string mLayer;
|
||||
};
|
||||
/** Support Classes
|
||||
** **
|
||||
*******************************************************************************/
|
||||
};
|
||||
|
||||
#endif // LL_AVATAR_APPEARANCE_H
|
||||
@@ -1,51 +1,43 @@
|
||||
/**
|
||||
* @file llvoavatar.cpp
|
||||
* @brief Implementation of LLVOAvatar class which is a derivation fo LLViewerObject
|
||||
* @file llavatarappearancedefines.cpp
|
||||
* @brief Implementation of LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2001-2009, Linden Research, Inc.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
#include "llvoavatardefines.h"
|
||||
#include "llviewercontrol.h" // gSavedSettings
|
||||
#include "linden_common.h"
|
||||
#include "llavatarappearancedefines.h"
|
||||
|
||||
const S32 LLVOAvatarDefines::SCRATCH_TEX_WIDTH = 512;
|
||||
const S32 LLVOAvatarDefines::SCRATCH_TEX_HEIGHT = 512;
|
||||
const S32 LLVOAvatarDefines::IMPOSTOR_PERIOD = 2;
|
||||
const S32 LLAvatarAppearanceDefines::SCRATCH_TEX_WIDTH = 512;
|
||||
const S32 LLAvatarAppearanceDefines::SCRATCH_TEX_HEIGHT = 512;
|
||||
const S32 LLAvatarAppearanceDefines::IMPOSTOR_PERIOD = 2;
|
||||
|
||||
using namespace LLVOAvatarDefines;
|
||||
using namespace LLAvatarAppearanceDefines;
|
||||
|
||||
/*********************************************************************************
|
||||
* Edit this function to add/remove/change textures and mesh definitions for avatars.
|
||||
* If these are changed, they MUST be changed in floater_avatar_textures.xml as well!
|
||||
*/
|
||||
|
||||
LLVOAvatarDictionary::Textures::Textures()
|
||||
LLAvatarAppearanceDictionary::Textures::Textures()
|
||||
{
|
||||
addEntry(TEX_HEAD_BODYPAINT, new TextureEntry("head_bodypaint", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_SKIN));
|
||||
addEntry(TEX_UPPER_SHIRT, new TextureEntry("upper_shirt", TRUE, BAKED_NUM_INDICES, "UIImgDefaultShirtUUID", LLWearableType::WT_SHIRT));
|
||||
@@ -73,15 +65,15 @@ LLVOAvatarDictionary::Textures::Textures()
|
||||
addEntry(TEX_UPPER_TATTOO, new TextureEntry("upper_tattoo", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_TATTOO));
|
||||
addEntry(TEX_LOWER_TATTOO, new TextureEntry("lower_tattoo", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_TATTOO));
|
||||
|
||||
addEntry(TEX_HEAD_BAKED, new TextureEntry("head-baked", FALSE, BAKED_HEAD));
|
||||
addEntry(TEX_UPPER_BAKED, new TextureEntry("upper-baked", FALSE, BAKED_UPPER));
|
||||
addEntry(TEX_LOWER_BAKED, new TextureEntry("lower-baked", FALSE, BAKED_LOWER));
|
||||
addEntry(TEX_EYES_BAKED, new TextureEntry("eyes-baked", FALSE, BAKED_EYES));
|
||||
addEntry(TEX_HAIR_BAKED, new TextureEntry("hair-baked", FALSE, BAKED_HAIR));
|
||||
addEntry(TEX_SKIRT_BAKED, new TextureEntry("skirt-baked", FALSE, BAKED_SKIRT));
|
||||
addEntry(TEX_HEAD_BAKED, new TextureEntry("head-baked", FALSE, BAKED_HEAD, "head"));
|
||||
addEntry(TEX_UPPER_BAKED, new TextureEntry("upper-baked", FALSE, BAKED_UPPER, "upper"));
|
||||
addEntry(TEX_LOWER_BAKED, new TextureEntry("lower-baked", FALSE, BAKED_LOWER, "lower"));
|
||||
addEntry(TEX_EYES_BAKED, new TextureEntry("eyes-baked", FALSE, BAKED_EYES, "eyes"));
|
||||
addEntry(TEX_HAIR_BAKED, new TextureEntry("hair-baked", FALSE, BAKED_HAIR, "hair"));
|
||||
addEntry(TEX_SKIRT_BAKED, new TextureEntry("skirt-baked", FALSE, BAKED_SKIRT, "skirt"));
|
||||
}
|
||||
|
||||
LLVOAvatarDictionary::BakedTextures::BakedTextures()
|
||||
LLAvatarAppearanceDictionary::BakedTextures::BakedTextures()
|
||||
{
|
||||
// Baked textures
|
||||
addEntry(BAKED_HEAD, new BakedEntry(TEX_HEAD_BAKED,
|
||||
@@ -117,36 +109,36 @@ LLVOAvatarDictionary::BakedTextures::BakedTextures()
|
||||
2, LLWearableType::WT_HAIR, LLWearableType::WT_ALPHA));
|
||||
}
|
||||
|
||||
LLVOAvatarDictionary::Meshes::Meshes()
|
||||
LLAvatarAppearanceDictionary::MeshEntries::MeshEntries()
|
||||
{
|
||||
// Meshes
|
||||
addEntry(MESH_ID_HAIR, new MeshEntry(BAKED_HAIR, "hairMesh", 6, LLViewerJoint::PN_4));
|
||||
addEntry(MESH_ID_HEAD, new MeshEntry(BAKED_HEAD, "headMesh", 5, LLViewerJoint::PN_5));
|
||||
addEntry(MESH_ID_EYELASH, new MeshEntry(BAKED_HEAD, "eyelashMesh", 1, LLViewerJoint::PN_0)); // no baked mesh associated currently
|
||||
addEntry(MESH_ID_UPPER_BODY, new MeshEntry(BAKED_UPPER, "upperBodyMesh", 5, LLViewerJoint::PN_1));
|
||||
addEntry(MESH_ID_LOWER_BODY, new MeshEntry(BAKED_LOWER, "lowerBodyMesh", 5, LLViewerJoint::PN_2));
|
||||
addEntry(MESH_ID_EYEBALL_LEFT, new MeshEntry(BAKED_EYES, "eyeBallLeftMesh", 2, LLViewerJoint::PN_3));
|
||||
addEntry(MESH_ID_EYEBALL_RIGHT, new MeshEntry(BAKED_EYES, "eyeBallRightMesh", 2, LLViewerJoint::PN_3));
|
||||
addEntry(MESH_ID_SKIRT, new MeshEntry(BAKED_SKIRT, "skirtMesh", 5, LLViewerJoint::PN_5));
|
||||
// MeshEntries
|
||||
addEntry(MESH_ID_HAIR, new MeshEntry(BAKED_HAIR, "hairMesh", 6, PN_4));
|
||||
addEntry(MESH_ID_HEAD, new MeshEntry(BAKED_HEAD, "headMesh", 5, PN_5));
|
||||
addEntry(MESH_ID_EYELASH, new MeshEntry(BAKED_HEAD, "eyelashMesh", 1, PN_0)); // no baked mesh associated currently
|
||||
addEntry(MESH_ID_UPPER_BODY, new MeshEntry(BAKED_UPPER, "upperBodyMesh", 5, PN_1));
|
||||
addEntry(MESH_ID_LOWER_BODY, new MeshEntry(BAKED_LOWER, "lowerBodyMesh", 5, PN_2));
|
||||
addEntry(MESH_ID_EYEBALL_LEFT, new MeshEntry(BAKED_EYES, "eyeBallLeftMesh", 2, PN_3));
|
||||
addEntry(MESH_ID_EYEBALL_RIGHT, new MeshEntry(BAKED_EYES, "eyeBallRightMesh", 2, PN_3));
|
||||
addEntry(MESH_ID_SKIRT, new MeshEntry(BAKED_SKIRT, "skirtMesh", 5, PN_5));
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*********************************************************************************/
|
||||
|
||||
LLVOAvatarDictionary::LLVOAvatarDictionary()
|
||||
LLAvatarAppearanceDictionary::LLAvatarAppearanceDictionary()
|
||||
{
|
||||
createAssociations();
|
||||
}
|
||||
|
||||
//virtual
|
||||
LLVOAvatarDictionary::~LLVOAvatarDictionary()
|
||||
LLAvatarAppearanceDictionary::~LLAvatarAppearanceDictionary()
|
||||
{
|
||||
}
|
||||
|
||||
// Baked textures are composites of textures; for each such composited texture,
|
||||
// map it to the baked texture.
|
||||
void LLVOAvatarDictionary::createAssociations()
|
||||
void LLAvatarAppearanceDictionary::createAssociations()
|
||||
{
|
||||
for (BakedTextures::const_iterator iter = mBakedTextures.begin(); iter != mBakedTextures.end(); iter++)
|
||||
{
|
||||
@@ -167,11 +159,11 @@ void LLVOAvatarDictionary::createAssociations()
|
||||
|
||||
}
|
||||
|
||||
LLVOAvatarDictionary::TextureEntry::TextureEntry(const std::string &name,
|
||||
bool is_local_texture,
|
||||
EBakedTextureIndex baked_texture_index,
|
||||
const std::string &default_image_name,
|
||||
LLWearableType::EType wearable_type) :
|
||||
LLAvatarAppearanceDictionary::TextureEntry::TextureEntry(const std::string &name,
|
||||
bool is_local_texture,
|
||||
EBakedTextureIndex baked_texture_index,
|
||||
const std::string &default_image_name,
|
||||
LLWearableType::EType wearable_type) :
|
||||
LLDictionaryEntry(name),
|
||||
mIsLocalTexture(is_local_texture),
|
||||
mIsBakedTexture(!is_local_texture),
|
||||
@@ -182,17 +174,17 @@ LLVOAvatarDictionary::TextureEntry::TextureEntry(const std::string &name,
|
||||
{
|
||||
}
|
||||
|
||||
LLVOAvatarDictionary::MeshEntry::MeshEntry(EBakedTextureIndex baked_index,
|
||||
LLAvatarAppearanceDictionary::MeshEntry::MeshEntry(EBakedTextureIndex baked_index,
|
||||
const std::string &name,
|
||||
U8 level,
|
||||
LLViewerJoint::PickName pick) :
|
||||
LLJointPickName pick) :
|
||||
LLDictionaryEntry(name),
|
||||
mBakedID(baked_index),
|
||||
mLOD(level),
|
||||
mPickName(pick)
|
||||
{
|
||||
}
|
||||
LLVOAvatarDictionary::BakedEntry::BakedEntry(ETextureIndex tex_index,
|
||||
LLAvatarAppearanceDictionary::BakedEntry::BakedEntry(ETextureIndex tex_index,
|
||||
const std::string &name,
|
||||
const std::string &hash_name,
|
||||
U32 num_local_textures,
|
||||
@@ -223,18 +215,18 @@ LLVOAvatarDictionary::BakedEntry::BakedEntry(ETextureIndex tex_index,
|
||||
}
|
||||
|
||||
// static
|
||||
ETextureIndex LLVOAvatarDictionary::bakedToLocalTextureIndex(EBakedTextureIndex index)
|
||||
ETextureIndex LLAvatarAppearanceDictionary::bakedToLocalTextureIndex(EBakedTextureIndex index)
|
||||
{
|
||||
return LLVOAvatarDictionary::getInstance()->getBakedTexture(index)->mTextureIndex;
|
||||
return LLAvatarAppearanceDictionary::getInstance()->getBakedTexture(index)->mTextureIndex;
|
||||
}
|
||||
|
||||
//static
|
||||
EBakedTextureIndex LLVOAvatarDictionary::findBakedByRegionName(std::string name)
|
||||
// static
|
||||
EBakedTextureIndex LLAvatarAppearanceDictionary::findBakedByRegionName(std::string name)
|
||||
{
|
||||
U8 index = 0;
|
||||
while (index < BAKED_NUM_INDICES)
|
||||
{
|
||||
const BakedEntry *be = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex) index);
|
||||
const BakedEntry *be = LLAvatarAppearanceDictionary::getInstance()->getBakedTexture((EBakedTextureIndex) index);
|
||||
if (be && be->mName.compare(name) == 0)
|
||||
{
|
||||
// baked texture found
|
||||
@@ -246,23 +238,31 @@ EBakedTextureIndex LLVOAvatarDictionary::findBakedByRegionName(std::string name)
|
||||
return BAKED_NUM_INDICES;
|
||||
}
|
||||
|
||||
//static
|
||||
const LLUUID LLVOAvatarDictionary::getDefaultTextureImageID(ETextureIndex index)
|
||||
// static
|
||||
EBakedTextureIndex LLAvatarAppearanceDictionary::findBakedByImageName(std::string name)
|
||||
{
|
||||
const TextureEntry *texture_dict = getInstance()->getTexture(index);
|
||||
const std::string &default_image_name = texture_dict->mDefaultImageName;
|
||||
if (default_image_name == "")
|
||||
U8 index = 0;
|
||||
while (index < BAKED_NUM_INDICES)
|
||||
{
|
||||
return IMG_DEFAULT_AVATAR;
|
||||
}
|
||||
else
|
||||
{
|
||||
return LLUUID(gSavedSettings.getString(default_image_name));
|
||||
const BakedEntry *be = LLAvatarAppearanceDictionary::getInstance()->getBakedTexture((EBakedTextureIndex) index);
|
||||
if (be)
|
||||
{
|
||||
const TextureEntry *te = LLAvatarAppearanceDictionary::getInstance()->getTexture(be->mTextureIndex);
|
||||
if (te && te->mDefaultImageName.compare(name) == 0)
|
||||
{
|
||||
// baked texture found
|
||||
return (EBakedTextureIndex) index;
|
||||
}
|
||||
}
|
||||
index++;
|
||||
}
|
||||
// baked texture could not be found
|
||||
return BAKED_NUM_INDICES;
|
||||
}
|
||||
|
||||
// static
|
||||
LLWearableType::EType LLVOAvatarDictionary::getTEWearableType(ETextureIndex index )
|
||||
LLWearableType::EType LLAvatarAppearanceDictionary::getTEWearableType(ETextureIndex index )
|
||||
{
|
||||
return getInstance()->getTexture(index)->mWearableType;
|
||||
}
|
||||
|
||||
@@ -1,45 +1,40 @@
|
||||
/**
|
||||
* @file llvoavatar.h
|
||||
* @brief Declaration of LLVOAvatar class which is a derivation fo
|
||||
* @file llavatarappearancedefines.h
|
||||
* @brief Various LLAvatarAppearance related definitions
|
||||
* LLViewerObject
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2001-2009, Linden Research, Inc.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LLVOAVATAR_DEFINES_H
|
||||
#define LLVOAVATAR_DEFINES_H
|
||||
#ifndef LL_AVATARAPPEARANCE_DEFINES_H
|
||||
#define LL_AVATARAPPEARANCE_DEFINES_H
|
||||
|
||||
#include <vector>
|
||||
#include "llwearable.h"
|
||||
#include "llviewerjoint.h"
|
||||
#include "lljointpickname.h"
|
||||
#include "lldictionary.h"
|
||||
#include "llwearabletype.h"
|
||||
#include "lluuid.h"
|
||||
|
||||
namespace LLVOAvatarDefines
|
||||
namespace LLAvatarAppearanceDefines
|
||||
{
|
||||
|
||||
extern const S32 SCRATCH_TEX_WIDTH;
|
||||
@@ -47,10 +42,11 @@ extern const S32 SCRATCH_TEX_HEIGHT;
|
||||
extern const S32 IMPOSTOR_PERIOD;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// texture entry assignment
|
||||
// Enums
|
||||
//--------------------------------------------------------------------
|
||||
enum ETextureIndex
|
||||
{
|
||||
TEX_INVALID = -1,
|
||||
TEX_HEAD_BODYPAINT = 0,
|
||||
TEX_UPPER_SHIRT,
|
||||
TEX_LOWER_PANTS,
|
||||
@@ -59,9 +55,9 @@ enum ETextureIndex
|
||||
TEX_UPPER_BODYPAINT,
|
||||
TEX_LOWER_BODYPAINT,
|
||||
TEX_LOWER_SHOES,
|
||||
TEX_HEAD_BAKED, // Pre-composited
|
||||
TEX_UPPER_BAKED, // Pre-composited
|
||||
TEX_LOWER_BAKED, // Pre-composited
|
||||
TEX_HEAD_BAKED, // Pre-composited
|
||||
TEX_UPPER_BAKED, // Pre-composited
|
||||
TEX_LOWER_BAKED, // Pre-composited
|
||||
TEX_EYES_BAKED, // Pre-composited
|
||||
TEX_LOWER_SOCKS,
|
||||
TEX_UPPER_JACKET,
|
||||
@@ -70,7 +66,7 @@ enum ETextureIndex
|
||||
TEX_UPPER_UNDERSHIRT,
|
||||
TEX_LOWER_UNDERPANTS,
|
||||
TEX_SKIRT,
|
||||
TEX_SKIRT_BAKED, // Pre-composited
|
||||
TEX_SKIRT_BAKED, // Pre-composited
|
||||
TEX_HAIR_BAKED, // Pre-composited
|
||||
TEX_LOWER_ALPHA,
|
||||
TEX_UPPER_ALPHA,
|
||||
@@ -81,7 +77,7 @@ enum ETextureIndex
|
||||
TEX_UPPER_TATTOO,
|
||||
TEX_LOWER_TATTOO,
|
||||
TEX_NUM_INDICES
|
||||
};
|
||||
};
|
||||
|
||||
enum EBakedTextureIndex
|
||||
{
|
||||
@@ -117,21 +113,21 @@ typedef std::vector<EMeshIndex> mesh_vec_t;
|
||||
typedef std::vector<LLWearableType::EType> wearables_vec_t;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// LLVOAvatarDictionary
|
||||
// LLAvatarAppearanceDictionary
|
||||
//
|
||||
// Holds dictionary static entries for textures, baked textures, meshes, etc.; i.e.
|
||||
// information that is common to all avatars.
|
||||
//
|
||||
// This holds const data - it is initialized once and the contents never change after that.
|
||||
//------------------------------------------------------------------------
|
||||
class LLVOAvatarDictionary : public LLSingleton<LLVOAvatarDictionary>
|
||||
class LLAvatarAppearanceDictionary : public LLSingleton<LLAvatarAppearanceDictionary>
|
||||
{
|
||||
//--------------------------------------------------------------------
|
||||
// Constructors and Destructors
|
||||
//--------------------------------------------------------------------
|
||||
public:
|
||||
LLVOAvatarDictionary();
|
||||
virtual ~LLVOAvatarDictionary();
|
||||
LLAvatarAppearanceDictionary();
|
||||
virtual ~LLAvatarAppearanceDictionary();
|
||||
private:
|
||||
void createAssociations();
|
||||
|
||||
@@ -141,19 +137,19 @@ private:
|
||||
public:
|
||||
struct TextureEntry : public LLDictionaryEntry
|
||||
{
|
||||
TextureEntry(const std::string &name,
|
||||
bool is_local_texture,
|
||||
EBakedTextureIndex baked_texture_index = BAKED_NUM_INDICES,
|
||||
const std::string &default_image_name = "",
|
||||
TextureEntry(const std::string &name, // this must match the xml name used by LLTexLayerInfo::parseXml
|
||||
bool is_local_texture,
|
||||
EBakedTextureIndex baked_texture_index = BAKED_NUM_INDICES,
|
||||
const std::string& default_image_name = "",
|
||||
LLWearableType::EType wearable_type = LLWearableType::WT_INVALID);
|
||||
const std::string mDefaultImageName;
|
||||
const std::string mDefaultImageName;
|
||||
const LLWearableType::EType mWearableType;
|
||||
// It's either a local texture xor baked
|
||||
BOOL mIsLocalTexture;
|
||||
BOOL mIsBakedTexture;
|
||||
BOOL mIsLocalTexture;
|
||||
BOOL mIsBakedTexture;
|
||||
// If it's a local texture, it may be used by a baked texture
|
||||
BOOL mIsUsedByBakedTexture;
|
||||
EBakedTextureIndex mBakedTextureIndex;
|
||||
BOOL mIsUsedByBakedTexture;
|
||||
EBakedTextureIndex mBakedTextureIndex;
|
||||
};
|
||||
|
||||
struct Textures : public LLDictionary<ETextureIndex, TextureEntry>
|
||||
@@ -170,22 +166,22 @@ public:
|
||||
struct MeshEntry : public LLDictionaryEntry
|
||||
{
|
||||
MeshEntry(EBakedTextureIndex baked_index,
|
||||
const std::string &name,
|
||||
U8 level,
|
||||
LLViewerJoint::PickName pick);
|
||||
const std::string &name, // names of mesh types as they are used in avatar_lad.xml
|
||||
U8 level,
|
||||
LLJointPickName pick);
|
||||
// Levels of Detail for each mesh. Must match levels of detail present in avatar_lad.xml
|
||||
// Otherwise meshes will be unable to be found, or levels of detail will be ignored
|
||||
const U8 mLOD;
|
||||
const EBakedTextureIndex mBakedID;
|
||||
const LLViewerJoint::PickName mPickName;
|
||||
const U8 mLOD;
|
||||
const EBakedTextureIndex mBakedID;
|
||||
const LLJointPickName mPickName;
|
||||
};
|
||||
|
||||
struct Meshes : public LLDictionary<EMeshIndex, MeshEntry>
|
||||
struct MeshEntries : public LLDictionary<EMeshIndex, MeshEntry>
|
||||
{
|
||||
Meshes();
|
||||
} mMeshes;
|
||||
const MeshEntry* getMesh(EMeshIndex index) const { return mMeshes.lookup(index); }
|
||||
const Meshes& getMeshes() const { return mMeshes; }
|
||||
MeshEntries();
|
||||
} mMeshEntries;
|
||||
const MeshEntry* getMeshEntry(EMeshIndex index) const { return mMeshEntries.lookup(index); }
|
||||
const MeshEntries& getMeshEntries() const { return mMeshEntries; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Baked Textures
|
||||
@@ -204,7 +200,7 @@ public:
|
||||
const LLUUID mWearablesHashID;
|
||||
wearables_vec_t mWearables;
|
||||
};
|
||||
|
||||
|
||||
struct BakedTextures: public LLDictionary<EBakedTextureIndex, BakedEntry>
|
||||
{
|
||||
BakedTextures();
|
||||
@@ -221,14 +217,13 @@ public:
|
||||
|
||||
// find a baked texture index based on its name
|
||||
static EBakedTextureIndex findBakedByRegionName(std::string name);
|
||||
|
||||
static const LLUUID getDefaultTextureImageID(ETextureIndex index);
|
||||
static EBakedTextureIndex findBakedByImageName(std::string name);
|
||||
|
||||
// Given a texture entry, determine which wearable type owns it.
|
||||
static LLWearableType::EType getTEWearableType(ETextureIndex index);
|
||||
|
||||
}; // End LLVOAvatarDictionary
|
||||
}; // End LLAvatarAppearanceDictionary
|
||||
|
||||
} // End namespace LLVOAvatarDefines
|
||||
} // End namespace LLAvatarAppearanceDefines
|
||||
|
||||
#endif
|
||||
#endif //LL_AVATARAPPEARANCE_DEFINES_H
|
||||
326
indra/llappearance/llavatarjoint.cpp
Normal file
326
indra/llappearance/llavatarjoint.cpp
Normal file
@@ -0,0 +1,326 @@
|
||||
/**
|
||||
* @file llavatarjoint.cpp
|
||||
* @brief Implementation of LLAvatarJoint class
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Header Files
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "llavatarjoint.h"
|
||||
|
||||
#include "llgl.h"
|
||||
#include "llrender.h"
|
||||
#include "llmath.h"
|
||||
#include "llglheaders.h"
|
||||
#include "llavatarappearance.h"
|
||||
|
||||
const F32 DEFAULT_AVATAR_JOINT_LOD = 0.0f;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Static Data
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL LLAvatarJoint::sDisableLOD = FALSE;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLAvatarJoint()
|
||||
// Class Constructors
|
||||
//-----------------------------------------------------------------------------
|
||||
LLAvatarJoint::LLAvatarJoint() :
|
||||
LLJoint()
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
LLAvatarJoint::LLAvatarJoint(const std::string &name, LLJoint *parent) :
|
||||
LLJoint(name, parent)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
LLAvatarJoint::LLAvatarJoint(S32 joint_num) :
|
||||
LLJoint(joint_num)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
void LLAvatarJoint::init()
|
||||
{
|
||||
mValid = FALSE;
|
||||
mComponents = SC_JOINT | SC_BONE | SC_AXES;
|
||||
mMinPixelArea = DEFAULT_AVATAR_JOINT_LOD;
|
||||
mPickName = PN_DEFAULT;
|
||||
mVisible = TRUE;
|
||||
mMeshID = 0;
|
||||
mIsTransparent = FALSE;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ~LLAvatarJoint()
|
||||
// Class Destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
LLAvatarJoint::~LLAvatarJoint()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// setValid()
|
||||
//--------------------------------------------------------------------
|
||||
void LLAvatarJoint::setValid( BOOL valid, BOOL recursive )
|
||||
{
|
||||
//----------------------------------------------------------------
|
||||
// set visibility for this joint
|
||||
//----------------------------------------------------------------
|
||||
mValid = valid;
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// set visibility for children
|
||||
//----------------------------------------------------------------
|
||||
if (recursive)
|
||||
{
|
||||
for (child_list_t::iterator iter = mChildren.begin();
|
||||
iter != mChildren.end(); ++iter)
|
||||
{
|
||||
LLAvatarJoint* joint = (LLAvatarJoint*)(*iter);
|
||||
joint->setValid(valid, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// setSkeletonComponents()
|
||||
//--------------------------------------------------------------------
|
||||
void LLAvatarJoint::setSkeletonComponents( U32 comp, BOOL recursive )
|
||||
{
|
||||
mComponents = comp;
|
||||
if (recursive)
|
||||
{
|
||||
for (child_list_t::iterator iter = mChildren.begin();
|
||||
iter != mChildren.end(); ++iter)
|
||||
{
|
||||
LLAvatarJoint* joint = dynamic_cast<LLAvatarJoint*>(*iter);
|
||||
joint->setSkeletonComponents(comp, recursive);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLAvatarJoint::setVisible(BOOL visible, BOOL recursive)
|
||||
{
|
||||
mVisible = visible;
|
||||
|
||||
if (recursive)
|
||||
{
|
||||
for (child_list_t::iterator iter = mChildren.begin();
|
||||
iter != mChildren.end(); ++iter)
|
||||
{
|
||||
LLAvatarJoint* joint = (LLAvatarJoint*)(*iter);
|
||||
joint->setVisible(visible, recursive);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLAvatarJoint::updateFaceSizes(U32 &num_vertices, U32& num_indices, F32 pixel_area)
|
||||
{
|
||||
for (child_list_t::iterator iter = mChildren.begin();
|
||||
iter != mChildren.end(); ++iter)
|
||||
{
|
||||
LLAvatarJoint* joint = dynamic_cast<LLAvatarJoint*>(*iter);
|
||||
joint->updateFaceSizes(num_vertices, num_indices, pixel_area);
|
||||
}
|
||||
}
|
||||
|
||||
void LLAvatarJoint::updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_wind, bool terse_update)
|
||||
{
|
||||
for (child_list_t::iterator iter = mChildren.begin();
|
||||
iter != mChildren.end(); ++iter)
|
||||
{
|
||||
LLAvatarJoint* joint = dynamic_cast<LLAvatarJoint*>(*iter);
|
||||
joint->updateFaceData(face, pixel_area, damp_wind, terse_update);
|
||||
}
|
||||
}
|
||||
|
||||
void LLAvatarJoint::updateJointGeometry()
|
||||
{
|
||||
for (child_list_t::iterator iter = mChildren.begin();
|
||||
iter != mChildren.end(); ++iter)
|
||||
{
|
||||
LLAvatarJoint* joint = dynamic_cast<LLAvatarJoint*>(*iter);
|
||||
joint->updateJointGeometry();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BOOL LLAvatarJoint::updateLOD(F32 pixel_area, BOOL activate)
|
||||
{
|
||||
BOOL lod_changed = FALSE;
|
||||
BOOL found_lod = FALSE;
|
||||
|
||||
for (child_list_t::iterator iter = mChildren.begin();
|
||||
iter != mChildren.end(); ++iter)
|
||||
{
|
||||
LLAvatarJoint* joint = dynamic_cast<LLAvatarJoint*>(*iter);
|
||||
F32 jointLOD = joint->getLOD();
|
||||
|
||||
if (found_lod || jointLOD == DEFAULT_AVATAR_JOINT_LOD)
|
||||
{
|
||||
// we've already found a joint to enable, so enable the rest as alternatives
|
||||
lod_changed |= joint->updateLOD(pixel_area, TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pixel_area >= jointLOD || sDisableLOD)
|
||||
{
|
||||
lod_changed |= joint->updateLOD(pixel_area, TRUE);
|
||||
found_lod = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
lod_changed |= joint->updateLOD(pixel_area, FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
return lod_changed;
|
||||
}
|
||||
|
||||
void LLAvatarJoint::dump()
|
||||
{
|
||||
for (child_list_t::iterator iter = mChildren.begin();
|
||||
iter != mChildren.end(); ++iter)
|
||||
{
|
||||
LLAvatarJoint* joint = dynamic_cast<LLAvatarJoint*>(*iter);
|
||||
joint->dump();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LLAvatarJoint::setMeshesToChildren()
|
||||
{
|
||||
removeAllChildren();
|
||||
for (avatar_joint_mesh_list_t::iterator iter = mMeshParts.begin();
|
||||
iter != mMeshParts.end(); iter++)
|
||||
{
|
||||
addChild((*iter));
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLAvatarJointCollisionVolume()
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
LLAvatarJointCollisionVolume::LLAvatarJointCollisionVolume()
|
||||
{
|
||||
mUpdateXform = FALSE;
|
||||
}
|
||||
|
||||
/*virtual*/
|
||||
U32 LLAvatarJointCollisionVolume::render( F32 pixelArea, BOOL first_pass, BOOL is_dummy )
|
||||
{
|
||||
llerrs << "Cannot call render() on LLAvatarJointCollisionVolume" << llendl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
LLVector3 LLAvatarJointCollisionVolume::getVolumePos(LLVector3 &offset)
|
||||
{
|
||||
mUpdateXform = TRUE;
|
||||
|
||||
LLVector3 result = offset;
|
||||
result.scaleVec(getScale());
|
||||
result.rotVec(getWorldRotation());
|
||||
result += getWorldPosition();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void LLAvatarJointCollisionVolume::renderCollision()
|
||||
{
|
||||
updateWorldMatrix();
|
||||
|
||||
gGL.pushMatrix();
|
||||
gGL.multMatrix( &mXform.getWorldMatrix().mMatrix[0][0] );
|
||||
|
||||
gGL.diffuseColor3f( 0.f, 0.f, 1.f );
|
||||
|
||||
gGL.begin(LLRender::LINES);
|
||||
|
||||
LLVector3 v[] =
|
||||
{
|
||||
LLVector3(1,0,0),
|
||||
LLVector3(-1,0,0),
|
||||
LLVector3(0,1,0),
|
||||
LLVector3(0,-1,0),
|
||||
|
||||
LLVector3(0,0,-1),
|
||||
LLVector3(0,0,1),
|
||||
};
|
||||
|
||||
//sides
|
||||
gGL.vertex3fv(v[0].mV);
|
||||
gGL.vertex3fv(v[2].mV);
|
||||
|
||||
gGL.vertex3fv(v[0].mV);
|
||||
gGL.vertex3fv(v[3].mV);
|
||||
|
||||
gGL.vertex3fv(v[1].mV);
|
||||
gGL.vertex3fv(v[2].mV);
|
||||
|
||||
gGL.vertex3fv(v[1].mV);
|
||||
gGL.vertex3fv(v[3].mV);
|
||||
|
||||
|
||||
//top
|
||||
gGL.vertex3fv(v[0].mV);
|
||||
gGL.vertex3fv(v[4].mV);
|
||||
|
||||
gGL.vertex3fv(v[1].mV);
|
||||
gGL.vertex3fv(v[4].mV);
|
||||
|
||||
gGL.vertex3fv(v[2].mV);
|
||||
gGL.vertex3fv(v[4].mV);
|
||||
|
||||
gGL.vertex3fv(v[3].mV);
|
||||
gGL.vertex3fv(v[4].mV);
|
||||
|
||||
|
||||
//bottom
|
||||
gGL.vertex3fv(v[0].mV);
|
||||
gGL.vertex3fv(v[5].mV);
|
||||
|
||||
gGL.vertex3fv(v[1].mV);
|
||||
gGL.vertex3fv(v[5].mV);
|
||||
|
||||
gGL.vertex3fv(v[2].mV);
|
||||
gGL.vertex3fv(v[5].mV);
|
||||
|
||||
gGL.vertex3fv(v[3].mV);
|
||||
gGL.vertex3fv(v[5].mV);
|
||||
|
||||
gGL.end();
|
||||
|
||||
gGL.popMatrix();
|
||||
}
|
||||
|
||||
|
||||
// End
|
||||
140
indra/llappearance/llavatarjoint.h
Normal file
140
indra/llappearance/llavatarjoint.h
Normal file
@@ -0,0 +1,140 @@
|
||||
/**
|
||||
* @file llavatarjoint.h
|
||||
* @brief Implementation of LLAvatarJoint class
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLAVATARJOINT_H
|
||||
#define LL_LLAVATARJOINT_H
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Header Files
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "lljoint.h"
|
||||
#include "lljointpickname.h"
|
||||
|
||||
class LLFace;
|
||||
class LLAvatarJointMesh;
|
||||
|
||||
extern const F32 DEFAULT_AVATAR_JOINT_LOD;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// class LLViewerJoint
|
||||
//-----------------------------------------------------------------------------
|
||||
class LLAvatarJoint :
|
||||
public LLJoint
|
||||
{
|
||||
public:
|
||||
LLAvatarJoint();
|
||||
LLAvatarJoint(S32 joint_num);
|
||||
// *TODO: Only used for LLVOAvatarSelf::mScreenp. *DOES NOT INITIALIZE mResetAfterRestoreOldXform*
|
||||
LLAvatarJoint(const std::string &name, LLJoint *parent = NULL);
|
||||
virtual ~LLAvatarJoint();
|
||||
|
||||
// Gets the validity of this joint
|
||||
BOOL getValid() { return mValid; }
|
||||
|
||||
// Sets the validity of this joint
|
||||
virtual void setValid( BOOL valid, BOOL recursive=FALSE );
|
||||
|
||||
// Returns true if this object is transparent.
|
||||
// This is used to determine in which order to draw objects.
|
||||
virtual BOOL isTransparent() { return mIsTransparent; }
|
||||
|
||||
// Returns true if this object should inherit scale modifiers from its immediate parent
|
||||
virtual BOOL inheritScale() { return FALSE; }
|
||||
|
||||
enum Components
|
||||
{
|
||||
SC_BONE = 1,
|
||||
SC_JOINT = 2,
|
||||
SC_AXES = 4
|
||||
};
|
||||
|
||||
// Selects which skeleton components to draw
|
||||
void setSkeletonComponents( U32 comp, BOOL recursive = TRUE );
|
||||
|
||||
// Returns which skeleton components are enables for drawing
|
||||
U32 getSkeletonComponents() { return mComponents; }
|
||||
|
||||
// Sets the level of detail for this node as a minimum
|
||||
// pixel area threshold. If the current pixel area for this
|
||||
// object is less than the specified threshold, the node is
|
||||
// not traversed. In addition, if a value is specified (not
|
||||
// default of 0.0), and the pixel area is larger than the
|
||||
// specified minimum, the node is rendered, but no other siblings
|
||||
// of this node under the same parent will be.
|
||||
F32 getLOD() { return mMinPixelArea; }
|
||||
void setLOD( F32 pixelArea ) { mMinPixelArea = pixelArea; }
|
||||
|
||||
void setPickName(LLJointPickName name) { mPickName = name; }
|
||||
LLJointPickName getPickName() { return mPickName; }
|
||||
|
||||
void setVisible( BOOL visible, BOOL recursive );
|
||||
|
||||
// Takes meshes in mMeshParts and sets each one as a child joint
|
||||
void setMeshesToChildren();
|
||||
|
||||
// LLViewerJoint interface
|
||||
virtual U32 render( F32 pixelArea, BOOL first_pass = TRUE, BOOL is_dummy = FALSE ) = 0;
|
||||
virtual void updateFaceSizes(U32 &num_vertices, U32& num_indices, F32 pixel_area);
|
||||
virtual void updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_wind = FALSE, bool terse_update = false);
|
||||
virtual BOOL updateLOD(F32 pixel_area, BOOL activate);
|
||||
virtual void updateJointGeometry();
|
||||
virtual void dump();
|
||||
|
||||
|
||||
public:
|
||||
static BOOL sDisableLOD;
|
||||
avatar_joint_mesh_list_t mMeshParts; //LLViewerJointMesh*
|
||||
void setMeshID( S32 id ) {mMeshID = id;}
|
||||
|
||||
protected:
|
||||
void init();
|
||||
|
||||
BOOL mValid;
|
||||
BOOL mIsTransparent;
|
||||
U32 mComponents;
|
||||
F32 mMinPixelArea;
|
||||
LLJointPickName mPickName;
|
||||
BOOL mVisible;
|
||||
S32 mMeshID;
|
||||
};
|
||||
|
||||
class LLAvatarJointCollisionVolume : public LLAvatarJoint
|
||||
{
|
||||
public:
|
||||
LLAvatarJointCollisionVolume();
|
||||
virtual ~LLAvatarJointCollisionVolume() {};
|
||||
|
||||
/*virtual*/ BOOL inheritScale() { return TRUE; }
|
||||
/*virtual*/ U32 render( F32 pixelArea, BOOL first_pass = TRUE, BOOL is_dummy = FALSE );
|
||||
|
||||
void renderCollision();
|
||||
|
||||
LLVector3 getVolumePos(LLVector3 &offset);
|
||||
};
|
||||
|
||||
#endif // LL_LLAVATARJOINT_H
|
||||
|
||||
|
||||
375
indra/llappearance/llavatarjointmesh.cpp
Normal file
375
indra/llappearance/llavatarjointmesh.cpp
Normal file
@@ -0,0 +1,375 @@
|
||||
/**
|
||||
* @file LLAvatarJointMesh.cpp
|
||||
* @brief Implementation of LLAvatarJointMesh class
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Header Files
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "linden_common.h"
|
||||
#include "imageids.h"
|
||||
#include "llfasttimer.h"
|
||||
#include "llrender.h"
|
||||
|
||||
#include "llavatarjointmesh.h"
|
||||
#include "llavatarappearance.h"
|
||||
//#include "llapr.h"
|
||||
//#include "llbox.h"
|
||||
//#include "lldrawable.h"
|
||||
//#include "lldrawpoolavatar.h"
|
||||
//#include "lldrawpoolbump.h"
|
||||
//#include "lldynamictexture.h"
|
||||
//#include "llface.h"
|
||||
//#include "llgldbg.h"
|
||||
//#include "llglheaders.h"
|
||||
#include "lltexlayer.h"
|
||||
//#include "llviewercamera.h"
|
||||
//#include "llviewercontrol.h"
|
||||
//#include "llviewertexturelist.h"
|
||||
//#include "llsky.h"
|
||||
//#include "pipeline.h"
|
||||
//#include "llviewershadermgr.h"
|
||||
#include "llmath.h"
|
||||
#include "v4math.h"
|
||||
#include "m3math.h"
|
||||
#include "m4math.h"
|
||||
#include "llmatrix4a.h"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLAvatarJointMesh::LLSkinJoint
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLSkinJoint
|
||||
//-----------------------------------------------------------------------------
|
||||
LLSkinJoint::LLSkinJoint()
|
||||
{
|
||||
mJoint = NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ~LLSkinJoint
|
||||
//-----------------------------------------------------------------------------
|
||||
LLSkinJoint::~LLSkinJoint()
|
||||
{
|
||||
mJoint = NULL;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLSkinJoint::setupSkinJoint()
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL LLSkinJoint::setupSkinJoint( LLAvatarJoint *joint)
|
||||
{
|
||||
// find the named joint
|
||||
mJoint = joint;
|
||||
if ( !mJoint )
|
||||
{
|
||||
llinfos << "Can't find joint" << llendl;
|
||||
}
|
||||
|
||||
// compute the inverse root skin matrix
|
||||
mRootToJointSkinOffset.clearVec();
|
||||
|
||||
LLVector3 rootSkinOffset;
|
||||
while (joint)
|
||||
{
|
||||
rootSkinOffset += joint->getSkinOffset();
|
||||
joint = (LLAvatarJoint*)joint->getParent();
|
||||
}
|
||||
|
||||
mRootToJointSkinOffset = -rootSkinOffset;
|
||||
mRootToParentJointSkinOffset = mRootToJointSkinOffset;
|
||||
mRootToParentJointSkinOffset += mJoint->getSkinOffset();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLAvatarJointMesh
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
BOOL LLAvatarJointMesh::sPipelineRender = FALSE;
|
||||
EAvatarRenderPass LLAvatarJointMesh::sRenderPass = AVATAR_RENDER_PASS_SINGLE;
|
||||
U32 LLAvatarJointMesh::sClothingMaskImageName = 0;
|
||||
LLColor4 LLAvatarJointMesh::sClothingInnerColor;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLAvatarJointMesh()
|
||||
//-----------------------------------------------------------------------------
|
||||
LLAvatarJointMesh::LLAvatarJointMesh()
|
||||
:
|
||||
mTexture( NULL ),
|
||||
mLayerSet( NULL ),
|
||||
mTestImageName( 0 ),
|
||||
mFaceIndexCount(0)
|
||||
{
|
||||
|
||||
mColor[0] = 1.0f;
|
||||
mColor[1] = 1.0f;
|
||||
mColor[2] = 1.0f;
|
||||
mColor[3] = 1.0f;
|
||||
mShiny = 0.0f;
|
||||
mCullBackFaces = TRUE;
|
||||
|
||||
mMesh = NULL;
|
||||
|
||||
mNumSkinJoints = 0;
|
||||
mSkinJoints = NULL;
|
||||
|
||||
mFace = NULL;
|
||||
|
||||
mMeshID = 0;
|
||||
mUpdateXform = FALSE;
|
||||
|
||||
mValid = FALSE;
|
||||
|
||||
mIsTransparent = FALSE;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ~LLAvatarJointMesh()
|
||||
// Class Destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
LLAvatarJointMesh::~LLAvatarJointMesh()
|
||||
{
|
||||
mMesh = NULL;
|
||||
mTexture = NULL;
|
||||
freeSkinData();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLAvatarJointMesh::allocateSkinData()
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL LLAvatarJointMesh::allocateSkinData( U32 numSkinJoints )
|
||||
{
|
||||
mSkinJoints = new LLSkinJoint[ numSkinJoints ];
|
||||
mNumSkinJoints = numSkinJoints;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLAvatarJointMesh::freeSkinData()
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLAvatarJointMesh::freeSkinData()
|
||||
{
|
||||
mNumSkinJoints = 0;
|
||||
delete [] mSkinJoints;
|
||||
mSkinJoints = NULL;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// LLAvatarJointMesh::getColor()
|
||||
//--------------------------------------------------------------------
|
||||
void LLAvatarJointMesh::getColor( F32 *red, F32 *green, F32 *blue, F32 *alpha )
|
||||
{
|
||||
*red = mColor[0];
|
||||
*green = mColor[1];
|
||||
*blue = mColor[2];
|
||||
*alpha = mColor[3];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// LLAvatarJointMesh::setColor()
|
||||
//--------------------------------------------------------------------
|
||||
void LLAvatarJointMesh::setColor( F32 red, F32 green, F32 blue, F32 alpha )
|
||||
{
|
||||
mColor[0] = red;
|
||||
mColor[1] = green;
|
||||
mColor[2] = blue;
|
||||
mColor[3] = alpha;
|
||||
}
|
||||
|
||||
void LLAvatarJointMesh::setColor( const LLColor4& color )
|
||||
{
|
||||
mColor = color;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// LLAvatarJointMesh::getTexture()
|
||||
//--------------------------------------------------------------------
|
||||
//LLViewerTexture *LLAvatarJointMesh::getTexture()
|
||||
//{
|
||||
// return mTexture;
|
||||
//}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// LLAvatarJointMesh::setTexture()
|
||||
//--------------------------------------------------------------------
|
||||
void LLAvatarJointMesh::setTexture( LLGLTexture *texture )
|
||||
{
|
||||
mTexture = texture;
|
||||
|
||||
// texture and dynamic_texture are mutually exclusive
|
||||
if( texture )
|
||||
{
|
||||
mLayerSet = NULL;
|
||||
//texture->bindTexture(0);
|
||||
//texture->setClamp(TRUE, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BOOL LLAvatarJointMesh::hasGLTexture() const
|
||||
{
|
||||
return mTexture.notNull() && mTexture->hasGLTexture();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// LLAvatarJointMesh::setLayerSet()
|
||||
// Sets the shape texture (takes precedence over normal texture)
|
||||
//--------------------------------------------------------------------
|
||||
void LLAvatarJointMesh::setLayerSet( LLTexLayerSet* layer_set )
|
||||
{
|
||||
mLayerSet = layer_set;
|
||||
|
||||
// texture and dynamic_texture are mutually exclusive
|
||||
if( layer_set )
|
||||
{
|
||||
mTexture = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL LLAvatarJointMesh::hasComposite() const
|
||||
{
|
||||
return (mLayerSet && mLayerSet->hasComposite());
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// LLAvatarJointMesh::getMesh()
|
||||
//--------------------------------------------------------------------
|
||||
LLPolyMesh *LLAvatarJointMesh::getMesh()
|
||||
{
|
||||
return mMesh;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLAvatarJointMesh::setMesh()
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLAvatarJointMesh::setMesh( LLPolyMesh *mesh )
|
||||
{
|
||||
// set the mesh pointer
|
||||
mMesh = mesh;
|
||||
|
||||
// release any existing skin joints
|
||||
freeSkinData();
|
||||
|
||||
if ( mMesh == NULL )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// acquire the transform from the mesh object
|
||||
setPosition( mMesh->getPosition() );
|
||||
setRotation( mMesh->getRotation() );
|
||||
setScale( mMesh->getScale() );
|
||||
|
||||
// create skin joints if necessary
|
||||
if ( mMesh->hasWeights() && !mMesh->isLOD())
|
||||
{
|
||||
U32 numJointNames = mMesh->getNumJointNames();
|
||||
|
||||
allocateSkinData( numJointNames );
|
||||
std::string *jointNames = mMesh->getJointNames();
|
||||
|
||||
U32 jn;
|
||||
for (jn = 0; jn < numJointNames; jn++)
|
||||
{
|
||||
//llinfos << "Setting up joint " << jointNames[jn] << llendl;
|
||||
LLAvatarJoint* joint = (LLAvatarJoint*)(getRoot()->findJoint(jointNames[jn]) );
|
||||
mSkinJoints[jn].setupSkinJoint( joint );
|
||||
}
|
||||
}
|
||||
|
||||
// setup joint array
|
||||
if (!mMesh->isLOD())
|
||||
{
|
||||
setupJoint((LLAvatarJoint*)getRoot());
|
||||
}
|
||||
|
||||
// llinfos << "joint render entries: " << mMesh->mJointRenderData.count() << llendl;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// setupJoint()
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLAvatarJointMesh::setupJoint(LLAvatarJoint* current_joint)
|
||||
{
|
||||
// llinfos << "Mesh: " << getName() << llendl;
|
||||
|
||||
// S32 joint_count = 0;
|
||||
U32 sj;
|
||||
for (sj=0; sj<mNumSkinJoints; sj++)
|
||||
{
|
||||
LLSkinJoint &js = mSkinJoints[sj];
|
||||
|
||||
if (js.mJoint != current_joint)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// we've found a skinjoint for this joint..
|
||||
|
||||
// is the last joint in the array our parent?
|
||||
if(mMesh->mJointRenderData.count() && mMesh->mJointRenderData[mMesh->mJointRenderData.count() - 1]->mWorldMatrix == ¤t_joint->getParent()->getWorldMatrix())
|
||||
{
|
||||
// ...then just add ourselves
|
||||
LLAvatarJoint* jointp = js.mJoint;
|
||||
mMesh->mJointRenderData.put(new LLJointRenderData(&jointp->getWorldMatrix(), &js));
|
||||
// llinfos << "joint " << joint_count << js.mJoint->getName() << llendl;
|
||||
// joint_count++;
|
||||
}
|
||||
// otherwise add our parent and ourselves
|
||||
else
|
||||
{
|
||||
mMesh->mJointRenderData.put(new LLJointRenderData(¤t_joint->getParent()->getWorldMatrix(), NULL));
|
||||
// llinfos << "joint " << joint_count << current_joint->getParent()->getName() << llendl;
|
||||
// joint_count++;
|
||||
mMesh->mJointRenderData.put(new LLJointRenderData(¤t_joint->getWorldMatrix(), &js));
|
||||
// llinfos << "joint " << joint_count << current_joint->getName() << llendl;
|
||||
// joint_count++;
|
||||
}
|
||||
}
|
||||
|
||||
// depth-first traversal
|
||||
for (LLJoint::child_list_t::iterator iter = current_joint->mChildren.begin();
|
||||
iter != current_joint->mChildren.end(); ++iter)
|
||||
{
|
||||
LLAvatarJoint* child_joint = (LLAvatarJoint*)(*iter);
|
||||
setupJoint(child_joint);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// End
|
||||
142
indra/llappearance/llavatarjointmesh.h
Normal file
142
indra/llappearance/llavatarjointmesh.h
Normal file
@@ -0,0 +1,142 @@
|
||||
/**
|
||||
* @file llavatarjointmesh.h
|
||||
* @brief Declaration of LLAvatarJointMesh class
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLAVATARJOINTMESH_H
|
||||
#define LL_LLAVATARJOINTMESH_H
|
||||
|
||||
#include "llavatarjoint.h"
|
||||
#include "llgltexture.h"
|
||||
#include "llpolymesh.h"
|
||||
#include "v4color.h"
|
||||
|
||||
class LLDrawable;
|
||||
class LLFace;
|
||||
class LLCharacter;
|
||||
class LLTexLayerSet;
|
||||
|
||||
typedef enum e_avatar_render_pass
|
||||
{
|
||||
AVATAR_RENDER_PASS_SINGLE,
|
||||
AVATAR_RENDER_PASS_CLOTHING_INNER,
|
||||
AVATAR_RENDER_PASS_CLOTHING_OUTER
|
||||
} EAvatarRenderPass;
|
||||
|
||||
class LLSkinJoint
|
||||
{
|
||||
public:
|
||||
LLSkinJoint();
|
||||
~LLSkinJoint();
|
||||
BOOL setupSkinJoint( LLAvatarJoint *joint);
|
||||
|
||||
LLAvatarJoint *mJoint;
|
||||
LLVector3 mRootToJointSkinOffset;
|
||||
LLVector3 mRootToParentJointSkinOffset;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// class LLViewerJointMesh
|
||||
//-----------------------------------------------------------------------------
|
||||
class LLAvatarJointMesh : public virtual LLAvatarJoint
|
||||
{
|
||||
protected:
|
||||
LLColor4 mColor; // color value
|
||||
// LLColor4 mSpecular; // specular color (always white for now)
|
||||
F32 mShiny; // shiny value
|
||||
LLPointer<LLGLTexture> mTexture; // ptr to a global texture
|
||||
LLTexLayerSet* mLayerSet; // ptr to a layer set owned by the avatar
|
||||
U32 mTestImageName; // handle to a temporary texture for previewing uploads
|
||||
LLPolyMesh* mMesh; // ptr to a global polymesh
|
||||
BOOL mCullBackFaces; // true by default
|
||||
LLFace* mFace; // ptr to a face w/ AGP copy of mesh
|
||||
|
||||
U32 mFaceIndexCount;
|
||||
|
||||
U32 mNumSkinJoints;
|
||||
LLSkinJoint* mSkinJoints;
|
||||
S32 mMeshID;
|
||||
|
||||
public:
|
||||
static BOOL sPipelineRender;
|
||||
//RN: this is here for testing purposes
|
||||
static U32 sClothingMaskImageName;
|
||||
static EAvatarRenderPass sRenderPass;
|
||||
static LLColor4 sClothingInnerColor;
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
LLAvatarJointMesh();
|
||||
|
||||
// Destructor
|
||||
virtual ~LLAvatarJointMesh();
|
||||
|
||||
// Gets the shape color
|
||||
void getColor( F32 *red, F32 *green, F32 *blue, F32 *alpha );
|
||||
|
||||
// Sets the shape color
|
||||
void setColor( F32 red, F32 green, F32 blue, F32 alpha );
|
||||
void setColor( const LLColor4& color );
|
||||
|
||||
// Sets the shininess
|
||||
void setSpecular( const LLColor4& color, F32 shiny ) { /*mSpecular = color;*/ mShiny = shiny; };
|
||||
|
||||
// Sets the shape texture
|
||||
void setTexture( LLGLTexture *texture );
|
||||
|
||||
BOOL hasGLTexture() const;
|
||||
|
||||
void setTestTexture( U32 name ) { mTestImageName = name; }
|
||||
|
||||
// Sets layer set responsible for a dynamic shape texture (takes precedence over normal texture)
|
||||
void setLayerSet( LLTexLayerSet* layer_set );
|
||||
|
||||
BOOL hasComposite() const;
|
||||
|
||||
// Gets the poly mesh
|
||||
LLPolyMesh *getMesh();
|
||||
|
||||
// Sets the poly mesh
|
||||
void setMesh( LLPolyMesh *mesh );
|
||||
|
||||
// Sets up joint matrix data for rendering
|
||||
void setupJoint(LLAvatarJoint* current_joint);
|
||||
|
||||
// Sets ID for picking
|
||||
void setMeshID( S32 id ) {mMeshID = id;}
|
||||
|
||||
// Gets ID for picking
|
||||
S32 getMeshID() { return mMeshID; }
|
||||
|
||||
void setIsTransparent(BOOL is_transparent) { mIsTransparent = is_transparent; }
|
||||
|
||||
private:
|
||||
// Allocate skin data
|
||||
BOOL allocateSkinData( U32 numSkinJoints );
|
||||
|
||||
// Free skin data
|
||||
void freeSkinData();
|
||||
};
|
||||
|
||||
#endif // LL_LLAVATARJOINTMESH_H
|
||||
@@ -24,22 +24,20 @@
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "lldriverparam.h"
|
||||
|
||||
#include "llfasttimer.h"
|
||||
#include "llvoavatar.h"
|
||||
#include "llvoavatarself.h"
|
||||
#include "llagent.h"
|
||||
#include "llavatarappearance.h"
|
||||
#include "llwearable.h"
|
||||
#include "llagentwearables.h"
|
||||
#include "llwearabledata.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLDriverParamInfo
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
LLDriverParamInfo::LLDriverParamInfo()
|
||||
LLDriverParamInfo::LLDriverParamInfo() :
|
||||
mDriverParam(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -112,12 +110,14 @@ void LLDriverParamInfo::toStream(std::ostream &out)
|
||||
|
||||
out << std::endl;
|
||||
|
||||
if(isAgentAvatarValid())
|
||||
if(mDriverParam && mDriverParam->getAvatarAppearance()->isSelf() &&
|
||||
mDriverParam->getAvatarAppearance()->isValid())
|
||||
{
|
||||
for (entry_info_list_t::iterator iter = mDrivenInfoList.begin(); iter != mDrivenInfoList.end(); iter++)
|
||||
{
|
||||
LLDrivenEntryInfo driven = *iter;
|
||||
LLViewerVisualParam *param = (LLViewerVisualParam*)gAgentAvatarp->getVisualParam(driven.mDrivenID);
|
||||
LLViewerVisualParam *param =
|
||||
(LLViewerVisualParam*)mDriverParam->getAvatarAppearance()->getVisualParam(driven.mDrivenID);
|
||||
if (param)
|
||||
{
|
||||
param->getInfo()->toStream(out);
|
||||
@@ -139,7 +139,9 @@ void LLDriverParamInfo::toStream(std::ostream &out)
|
||||
}
|
||||
else
|
||||
{
|
||||
llwarns << "could not get parameter " << driven.mDrivenID << " from avatar " << gAgentAvatarp.get() << " for driver parameter " << getID() << llendl;
|
||||
llwarns << "could not get parameter " << driven.mDrivenID << " from avatar "
|
||||
<< mDriverParam->getAvatarAppearance()
|
||||
<< " for driver parameter " << getID() << llendl;
|
||||
}
|
||||
out << std::endl;
|
||||
}
|
||||
@@ -150,19 +152,16 @@ void LLDriverParamInfo::toStream(std::ostream &out)
|
||||
// LLDriverParam
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
LLDriverParam::LLDriverParam(LLVOAvatar *avatarp) :
|
||||
LLDriverParam::LLDriverParam(LLAvatarAppearance *appearance, LLWearable* wearable /* = NULL */) :
|
||||
mCurrentDistortionParam( NULL ),
|
||||
mAvatarp(avatarp),
|
||||
mWearablep(NULL)
|
||||
{
|
||||
mDefaultVec.clear();
|
||||
}
|
||||
|
||||
LLDriverParam::LLDriverParam(LLWearable *wearablep) :
|
||||
mCurrentDistortionParam( NULL ),
|
||||
mAvatarp(NULL),
|
||||
mWearablep(wearablep)
|
||||
mAvatarAppearance(appearance),
|
||||
mWearablep(wearable)
|
||||
{
|
||||
llassert(mAvatarAppearance);
|
||||
if (mWearablep)
|
||||
{
|
||||
llassert(mAvatarAppearance->isSelf());
|
||||
}
|
||||
mDefaultVec.clear();
|
||||
}
|
||||
|
||||
@@ -177,49 +176,22 @@ BOOL LLDriverParam::setInfo(LLDriverParamInfo *info)
|
||||
return FALSE;
|
||||
mInfo = info;
|
||||
mID = info->mID;
|
||||
info->mDriverParam = this;
|
||||
|
||||
setWeight(getDefaultWeight(), FALSE );
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void LLDriverParam::setWearable(LLWearable *wearablep)
|
||||
{
|
||||
if (wearablep)
|
||||
{
|
||||
mWearablep = wearablep;
|
||||
mAvatarp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void LLDriverParam::setAvatar(LLVOAvatar *avatarp)
|
||||
{
|
||||
if (avatarp)
|
||||
{
|
||||
mWearablep = NULL;
|
||||
mAvatarp = avatarp;
|
||||
}
|
||||
}
|
||||
|
||||
/*virtual*/ LLViewerVisualParam* LLDriverParam::cloneParam(LLWearable* wearable) const
|
||||
{
|
||||
LLDriverParam *new_param;
|
||||
if (wearable)
|
||||
{
|
||||
new_param = new LLDriverParam(wearable);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mWearablep)
|
||||
{
|
||||
new_param = new LLDriverParam(mWearablep);
|
||||
}
|
||||
else
|
||||
{
|
||||
new_param = new LLDriverParam(mAvatarp);
|
||||
}
|
||||
}
|
||||
llassert(wearable);
|
||||
LLDriverParam *new_param = new LLDriverParam(mAvatarAppearance, wearable);
|
||||
// FIXME DRANO this clobbers mWearablep, which means any code
|
||||
// currently using mWearablep is wrong, or at least untested.
|
||||
*new_param = *this;
|
||||
//new_param->mWearablep = wearable;
|
||||
// new_param->mDriven.clear(); // clear driven list to avoid overwriting avatar driven params from wearables.
|
||||
return new_param;
|
||||
}
|
||||
|
||||
@@ -456,6 +428,20 @@ const LLVector4a* LLDriverParam::getNextDistortion(U32 *index, LLPolyMesh **poly
|
||||
return v;
|
||||
};
|
||||
|
||||
S32 LLDriverParam::getDrivenParamsCount() const
|
||||
{
|
||||
return mDriven.size();
|
||||
}
|
||||
|
||||
const LLViewerVisualParam* LLDriverParam::getDrivenParam(S32 index) const
|
||||
{
|
||||
if (0 > index || index >= (S32)mDriven.size())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return mDriven[index].mParam;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// setAnimationTarget()
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -511,6 +497,7 @@ BOOL LLDriverParam::linkDrivenParams(visual_param_mapper mapper, BOOL only_cross
|
||||
if (!found)
|
||||
{
|
||||
LLViewerVisualParam* param = (LLViewerVisualParam*)mapper(driven_id);
|
||||
if (param) param->setParamLocation(this->getParamLocation());
|
||||
bool push = param && (!only_cross_params || param->getCrossWearable());
|
||||
if (push)
|
||||
{
|
||||
@@ -555,7 +542,7 @@ void LLDriverParam::updateCrossDrivenParams(LLWearableType::EType driven_type)
|
||||
// Thus this wearable needs to get updates from the driver wearable.
|
||||
// The call to setVisualParamWeight seems redundant, but is necessary
|
||||
// as the number of driven wearables has changed since the last update. -Nyx
|
||||
LLWearable *wearable = gAgentWearables.getTopWearable(driver_type);
|
||||
LLWearable *wearable = mAvatarAppearance->getWearableData()->getTopWearable(driver_type);
|
||||
if (wearable)
|
||||
{
|
||||
wearable->setVisualParamWeight(mID, wearable->getVisualParamWeight(mID), false);
|
||||
@@ -623,13 +610,22 @@ F32 LLDriverParam::getDrivenWeight(const LLDrivenEntry* driven, F32 input_weight
|
||||
|
||||
void LLDriverParam::setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight, bool upload_bake)
|
||||
{
|
||||
if(isAgentAvatarValid() &&
|
||||
mWearablep &&
|
||||
driven->mParam->getCrossWearable() &&
|
||||
mWearablep->isOnTop())
|
||||
bool use_self = false;
|
||||
if(mWearablep &&
|
||||
mAvatarAppearance->isValid() &&
|
||||
driven->mParam->getCrossWearable())
|
||||
{
|
||||
LLWearable* wearable = dynamic_cast<LLWearable*> (mWearablep);
|
||||
if (mAvatarAppearance->getWearableData()->isOnTop(wearable))
|
||||
{
|
||||
use_self = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (use_self)
|
||||
{
|
||||
// call setWeight through LLVOAvatarSelf so other wearables can be updated with the correct values
|
||||
gAgentAvatarp->setVisualParamWeight( (LLVisualParam*)driven->mParam, driven_weight, upload_bake );
|
||||
mAvatarAppearance->setVisualParamWeight( (LLVisualParam*)driven->mParam, driven_weight, upload_bake );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -30,8 +30,8 @@
|
||||
#include "llviewervisualparam.h"
|
||||
#include "llwearabletype.h"
|
||||
|
||||
class LLPhysicsMotion;
|
||||
class LLVOAvatar;
|
||||
class LLAvatarAppearance;
|
||||
class LLDriverParam;
|
||||
class LLWearable;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -71,16 +71,19 @@ public:
|
||||
protected:
|
||||
typedef std::deque<LLDrivenEntryInfo> entry_info_list_t;
|
||||
entry_info_list_t mDrivenInfoList;
|
||||
LLDriverParam* mDriverParam; // backpointer
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class LLDriverParam : public LLViewerVisualParam
|
||||
{
|
||||
friend class LLPhysicsMotion; // physics motion needs to access driven params directly.
|
||||
friend class LLPhysicsMotion;
|
||||
private:
|
||||
// Hide the default constructor. Force construction with LLAvatarAppearance.
|
||||
LLDriverParam() {}
|
||||
public:
|
||||
LLDriverParam(LLVOAvatar *avatarp);
|
||||
LLDriverParam(LLWearable *wearablep);
|
||||
LLDriverParam(LLAvatarAppearance *appearance, LLWearable* wearable = NULL);
|
||||
~LLDriverParam();
|
||||
|
||||
void* operator new(size_t size)
|
||||
@@ -98,8 +101,9 @@ public:
|
||||
// This sets mInfo and calls initialization functions
|
||||
BOOL setInfo(LLDriverParamInfo *info);
|
||||
|
||||
void setWearable(LLWearable *wearablep);
|
||||
void setAvatar(LLVOAvatar *avatarp);
|
||||
LLAvatarAppearance* getAvatarAppearance() { return mAvatarAppearance; }
|
||||
const LLAvatarAppearance* getAvatarAppearance() const { return mAvatarAppearance; }
|
||||
|
||||
void updateCrossDrivenParams(LLWearableType::EType driven_type);
|
||||
|
||||
/*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const;
|
||||
@@ -121,6 +125,9 @@ public:
|
||||
/*virtual*/ const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh);
|
||||
/*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh);
|
||||
|
||||
S32 getDrivenParamsCount() const;
|
||||
const LLViewerVisualParam* getDrivenParam(S32 index) const;
|
||||
|
||||
protected:
|
||||
F32 getDrivenWeight(const LLDrivenEntry* driven, F32 input_weight);
|
||||
void setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight, bool upload_bake);
|
||||
@@ -131,7 +138,7 @@ protected:
|
||||
entry_list_t mDriven;
|
||||
LLViewerVisualParam* mCurrentDistortionParam;
|
||||
// Backlink only; don't make this an LLPointer.
|
||||
LLVOAvatar* mAvatarp;
|
||||
LLAvatarAppearance* mAvatarAppearance;
|
||||
LLWearable* mWearablep;
|
||||
};
|
||||
|
||||
49
indra/llappearance/lljointpickname.h
Normal file
49
indra/llappearance/lljointpickname.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* @file lljointpickname.h
|
||||
* @brief Defines OpenGL seleciton stack names
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
|
||||
#ifndef LL_LLJOINTPICKNAME_H
|
||||
#define LL_LLJOINTPICKNAME_H
|
||||
|
||||
class LLAvatarJointMesh;
|
||||
|
||||
// Sets the OpenGL selection stack name that is pushed and popped
|
||||
// with this joint state. The default value indicates that no name
|
||||
// should be pushed/popped.
|
||||
enum LLJointPickName
|
||||
{
|
||||
PN_DEFAULT = -1,
|
||||
PN_0 = 0,
|
||||
PN_1 = 1,
|
||||
PN_2 = 2,
|
||||
PN_3 = 3,
|
||||
PN_4 = 4,
|
||||
PN_5 = 5
|
||||
};
|
||||
|
||||
typedef std::vector<LLAvatarJointMesh*> avatar_joint_mesh_list_t;
|
||||
|
||||
#endif // LL_LLJOINTPICKNAME_H
|
||||
@@ -23,13 +23,14 @@
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "lllocaltextureobject.h"
|
||||
|
||||
#include "llimage.h"
|
||||
#include "llrender.h"
|
||||
#include "lltexlayer.h"
|
||||
#include "llviewertexture.h"
|
||||
#include "lltextureentry.h"
|
||||
#include "llgltexture.h"
|
||||
#include "lluuid.h"
|
||||
#include "llwearable.h"
|
||||
|
||||
@@ -41,7 +42,7 @@ LLLocalTextureObject::LLLocalTextureObject() :
|
||||
mImage = NULL;
|
||||
}
|
||||
|
||||
LLLocalTextureObject::LLLocalTextureObject(LLViewerFetchedTexture* image, const LLUUID& id) :
|
||||
LLLocalTextureObject::LLLocalTextureObject(LLGLTexture* image, const LLUUID& id) :
|
||||
mIsBakedReady(FALSE),
|
||||
mDiscard(MAX_DISCARD_LEVEL+1)
|
||||
{
|
||||
@@ -77,7 +78,7 @@ LLLocalTextureObject::~LLLocalTextureObject()
|
||||
{
|
||||
}
|
||||
|
||||
LLViewerFetchedTexture* LLLocalTextureObject::getImage() const
|
||||
LLGLTexture* LLLocalTextureObject::getImage() const
|
||||
{
|
||||
return mImage;
|
||||
}
|
||||
@@ -126,7 +127,7 @@ BOOL LLLocalTextureObject::getBakedReady() const
|
||||
return mIsBakedReady;
|
||||
}
|
||||
|
||||
void LLLocalTextureObject::setImage(LLViewerFetchedTexture* new_image)
|
||||
void LLLocalTextureObject::setImage(LLGLTexture* new_image)
|
||||
{
|
||||
mImage = new_image;
|
||||
}
|
||||
@@ -29,11 +29,10 @@
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include "llviewertexture.h"
|
||||
#include "llpointer.h"
|
||||
#include "llgltexture.h"
|
||||
|
||||
class LLUUID;
|
||||
class LLTexLayer;
|
||||
class LLTextureEntry;
|
||||
class LLTexLayerTemplate;
|
||||
class LLWearable;
|
||||
|
||||
@@ -44,11 +43,11 @@ class LLLocalTextureObject
|
||||
{
|
||||
public:
|
||||
LLLocalTextureObject();
|
||||
LLLocalTextureObject(LLViewerFetchedTexture* image, const LLUUID& id);
|
||||
LLLocalTextureObject(LLGLTexture* image, const LLUUID& id);
|
||||
LLLocalTextureObject(const LLLocalTextureObject& lto);
|
||||
~LLLocalTextureObject();
|
||||
|
||||
LLViewerFetchedTexture* getImage() const;
|
||||
LLGLTexture* getImage() const;
|
||||
LLTexLayer* getTexLayer(U32 index) const;
|
||||
LLTexLayer* getTexLayer(const std::string &name);
|
||||
U32 getNumTexLayers() const;
|
||||
@@ -56,7 +55,7 @@ public:
|
||||
S32 getDiscard() const;
|
||||
BOOL getBakedReady() const;
|
||||
|
||||
void setImage(LLViewerFetchedTexture* new_image);
|
||||
void setImage(LLGLTexture* new_image);
|
||||
BOOL setTexLayer(LLTexLayer *new_tex_layer, U32 index);
|
||||
BOOL addTexLayer(LLTexLayer *new_tex_layer, LLWearable *wearable);
|
||||
BOOL addTexLayer(LLTexLayerTemplate *new_tex_layer, LLWearable *wearable);
|
||||
@@ -70,7 +69,7 @@ protected:
|
||||
|
||||
private:
|
||||
|
||||
LLPointer<LLViewerFetchedTexture> mImage;
|
||||
LLPointer<LLGLTexture> mImage;
|
||||
// NOTE: LLLocalTextureObject should be the exclusive owner of mTexEntry and mTexLayer
|
||||
// using shared pointers here only for smart assignment & cleanup
|
||||
// do NOT create new shared pointers to these objects, or keep pointers to them around
|
||||
@@ -27,25 +27,24 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Header Files
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "linden_common.h"
|
||||
#include "llpolymesh.h"
|
||||
#include "llfasttimer.h"
|
||||
#include "llmemory.h"
|
||||
|
||||
#include "llviewercontrol.h"
|
||||
//#include "llviewercontrol.h"
|
||||
#include "llxmltree.h"
|
||||
#include "llvoavatar.h"
|
||||
#include "llwearable.h"
|
||||
#include "llavatarappearance.h"
|
||||
//#include "llwearable.h"
|
||||
#include "lldir.h"
|
||||
#include "llvolume.h"
|
||||
#include "llendianswizzle.h"
|
||||
|
||||
#include "llpolymesh.h"
|
||||
|
||||
#define HEADER_ASCII "Linden Mesh 1.0"
|
||||
#define HEADER_BINARY "Linden Binary Mesh 1.0"
|
||||
|
||||
extern LLControlGroup gSavedSettings; // read only
|
||||
//extern LLControlGroup gSavedSettings; // read only
|
||||
|
||||
LLPolyMorphData *clone_morph_param_duplicate(const LLPolyMorphData *src_data,
|
||||
const std::string &name);
|
||||
@@ -1492,7 +1491,7 @@ BOOL LLPolyMesh::setSharedFromCurrent()
|
||||
std::vector< LLCharacter* >::iterator avatar_it;
|
||||
for(avatar_it = LLCharacter::sInstances.begin(); avatar_it != LLCharacter::sInstances.end(); ++avatar_it)
|
||||
{
|
||||
LLVOAvatar* avatarp = (LLVOAvatar*)*avatar_it;
|
||||
LLAvatarAppearance* avatarp = (LLAvatarAppearance*)*avatar_it;
|
||||
LLPolyMesh* mesh = avatarp->getMesh(mSharedData);
|
||||
if (mesh)
|
||||
{
|
||||
@@ -1770,250 +1769,4 @@ F32* LLPolyMesh::getWritableWeights() const
|
||||
return mSharedData->mWeights;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLPolySkeletalDistortionInfo()
|
||||
//-----------------------------------------------------------------------------
|
||||
LLPolySkeletalDistortionInfo::LLPolySkeletalDistortionInfo()
|
||||
{
|
||||
}
|
||||
|
||||
BOOL LLPolySkeletalDistortionInfo::parseXml(LLXmlTreeNode* node)
|
||||
{
|
||||
llassert( node->hasName( "param" ) && node->getChildByName( "param_skeleton" ) );
|
||||
|
||||
if (!LLViewerVisualParamInfo::parseXml(node))
|
||||
return FALSE;
|
||||
|
||||
LLXmlTreeNode* skeletalParam = node->getChildByName("param_skeleton");
|
||||
|
||||
if (NULL == skeletalParam)
|
||||
{
|
||||
llwarns << "Failed to getChildByName(\"param_skeleton\")"
|
||||
<< llendl;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for( LLXmlTreeNode* bone = skeletalParam->getFirstChild(); bone; bone = skeletalParam->getNextChild() )
|
||||
{
|
||||
if (bone->hasName("bone"))
|
||||
{
|
||||
std::string name;
|
||||
LLVector3 scale;
|
||||
LLVector3 pos;
|
||||
BOOL haspos = FALSE;
|
||||
|
||||
static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
|
||||
if (!bone->getFastAttributeString(name_string, name))
|
||||
{
|
||||
llwarns << "No bone name specified for skeletal param." << llendl;
|
||||
continue;
|
||||
}
|
||||
|
||||
static LLStdStringHandle scale_string = LLXmlTree::addAttributeString("scale");
|
||||
if (!bone->getFastAttributeVector3(scale_string, scale))
|
||||
{
|
||||
llwarns << "No scale specified for bone " << name << "." << llendl;
|
||||
continue;
|
||||
}
|
||||
|
||||
// optional offset deformation (translation)
|
||||
static LLStdStringHandle offset_string = LLXmlTree::addAttributeString("offset");
|
||||
if (bone->getFastAttributeVector3(offset_string, pos))
|
||||
{
|
||||
haspos = TRUE;
|
||||
}
|
||||
mBoneInfoList.push_back(LLPolySkeletalBoneInfo(name, scale, pos, haspos));
|
||||
}
|
||||
else
|
||||
{
|
||||
llwarns << "Unrecognized element " << bone->getName() << " in skeletal distortion" << llendl;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLPolySkeletalDistortion()
|
||||
//-----------------------------------------------------------------------------
|
||||
LLPolySkeletalDistortion::LLPolySkeletalDistortion(LLVOAvatar *avatarp)
|
||||
{
|
||||
mAvatar = avatarp;
|
||||
mDefaultVec.splat(0.001f);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ~LLPolySkeletalDistortion()
|
||||
//-----------------------------------------------------------------------------
|
||||
LLPolySkeletalDistortion::~LLPolySkeletalDistortion()
|
||||
{
|
||||
}
|
||||
|
||||
BOOL LLPolySkeletalDistortion::setInfo(LLPolySkeletalDistortionInfo *info)
|
||||
{
|
||||
llassert(mInfo == NULL);
|
||||
if (info->mID < 0)
|
||||
return FALSE;
|
||||
mInfo = info;
|
||||
mID = info->mID;
|
||||
setWeight(getDefaultWeight(), FALSE );
|
||||
|
||||
LLPolySkeletalDistortionInfo::bone_info_list_t::iterator iter;
|
||||
for (iter = getInfo()->mBoneInfoList.begin(); iter != getInfo()->mBoneInfoList.end(); iter++)
|
||||
{
|
||||
LLPolySkeletalBoneInfo *bone_info = &(*iter);
|
||||
LLJoint* joint = mAvatar->getJoint(bone_info->mBoneName);
|
||||
if (!joint)
|
||||
{
|
||||
llwarns << "Joint " << bone_info->mBoneName << " not found." << llendl;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mJointScales.find(joint) != mJointScales.end())
|
||||
{
|
||||
llwarns << "Scale deformation already supplied for joint " << joint->getName() << "." << llendl;
|
||||
}
|
||||
|
||||
// store it
|
||||
mJointScales[joint] = bone_info->mScaleDeformation;
|
||||
|
||||
// apply to children that need to inherit it
|
||||
for (LLJoint::child_list_t::iterator iter = joint->mChildren.begin();
|
||||
iter != joint->mChildren.end(); ++iter)
|
||||
{
|
||||
LLViewerJoint* child_joint = (LLViewerJoint*)(*iter);
|
||||
if (child_joint->inheritScale())
|
||||
{
|
||||
LLVector3 childDeformation = LLVector3(child_joint->getScale());
|
||||
childDeformation.scaleVec(bone_info->mScaleDeformation);
|
||||
mJointScales[child_joint] = childDeformation;
|
||||
}
|
||||
}
|
||||
|
||||
if (bone_info->mHasPositionDeformation)
|
||||
{
|
||||
if (mJointOffsets.find(joint) != mJointOffsets.end())
|
||||
{
|
||||
llwarns << "Offset deformation already supplied for joint " << joint->getName() << "." << llendl;
|
||||
}
|
||||
mJointOffsets[joint] = bone_info->mPositionDeformation;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*virtual*/ LLViewerVisualParam* LLPolySkeletalDistortion::cloneParam(LLWearable* wearable) const
|
||||
{
|
||||
LLPolySkeletalDistortion *new_param = new LLPolySkeletalDistortion(mAvatar);
|
||||
*new_param = *this;
|
||||
return new_param;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// apply()
|
||||
//-----------------------------------------------------------------------------
|
||||
static LLFastTimer::DeclareTimer FTM_POLYSKELETAL_DISTORTION_APPLY("Skeletal Distortion");
|
||||
|
||||
void LLPolySkeletalDistortion::apply( ESex avatar_sex )
|
||||
{
|
||||
LLFastTimer t(FTM_POLYSKELETAL_DISTORTION_APPLY);
|
||||
|
||||
F32 effective_weight = ( getSex() & avatar_sex ) ? mCurWeight : getDefaultWeight();
|
||||
|
||||
LLJoint* joint;
|
||||
joint_vec_map_t::iterator iter;
|
||||
|
||||
for (iter = mJointScales.begin();
|
||||
iter != mJointScales.end();
|
||||
iter++)
|
||||
{
|
||||
joint = iter->first;
|
||||
LLVector3 newScale = joint->getScale();
|
||||
LLVector3 scaleDelta = iter->second;
|
||||
newScale = newScale + (effective_weight * scaleDelta) - (mLastWeight * scaleDelta);
|
||||
joint->setScale(newScale);
|
||||
}
|
||||
|
||||
for (iter = mJointOffsets.begin();
|
||||
iter != mJointOffsets.end();
|
||||
iter++)
|
||||
{
|
||||
joint = iter->first;
|
||||
LLVector3 newPosition = joint->getPosition();
|
||||
LLVector3 positionDelta = iter->second;
|
||||
newPosition = newPosition + (effective_weight * positionDelta) - (mLastWeight * positionDelta);
|
||||
joint->setPosition(newPosition);
|
||||
}
|
||||
|
||||
if (mLastWeight != mCurWeight && !mIsAnimating)
|
||||
{
|
||||
mAvatar->setSkeletonSerialNum(mAvatar->getSkeletonSerialNum() + 1);
|
||||
}
|
||||
mLastWeight = mCurWeight;
|
||||
}
|
||||
|
||||
|
||||
LLPolyMorphData *clone_morph_param_duplicate(const LLPolyMorphData *src_data,
|
||||
const std::string &name)
|
||||
{
|
||||
LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data);
|
||||
cloned_morph_data->mName = name;
|
||||
for (U32 v=0; v < cloned_morph_data->mNumIndices; v++)
|
||||
{
|
||||
cloned_morph_data->mCoords[v] = src_data->mCoords[v];
|
||||
cloned_morph_data->mNormals[v] = src_data->mNormals[v];
|
||||
cloned_morph_data->mBinormals[v] = src_data->mBinormals[v];
|
||||
}
|
||||
return cloned_morph_data;
|
||||
}
|
||||
|
||||
LLPolyMorphData *clone_morph_param_direction(const LLPolyMorphData *src_data,
|
||||
const LLVector3 &direction,
|
||||
const std::string &name)
|
||||
{
|
||||
LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data);
|
||||
cloned_morph_data->mName = name;
|
||||
LLVector4a dir;
|
||||
dir.load3(direction.mV);
|
||||
|
||||
for (U32 v=0; v < cloned_morph_data->mNumIndices; v++)
|
||||
{
|
||||
cloned_morph_data->mCoords[v] = dir;
|
||||
cloned_morph_data->mNormals[v].clear();
|
||||
cloned_morph_data->mBinormals[v].clear();
|
||||
}
|
||||
return cloned_morph_data;
|
||||
}
|
||||
|
||||
LLPolyMorphData *clone_morph_param_cleavage(const LLPolyMorphData *src_data,
|
||||
F32 scale,
|
||||
const std::string &name)
|
||||
{
|
||||
LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data);
|
||||
cloned_morph_data->mName = name;
|
||||
|
||||
LLVector4a sc;
|
||||
sc.splat(scale);
|
||||
|
||||
LLVector4a nsc;
|
||||
nsc.set(scale, -scale, scale, scale);
|
||||
|
||||
for (U32 v=0; v < cloned_morph_data->mNumIndices; v++)
|
||||
{
|
||||
if (cloned_morph_data->mCoords[v][1] < 0)
|
||||
{
|
||||
cloned_morph_data->mCoords[v].setMul(src_data->mCoords[v],nsc);
|
||||
cloned_morph_data->mNormals[v].setMul(src_data->mNormals[v],nsc);
|
||||
cloned_morph_data->mBinormals[v].setMul(src_data->mBinormals[v],nsc);
|
||||
}
|
||||
else
|
||||
{
|
||||
cloned_morph_data->mCoords[v].setMul(src_data->mCoords[v],sc);
|
||||
cloned_morph_data->mNormals[v].setMul(src_data->mNormals[v], sc);
|
||||
cloned_morph_data->mBinormals[v].setMul(src_data->mBinormals[v],sc);
|
||||
}
|
||||
}
|
||||
return cloned_morph_data;
|
||||
}
|
||||
|
||||
// End
|
||||
@@ -24,8 +24,8 @@
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLPOLYMESH_H
|
||||
#define LL_LLPOLYMESH_H
|
||||
#ifndef LL_LLPOLYMESHINTERFACE_H
|
||||
#define LL_LLPOLYMESHINTERFACE_H
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
@@ -39,7 +39,7 @@
|
||||
//#include "lldarray.h"
|
||||
|
||||
class LLSkinJoint;
|
||||
class LLVOAvatar;
|
||||
class LLAvatarAppearance;
|
||||
class LLWearable;
|
||||
|
||||
//#define USE_STRIPS // Use tri-strips for rendering.
|
||||
@@ -340,8 +340,8 @@ public:
|
||||
|
||||
BOOL isLOD() { return mSharedData && mSharedData->isLOD(); }
|
||||
|
||||
void setAvatar(LLVOAvatar* avatarp) { mAvatarp = avatarp; }
|
||||
LLVOAvatar* getAvatar() { return mAvatarp; }
|
||||
void setAvatar(LLAvatarAppearance* avatarp) { mAvatarp = avatarp; }
|
||||
LLAvatarAppearance* getAvatar() { return mAvatarp; }
|
||||
|
||||
LLDynamicArray<LLJointRenderData*> mJointRenderData;
|
||||
|
||||
@@ -384,87 +384,8 @@ protected:
|
||||
static LLPolyMeshSharedDataTable sGlobalSharedMeshList;
|
||||
|
||||
// Backlink only; don't make this an LLPointer.
|
||||
LLVOAvatar* mAvatarp;
|
||||
LLAvatarAppearance* mAvatarp;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLPolySkeletalDeformationInfo
|
||||
// Shared information for LLPolySkeletalDeformations
|
||||
//-----------------------------------------------------------------------------
|
||||
struct LLPolySkeletalBoneInfo
|
||||
{
|
||||
LLPolySkeletalBoneInfo(std::string &name, LLVector3 &scale, LLVector3 &pos, BOOL haspos)
|
||||
: mBoneName(name),
|
||||
mScaleDeformation(scale),
|
||||
mPositionDeformation(pos),
|
||||
mHasPositionDeformation(haspos) {}
|
||||
std::string mBoneName;
|
||||
LLVector3 mScaleDeformation;
|
||||
LLVector3 mPositionDeformation;
|
||||
BOOL mHasPositionDeformation;
|
||||
};
|
||||
|
||||
class LLPolySkeletalDistortionInfo : public LLViewerVisualParamInfo
|
||||
{
|
||||
friend class LLPolySkeletalDistortion;
|
||||
public:
|
||||
LLPolySkeletalDistortionInfo();
|
||||
/*virtual*/ ~LLPolySkeletalDistortionInfo() {};
|
||||
|
||||
/*virtual*/ BOOL parseXml(LLXmlTreeNode* node);
|
||||
|
||||
protected:
|
||||
typedef std::vector<LLPolySkeletalBoneInfo> bone_info_list_t;
|
||||
bone_info_list_t mBoneInfoList;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLPolySkeletalDeformation
|
||||
// A set of joint scale data for deforming the avatar mesh
|
||||
//-----------------------------------------------------------------------------
|
||||
class LLPolySkeletalDistortion : public LLViewerVisualParam
|
||||
{
|
||||
public:
|
||||
LLPolySkeletalDistortion(LLVOAvatar *avatarp);
|
||||
~LLPolySkeletalDistortion();
|
||||
|
||||
void* operator new(size_t size)
|
||||
{
|
||||
return ll_aligned_malloc_16(size);
|
||||
}
|
||||
|
||||
void operator delete(void* ptr)
|
||||
{
|
||||
ll_aligned_free_16(ptr);
|
||||
}
|
||||
|
||||
// Special: These functions are overridden by child classes
|
||||
LLPolySkeletalDistortionInfo* getInfo() const { return (LLPolySkeletalDistortionInfo*)mInfo; }
|
||||
// This sets mInfo and calls initialization functions
|
||||
BOOL setInfo(LLPolySkeletalDistortionInfo *info);
|
||||
|
||||
/*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const;
|
||||
|
||||
// LLVisualParam Virtual functions
|
||||
///*virtual*/ BOOL parseData(LLXmlTreeNode* node);
|
||||
/*virtual*/ void apply( ESex sex );
|
||||
|
||||
// LLViewerVisualParam Virtual functions
|
||||
/*virtual*/ F32 getTotalDistortion() { return 0.1f; }
|
||||
/*virtual*/ const LLVector4a& getAvgDistortion() { return mDefaultVec; }
|
||||
/*virtual*/ F32 getMaxDistortion() { return 0.1f; }
|
||||
/*virtual*/ LLVector4a getVertexDistortion(S32 index, LLPolyMesh *poly_mesh){return LLVector4a(0.001f, 0.001f, 0.001f);}
|
||||
/*virtual*/ const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh){index = 0; poly_mesh = NULL; return &mDefaultVec;};
|
||||
/*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh){index = 0; poly_mesh = NULL; return NULL;};
|
||||
|
||||
protected:
|
||||
typedef std::map<LLJoint*, LLVector3> joint_vec_map_t;
|
||||
joint_vec_map_t mJointScales;
|
||||
joint_vec_map_t mJointOffsets;
|
||||
LLVector4a mDefaultVec;
|
||||
// Backlink only; don't make this an LLPointer.
|
||||
LLVOAvatar *mAvatar;
|
||||
};
|
||||
|
||||
#endif // LL_LLPOLYMESH_H
|
||||
#endif // LL_LLPOLYMESHINTERFACE_H
|
||||
|
||||
@@ -27,13 +27,15 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Header Files
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llpolymorph.h"
|
||||
#include "llvoavatar.h"
|
||||
#include "llwearable.h"
|
||||
#include "llavatarappearance.h"
|
||||
#include "llavatarjoint.h"
|
||||
//#include "llwearable.h"
|
||||
#include "llxmltree.h"
|
||||
#include "llendianswizzle.h"
|
||||
#include "llpolymesh.h"
|
||||
#include "v2math.h"
|
||||
|
||||
//#include "../tools/imdebug/imdebug.h"
|
||||
|
||||
@@ -462,7 +464,7 @@ BOOL LLPolyMorphData::setMorphFromMesh(LLPolyMesh *morph)
|
||||
std::vector< LLCharacter* >::iterator avatar_it;
|
||||
for(avatar_it = LLCharacter::sInstances.begin(); avatar_it != LLCharacter::sInstances.end(); ++avatar_it)
|
||||
{
|
||||
LLVOAvatar* avatarp = (LLVOAvatar*)*avatar_it;
|
||||
LLAvatarAppearance* avatarp = (LLAvatarAppearance*)*avatar_it;
|
||||
|
||||
LLPolyMorphTarget* param = (LLPolyMorphTarget*) avatarp->getVisualParam(mName.c_str());
|
||||
if (!param)
|
||||
@@ -633,7 +635,7 @@ BOOL LLPolyMorphTarget::setInfo(LLPolyMorphTargetInfo* info)
|
||||
mID = info->mID;
|
||||
setWeight(getDefaultWeight(), FALSE );
|
||||
|
||||
LLVOAvatar* avatarp = mMesh->getAvatar();
|
||||
LLAvatarAppearance* avatarp = mMesh->getAvatar();
|
||||
LLPolyMorphTargetInfo::volume_info_list_t::iterator iter;
|
||||
for (iter = getInfo()->mVolumeInfoList.begin(); iter != getInfo()->mVolumeInfoList.end(); iter++)
|
||||
{
|
||||
@@ -2,31 +2,25 @@
|
||||
* @file llpolymorph.h
|
||||
* @brief Implementation of LLPolyMesh class
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2001-2009, Linden Research, Inc.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
@@ -38,10 +32,10 @@
|
||||
|
||||
#include "llviewervisualparam.h"
|
||||
|
||||
class LLAvatarJointCollisionVolume;
|
||||
class LLPolyMeshSharedData;
|
||||
class LLVOAvatar;
|
||||
class LLVector2;
|
||||
class LLViewerJointCollisionVolume;
|
||||
class LLAvatarJointCollisionVolume;
|
||||
class LLWearable;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -127,10 +121,10 @@ struct LLPolyVolumeMorphInfo
|
||||
|
||||
struct LLPolyVolumeMorph
|
||||
{
|
||||
LLPolyVolumeMorph(LLViewerJointCollisionVolume* volume, LLVector3 scale, LLVector3 pos)
|
||||
LLPolyVolumeMorph(LLAvatarJointCollisionVolume* volume, LLVector3 scale, LLVector3 pos)
|
||||
: mVolume(volume), mScale(scale), mPos(pos) {};
|
||||
|
||||
LLViewerJointCollisionVolume* mVolume;
|
||||
LLAvatarJointCollisionVolume* mVolume;
|
||||
LLVector3 mScale;
|
||||
LLVector3 mPos;
|
||||
};
|
||||
293
indra/llappearance/llpolyskeletaldistortion.cpp
Normal file
293
indra/llappearance/llpolyskeletaldistortion.cpp
Normal file
@@ -0,0 +1,293 @@
|
||||
/**
|
||||
* @file llpolyskeletaldistortion.cpp
|
||||
* @brief Implementation of LLPolySkeletalDistortion classes
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Header Files
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "llpreprocessor.h"
|
||||
#include "llerrorlegacy.h"
|
||||
//#include "llcommon.h"
|
||||
//#include "llmemory.h"
|
||||
#include "llavatarappearance.h"
|
||||
#include "llavatarjoint.h"
|
||||
#include "llpolymorph.h"
|
||||
//#include "llviewercontrol.h"
|
||||
//#include "llxmltree.h"
|
||||
//#include "llvoavatar.h"
|
||||
#include "llwearable.h"
|
||||
//#include "lldir.h"
|
||||
//#include "llvolume.h"
|
||||
//#include "llendianswizzle.h"
|
||||
|
||||
#include "llpolyskeletaldistortion.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLPolySkeletalDistortionInfo()
|
||||
//-----------------------------------------------------------------------------
|
||||
LLPolySkeletalDistortionInfo::LLPolySkeletalDistortionInfo()
|
||||
{
|
||||
}
|
||||
|
||||
BOOL LLPolySkeletalDistortionInfo::parseXml(LLXmlTreeNode* node)
|
||||
{
|
||||
llassert( node->hasName( "param" ) && node->getChildByName( "param_skeleton" ) );
|
||||
|
||||
if (!LLViewerVisualParamInfo::parseXml(node))
|
||||
return FALSE;
|
||||
|
||||
LLXmlTreeNode* skeletalParam = node->getChildByName("param_skeleton");
|
||||
|
||||
if (NULL == skeletalParam)
|
||||
{
|
||||
llwarns << "Failed to getChildByName(\"param_skeleton\")"
|
||||
<< llendl;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for( LLXmlTreeNode* bone = skeletalParam->getFirstChild(); bone; bone = skeletalParam->getNextChild() )
|
||||
{
|
||||
if (bone->hasName("bone"))
|
||||
{
|
||||
std::string name;
|
||||
LLVector3 scale;
|
||||
LLVector3 pos;
|
||||
BOOL haspos = FALSE;
|
||||
|
||||
static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
|
||||
if (!bone->getFastAttributeString(name_string, name))
|
||||
{
|
||||
llwarns << "No bone name specified for skeletal param." << llendl;
|
||||
continue;
|
||||
}
|
||||
|
||||
static LLStdStringHandle scale_string = LLXmlTree::addAttributeString("scale");
|
||||
if (!bone->getFastAttributeVector3(scale_string, scale))
|
||||
{
|
||||
llwarns << "No scale specified for bone " << name << "." << llendl;
|
||||
continue;
|
||||
}
|
||||
|
||||
// optional offset deformation (translation)
|
||||
static LLStdStringHandle offset_string = LLXmlTree::addAttributeString("offset");
|
||||
if (bone->getFastAttributeVector3(offset_string, pos))
|
||||
{
|
||||
haspos = TRUE;
|
||||
}
|
||||
mBoneInfoList.push_back(LLPolySkeletalBoneInfo(name, scale, pos, haspos));
|
||||
}
|
||||
else
|
||||
{
|
||||
llwarns << "Unrecognized element " << bone->getName() << " in skeletal distortion" << llendl;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLPolySkeletalDistortion()
|
||||
//-----------------------------------------------------------------------------
|
||||
LLPolySkeletalDistortion::LLPolySkeletalDistortion(LLAvatarAppearance *avatarp)
|
||||
{
|
||||
mAvatar = avatarp;
|
||||
mDefaultVec.splat(0.001f);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ~LLPolySkeletalDistortion()
|
||||
//-----------------------------------------------------------------------------
|
||||
LLPolySkeletalDistortion::~LLPolySkeletalDistortion()
|
||||
{
|
||||
}
|
||||
|
||||
BOOL LLPolySkeletalDistortion::setInfo(LLPolySkeletalDistortionInfo *info)
|
||||
{
|
||||
llassert(mInfo == NULL);
|
||||
if (info->mID < 0)
|
||||
return FALSE;
|
||||
mInfo = info;
|
||||
mID = info->mID;
|
||||
setWeight(getDefaultWeight(), FALSE );
|
||||
|
||||
LLPolySkeletalDistortionInfo::bone_info_list_t::iterator iter;
|
||||
for (iter = getInfo()->mBoneInfoList.begin(); iter != getInfo()->mBoneInfoList.end(); iter++)
|
||||
{
|
||||
LLPolySkeletalBoneInfo *bone_info = &(*iter);
|
||||
LLJoint* joint = mAvatar->getJoint(bone_info->mBoneName);
|
||||
if (!joint)
|
||||
{
|
||||
llwarns << "Joint " << bone_info->mBoneName << " not found." << llendl;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mJointScales.find(joint) != mJointScales.end())
|
||||
{
|
||||
llwarns << "Scale deformation already supplied for joint " << joint->getName() << "." << llendl;
|
||||
}
|
||||
|
||||
// store it
|
||||
mJointScales[joint] = bone_info->mScaleDeformation;
|
||||
|
||||
// apply to children that need to inherit it
|
||||
for (LLJoint::child_list_t::iterator iter = joint->mChildren.begin();
|
||||
iter != joint->mChildren.end(); ++iter)
|
||||
{
|
||||
LLAvatarJoint* child_joint = (LLAvatarJoint*)(*iter);
|
||||
if (child_joint->inheritScale())
|
||||
{
|
||||
LLVector3 childDeformation = LLVector3(child_joint->getScale());
|
||||
childDeformation.scaleVec(bone_info->mScaleDeformation);
|
||||
mJointScales[child_joint] = childDeformation;
|
||||
}
|
||||
}
|
||||
|
||||
if (bone_info->mHasPositionDeformation)
|
||||
{
|
||||
if (mJointOffsets.find(joint) != mJointOffsets.end())
|
||||
{
|
||||
llwarns << "Offset deformation already supplied for joint " << joint->getName() << "." << llendl;
|
||||
}
|
||||
mJointOffsets[joint] = bone_info->mPositionDeformation;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*virtual*/ LLViewerVisualParam* LLPolySkeletalDistortion::cloneParam(LLWearable* wearable) const
|
||||
{
|
||||
LLPolySkeletalDistortion *new_param = new LLPolySkeletalDistortion(mAvatar);
|
||||
*new_param = *this;
|
||||
return new_param;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// apply()
|
||||
//-----------------------------------------------------------------------------
|
||||
static LLFastTimer::DeclareTimer FTM_POLYSKELETAL_DISTORTION_APPLY("Skeletal Distortion");
|
||||
|
||||
void LLPolySkeletalDistortion::apply( ESex avatar_sex )
|
||||
{
|
||||
LLFastTimer t(FTM_POLYSKELETAL_DISTORTION_APPLY);
|
||||
|
||||
F32 effective_weight = ( getSex() & avatar_sex ) ? mCurWeight : getDefaultWeight();
|
||||
|
||||
LLJoint* joint;
|
||||
joint_vec_map_t::iterator iter;
|
||||
|
||||
for (iter = mJointScales.begin();
|
||||
iter != mJointScales.end();
|
||||
iter++)
|
||||
{
|
||||
joint = iter->first;
|
||||
LLVector3 newScale = joint->getScale();
|
||||
LLVector3 scaleDelta = iter->second;
|
||||
newScale = newScale + (effective_weight * scaleDelta) - (mLastWeight * scaleDelta);
|
||||
joint->setScale(newScale);
|
||||
}
|
||||
|
||||
for (iter = mJointOffsets.begin();
|
||||
iter != mJointOffsets.end();
|
||||
iter++)
|
||||
{
|
||||
joint = iter->first;
|
||||
LLVector3 newPosition = joint->getPosition();
|
||||
LLVector3 positionDelta = iter->second;
|
||||
newPosition = newPosition + (effective_weight * positionDelta) - (mLastWeight * positionDelta);
|
||||
joint->setPosition(newPosition);
|
||||
}
|
||||
|
||||
if (mLastWeight != mCurWeight && !mIsAnimating)
|
||||
{
|
||||
mAvatar->setSkeletonSerialNum(mAvatar->getSkeletonSerialNum() + 1);
|
||||
}
|
||||
mLastWeight = mCurWeight;
|
||||
}
|
||||
|
||||
|
||||
LLPolyMorphData *clone_morph_param_duplicate(const LLPolyMorphData *src_data,
|
||||
const std::string &name)
|
||||
{
|
||||
LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data);
|
||||
cloned_morph_data->mName = name;
|
||||
for (U32 v=0; v < cloned_morph_data->mNumIndices; v++)
|
||||
{
|
||||
cloned_morph_data->mCoords[v] = src_data->mCoords[v];
|
||||
cloned_morph_data->mNormals[v] = src_data->mNormals[v];
|
||||
cloned_morph_data->mBinormals[v] = src_data->mBinormals[v];
|
||||
}
|
||||
return cloned_morph_data;
|
||||
}
|
||||
|
||||
LLPolyMorphData *clone_morph_param_direction(const LLPolyMorphData *src_data,
|
||||
const LLVector3 &direction,
|
||||
const std::string &name)
|
||||
{
|
||||
LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data);
|
||||
cloned_morph_data->mName = name;
|
||||
LLVector4a dir;
|
||||
dir.load3(direction.mV);
|
||||
|
||||
for (U32 v=0; v < cloned_morph_data->mNumIndices; v++)
|
||||
{
|
||||
cloned_morph_data->mCoords[v] = dir;
|
||||
cloned_morph_data->mNormals[v].clear();
|
||||
cloned_morph_data->mBinormals[v].clear();
|
||||
}
|
||||
return cloned_morph_data;
|
||||
}
|
||||
|
||||
LLPolyMorphData *clone_morph_param_cleavage(const LLPolyMorphData *src_data,
|
||||
F32 scale,
|
||||
const std::string &name)
|
||||
{
|
||||
LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data);
|
||||
cloned_morph_data->mName = name;
|
||||
|
||||
LLVector4a sc;
|
||||
sc.splat(scale);
|
||||
|
||||
LLVector4a nsc;
|
||||
nsc.set(scale, -scale, scale, scale);
|
||||
|
||||
for (U32 v=0; v < cloned_morph_data->mNumIndices; v++)
|
||||
{
|
||||
if (cloned_morph_data->mCoords[v][1] < 0)
|
||||
{
|
||||
cloned_morph_data->mCoords[v].setMul(src_data->mCoords[v],nsc);
|
||||
cloned_morph_data->mNormals[v].setMul(src_data->mNormals[v],nsc);
|
||||
cloned_morph_data->mBinormals[v].setMul(src_data->mBinormals[v],nsc);
|
||||
}
|
||||
else
|
||||
{
|
||||
cloned_morph_data->mCoords[v].setMul(src_data->mCoords[v],sc);
|
||||
cloned_morph_data->mNormals[v].setMul(src_data->mNormals[v], sc);
|
||||
cloned_morph_data->mBinormals[v].setMul(src_data->mBinormals[v],sc);
|
||||
}
|
||||
}
|
||||
return cloned_morph_data;
|
||||
}
|
||||
|
||||
// End
|
||||
130
indra/llappearance/llpolyskeletaldistortion.h
Normal file
130
indra/llappearance/llpolyskeletaldistortion.h
Normal file
@@ -0,0 +1,130 @@
|
||||
/**
|
||||
* @file llpolyskeletaldistortion.h
|
||||
* @brief Implementation of LLPolyMesh class
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLPOLYSKELETALDISTORTION_H
|
||||
#define LL_LLPOLYSKELETALDISTORTION_H
|
||||
|
||||
#include "llcommon.h"
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include "llstl.h"
|
||||
|
||||
#include "v3math.h"
|
||||
#include "v2math.h"
|
||||
#include "llquaternion.h"
|
||||
//#include "llpolymorph.h"
|
||||
#include "lljoint.h"
|
||||
#include "llviewervisualparam.h"
|
||||
//#include "lldarray.h"
|
||||
|
||||
//class LLSkinJoint;
|
||||
class LLAvatarAppearance;
|
||||
|
||||
//#define USE_STRIPS // Use tri-strips for rendering.
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLPolySkeletalDeformationInfo
|
||||
// Shared information for LLPolySkeletalDeformations
|
||||
//-----------------------------------------------------------------------------
|
||||
struct LLPolySkeletalBoneInfo
|
||||
{
|
||||
LLPolySkeletalBoneInfo(std::string &name, LLVector3 &scale, LLVector3 &pos, BOOL haspos)
|
||||
: mBoneName(name),
|
||||
mScaleDeformation(scale),
|
||||
mPositionDeformation(pos),
|
||||
mHasPositionDeformation(haspos) {}
|
||||
std::string mBoneName;
|
||||
LLVector3 mScaleDeformation;
|
||||
LLVector3 mPositionDeformation;
|
||||
BOOL mHasPositionDeformation;
|
||||
};
|
||||
|
||||
class LLPolySkeletalDistortionInfo : public LLViewerVisualParamInfo
|
||||
{
|
||||
friend class LLPolySkeletalDistortion;
|
||||
public:
|
||||
|
||||
LLPolySkeletalDistortionInfo();
|
||||
/*virtual*/ ~LLPolySkeletalDistortionInfo() {};
|
||||
|
||||
/*virtual*/ BOOL parseXml(LLXmlTreeNode* node);
|
||||
|
||||
protected:
|
||||
typedef std::vector<LLPolySkeletalBoneInfo> bone_info_list_t;
|
||||
bone_info_list_t mBoneInfoList;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLPolySkeletalDeformation
|
||||
// A set of joint scale data for deforming the avatar mesh
|
||||
//-----------------------------------------------------------------------------
|
||||
class LLPolySkeletalDistortion : public LLViewerVisualParam
|
||||
{
|
||||
public:
|
||||
void* operator new(size_t size)
|
||||
{
|
||||
return ll_aligned_malloc_16(size);
|
||||
}
|
||||
|
||||
void operator delete(void* ptr)
|
||||
{
|
||||
ll_aligned_free_16(ptr);
|
||||
}
|
||||
|
||||
LLPolySkeletalDistortion(LLAvatarAppearance *avatarp);
|
||||
~LLPolySkeletalDistortion();
|
||||
|
||||
// Special: These functions are overridden by child classes
|
||||
LLPolySkeletalDistortionInfo* getInfo() const { return (LLPolySkeletalDistortionInfo*)mInfo; }
|
||||
// This sets mInfo and calls initialization functions
|
||||
BOOL setInfo(LLPolySkeletalDistortionInfo *info);
|
||||
|
||||
/*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const;
|
||||
|
||||
// LLVisualParam Virtual functions
|
||||
///*virtual*/ BOOL parseData(LLXmlTreeNode* node);
|
||||
/*virtual*/ void apply( ESex sex );
|
||||
|
||||
// LLViewerVisualParam Virtual functions
|
||||
/*virtual*/ F32 getTotalDistortion() { return 0.1f; }
|
||||
/*virtual*/ const LLVector4a& getAvgDistortion() { return mDefaultVec; }
|
||||
/*virtual*/ F32 getMaxDistortion() { return 0.1f; }
|
||||
/*virtual*/ LLVector4a getVertexDistortion(S32 index, LLPolyMesh *poly_mesh){return LLVector4a(0.001f, 0.001f, 0.001f);}
|
||||
/*virtual*/ const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh){index = 0; poly_mesh = NULL; return &mDefaultVec;};
|
||||
/*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh){index = 0; poly_mesh = NULL; return NULL;};
|
||||
|
||||
protected:
|
||||
typedef std::map<LLJoint*, LLVector3> joint_vec_map_t;
|
||||
joint_vec_map_t mJointScales;
|
||||
joint_vec_map_t mJointOffsets;
|
||||
LLVector4a mDefaultVec;
|
||||
// Backlink only; don't make this an LLPointer.
|
||||
LLAvatarAppearance *mAvatar;
|
||||
};
|
||||
|
||||
#endif // LL_LLPOLYSKELETALDISTORTION_H
|
||||
|
||||
@@ -24,20 +24,20 @@
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
#include "llagent.h"
|
||||
#include "linden_common.h"
|
||||
#include "llavatarappearance.h"
|
||||
#include "lltexlayer.h"
|
||||
#include "llvoavatar.h"
|
||||
#include "llwearable.h"
|
||||
#include "lltexglobalcolor.h"
|
||||
|
||||
class LLWearable;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLTexGlobalColor
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
LLTexGlobalColor::LLTexGlobalColor(LLVOAvatar* avatar)
|
||||
LLTexGlobalColor::LLTexGlobalColor(LLAvatarAppearance* appearance)
|
||||
:
|
||||
mAvatar(avatar),
|
||||
mAvatarAppearance(appearance),
|
||||
mInfo(NULL)
|
||||
{
|
||||
}
|
||||
@@ -91,7 +91,7 @@ const std::string& LLTexGlobalColor::getName() const
|
||||
// LLTexParamGlobalColor
|
||||
//-----------------------------------------------------------------------------
|
||||
LLTexParamGlobalColor::LLTexParamGlobalColor(LLTexGlobalColor* tex_global_color) :
|
||||
LLTexLayerParamColor(tex_global_color->getAvatar()),
|
||||
LLTexLayerParamColor(tex_global_color->getAvatarAppearance()),
|
||||
mTexGlobalColor(tex_global_color)
|
||||
{
|
||||
}
|
||||
@@ -105,7 +105,7 @@ LLTexParamGlobalColor::LLTexParamGlobalColor(LLTexGlobalColor* tex_global_color)
|
||||
|
||||
void LLTexParamGlobalColor::onGlobalColorChanged(bool upload_bake)
|
||||
{
|
||||
mAvatar->onGlobalColorChanged(mTexGlobalColor, upload_bake);
|
||||
mAvatarAppearance->onGlobalColorChanged(mTexGlobalColor, upload_bake);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @file lltexglobalcolor.h
|
||||
* @brief This is global texture color info used by llvoavatar.
|
||||
* @brief This is global texture color info used by llavatarappearance.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2008&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
@@ -30,31 +30,31 @@
|
||||
#include "lltexlayer.h"
|
||||
#include "lltexlayerparams.h"
|
||||
|
||||
class LLVOAvatar;
|
||||
class LLAvatarAppearance;
|
||||
class LLWearable;
|
||||
class LLTexGlobalColorInfo;
|
||||
|
||||
class LLTexGlobalColor
|
||||
{
|
||||
public:
|
||||
LLTexGlobalColor( LLVOAvatar* avatar );
|
||||
LLTexGlobalColor( LLAvatarAppearance* appearance );
|
||||
~LLTexGlobalColor();
|
||||
|
||||
LLTexGlobalColorInfo* getInfo() const { return mInfo; }
|
||||
// This sets mInfo and calls initialization functions
|
||||
BOOL setInfo(LLTexGlobalColorInfo *info);
|
||||
|
||||
LLVOAvatar* getAvatar() const { return mAvatar; }
|
||||
LLAvatarAppearance* getAvatarAppearance() const { return mAvatarAppearance; }
|
||||
LLColor4 getColor() const;
|
||||
const std::string& getName() const;
|
||||
|
||||
private:
|
||||
param_color_list_t mParamGlobalColorList;
|
||||
LLVOAvatar* mAvatar; // just backlink, don't LLPointer
|
||||
LLAvatarAppearance* mAvatarAppearance; // just backlink, don't LLPointer
|
||||
LLTexGlobalColorInfo *mInfo;
|
||||
};
|
||||
|
||||
// Used by llvoavatar to determine skin/eye/hair color.
|
||||
// Used by llavatarappearance to determine skin/eye/hair color.
|
||||
class LLTexGlobalColorInfo
|
||||
{
|
||||
friend class LLTexGlobalColor;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -28,14 +28,15 @@
|
||||
#define LL_LLTEXLAYER_H
|
||||
|
||||
#include <deque>
|
||||
#include "lldynamictexture.h"
|
||||
#include "llvoavatardefines.h"
|
||||
#include "llglslshader.h"
|
||||
#include "llgltexture.h"
|
||||
#include "llavatarappearancedefines.h"
|
||||
#include "lltexlayerparams.h"
|
||||
|
||||
class LLVOAvatar;
|
||||
class LLVOAvatarSelf;
|
||||
class LLAvatarAppearance;
|
||||
class LLImageTGA;
|
||||
class LLImageRaw;
|
||||
class LLLocalTextureObject;
|
||||
class LLXmlTreeNode;
|
||||
class LLTexLayerSet;
|
||||
class LLTexLayerSetInfo;
|
||||
@@ -50,7 +51,7 @@ class LLViewerVisualParam;
|
||||
// Interface class to generalize functionality shared by LLTexLayer
|
||||
// and LLTexLayerTemplate.
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
class LLTexLayerInterface
|
||||
class LLTexLayerInterface
|
||||
{
|
||||
public:
|
||||
enum ERenderPass
|
||||
@@ -71,6 +72,8 @@ public:
|
||||
|
||||
const LLTexLayerInfo* getInfo() const { return mInfo; }
|
||||
virtual BOOL setInfo(const LLTexLayerInfo *info, LLWearable* wearable); // sets mInfo, calls initialization functions
|
||||
LLWearableType::EType getWearableType() const;
|
||||
LLAvatarAppearanceDefines::ETextureIndex getLocalTextureIndex() const;
|
||||
|
||||
const std::string& getName() const;
|
||||
const LLTexLayerSet* const getTexLayerSet() const { return mTexLayerSet; }
|
||||
@@ -88,6 +91,8 @@ public:
|
||||
ERenderPass getRenderPass() const;
|
||||
BOOL isVisibilityMask() const;
|
||||
|
||||
virtual void asLLSD(LLSD& sd) const {}
|
||||
|
||||
protected:
|
||||
const std::string& getGlobalColor() const;
|
||||
LLViewerVisualParam* getVisualParamPtr(S32 index) const;
|
||||
@@ -113,7 +118,7 @@ protected:
|
||||
class LLTexLayerTemplate : public LLTexLayerInterface
|
||||
{
|
||||
public:
|
||||
LLTexLayerTemplate(LLTexLayerSet* const layer_set);
|
||||
LLTexLayerTemplate(LLTexLayerSet* const layer_set, LLAvatarAppearance* const appearance);
|
||||
LLTexLayerTemplate(const LLTexLayerTemplate &layer);
|
||||
/*virtual*/ ~LLTexLayerTemplate();
|
||||
/*virtual*/ BOOL render(S32 x, S32 y, S32 width, S32 height);
|
||||
@@ -126,7 +131,9 @@ public:
|
||||
protected:
|
||||
U32 updateWearableCache() const;
|
||||
LLTexLayer* getLayer(U32 i) const;
|
||||
LLAvatarAppearance* getAvatarAppearance() const { return mAvatarAppearance; }
|
||||
private:
|
||||
LLAvatarAppearance* const mAvatarAppearance; // note: backlink only; don't make this an LLPointer.
|
||||
typedef std::vector<LLWearable*> wearable_cache_t;
|
||||
mutable wearable_cache_t mWearableCache; // mutable b/c most get- require updating this cache
|
||||
};
|
||||
@@ -160,10 +167,11 @@ public:
|
||||
void setLTO(LLLocalTextureObject *lto) { mLocalTextureObject = lto; }
|
||||
LLLocalTextureObject* getLTO() { return mLocalTextureObject; }
|
||||
|
||||
/*virtual*/ void asLLSD(LLSD& sd) const;
|
||||
|
||||
static void calculateTexLayerColor(const param_color_list_t ¶m_list, LLColor4 &net_color);
|
||||
protected:
|
||||
LLUUID getUUID() const;
|
||||
private:
|
||||
typedef std::map<U32, U8*> alpha_cache_t;
|
||||
alpha_cache_t mAlphaCache;
|
||||
LLLocalTextureObject* mLocalTextureObject;
|
||||
@@ -179,8 +187,14 @@ class LLTexLayerSet
|
||||
{
|
||||
friend class LLTexLayerSetBuffer;
|
||||
public:
|
||||
LLTexLayerSet(LLVOAvatarSelf* const avatar);
|
||||
~LLTexLayerSet();
|
||||
LLTexLayerSet(LLAvatarAppearance* const appearance);
|
||||
virtual ~LLTexLayerSet();
|
||||
|
||||
LLTexLayerSetBuffer* getComposite();
|
||||
const LLTexLayerSetBuffer* getComposite() const; // Do not create one if it doesn't exist.
|
||||
virtual void createComposite() = 0;
|
||||
void destroyComposite();
|
||||
void gatherMorphMaskAlpha(U8 *data, S32 origin_x, S32 origin_y, S32 width, S32 height);
|
||||
|
||||
const LLTexLayerSetInfo* getInfo() const { return mInfo; }
|
||||
BOOL setInfo(const LLTexLayerSetInfo *info); // This sets mInfo and calls initialization functions
|
||||
@@ -189,45 +203,34 @@ public:
|
||||
void renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, bool forceClear = false);
|
||||
|
||||
BOOL isBodyRegion(const std::string& region) const;
|
||||
LLTexLayerSetBuffer* getComposite();
|
||||
const LLTexLayerSetBuffer* getComposite() const; // Do not create one if it doesn't exist.
|
||||
void requestUpdate();
|
||||
void requestUpload();
|
||||
void cancelUpload();
|
||||
void updateComposite();
|
||||
BOOL isLocalTextureDataAvailable() const;
|
||||
BOOL isLocalTextureDataFinal() const;
|
||||
void createComposite();
|
||||
void destroyComposite();
|
||||
void setUpdatesEnabled(BOOL b);
|
||||
BOOL getUpdatesEnabled() const { return mUpdatesEnabled; }
|
||||
void deleteCaches();
|
||||
void gatherMorphMaskAlpha(U8 *data, S32 width, S32 height);
|
||||
void applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components);
|
||||
BOOL isMorphValid() const;
|
||||
virtual void requestUpdate() = 0;
|
||||
void invalidateMorphMasks();
|
||||
void deleteCaches();
|
||||
LLTexLayerInterface* findLayerByName(const std::string& name);
|
||||
void cloneTemplates(LLLocalTextureObject *lto, LLVOAvatarDefines::ETextureIndex tex_index, LLWearable* wearable);
|
||||
void cloneTemplates(LLLocalTextureObject *lto, LLAvatarAppearanceDefines::ETextureIndex tex_index, LLWearable* wearable);
|
||||
|
||||
LLVOAvatarSelf* getAvatar() const { return mAvatar; }
|
||||
LLAvatarAppearance* getAvatarAppearance() const { return mAvatarAppearance; }
|
||||
const std::string getBodyRegionName() const;
|
||||
BOOL hasComposite() const { return (mComposite.notNull()); }
|
||||
LLVOAvatarDefines::EBakedTextureIndex getBakedTexIndex() { return mBakedTexIndex; }
|
||||
void setBakedTexIndex(LLVOAvatarDefines::EBakedTextureIndex index) { mBakedTexIndex = index; }
|
||||
LLAvatarAppearanceDefines::EBakedTextureIndex getBakedTexIndex() const { return mBakedTexIndex; }
|
||||
void setBakedTexIndex(LLAvatarAppearanceDefines::EBakedTextureIndex index) { mBakedTexIndex = index; }
|
||||
BOOL isVisible() const { return mIsVisible; }
|
||||
|
||||
static BOOL sHasCaches;
|
||||
|
||||
private:
|
||||
virtual void asLLSD(LLSD& sd) const;
|
||||
|
||||
protected:
|
||||
typedef std::vector<LLTexLayerInterface *> layer_list_t;
|
||||
layer_list_t mLayerList;
|
||||
layer_list_t mMaskLayerList;
|
||||
LLPointer<LLTexLayerSetBuffer> mComposite;
|
||||
LLVOAvatarSelf* const mAvatar; // note: backlink only; don't make this an LLPointer.
|
||||
BOOL mUpdatesEnabled;
|
||||
LLAvatarAppearance* const mAvatarAppearance; // note: backlink only; don't make this an LLPointer.
|
||||
BOOL mIsVisible;
|
||||
|
||||
LLVOAvatarDefines::EBakedTextureIndex mBakedTexIndex;
|
||||
LLAvatarAppearanceDefines::EBakedTextureIndex mBakedTexIndex;
|
||||
const LLTexLayerSetInfo* mInfo;
|
||||
};
|
||||
|
||||
@@ -243,8 +246,10 @@ public:
|
||||
LLTexLayerSetInfo();
|
||||
~LLTexLayerSetInfo();
|
||||
BOOL parseXml(LLXmlTreeNode* node);
|
||||
void createVisualParams(LLVOAvatar *avatar);
|
||||
private:
|
||||
void createVisualParams(LLAvatarAppearance *appearance);
|
||||
S32 getWidth() const { return mWidth; }
|
||||
S32 getHeight() const { return mHeight; }
|
||||
protected:
|
||||
std::string mBodyRegion;
|
||||
S32 mWidth;
|
||||
S32 mHeight;
|
||||
@@ -259,78 +264,27 @@ private:
|
||||
//
|
||||
// The composite image that a LLTexLayerSet writes to. Each LLTexLayerSet has one.
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
class LLTexLayerSetBuffer : public LLViewerDynamicTexture
|
||||
class LLTexLayerSetBuffer : public virtual LLRefCount
|
||||
{
|
||||
LOG_CLASS(LLTexLayerSetBuffer);
|
||||
|
||||
public:
|
||||
LLTexLayerSetBuffer(LLTexLayerSet* const owner, S32 width, S32 height);
|
||||
LLTexLayerSetBuffer(LLTexLayerSet* const owner);
|
||||
virtual ~LLTexLayerSetBuffer();
|
||||
|
||||
public:
|
||||
/*virtual*/ S8 getType() const;
|
||||
BOOL isInitialized(void) const;
|
||||
static void dumpTotalByteCount();
|
||||
const std::string dumpTextureInfo() const;
|
||||
virtual void restoreGLTexture();
|
||||
virtual void destroyGLTexture();
|
||||
protected:
|
||||
void pushProjection() const;
|
||||
void popProjection() const;
|
||||
private:
|
||||
LLTexLayerSet* const mTexLayerSet;
|
||||
static S32 sGLByteCount;
|
||||
virtual void preRenderTexLayerSet();
|
||||
virtual void midRenderTexLayerSet(BOOL success) {}
|
||||
virtual void postRenderTexLayerSet(BOOL success);
|
||||
virtual S32 getCompositeOriginX() const = 0;
|
||||
virtual S32 getCompositeOriginY() const = 0;
|
||||
virtual S32 getCompositeWidth() const = 0;
|
||||
virtual S32 getCompositeHeight() const = 0;
|
||||
BOOL renderTexLayerSet();
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Render
|
||||
//--------------------------------------------------------------------
|
||||
public:
|
||||
/*virtual*/ BOOL needsRender();
|
||||
protected:
|
||||
BOOL render(S32 x, S32 y, S32 width, S32 height);
|
||||
virtual void preRender(BOOL clear_depth);
|
||||
virtual void postRender(BOOL success);
|
||||
virtual BOOL render();
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Uploads
|
||||
//--------------------------------------------------------------------
|
||||
public:
|
||||
void requestUpload();
|
||||
void cancelUpload();
|
||||
BOOL uploadNeeded() const; // We need to upload a new texture
|
||||
BOOL uploadInProgress() const; // We have started uploading a new texture and are awaiting the result
|
||||
BOOL uploadPending() const; // We are expecting a new texture to be uploaded at some point
|
||||
static void onTextureUploadComplete(const LLUUID& uuid,
|
||||
void* userdata,
|
||||
S32 result, LLExtStat ext_status);
|
||||
protected:
|
||||
BOOL isReadyToUpload() const;
|
||||
void doUpload(); // Does a read back and upload.
|
||||
void conditionalRestartUploadTimer();
|
||||
private:
|
||||
BOOL mNeedsUpload; // Whether we need to send our baked textures to the server
|
||||
U32 mNumLowresUploads; // Number of times we've sent a lowres version of our baked textures to the server
|
||||
BOOL mUploadPending; // Whether we have received back the new baked textures
|
||||
LLUUID mUploadID; // The current upload process (null if none).
|
||||
LLFrameTimer mNeedsUploadTimer; // Tracks time since upload was requested and performed.
|
||||
S32 mUploadFailCount; // Number of consecutive upload failures
|
||||
LLFrameTimer mUploadRetryTimer; // Tracks time since last upload failure.
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Updates
|
||||
//--------------------------------------------------------------------
|
||||
public:
|
||||
void requestUpdate();
|
||||
BOOL requestUpdateImmediate();
|
||||
protected:
|
||||
BOOL isReadyToUpdate() const;
|
||||
void doUpdate();
|
||||
void restartUpdateTimer();
|
||||
private:
|
||||
BOOL mNeedsUpdate; // Whether we need to locally update our baked textures
|
||||
U32 mNumLowresUpdates; // Number of times we've locally updated with lowres version of our baked textures
|
||||
LLFrameTimer mNeedsUpdateTimer; // Tracks time since update was requested and performed.
|
||||
LLTexLayerSet* const mTexLayerSet;
|
||||
};
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -342,7 +296,7 @@ class LLTexLayerStaticImageList : public LLSingleton<LLTexLayerStaticImageList>
|
||||
public:
|
||||
LLTexLayerStaticImageList();
|
||||
~LLTexLayerStaticImageList();
|
||||
LLViewerTexture* getTexture(const std::string& file_name, BOOL is_mask);
|
||||
LLGLTexture* getTexture(const std::string& file_name, BOOL is_mask);
|
||||
LLImageTGA* getImageTGA(const std::string& file_name);
|
||||
void deleteCachedImages();
|
||||
void dumpByteCount() const;
|
||||
@@ -350,7 +304,7 @@ protected:
|
||||
BOOL loadImageRaw(const std::string& file_name, LLImageRaw* image_raw);
|
||||
private:
|
||||
LLStringTable mImageNames;
|
||||
typedef std::map<const char*, LLPointer<LLViewerTexture> > texture_map_t;
|
||||
typedef std::map<const char*, LLPointer<LLGLTexture> > texture_map_t;
|
||||
texture_map_t mStaticImageList;
|
||||
typedef std::map<const char*, LLPointer<LLImageTGA> > image_tga_map_t;
|
||||
image_tga_map_t mStaticImageListTGA;
|
||||
@@ -358,23 +312,4 @@ private:
|
||||
S32 mTGABytes;
|
||||
};
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// LLBakedUploadData
|
||||
//
|
||||
// Used by LLTexLayerSetBuffer for a callback.
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
struct LLBakedUploadData
|
||||
{
|
||||
LLBakedUploadData(const LLVOAvatarSelf* avatar,
|
||||
LLTexLayerSet* layerset,
|
||||
const LLUUID& id,
|
||||
bool highest_res);
|
||||
~LLBakedUploadData() {}
|
||||
const LLUUID mID;
|
||||
const LLVOAvatarSelf* mAvatar; // note: backlink only; don't LLPointer
|
||||
LLTexLayerSet* mTexLayerSet;
|
||||
const U64 mStartTime; // for measuring baked texture upload time
|
||||
const bool mIsHighestRes; // whether this is a "final" bake, or intermediate low res
|
||||
};
|
||||
|
||||
#endif // LL_LLTEXLAYER_H
|
||||
@@ -24,27 +24,28 @@
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "lltexlayerparams.h"
|
||||
|
||||
#include "llagentcamera.h"
|
||||
#include "llavatarappearance.h"
|
||||
#include "llimagetga.h"
|
||||
#include "llquantize.h"
|
||||
#include "lltexlayer.h"
|
||||
#include "llvoavatarself.h"
|
||||
#include "lltexturemanagerbridge.h"
|
||||
#include "llrender2dutils.h"
|
||||
#include "llwearable.h"
|
||||
#include "llui.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLTexLayerParam
|
||||
//-----------------------------------------------------------------------------
|
||||
LLTexLayerParam::LLTexLayerParam(LLTexLayerInterface *layer) :
|
||||
mTexLayer(layer),
|
||||
mAvatar(NULL)
|
||||
mAvatarAppearance(NULL)
|
||||
{
|
||||
if (mTexLayer != NULL)
|
||||
{
|
||||
mAvatar = mTexLayer->getTexLayerSet()->getAvatar();
|
||||
mAvatarAppearance = mTexLayer->getTexLayerSet()->getAvatarAppearance();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -52,20 +53,21 @@ LLTexLayerParam::LLTexLayerParam(LLTexLayerInterface *layer) :
|
||||
}
|
||||
}
|
||||
|
||||
LLTexLayerParam::LLTexLayerParam(LLVOAvatar *avatar) :
|
||||
mTexLayer(NULL)
|
||||
LLTexLayerParam::LLTexLayerParam(LLAvatarAppearance *appearance) :
|
||||
mTexLayer(NULL),
|
||||
mAvatarAppearance(appearance)
|
||||
{
|
||||
mAvatar = avatar;
|
||||
}
|
||||
|
||||
|
||||
BOOL LLTexLayerParam::setInfo(LLViewerVisualParamInfo *info, BOOL add_to_avatar )
|
||||
{
|
||||
BOOL LLTexLayerParam::setInfo(LLViewerVisualParamInfo *info, BOOL add_to_appearance)
|
||||
{
|
||||
LLViewerVisualParam::setInfo(info);
|
||||
|
||||
if (add_to_avatar)
|
||||
if (add_to_appearance)
|
||||
{
|
||||
mAvatar->addVisualParam( this);
|
||||
mAvatarAppearance->addVisualParam( this);
|
||||
this->setParamLocation(mAvatarAppearance->isSelf() ? LOC_AV_SELF : LOC_AV_OTHER);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
@@ -96,7 +98,7 @@ void LLTexLayerParamAlpha::getCacheByteCount(S32* gl_bytes)
|
||||
iter != sInstances.end(); iter++)
|
||||
{
|
||||
LLTexLayerParamAlpha* instance = *iter;
|
||||
LLViewerTexture* tex = instance->mCachedProcessedTexture;
|
||||
LLGLTexture* tex = instance->mCachedProcessedTexture;
|
||||
if (tex)
|
||||
{
|
||||
S32 bytes = (S32)tex->getWidth() * tex->getHeight() * tex->getComponents();
|
||||
@@ -120,8 +122,8 @@ LLTexLayerParamAlpha::LLTexLayerParamAlpha(LLTexLayerInterface* layer) :
|
||||
sInstances.push_front(this);
|
||||
}
|
||||
|
||||
LLTexLayerParamAlpha::LLTexLayerParamAlpha(LLVOAvatar* avatar) :
|
||||
LLTexLayerParam(avatar),
|
||||
LLTexLayerParamAlpha::LLTexLayerParamAlpha(LLAvatarAppearance* appearance) :
|
||||
LLTexLayerParam(appearance),
|
||||
mCachedProcessedTexture(NULL),
|
||||
mNeedsCreateTexture(FALSE),
|
||||
mStaticImageInvalid(FALSE),
|
||||
@@ -173,13 +175,14 @@ void LLTexLayerParamAlpha::setWeight(F32 weight, BOOL upload_bake)
|
||||
{
|
||||
mCurWeight = new_weight;
|
||||
|
||||
if ((mAvatar->getSex() & getSex()) && (mAvatar->isSelf() && !mIsDummy)) // only trigger a baked texture update if we're changing a wearable's visual param.
|
||||
if ((mAvatarAppearance->getSex() & getSex()) &&
|
||||
(mAvatarAppearance->isSelf() && !mIsDummy)) // only trigger a baked texture update if we're changing a wearable's visual param.
|
||||
{
|
||||
if (isAgentAvatarValid() && !gAgentAvatarp->isUsingBakedTextures())
|
||||
if (mAvatarAppearance->isValid() && mAvatarAppearance->isEditingAppearance())
|
||||
{
|
||||
upload_bake = FALSE;
|
||||
}
|
||||
mAvatar->invalidateComposite(mTexLayer->getTexLayerSet(), upload_bake);
|
||||
mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet(), upload_bake);
|
||||
mTexLayer->invalidateMorphMasks();
|
||||
}
|
||||
}
|
||||
@@ -218,11 +221,11 @@ BOOL LLTexLayerParamAlpha::getSkip() const
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
const LLVOAvatar *avatar = mTexLayer->getTexLayerSet()->getAvatar();
|
||||
const LLAvatarAppearance *appearance = mTexLayer->getTexLayerSet()->getAvatarAppearance();
|
||||
|
||||
if (((LLTexLayerParamAlphaInfo *)getInfo())->mSkipIfZeroWeight)
|
||||
{
|
||||
F32 effective_weight = (avatar->getSex() & getSex()) ? mCurWeight : getDefaultWeight();
|
||||
F32 effective_weight = (appearance->getSex() & getSex()) ? mCurWeight : getDefaultWeight();
|
||||
if (is_approx_zero(effective_weight))
|
||||
{
|
||||
return TRUE;
|
||||
@@ -230,7 +233,7 @@ BOOL LLTexLayerParamAlpha::getSkip() const
|
||||
}
|
||||
|
||||
LLWearableType::EType type = (LLWearableType::EType)getWearableType();
|
||||
if ((type != LLWearableType::WT_INVALID) && !avatar->isWearingWearableType(type))
|
||||
if ((type != LLWearableType::WT_INVALID) && !appearance->isWearingWearableType(type))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
@@ -239,8 +242,10 @@ BOOL LLTexLayerParamAlpha::getSkip() const
|
||||
}
|
||||
|
||||
|
||||
static LLFastTimer::DeclareTimer FTM_TEX_LAYER_PARAM_ALPHA("alpha render");
|
||||
BOOL LLTexLayerParamAlpha::render(S32 x, S32 y, S32 width, S32 height)
|
||||
{
|
||||
LLFastTimer t(FTM_TEX_LAYER_PARAM_ALPHA);
|
||||
BOOL success = TRUE;
|
||||
|
||||
if (!mTexLayer)
|
||||
@@ -248,7 +253,7 @@ BOOL LLTexLayerParamAlpha::render(S32 x, S32 y, S32 width, S32 height)
|
||||
return success;
|
||||
}
|
||||
|
||||
F32 effective_weight = (mTexLayer->getTexLayerSet()->getAvatar()->getSex() & getSex()) ? mCurWeight : getDefaultWeight();
|
||||
F32 effective_weight = (mTexLayer->getTexLayerSet()->getAvatarAppearance()->getSex() & getSex()) ? mCurWeight : getDefaultWeight();
|
||||
BOOL weight_changed = effective_weight != mCachedEffectiveWeight;
|
||||
if (getSkip())
|
||||
{
|
||||
@@ -290,12 +295,12 @@ BOOL LLTexLayerParamAlpha::render(S32 x, S32 y, S32 width, S32 height)
|
||||
(mCachedProcessedTexture->getHeight() != image_tga_height) ||
|
||||
(weight_changed))
|
||||
{
|
||||
// llinfos << "Building Cached Alpha: " << mName << ": (" << mStaticImageRaw->getWidth() << ", " << mStaticImageRaw->getHeight() << ") " << effective_weight << llendl;
|
||||
mCachedEffectiveWeight = effective_weight;
|
||||
|
||||
if (!mCachedProcessedTexture)
|
||||
{
|
||||
mCachedProcessedTexture = LLViewerTextureManager::getLocalTexture(image_tga_width, image_tga_height, 1, FALSE);
|
||||
llassert(gTextureManagerBridgep);
|
||||
mCachedProcessedTexture = gTextureManagerBridgep->getLocalTexture(image_tga_width, image_tga_height, 1, FALSE);
|
||||
|
||||
// We now have something in one of our caches
|
||||
LLTexLayerSet::sHasCaches |= mCachedProcessedTexture ? TRUE : FALSE;
|
||||
@@ -308,6 +313,7 @@ BOOL LLTexLayerParamAlpha::render(S32 x, S32 y, S32 width, S32 height)
|
||||
mStaticImageRaw = new LLImageRaw;
|
||||
mStaticImageTGA->decodeAndProcess(mStaticImageRaw, info->mDomain, effective_weight);
|
||||
mNeedsCreateTexture = TRUE;
|
||||
lldebugs << "Built Cached Alpha: " << info->mStaticImageFileName << ": (" << mStaticImageRaw->getWidth() << ", " << mStaticImageRaw->getHeight() << ") " << "Domain: " << info->mDomain << " Weight: " << effective_weight << llendl;
|
||||
}
|
||||
|
||||
if (mCachedProcessedTexture)
|
||||
@@ -332,7 +338,7 @@ BOOL LLTexLayerParamAlpha::render(S32 x, S32 y, S32 width, S32 height)
|
||||
|
||||
// Don't keep the cache for other people's avatars
|
||||
// (It's not really a "cache" in that case, but the logic is the same)
|
||||
if (!mAvatar->isSelf())
|
||||
if (!mAvatarAppearance->isSelf())
|
||||
{
|
||||
mCachedProcessedTexture = NULL;
|
||||
}
|
||||
@@ -402,8 +408,8 @@ LLTexLayerParamColor::LLTexLayerParamColor(LLTexLayerInterface* layer) :
|
||||
{
|
||||
}
|
||||
|
||||
LLTexLayerParamColor::LLTexLayerParamColor(LLVOAvatar *avatar) :
|
||||
LLTexLayerParam(avatar),
|
||||
LLTexLayerParamColor::LLTexLayerParamColor(LLAvatarAppearance *appearance) :
|
||||
LLTexLayerParam(appearance),
|
||||
mAvgDistortionVec(1.f, 1.f, 1.f)
|
||||
{
|
||||
}
|
||||
@@ -425,7 +431,7 @@ LLColor4 LLTexLayerParamColor::getNetColor() const
|
||||
|
||||
llassert(info->mNumColors >= 1);
|
||||
|
||||
F32 effective_weight = (mAvatar && (mAvatar->getSex() & getSex())) ? mCurWeight : getDefaultWeight();
|
||||
F32 effective_weight = (mAvatarAppearance && (mAvatarAppearance->getSex() & getSex())) ? mCurWeight : getDefaultWeight();
|
||||
|
||||
S32 index_last = info->mNumColors - 1;
|
||||
F32 scaled_weight = effective_weight * index_last;
|
||||
@@ -470,12 +476,12 @@ void LLTexLayerParamColor::setWeight(F32 weight, BOOL upload_bake)
|
||||
return;
|
||||
}
|
||||
|
||||
if ((mAvatar->getSex() & getSex()) && (mAvatar->isSelf() && !mIsDummy)) // only trigger a baked texture update if we're changing a wearable's visual param.
|
||||
if ((mAvatarAppearance->getSex() & getSex()) && (mAvatarAppearance->isSelf() && !mIsDummy)) // only trigger a baked texture update if we're changing a wearable's visual param.
|
||||
{
|
||||
onGlobalColorChanged(upload_bake);
|
||||
if (mTexLayer)
|
||||
{
|
||||
mAvatar->invalidateComposite(mTexLayer->getTexLayerSet(), upload_bake);
|
||||
mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet(), upload_bake);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,14 +27,16 @@
|
||||
#ifndef LL_LLTEXLAYERPARAMS_H
|
||||
#define LL_LLTEXLAYERPARAMS_H
|
||||
|
||||
#include "llpointer.h"
|
||||
#include "v4color.h"
|
||||
#include "llviewervisualparam.h"
|
||||
|
||||
class LLAvatarAppearance;
|
||||
class LLImageRaw;
|
||||
class LLImageTGA;
|
||||
class LLTexLayer;
|
||||
class LLTexLayerInterface;
|
||||
class LLViewerTexture;
|
||||
class LLVOAvatar;
|
||||
class LLGLTexture;
|
||||
class LLWearable;
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -45,13 +47,13 @@ class LLTexLayerParam : public LLViewerVisualParam
|
||||
{
|
||||
public:
|
||||
LLTexLayerParam(LLTexLayerInterface *layer);
|
||||
LLTexLayerParam(LLVOAvatar *avatar);
|
||||
/*virtual*/ BOOL setInfo(LLViewerVisualParamInfo *info, BOOL add_to_avatar );
|
||||
LLTexLayerParam(LLAvatarAppearance *appearance);
|
||||
/*virtual*/ BOOL setInfo(LLViewerVisualParamInfo *info, BOOL add_to_appearance);
|
||||
/*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const = 0;
|
||||
|
||||
protected:
|
||||
LLTexLayerInterface* mTexLayer;
|
||||
LLVOAvatar* mAvatar;
|
||||
LLAvatarAppearance* mAvatarAppearance;
|
||||
};
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -62,7 +64,7 @@ class LLTexLayerParamAlpha : public LLTexLayerParam
|
||||
{
|
||||
public:
|
||||
LLTexLayerParamAlpha( LLTexLayerInterface* layer );
|
||||
LLTexLayerParamAlpha( LLVOAvatar* avatar );
|
||||
LLTexLayerParamAlpha( LLAvatarAppearance* appearance );
|
||||
/*virtual*/ ~LLTexLayerParamAlpha();
|
||||
|
||||
/*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable = NULL) const;
|
||||
@@ -99,7 +101,7 @@ public:
|
||||
BOOL getMultiplyBlend() const;
|
||||
|
||||
private:
|
||||
LLPointer<LLViewerTexture> mCachedProcessedTexture;
|
||||
LLPointer<LLGLTexture> mCachedProcessedTexture;
|
||||
LLPointer<LLImageTGA> mStaticImageTGA;
|
||||
LLPointer<LLImageRaw> mStaticImageRaw;
|
||||
BOOL mNeedsCreateTexture;
|
||||
@@ -150,7 +152,7 @@ public:
|
||||
};
|
||||
|
||||
LLTexLayerParamColor( LLTexLayerInterface* layer );
|
||||
LLTexLayerParamColor( LLVOAvatar* avatar );
|
||||
LLTexLayerParamColor( LLAvatarAppearance* appearance );
|
||||
/* virtual */ ~LLTexLayerParamColor();
|
||||
|
||||
void* operator new(size_t size)
|
||||
33
indra/llappearance/lltexturemanagerbridge.cpp
Normal file
33
indra/llappearance/lltexturemanagerbridge.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* @file lltexturemanagerbridge.cpp
|
||||
* @brief Defined a null texture manager bridge. Applications must provide their own bridge implementaton.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
#include "lltexturemanagerbridge.h"
|
||||
|
||||
// Define a null texture manager bridge. Applications must provide their own bridge implementaton.
|
||||
LLTextureManagerBridge* gTextureManagerBridgep = NULL;
|
||||
|
||||
|
||||
47
indra/llappearance/lltexturemanagerbridge.h
Normal file
47
indra/llappearance/lltexturemanagerbridge.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* @file lltexturemanagerbridge.h
|
||||
* @brief Bridge to an application-specific texture manager.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_TEXTUREMANAGERBRIDGE_H
|
||||
#define LL_TEXTUREMANAGERBRIDGE_H
|
||||
|
||||
#include "llavatarappearancedefines.h"
|
||||
#include "llpointer.h"
|
||||
#include "llgltexture.h"
|
||||
|
||||
// Abstract bridge interface
|
||||
class LLTextureManagerBridge
|
||||
{
|
||||
public:
|
||||
virtual ~LLTextureManagerBridge(){};
|
||||
virtual LLPointer<LLGLTexture> getLocalTexture(BOOL usemipmaps = TRUE, BOOL generate_gl_tex = TRUE) = 0;
|
||||
virtual LLPointer<LLGLTexture> getLocalTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps, BOOL generate_gl_tex = TRUE) = 0;
|
||||
virtual LLGLTexture* getFetchedTexture(const LLUUID &image_id) = 0;
|
||||
};
|
||||
|
||||
extern LLTextureManagerBridge* gTextureManagerBridgep;
|
||||
|
||||
#endif // LL_TEXTUREMANAGERBRIDGE_H
|
||||
|
||||
@@ -2,42 +2,35 @@
|
||||
* @file llviewervisualparam.cpp
|
||||
* @brief Implementation of LLViewerVisualParam class
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2001-2009, Linden Research, Inc.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Header Files
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llviewervisualparam.h"
|
||||
#include "llxmltree.h"
|
||||
#include "llui.h"
|
||||
#include "llwearable.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
820
indra/llappearance/llwearable.cpp
Normal file
820
indra/llappearance/llwearable.cpp
Normal file
@@ -0,0 +1,820 @@
|
||||
/**
|
||||
* @file llwearable.cpp
|
||||
* @brief LLWearable class implementation
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llavatarappearance.h"
|
||||
#include "lllocaltextureobject.h"
|
||||
#include "lltexlayer.h"
|
||||
#include "lltexturemanagerbridge.h"
|
||||
#include "llvisualparam.h"
|
||||
#include "llavatarappearancedefines.h"
|
||||
#include "llwearable.h"
|
||||
|
||||
using namespace LLAvatarAppearanceDefines;
|
||||
|
||||
// static
|
||||
S32 LLWearable::sCurrentDefinitionVersion = 1;
|
||||
|
||||
// Private local functions
|
||||
static std::string terse_F32_to_string(F32 f);
|
||||
|
||||
LLWearable::LLWearable() :
|
||||
mDefinitionVersion(0),
|
||||
mType(LLWearableType::WT_INVALID)
|
||||
{
|
||||
}
|
||||
|
||||
// virtual
|
||||
LLWearable::~LLWearable()
|
||||
{
|
||||
}
|
||||
|
||||
const std::string& LLWearable::getTypeLabel() const
|
||||
{
|
||||
return LLWearableType::getTypeLabel(mType);
|
||||
}
|
||||
|
||||
const std::string& LLWearable::getTypeName() const
|
||||
{
|
||||
return LLWearableType::getTypeName(mType);
|
||||
}
|
||||
|
||||
LLAssetType::EType LLWearable::getAssetType() const
|
||||
{
|
||||
return LLWearableType::getAssetType(mType);
|
||||
}
|
||||
|
||||
// reX: new function
|
||||
BOOL LLWearable::FileExportParams( FILE* file ) const
|
||||
{
|
||||
// wearable type
|
||||
S32 type = (S32)mType;
|
||||
fprintf( file, "type %d\n", type );
|
||||
|
||||
// parameters
|
||||
S32 num_parameters = mVisualParamIndexMap.size();
|
||||
fprintf( file, "parameters %d\n", num_parameters );
|
||||
|
||||
for (visual_param_index_map_t::const_iterator iter = mVisualParamIndexMap.begin();
|
||||
iter != mVisualParamIndexMap.end(); ++iter)
|
||||
{
|
||||
S32 param_id = iter->first;
|
||||
F32 param_weight = iter->second->getWeight();
|
||||
fprintf( file, "%d %s\n", param_id, terse_F32_to_string(param_weight).c_str() );
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// reX: new function
|
||||
BOOL LLWearable::FileExportTextures( FILE* file ) const
|
||||
{
|
||||
// wearable type
|
||||
S32 type = (S32)mType;
|
||||
fprintf( file, "type %d\n", type );
|
||||
|
||||
// texture entries
|
||||
S32 num_textures = mTEMap.size();
|
||||
fprintf( file, "textures %d\n", num_textures );
|
||||
|
||||
for (te_map_t::const_iterator iter = mTEMap.begin();
|
||||
iter != mTEMap.end(); ++iter)
|
||||
{
|
||||
S32 te = iter->first;
|
||||
fprintf( file, "%d %s\n", te, iter->second->getID().asString().c_str() );
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL LLWearable::exportFile(LLFILE* fp) const
|
||||
{
|
||||
llofstream ofs(fp);
|
||||
return exportStream(ofs);
|
||||
}
|
||||
|
||||
// virtual
|
||||
BOOL LLWearable::exportStream( std::ostream& output_stream ) const
|
||||
{
|
||||
if (!output_stream.good()) return FALSE;
|
||||
|
||||
// header and version
|
||||
output_stream << "LLWearable version " << mDefinitionVersion << "\n";
|
||||
// name
|
||||
output_stream << mName << "\n";
|
||||
// description
|
||||
output_stream << mDescription << "\n";
|
||||
|
||||
// permissions
|
||||
if( !mPermissions.exportStream( output_stream ) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// sale info
|
||||
if( !mSaleInfo.exportStream( output_stream ) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// wearable type
|
||||
output_stream << "type " << (S32) getType() << "\n";
|
||||
|
||||
// parameters
|
||||
output_stream << "parameters " << mVisualParamIndexMap.size() << "\n";
|
||||
|
||||
for (visual_param_index_map_t::const_iterator iter = mVisualParamIndexMap.begin();
|
||||
iter != mVisualParamIndexMap.end();
|
||||
++iter)
|
||||
{
|
||||
S32 param_id = iter->first;
|
||||
const LLVisualParam* param = iter->second;
|
||||
F32 param_weight = param->getWeight();
|
||||
output_stream << param_id << " " << terse_F32_to_string( param_weight ) << "\n";
|
||||
}
|
||||
|
||||
// texture entries
|
||||
output_stream << "textures " << mTEMap.size() << "\n";
|
||||
|
||||
for (te_map_t::const_iterator iter = mTEMap.begin(); iter != mTEMap.end(); ++iter)
|
||||
{
|
||||
S32 te = iter->first;
|
||||
const LLUUID& image_id = iter->second->getID();
|
||||
output_stream << te << " " << image_id << "\n";
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void LLWearable::createVisualParams(LLAvatarAppearance *avatarp)
|
||||
{
|
||||
for (LLViewerVisualParam* param = (LLViewerVisualParam*) avatarp->getFirstVisualParam();
|
||||
param;
|
||||
param = (LLViewerVisualParam*) avatarp->getNextVisualParam())
|
||||
{
|
||||
if (param->getWearableType() == mType)
|
||||
{
|
||||
LLVisualParam *clone_param = param->cloneParam(this);
|
||||
clone_param->setParamLocation(LOC_UNKNOWN);
|
||||
clone_param->setParamLocation(LOC_WEARABLE);
|
||||
addVisualParam(clone_param);
|
||||
}
|
||||
}
|
||||
|
||||
// resync driver parameters to point to the newly cloned driven parameters
|
||||
for (visual_param_index_map_t::iterator param_iter = mVisualParamIndexMap.begin();
|
||||
param_iter != mVisualParamIndexMap.end();
|
||||
++param_iter)
|
||||
{
|
||||
LLVisualParam* param = param_iter->second;
|
||||
LLVisualParam*(LLWearable::*wearable_function)(S32)const = &LLWearable::getVisualParam;
|
||||
// need this line to disambiguate between versions of LLCharacter::getVisualParam()
|
||||
LLVisualParam*(LLAvatarAppearance::*param_function)(S32)const = &LLAvatarAppearance::getVisualParam;
|
||||
param->resetDrivenParams();
|
||||
if(!param->linkDrivenParams(boost::bind(wearable_function,(LLWearable*)this, _1), false))
|
||||
{
|
||||
if( !param->linkDrivenParams(boost::bind(param_function,avatarp,_1 ), true))
|
||||
{
|
||||
llwarns << "could not link driven params for wearable " << getName() << " id: " << param->getID() << llendl;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLWearable::createLayers(S32 te, LLAvatarAppearance *avatarp)
|
||||
{
|
||||
LLTexLayerSet *layer_set = NULL;
|
||||
const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = LLAvatarAppearanceDictionary::getInstance()->getTexture((ETextureIndex)te);
|
||||
if (texture_dict->mIsUsedByBakedTexture)
|
||||
{
|
||||
const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex;
|
||||
|
||||
layer_set = avatarp->getAvatarLayerSet(baked_index);
|
||||
}
|
||||
|
||||
if (layer_set)
|
||||
{
|
||||
layer_set->cloneTemplates(mTEMap[te], (ETextureIndex)te, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
llerrs << "could not find layerset for LTO in wearable!" << llendl;
|
||||
}
|
||||
}
|
||||
|
||||
LLWearable::EImportResult LLWearable::importFile(LLFILE* fp, LLAvatarAppearance* avatarp )
|
||||
{
|
||||
llifstream ifs(fp);
|
||||
return importStream(ifs, avatarp);
|
||||
}
|
||||
|
||||
// virtual
|
||||
LLWearable::EImportResult LLWearable::importStream( std::istream& input_stream, LLAvatarAppearance* avatarp )
|
||||
{
|
||||
// *NOTE: changing the type or size of this buffer will require
|
||||
// changes in the fscanf() code below.
|
||||
// We are using a local max buffer size here to avoid issues
|
||||
// if MAX_STRING size changes.
|
||||
const U32 PARSE_BUFFER_SIZE = 2048;
|
||||
char buffer[2048]; /* Flawfinder: ignore */
|
||||
char uuid_buffer[37]; /* Flawfinder: ignore */
|
||||
|
||||
// This data is being generated on the viewer.
|
||||
// Impose some sane limits on parameter and texture counts.
|
||||
const S32 MAX_WEARABLE_ASSET_TEXTURES = 100;
|
||||
const S32 MAX_WEARABLE_ASSET_PARAMETERS = 1000;
|
||||
|
||||
if(!avatarp)
|
||||
{
|
||||
return LLWearable::FAILURE;
|
||||
}
|
||||
|
||||
// read header and version
|
||||
if (!input_stream.good())
|
||||
{
|
||||
llwarns << "Failed to read wearable asset input stream." << llendl;
|
||||
return LLWearable::FAILURE;
|
||||
}
|
||||
input_stream.getline(buffer, PARSE_BUFFER_SIZE);
|
||||
if ( 1 != sscanf( /* Flawfinder: ignore */
|
||||
buffer,
|
||||
"LLWearable version %d\n",
|
||||
&mDefinitionVersion ) )
|
||||
{
|
||||
return LLWearable::BAD_HEADER;
|
||||
}
|
||||
|
||||
// Hack to allow wearables with definition version 24 to still load.
|
||||
// This should only affect lindens and NDA'd testers who have saved wearables in 2.0
|
||||
// the extra check for version == 24 can be removed before release, once internal testers
|
||||
// have loaded these wearables again. See hack pt 2 at bottom of function to ensure that
|
||||
// these wearables get re-saved with version definition 22.
|
||||
if( mDefinitionVersion > LLWearable::sCurrentDefinitionVersion && mDefinitionVersion != 24 )
|
||||
{
|
||||
llwarns << "Wearable asset has newer version (" << mDefinitionVersion << ") than XML (" << LLWearable::sCurrentDefinitionVersion << ")" << llendl;
|
||||
return LLWearable::FAILURE;
|
||||
}
|
||||
|
||||
// name
|
||||
if (!input_stream.good())
|
||||
{
|
||||
llwarns << "Bad Wearable asset: early end of input stream "
|
||||
<< "while reading name" << llendl;
|
||||
return LLWearable::FAILURE;
|
||||
}
|
||||
input_stream.getline(buffer, PARSE_BUFFER_SIZE);
|
||||
mName = buffer;
|
||||
|
||||
// description
|
||||
if (!input_stream.good())
|
||||
{
|
||||
llwarns << "Bad Wearable asset: early end of input stream "
|
||||
<< "while reading description" << llendl;
|
||||
return LLWearable::FAILURE;
|
||||
}
|
||||
input_stream.getline(buffer, PARSE_BUFFER_SIZE);
|
||||
mDescription = buffer;
|
||||
|
||||
// permissions
|
||||
if (!input_stream.good())
|
||||
{
|
||||
llwarns << "Bad Wearable asset: early end of input stream "
|
||||
<< "while reading permissions" << llendl;
|
||||
return LLWearable::FAILURE;
|
||||
}
|
||||
input_stream.getline(buffer, PARSE_BUFFER_SIZE);
|
||||
S32 perm_version = -1;
|
||||
if ( 1 != sscanf( buffer, " permissions %d\n", &perm_version ) ||
|
||||
perm_version != 0 )
|
||||
{
|
||||
llwarns << "Bad Wearable asset: missing valid permissions" << llendl;
|
||||
return LLWearable::FAILURE;
|
||||
}
|
||||
if( !mPermissions.importStream( input_stream ) )
|
||||
{
|
||||
return LLWearable::FAILURE;
|
||||
}
|
||||
|
||||
// sale info
|
||||
if (!input_stream.good())
|
||||
{
|
||||
llwarns << "Bad Wearable asset: early end of input stream "
|
||||
<< "while reading sale info" << llendl;
|
||||
return LLWearable::FAILURE;
|
||||
}
|
||||
input_stream.getline(buffer, PARSE_BUFFER_SIZE);
|
||||
S32 sale_info_version = -1;
|
||||
if ( 1 != sscanf( buffer, " sale_info %d\n", &sale_info_version ) ||
|
||||
sale_info_version != 0 )
|
||||
{
|
||||
llwarns << "Bad Wearable asset: missing valid sale_info" << llendl;
|
||||
return LLWearable::FAILURE;
|
||||
}
|
||||
// Sale info used to contain next owner perm. It is now in the
|
||||
// permissions. Thus, we read that out, and fix legacy
|
||||
// objects. It's possible this op would fail, but it should pick
|
||||
// up the vast majority of the tasks.
|
||||
BOOL has_perm_mask = FALSE;
|
||||
U32 perm_mask = 0;
|
||||
if( !mSaleInfo.importStream(input_stream, has_perm_mask, perm_mask) )
|
||||
{
|
||||
return LLWearable::FAILURE;
|
||||
}
|
||||
if(has_perm_mask)
|
||||
{
|
||||
// fair use fix.
|
||||
if(!(perm_mask & PERM_COPY))
|
||||
{
|
||||
perm_mask |= PERM_TRANSFER;
|
||||
}
|
||||
mPermissions.setMaskNext(perm_mask);
|
||||
}
|
||||
|
||||
// wearable type
|
||||
if (!input_stream.good())
|
||||
{
|
||||
llwarns << "Bad Wearable asset: early end of input stream "
|
||||
<< "while reading type" << llendl;
|
||||
return LLWearable::FAILURE;
|
||||
}
|
||||
input_stream.getline(buffer, PARSE_BUFFER_SIZE);
|
||||
S32 type = -1;
|
||||
if ( 1 != sscanf( buffer, "type %d\n", &type ) )
|
||||
{
|
||||
llwarns << "Bad Wearable asset: bad type" << llendl;
|
||||
return LLWearable::FAILURE;
|
||||
}
|
||||
if( 0 <= type && type < LLWearableType::WT_COUNT )
|
||||
{
|
||||
setType((LLWearableType::EType)type, avatarp);
|
||||
}
|
||||
else
|
||||
{
|
||||
mType = LLWearableType::WT_COUNT;
|
||||
llwarns << "Bad Wearable asset: bad type #" << type << llendl;
|
||||
return LLWearable::FAILURE;
|
||||
}
|
||||
|
||||
// parameters header
|
||||
if (!input_stream.good())
|
||||
{
|
||||
llwarns << "Bad Wearable asset: early end of input stream "
|
||||
<< "while reading parameters header" << llendl;
|
||||
return LLWearable::FAILURE;
|
||||
}
|
||||
input_stream.getline(buffer, PARSE_BUFFER_SIZE);
|
||||
S32 num_parameters = -1;
|
||||
if ( 1 != sscanf( buffer, "parameters %d\n", &num_parameters ) )
|
||||
{
|
||||
llwarns << "Bad Wearable asset: missing parameters block" << llendl;
|
||||
return LLWearable::FAILURE;
|
||||
}
|
||||
if ( num_parameters > MAX_WEARABLE_ASSET_PARAMETERS )
|
||||
{
|
||||
llwarns << "Bad Wearable asset: too many parameters, "
|
||||
<< num_parameters << llendl;
|
||||
return LLWearable::FAILURE;
|
||||
}
|
||||
if( num_parameters != mVisualParamIndexMap.size() )
|
||||
{
|
||||
llwarns << "Wearable parameter mismatch. Reading in "
|
||||
<< num_parameters << " from file, but created "
|
||||
<< mVisualParamIndexMap.size()
|
||||
<< " from avatar parameters. type: "
|
||||
<< getType() << llendl;
|
||||
}
|
||||
|
||||
// parameters
|
||||
S32 i;
|
||||
for( i = 0; i < num_parameters; i++ )
|
||||
{
|
||||
if (!input_stream.good())
|
||||
{
|
||||
llwarns << "Bad Wearable asset: early end of input stream "
|
||||
<< "while reading parameter #" << i << llendl;
|
||||
return LLWearable::FAILURE;
|
||||
}
|
||||
input_stream.getline(buffer, PARSE_BUFFER_SIZE);
|
||||
S32 param_id = 0;
|
||||
F32 param_weight = 0.f;
|
||||
if ( 2 != sscanf( buffer, "%d %f\n", ¶m_id, ¶m_weight ) )
|
||||
{
|
||||
llwarns << "Bad Wearable asset: bad parameter, #" << i << llendl;
|
||||
return LLWearable::FAILURE;
|
||||
}
|
||||
mSavedVisualParamMap[param_id] = param_weight;
|
||||
}
|
||||
|
||||
// textures header
|
||||
if (!input_stream.good())
|
||||
{
|
||||
llwarns << "Bad Wearable asset: early end of input stream "
|
||||
<< "while reading textures header" << i << llendl;
|
||||
return LLWearable::FAILURE;
|
||||
}
|
||||
input_stream.getline(buffer, PARSE_BUFFER_SIZE);
|
||||
S32 num_textures = -1;
|
||||
if ( 1 != sscanf( buffer, "textures %d\n", &num_textures) )
|
||||
{
|
||||
llwarns << "Bad Wearable asset: missing textures block" << llendl;
|
||||
return LLWearable::FAILURE;
|
||||
}
|
||||
if ( num_textures > MAX_WEARABLE_ASSET_TEXTURES )
|
||||
{
|
||||
llwarns << "Bad Wearable asset: too many textures, "
|
||||
<< num_textures << llendl;
|
||||
return LLWearable::FAILURE;
|
||||
}
|
||||
|
||||
// textures
|
||||
for( i = 0; i < num_textures; i++ )
|
||||
{
|
||||
if (!input_stream.good())
|
||||
{
|
||||
llwarns << "Bad Wearable asset: early end of input stream "
|
||||
<< "while reading textures #" << i << llendl;
|
||||
return LLWearable::FAILURE;
|
||||
}
|
||||
input_stream.getline(buffer, PARSE_BUFFER_SIZE);
|
||||
S32 te = 0;
|
||||
if ( 2 != sscanf( /* Flawfinder: ignore */
|
||||
buffer,
|
||||
"%d %36s\n",
|
||||
&te, uuid_buffer) )
|
||||
{
|
||||
llwarns << "Bad Wearable asset: bad texture, #" << i << llendl;
|
||||
return LLWearable::FAILURE;
|
||||
}
|
||||
|
||||
if( !LLUUID::validate( uuid_buffer ) )
|
||||
{
|
||||
llwarns << "Bad Wearable asset: bad texture uuid: "
|
||||
<< uuid_buffer << llendl;
|
||||
return LLWearable::FAILURE;
|
||||
}
|
||||
LLUUID id = LLUUID(uuid_buffer);
|
||||
LLGLTexture* image = gTextureManagerBridgep->getFetchedTexture( id );
|
||||
if( mTEMap.find(te) != mTEMap.end() )
|
||||
{
|
||||
delete mTEMap[te];
|
||||
}
|
||||
if( mSavedTEMap.find(te) != mSavedTEMap.end() )
|
||||
{
|
||||
delete mSavedTEMap[te];
|
||||
}
|
||||
|
||||
LLUUID textureid(uuid_buffer);
|
||||
mTEMap[te] = new LLLocalTextureObject(image, textureid);
|
||||
mSavedTEMap[te] = new LLLocalTextureObject(image, textureid);
|
||||
createLayers(te, avatarp);
|
||||
}
|
||||
|
||||
// copy all saved param values to working params
|
||||
revertValues();
|
||||
|
||||
return LLWearable::SUCCESS;
|
||||
}
|
||||
|
||||
void LLWearable::setType(LLWearableType::EType type, LLAvatarAppearance *avatarp)
|
||||
{
|
||||
mType = type;
|
||||
createVisualParams(avatarp);
|
||||
}
|
||||
|
||||
|
||||
LLLocalTextureObject* LLWearable::getLocalTextureObject(S32 index)
|
||||
{
|
||||
te_map_t::iterator iter = mTEMap.find(index);
|
||||
if( iter != mTEMap.end() )
|
||||
{
|
||||
LLLocalTextureObject* lto = iter->second;
|
||||
return lto;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const LLLocalTextureObject* LLWearable::getLocalTextureObject(S32 index) const
|
||||
{
|
||||
te_map_t::const_iterator iter = mTEMap.find(index);
|
||||
if( iter != mTEMap.end() )
|
||||
{
|
||||
const LLLocalTextureObject* lto = iter->second;
|
||||
return lto;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
std::vector<LLLocalTextureObject*> LLWearable::getLocalTextureListSeq()
|
||||
{
|
||||
std::vector<LLLocalTextureObject*> result;
|
||||
|
||||
for(te_map_t::const_iterator iter = mTEMap.begin();
|
||||
iter != mTEMap.end(); iter++)
|
||||
{
|
||||
LLLocalTextureObject* lto = iter->second;
|
||||
result.push_back(lto);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void LLWearable::setLocalTextureObject(S32 index, LLLocalTextureObject <o)
|
||||
{
|
||||
if( mTEMap.find(index) != mTEMap.end() )
|
||||
{
|
||||
mTEMap.erase(index);
|
||||
}
|
||||
mTEMap[index] = new LLLocalTextureObject(lto);
|
||||
}
|
||||
|
||||
void LLWearable::revertValues()
|
||||
{
|
||||
// FIXME DRANO - this triggers changes to driven params on avatar, potentially clobbering baked appearance.
|
||||
|
||||
//update saved settings so wearable is no longer dirty
|
||||
// non-driver params first
|
||||
for (param_map_t::const_iterator iter = mSavedVisualParamMap.begin(); iter != mSavedVisualParamMap.end(); iter++)
|
||||
{
|
||||
S32 id = iter->first;
|
||||
F32 value = iter->second;
|
||||
LLVisualParam *param = getVisualParam(id);
|
||||
if(param && !dynamic_cast<LLDriverParam*>(param) )
|
||||
{
|
||||
setVisualParamWeight(id, value, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
//then driver params
|
||||
for (param_map_t::const_iterator iter = mSavedVisualParamMap.begin(); iter != mSavedVisualParamMap.end(); iter++)
|
||||
{
|
||||
S32 id = iter->first;
|
||||
F32 value = iter->second;
|
||||
LLVisualParam *param = getVisualParam(id);
|
||||
if(param && dynamic_cast<LLDriverParam*>(param) )
|
||||
{
|
||||
setVisualParamWeight(id, value, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
// make sure that saved values are sane
|
||||
for (param_map_t::const_iterator iter = mSavedVisualParamMap.begin(); iter != mSavedVisualParamMap.end(); iter++)
|
||||
{
|
||||
S32 id = iter->first;
|
||||
LLVisualParam *param = getVisualParam(id);
|
||||
if( param )
|
||||
{
|
||||
mSavedVisualParamMap[id] = param->getWeight();
|
||||
}
|
||||
}
|
||||
|
||||
syncImages(mSavedTEMap, mTEMap);
|
||||
}
|
||||
|
||||
void LLWearable::saveValues()
|
||||
{
|
||||
//update saved settings so wearable is no longer dirty
|
||||
mSavedVisualParamMap.clear();
|
||||
for (visual_param_index_map_t::const_iterator iter = mVisualParamIndexMap.begin(); iter != mVisualParamIndexMap.end(); ++iter)
|
||||
{
|
||||
S32 id = iter->first;
|
||||
LLVisualParam *wearable_param = iter->second;
|
||||
F32 value = wearable_param->getWeight();
|
||||
mSavedVisualParamMap[id] = value;
|
||||
}
|
||||
|
||||
// Deep copy of mTEMap (copies only those tes that are current, filling in defaults where needed)
|
||||
syncImages(mTEMap, mSavedTEMap);
|
||||
}
|
||||
|
||||
void LLWearable::syncImages(te_map_t &src, te_map_t &dst)
|
||||
{
|
||||
// Deep copy of src (copies only those tes that are current, filling in defaults where needed)
|
||||
for( S32 te = 0; te < TEX_NUM_INDICES; te++ )
|
||||
{
|
||||
if (LLAvatarAppearanceDictionary::getTEWearableType((ETextureIndex) te) == mType)
|
||||
{
|
||||
te_map_t::const_iterator iter = src.find(te);
|
||||
LLUUID image_id;
|
||||
LLGLTexture *image = NULL;
|
||||
LLLocalTextureObject *lto = NULL;
|
||||
if(iter != src.end())
|
||||
{
|
||||
// there's a Local Texture Object in the source image map. Use this to populate the values to store in the destination image map.
|
||||
lto = iter->second;
|
||||
image = lto->getImage();
|
||||
image_id = lto->getID();
|
||||
}
|
||||
else
|
||||
{
|
||||
// there is no Local Texture Object in the source image map. Get defaults values for populating the destination image map.
|
||||
image_id = getDefaultTextureImageID((ETextureIndex) te);
|
||||
image = gTextureManagerBridgep->getFetchedTexture( image_id );
|
||||
}
|
||||
|
||||
if( dst.find(te) != dst.end() )
|
||||
{
|
||||
// there's already an entry in the destination map for the texture. Just update its values.
|
||||
dst[te]->setImage(image);
|
||||
dst[te]->setID(image_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
// no entry found in the destination map, we need to create a new Local Texture Object
|
||||
dst[te] = new LLLocalTextureObject(image, image_id);
|
||||
}
|
||||
|
||||
if( lto )
|
||||
{
|
||||
// If we pulled values from a Local Texture Object in the source map, make sure the proper flags are set in the new (or updated) entry in the destination map.
|
||||
dst[te]->setBakedReady(lto->getBakedReady());
|
||||
dst[te]->setDiscard(lto->getDiscard());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLWearable::destroyTextures()
|
||||
{
|
||||
for( te_map_t::iterator iter = mTEMap.begin(); iter != mTEMap.end(); ++iter )
|
||||
{
|
||||
LLLocalTextureObject *lto = iter->second;
|
||||
delete lto;
|
||||
}
|
||||
mTEMap.clear();
|
||||
for( te_map_t::iterator iter = mSavedTEMap.begin(); iter != mSavedTEMap.end(); ++iter )
|
||||
{
|
||||
LLLocalTextureObject *lto = iter->second;
|
||||
delete lto;
|
||||
}
|
||||
mSavedTEMap.clear();
|
||||
}
|
||||
|
||||
void LLWearable::addVisualParam(LLVisualParam *param)
|
||||
{
|
||||
if( mVisualParamIndexMap[param->getID()] )
|
||||
{
|
||||
delete mVisualParamIndexMap[param->getID()];
|
||||
}
|
||||
param->setIsDummy(FALSE);
|
||||
param->setParamLocation(LOC_WEARABLE);
|
||||
mVisualParamIndexMap[param->getID()] = param;
|
||||
mSavedVisualParamMap[param->getID()] = param->getDefaultWeight();
|
||||
}
|
||||
|
||||
|
||||
void LLWearable::setVisualParamWeight(S32 param_index, F32 value, BOOL upload_bake)
|
||||
{
|
||||
if( is_in_map(mVisualParamIndexMap, param_index ) )
|
||||
{
|
||||
LLVisualParam *wearable_param = mVisualParamIndexMap[param_index];
|
||||
wearable_param->setWeight(value, upload_bake);
|
||||
}
|
||||
else
|
||||
{
|
||||
llerrs << "LLWearable::setVisualParam passed invalid parameter index: " << param_index << " for wearable type: " << this->getName() << llendl;
|
||||
}
|
||||
}
|
||||
|
||||
F32 LLWearable::getVisualParamWeight(S32 param_index) const
|
||||
{
|
||||
if( is_in_map(mVisualParamIndexMap, param_index ) )
|
||||
{
|
||||
const LLVisualParam *wearable_param = mVisualParamIndexMap.find(param_index)->second;
|
||||
return wearable_param->getWeight();
|
||||
}
|
||||
else
|
||||
{
|
||||
llwarns << "LLWerable::getVisualParam passed invalid parameter index: " << param_index << " for wearable type: " << this->getName() << llendl;
|
||||
}
|
||||
return (F32)-1.0;
|
||||
}
|
||||
|
||||
LLVisualParam* LLWearable::getVisualParam(S32 index) const
|
||||
{
|
||||
visual_param_index_map_t::const_iterator iter = mVisualParamIndexMap.find(index);
|
||||
return (iter == mVisualParamIndexMap.end()) ? NULL : iter->second;
|
||||
}
|
||||
|
||||
|
||||
void LLWearable::getVisualParams(visual_param_vec_t &list)
|
||||
{
|
||||
visual_param_index_map_t::iterator iter = mVisualParamIndexMap.begin();
|
||||
visual_param_index_map_t::iterator end = mVisualParamIndexMap.end();
|
||||
|
||||
// add all visual params to the passed-in vector
|
||||
for( ; iter != end; ++iter )
|
||||
{
|
||||
list.push_back(iter->second);
|
||||
}
|
||||
}
|
||||
|
||||
void LLWearable::animateParams(F32 delta, BOOL upload_bake)
|
||||
{
|
||||
for(visual_param_index_map_t::iterator iter = mVisualParamIndexMap.begin();
|
||||
iter != mVisualParamIndexMap.end();
|
||||
++iter)
|
||||
{
|
||||
LLVisualParam *param = (LLVisualParam*) iter->second;
|
||||
param->animate(delta, upload_bake);
|
||||
}
|
||||
}
|
||||
|
||||
LLColor4 LLWearable::getClothesColor(S32 te) const
|
||||
{
|
||||
LLColor4 color;
|
||||
U32 param_name[3];
|
||||
if( LLAvatarAppearance::teToColorParams( (LLAvatarAppearanceDefines::ETextureIndex)te, param_name ) )
|
||||
{
|
||||
for( U8 index = 0; index < 3; index++ )
|
||||
{
|
||||
color.mV[index] = getVisualParamWeight(param_name[index]);
|
||||
}
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
void LLWearable::setClothesColor( S32 te, const LLColor4& new_color, BOOL upload_bake )
|
||||
{
|
||||
U32 param_name[3];
|
||||
if( LLAvatarAppearance::teToColorParams( (LLAvatarAppearanceDefines::ETextureIndex)te, param_name ) )
|
||||
{
|
||||
for( U8 index = 0; index < 3; index++ )
|
||||
{
|
||||
setVisualParamWeight(param_name[index], new_color.mV[index], upload_bake);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLWearable::writeToAvatar(LLAvatarAppearance* avatarp)
|
||||
{
|
||||
if (!avatarp) return;
|
||||
|
||||
// Pull params
|
||||
for( LLVisualParam* param = avatarp->getFirstVisualParam(); param; param = avatarp->getNextVisualParam() )
|
||||
{
|
||||
// cross-wearable parameters are not authoritative, as they are driven by a different wearable. So don't copy the values to the
|
||||
// avatar object if cross wearable. Cross wearable params get their values from the avatar, they shouldn't write the other way.
|
||||
if( (((LLViewerVisualParam*)param)->getWearableType() == mType) && (!((LLViewerVisualParam*)param)->getCrossWearable()) )
|
||||
{
|
||||
S32 param_id = param->getID();
|
||||
F32 weight = getVisualParamWeight(param_id);
|
||||
|
||||
avatarp->setVisualParamWeight( param_id, weight, FALSE );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string terse_F32_to_string(F32 f)
|
||||
{
|
||||
std::string r = llformat("%.2f", f);
|
||||
S32 len = r.length();
|
||||
|
||||
// "1.20" -> "1.2"
|
||||
// "24.00" -> "24."
|
||||
while (len > 0 && ('0' == r[len - 1]))
|
||||
{
|
||||
r.erase(len-1, 1);
|
||||
len--;
|
||||
}
|
||||
if ('.' == r[len - 1])
|
||||
{
|
||||
// "24." -> "24"
|
||||
r.erase(len-1, 1);
|
||||
}
|
||||
else if (('-' == r[0]) && ('0' == r[1]))
|
||||
{
|
||||
// "-0.59" -> "-.59"
|
||||
r.erase(1, 1);
|
||||
}
|
||||
else if ('0' == r[0])
|
||||
{
|
||||
// "0.59" -> ".59"
|
||||
r.erase(0, 1);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
@@ -27,48 +27,35 @@
|
||||
#ifndef LL_LLWEARABLE_H
|
||||
#define LL_LLWEARABLE_H
|
||||
|
||||
#include "lluuid.h"
|
||||
#include "llstring.h"
|
||||
#include "llavatarappearancedefines.h"
|
||||
#include "llextendedstatus.h"
|
||||
#include "llpermissions.h"
|
||||
#include "llsaleinfo.h"
|
||||
#include "llassetstorage.h"
|
||||
#include "llwearabletype.h"
|
||||
#include "llfile.h"
|
||||
#include "lllocaltextureobject.h"
|
||||
|
||||
class LLViewerInventoryItem;
|
||||
class LLMD5;
|
||||
class LLVisualParam;
|
||||
class LLTexGlobalColorInfo;
|
||||
class LLTexGlobalColor;
|
||||
class LLAvatarAppearance;
|
||||
|
||||
// Abstract class.
|
||||
class LLWearable
|
||||
{
|
||||
friend class LLWearableList;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Constructors and destructors
|
||||
//--------------------------------------------------------------------
|
||||
private:
|
||||
// Private constructors used by LLWearableList
|
||||
LLWearable(const LLTransactionID& transactionID);
|
||||
LLWearable(const LLAssetID& assetID);
|
||||
public:
|
||||
LLWearable();
|
||||
virtual ~LLWearable();
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Accessors
|
||||
//--------------------------------------------------------------------
|
||||
public:
|
||||
const LLUUID& getItemID() const;
|
||||
const LLAssetID& getAssetID() const { return mAssetID; }
|
||||
const LLTransactionID& getTransactionID() const { return mTransactionID; }
|
||||
|
||||
BOOL FileExportParams(FILE* file);
|
||||
BOOL FileExportTextures(FILE* file);
|
||||
|
||||
|
||||
LLWearableType::EType getType() const { return mType; }
|
||||
void setType( LLWearableType::EType type );
|
||||
void setType(LLWearableType::EType type, LLAvatarAppearance *avatarp);
|
||||
const std::string& getName() const { return mName; }
|
||||
void setName( const std::string& name ) { mName = name; }
|
||||
const std::string& getDescription() const { return mDescription; }
|
||||
@@ -82,39 +69,36 @@ public:
|
||||
LLAssetType::EType getAssetType() const;
|
||||
S32 getDefinitionVersion() const { return mDefinitionVersion; }
|
||||
void setDefinitionVersion( S32 new_version ) { mDefinitionVersion = new_version; }
|
||||
static S32 getCurrentDefinitionVersion() { return LLWearable::sCurrentDefinitionVersion; }
|
||||
|
||||
public:
|
||||
typedef std::vector<LLVisualParam*> visual_param_vec_t;
|
||||
|
||||
BOOL isDirty() const;
|
||||
BOOL isOldVersion() const;
|
||||
|
||||
void writeToAvatar();
|
||||
void removeFromAvatar( BOOL upload_bake ) { LLWearable::removeFromAvatar( mType, upload_bake ); }
|
||||
static void removeFromAvatar( LLWearableType::EType type, BOOL upload_bake );
|
||||
virtual void writeToAvatar(LLAvatarAppearance* avatarp);
|
||||
|
||||
BOOL FileExportParams(FILE* file) const;
|
||||
BOOL FileExportTextures(FILE* file) const;
|
||||
|
||||
enum EImportResult
|
||||
{
|
||||
FAILURE = 0,
|
||||
SUCCESS,
|
||||
BAD_HEADER
|
||||
};
|
||||
BOOL exportFile(LLFILE* file) const;
|
||||
BOOL importFile(LLFILE* file);
|
||||
|
||||
void setParamsToDefaults();
|
||||
void setTexturesToDefaults();
|
||||
|
||||
void saveNewAsset() const;
|
||||
static void onSaveNewAssetComplete( const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status );
|
||||
|
||||
void copyDataFrom(const LLWearable* src);
|
||||
EImportResult importFile(LLFILE* file, LLAvatarAppearance* avatarp );
|
||||
virtual BOOL exportStream( std::ostream& output_stream ) const;
|
||||
virtual EImportResult importStream( std::istream& input_stream, LLAvatarAppearance* avatarp );
|
||||
|
||||
static void setCurrentDefinitionVersion( S32 version ) { LLWearable::sCurrentDefinitionVersion = version; }
|
||||
|
||||
friend std::ostream& operator<<(std::ostream &s, const LLWearable &w);
|
||||
void setItemID(const LLUUID& item_id);
|
||||
virtual const LLUUID getDefaultTextureImageID(LLAvatarAppearanceDefines::ETextureIndex index) const = 0;
|
||||
|
||||
LLLocalTextureObject* getLocalTextureObject(S32 index);
|
||||
const LLLocalTextureObject* getLocalTextureObject(S32 index) const;
|
||||
std::vector<LLLocalTextureObject*> getLocalTextureListSeq();
|
||||
|
||||
void setLocalTextureObject(S32 index, LLLocalTextureObject <o);
|
||||
void addVisualParam(LLVisualParam *param);
|
||||
void setVisualParams();
|
||||
void setVisualParamWeight(S32 index, F32 value, BOOL upload_bake);
|
||||
F32 getVisualParamWeight(S32 index) const;
|
||||
LLVisualParam* getVisualParam(S32 index) const;
|
||||
@@ -124,27 +108,21 @@ public:
|
||||
LLColor4 getClothesColor(S32 te) const;
|
||||
void setClothesColor( S32 te, const LLColor4& new_color, BOOL upload_bake );
|
||||
|
||||
void revertValues();
|
||||
void saveValues();
|
||||
void pullCrossWearableValues();
|
||||
virtual void revertValues();
|
||||
virtual void saveValues();
|
||||
|
||||
BOOL isOnTop() const;
|
||||
// Something happened that requires the wearable to be updated (e.g. worn/unworn).
|
||||
virtual void setUpdated() const = 0;
|
||||
|
||||
// Something happened that requires the wearable's label to be updated (e.g. worn/unworn).
|
||||
void setLabelUpdated() const;
|
||||
// Update the baked texture hash.
|
||||
virtual void addToBakedTextureHash(LLMD5& hash) const = 0;
|
||||
|
||||
// the wearable was worn. make sure the name of the wearable object matches the LLViewerInventoryItem,
|
||||
// not the wearable asset itself.
|
||||
void refreshName();
|
||||
|
||||
private:
|
||||
protected:
|
||||
typedef std::map<S32, LLLocalTextureObject*> te_map_t;
|
||||
typedef std::map<S32, LLVisualParam *> visual_param_index_map_t;
|
||||
|
||||
void createLayers(S32 te);
|
||||
void createVisualParams();
|
||||
void syncImages(te_map_t &src, te_map_t &dst);
|
||||
void destroyTextures();
|
||||
void destroyTextures();
|
||||
void createVisualParams(LLAvatarAppearance *avatarp);
|
||||
void createLayers(S32 te, LLAvatarAppearance *avatarp);
|
||||
|
||||
static S32 sCurrentDefinitionVersion; // Depends on the current state of the avatar_lad.xml.
|
||||
S32 mDefinitionVersion; // Depends on the state of the avatar_lad.xml when this asset was created.
|
||||
@@ -152,18 +130,16 @@ private:
|
||||
std::string mDescription;
|
||||
LLPermissions mPermissions;
|
||||
LLSaleInfo mSaleInfo;
|
||||
LLAssetID mAssetID;
|
||||
LLTransactionID mTransactionID;
|
||||
LLWearableType::EType mType;
|
||||
|
||||
typedef std::map<S32, F32> param_map_t;
|
||||
param_map_t mSavedVisualParamMap; // last saved version of visual params
|
||||
|
||||
typedef std::map<S32, LLVisualParam *> visual_param_index_map_t;
|
||||
visual_param_index_map_t mVisualParamIndexMap;
|
||||
|
||||
te_map_t mTEMap; // maps TE to LocalTextureObject
|
||||
te_map_t mSavedTEMap; // last saved version of TEMap
|
||||
LLUUID mItemID; // ID of the inventory item in the agent's inventory
|
||||
};
|
||||
|
||||
#endif // LL_LLWEARABLE_H
|
||||
363
indra/llappearance/llwearabledata.cpp
Normal file
363
indra/llappearance/llwearabledata.cpp
Normal file
@@ -0,0 +1,363 @@
|
||||
/**
|
||||
* @file llwearabledata.cpp
|
||||
* @brief LLWearableData class implementation
|
||||
*
|
||||
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llwearabledata.h"
|
||||
|
||||
#include "llavatarappearance.h"
|
||||
#include "llavatarappearancedefines.h"
|
||||
#include "lldriverparam.h"
|
||||
#include "llmd5.h"
|
||||
|
||||
LLWearableData::LLWearableData() :
|
||||
mAvatarAppearance(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
// virtual
|
||||
LLWearableData::~LLWearableData()
|
||||
{
|
||||
}
|
||||
|
||||
using namespace LLAvatarAppearanceDefines;
|
||||
|
||||
LLWearable* LLWearableData::getWearable(const LLWearableType::EType type, U32 index)
|
||||
{
|
||||
//llassert_always(index == 0);
|
||||
wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type);
|
||||
if (wearable_iter == mWearableDatas.end())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
wearableentry_vec_t& wearable_vec = wearable_iter->second;
|
||||
if (index>=wearable_vec.size())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return wearable_vec[index];
|
||||
}
|
||||
}
|
||||
|
||||
void LLWearableData::setWearable(const LLWearableType::EType type, U32 index, LLWearable *wearable)
|
||||
{
|
||||
//llassert_always(index == 0);
|
||||
LLWearable *old_wearable = getWearable(type,index);
|
||||
if (!old_wearable)
|
||||
{
|
||||
pushWearable(type,wearable);
|
||||
return;
|
||||
}
|
||||
|
||||
wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type);
|
||||
if (wearable_iter == mWearableDatas.end())
|
||||
{
|
||||
llwarns << "invalid type, type " << type << " index " << index << llendl;
|
||||
return;
|
||||
}
|
||||
wearableentry_vec_t& wearable_vec = wearable_iter->second;
|
||||
if (index>=wearable_vec.size())
|
||||
{
|
||||
llwarns << "invalid index, type " << type << " index " << index << llendl;
|
||||
}
|
||||
else
|
||||
{
|
||||
wearable_vec[index] = wearable;
|
||||
old_wearable->setUpdated();
|
||||
const BOOL removed = FALSE;
|
||||
wearableUpdated(wearable, removed);
|
||||
}
|
||||
}
|
||||
|
||||
U32 LLWearableData::pushWearable(const LLWearableType::EType type,
|
||||
LLWearable *wearable)
|
||||
{
|
||||
if (wearable == NULL)
|
||||
{
|
||||
// no null wearables please!
|
||||
llwarns << "Null wearable sent for type " << type << llendl;
|
||||
return MAX_CLOTHING_PER_TYPE;
|
||||
}
|
||||
// if (type < LLWearableType::WT_COUNT || mWearableDatas[type].size() < MAX_CLOTHING_PER_TYPE)
|
||||
// {
|
||||
// mWearableDatas[type].push_back(wearable);
|
||||
// wearableUpdated(wearable);
|
||||
// checkWearableAgainstInventory(wearable);
|
||||
// return mWearableDatas[type].size()-1;
|
||||
// }
|
||||
// [RLVa:KB] - Checked: 2010-06-08 (RLVa-1.2.0g) | Added: RLVa-1.2.0g
|
||||
if ( (type < LLWearableType::WT_COUNT) && (mWearableDatas[type].size() < MAX_CLOTHING_PER_TYPE) )
|
||||
{
|
||||
// Don't add the same wearable twice
|
||||
U32 idxWearable = getWearableIndex(wearable);
|
||||
//RLV_ASSERT(MAX_CLOTHING_PER_TYPE == idxWearable); // pushWearable() on an already added wearable is a bug *somewhere*
|
||||
if (MAX_CLOTHING_PER_TYPE == idxWearable)
|
||||
{
|
||||
mWearableDatas[type].push_back(wearable);
|
||||
idxWearable = mWearableDatas[type].size() - 1;
|
||||
}
|
||||
const BOOL removed = FALSE;
|
||||
wearableUpdated(wearable, removed);
|
||||
return idxWearable;
|
||||
// [/RLVa:KB]
|
||||
}
|
||||
return MAX_CLOTHING_PER_TYPE;
|
||||
}
|
||||
|
||||
// virtual
|
||||
void LLWearableData::wearableUpdated(LLWearable *wearable, BOOL removed)
|
||||
{
|
||||
wearable->setUpdated();
|
||||
// FIXME DRANO avoid updating params via wearables when rendering server-baked appearance.
|
||||
#if 0
|
||||
if (mAvatarAppearance->isUsingServerBakes() && !mAvatarAppearance->isUsingLocalAppearance())
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (!removed)
|
||||
{
|
||||
pullCrossWearableValues(wearable->getType());
|
||||
}
|
||||
}
|
||||
|
||||
void LLWearableData::popWearable(LLWearable *wearable)
|
||||
{
|
||||
if (wearable == NULL)
|
||||
{
|
||||
// nothing to do here. move along.
|
||||
return;
|
||||
}
|
||||
|
||||
U32 index = getWearableIndex(wearable);
|
||||
const LLWearableType::EType type = wearable->getType();
|
||||
|
||||
if (index < MAX_CLOTHING_PER_TYPE && index < getWearableCount(type))
|
||||
{
|
||||
popWearable(type, index);
|
||||
}
|
||||
}
|
||||
|
||||
void LLWearableData::popWearable(const LLWearableType::EType type, U32 index)
|
||||
{
|
||||
//llassert_always(index == 0);
|
||||
LLWearable *wearable = getWearable(type, index);
|
||||
if (wearable)
|
||||
{
|
||||
mWearableDatas[type].erase(mWearableDatas[type].begin() + index);
|
||||
const BOOL removed = TRUE;
|
||||
wearableUpdated(wearable, removed);
|
||||
}
|
||||
}
|
||||
|
||||
bool LLWearableData::swapWearables(const LLWearableType::EType type, U32 index_a, U32 index_b)
|
||||
{
|
||||
wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type);
|
||||
if (wearable_iter == mWearableDatas.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
wearableentry_vec_t& wearable_vec = wearable_iter->second;
|
||||
if (0 > index_a || index_a >= wearable_vec.size()) return false;
|
||||
if (0 > index_b || index_b >= wearable_vec.size()) return false;
|
||||
|
||||
LLWearable* wearable = wearable_vec[index_a];
|
||||
wearable_vec[index_a] = wearable_vec[index_b];
|
||||
wearable_vec[index_b] = wearable;
|
||||
return true;
|
||||
}
|
||||
|
||||
void LLWearableData::pullCrossWearableValues(const LLWearableType::EType type)
|
||||
{
|
||||
llassert(mAvatarAppearance);
|
||||
// scan through all of the avatar's visual parameters
|
||||
for (LLViewerVisualParam* param = (LLViewerVisualParam*) mAvatarAppearance->getFirstVisualParam();
|
||||
param;
|
||||
param = (LLViewerVisualParam*) mAvatarAppearance->getNextVisualParam())
|
||||
{
|
||||
if( param )
|
||||
{
|
||||
LLDriverParam *driver_param = dynamic_cast<LLDriverParam*>(param);
|
||||
if(driver_param)
|
||||
{
|
||||
// parameter is a driver parameter, have it update its cross-driven params
|
||||
driver_param->updateCrossDrivenParams(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
U32 LLWearableData::getWearableIndex(const LLWearable *wearable) const
|
||||
{
|
||||
if (wearable == NULL)
|
||||
{
|
||||
return MAX_CLOTHING_PER_TYPE;
|
||||
}
|
||||
|
||||
const LLWearableType::EType type = wearable->getType();
|
||||
wearableentry_map_t::const_iterator wearable_iter = mWearableDatas.find(type);
|
||||
if (wearable_iter == mWearableDatas.end())
|
||||
{
|
||||
llwarns << "tried to get wearable index with an invalid type!" << llendl;
|
||||
return MAX_CLOTHING_PER_TYPE;
|
||||
}
|
||||
const wearableentry_vec_t& wearable_vec = wearable_iter->second;
|
||||
for(U32 index = 0; index < wearable_vec.size(); index++)
|
||||
{
|
||||
if (wearable_vec[index] == wearable)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
return MAX_CLOTHING_PER_TYPE;
|
||||
}
|
||||
|
||||
BOOL LLWearableData::isOnTop(LLWearable* wearable) const
|
||||
{
|
||||
if (!wearable) return FALSE;
|
||||
const LLWearableType::EType type = wearable->getType();
|
||||
return ( getTopWearable(type) == wearable );
|
||||
}
|
||||
|
||||
const LLWearable* LLWearableData::getWearable(const LLWearableType::EType type, U32 index) const
|
||||
{
|
||||
//llassert_always(index == 0);
|
||||
wearableentry_map_t::const_iterator wearable_iter = mWearableDatas.find(type);
|
||||
if (wearable_iter == mWearableDatas.end())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
const wearableentry_vec_t& wearable_vec = wearable_iter->second;
|
||||
if (index>=wearable_vec.size())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return wearable_vec[index];
|
||||
}
|
||||
}
|
||||
|
||||
LLWearable* LLWearableData::getTopWearable(const LLWearableType::EType type)
|
||||
{
|
||||
U32 count = getWearableCount(type);
|
||||
if ( count == 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return getWearable(type, count-1);
|
||||
}
|
||||
|
||||
const LLWearable* LLWearableData::getTopWearable(const LLWearableType::EType type) const
|
||||
{
|
||||
U32 count = getWearableCount(type);
|
||||
if ( count == 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return getWearable(type, count-1);
|
||||
}
|
||||
|
||||
LLWearable* LLWearableData::getBottomWearable(const LLWearableType::EType type)
|
||||
{
|
||||
if (getWearableCount(type) == 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return getWearable(type, 0);
|
||||
}
|
||||
|
||||
const LLWearable* LLWearableData::getBottomWearable(const LLWearableType::EType type) const
|
||||
{
|
||||
if (getWearableCount(type) == 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return getWearable(type, 0);
|
||||
}
|
||||
|
||||
U32 LLWearableData::getWearableCount(const LLWearableType::EType type) const
|
||||
{
|
||||
wearableentry_map_t::const_iterator wearable_iter = mWearableDatas.find(type);
|
||||
if (wearable_iter == mWearableDatas.end())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
const wearableentry_vec_t& wearable_vec = wearable_iter->second;
|
||||
return wearable_vec.size();
|
||||
}
|
||||
|
||||
U32 LLWearableData::getWearableCount(const U32 tex_index) const
|
||||
{
|
||||
const LLWearableType::EType wearable_type = LLAvatarAppearanceDictionary::getTEWearableType((LLAvatarAppearanceDefines::ETextureIndex)tex_index);
|
||||
return getWearableCount(wearable_type);
|
||||
}
|
||||
|
||||
LLUUID LLWearableData::computeBakedTextureHash(LLAvatarAppearanceDefines::EBakedTextureIndex baked_index,
|
||||
BOOL generate_valid_hash) // Set to false if you want to upload the baked texture w/o putting it in the cache
|
||||
{
|
||||
LLUUID hash_id;
|
||||
bool hash_computed = false;
|
||||
LLMD5 hash;
|
||||
const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = LLAvatarAppearanceDictionary::getInstance()->getBakedTexture(baked_index);
|
||||
|
||||
for (U8 i=0; i < baked_dict->mWearables.size(); i++)
|
||||
{
|
||||
const LLWearableType::EType baked_type = baked_dict->mWearables[i];
|
||||
const U32 num_wearables = getWearableCount(baked_type);
|
||||
for (U32 index = 0; index < num_wearables; ++index)
|
||||
{
|
||||
const LLWearable* wearable = getWearable(baked_type,index);
|
||||
if (wearable)
|
||||
{
|
||||
wearable->addToBakedTextureHash(hash);
|
||||
hash_computed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hash_computed)
|
||||
{
|
||||
hash.update((const unsigned char*)baked_dict->mWearablesHashID.mData, UUID_BYTES);
|
||||
|
||||
if (!generate_valid_hash)
|
||||
{
|
||||
invalidateBakedTextureHash(hash);
|
||||
}
|
||||
hash.finalize();
|
||||
hash.raw_digest(hash_id.mData);
|
||||
}
|
||||
|
||||
return hash_id;
|
||||
}
|
||||
106
indra/llappearance/llwearabledata.h
Normal file
106
indra/llappearance/llwearabledata.h
Normal file
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* @file llwearabledata.h
|
||||
* @brief LLWearableData class header file
|
||||
*
|
||||
* $LicenseInfo:firstyear=20012license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_WEARABLEDATA_H
|
||||
#define LL_WEARABLEDATA_H
|
||||
|
||||
#include "llavatarappearancedefines.h"
|
||||
#include "llwearable.h"
|
||||
#include "llerror.h"
|
||||
|
||||
class LLAvatarAppearance;
|
||||
|
||||
class LLWearableData
|
||||
{
|
||||
// *TODO: Figure out why this is causing compile error.
|
||||
//LOG_CLASS(LLWearableData);
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Constructors / destructors / Initializers
|
||||
//--------------------------------------------------------------------
|
||||
public:
|
||||
LLWearableData();
|
||||
virtual ~LLWearableData();
|
||||
|
||||
void setAvatarAppearance(LLAvatarAppearance* appearance) { mAvatarAppearance = appearance; }
|
||||
|
||||
protected:
|
||||
//--------------------------------------------------------------------
|
||||
// Accessors
|
||||
//--------------------------------------------------------------------
|
||||
public:
|
||||
LLWearable* getWearable(const LLWearableType::EType type, U32 index /*= 0*/);
|
||||
const LLWearable* getWearable(const LLWearableType::EType type, U32 index /*= 0*/) const;
|
||||
LLWearable* getTopWearable(const LLWearableType::EType type);
|
||||
const LLWearable* getTopWearable(const LLWearableType::EType type) const;
|
||||
LLWearable* getBottomWearable(const LLWearableType::EType type);
|
||||
const LLWearable* getBottomWearable(const LLWearableType::EType type) const;
|
||||
U32 getWearableCount(const LLWearableType::EType type) const;
|
||||
U32 getWearableCount(const U32 tex_index) const;
|
||||
U32 getWearableIndex(const LLWearable *wearable) const;
|
||||
|
||||
BOOL isOnTop(LLWearable* wearable) const;
|
||||
|
||||
static const U32 MAX_CLOTHING_PER_TYPE = 5;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Setters
|
||||
//--------------------------------------------------------------------
|
||||
protected:
|
||||
// Low-level data structure setter - public access is via setWearableItem, etc.
|
||||
void setWearable(const LLWearableType::EType type, U32 index, LLWearable *wearable);
|
||||
U32 pushWearable(const LLWearableType::EType type, LLWearable *wearable);
|
||||
virtual void wearableUpdated(LLWearable *wearable, BOOL removed) = 0;
|
||||
void popWearable(LLWearable *wearable);
|
||||
void popWearable(const LLWearableType::EType type, U32 index);
|
||||
bool swapWearables(const LLWearableType::EType type, U32 index_a, U32 index_b);
|
||||
|
||||
private:
|
||||
void pullCrossWearableValues(const LLWearableType::EType type);
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Server Communication
|
||||
//--------------------------------------------------------------------
|
||||
public:
|
||||
LLUUID computeBakedTextureHash(LLAvatarAppearanceDefines::EBakedTextureIndex baked_index,
|
||||
BOOL generate_valid_hash = TRUE);
|
||||
protected:
|
||||
virtual void invalidateBakedTextureHash(LLMD5& hash) const = 0;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Member variables
|
||||
//--------------------------------------------------------------------
|
||||
protected:
|
||||
LLAvatarAppearance* mAvatarAppearance;
|
||||
typedef std::vector<LLWearable*> wearableentry_vec_t; // all wearables of a certain type (EG all shirts)
|
||||
typedef std::map<LLWearableType::EType, wearableentry_vec_t> wearableentry_map_t; // wearable "categories" arranged by wearable type
|
||||
wearableentry_map_t mWearableDatas;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // LL_WEARABLEDATA_H
|
||||
@@ -24,24 +24,36 @@
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
#include "linden_common.h"
|
||||
#include "llwearabletype.h"
|
||||
#include "llinventoryfunctions.h"
|
||||
#include "lltrans.h"
|
||||
#include "llinventorytype.h"
|
||||
|
||||
static LLTranslationBridge* sTrans = NULL;
|
||||
|
||||
// static
|
||||
void LLWearableType::initClass(LLTranslationBridge* trans)
|
||||
{
|
||||
sTrans = trans;
|
||||
}
|
||||
|
||||
void LLWearableType::cleanupClass()
|
||||
{
|
||||
delete sTrans;
|
||||
}
|
||||
|
||||
struct WearableEntry : public LLDictionaryEntry
|
||||
{
|
||||
WearableEntry(const std::string &name,
|
||||
const std::string& default_new_name,
|
||||
LLAssetType::EType assetType,
|
||||
LLInventoryIcon::EIconName iconName,
|
||||
LLInventoryType::EIconName iconName,
|
||||
BOOL disable_camera_switch = FALSE,
|
||||
BOOL allow_multiwear = TRUE) :
|
||||
LLDictionaryEntry(name),
|
||||
mAssetType(assetType),
|
||||
mDefaultNewName(default_new_name),
|
||||
//*TODO:Translate
|
||||
mLabel(/*LLTrans::getString*/(name)),
|
||||
mLabel(/*sTrans->getString*/(name)),
|
||||
mIconName(iconName),
|
||||
mDisableCameraSwitch(disable_camera_switch),
|
||||
mAllowMultiwear(allow_multiwear)
|
||||
@@ -51,7 +63,7 @@ struct WearableEntry : public LLDictionaryEntry
|
||||
const LLAssetType::EType mAssetType;
|
||||
const std::string mLabel;
|
||||
const std::string mDefaultNewName; //keep mLabel for backward compatibility
|
||||
LLInventoryIcon::EIconName mIconName;
|
||||
LLInventoryType::EIconName mIconName;
|
||||
BOOL mDisableCameraSwitch;
|
||||
BOOL mAllowMultiwear;
|
||||
};
|
||||
@@ -71,26 +83,26 @@ protected:
|
||||
|
||||
LLWearableDictionary::LLWearableDictionary()
|
||||
{
|
||||
addEntry(LLWearableType::WT_SHAPE, new WearableEntry("shape", "New Shape", LLAssetType::AT_BODYPART, LLInventoryIcon::ICONNAME_BODYPART_SHAPE, FALSE, FALSE));
|
||||
addEntry(LLWearableType::WT_SKIN, new WearableEntry("skin", "New Skin", LLAssetType::AT_BODYPART, LLInventoryIcon::ICONNAME_BODYPART_SKIN, FALSE, FALSE));
|
||||
addEntry(LLWearableType::WT_HAIR, new WearableEntry("hair", "New Hair", LLAssetType::AT_BODYPART, LLInventoryIcon::ICONNAME_BODYPART_HAIR, FALSE, FALSE));
|
||||
addEntry(LLWearableType::WT_EYES, new WearableEntry("eyes", "New Eyes", LLAssetType::AT_BODYPART, LLInventoryIcon::ICONNAME_BODYPART_EYES, FALSE, FALSE));
|
||||
addEntry(LLWearableType::WT_SHIRT, new WearableEntry("shirt", "New Shirt", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_SHIRT, FALSE, TRUE));
|
||||
addEntry(LLWearableType::WT_PANTS, new WearableEntry("pants", "New Pants", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_PANTS, FALSE, TRUE));
|
||||
addEntry(LLWearableType::WT_SHOES, new WearableEntry("shoes", "New Shoes", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_SHOES, FALSE, TRUE));
|
||||
addEntry(LLWearableType::WT_SOCKS, new WearableEntry("socks", "New Socks", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_SOCKS, FALSE, TRUE));
|
||||
addEntry(LLWearableType::WT_JACKET, new WearableEntry("jacket", "New Jacket", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_JACKET, FALSE, TRUE));
|
||||
addEntry(LLWearableType::WT_GLOVES, new WearableEntry("gloves", "New Gloves", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_GLOVES, FALSE, TRUE));
|
||||
addEntry(LLWearableType::WT_UNDERSHIRT, new WearableEntry("undershirt", "New Undershirt", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_UNDERSHIRT, FALSE, TRUE));
|
||||
addEntry(LLWearableType::WT_UNDERPANTS, new WearableEntry("underpants", "New Underpants", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_UNDERPANTS, FALSE, TRUE));
|
||||
addEntry(LLWearableType::WT_SKIRT, new WearableEntry("skirt", "New Skirt", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_SKIRT, FALSE, TRUE));
|
||||
addEntry(LLWearableType::WT_ALPHA, new WearableEntry("alpha", "New Alpha", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_ALPHA, FALSE, TRUE));
|
||||
addEntry(LLWearableType::WT_TATTOO, new WearableEntry("tattoo", "New Tattoo", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_TATTOO, FALSE, TRUE));
|
||||
addEntry(LLWearableType::WT_SHAPE, new WearableEntry("shape", "New Shape", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_SHAPE, FALSE, FALSE));
|
||||
addEntry(LLWearableType::WT_SKIN, new WearableEntry("skin", "New Skin", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_SKIN, FALSE, FALSE));
|
||||
addEntry(LLWearableType::WT_HAIR, new WearableEntry("hair", "New Hair", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_HAIR, FALSE, FALSE));
|
||||
addEntry(LLWearableType::WT_EYES, new WearableEntry("eyes", "New Eyes", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_EYES, FALSE, FALSE));
|
||||
addEntry(LLWearableType::WT_SHIRT, new WearableEntry("shirt", "New Shirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SHIRT, FALSE, TRUE));
|
||||
addEntry(LLWearableType::WT_PANTS, new WearableEntry("pants", "New Pants", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PANTS, FALSE, TRUE));
|
||||
addEntry(LLWearableType::WT_SHOES, new WearableEntry("shoes", "New Shoes", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SHOES, FALSE, TRUE));
|
||||
addEntry(LLWearableType::WT_SOCKS, new WearableEntry("socks", "New Socks", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SOCKS, FALSE, TRUE));
|
||||
addEntry(LLWearableType::WT_JACKET, new WearableEntry("jacket", "New Jacket", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_JACKET, FALSE, TRUE));
|
||||
addEntry(LLWearableType::WT_GLOVES, new WearableEntry("gloves", "New Gloves", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_GLOVES, FALSE, TRUE));
|
||||
addEntry(LLWearableType::WT_UNDERSHIRT, new WearableEntry("undershirt", "New Undershirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNDERSHIRT, FALSE, TRUE));
|
||||
addEntry(LLWearableType::WT_UNDERPANTS, new WearableEntry("underpants", "New Underpants", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNDERPANTS, FALSE, TRUE));
|
||||
addEntry(LLWearableType::WT_SKIRT, new WearableEntry("skirt", "New Skirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SKIRT, FALSE, TRUE));
|
||||
addEntry(LLWearableType::WT_ALPHA, new WearableEntry("alpha", "New Alpha", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_ALPHA, FALSE, TRUE));
|
||||
addEntry(LLWearableType::WT_TATTOO, new WearableEntry("tattoo", "New Tattoo", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_TATTOO, FALSE, TRUE));
|
||||
|
||||
addEntry(LLWearableType::WT_PHYSICS, new WearableEntry("physics", "New Physics", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_PHYSICS, TRUE, TRUE));
|
||||
addEntry(LLWearableType::WT_PHYSICS, new WearableEntry("physics", "New Physics", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PHYSICS, TRUE, TRUE));
|
||||
|
||||
addEntry(LLWearableType::WT_INVALID, new WearableEntry("invalid", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryIcon::ICONNAME_NONE, FALSE, FALSE));
|
||||
addEntry(LLWearableType::WT_NONE, new WearableEntry("none", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryIcon::ICONNAME_NONE, FALSE, FALSE));
|
||||
addEntry(LLWearableType::WT_INVALID, new WearableEntry("invalid", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryType::ICONNAME_NONE, FALSE, FALSE));
|
||||
addEntry(LLWearableType::WT_NONE, new WearableEntry("none", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryType::ICONNAME_NONE, FALSE, FALSE));
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -138,7 +150,7 @@ LLAssetType::EType LLWearableType::getAssetType(LLWearableType::EType type)
|
||||
}
|
||||
|
||||
// static
|
||||
LLInventoryIcon::EIconName LLWearableType::getIconName(LLWearableType::EType type)
|
||||
LLInventoryType::EIconName LLWearableType::getIconName(LLWearableType::EType type)
|
||||
{
|
||||
const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
|
||||
const WearableEntry *entry = dict->lookup(type);
|
||||
@@ -29,9 +29,17 @@
|
||||
|
||||
#include "llassettype.h"
|
||||
#include "lldictionary.h"
|
||||
#include "llinventoryicon.h"
|
||||
#include "llinventorytype.h"
|
||||
#include "llsingleton.h"
|
||||
|
||||
class LLTranslationBridge
|
||||
{
|
||||
public:
|
||||
virtual ~LLTranslationBridge(){};
|
||||
virtual std::string getString(const std::string &xml_desc) = 0;
|
||||
};
|
||||
|
||||
|
||||
class LLWearableType
|
||||
{
|
||||
public:
|
||||
@@ -59,12 +67,15 @@ public:
|
||||
WT_NONE = -1,
|
||||
};
|
||||
|
||||
static void initClass(LLTranslationBridge* trans); // initializes static members
|
||||
static void cleanupClass(); // initializes static members
|
||||
|
||||
static const std::string& getTypeName(EType type);
|
||||
static const std::string& getTypeDefaultNewName(EType type);
|
||||
static const std::string& getTypeLabel(EType type);
|
||||
static LLAssetType::EType getAssetType(EType type);
|
||||
static EType typeNameToType(const std::string& type_name);
|
||||
static LLInventoryIcon::EIconName getIconName(EType type);
|
||||
static LLInventoryType::EIconName getIconName(EType type);
|
||||
static BOOL getDisableCameraSwitch(EType type);
|
||||
static BOOL getAllowMultiwear(EType type);
|
||||
|
||||
@@ -1,31 +1,25 @@
|
||||
/**
|
||||
* @file llaudiodecodemgr.h
|
||||
*
|
||||
* $LicenseInfo:firstyear=2003&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2003-2009, Linden Research, Inc.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2003&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
|
||||
@@ -3,31 +3,25 @@
|
||||
* @brief implementation of LLAudioEngine class abstracting the Open
|
||||
* AL audio support
|
||||
*
|
||||
* $LicenseInfo:firstyear=2000&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2000-2009, Linden Research, Inc.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2000&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user