This commit is contained in:
Shyotl
2013-11-18 10:38:39 -06:00
274 changed files with 9337 additions and 3393 deletions

View File

@@ -21,6 +21,7 @@ set(aistatemachine_SOURCE_FILES
aistatemachine.cpp
aistatemachinethread.cpp
aitimer.cpp
aicondition.cpp
)
set(aistatemachine_HEADER_FILES
@@ -29,6 +30,7 @@ set(aistatemachine_HEADER_FILES
aistatemachine.h
aistatemachinethread.h
aitimer.h
aicondition.h
)
set_source_files_properties(${aistatemachine_HEADER_FILES}

View File

@@ -0,0 +1,89 @@
/**
* @file aicondition.cpp
* @brief Implementation of AICondition
*
* 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.
*
* 14/10/2013
* Initial version, written by Aleric Inglewood @ SL
*/
#include "sys.h"
#include "aicondition.h"
#include "aistatemachine.h"
void AIConditionBase::wait(AIStateMachine* state_machine)
{
// The condition must be locked before calling AIStateMachine::wait().
llassert(mutex().isSelfLocked());
// Add the new state machine at the end.
mWaitingStateMachines.push_back(state_machine);
}
void AIConditionBase::remove(AIStateMachine* state_machine)
{
mutex().lock();
// Remove all occurances of state_machine from the queue.
queue_t::iterator const end = mWaitingStateMachines.end();
queue_t::iterator last = end;
for (queue_t::iterator iter = mWaitingStateMachines.begin(); iter != last; ++iter)
{
if (iter->get() == state_machine)
{
if (--last == iter)
{
break;
}
queue_t::value_type::swap(*iter, *last);
}
}
// This invalidates all iterators involved, including end, but not any iterators to the remaining elements.
mWaitingStateMachines.erase(last, end);
mutex().unlock();
}
void AIConditionBase::signal(int n)
{
// The condition must be locked before calling AICondition::signal or AICondition::broadcast.
llassert(mutex().isSelfLocked());
// Signal n state machines.
while (n > 0 && !mWaitingStateMachines.empty())
{
LLPointer<AIStateMachine> state_machine = mWaitingStateMachines.front();
bool success = state_machine->signalled();
// Only state machines that are actually still blocked should be in the queue:
// they are removed from the queue by calling AICondition::remove whenever
// they are unblocked for whatever reason...
llassert(success);
if (success)
{
++n;
}
else
{
// We never get here...
remove(state_machine.get());
}
}
}

View File

@@ -0,0 +1,110 @@
/**
* @file aicondition.h
* @brief Condition variable for statemachines.
*
* 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.
*
* 14/10/2013
* Initial version, written by Aleric Inglewood @ SL
*/
#ifndef AICONDITION_H
#define AICONDITION_H
#include <deque>
#include <llpointer.h>
#include "aithreadsafe.h"
class AIStateMachine;
class LLMutex;
// class AICondition
//
// Call AIStateMachine::wait(AICondition&) in the multiplex_impl of a state machine to
// make the state machine go idle until some thread calls AICondition::signal().
//
// If the state machine is no longer running or wasn't waiting anymore because
// something else woke it up, then AICondition::signal() will wake up another
// state machine (if any).
//
// Usage:
//
// struct Foo { bool met(); }; // Returns true when the condition is met.
// AICondition<Foo> Condition_t;
// AIAccess<Foo> Condition_wat;
//
// // Some thread-safe condition variable.
// Condition_t condition;
//
// // Inside the state machine:
// {
// ...
// state WAIT_FOR_CONDITION:
// {
// // Lock condition and check it. Wait if condition is not met yet.
// {
// Condition_wat condition_w(condition);
// if (!condition_w->met())
// {
// wait(condition);
// break;
// }
// }
// set_state(CONDITION_MET);
// break;
// }
// CONDITION_MET:
// {
//
class AIConditionBase
{
public:
virtual ~AIConditionBase() { }
void signal(int n = 1); // Call this when the condition was met to release n state machines.
void broadcast(void) { signal(mWaitingStateMachines.size()); } // Release all blocked state machines.
private:
// These functions are called by AIStateMachine.
friend class AIStateMachine;
void wait(AIStateMachine* state_machine);
void remove(AIStateMachine* state_machine);
protected:
virtual LLMutex& mutex(void) = 0;
protected:
typedef std::deque<LLPointer<AIStateMachine> > queue_t;
queue_t mWaitingStateMachines;
};
template<typename T>
class AICondition : public AIThreadSafeSimpleDC<T>, public AIConditionBase
{
protected:
/*virtual*/ LLMutex& mutex(void) { return this->mMutex; }
};
#endif

View File

@@ -33,6 +33,7 @@
#include "linden_common.h"
#include "aistatemachine.h"
#include "aicondition.h"
#include "lltimer.h"
//==================================================================
@@ -283,7 +284,7 @@ char const* HelloWorld::state_str_impl(state_type run_state) const
void AIEngine::add(AIStateMachine* state_machine)
{
Dout(dc::statemachine, "Adding state machine [" << (void*)state_machine << "] to " << mName);
Dout(dc::statemachine(state_machine->mSMDebug), "Adding state machine [" << (void*)state_machine << "] to " << mName);
engine_state_type_wat engine_state_w(mEngineState);
engine_state_w->list.push_back(QueueElement(state_machine));
if (engine_state_w->waiting)
@@ -330,7 +331,7 @@ void AIEngine::mainloop(void)
engine_state_type_wat engine_state_w(mEngineState);
if (!active)
{
Dout(dc::statemachine, "Erasing state machine [" << (void*)&state_machine << "] from " << mName);
Dout(dc::statemachine(state_machine.mSMDebug), "Erasing state machine [" << (void*)&state_machine << "] from " << mName);
engine_state_w->list.erase(queued_element++);
}
else
@@ -392,7 +393,7 @@ void AIStateMachine::multiplex(event_type event)
// If this fails then you are using a pointer to a state machine instead of an LLPointer.
llassert(event == initial_run || getNumRefs() > 0);
DoutEntering(dc::statemachine, "AIStateMachine::multiplex(" << event_str(event) << ") [" << (void*)this << "]");
DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::multiplex(" << event_str(event) << ") [" << (void*)this << "]");
base_state_type state;
state_type run_state;
@@ -407,7 +408,7 @@ void AIStateMachine::multiplex(event_type event)
llassert(!mMultiplexMutex.isSelfLocked()); // We may never enter recursively!
if (!mMultiplexMutex.tryLock())
{
Dout(dc::statemachine, "Leaving because it is already being run [" << (void*)this << "]");
Dout(dc::statemachine(mSMDebug), "Leaving because it is already being run [" << (void*)this << "]");
return;
}
@@ -421,7 +422,7 @@ void AIStateMachine::multiplex(event_type event)
// we should indeed run, again.
if (event == schedule_run && !sub_state_type_rat(mSubState)->need_run)
{
Dout(dc::statemachine, "Leaving because it was already being run [" << (void*)this << "]");
Dout(dc::statemachine(mSMDebug), "Leaving because it was already being run [" << (void*)this << "]");
return;
}
@@ -440,9 +441,9 @@ void AIStateMachine::multiplex(event_type event)
{
#ifdef CWDEBUG
if (state == bs_multiplex)
Dout(dc::statemachine, "Running state bs_multiplex / " << state_str_impl(run_state) << " [" << (void*)this << "]");
Dout(dc::statemachine(mSMDebug), "Running state bs_multiplex / " << state_str_impl(run_state) << " [" << (void*)this << "]");
else
Dout(dc::statemachine, "Running state " << state_str(state) << " [" << (void*)this << "]");
Dout(dc::statemachine(mSMDebug), "Running state " << state_str(state) << " [" << (void*)this << "]");
#endif
#ifdef SHOW_ASSERT
@@ -503,7 +504,7 @@ void AIStateMachine::multiplex(event_type event)
// run of bs_reset is not a problem because it happens to be a NoOp.
state = (state == bs_initialize) ? bs_reset : bs_abort;
#ifdef CWDEBUG
Dout(dc::statemachine, "Late abort detected! Running state " << state_str(state) << " instead [" << (void*)this << "]");
Dout(dc::statemachine(mSMDebug), "Late abort detected! Running state " << state_str(state) << " instead [" << (void*)this << "]");
#endif
}
#ifdef SHOW_ASSERT
@@ -665,7 +666,7 @@ void AIStateMachine::multiplex(event_type event)
#ifdef CWDEBUG
if (state != state_w->base_state)
Dout(dc::statemachine, "Base state changed from " << state_str(state) << " to " << state_str(state_w->base_state) <<
Dout(dc::statemachine(mSMDebug), "Base state changed from " << state_str(state) << " to " << state_str(state_w->base_state) <<
"; need_new_run = " << (need_new_run ? "true" : "false") << " [" << (void*)this << "]");
#endif
}
@@ -699,11 +700,15 @@ void AIStateMachine::multiplex(event_type event)
// Mark that we're added to this engine, and at the same time, that we're not added to the previous one.
state_w->current_engine = engine;
}
#ifdef SHOW_ASSERT
// We are leaving the loop, but we're not idle. The statemachine should re-enter the loop again.
mDebugShouldRun = true;
#endif
}
else
{
// Remove this state machine from any engine.
// Cause the engine to remove us.
// Remove this state machine from any engine,
// causing the engine to remove us.
state_w->current_engine = NULL;
}
@@ -749,7 +754,7 @@ void AIStateMachine::multiplex(event_type event)
AIStateMachine::state_type AIStateMachine::begin_loop(base_state_type base_state)
{
DoutEntering(dc::statemachine, "AIStateMachine::begin_loop(" << state_str(base_state) << ") [" << (void*)this << "]");
DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::begin_loop(" << state_str(base_state) << ") [" << (void*)this << "]");
sub_state_type_wat sub_state_w(mSubState);
// Honor a subsequent call to idle() (only necessary in bs_multiplex, but it doesn't hurt to reset this flag in other states too).
@@ -759,7 +764,7 @@ AIStateMachine::state_type AIStateMachine::begin_loop(base_state_type base_state
// Honor previous calls to advance_state() (once run_state is initialized).
if (base_state == bs_multiplex && sub_state_w->advance_state > sub_state_w->run_state)
{
Dout(dc::statemachine, "Copying advance_state to run_state, because it is larger [" << state_str_impl(sub_state_w->advance_state) << " > " << state_str_impl(sub_state_w->run_state) << "]");
Dout(dc::statemachine(mSMDebug), "Copying advance_state to run_state, because it is larger [" << state_str_impl(sub_state_w->advance_state) << " > " << state_str_impl(sub_state_w->run_state) << "]");
sub_state_w->run_state = sub_state_w->advance_state;
}
#ifdef SHOW_ASSERT
@@ -789,7 +794,7 @@ AIStateMachine::state_type AIStateMachine::begin_loop(base_state_type base_state
void AIStateMachine::run(AIStateMachine* parent, state_type new_parent_state, bool abort_parent, bool on_abort_signal_parent, AIEngine* default_engine)
{
DoutEntering(dc::statemachine, "AIStateMachine::run(" <<
DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::run(" <<
(void*)parent << ", " <<
(parent ? parent->state_str_impl(new_parent_state) : "NA") <<
", abort_parent = " << (abort_parent ? "true" : "false") <<
@@ -839,7 +844,7 @@ void AIStateMachine::run(AIStateMachine* parent, state_type new_parent_state, bo
void AIStateMachine::run(callback_type::signal_type::slot_type const& slot, AIEngine* default_engine)
{
DoutEntering(dc::statemachine, "AIStateMachine::run(<slot>, default_engine = " << default_engine->name() << ") [" << (void*)this << "]");
DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::run(<slot>, default_engine = " << default_engine->name() << ") [" << (void*)this << "]");
#ifdef SHOW_ASSERT
{
@@ -874,7 +879,7 @@ void AIStateMachine::run(callback_type::signal_type::slot_type const& slot, AIEn
void AIStateMachine::callback(void)
{
DoutEntering(dc::statemachine, "AIStateMachine::callback() [" << (void*)this << "]");
DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::callback() [" << (void*)this << "]");
bool aborted = sub_state_type_rat(mSubState)->aborted;
if (mParent)
@@ -920,7 +925,7 @@ void AIStateMachine::force_killed(void)
void AIStateMachine::kill(void)
{
DoutEntering(dc::statemachine, "AIStateMachine::kill() [" << (void*)this << "]");
DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::kill() [" << (void*)this << "]");
#ifdef SHOW_ASSERT
{
multiplex_state_type_rat state_r(mState);
@@ -937,7 +942,7 @@ void AIStateMachine::kill(void)
void AIStateMachine::reset()
{
DoutEntering(dc::statemachine, "AIStateMachine::reset() [" << (void*)this << "]");
DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::reset() [" << (void*)this << "]");
#ifdef SHOW_ASSERT
mDebugAborted = false;
mDebugContPending = false;
@@ -960,6 +965,8 @@ void AIStateMachine::reset()
sub_state_w->reset = true;
// Start running.
sub_state_w->idle = false;
// We're not waiting for a condition.
sub_state_w->blocked = NULL;
// Keep running till we reach at least bs_multiplex.
sub_state_w->need_run = true;
}
@@ -972,7 +979,7 @@ void AIStateMachine::reset()
void AIStateMachine::set_state(state_type new_state)
{
DoutEntering(dc::statemachine, "AIStateMachine::set_state(" << state_str_impl(new_state) << ") [" << (void*)this << "]");
DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::set_state(" << state_str_impl(new_state) << ") [" << (void*)this << "]");
#ifdef SHOW_ASSERT
{
multiplex_state_type_rat state_r(mState);
@@ -983,6 +990,8 @@ void AIStateMachine::set_state(state_type new_state)
}
#endif
sub_state_type_wat sub_state_w(mSubState);
// It should never happen that set_state() is called while we're blocked.
llassert(!sub_state_w->blocked);
// Force current state to the requested state.
sub_state_w->run_state = new_state;
// Void last call to advance_state.
@@ -999,13 +1008,13 @@ void AIStateMachine::set_state(state_type new_state)
void AIStateMachine::advance_state(state_type new_state)
{
DoutEntering(dc::statemachine, "AIStateMachine::advance_state(" << state_str_impl(new_state) << ") [" << (void*)this << "]");
DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::advance_state(" << state_str_impl(new_state) << ") [" << (void*)this << "]");
{
sub_state_type_wat sub_state_w(mSubState);
// Ignore call to advance_state when the currently queued state is already greater or equal to the requested state.
if (sub_state_w->advance_state >= new_state)
{
Dout(dc::statemachine, "Ignored, because " << state_str_impl(sub_state_w->advance_state) << " >= " << state_str_impl(new_state) << ".");
Dout(dc::statemachine(mSMDebug), "Ignored, because " << state_str_impl(sub_state_w->advance_state) << " >= " << state_str_impl(new_state) << ".");
return;
}
// Ignore call to advance_state when the current state is greater than the requested state: the new state would be
@@ -1014,7 +1023,7 @@ void AIStateMachine::advance_state(state_type new_state)
// the state change is and should be being ignored: the statemachine would start running it's current state (again).
if (sub_state_w->run_state > new_state)
{
Dout(dc::statemachine, "Ignored, because " << state_str_impl(sub_state_w->run_state) << " > " << state_str_impl(new_state) << " (current state).");
Dout(dc::statemachine(mSMDebug), "Ignored, because " << state_str_impl(sub_state_w->run_state) << " > " << state_str_impl(new_state) << " (current state).");
return;
}
// Increment state.
@@ -1023,6 +1032,13 @@ void AIStateMachine::advance_state(state_type new_state)
sub_state_w->idle = false;
// Ignore a call to idle if it occurs before we leave multiplex_impl().
sub_state_w->skip_idle = true;
// No longer say we woke up when signalled() is called.
if (sub_state_w->blocked)
{
Dout(dc::statemachine(mSMDebug), "Removing statemachine from condition " << (void*)sub_state_w->blocked);
sub_state_w->blocked->remove(this);
sub_state_w->blocked = NULL;
}
// Mark that a re-entry of multiplex() is necessary.
sub_state_w->need_run = true;
#ifdef SHOW_ASSERT
@@ -1048,7 +1064,7 @@ void AIStateMachine::advance_state(state_type new_state)
void AIStateMachine::idle(void)
{
DoutEntering(dc::statemachine, "AIStateMachine::idle() [" << (void*)this << "]");
DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::idle() [" << (void*)this << "]");
#ifdef SHOW_ASSERT
{
multiplex_state_type_rat state_r(mState);
@@ -1066,7 +1082,7 @@ void AIStateMachine::idle(void)
// Ignore call to idle() when advance_state() was called since last call to set_state().
if (sub_state_w->skip_idle)
{
Dout(dc::statemachine, "Ignored, because skip_idle is true (advance_state() was called last).");
Dout(dc::statemachine(mSMDebug), "Ignored, because skip_idle is true (advance_state() was called last).");
return;
}
// Mark that we are idle.
@@ -1075,13 +1091,54 @@ void AIStateMachine::idle(void)
mSleep = 0;
}
// This function is very much like idle().
void AIStateMachine::wait(AIConditionBase& condition)
{
DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::wait(" << (void*)&condition << ") [" << (void*)this << "]");
#ifdef SHOW_ASSERT
{
multiplex_state_type_rat state_r(mState);
// wait() may only be called multiplex_impl().
llassert(state_r->base_state == bs_multiplex);
// May only be called by the thread that is holding mMultiplexMutex.
llassert(mThreadId.equals_current_thread());
}
// wait() following set_state() cancels the reason to run because of the call to set_state.
mDebugSetStatePending = false;
#endif
sub_state_type_wat sub_state_w(mSubState);
// As wait() may only be called from within the state machine, it should never happen that the state machine is already idle.
llassert(!sub_state_w->idle);
// Ignore call to wait() when advance_state() was called since last call to set_state().
if (sub_state_w->skip_idle)
{
Dout(dc::statemachine(mSMDebug), "Ignored, because skip_idle is true (advance_state() was called last).");
return;
}
// Register ourselves with the condition object.
condition.wait(this);
// Mark that we are idle.
sub_state_w->idle = true;
// Mark that we are waiting for a condition.
sub_state_w->blocked = &condition;
// Not sleeping (anymore).
mSleep = 0;
}
void AIStateMachine::cont(void)
{
DoutEntering(dc::statemachine, "AIStateMachine::cont() [" << (void*)this << "]");
DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::cont() [" << (void*)this << "]");
{
sub_state_type_wat sub_state_w(mSubState);
// Void last call to idle(), if any.
sub_state_w->idle = false;
// No longer say we woke up when signalled() is called.
if (sub_state_w->blocked)
{
Dout(dc::statemachine(mSMDebug), "Removing statemachine from condition " << (void*)sub_state_w->blocked);
sub_state_w->blocked->remove(this);
sub_state_w->blocked = NULL;
}
// Mark that a re-entry of multiplex() is necessary.
sub_state_w->need_run = true;
#ifdef SHOW_ASSERT
@@ -1095,15 +1152,56 @@ void AIStateMachine::cont(void)
}
}
// This function is very much like cont(), except that it has no effect when we are not in a blocked state.
// Returns true if the state machine was unblocked, false if it was already unblocked.
bool AIStateMachine::signalled(void)
{
DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::signalled() [" << (void*)this << "]");
{
sub_state_type_wat sub_state_w(mSubState);
// Test if we are blocked or not.
if (sub_state_w->blocked)
{
Dout(dc::statemachine(mSMDebug), "Removing statemachine from condition " << (void*)sub_state_w->blocked);
sub_state_w->blocked->remove(this);
sub_state_w->blocked = NULL;
}
else
{
return false;
}
// Void last call to wait().
sub_state_w->idle = false;
// Mark that a re-entry of multiplex() is necessary.
sub_state_w->need_run = true;
#ifdef SHOW_ASSERT
// From this moment.
mDebugContPending = true;
#endif
}
if (!mMultiplexMutex.isSelfLocked())
{
multiplex(schedule_run);
}
return true;
}
void AIStateMachine::abort(void)
{
DoutEntering(dc::statemachine, "AIStateMachine::abort() [" << (void*)this << "]");
DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::abort() [" << (void*)this << "]");
bool is_waiting = false;
{
multiplex_state_type_rat state_r(mState);
sub_state_type_wat sub_state_w(mSubState);
// Mark that we are aborted, iff we didn't already finish.
sub_state_w->aborted = !sub_state_w->finished;
// No longer say we woke up when signalled() is called.
if (sub_state_w->blocked)
{
Dout(dc::statemachine(mSMDebug), "Removing statemachine from condition " << (void*)sub_state_w->blocked);
sub_state_w->blocked->remove(this);
sub_state_w->blocked = NULL;
}
// Mark that a re-entry of multiplex() is necessary.
sub_state_w->need_run = true;
// Schedule a new run when this state machine is waiting.
@@ -1128,7 +1226,7 @@ void AIStateMachine::abort(void)
void AIStateMachine::finish(void)
{
DoutEntering(dc::statemachine, "AIStateMachine::finish() [" << (void*)this << "]");
DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::finish() [" << (void*)this << "]");
#ifdef SHOW_ASSERT
{
multiplex_state_type_rat state_r(mState);
@@ -1147,7 +1245,7 @@ void AIStateMachine::finish(void)
void AIStateMachine::yield(void)
{
DoutEntering(dc::statemachine, "AIStateMachine::yield() [" << (void*)this << "]");
DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::yield() [" << (void*)this << "]");
multiplex_state_type_rat state_r(mState);
// yield() may only be called from multiplex_impl().
llassert(state_r->base_state == bs_multiplex);
@@ -1160,7 +1258,7 @@ void AIStateMachine::yield(void)
void AIStateMachine::yield(AIEngine* engine)
{
llassert(engine);
DoutEntering(dc::statemachine, "AIStateMachine::yield(" << engine->name() << ") [" << (void*)this << "]");
DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::yield(" << engine->name() << ") [" << (void*)this << "]");
#ifdef SHOW_ASSERT
{
multiplex_state_type_rat state_r(mState);
@@ -1173,9 +1271,19 @@ void AIStateMachine::yield(AIEngine* engine)
mYieldEngine = engine;
}
bool AIStateMachine::yield_if_not(AIEngine* engine)
{
if (engine && multiplex_state_type_rat(mState)->current_engine != engine)
{
yield(engine);
return true;
}
return false;
}
void AIStateMachine::yield_frame(unsigned int frames)
{
DoutEntering(dc::statemachine, "AIStateMachine::yield_frame(" << frames << ") [" << (void*)this << "]");
DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::yield_frame(" << frames << ") [" << (void*)this << "]");
mSleep = -(S64)frames;
// Sleeping is always done from the main thread.
yield(&gMainThreadEngine);
@@ -1183,7 +1291,7 @@ void AIStateMachine::yield_frame(unsigned int frames)
void AIStateMachine::yield_ms(unsigned int ms)
{
DoutEntering(dc::statemachine, "AIStateMachine::yield_ms(" << ms << ") [" << (void*)this << "]");
DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::yield_ms(" << ms << ") [" << (void*)this << "]");
mSleep = get_clock_count() + calc_clock_frequency() * ms / 1000;
// Sleeping is always done from the main thread.
yield(&gMainThreadEngine);
@@ -1233,7 +1341,7 @@ void AIEngine::threadloop(void)
engine_state_type_wat engine_state_w(mEngineState);
if (!active)
{
Dout(dc::statemachine, "Erasing state machine [" << (void*)&state_machine << "] from " << mName);
Dout(dc::statemachine(state_machine.mSMDebug), "Erasing state machine [" << (void*)&state_machine << "] from " << mName);
engine_state_w->list.erase(queued_element++);
}
else

View File

@@ -39,6 +39,7 @@
#include <list>
#include <boost/signals2.hpp>
class AIConditionBase;
class AIStateMachine;
class AIEngine
@@ -132,6 +133,7 @@ class AIStateMachine : public LLThreadSafeRefCount
struct sub_state_type {
state_type run_state;
state_type advance_state;
AIConditionBase* blocked;
bool reset;
bool need_run;
bool idle;
@@ -195,20 +197,36 @@ class AIStateMachine : public LLThreadSafeRefCount
bool mDebugAdvanceStatePending; // True while advance_state() was called by not handled yet.
bool mDebugRefCalled; // True when ref() is called (or will be called within the critial area of mMultiplexMutex).
#endif
#ifdef CWDEBUG
protected:
bool mSMDebug; // Print debug output only when true.
#endif
private:
U64 mRuntime; // Total time spent running in the main thread (in clocks).
public:
AIStateMachine(void) : mCallback(NULL), mDefaultEngine(NULL), mYieldEngine(NULL),
AIStateMachine(CWD_ONLY(bool debug)) : mCallback(NULL), mDefaultEngine(NULL), mYieldEngine(NULL),
#ifdef SHOW_ASSERT
mThreadId(AIThreadID::none), mDebugLastState(bs_killed), mDebugShouldRun(false), mDebugAborted(false), mDebugContPending(false),
mDebugSetStatePending(false), mDebugAdvanceStatePending(false), mDebugRefCalled(false),
#endif
#ifdef CWDEBUG
mSMDebug(debug),
#endif
mRuntime(0)
{ }
protected:
// The user should call finish() (or abort(), or kill() from the call back when finish_impl() calls run()), not delete a class derived from AIStateMachine directly.
virtual ~AIStateMachine() { llassert(multiplex_state_type_rat(mState)->base_state == bs_killed); }
// The user should call finish() (or abort(), or kill() from the call back when finish_impl() calls run()),
// not delete a class derived from AIStateMachine directly. Deleting it directly before calling run() is
// ok however.
virtual ~AIStateMachine()
{
#ifdef SHOW_ASSERT
base_state_type state = multiplex_state_type_rat(mState)->base_state;
llassert(state == bs_killed || state == bs_reset);
#endif
}
public:
// These functions may be called directly after creation, or from within finish_impl(), or from the call back function.
@@ -224,11 +242,13 @@ class AIStateMachine : public LLThreadSafeRefCount
void set_state(state_type new_state); // Run this state the NEXT loop.
// These functions can only be called from within multiplex_impl().
void idle(void); // Go idle unless cont() or advance_state() were called since the start of the current loop, or until they are called.
void wait(AIConditionBase& condition); // The same as idle(), but wake up when AICondition<T>::signal() is called.
void finish(void); // Mark that the state machine finished and schedule the call back.
void yield(void); // Yield to give CPU to other state machines, but do not go idle.
void yield(AIEngine* engine); // Yield to give CPU to other state machines, but do not go idle. Continue running from engine 'engine'.
void yield_frame(unsigned int frames); // Run from the main-thread engine after at least 'frames' frames have passed.
void yield_ms(unsigned int ms); // Run from the main-thread engine after roughly 'ms' miliseconds have passed.
bool yield_if_not(AIEngine* engine); // Do not really yield, unless the current engine is not 'engine'. Returns true if it switched engine.
public:
// This function can be called from multiplex_imp(), but also by a child state machine and
@@ -236,11 +256,12 @@ class AIStateMachine : public LLThreadSafeRefCount
// to access this state machine.
void abort(void); // Abort the state machine (unsuccessful finish).
// These are the only two functions that can be called by any thread at any moment.
// These are the only three functions that can be called by any thread at any moment.
// Those threads should use an LLPointer<AIStateMachine> to access this state machine.
void cont(void); // Guarantee at least one full run of multiplex() after this function is called. Cancels the last call to idle().
void advance_state(state_type new_state); // Guarantee at least one full run of multiplex() after this function is called
// iff new_state is larger than the last state that was processed.
bool signalled(void); // Call cont() iff this state machine is still blocked after a call to wait(). Returns false if it already unblocked.
public:
// Accessors.

View File

@@ -181,7 +181,11 @@ class AIStateMachineThreadBase : public AIStateMachine {
static state_type const max_state = wait_stopped + 1;
protected:
AIStateMachineThreadBase(void) { }
AIStateMachineThreadBase(CWD_ONLY(bool debug))
#ifdef CWDEBUG
: AIStateMachine(debug)
#endif
{ }
private:
// Handle initializing the object.
@@ -217,7 +221,10 @@ class AIStateMachineThread : public AIStateMachineThreadBase {
public:
// Constructor.
AIStateMachineThread(void)
AIStateMachineThread(CWD_ONLY(bool debug))
#ifdef CWDEBUG
: AIStateMachineThreadBase(debug)
#endif
{
*AIThreadImpl::StateMachineThread_wat(mThreadImpl.mStateMachineThread) = this;
}

View File

@@ -76,7 +76,11 @@ class AITimer : public AIStateMachine {
F64 mInterval; //!< Input variable: interval after which the event will be generated, in seconds.
public:
AITimer(void) : mInterval(0) { DoutEntering(dc::statemachine, "AITimer(void) [" << (void*)this << "]"); }
AITimer(CWD_ONLY(bool debug = false)) :
#ifdef CWDEBUG
AIStateMachine(debug),
#endif
mInterval(0) { DoutEntering(dc::statemachine(mSMDebug), "AITimer(void) [" << (void*)this << "]"); }
/**
* @brief Set the interval after which the timer should expire.
@@ -96,7 +100,7 @@ class AITimer : public AIStateMachine {
protected:
// Call finish() (or abort()), not delete.
/*virtual*/ ~AITimer() { DoutEntering(dc::statemachine, "~AITimer() [" << (void*)this << "]"); mFrameTimer.cancel(); }
/*virtual*/ ~AITimer() { DoutEntering(dc::statemachine(mSMDebug), "~AITimer() [" << (void*)this << "]"); mFrameTimer.cancel(); }
// Handle initializing the object.
/*virtual*/ void initialize_impl(void);

View File

@@ -46,6 +46,10 @@ if (WINDOWS)
set(MSVC_DIR 10.0)
set(MSVC_SUFFIX 100)
endif (MSVC10)
if (MSVC11)
set(MSVC_DIR 11.0)
set(MSVC_SUFFIX 110)
endif (MSVC11)
# Remove default /Zm1000 flag that cmake inserts
string (REPLACE "/Zm1000" " " CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
@@ -78,11 +82,17 @@ if (WINDOWS)
/W3
/c
/Zc:forScope
/Zc:wchar_t-
/Zc:wchar_t-
/nologo
/Oy-
/arch:SSE2
)
# SSE2 is implied on win64
if(WORD_SIZE EQUAL 32)
add_definitions(/arch:SSE2)
else(WORD_SIZE EQUAL 32)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /wd4267 /wd4250 /wd4244")
endif(WORD_SIZE EQUAL 32)
# 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)")

View File

@@ -81,6 +81,7 @@ set(cmake_SOURCE_FILES
Linking.cmake
MediaPluginBase.cmake
NDOF.cmake
NVAPI.cmake
OPENAL.cmake
OpenGL.cmake
OpenJPEG.cmake

View File

@@ -6,6 +6,14 @@
include(CMakeCopyIfDifferent)
if(WORD_SIZE EQUAL 32)
set(debug_libs_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/debug")
set(release_libs_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/release")
else(WORD_SIZE EQUAL 32)
set(debug_libs_dir "${CMAKE_SOURCE_DIR}/../libraries/x86_64-win/lib/debug")
set(release_libs_dir "${CMAKE_SOURCE_DIR}/../libraries/x86_64-win/lib/release")
endif(WORD_SIZE EQUAL 32)
set(vivox_src_dir "${CMAKE_SOURCE_DIR}/newview/vivox-runtime/i686-win32")
set(vivox_files
SLVoice.exe
@@ -23,7 +31,7 @@ copy_if_different(
set(all_targets ${all_targets} ${out_targets})
set(debug_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/debug")
set(debug_src_dir "${debug_libs_dir}")
set(debug_files
libhunspell.dll
libapr-1.dll
@@ -44,7 +52,7 @@ copy_if_different(
set(all_targets ${all_targets} ${out_targets})
# Debug config runtime files required for the plugin test mule
set(plugintest_debug_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/debug")
set(plugintest_debug_src_dir "${debug_libs_dir}")
set(plugintest_debug_files
libeay32.dll
qtcored4.dll
@@ -63,7 +71,7 @@ copy_if_different(
set(all_targets ${all_targets} ${out_targets})
# Debug config runtime files required for the plugin test mule (Qt image format plugins)
set(plugintest_debug_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/debug/imageformats")
set(plugintest_debug_src_dir "${debug_libs_dir}/imageformats")
set(plugintest_debug_files
qgifd4.dll
qicod4.dll
@@ -89,7 +97,7 @@ copy_if_different(
set(all_targets ${all_targets} ${out_targets})
# Release & ReleaseDebInfo config runtime files required for the plugin test mule
set(plugintest_release_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/release")
set(plugintest_release_src_dir "${release_libs_dir}")
set(plugintest_release_files
libeay32.dll
qtcore4.dll
@@ -116,7 +124,7 @@ copy_if_different(
set(all_targets ${all_targets} ${out_targets})
# Release & ReleaseDebInfo config runtime files required for the plugin test mule (Qt image format plugins)
set(plugintest_release_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/release/imageformats")
set(plugintest_release_src_dir "${release_libs_dir}/imageformats")
set(plugintest_release_files
qgif4.dll
qico4.dll
@@ -158,7 +166,7 @@ copy_if_different(
set(all_targets ${all_targets} ${out_targets})
# Debug config runtime files required for the plugins
set(plugins_debug_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/debug")
set(plugins_debug_src_dir "${debug_libs_dir}")
set(plugins_debug_files
libeay32.dll
qtcored4.dll
@@ -177,7 +185,7 @@ copy_if_different(
set(all_targets ${all_targets} ${out_targets})
# Release & ReleaseDebInfo config runtime files required for the plugins
set(plugins_release_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/release")
set(plugins_release_src_dir "${release_libs_dir}")
set(plugins_release_files
libeay32.dll
qtcore4.dll
@@ -203,9 +211,9 @@ copy_if_different(
)
set(all_targets ${all_targets} ${out_targets})
set(release_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/release")
set(release_src_dir "${release_libs_dir}")
set(release_files
libtcmalloc_minimal.dll
libhunspell.dll
libapr-1.dll
libaprutil-1.dll
@@ -216,8 +224,21 @@ set(release_files
glod.dll
)
if(WORD_SIZE EQUAL 32)
set(release_files ${release_files}
libtcmalloc_minimal.dll
)
endif(WORD_SIZE EQUAL 32)
if(FMODEX)
find_path(FMODEX_BINARY_DIR fmodex.dll
if (WORD_SIZE EQUAL 32)
set(fmodex_dll_file "fmodex.dll")
else (WORD_SIZE EQUAL 32)
set(fmodex_dll_file "fmodex64.dll")
endif (WORD_SIZE EQUAL 32)
find_path(FMODEX_BINARY_DIR "${fmodex_dll_file}"
"${release_src_dir}"
"${FMODEX_SDK_DIR}/api"
"${FMODEX_SDK_DIR}"
@@ -225,11 +246,11 @@ if(FMODEX)
)
if(FMODEX_BINARY_DIR)
copy_if_different("${FMODEX_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/Release" out_targets fmodex.dll)
copy_if_different("${FMODEX_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/Release" out_targets "${fmodex_dll_file}")
set(all_targets ${all_targets} ${out_targets})
copy_if_different("${FMODEX_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo" out_targets fmodex.dll)
copy_if_different("${FMODEX_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo" out_targets "${fmodex_dll_file}")
set(all_targets ${all_targets} ${out_targets})
copy_if_different("${FMODEX_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/Debug" out_targets fmodex.dll)
copy_if_different("${FMODEX_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/Debug" out_targets "${fmodex_dll_file}")
set(all_targets ${all_targets} ${out_targets})
endif(FMODEX_BINARY_DIR)
endif(FMODEX)
@@ -285,105 +306,6 @@ copy_if_different(
)
set(all_targets ${all_targets} ${out_targets})
# Copy MS C runtime dlls, required for packaging.
# *TODO - Adapt this to support VC9
if (MSVC80)
FIND_PATH(debug_msvc8_redist_path msvcr80d.dll
PATHS
[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0\\Setup\\VC;ProductDir]/redist/Debug_NonRedist/x86/Microsoft.VC80.DebugCRT
NO_DEFAULT_PATH
NO_DEFAULT_PATH
)
if(EXISTS ${debug_msvc8_redist_path})
set(debug_msvc8_files
msvcr80d.dll
msvcp80d.dll
Microsoft.VC80.DebugCRT.manifest
)
copy_if_different(
${debug_msvc8_redist_path}
"${CMAKE_CURRENT_BINARY_DIR}/Debug"
out_targets
${debug_msvc8_files}
)
set(all_targets ${all_targets} ${out_targets})
set(debug_appconfig_file ${CMAKE_CURRENT_BINARY_DIR}/Debug/${VIEWER_BINARY_NAME}.exe.config)
add_custom_command(
OUTPUT ${debug_appconfig_file}
COMMAND ${PYTHON_EXECUTABLE}
ARGS
${CMAKE_CURRENT_SOURCE_DIR}/build_win32_appConfig.py
${CMAKE_CURRENT_BINARY_DIR}/Debug/Microsoft.VC80.DebugCRT.manifest
${CMAKE_CURRENT_SOURCE_DIR}/SecondLifeDebug.exe.config
${debug_appconfig_file}
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/Debug/Microsoft.VC80.DebugCRT.manifest
COMMENT "Creating debug app config file"
)
endif (EXISTS ${debug_msvc8_redist_path})
FIND_PATH(release_msvc8_redist_path msvcr80.dll
PATHS
[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0\\Setup\\VC;ProductDir]/redist/x86/Microsoft.VC80.CRT
NO_DEFAULT_PATH
NO_DEFAULT_PATH
)
if(EXISTS ${release_msvc8_redist_path})
set(release_msvc8_files
msvcr80.dll
msvcp80.dll
Microsoft.VC80.CRT.manifest
)
copy_if_different(
${release_msvc8_redist_path}
"${CMAKE_CURRENT_BINARY_DIR}/Release"
out_targets
${release_msvc8_files}
)
set(all_targets ${all_targets} ${out_targets})
copy_if_different(
${release_msvc8_redist_path}
"${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo"
out_targets
${release_msvc8_files}
)
set(all_targets ${all_targets} ${out_targets})
set(release_appconfig_file ${CMAKE_CURRENT_BINARY_DIR}/Release/${VIEWER_BINARY_NAME}.exe.config)
add_custom_command(
OUTPUT ${release_appconfig_file}
COMMAND ${PYTHON_EXECUTABLE}
ARGS
${CMAKE_CURRENT_SOURCE_DIR}/build_win32_appConfig.py
${CMAKE_CURRENT_BINARY_DIR}/Release/Microsoft.VC80.CRT.manifest
${CMAKE_CURRENT_SOURCE_DIR}/SecondLife.exe.config
${release_appconfig_file}
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/Release/Microsoft.VC80.CRT.manifest
COMMENT "Creating release app config file"
)
set(relwithdebinfo_appconfig_file ${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo/${VIEWER_BINARY_NAME}.exe.config)
add_custom_command(
OUTPUT ${relwithdebinfo_appconfig_file}
COMMAND ${PYTHON_EXECUTABLE}
ARGS
${CMAKE_CURRENT_SOURCE_DIR}/build_win32_appConfig.py
${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo/Microsoft.VC80.CRT.manifest
${CMAKE_CURRENT_SOURCE_DIR}/SecondLife.exe.config
${relwithdebinfo_appconfig_file}
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo/Microsoft.VC80.CRT.manifest
COMMENT "Creating relwithdebinfo app config file"
)
endif (EXISTS ${release_msvc8_redist_path})
endif (MSVC80)
add_custom_target(copy_win_libs ALL
DEPENDS
${all_targets}

View File

@@ -44,10 +44,15 @@ if (WINDOWS)
"$ENV{ProgramFiles(x86)}/Windows Kits/8.0"
)
if (WIN_KIT_ROOT_DIR)
find_path (WIN_KIT_LIB_DIR dxguid.lib
"${WIN_KIT_ROOT_DIR}/Lib/winv6.3/um/${DIRECTX_ARCHITECTURE}"
"${WIN_KIT_ROOT_DIR}/Lib/Win8/um/${DIRECTX_ARCHITECTURE}"
)
if (WIN_KIT_ROOT_DIR AND WIN_KIT_LIB_DIR)
set (DIRECTX_INCLUDE_DIR "${WIN_KIT_ROOT_DIR}/Include/um" "${WIN_KIT_ROOT_DIR}/Include/shared")
set (DIRECTX_LIBRARY_DIR "${WIN_KIT_ROOT_DIR}/Lib/Win8/um/${DIRECTX_ARCHITECTURE}")
endif (WIN_KIT_ROOT_DIR)
set (DIRECTX_LIBRARY_DIR "${WIN_KIT_LIB_DIR}")
endif (WIN_KIT_ROOT_DIR AND WIN_KIT_LIB_DIR)
endif (DIRECTX_ROOT_DIR)
if (DIRECTX_INCLUDE_DIR)

View File

@@ -16,7 +16,7 @@ if (NOT FMODEX_LIBRARY)
)
elseif(WORD_SIZE EQUAL 64)
find_library(FMODEX_LIBRARY
fmodex64 fmodexL64
fmodex64_vc fmodexL64_vc fmodex64 fmodexL64
PATHS
"${FMODEX_SDK_DIR}/api/lib"
"${FMODEX_SDK_DIR}/api"
@@ -25,21 +25,31 @@ if (NOT FMODEX_LIBRARY)
)
endif(WORD_SIZE EQUAL 32)
endif(FMODEX_SDK_DIR)
if(WINDOWS AND NOT FMODEX_LIBRARY)
set(FMODEX_PROG_DIR "$ENV{PROGRAMFILES}/FMOD SoundSystem/FMOD Programmers API Windows")
find_library(FMODEX_LIBRARY
fmodex_vc fmodexL_vc
PATHS
"${FMODEX_PROG_DIR}/api/lib"
"${FMODEX_PROG_DIR}/api"
"${FMODEX_PROG_DIR}"
)
if(WINDOWS AND NOT FMODEX_SDK_DIR)
GET_FILENAME_COMPONENT(FMODEX_PROG_DIR [HKEY_CURRENT_USER\\Software\\FMOD\ Programmers\ API\ Windows] ABSOLUTE CACHE)
if(WORD_SIZE EQUAL 32)
find_library(FMODEX_LIBRARY
fmodex_vc fmodexL_vc
PATHS
"${FMODEX_PROG_DIR}/api/lib"
"${FMODEX_PROG_DIR}/api"
"${FMODEX_PROG_DIR}"
)
else(WORD_SIZE EQUAL 32)
find_library(FMODEX_LIBRARY
fmodex64_vc fmodexL64_vc
PATHS
"${FMODEX_PROG_DIR}/api/lib"
"${FMODEX_PROG_DIR}/api"
"${FMODEX_PROG_DIR}"
)
endif(WORD_SIZE EQUAL 32)
if(FMODEX_LIBRARY)
message(STATUS "Found fmodex in ${FMODEX_PROG_DIR}")
set(FMODEX_SDK_DIR "${FMODEX_PROG_DIR}")
set(FMODEX_SDK_DIR "${FMODEX_PROG_DIR}" CACHE PATH "Path to the FMOD Ex SDK." FORCE)
endif(FMODEX_LIBRARY)
endif(WINDOWS AND NOT FMODEX_LIBRARY)
endif(WINDOWS AND NOT FMODEX_SDK_DIR)
endif (NOT FMODEX_LIBRARY)
find_path(FMODEX_INCLUDE_DIR fmod.hpp

View File

@@ -5,22 +5,29 @@ set(${CMAKE_CURRENT_LIST_FILE}_INCLUDED "YES")
include(Variables)
if (NOT STANDALONE)
if (WINDOWS)
set(ARCH_PREBUILT_DIRS ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib)
set(ARCH_PREBUILT_DIRS_RELEASE ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib/release)
set(ARCH_PREBUILT_DIRS_DEBUG ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib/debug)
elseif (LINUX)
set(ARCH_PREBUILT_DIRS ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib/release)
set(ARCH_PREBUILT_DIRS_RELEASE ${ARCH_PREBUILT_DIRS})
set(ARCH_PREBUILT_DIRS_DEBUG ${ARCH_PREBUILT_DIRS})
elseif (DARWIN)
set(ARCH_PREBUILT_DIRS ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib)
set(ARCH_PREBUILT_DIRS_RELEASE ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib/release)
set(ARCH_PREBUILT_DIRS_DEBUG ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib/debug)
endif (WINDOWS)
set(ARCH_PREBUILT_DIRS ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib)
set(ARCH_PREBUILT_DIRS_RELEASE ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib/release)
set(ARCH_PREBUILT_DIRS_DEBUG ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib/debug)
if(WINDOWS OR ${CMAKE_GENERATOR} MATCHES "Xcode")
# the cmake xcode and VS generators implicitly append ${CMAKE_CFG_INTDIR} to the library paths for us
# fortunately both windows and darwin are case insensitive filesystems so this works.
set(ARCH_PREBUILT_LINK_DIRS "${ARCH_PREBUILT_DIRS}")
else(WINDOWS OR ${CMAKE_GENERATOR} MATCHES "Xcode")
# else block is for linux and any other makefile based generators
string(TOLOWER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_LOWER)
set(ARCH_PREBUILT_LINK_DIRS ${ARCH_PREBUILT_DIRS}/${CMAKE_BUILD_TYPE_LOWER})
endif(WINDOWS OR ${CMAKE_GENERATOR} MATCHES "Xcode")
if (NOT "${CMAKE_BUILD_TYPE}" STREQUAL "Release")
# When we're building something other than Release, append the
# packages/lib/release directory to deal with autobuild packages that don't
# provide (e.g.) lib/debug libraries.
list(APPEND ARCH_PREBUILT_LINK_DIRS ${ARCH_PREBUILT_DIRS_RELEASE})
endif (NOT "${CMAKE_BUILD_TYPE}" STREQUAL "Release")
endif (NOT STANDALONE)
link_directories(${ARCH_PREBUILT_DIRS})
link_directories(${ARCH_PREBUILT_LINK_DIRS})
if (LINUX)
set(DL_LIBRARY dl)

21
indra/cmake/NVAPI.cmake Normal file
View File

@@ -0,0 +1,21 @@
# -*- cmake -*-
include(Prebuilt)
include(Variables)
set(NVAPI ON CACHE BOOL "Use NVAPI.")
if (NVAPI)
if (WINDOWS)
use_prebuilt_binary(nvapi)
if (WORD_SIZE EQUAL 32)
set(NVAPI_LIBRARY nvapi)
elseif (WORD_SIZE EQUAL 64)
set(NVAPI_LIBRARY nvapi64)
endif (WORD_SIZE EQUAL 32)
else (WINDOWS)
set(NVAPI_LIBRARY "")
endif (WINDOWS)
else (NVAPI)
set(NVAPI_LIBRARY "")
endif (NVAPI)

View File

@@ -8,7 +8,7 @@ endif(INSTALL_PROPRIETARY)
if (DARWIN)
include(CMakeFindFrameworks)
find_library(QUICKTIME_LIBRARY QuickTime)
elseif (WINDOWS)
elseif (WINDOWS AND WORD_SIZE EQUAL 32)
set(QUICKTIME_SDK_DIR "$ENV{PROGRAMFILES}/QuickTime SDK"
CACHE PATH "Location of the QuickTime SDK.")

View File

@@ -37,10 +37,15 @@ set(LIBS_PREBUILT_DIR ${CMAKE_SOURCE_DIR}/../libraries CACHE PATH
if (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
set(WINDOWS ON BOOL FORCE)
set(ARCH i686)
set(LL_ARCH ${ARCH}_win32)
set(LL_ARCH_DIR ${ARCH}-win32)
set(WORD_SIZE 32)
if (WORD_SIZE EQUAL 32)
set(ARCH i686)
set(LL_ARCH ${ARCH}_win32)
set(LL_ARCH_DIR ${ARCH}-win32)
elseif (WORD_SIZE EQUAL 64)
set(ARCH x86_64)
set(LL_ARCH ${ARCH}_win)
set(LL_ARCH_DIR ${ARCH}-win)
endif (WORD_SIZE EQUAL 32)
endif (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
@@ -92,7 +97,7 @@ endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(DARWIN 1)
if(${CMAKE_GENERATOR} MATCHES Xcode)
if(${CMAKE_GENERATOR} MATCHES "Xcode")
#SDK Compiler and Deployment targets for XCode
if (${XCODE_VERSION} VERSION_LESS 4.0.0)
set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.5.sdk)
@@ -101,10 +106,10 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.6.sdk)
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.6)
endif (${XCODE_VERSION} VERSION_LESS 4.0.0)
else(${CMAKE_GENERATOR} MATCHES Xcode)
else(${CMAKE_GENERATOR} MATCHES "Xcode")
set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.6.sdk)
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.6)
endif(${CMAKE_GENERATOR} MATCHES Xcode)
endif(${CMAKE_GENERATOR} MATCHES "Xcode")
set(CMAKE_XCODE_ATTRIBUTE_GCC_VERSION "com.apple.compilers.llvmgcc42")
@@ -119,15 +124,17 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(LL_ARCH_DIR universal-darwin)
endif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
if (WINDOWS)
if (WINDOWS AND WORD_SIZE EQUAL 32)
set(PREBUILT_TYPE windows)
elseif (WINDOWS AND WORD_SIZE EQUAL 64)
set(PREBUILT_TYPE windows64)
elseif(DARWIN)
set(PREBUILT_TYPE darwin)
elseif(LINUX AND WORD_SIZE EQUAL 32)
set(PREBUILT_TYPE linux)
elseif(LINUX AND WORD_SIZE EQUAL 64)
set(PREBUILT_TYPE linux64)
endif(WINDOWS)
endif(WINDOWS AND WORD_SIZE EQUAL 32)
# Default deploy grid
set(GRID agni CACHE STRING "Target Grid")

View File

@@ -144,6 +144,7 @@ extern LL_COMMON_API fake_channel const snapshot;
#define CWDEBUG_MARKER 0
#define BACKTRACE do { } while(0)
#define CWD_ONLY(...)
#endif // !DOXYGEN
@@ -180,6 +181,7 @@ extern LL_COMMON_API fake_channel const snapshot;
#include <set>
#define CWD_API __attribute__ ((visibility("default")))
#define CWD_ONLY(...) __VA_ARGS__
//! Debug specific code.
namespace debug {

View File

@@ -443,9 +443,15 @@ class WindowsSetup(PlatformSetup):
'vc100' : {
'gen' : r'Visual Studio 10',
'ver' : r'10.0'
},
'vc110' : {
'gen' : r'Visual Studio 11',
'ver' : r'11.0'
}
}
gens['vs2010'] = gens['vc100']
gens['vs2012'] = gens['vc110']
search_path = r'C:\windows'
exe_suffixes = ('.exe', '.bat', '.com')
@@ -503,6 +509,9 @@ class WindowsSetup(PlatformSetup):
project_name=self.project_name,
word_size=self.word_size,
)
if self.word_size == 64:
args["generator"] += r' Win64'
#if simple:
# return 'cmake %(opts)s "%(dir)s"' % args
return ('cmake -G "%(generator)s" '

View File

@@ -192,6 +192,8 @@ def usage(srctree=""):
arg['description'] % nd)
def main():
print "cwd:", os.getcwd()
print " ".join(sys.argv)
option_names = [arg['name'] + '=' for arg in ARGUMENTS]
option_names.append('help')
options, remainder = getopt.getopt(sys.argv[1:], "", option_names)
@@ -266,7 +268,7 @@ class LLManifest(object):
__metaclass__ = LLManifestRegistry
manifests = {}
def for_platform(self, platform, arch = None):
if arch:
if arch and platform != "windows":
platform = platform + '_' + arch
return self.manifests[platform.lower()]
for_platform = classmethod(for_platform)

View File

@@ -138,7 +138,7 @@ namespace HACD
if (m_callBack)
{
char msg[1024];
sprintf(msg, "nCC %lu\n", m_graph.m_nCCs);
sprintf(msg, "nCC %zu\n", m_graph.m_nCCs);
(*m_callBack)(msg, 0.0, 0.0, m_graph.GetNVertices());
}
@@ -879,7 +879,7 @@ namespace HACD
if (m_callBack)
{
char msg[1024];
sprintf(msg, "\t CH(%zu) \t %zu \t %lf \t %zu \t %f \t %zu\n", v, static_cast<unsigned long>(p), m_graph.m_vertices[v].m_concavity, m_graph.m_vertices[v].m_distPoints.Size(), m_graph.m_vertices[v].m_surf*100.0/m_area, m_graph.m_vertices[v].m_ancestors.size());
sprintf(msg, "\t CH(%zu) \t %zu \t %lf \t %zu \t %f \t %zu\n", v, p, m_graph.m_vertices[v].m_concavity, m_graph.m_vertices[v].m_distPoints.Size(), m_graph.m_vertices[v].m_surf*100.0/m_area, m_graph.m_vertices[v].m_ancestors.size());
(*m_callBack)(msg, 0.0, 0.0, m_nClusters);
p++;
}

View File

@@ -22,7 +22,9 @@
#include <set>
#include <vector>
#include <queue>
#if defined(_MSC_VER) && _MSC_VER >= 1700
#include <functional>
#endif
namespace HACD
{
const double sc_pi = 3.14159265;

View File

@@ -106,7 +106,7 @@ namespace HACD
m_nMaxNodes = 0;
for(size_t k = 0; k < maxDepth; k++)
{
m_nMaxNodes += (1 << maxDepth);
m_nMaxNodes += (static_cast<size_t>(1) << maxDepth);
}
m_nodes = new RMNode[m_nMaxNodes];
RMNode & root = m_nodes[AddNode()];

View File

@@ -117,7 +117,8 @@ public:
/*virtual*/ void stopAnimating(BOOL upload_bake);
/*virtual*/ BOOL linkDrivenParams(visual_param_mapper mapper, BOOL only_cross_params);
/*virtual*/ void resetDrivenParams();
/*virtual*/ char const* getTypeString(void) const { return "param_driver"; }
// LLViewerVisualParam Virtual functions
/*virtual*/ F32 getTotalDistortion();
/*virtual*/ const LLVector4a& getAvgDistortion();

View File

@@ -173,6 +173,7 @@ public:
// LLVisualParam Virtual functions
///*virtual*/ BOOL parseData(LLXmlTreeNode* node);
/*virtual*/ void apply( ESex sex );
/*virtual*/ char const* getTypeString(void) const { return "param_morph"; }
// LLViewerVisualParam Virtual functions
/*virtual*/ F32 getTotalDistortion();

View File

@@ -109,7 +109,8 @@ public:
// LLVisualParam Virtual functions
///*virtual*/ BOOL parseData(LLXmlTreeNode* node);
/*virtual*/ void apply( ESex sex );
/*virtual*/ char const* getTypeString(void) const { return "param_skeleton"; }
// LLViewerVisualParam Virtual functions
/*virtual*/ F32 getTotalDistortion() { return 0.1f; }
/*virtual*/ const LLVector4a& getAvgDistortion() { return mDefaultVec; }

View File

@@ -86,6 +86,7 @@ public:
/*virtual*/ void setWeight(F32 weight, BOOL upload_bake);
/*virtual*/ void setAnimationTarget(F32 target_value, BOOL upload_bake);
/*virtual*/ void animate(F32 delta, BOOL upload_bake);
/*virtual*/ char const* getTypeString(void) const { return "param_alpha"; }
// LLViewerVisualParam Virtual functions
/*virtual*/ F32 getTotalDistortion() { return 1.f; }
@@ -177,7 +178,7 @@ public:
/*virtual*/ void setWeight(F32 weight, BOOL upload_bake);
/*virtual*/ void setAnimationTarget(F32 target_value, BOOL upload_bake);
/*virtual*/ void animate(F32 delta, BOOL upload_bake);
/*virtual*/ char const* getTypeString(void) const { return "param_color"; }
// LLViewerVisualParam Virtual functions
/*virtual*/ F32 getTotalDistortion() { return 1.f; }

View File

@@ -143,6 +143,12 @@ BOOL LLViewerVisualParam::setInfo(LLViewerVisualParamInfo *info)
return TRUE;
}
//virtual
std::string LLViewerVisualParam::getDumpWearableTypeName(void) const
{
return LLWearableType::getTypeName(LLWearableType::EType(getInfo()->mWearableType));
}
/*
//=============================================================================
// These virtual functions should always be overridden,

View File

@@ -82,6 +82,7 @@ public:
// LLVisualParam Virtual functions
///*virtual*/ BOOL parseData(LLXmlTreeNode* node);
/*virtual*/ std::string getDumpWearableTypeName(void) const;
// New Virtual functions
virtual F32 getTotalDistortion() = 0;

View File

@@ -41,6 +41,7 @@ class LLVisualParam;
class LLTexGlobalColorInfo;
class LLTexGlobalColor;
class LLAvatarAppearance;
class AIArchetype;
// Abstract class.
class LLWearable

View File

@@ -59,8 +59,13 @@ bool attemptDelayLoad()
{
__try
{
#if defined(_WIN64)
if( FAILED( __HrLoadAllImportsForDll( "fmodex64.dll" ) ) )
return false;
#else
if( FAILED( __HrLoadAllImportsForDll( "fmodex.dll" ) ) )
return false;
#endif
}
__except( EXCEPTION_EXECUTE_HANDLER )
{

View File

@@ -162,6 +162,10 @@ public:
void setParamLocation(EParamLocation loc);
EParamLocation getParamLocation() const { return mParamLocation; }
// Singu extensions. Used for dumping the archtype.
virtual char const* getTypeString(void) const = 0;
virtual std::string getDumpWearableTypeName(void) const = 0;
protected:
F32 mCurWeight; // current weight
F32 mLastWeight; // last weight

View File

@@ -17,6 +17,8 @@ include_directories(
)
set(llcommon_SOURCE_FILES
aialert.cpp
aifile.cpp
aiframetimer.cpp
aithreadid.cpp
imageids.cpp
@@ -106,6 +108,8 @@ set(llcommon_SOURCE_FILES
set(llcommon_HEADER_FILES
CMakeLists.txt
aialert.h
aifile.h
aiframetimer.h
airecursive.h
aithreadid.h

View File

@@ -0,0 +1,82 @@
/**
* @file aialert.cpp
*
* 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.
*
* 02/11/2013
* - Initial version, written by Aleric Inglewood @ SL
*
* 05/11/2013
* Moved everything in namespace AIAlert, except AIArgs.
*/
#include "aialert.h"
namespace AIAlert
{
Error::Error(Prefix const& prefix, modal_nt type,
Error const& alert) : mLines(alert.mLines), mModal(type)
{
if (alert.mModal == modal) mModal = modal;
if (prefix) mLines.push_front(Line(prefix));
}
Error::Error(Prefix const& prefix, modal_nt type,
std::string const& xml_desc, AIArgs const& args) : mModal(type)
{
if (prefix) mLines.push_back(Line(prefix));
mLines.push_back(Line(xml_desc, args));
}
Error::Error(Prefix const& prefix, modal_nt type,
Error const& alert,
std::string const& xml_desc, AIArgs const& args) : mLines(alert.mLines), mModal(type)
{
if (alert.mModal == modal) mModal = modal;
if (prefix) mLines.push_back(Line(prefix, !mLines.empty()));
mLines.push_back(Line(xml_desc, args));
}
Error::Error(Prefix const& prefix, modal_nt type,
std::string const& xml_desc,
Error const& alert) : mLines(alert.mLines), mModal(type)
{
if (alert.mModal == modal) mModal = modal;
if (!mLines.empty()) { mLines.front().set_newline(); }
mLines.push_front(Line(xml_desc));
if (prefix) mLines.push_front(Line(prefix));
}
Error::Error(Prefix const& prefix, modal_nt type,
std::string const& xml_desc, AIArgs const& args,
Error const& alert) : mLines(alert.mLines), mModal(type)
{
if (alert.mModal == modal) mModal = modal;
if (!mLines.empty()) { mLines.front().set_newline(); }
mLines.push_front(Line(xml_desc, args));
if (prefix) mLines.push_front(Line(prefix));
}
} // namespace AIAlert

306
indra/llcommon/aialert.h Normal file
View File

@@ -0,0 +1,306 @@
/**
* @file aialert.h
* @brief Declaration of AIArgs and AIAlert classes.
*
* 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.
*
* 02/11/2013
* Initial version, written by Aleric Inglewood @ SL
*
* 05/11/2013
* Moved everything in namespace AIAlert, except AIArgs.
*/
#ifndef AI_ALERT
#define AI_ALERT
#include "llpreprocessor.h"
#include "llstring.h"
#include <deque>
#include <exception>
//===================================================================================================================================
// Facility to throw errors that can easily be converted to an informative pop-up floater for the user.
// Throw arbitrary class.
#define THROW_ALERT_CLASS(Alert, ...) throw Alert(AIAlert::Prefix(), AIAlert::not_modal, __VA_ARGS__)
#define THROW_MALERT_CLASS(Alert, ...) throw Alert(AIAlert::Prefix(), AIAlert::modal, __VA_ARGS__)
#ifdef __GNUC__
#define THROW_FALERT_CLASS(Alert, ...) throw Alert(AIAlert::Prefix(__PRETTY_FUNCTION__, AIAlert::pretty_function_prefix), AIAlert::not_modal, __VA_ARGS__)
#define THROW_FMALERT_CLASS(Alert, ...) throw Alert(AIAlert::Prefix(__PRETTY_FUNCTION__, AIAlert::pretty_function_prefix), AIAlert::modal, __VA_ARGS__)
#else
#define THROW_FALERT_CLASS(Alert, ...) throw Alert(AIAlert::Prefix(__FUNCTION__, AIAlert::pretty_function_prefix), AIAlert::not_modal, __VA_ARGS__)
#define THROW_FMALERT_CLASS(Alert, ...) throw Alert(AIAlert::Prefix(__FUNCTION__, AIAlert::pretty_function_prefix), AIAlert::modal, __VA_ARGS__)
#endif
// Shortcut to throw AIAlert::Error.
#define THROW_ALERT(...) THROW_ALERT_CLASS(AIAlert::Error, __VA_ARGS__)
#define THROW_MALERT(...) THROW_MALERT_CLASS(AIAlert::Error, __VA_ARGS__)
#define THROW_FALERT(...) THROW_FALERT_CLASS(AIAlert::Error, __VA_ARGS__)
#define THROW_FMALERT(...) THROW_FMALERT_CLASS(AIAlert::Error, __VA_ARGS__)
// Shortcut to throw AIAlert::ErrorCode.
#define THROW_ALERTC(...) THROW_ALERT_CLASS(AIAlert::ErrorCode, __VA_ARGS__)
#define THROW_MALERTC(...) THROW_MALERT_CLASS(AIAlert::ErrorCode, __VA_ARGS__)
#define THROW_FALERTC(...) THROW_FALERT_CLASS(AIAlert::ErrorCode, __VA_ARGS__)
#define THROW_FMALERTC(...) THROW_FMALERT_CLASS(AIAlert::ErrorCode, __VA_ARGS__)
// Shortcut to throw AIAlert::ErrorCode with errno as code.
#define THROW_ALERTE(...) do { int errn = errno; THROW_ALERT_CLASS(AIAlert::ErrorCode, errn, __VA_ARGS__); } while(0)
#define THROW_MALERTE(...) do { int errn = errno; THROW_MALERT_CLASS(AIAlert::ErrorCode, errn, __VA_ARGS__); } while(0)
#define THROW_FALERTE(...) do { int errn = errno; THROW_FALERT_CLASS(AIAlert::ErrorCode, errn, __VA_ARGS__); } while(0)
#define THROW_FMALERTE(...) do { int errn = errno; THROW_FMALERT_CLASS(AIAlert::ErrorCode, errn, __VA_ARGS__); } while(0)
// Examples
#ifdef EXAMPLE_CODE
//----------------------------------------------------------
// To show the alert box:
catch (AIAlert::Error const& error)
{
AIAlert::add(error); // Optionally pass pretty_function_prefix as second parameter to *suppress* that output.
}
// or, for example
catch (AIAlert::ErrorCode const& error)
{
if (error.getCode() != EEXIST)
{
AIAlert::add(alert, AIAlert::pretty_function_prefix);
}
}
//----------------------------------------------------------
// To throw alerts:
THROW_ALERT("ExampleKey"); // A) Lookup "ExampleKey" in strings.xml and show translation.
THROW_ALERT("ExampleKey", AIArgs("[FIRST]", first)("[SECOND]", second)(...etc...)); // B) Same as A, but replace [FIRST] with first, [SECOND] with second, etc.
THROW_ALERT("ExampleKey", error); // C) As A, but followed by a colon and a newline, and then the text of 'error'.
THROW_ALERT(error, "ExampleKey"); // D) The text of 'error', followed by a colon and a newline and then as A.
THROW_ALERT("ExampleKey", AIArgs("[FIRST]", first)("[SECOND]", second), error); // E) As B, but followed by a colon and a newline, and then the text of 'error'.
THROW_ALERT(error, "ExampleKey", AIArgs("[FIRST]", first)("[SECOND]", second)); // F) The text of 'error', followed by a colon and a newline and then as B.
// where 'error' is a caught Error object (as above) in a rethrow.
// Prepend ALERT with M and/or F to make the alert box Modal and/or prepend the text with the current function name.
// For example,
THROW_MFALERT("ExampleKey", AIArgs("[FIRST]", first)); // Throw a Modal alert box that is prefixed with the current Function name.
// Append E after ALERT to throw an ErrorCode class that contains the current errno.
// For example,
THROW_FALERTE("ExampleKey", AIArgs("[FIRST]", first)); // Throw an alert box that is prefixed with the current Function name and pass errno to the catcher.
#endif // EXAMPLE_CODE
//
//===================================================================================================================================
// A wrapper around LLStringUtil::format_map_t to allow constructing a dictionary
// on one line by doing:
//
// AIArgs("[ARG1]", arg1)("[ARG2]", arg2)("[ARG3]", arg3)...
class LL_COMMON_API AIArgs
{
private:
LLStringUtil::format_map_t mArgs; // The underlying replacement map.
public:
// Construct an empty map.
AIArgs(void) { }
// Construct a map with a single replacement.
AIArgs(char const* key, std::string const& replacement) { mArgs[key] = replacement; }
// Add another replacement.
AIArgs& operator()(char const* key, std::string const& replacement) { mArgs[key] = replacement; return *this; }
// The destructor may not throw.
~AIArgs() throw() { }
// Accessor.
LLStringUtil::format_map_t const& operator*() const { return mArgs; }
};
namespace AIAlert
{
enum modal_nt
{
not_modal,
modal
};
enum alert_line_type_nt
{
normal = 0,
empty_prefix = 1,
pretty_function_prefix = 2
// These must exist of single bits (a mask).
};
// An Prefix currently comes only in two flavors:
//
// empty_prefix : An empty prefix.
// pretty_function_prefix : A function name prefix, this is the function from which the alert was thrown.
class LL_COMMON_API Prefix
{
public:
Prefix(void) : mType(empty_prefix) { }
Prefix(char const* str, alert_line_type_nt type) : mStr(str), mType(type) { }
operator bool(void) const { return mType != empty_prefix; }
alert_line_type_nt type(void) const { return mType; }
std::string const& str(void) const { return mStr; }
private:
std::string mStr; // Literal text. For example a C++ function name.
alert_line_type_nt mType; // The type of this prefix.
};
// A class that represents one line with its replacements.
// The string mXmlDesc shall be looked up in strings.xml.
// This is not done as part of this class because LLTrans::getString
// is not part of llcommon.
class LL_COMMON_API Line
{
private:
bool mNewline; // Prepend this line with a newline if set.
std::string mXmlDesc; // The keyword to look up in string.xml.
AIArgs mArgs; // Replacement map.
alert_line_type_nt mType; // The type of this line: normal for normal lines, other for prefixes.
public:
Line(std::string const& xml_desc, bool newline = false) : mNewline(newline), mXmlDesc(xml_desc), mType(normal) { }
Line(std::string const& xml_desc, AIArgs const& args, bool newline = false) : mNewline(newline), mXmlDesc(xml_desc), mArgs(args), mType(normal) { }
Line(Prefix const& prefix, bool newline = false) : mNewline(newline), mXmlDesc("AIPrefix"), mArgs("[PREFIX]", prefix.str()), mType(prefix.type()) { }
// The destructor may not throw.
~Line() throw() { }
// Prepend a newline before this line.
void set_newline(void) { mNewline = true; }
// These are to be used like: LLTrans::getString(line.getXmlDesc(), line.args()) and prepend with a \n if prepend_newline() returns true.
std::string getXmlDesc(void) const { return mXmlDesc; }
LLStringUtil::format_map_t const& args(void) const { return *mArgs; }
bool prepend_newline(void) const { return mNewline; }
// Accessors.
bool suppressed(unsigned int suppress_mask) const { return (suppress_mask & mType) != 0; }
bool is_prefix(void) const { return mType != normal; }
};
// This class is used to throw an error that will cause
// an alert box to pop up for the user.
//
// An alert box only has text and an OK button.
// The alert box does not give feed back to the program; it is purely informational.
// The class represents multiple lines, each line is to be translated and catenated,
// separated by newlines, and then written to an alert box. This is not done as part
// of this class because LLTrans::getString and LLNotification is not part of llcommon.
// Instead call LLNotificationUtil::add(Error const&).
class LL_COMMON_API Error : public std::exception
{
public:
typedef std::deque<Line> lines_type;
// The destructor may not throw.
~Error() throw() { }
// Accessors.
lines_type const& lines(void) const { return mLines; }
bool is_modal(void) const { return mModal == modal; }
// Existing alert, just add a prefix and turn alert into modal if appropriate.
Error(Prefix const& prefix, modal_nt type, Error const& alert);
// A string with zero or more replacements.
Error(Prefix const& prefix, modal_nt type,
std::string const& xml_desc, AIArgs const& args = AIArgs());
// Same as above bit prepending the message with the text of another alert.
Error(Prefix const& prefix, modal_nt type,
Error const& alert,
std::string const& xml_desc, AIArgs const& args = AIArgs());
// Same as above but appending the message with the text of another alert.
// (no args)
Error(Prefix const& prefix, modal_nt type,
std::string const& xml_desc,
Error const& alert);
// (with args)
Error(Prefix const& prefix, modal_nt type,
std::string const& xml_desc, AIArgs const& args,
Error const& alert);
private:
lines_type mLines; // The lines (or prefixes) of text to be displayed, each consisting on a keyword (to be looked up in strings.xml) and a replacement map.
modal_nt mModal; // If true, make the alert box a modal floater.
};
// Same as Error but allows to pass an additional error code.
class LL_COMMON_API ErrorCode : public Error
{
private:
int mCode;
public:
// The destructor may not throw.
~ErrorCode() throw() { }
// Accessor.
int getCode(void) const { return mCode; }
// Just an Error with a code.
ErrorCode(Prefix const& prefix, modal_nt type, int code,
Error const& alert) :
Error(prefix, type, alert), mCode(code) { }
// A string with zero or more replacements.
ErrorCode(Prefix const& prefix, modal_nt type, int code,
std::string const& xml_desc, AIArgs const& args = AIArgs()) :
Error(prefix, type, xml_desc, args), mCode(code) { }
// Same as above bit prepending the message with the text of another alert.
ErrorCode(Prefix const& prefix, modal_nt type, int code,
Error const& alert,
std::string const& xml_desc, AIArgs const& args = AIArgs()) :
Error(prefix, type, alert, xml_desc, args), mCode(code) { }
// Same as above but appending the message with the text of another alert.
// (no args)
ErrorCode(Prefix const& prefix, modal_nt type, int code,
std::string const& xml_desc,
Error const& alert) :
Error(prefix, type, xml_desc, alert), mCode(code) { }
// (with args)
ErrorCode(Prefix const& prefix, modal_nt type, int code,
std::string const& xml_desc, AIArgs const& args,
Error const& alert) :
Error(prefix, type, xml_desc, args, alert), mCode(code) { }
};
} // namespace AIAlert
#endif // AI_ALERT

119
indra/llcommon/aifile.cpp Normal file
View File

@@ -0,0 +1,119 @@
/**
* @file aifile.cpp
* @brief POSIX file operations that throw on error.
*
* 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.
*
* 03/11/2013
* Initial version, written by Aleric Inglewood @ SL
*/
#include "linden_common.h"
#include "aifile.h"
#include "aialert.h"
#if LL_WINDOWS
#include <windows.h>
#include <stdlib.h> // Windows errno
#else
#include <errno.h>
#endif
AIFile::AIFile(std::string const& filename, char const* accessmode)
{
mFp = AIFile::fopen(filename, accessmode);
}
AIFile::~AIFile()
{
AIFile::close(mFp);
}
// Like THROW_MALERTE but appends "LLFile::strerr(errn) << " (" << errn << ')'" as argument to replace [ERROR].
#define THROW_ERROR(...) \
do { \
int errn = errno; \
std::ostringstream error; \
error << LLFile::strerr(errn) << " (" << errn << ')'; \
THROW_MALERT_CLASS(AIAlert::ErrorCode, errn, __VA_ARGS__ ("[ERROR]", error.str())); \
} while(0)
//static
void AIFile::mkdir(std::string const& dirname, int perms)
{
int rc = LLFile::mkdir_nowarn(dirname, perms);
if (rc < 0 && errno != EEXIST)
{
THROW_ERROR("AIFile_mkdir_Failed_to_create_DIRNAME", AIArgs("[DIRNAME]", dirname));
}
}
//static
void AIFile::rmdir(std::string const& dirname)
{
int rc = LLFile::rmdir_nowarn(dirname);
if (rc < 0 && errno != ENOENT)
{
THROW_ERROR("AIFile_rmdir_Failed_to_remove_DIRNAME", AIArgs("[DIRNAME]", dirname));
}
}
//static
LLFILE* AIFile::fopen(std::string const& filename, const char* mode)
{
LLFILE* fp = LLFile::fopen(filename, mode);
if (!fp)
{
THROW_ERROR("AIFile_fopen_Failed_to_open_FILENAME", AIArgs("[FILENAME]", filename));
}
return fp;
}
//static
void AIFile::close(LLFILE* file)
{
if (LLFile::close(file) < 0)
{
THROW_ERROR("AIFile_close_Failed_to_close_file", AIArgs);
}
}
//static
void AIFile::remove(std::string const& filename)
{
int rc = LLFile::remove_nowarn(filename);
if (rc < 0 && errno != ENOENT)
{
THROW_ERROR("AIFile_remove_Failed_to_remove_FILENAME", AIArgs("[FILENAME]", filename));
}
}
//static
void AIFile::rename(std::string const& filename, std::string const& newname)
{
if (LLFile::rename_nowarn(filename, newname) < 0)
{
THROW_ERROR("AIFile_rename_Failed_to_rename_FILE_to_NEWFILE", AIArgs("[FILE]", filename)("[NEWFILE]", newname));
}
}

59
indra/llcommon/aifile.h Normal file
View File

@@ -0,0 +1,59 @@
/**
* @file aifile.h
* @brief Declaration of AIFile.
*
* 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.
*
* 02/11/2013
* Initial version, written by Aleric Inglewood @ SL
*/
#ifndef AIFILE_H
#define AIFILE_H
#include "llfile.h"
// As LLFile, but throws AIAlert instead of printing a warning.
class LL_COMMON_API AIFile
{
private:
LLFILE* mFp;
public:
// Scoped file (exception safe). Throws AIAlertCode with errno on failure.
AIFile(std::string const& filename, char const* accessmode);
~AIFile();
operator LLFILE* () const { return mFp; }
// All these functions take UTF8 path/filenames.
static LLFILE* fopen(std::string const& filename, char const* accessmode);
static void close(LLFILE* file);
static void mkdir(std::string const& dirname, int perms = 0700); // Does NOT throw when dirname already exists.
static void rmdir(std::string const& dirname); // Does NOT throw when dirname does not exist.
static void remove(std::string const& filename); // Does NOT throw when filename does not exist.
static void rename(std::string const& filename, std::string const& newname);
};
#endif // AIFILE_H

View File

@@ -123,6 +123,8 @@ LLApp::LLApp() : mThreadErrorp(NULL)
commonCtor();
}
static void* sCrashLoggerReserve = NULL;
void LLApp::commonCtor()
{
// Set our status to running
@@ -148,6 +150,12 @@ void LLApp::commonCtor()
sApplication = this;
mExceptionHandler = 0;
#if LL_WINDOWS
sCrashLoggerReserve = VirtualAlloc(NULL, 512*1024, MEM_COMMIT|MEM_RESERVE, PAGE_NOACCESS);
#else
sCrashLoggerReserve = malloc(512*1024);
#endif
// initialize the buffer to write the minidump filename to
// (this is used to avoid allocating memory in the crash handler)
@@ -155,6 +163,20 @@ void LLApp::commonCtor()
mCrashReportPipeStr = L"\\\\.\\pipe\\LLCrashReporterPipe";
}
#if LL_WINDOWS
static bool clear_CrashLoggerReserve_callback(void* context, EXCEPTION_POINTERS* exinfo, MDRawAssertionInfo* assertion)
{
VirtualFree(sCrashLoggerReserve, 0, MEM_RELEASE);
return true;
}
#else
static bool clear_CrashLoggerReserve_callback(void* context)
{
free(sCrashLoggerReserve);
return true;
}
#endif
LLApp::LLApp(LLErrorThread *error_thread) :
mThreadErrorp(error_thread)
{
@@ -307,46 +329,12 @@ void LLApp::setupErrorHandling()
// Install the Google Breakpad crash handler for Windows
if(mExceptionHandler == 0)
{
llwarns << "adding breakpad exception handler" << llendl;
std::wostringstream ws;
ws << mCrashReportPipeStr << getPid();
std::wstring wpipe_name = ws.str();
std::string ptmp = std::string(wpipe_name.begin(), wpipe_name.end());
::Sleep(2000); //HACK hopefully a static wait won't blow up in my face before google fixes their implementation.
//HACK this for loop is ueless. Breakpad dumbly returns success when the OOP handler isn't initialized.
for (int retries=0;retries<5;++retries)
{
mExceptionHandler = new google_breakpad::ExceptionHandler(
L"",
NULL, //No filter
windows_post_minidump_callback,
0,
google_breakpad::ExceptionHandler::HANDLER_ALL,
MiniDumpNormal, //Generate a 'normal' minidump.
(WCHAR *)wpipe_name.c_str(),
NULL); //No custom client info.
if (mExceptionHandler)
{
break;
}
else
{
::Sleep(100); //Wait a tick and try again.
}
}
if (!mExceptionHandler)
{
llwarns << "Failed to initialize OOP exception handler. Defaulting to In Process handling" << llendl;
mExceptionHandler = new google_breakpad::ExceptionHandler(
std::wstring(mDumpPath.begin(),mDumpPath.end()), //Dump path
0, //dump filename
windows_post_minidump_callback,
0,
google_breakpad::ExceptionHandler::HANDLER_ALL);
}
mExceptionHandler = new google_breakpad::ExceptionHandler(
std::wstring(mDumpPath.begin(),mDumpPath.end()), //Dump path
clear_CrashLoggerReserve_callback,
windows_post_minidump_callback,
0,
google_breakpad::ExceptionHandler::HANDLER_ALL);
if (mExceptionHandler)
{
mExceptionHandler->set_handle_debug_exceptions(true);
@@ -401,7 +389,7 @@ void LLApp::setupErrorHandling()
if(installHandler && (mExceptionHandler == 0))
{
mExceptionHandler = new google_breakpad::ExceptionHandler(mDumpPath, 0, &unix_post_minidump_callback, 0, true, 0);
mExceptionHandler = new google_breakpad::ExceptionHandler(mDumpPath, clear_CrashLoggerReserve_callback, &unix_post_minidump_callback, 0, true, 0);
}
#elif LL_LINUX
if(installHandler && (mExceptionHandler == 0))
@@ -411,8 +399,7 @@ void LLApp::setupErrorHandling()
mDumpPath = "/tmp";
}
google_breakpad::MinidumpDescriptor desc(mDumpPath);
//mExceptionHandler = new google_breakpad::ExceptionHandler(desc, 0, unix_minidump_callback, 0, true, 0);
mExceptionHandler = new google_breakpad::ExceptionHandler(desc, NULL, unix_minidump_callback, NULL, true, -1);
mExceptionHandler = new google_breakpad::ExceptionHandler(desc, clear_CrashLoggerReserve_callback, unix_minidump_callback, NULL, true, -1);
}
#endif

View File

@@ -184,7 +184,7 @@ LLMutex* LLFastTimer::sLogLock = NULL;
std::queue<LLSD> LLFastTimer::sLogQueue;
const int LLFastTimer::NamedTimer::HISTORY_NUM = 300;
#if LL_WINDOWS
#if defined(LL_WINDOWS) && !defined(_WIN64)
#define USE_RDTSC 1
#endif

View File

@@ -49,7 +49,8 @@ static std::string empty;
#if LL_WINDOWS
// On Windows, use strerror_s().
std::string strerr(int errn)
//static
std::string LLFile::strerr(int errn)
{
char buffer[256];
strerror_s(buffer, errn); // infers sizeof(buffer) -- love it!
@@ -98,7 +99,8 @@ std::string message_from(int orig_errno, const char* buffer, size_t bufflen,
<< " (error " << stre_errno << ')');
}
std::string strerr(int errn)
//static
std::string LLFile::strerr(int errn)
{
char buffer[256];
// Select message_from() function matching the strerror_r() we have on hand.
@@ -108,7 +110,8 @@ std::string strerr(int errn)
#endif // ! LL_WINDOWS
// On either system, shorthand call just infers global 'errno'.
std::string strerr()
//static
std::string LLFile::strerr()
{
return strerr(errno);
}
@@ -125,7 +128,7 @@ int warnif(const std::string& desc, const std::string& filename, int rc, int acc
if (errn != accept)
{
LL_WARNS("LLFile") << "Couldn't " << desc << " '" << filename
<< "' (errno " << errn << "): " << strerr(errn) << LL_ENDL;
<< "' (errno " << errn << "): " << LLFile::strerr(errn) << LL_ENDL;
}
#if 0 && LL_WINDOWS // turn on to debug file-locking problems
// If the problem is "Permission denied," maybe it's because another
@@ -171,7 +174,7 @@ int warnif(const std::string& desc, const std::string& filename, int rc, int acc
}
// static
int LLFile::mkdir(const std::string& dirname, int perms)
int LLFile::mkdir_nowarn(const std::string& dirname, int perms)
{
#if LL_WINDOWS
// permissions are ignored on Windows
@@ -181,13 +184,19 @@ int LLFile::mkdir(const std::string& dirname, int perms)
#else
int rc = ::mkdir(dirname.c_str(), (mode_t)perms);
#endif
return rc;
}
int LLFile::mkdir(const std::string& dirname, int perms)
{
int rc = LLFile::mkdir_nowarn(dirname, perms);
// We often use mkdir() to ensure the existence of a directory that might
// already exist. Don't spam the log if it does.
return warnif("mkdir", dirname, rc, EEXIST);
}
// static
int LLFile::rmdir(const std::string& dirname)
int LLFile::rmdir_nowarn(const std::string& dirname)
{
#if LL_WINDOWS
// permissions are ignored on Windows
@@ -197,6 +206,12 @@ int LLFile::rmdir(const std::string& dirname)
#else
int rc = ::rmdir(dirname.c_str());
#endif
return rc;
}
int LLFile::rmdir(const std::string& dirname)
{
int rc = LLFile::rmdir_nowarn(dirname);
return warnif("rmdir", dirname, rc);
}
@@ -238,8 +253,7 @@ int LLFile::close(LLFILE * file)
return ret_value;
}
int LLFile::remove(const std::string& filename)
int LLFile::remove_nowarn(const std::string& filename)
{
#if LL_WINDOWS
std::string utf8filename = filename;
@@ -248,10 +262,16 @@ int LLFile::remove(const std::string& filename)
#else
int rc = ::remove(filename.c_str());
#endif
return rc;
}
int LLFile::remove(const std::string& filename)
{
int rc = LLFile::remove_nowarn(filename);
return warnif("remove", filename, rc);
}
int LLFile::rename(const std::string& filename, const std::string& newname)
int LLFile::rename_nowarn(const std::string& filename, const std::string& newname)
{
#if LL_WINDOWS
std::string utf8filename = filename;
@@ -262,6 +282,12 @@ int LLFile::rename(const std::string& filename, const std::string& newname)
#else
int rc = ::rename(filename.c_str(),newname.c_str());
#endif
return rc;
}
int LLFile::rename(const std::string& filename, const std::string& newname)
{
int rc = LLFile::rename_nowarn(filename, newname);
return warnif(STRINGIZE("rename to '" << newname << "' from"), filename, rc);
}

View File

@@ -30,6 +30,9 @@
#ifndef LL_LLFILE_H
#define LL_LLFILE_H
#include <fstream>
#include <sys/stat.h>
/**
* This class provides a cross platform interface to the filesystem.
* Attempts to mostly mirror the POSIX style IO functions.
@@ -37,9 +40,6 @@
typedef FILE LLFILE;
#include <fstream>
#include <sys/stat.h>
#if LL_WINDOWS
// windows version of stat function and stat data structure are called _stat
typedef struct _stat llstat;
@@ -68,6 +68,12 @@ public:
static int close(LLFILE * file);
// Singu extension: the same as below, but doesn't print a warning as to leave errno alone.
static int mkdir_nowarn(const std::string& filename, int perms);
static int rmdir_nowarn(const std::string& filename);
static int remove_nowarn(const std::string& filename);
static int rename_nowarn(const std::string& filename, const std::string& newname);
// perms is a permissions mask like 0777 or 0700. In most cases it will
// be overridden by the user's umask. It is ignored on Windows.
static int mkdir(const std::string& filename, int perms = 0700);
@@ -82,6 +88,9 @@ public:
std::ios::openmode mode);
static const char * tmpdir();
static std::string strerr(int errn);
static std::string strerr();
};
/**

View File

@@ -32,6 +32,7 @@
#include <typeinfo>
#include "string_table.h"
#include "llerror.h" // llassert_always
#include <boost/utility.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>

View File

@@ -281,7 +281,12 @@ void LLMD5::raw_digest(unsigned char *s) const
return;
}
//Singu extension: the inverse of LLMD5::raw_digest.
void LLMD5::clone(unsigned char const* s)
{
memcpy(digest, s, 16);
finalized = 1;
}
void LLMD5::hex_digest(char *s) const
{
@@ -305,12 +310,26 @@ void LLMD5::hex_digest(char *s) const
return;
}
//Singu extension: the inverse of LLMD5::hex_digest.
void LLMD5::clone(std::string const& hash_str)
{
for (int i = 0; i < 16; ++i)
{
unsigned char byte = 0;
for (int j = 0; j < 2; ++j)
{
char c = hash_str[i * 2 + j];
unsigned char nibble = (c >= '0' && c <= '9') ? c - '0' : c - 'a' + 10;
byte += nibble << ((1 - j) << 2);
}
digest[i] = byte;
}
finalized = 1;
}
std::ostream& operator<<(std::ostream &stream, LLMD5 context)
std::ostream& operator<<(std::ostream &stream, LLMD5 const& context)
{
char s[33]; /* Flawfinder: ignore */
context.hex_digest(s);
@@ -318,23 +337,6 @@ std::ostream& operator<<(std::ostream &stream, LLMD5 context)
return stream;
}
bool operator==(const LLMD5& a, const LLMD5& b)
{
unsigned char a_guts[16];
unsigned char b_guts[16];
a.raw_digest(a_guts);
b.raw_digest(b_guts);
if (memcmp(a_guts,b_guts,16)==0)
return true;
else
return false;
}
bool operator!=(const LLMD5& a, const LLMD5& b)
{
return !(a==b);
}
// PRIVATE METHODS:
void LLMD5::init(){

View File

@@ -32,6 +32,10 @@
#ifndef LL_LLMD5_H
#define LL_LLMD5_H
#include "llpreprocessor.h"
#include <iosfwd>
#include <cstring> // memcmp
// LLMD5.CC - source code for the C++/object oriented translation and
// modification of MD5.
@@ -98,18 +102,27 @@ public:
void update (const std::string& str);
void finalize ();
bool isFinalized() const { return finalized; }
// constructors for special circumstances. All these constructors finalize
// the MD5 context.
LLMD5 (const unsigned char *string); // digest string, finalize
LLMD5 (std::istream& stream); // digest stream, finalize
LLMD5 (FILE *file); // digest file, close, finalize
LLMD5 (const unsigned char *string, const unsigned int number);
// Singu extension: set digest directly, finalize.
void clone(unsigned char const* digest); // Inverse of raw_digest.
void clone(std::string const& hash_str); // Inverse of hex_digest.
// methods to acquire finalized result
void raw_digest(unsigned char *array) const; // provide 16-byte array for binary data
void hex_digest(char *string) const; // provide 33-byte array for ascii-hex string
friend LL_COMMON_API std::ostream& operator<< (std::ostream&, LLMD5 context);
friend LL_COMMON_API std::ostream& operator<< (std::ostream&, LLMD5 const& context);
friend LL_COMMON_API bool operator==(const LLMD5& a, const LLMD5& b) { return std::memcmp(a.digest ,b.digest, 16) == 0; }
friend LL_COMMON_API bool operator!=(const LLMD5& a, const LLMD5& b) { return std::memcmp(a.digest ,b.digest, 16) != 0; }
friend LL_COMMON_API bool operator<(const LLMD5& a, const LLMD5& b) { return std::memcmp(a.digest ,b.digest, 16) < 0; }
private:
@@ -131,7 +144,4 @@ private:
};
LL_COMMON_API bool operator==(const LLMD5& a, const LLMD5& b);
LL_COMMON_API bool operator!=(const LLMD5& a, const LLMD5& b);
#endif // LL_LLMD5_H

View File

@@ -200,7 +200,7 @@ inline void ll_memcpy_nonaliased_aligned_16(char* __restrict dst, const char* __
assert((bytes % sizeof(F32))== 0);
ll_assert_aligned(src,16);
ll_assert_aligned(dst,16);
assert((src < dst) ? ((src + bytes) < dst) : ((dst + bytes) < src));
assert((src < dst) ? ((src + bytes) <= dst) : ((dst + bytes) <= src));
assert(bytes%16==0);
char* end = dst + bytes;

View File

@@ -416,7 +416,7 @@ static F64 calculate_cpu_frequency(U32 measure_msecs)
unsigned long dwCurPriorityClass = GetPriorityClass(hProcess);
int iCurThreadPriority = GetThreadPriority(hThread);
unsigned long dwProcessMask, dwSystemMask, dwNewMask = 1;
GetProcessAffinityMask(hProcess, &dwProcessMask, &dwSystemMask);
GetProcessAffinityMask(hProcess, (PDWORD_PTR)&dwProcessMask, (PDWORD_PTR)&dwSystemMask);
SetPriorityClass(hProcess, REALTIME_PRIORITY_CLASS);
SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL);

View File

@@ -27,6 +27,9 @@
#define LLREFCOUNT_H
#include <boost/noncopyable.hpp>
#include "llpreprocessor.h" // LL_COMMON_API
#include "stdtypes.h" // S32
#include "llerror.h" // llassert
#define LL_REF_COUNT_DEBUG 0
#if LL_REF_COUNT_DEBUG

View File

@@ -37,6 +37,8 @@
#include <vector>
#include <boost/shared_ptr.hpp>
#include "llpreprocessor.h"
#include "stdtypes.h"
class LLRunnable;

View File

@@ -27,6 +27,7 @@
#include "llerror.h" // *TODO: eliminate this
#include <map>
#include <typeinfo>
#include <boost/noncopyable.hpp>

View File

@@ -231,7 +231,9 @@ public:
operator std::string() const { return mString; }
bool operator<(const LLFormatMapString& rhs) const { return mString < rhs.mString; }
std::size_t length() const { return mString.length(); }
// The destructor may not throw.
~LLFormatMapString() throw() { }
private:
std::string mString;
};

View File

@@ -28,6 +28,7 @@
#include <iostream>
#include <set>
#include <vector>
#include "stdtypes.h"
#include "llpreprocessor.h"

View File

@@ -35,7 +35,7 @@
const S32 LL_VERSION_MAJOR = 1;
const S32 LL_VERSION_MINOR = 8;
const S32 LL_VERSION_PATCH = 3;
const S32 LL_VERSION_PATCH = 4;
const S32 LL_VERSION_BUILD = ${vBUILD};
const char * const LL_CHANNEL = "${VIEWER_CHANNEL}";

View File

@@ -140,7 +140,7 @@ inline F64 llabs(const F64 a)
inline S32 lltrunc( F32 f )
{
#if LL_WINDOWS && !defined( __INTEL_COMPILER )
#if LL_WINDOWS && !defined( __INTEL_COMPILER ) && !defined(_WIN64)
// Avoids changing the floating point control word.
// Add or subtract 0.5 - epsilon and then round
const static U32 zpfp[] = { 0xBEFFFFFF, 0x3EFFFFFF };
@@ -166,7 +166,7 @@ inline S32 lltrunc( F64 f )
inline S32 llfloor( F32 f )
{
#if LL_WINDOWS && !defined( __INTEL_COMPILER )
#if LL_WINDOWS && !defined( __INTEL_COMPILER ) && !defined(_WIN64)
// Avoids changing the floating point control word.
// Accurate (unlike Stereopsis version) for all values between S32_MIN and S32_MAX and slightly faster than Stereopsis version.
// Add -(0.5 - epsilon) and then round

View File

@@ -31,7 +31,7 @@
#error "Please include llmath.h before this file."
#endif
#if ( ( LL_DARWIN || LL_LINUX ) && !(__SSE2__) ) || ( LL_WINDOWS && ( _M_IX86_FP < 2 ) )
#if ( ( LL_DARWIN || LL_LINUX ) && !(__SSE2__) ) || ( LL_WINDOWS && ( _M_IX86_FP < 2 ) && !defined(_WIN64) )
#error SSE2 not enabled. LLVector4a and related class will not compile.
#endif

View File

@@ -250,10 +250,13 @@ void AICurlEasyRequestStateMachine::finish_impl(void)
}
}
AICurlEasyRequestStateMachine::AICurlEasyRequestStateMachine(void) :
AICurlEasyRequestStateMachine::AICurlEasyRequestStateMachine(CWD_ONLY(bool debug)) :
#ifdef CWDEBUG
AIStateMachine(debug),
#endif
mTotalDelayTimeout(AIHTTPTimeoutPolicy::getDebugSettingsCurlTimeout().getTotalDelay())
{
Dout(dc::statemachine, "Calling AICurlEasyRequestStateMachine(void) [" << (void*)this << "] [" << (void*)mCurlEasyRequest.get() << "]");
Dout(dc::statemachine(mSMDebug), "Calling AICurlEasyRequestStateMachine(void) [" << (void*)this << "] [" << (void*)mCurlEasyRequest.get() << "]");
AICurlInterface::Stats::AICurlEasyRequestStateMachine_count++;
}
@@ -264,7 +267,7 @@ void AICurlEasyRequestStateMachine::setTotalDelayTimeout(F32 totalDelayTimeout)
AICurlEasyRequestStateMachine::~AICurlEasyRequestStateMachine()
{
Dout(dc::statemachine, "Calling ~AICurlEasyRequestStateMachine() [" << (void*)this << "] [" << (void*)mCurlEasyRequest.get() << "]");
Dout(dc::statemachine(mSMDebug), "Calling ~AICurlEasyRequestStateMachine() [" << (void*)this << "] [" << (void*)mCurlEasyRequest.get() << "]");
--AICurlInterface::Stats::AICurlEasyRequestStateMachine_count;
}

View File

@@ -52,7 +52,7 @@
// Construction of a AICurlEasyRequestStateMachine might throw AICurlNoEasyHandle.
class AICurlEasyRequestStateMachine : public AIStateMachine, public AICurlEasyHandleEvents {
public:
AICurlEasyRequestStateMachine(void);
AICurlEasyRequestStateMachine(CWD_ONLY(bool debug = false));
// Transparent access.
AICurlEasyRequest mCurlEasyRequest;

View File

@@ -343,6 +343,7 @@ void LLHTTPClient::ResponderBase::decode_llsd_body(U32 status, std::string const
strncmp(str, "cap not found:", 14) && // Most of the other 3%.
str[0] && // Empty happens too and aint LLSD either.
strncmp(str, "Not Found", 9) &&
strncmp(str, "Upstream error: ", 16) && // Received by LLEventPollResponder every 50 seconds (see http://wiki.secondlife.com/wiki/EventQueueGet).
LLSDSerialize::fromXML(dummy, ss) > 0;
if (server_sent_llsd_with_http_error)
{

View File

@@ -294,14 +294,14 @@ BOOL LLPartSysData::unpack(LLDataPacker &dp)
//skip to LLPartData block
U8 feh = 0;
for (U32 i = 0; i < size; ++i)
for (S32 i = 0; i < size; ++i)
{
dp.unpackU8(feh, "whippang");
}
dp.unpackS32(size, "partsize");
//skip LLPartData block
for (U32 i = 0; i < size; ++i)
for (S32 i = 0; i < size; ++i)
{
dp.unpackU8(feh, "whippang");
}

View File

@@ -49,7 +49,7 @@ set_source_files_properties(${llplugin_HEADER_FILES}
if(NOT WORD_SIZE EQUAL 32)
if(WINDOWS)
add_definitions(/FIXED:NO)
# add_definitions(/FIXED:NO)
else(WINDOWS) # not windows therefore gcc LINUX and DARWIN
add_definitions(-fPIC)
endif(WINDOWS)

View File

@@ -545,7 +545,7 @@ S32 LLTextureEntry::setMaterialID(const LLMaterialID& pMaterialID)
{
mMaterialUpdatePending = true;
mMaterialID = pMaterialID;
return TEM_CHANGE_NONE;
return TEM_CHANGE_TEXTURE;
}
mMaterialUpdatePending = false;

View File

@@ -38,7 +38,7 @@
const S32 TEM_CHANGE_NONE = 0x0;
const S32 TEM_CHANGE_COLOR = 0x1;
const S32 TEM_CHANGE_TEXTURE = 0x2;
const S32 TEM_CHANGE_MEDIA = 0x4; //Currently doesn't do anything, (not that TEM_CHANGE_TEXTURE either)
const S32 TEM_CHANGE_MEDIA = 0x4;
const S32 TEM_INVALID = 0x8;
const S32 TEM_BUMPMAP_COUNT = 32;
@@ -133,7 +133,13 @@ public:
virtual const LLUUID &getID() const { return mID; }
const LLColor4 &getColor() const { return mColor; }
void getScale(F32 *s, F32 *t) const { *s = mScaleS; *t = mScaleT; }
F32 getScaleS() const { return mScaleS; }
F32 getScaleT() const { return mScaleT; }
void getOffset(F32 *s, F32 *t) const { *s = mOffsetS; *t = mOffsetT; }
F32 getOffsetS() const { return mOffsetS; }
F32 getOffsetT() const { return mOffsetT; }
F32 getRotation() const { return mRotation; }
void getRotation(F32 *theta) const { *theta = mRotation; }
@@ -144,7 +150,7 @@ public:
U8 getBumpShinyFullbright() const { return mBump; }
U8 getMediaFlags() const { return mMediaFlags & TEM_MEDIA_MASK; }
U8 getTexGen() const { return mMediaFlags & TEM_TEX_GEN_MASK; }
LLTextureEntry::e_texgen getTexGen() const { return LLTextureEntry::e_texgen(mMediaFlags & TEM_TEX_GEN_MASK); }
U8 getMediaTexGen() const { return mMediaFlags; }
F32 getGlow() const { return mGlow; }
const LLMaterialID& getMaterialID() const { return mMaterialID; };

View File

@@ -755,10 +755,12 @@ bool LLGLManager::initGL()
#endif
stop_glerror();
#if LL_WINDOWS
if (mIsIntel && mGLVersion <= 3.f)
{ //never try to use framebuffer objects on older intel drivers (crashy)
mHasFramebufferObject = FALSE;
}
#endif
stop_glerror();

View File

@@ -550,7 +550,7 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
LL_WARNS("ShaderLoading") << "GL ERROR entering loadShaderFile(): " << error << LL_ENDL;
}
}
LL_DEBUGS("ShaderLoading") << "Loading shader file: " << filename << " class " << shader_level << LL_ENDL;
if (filename.empty())
@@ -610,6 +610,10 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
text[count++] = strdup("#define ATTRIBUTE attribute\n");
text[count++] = strdup("#define VARYING varying\n");
text[count++] = strdup("#define VARYING_FLAT varying\n");
// Need to enable extensions here instead of in the shader files,
// before any non-preprocessor directives (per spec)
text[count++] = strdup("#extension GL_ARB_texture_rectangle : enable\n");
text[count++] = strdup("#extension GL_ARB_shader_texture_lod : enable\n");
}
else if (minor_version <= 29)
{
@@ -620,6 +624,10 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
text[count++] = strdup("#define ATTRIBUTE attribute\n");
text[count++] = strdup("#define VARYING varying\n");
text[count++] = strdup("#define VARYING_FLAT varying\n");
// Need to enable extensions here instead of in the shader files,
// before any non-preprocessor directives (per spec)
text[count++] = strdup("#extension GL_ARB_texture_rectangle : enable\n");
text[count++] = strdup("#extension GL_ARB_shader_texture_lod : enable\n");
}
}
else
@@ -628,6 +636,11 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
{
//set version to 1.30
text[count++] = strdup("#version 130\n");
// Need to enable extensions here instead of in the shader files,
// before any non-preprocessor directives (per spec)
text[count++] = strdup("#extension GL_ARB_texture_rectangle : enable\n");
text[count++] = strdup("#extension GL_ARB_shader_texture_lod : enable\n");
//some implementations of GLSL 1.30 require integer precision be explicitly declared
text[count++] = strdup("precision mediump int;\n");
@@ -636,7 +649,12 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
else
{ //set version to 400
text[count++] = strdup("#version 400\n");
// Need to enable extensions here instead of in the shader files,
// before any non-preprocessor directives (per spec)
text[count++] = strdup("#extension GL_ARB_texture_rectangle : enable\n");
text[count++] = strdup("#extension GL_ARB_shader_texture_lod : enable\n");
}
text[count++] = strdup("#define DEFINE_GL_FRAGCOLOR 1\n");
text[count++] = strdup("#define FXAA_GLSL_130 1\n");

View File

@@ -171,9 +171,10 @@ LLView* LLComboBox::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *
LLXMLNodePtr child;
for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
{
if (child->hasName("combo_item"))
if (child->hasName("combo_item") || child->hasName("combo_box.item"))
{
std::string label = child->getTextContents();
child->getAttributeString("label", label);
std::string value = label;
child->getAttributeString("value", value);

View File

@@ -366,6 +366,20 @@ void LLFocusMgr::removeKeyboardFocusWithoutCallback( const LLFocusableElement* f
}
}
bool LLFocusMgr::keyboardFocusHasAccelerators() const
{
LLView* focus_view = dynamic_cast<LLView*>(mKeyboardFocus);
while(focus_view)
{
if (focus_view->hasAccelerators())
{
return true;
}
focus_view = focus_view->getParent();
}
return false;
}
void LLFocusMgr::setMouseCapture( LLMouseHandler* new_captor )
{

View File

@@ -121,6 +121,7 @@ public:
void unlockFocus();
BOOL focusLocked() const { return mLockedView != NULL; }
bool keyboardFocusHasAccelerators() const;
struct Impl;

View File

@@ -626,12 +626,12 @@ BOOL LLMenuItemSeparatorGL::handleMouseDown(S32 x, S32 y, MASK mask)
{
// the menu items are in the child list in bottom up order
LLView* prev_menu_item = parent_menu->findNextSibling(this);
return prev_menu_item ? prev_menu_item->handleMouseDown(x, prev_menu_item->getRect().getHeight(), mask) : FALSE;
return (prev_menu_item && prev_menu_item->getVisible() && prev_menu_item->getEnabled()) ? prev_menu_item->handleMouseDown(x, prev_menu_item->getRect().getHeight(), mask) : FALSE;
}
else
{
LLView* next_menu_item = parent_menu->findPrevSibling(this);
return next_menu_item ? next_menu_item->handleMouseDown(x, 0, mask) : FALSE;
return (next_menu_item && next_menu_item->getVisible() && next_menu_item->getEnabled()) ? next_menu_item->handleMouseDown(x, 0, mask) : FALSE;
}
}
@@ -641,12 +641,12 @@ BOOL LLMenuItemSeparatorGL::handleMouseUp(S32 x, S32 y, MASK mask)
if (y > getRect().getHeight() / 2)
{
LLView* prev_menu_item = parent_menu->findNextSibling(this);
return prev_menu_item ? prev_menu_item->handleMouseUp(x, prev_menu_item->getRect().getHeight(), mask) : FALSE;
return (prev_menu_item && prev_menu_item->getVisible() && prev_menu_item->getEnabled()) ? prev_menu_item->handleMouseUp(x, prev_menu_item->getRect().getHeight(), mask) : FALSE;
}
else
{
LLView* next_menu_item = parent_menu->findPrevSibling(this);
return next_menu_item ? next_menu_item->handleMouseUp(x, 0, mask) : FALSE;
return (next_menu_item && next_menu_item->getVisible() && next_menu_item->getEnabled()) ? next_menu_item->handleMouseUp(x, 0, mask) : FALSE;
}
}
@@ -3306,50 +3306,16 @@ void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y)
menu->getParent()->sendChildToFront(menu);
}
//-----------------------------------------------------------------------------
// class LLPieMenuBranch
// A branch to another pie menu
//-----------------------------------------------------------------------------
class LLPieMenuBranch : public LLMenuItemGL
{
public:
LLPieMenuBranch(const std::string& name, const std::string& label, LLPieMenu* branch);
virtual LLXMLNodePtr getXML(bool save_children = true) const;
// called to rebuild the draw label
virtual void buildDrawLabel( void );
virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask)
{
LLMenuItemGL::handleMouseUp(x,y,mask);
return TRUE;
}
// doIt() - do the primary funcationality of the menu item.
virtual void doIt( void );
LLPieMenu* getBranch() { return mBranch; }
protected:
LLPieMenu* mBranch;
};
const F32 PIE_MENU_WIDTH = 190;
const F32 PIE_MENU_HEIGHT = 190;
LLPieMenuBranch::LLPieMenuBranch(const std::string& name,
const std::string& label,
LLPieMenu* branch)
LLContextMenuBranch::LLContextMenuBranch(const std::string& name, const std::string& label, LLContextMenu* branch)
: LLMenuItemGL( name, label, KEY_NONE, MASK_NONE ),
mBranch( branch )
{
mBranch->hide(FALSE);
mBranch->hide();
mBranch->setParentMenuItem(this);
}
// virtual
LLXMLNodePtr LLPieMenuBranch::getXML(bool save_children) const
LLXMLNodePtr LLContextMenuBranch::getXML(bool save_children) const
{
if (mBranch)
{
@@ -3360,7 +3326,7 @@ LLXMLNodePtr LLPieMenuBranch::getXML(bool save_children) const
}
// called to rebuild the draw label
void LLPieMenuBranch::buildDrawLabel( void )
void LLContextMenuBranch::buildDrawLabel( void )
{
{
// default enablement is this -- if any of the subitems are
@@ -3386,62 +3352,72 @@ void LLPieMenuBranch::buildDrawLabel( void )
std::string st = mDrawAccelLabel;
appendAcceleratorString( st );
mDrawAccelLabel = st;
// No special branch suffix
mDrawBranchLabel.clear();
// Singu Note: This is meaningless to pies
mDrawBranchLabel = LLMenuGL::BRANCH_SUFFIX;
}
void LLContextMenuBranch::showSubMenu()
{
if (getDrawTextDisabled()) return; // Singu Note: Don't open disabled submenus!
S32 center_x;
S32 center_y;
static LLUICachedControl<bool> context("LiruUseContextMenus", false);
if (context) // Use the edge of this item
{
localPointToScreen(getRect().getWidth(), getRect().getHeight(), &center_x, &center_y);
}
else // Use the center of the parent pie menu, and hide it
{
LLContextMenu* parent = static_cast<LLContextMenu*>(getParent());
const LLRect& rect = parent->getRect();
parent->localPointToScreen(rect.getWidth() / 2, rect.getHeight() / 2, &center_x, &center_y);
parent->hide();
}
mBranch->show(center_x, center_y, context);
}
// doIt() - do the primary funcationality of the menu item.
void LLPieMenuBranch::doIt( void )
void LLContextMenuBranch::doIt( void )
{
LLPieMenu *parent = (LLPieMenu *)getParent();
LLRect rect = parent->getRect();
S32 center_x;
S32 center_y;
parent->localPointToScreen(rect.getWidth() / 2, rect.getHeight() / 2, &center_x, &center_y);
parent->hide(FALSE);
mBranch->show( center_x, center_y, FALSE );
showSubMenu();
}
void LLContextMenuBranch::setHighlight( BOOL highlight )
{
if (highlight == getHighlight()) return;
LLMenuItemGL::setHighlight(highlight);
// Singu Note: Pie menus show subs only on click
static LLUICachedControl<bool> context("LiruUseContextMenus", false);
if (!context) return;
if (highlight)
{
showSubMenu();
}
else
{
mBranch->hide();
}
}
///////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
// class LLPieMenu
// A circular menu of items, icons, etc.
// class LLContextMenu
// A context menu
//-----------------------------------------------------------------------------
LLPieMenu::LLPieMenu(const std::string& name, const std::string& label)
: LLMenuGL(name, label),
mFirstMouseDown(FALSE),
mUseInfiniteRadius(FALSE),
mHoverItem(NULL),
mHoverThisFrame(FALSE),
LLContextMenu::LLContextMenu(const std::string& name, const std::string& label)
: LLMenuGL(name, label.empty() ? name : label),
mHoveredAnyItem(FALSE),
mOuterRingAlpha(1.f),
mCurRadius(0.f),
mRightMouseDown(FALSE)
{
setRect(LLRect(0,PIE_MENU_HEIGHT,PIE_MENU_WIDTH,0));
mHoverItem(NULL)
{
//setBackgroundVisible(TRUE);
LLMenuGL::setVisible(FALSE);
}
LLPieMenu::LLPieMenu(const std::string& name)
: LLMenuGL(name, name),
mFirstMouseDown(FALSE),
mUseInfiniteRadius(FALSE),
mHoverItem(NULL),
mHoverThisFrame(FALSE),
mHoveredAnyItem(FALSE),
mOuterRingAlpha(1.f),
mCurRadius(0.f),
mRightMouseDown(FALSE)
{
setRect(LLRect(0,PIE_MENU_HEIGHT,PIE_MENU_WIDTH,0));
LLMenuGL::setVisible(FALSE);
}
// virtual
LLXMLNodePtr LLPieMenu::getXML(bool save_children) const
LLXMLNodePtr LLContextMenu::getXML(bool save_children) const
{
LLXMLNodePtr node = LLMenuGL::getXML();
@@ -3450,22 +3426,34 @@ LLXMLNodePtr LLPieMenu::getXML(bool save_children) const
return node;
}
void LLPieMenu::initXML(LLXMLNodePtr node, LLView *context, LLUICtrlFactory *factory)
void LLContextMenu::initXML(LLXMLNodePtr node, LLView *context, LLUICtrlFactory *factory, bool is_context)
{
LLXMLNodePtr child;
for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
{
if (child->hasName(LL_PIE_MENU_TAG))
{
// SUBMENU
std::string name("menu");
child->getAttributeString("name", name);
std::string label(name);
child->getAttributeString("label", label);
// In context menus, more submenu is just an extension of the parent
bool more(false);
if (is_context && child->getAttribute_bool("more", more) && more)
{
//addSeparator(); // Singu Note: perhaps a separator (above) is in order, too?
initXML(child, context, factory, true);
//addSeparator(); // Singu Note: perhaps a separator (below) is in order, too?
}
else
{
// SUBMENU
std::string name("menu");
child->getAttributeString("name", name);
std::string label(name);
child->getAttributeString("label", label);
LLPieMenu *submenu = new LLPieMenu(name, label);
appendPieMenu(submenu);
submenu->initXML(child, context, factory);
// Singu Note: Pie Submenus are denoted with >, while context submenus have an obvious arrow at the end
LLContextMenu* submenu = is_context ? new LLContextMenu(name, label) : new LLPieMenu(name, label + " >");
appendContextSubMenu(submenu);
submenu->initXML(child, context, factory, is_context);
}
}
else
{
@@ -3474,51 +3462,132 @@ void LLPieMenu::initXML(LLXMLNodePtr node, LLView *context, LLUICtrlFactory *fac
}
}
bool LLPieMenu::addChild(LLView* view, S32 tab_group)
{
if(LLMenuGL::addChild(view, tab_group))
{
LLMenuItemSeparatorGL* sep = dynamic_cast<LLMenuItemSeparatorGL*>(view);
if(sep)
sep->setVisible(false);
return true;
}
return false;
}
// virtual
void LLPieMenu::setVisible(BOOL visible)
void LLContextMenu::setVisible(BOOL visible)
{
if (!visible)
{
hide(FALSE);
hide();
}
}
BOOL LLPieMenu::handleHover( S32 x, S32 y, MASK mask )
void LLContextMenu::show(S32 x, S32 y, bool context)
{
// This is mostly copied from the llview class, but it continues
// the hover handle code after a hover handler has been found.
BOOL handled = FALSE;
// If we got a hover event, we've already moved the cursor
// for any menu shifts, so subsequent mouseup messages will be in the
// correct position. No need to correct them.
//mShiftHoriz = 0;
//mShiftVert = 0;
// release mouse capture after short period of visibility if we're using a finite boundary
// so that right click outside of boundary will trigger new pie menu
if (hasMouseCapture() &&
!mRightMouseDown &&
mShrinkBorderTimer.getStarted() &&
mShrinkBorderTimer.getElapsedTimeF32() >= PIE_SHRINK_TIME)
if (getChildList()->empty())
{
gFocusMgr.setMouseCapture(NULL);
mUseInfiniteRadius = FALSE;
// nothing to show, so abort
return;
}
// Save click point for detecting cursor moves before mouse-up.
// Must be in local coords to compare with mouseUp events.
// If the mouse doesn't move, the menu will stay open ala the Mac.
// See also LLMenuGL::showPopup()
LLMenuHolderGL::sContextMenuSpawnPos.set(x,y);
arrangeAndClear();
S32 width = getRect().getWidth();
S32 height = getRect().getHeight();
const LLRect menu_region_rect = LLMenuGL::sMenuContainer->getMenuRect();
LLView* parent_view = getParent();
// Singu TODO: These could probably be combined a bit more.
if (context) // Singu Note: Determine menu repositioning behavior based on menu type
{
// Open upwards if menu extends past bottom
if (y - height < menu_region_rect.mBottom)
{
if (getParentMenuItem())
{
y += height - getParentMenuItem()->getNominalHeight();
}
else
{
y += height;
}
}
// Open out to the left if menu extends past right edge
if (x + width > menu_region_rect.mRight)
{
if (getParentMenuItem())
{
x -= getParentMenuItem()->getRect().getWidth() + width;
}
else
{
x -= width;
}
}
S32 local_x, local_y;
parent_view->screenPointToLocal(x, y, &local_x, &local_y);
LLRect rect;
rect.setLeftTopAndSize(local_x, local_y, width, height);
setRect(rect);
}
else
{
S32 local_x, local_y;
parent_view->screenPointToLocal(x, y, &local_x, &local_y);
LLRect rect;
rect.setCenterAndSize(local_x, local_y, width, height);
setRect(rect);
if (!menu_region_rect.contains(rect)) // Adjust the pie rectangle to keep it on screen
{
S32 trans[2]={0,0};
if (rect.mLeft < menu_region_rect.mLeft)
{
trans[0] = menu_region_rect.mLeft - rect.mLeft;
}
else if (rect.mRight > menu_region_rect.mRight)
{
trans[0] = menu_region_rect.mRight - rect.mRight;
}
if (rect.mBottom < menu_region_rect.mBottom)
{
trans[1] = menu_region_rect.mBottom - rect.mBottom;
}
else if (rect.mTop > menu_region_rect.mTop)
{
trans[1] = menu_region_rect.mTop - rect.mTop;
}
setRect(rect.translate(trans[0],trans[1]));
LLUI::setMousePositionLocal(getParent(),rect.getCenterX(), rect.getCenterY());
}
}
LLMenuItemGL *item = pieItemFromXY( x, y );
arrange();
LLView::setVisible(TRUE);
}
void LLContextMenu::hide()
{
if (!getVisible()) return;
LLView::setVisible(FALSE);
if (mHoverItem)
{
mHoverItem->setHighlight( FALSE );
mHoverItem = NULL;
}
}
BOOL LLContextMenu::handleHover( S32 x, S32 y, MASK mask )
{
LLMenuGL::handleHover(x, y, mask);
LLMenuItemGL* item = getHighlightedItem();
return handleHoverOver(item, x, y);
}
BOOL LLContextMenu::handleHoverOver(LLMenuItemGL* item, S32 x, S32 y)
{
BOOL handled = FALSE;
if (item && item->getEnabled())
{
@@ -3534,37 +3603,6 @@ BOOL LLPieMenu::handleHover( S32 x, S32 y, MASK mask )
}
mHoverItem = item;
mHoverItem->setHighlight( TRUE );
switch(pieItemIndexFromXY(x, y))
{
case 0:
make_ui_sound("UISndPieMenuSliceHighlight0");
break;
case 1:
make_ui_sound("UISndPieMenuSliceHighlight1");
break;
case 2:
make_ui_sound("UISndPieMenuSliceHighlight2");
break;
case 3:
make_ui_sound("UISndPieMenuSliceHighlight3");
break;
case 4:
make_ui_sound("UISndPieMenuSliceHighlight4");
break;
case 5:
make_ui_sound("UISndPieMenuSliceHighlight5");
break;
case 6:
make_ui_sound("UISndPieMenuSliceHighlight6");
break;
case 7:
make_ui_sound("UISndPieMenuSliceHighlight7");
break;
default:
make_ui_sound("UISndPieMenuSliceHighlight0");
break;
}
}
mHoveredAnyItem = TRUE;
}
@@ -3585,8 +3623,170 @@ BOOL LLPieMenu::handleHover( S32 x, S32 y, MASK mask )
handled = TRUE;
}
return handled;
}
// handleMouseUp and handleMouseDown are handled by LLMenuGL
BOOL LLContextMenu::handleRightMouseDown(S32 x, S32 y, MASK mask)
{
BOOL handled = FALSE;
// The click was somewhere within our rectangle
LLMenuItemGL* item = getHighlightedItem();
S32 local_x = x - getRect().mLeft;
S32 local_y = y - getRect().mBottom;
BOOL clicked_in_menu = pointInView(local_x, local_y);
// grab mouse if right clicking anywhere within pie (even deadzone in middle), to detect drag outside of pie
if (clicked_in_menu)
{
// capture mouse cursor as if on initial menu show
handled = TRUE;
}
if (item)
{
// lie to the item about where the click happened
// to make sure it's within the item's rectangle
if (item->handleMouseDown( 0, 0, mask ))
{
handled = TRUE;
}
}
return handled;
}
BOOL LLContextMenu::handleRightMouseUp( S32 x, S32 y, MASK mask )
{
S32 local_x = x - getRect().mLeft;
S32 local_y = y - getRect().mBottom;
if (!mHoveredAnyItem && !pointInView(local_x, local_y))
{
sMenuContainer->hideMenus();
return TRUE;
}
BOOL result = handleMouseUp( x, y, mask );
mHoveredAnyItem = FALSE;
return result;
}
bool LLContextMenu::addChild(LLView* view, S32 tab_group)
{
if (LLContextMenu* context = dynamic_cast<LLContextMenu*>(view))
return appendContextSubMenu(context);
if (LLMenuItemGL* item = dynamic_cast<LLMenuItemGL*>(view))
return append(item);
if (LLMenuGL* menu = dynamic_cast<LLMenuGL*>(view))
return appendMenu(menu);
return false;
}
BOOL LLContextMenu::appendContextSubMenu(LLContextMenu* menu)
{
if (menu == this)
{
llerrs << "Can't attach a context menu to itself" << llendl;
}
LLContextMenuBranch* item = new LLContextMenuBranch(menu->getName(), menu->getLabel(), menu);
getParent()->addChild(item->getBranch());
return append(item);
}
const S32 PIE_MENU_HEIGHT = 190;
const S32 PIE_MENU_WIDTH = 190;
//-----------------------------------------------------------------------------
// class LLPieMenu
// A circular menu of items, icons, etc.
//-----------------------------------------------------------------------------
LLPieMenu::LLPieMenu(const std::string& name, const std::string& label)
: LLContextMenu(name, label),
mFirstMouseDown(FALSE),
mUseInfiniteRadius(FALSE),
mHoverIndex(-1),
mHoverThisFrame(FALSE),
mOuterRingAlpha(1.f),
mCurRadius(0.f),
mRightMouseDown(FALSE)
{
setRect(LLRect(0,PIE_MENU_HEIGHT,PIE_MENU_WIDTH,0));
}
// Separators on pie menus are invisible
bool LLPieMenu::addChild(LLView* view, S32 tab_group)
{
if (LLContextMenu::addChild(view, tab_group))
{
LLMenuItemSeparatorGL* sep = dynamic_cast<LLMenuItemSeparatorGL*>(view);
if(sep)
sep->setVisible(false);
return true;
}
return false;
}
BOOL LLPieMenu::handleHover( S32 x, S32 y, MASK mask )
{
// release mouse capture after short period of visibility if we're using a finite boundary
// so that right click outside of boundary will trigger new pie menu
if (hasMouseCapture() &&
!mRightMouseDown &&
mShrinkBorderTimer.getStarted() &&
mShrinkBorderTimer.getElapsedTimeF32() >= PIE_SHRINK_TIME)
{
gFocusMgr.setMouseCapture(NULL);
mUseInfiniteRadius = FALSE;
}
mHoverThisFrame = TRUE;
S32 index = mHoverIndex;
mHoverIndex = pieItemIndexFromXY(x, y);
BOOL handled = handleHoverOver(pieItemFromIndex(mHoverIndex), x, y);
if (mHoverItem && mHoverIndex != index)
{
switch(mHoverIndex)
{
case 0:
make_ui_sound("UISndPieMenuSliceHighlight0");
break;
case 1:
make_ui_sound("UISndPieMenuSliceHighlight1");
break;
case 2:
make_ui_sound("UISndPieMenuSliceHighlight2");
break;
case 3:
make_ui_sound("UISndPieMenuSliceHighlight3");
break;
case 4:
make_ui_sound("UISndPieMenuSliceHighlight4");
break;
case 5:
make_ui_sound("UISndPieMenuSliceHighlight5");
break;
case 6:
make_ui_sound("UISndPieMenuSliceHighlight6");
break;
case 7:
make_ui_sound("UISndPieMenuSliceHighlight7");
break;
default:
make_ui_sound("UISndPieMenuSliceHighlight0");
break;
}
}
return handled;
}
@@ -3602,11 +3802,6 @@ BOOL LLPieMenu::handleMouseDown( S32 x, S32 y, MASK mask )
// to make sure it's within the item's rectangle
handled = item->handleMouseDown( 0, 0, mask );
}
else if (!mRightMouseDown)
{
// call hidemenus to make sure transient selections get cleared
((LLMenuHolderGL*)getParent())->hideMenus();
}
// always handle mouse down as mouse up will close open menus
return TRUE;
@@ -3688,13 +3883,26 @@ BOOL LLPieMenu::handleMouseUp( S32 x, S32 y, MASK mask )
if (item->getEnabled())
{
handled = item->handleMouseUp( 0, 0, mask );
hide(TRUE);
hide();
}
}
else if (!mRightMouseDown)
{
// if shift is held, click is in the view, and a parent menu exists, go back up
if (mask & MASK_SHIFT && pointInView(x, y))
{
if (LLMenuItemGL* branch = getParentMenuItem())
{
if (LLContextMenu* parent = dynamic_cast<LLContextMenu*>(branch->getParent()))
{
hide();
parent->show(LLMenuHolderGL::sContextMenuSpawnPos.mX, LLMenuHolderGL::sContextMenuSpawnPos.mY, false);
return true;
}
}
}
// call hidemenus to make sure transient selections get cleared
((LLMenuHolderGL*)getParent())->hideMenus();
sMenuContainer->hideMenus();
}
if (handled)
@@ -3732,6 +3940,7 @@ void LLPieMenu::draw()
{
mHoverItem->setHighlight(FALSE);
mHoverItem = NULL;
mHoverIndex = -1;
}
F32 width = (F32) getRect().getWidth();
@@ -3765,22 +3974,16 @@ void LLPieMenu::draw()
gl_washer_2d( mCurRadius, (F32) PIE_CENTER_SIZE, steps, bg_color, outer_color );
// selected wedge
item_list_t::iterator item_iter;
S32 i = 0;
for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
if (mHoverItem)
{
if ((*item_iter)->getHighlight())
{
F32 arc_size = F_PI * 0.25f;
F32 arc_size = F_PI * 0.25f;
F32 start_radians = (i * arc_size) - (arc_size * 0.5f);
F32 end_radians = start_radians + arc_size;
F32 start_radians = (mHoverIndex * arc_size) - (arc_size * 0.5f);
F32 end_radians = start_radians + arc_size;
LLColor4 outer_color = selected_color;
outer_color.mV[VALPHA] *= mOuterRingAlpha;
gl_washer_segment_2d( mCurRadius, (F32)PIE_CENTER_SIZE, start_radians, end_radians, steps / 8, selected_color, outer_color );
}
i++;
LLColor4 outer_color = selected_color;
outer_color.mV[VALPHA] *= mOuterRingAlpha;
gl_washer_segment_2d( mCurRadius, (F32)PIE_CENTER_SIZE, start_radians, end_radians, steps / 8, selected_color, outer_color );
}
LLUI::setLineWidth( line_width );
@@ -3807,38 +4010,10 @@ void LLPieMenu::draw()
LLView::draw();
}
void LLPieMenu::drawBackground(LLMenuItemGL* itemp, LLColor4& color)
// virtual
void LLPieMenu::drawBackground(LLMenuItemGL*, LLColor4&)
{
F32 width = (F32) getRect().getWidth();
F32 height = (F32) getRect().getHeight();
F32 center_x = width/2;
F32 center_y = height/2;
S32 steps = 100;
gGL.color4fv( color.mV );
gGL.pushUIMatrix();
{
gGL.translateUI(center_x - itemp->getRect().mLeft, center_y - itemp->getRect().mBottom, 0.f);
item_list_t::iterator item_iter;
S32 i = 0;
for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
{
if ((*item_iter) == itemp)
{
F32 arc_size = F_PI * 0.25f;
F32 start_radians = (i * arc_size) - (arc_size * 0.5f);
F32 end_radians = start_radians + arc_size;
LLColor4 outer_color = color;
outer_color.mV[VALPHA] *= mOuterRingAlpha;
gl_washer_segment_2d( mCurRadius, (F32)PIE_CENTER_SIZE, start_radians, end_radians, steps / 8, color, outer_color );
}
i++;
}
}
gGL.popUIMatrix();
// Selection is drawn in our draw call, do nothing here and override base drawing rectangles.
}
// virtual
@@ -3853,24 +4028,9 @@ BOOL LLPieMenu::append(LLMenuItemGL *item)
BOOL LLPieMenu::addSeparator()
{
LLMenuItemGL* separator = new LLMenuItemBlankGL();
separator->setFont( LLFontGL::getFontSansSerifSmall() );
return append( separator );
}
BOOL LLPieMenu::appendPieMenu(LLPieMenu *menu)
{
if (menu == this)
{
llerrs << "Can't attach a pie menu to itself" << llendl;
}
LLPieMenuBranch *item;
item = new LLPieMenuBranch(menu->getName(), menu->getLabel(), menu);
getParent()->addChild(item->getBranch());
item->setFont( LLFontGL::getFontSansSerifSmall() );
return append( item );
}
// virtual
void LLPieMenu::arrange()
{
@@ -3925,13 +4085,15 @@ void LLPieMenu::arrange()
LLMenuItemGL *LLPieMenu::pieItemFromXY(S32 x, S32 y)
{
// We might have shifted this menu on draw. If so, we need
// to shift over mouseup events until we get a hover event.
//x += mShiftHoriz;
//y += mShiftVert;
return pieItemFromIndex(pieItemIndexFromXY(x, y));
}
S32 LLPieMenu::pieItemIndexFromXY(S32 x, S32 y)
{
// An arc of the pie menu is 45 degrees
const F32 ARC_DEG = 45.f;
// correct for non-square pixels
S32 delta_x = x - getRect().getWidth() / 2;
S32 delta_y = y - getRect().getHeight() / 2;
@@ -3939,14 +4101,14 @@ LLMenuItemGL *LLPieMenu::pieItemFromXY(S32 x, S32 y)
S32 dist_squared = delta_x*delta_x + delta_y*delta_y;
if (dist_squared < PIE_CENTER_SIZE*PIE_CENTER_SIZE)
{
return NULL;
return -1;
}
// infinite radius is only used with right clicks
S32 radius = llmax( getRect().getWidth()/2, getRect().getHeight()/2 );
if (!(mUseInfiniteRadius && mRightMouseDown) && dist_squared > radius * radius)
{
return NULL;
return -1;
}
F32 angle = RAD_TO_DEG * (F32) atan2((F32)delta_y, (F32)delta_x);
@@ -3958,8 +4120,11 @@ LLMenuItemGL *LLPieMenu::pieItemFromXY(S32 x, S32 y)
// make sure we're only using positive angles
if (angle < 0.f) angle += 360.f;
S32 which = S32( angle / ARC_DEG );
return S32( angle / ARC_DEG );
}
LLMenuItemGL* LLPieMenu::pieItemFromIndex(S32 which)
{
if (0 <= which && which < (S32)mItems.size() )
{
item_list_t::iterator item_iter;
@@ -3979,74 +4144,11 @@ LLMenuItemGL *LLPieMenu::pieItemFromXY(S32 x, S32 y)
return NULL;
}
S32 LLPieMenu::pieItemIndexFromXY(S32 x, S32 y)
// virtual
void LLPieMenu::show(S32 x, S32 y, bool mouse_down)
{
// An arc of the pie menu is 45 degrees
const F32 ARC_DEG = 45.f;
// correct for non-square pixels
S32 delta_x = x - getRect().getWidth() / 2;
S32 delta_y = y - getRect().getHeight() / 2;
// circle safe zone in the center
if (delta_x*delta_x + delta_y*delta_y < PIE_CENTER_SIZE*PIE_CENTER_SIZE)
{
return -1;
}
F32 angle = RAD_TO_DEG * (F32) atan2((F32)delta_y, (F32)delta_x);
// rotate marks CCW so that east = [0, ARC_DEG) instead of
// [-ARC_DEG/2, ARC_DEG/2)
angle += ARC_DEG / 2.f;
// make sure we're only using positive angles
if (angle < 0.f) angle += 360.f;
S32 which = S32( angle / ARC_DEG );
return which;
}
void LLPieMenu::show(S32 x, S32 y, BOOL mouse_down)
{
S32 width = getRect().getWidth();
S32 height = getRect().getHeight();
const LLRect menu_region_rect = LLMenuGL::sMenuContainer->getMenuRect();
LLView* parent_view = getParent();
S32 local_x, local_y;
parent_view->screenPointToLocal(x, y, &local_x, &local_y);
LLRect rect;
rect.setCenterAndSize(local_x, local_y, width, height);
setRect(rect);
arrange();
// Adjust the pie rectangle to keep it on screen
if(!menu_region_rect.contains(rect))
{
S32 trans[2]={0,0};
if (rect.mLeft < menu_region_rect.mLeft)
{
trans[0] = menu_region_rect.mLeft - rect.mLeft;
}
else if (rect.mRight > menu_region_rect.mRight)
{
trans[0] = menu_region_rect.mRight - rect.mRight;
}
if (rect.mBottom < menu_region_rect.mBottom)
{
trans[1] = menu_region_rect.mBottom - rect.mBottom;
}
else if (rect.mTop > menu_region_rect.mTop)
{
trans[1] = menu_region_rect.mTop - rect.mTop;
}
setRect(rect.translate(trans[0],trans[1]));
LLUI::setMousePositionLocal(getParent(),rect.getCenterX(), rect.getCenterY());
}
LLContextMenu::show(x, y, false);
// *FIX: what happens when mouse buttons reversed?
mRightMouseDown = mouse_down;
@@ -4059,8 +4161,6 @@ void LLPieMenu::show(S32 x, S32 y, BOOL mouse_down)
make_ui_sound("UISndPieMenuAppear");
}
LLView::setVisible(TRUE);
// we want all mouse events in case user does quick right click again off of pie menu
// rectangle, to support gestural menu traversal
gFocusMgr.setMouseCapture(this);
@@ -4075,16 +4175,10 @@ void LLPieMenu::show(S32 x, S32 y, BOOL mouse_down)
}
}
void LLPieMenu::hide(BOOL item_selected)
// virtual
void LLPieMenu::hide()
{
if (!getVisible()) return;
if (mHoverItem)
{
mHoverItem->setHighlight( FALSE );
mHoverItem = NULL;
}
LLContextMenu::hide();
make_ui_sound("UISndPieMenuHide");
mFirstMouseDown = FALSE;
@@ -4092,8 +4186,6 @@ void LLPieMenu::hide(BOOL item_selected)
mUseInfiniteRadius = FALSE;
mHoveredAnyItem = FALSE;
LLView::setVisible(FALSE);
gFocusMgr.setMouseCapture(NULL);
}
@@ -4630,10 +4722,13 @@ BOOL LLMenuHolderGL::handleKey(KEY key, MASK mask, BOOL called_from_parent)
}
else
{
//highlight first enabled one
if(pMenu->highlightNextItem(NULL))
if (key == KEY_UP || key == KEY_DOWN) // Singu Note: Only highlight if the user actually meant to navigate through the menu
{
handled = true;
//highlight first enabled one
if (pMenu->highlightNextItem(NULL))
{
handled = true;
}
}
}
}

View File

@@ -685,29 +685,59 @@ private:
//-----------------------------------------------------------------------------
// class LLContextMenu
// A context menu
//-----------------------------------------------------------------------------
class LLContextMenu
: public LLMenuGL
{
public:
LLContextMenu(const std::string& name, const std::string& label = "");
virtual LLXMLNodePtr getXML(bool save_children = true) const;
void initXML(LLXMLNodePtr node, LLView* context, LLUICtrlFactory* factory, bool is_context);
public:
virtual ~LLContextMenu() {}
// LLView Functionality
// can't set visibility directly, must call show or hide
virtual void setVisible(BOOL visible);
virtual void show(S32 x, S32 y, bool context = true);
virtual void hide();
virtual BOOL handleHover( S32 x, S32 y, MASK mask );
BOOL handleHoverOver(LLMenuItemGL* item, S32 x, S32 y); // Singu Note: Unify common functionality between Pie and Context hover behaviors
virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask );
virtual BOOL handleRightMouseUp( S32 x, S32 y, MASK mask );
virtual bool addChild(LLView* view, S32 tab_group = 0);
BOOL appendContextSubMenu(LLContextMenu* menu);
protected:
BOOL mHoveredAnyItem;
LLMenuItemGL* mHoverItem;
};
//-----------------------------------------------------------------------------
// class LLPieMenu
// A circular menu of items, icons, etc.
//-----------------------------------------------------------------------------
class LLPieMenu
: public LLMenuGL
: public LLContextMenu
{
public:
LLPieMenu(const std::string& name, const std::string& label);
LLPieMenu(const std::string& name);
LLPieMenu(const std::string& name, const std::string& label = "");
virtual ~LLPieMenu() {}
virtual LLXMLNodePtr getXML(bool save_children = true) const;
void initXML(LLXMLNodePtr node, LLView *context, LLUICtrlFactory *factory);
// LLView Functionality
// hide separators. they are added to 'pad' in empty cells.
virtual bool addChild(LLView* view, S32 tab_group = 0);
// can't set visibility directly, must call show or hide
virtual void setVisible(BOOL visible);
virtual BOOL handleHover( S32 x, S32 y, MASK mask );
virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask );
virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
@@ -721,34 +751,59 @@ private:
public:
virtual BOOL addSeparator();
BOOL appendPieMenu(LLPieMenu *menu);
virtual void arrange( void );
// Display the menu centered on this point on the screen.
void show(S32 x, S32 y, BOOL mouse_down);
void hide(BOOL item_selected);
/*virtual*/ void show(S32 x, S32 y, bool mouse_down = true);
/*virtual*/ void hide();
private:
LLMenuItemGL *pieItemFromXY(S32 x, S32 y);
LLMenuItemGL* pieItemFromIndex(S32 which);
S32 pieItemIndexFromXY(S32 x, S32 y);
// These cause menu items to be spuriously selected by right-clicks
// near the window edge at low frame rates. I don't think they are
// needed unless you shift the menu position in the draw() function. JC
//S32 mShiftHoriz; // non-zero if menu had to shift this frame
//S32 mShiftVert; // non-zero if menu had to shift this frame
BOOL mFirstMouseDown; // true from show until mouse up
BOOL mUseInfiniteRadius; // allow picking pie menu items anywhere outside of center circle
LLMenuItemGL* mHoverItem;
S32 mHoverIndex;
BOOL mHoverThisFrame;
BOOL mHoveredAnyItem;
LLFrameTimer mShrinkBorderTimer;
F32 mOuterRingAlpha; // for rendering pie menus as both bounded and unbounded
F32 mCurRadius;
BOOL mRightMouseDown;
};
//-----------------------------------------------------------------------------
// class LLContextMenuBranch
// A branch to another context menu
//-----------------------------------------------------------------------------
class LLContextMenuBranch : public LLMenuItemGL
{
public:
LLContextMenuBranch(const std::string& name, const std::string& label, LLContextMenu* branch);
virtual LLXMLNodePtr getXML(bool save_children = true) const;
// called to rebuild the draw label
virtual void buildDrawLabel( void );
virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask)
{
LLMenuItemGL::handleMouseUp(x,y,mask);
return TRUE;
}
// doIt() - do the primary funcationality of the menu item.
virtual void doIt( void );
LLContextMenu* getBranch() { return mBranch; }
void setHighlight( BOOL highlight );
protected:
void showSubMenu();
LLContextMenu* mBranch;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLMenuBarGL

View File

@@ -187,7 +187,8 @@ BOOL LLMultiFloater::closeAllFloaters()
//Tab did not actually close, possibly due to a pending Save Confirmation dialog..
//so try and close the next one in the list...
tabToClose++;
}else
}
else
{
//Tab closed ok.
lastTabCount = mTabContainer->getTabCount();
@@ -252,7 +253,7 @@ void LLMultiFloater::addFloater(LLFloater* floaterp, BOOL select_added_floater,
else if (floaterp->getHost())
{
// floaterp is hosted by somebody else and
// this is adding it, so remove it from it's old host
// this is adding it, so remove it from its old host
floaterp->getHost()->removeFloater(floaterp);
}
else if (floaterp->getParent() == gFloaterView)
@@ -302,8 +303,21 @@ void LLMultiFloater::addFloater(LLFloater* floaterp, BOOL select_added_floater,
{
floaterp->setVisible(FALSE);
}
// Tabs sometimes overlap resize handle
moveResizeHandlesToFront();
}
void LLMultiFloater::updateFloaterTitle(LLFloater* floaterp)
{
S32 index = mTabContainer->getIndexForPanel(floaterp);
if (index != -1)
{
mTabContainer->setPanelTitle(index, floaterp->getShortTitle());
}
}
/**
BOOL selectFloater(LLFloater* floaterp)
@@ -329,8 +343,9 @@ void LLMultiFloater::selectPrevFloater()
mTabContainer->selectPrevTab();
}
void LLMultiFloater::showFloater(LLFloater* floaterp)
void LLMultiFloater::showFloater(LLFloater* floaterp, LLTabContainer::eInsertionPoint insertion_point)
{
if(!floaterp) return;
// we won't select a panel that already is selected
// it is hard to do this internally to tab container
// as tab selection is handled via index and the tab at a given
@@ -338,7 +353,7 @@ void LLMultiFloater::showFloater(LLFloater* floaterp)
if (floaterp != mTabContainer->getCurrentPanel() &&
!mTabContainer->selectTabPanel(floaterp))
{
addFloater(floaterp, TRUE);
addFloater(floaterp, TRUE, insertion_point);
}
}
@@ -417,6 +432,13 @@ BOOL LLMultiFloater::handleKeyHere(KEY key, MASK mask)
if (floater && floater->canClose() && floater->isCloseable())
{
floater->close();
// EXT-5695 (Tabbed IM window loses focus if close any tabs by Ctrl+W)
// bring back focus on tab container if there are any tab left
if(mTabContainer->getTabCount() > 0)
{
mTabContainer->setFocus(TRUE);
}
}
return TRUE;
}
@@ -468,12 +490,17 @@ void LLMultiFloater::setFloaterFlashing(LLFloater* floaterp, BOOL flashing)
void LLMultiFloater::onTabSelected()
{
tabOpen((LLFloater*)mTabContainer->getCurrentPanel());
LLFloater* floaterp = dynamic_cast<LLFloater*>(mTabContainer->getCurrentPanel());
if (floaterp)
{
tabOpen(floaterp);
}
}
void LLMultiFloater::setCanResize(BOOL can_resize)
{
LLFloater::setCanResize(can_resize);
if (!mTabContainer) return;
if (isResizable() && mTabContainer->getTabPosition() == LLTabContainer::BOTTOM)
{
mTabContainer->setRightTabBtnOffset(RESIZE_HANDLE_WIDTH);
@@ -510,16 +537,9 @@ void LLMultiFloater::updateResizeLimits()
// initialize minimum size constraint to the original xml values.
S32 new_min_width = mOrigMinWidth;
S32 new_min_height = mOrigMinHeight;
// possibly increase minimum size constraint due to children's minimums.
for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx)
{
LLFloater* floaterp = (LLFloater*)mTabContainer->getPanelByIndex(tab_idx);
if (floaterp)
{
new_min_width = llmax(new_min_width, floaterp->getMinWidth() + LLPANEL_BORDER_WIDTH * 2);
new_min_height = llmax(new_min_height, floaterp->getMinHeight() + LLFLOATER_HEADER_SIZE + TABCNTR_HEADER_HEIGHT);
}
}
computeResizeLimits(new_min_width, new_min_height);
setResizeLimits(new_min_width, new_min_height);
S32 cur_height = getRect().getHeight();
@@ -545,3 +565,17 @@ void LLMultiFloater::updateResizeLimits()
gFloaterView->adjustToFitScreen(this, TRUE);
}
}
void LLMultiFloater::computeResizeLimits(S32& new_min_width, S32& new_min_height)
{
// possibly increase minimum size constraint due to children's minimums.
for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx)
{
LLFloater* floaterp = (LLFloater*)mTabContainer->getPanelByIndex(tab_idx);
if (floaterp)
{
new_min_width = llmax(new_min_width, floaterp->getMinWidth() + LLPANEL_BORDER_WIDTH * 2);
new_min_height = llmax(new_min_height, floaterp->getMinHeight() + LLFLOATER_HEADER_SIZE + TABCNTR_HEADER_HEIGHT);
}
}
}

View File

@@ -56,7 +56,7 @@ public:
virtual void growToFit(S32 content_width, S32 content_height);
virtual void addFloater(LLFloater* floaterp, BOOL select_added_floater, LLTabContainer::eInsertionPoint insertion_point = LLTabContainer::END);
virtual void showFloater(LLFloater* floaterp);
virtual void showFloater(LLFloater* floaterp, LLTabContainer::eInsertionPoint insertion_point = LLTabContainer::END);
virtual void removeFloater(LLFloater* floaterp);
virtual void tabOpen(LLFloater* opened_floater);
@@ -76,6 +76,7 @@ public:
void onTabSelected();
virtual void updateResizeLimits();
virtual void updateFloaterTitle(LLFloater* floaterp);
protected:
struct LLFloaterData
@@ -94,6 +95,9 @@ protected:
LLTabContainer::TabPosition mTabPos;
BOOL mAutoResize;
S32 mOrigMinWidth, mOrigMinHeight; // logically const but initialized late
private:
virtual void computeResizeLimits(S32& new_min_width, S32& new_min_height);
};
#endif // LL_MULTI_FLOATER_H

View File

@@ -40,6 +40,7 @@
#include "lltrans.h"
#include "llnotifications.h"
#include "aialert.h"
#include "../newview/hippogridmanager.h"
@@ -1479,6 +1480,14 @@ LLNotificationPtr LLNotifications::add(const LLNotification::Params& p)
return pNotif;
}
namespace AIAlert { std::string text(Error const& error, int suppress_mask = 0); }
LLNotificationPtr LLNotifications::add(AIAlert::Error const& error, int type, unsigned int suppress_mask)
{
LLSD substitutions = LLSD::emptyMap();
substitutions["[PAYLOAD]"] = AIAlert::text(error, suppress_mask);
return add(LLNotification::Params((type == AIAlert::modal || error.is_modal()) ? "AIAlertModal" : "AIAlert").substitutions(substitutions));
}
void LLNotifications::add(const LLNotificationPtr pNotif)
{

View File

@@ -108,6 +108,8 @@
#include "llnotificationptr.h"
#include "llnotificationcontext.h"
namespace AIAlert { class Error; }
typedef enum e_notification_priority
{
NOTIFICATION_PRIORITY_UNSPECIFIED,
@@ -737,6 +739,7 @@ public:
const LLSD& substitutions,
const LLSD& payload,
LLNotificationFunctorRegistry::ResponseFunctor functor);
LLNotificationPtr add(AIAlert::Error const& error, int type, unsigned int suppress_mask);
LLNotificationPtr add(const LLNotification::Params& p);
void forceResponse(const LLNotification::Params& params, S32 option);

View File

@@ -25,11 +25,76 @@
#include "linden_common.h"
#include "llnotificationsutil.h"
#include "lltrans.h"
#include "llnotifications.h"
#include "llsd.h"
#include "llxmlnode.h" // apparently needed to call LLNotifications::instance()
namespace AIAlert
{
LLNotificationPtr add(Error const& error, unsigned int suppress_mask, modal_nt type)
{
return LLNotifications::instance().add(error, type, suppress_mask);
}
LLNotificationPtr add(std::string const& xml_desc, modal_nt type)
{
return LLNotifications::instance().add(Error(Prefix(), type, xml_desc, AIArgs()), type, 0);
}
LLNotificationPtr add(std::string const& xml_desc, AIArgs const& args, modal_nt type)
{
return LLNotifications::instance().add(Error(Prefix(), type, xml_desc, args), type, 0);
}
LLNotificationPtr add(Error const& error, std::string const& xml_desc, unsigned int suppress_mask, modal_nt type)
{
return LLNotifications::instance().add(Error(Prefix(), type, error, xml_desc, AIArgs()), type, suppress_mask);
}
LLNotificationPtr add(Error const& error, std::string const& xml_desc, AIArgs const& args, unsigned int suppress_mask, modal_nt type)
{
return LLNotifications::instance().add(Error(Prefix(), type, error, xml_desc, args), type, suppress_mask);
}
LLNotificationPtr add(std::string const& xml_desc, Error const& error, unsigned int suppress_mask, modal_nt type)
{
return LLNotifications::instance().add(Error(Prefix(), type, xml_desc, AIArgs(), error), type, suppress_mask);
}
LLNotificationPtr add(std::string const& xml_desc, AIArgs const& args, Error const& error, unsigned int suppress_mask, modal_nt type)
{
return LLNotifications::instance().add(Error(Prefix(), type, xml_desc, args, error), type, suppress_mask);
}
std::string text(Error const& error, int suppress_mask)
{
std::string alert_text;
bool suppress_newlines = false;
bool last_was_prefix = false;
for (Error::lines_type::const_iterator line = error.lines().begin(); line != error.lines().end(); ++line)
{
// Even if a line is suppressed, we print its leading newline if requested, but never more than one.
if (!suppress_newlines && line->prepend_newline())
{
alert_text += '\n';
suppress_newlines = true;
}
if (!line->suppressed(suppress_mask))
{
if (last_was_prefix) alert_text += ' '; // The translation system strips off spaces... add them back.
alert_text += LLTrans::getString(line->getXmlDesc(), line->args());
suppress_newlines = false;
last_was_prefix = line->is_prefix();
}
}
return alert_text;
}
} // namespace AIAlert
LLNotificationPtr LLNotificationsUtil::add(const std::string& name)
{
return LLNotifications::instance().add(

View File

@@ -30,11 +30,55 @@
// to avoid including the heavyweight llnotifications.h
#include "llnotificationptr.h"
#include "aialert.h"
#include <boost/function.hpp>
class LLSD;
namespace AIAlert
{
// Add an alert directly to LLNotifications.
// Look up xml_desc in strings.xml.
LLNotificationPtr add(std::string const& xml_desc,
modal_nt type = not_modal);
// ... with replacement args.
LLNotificationPtr add(std::string const& xml_desc, AIArgs const& args,
modal_nt type = not_modal);
// Append it to an existing alert error.
LLNotificationPtr add(Error const& error,
std::string const& xml_desc,
unsigned int suppress_mask = 0, modal_nt type = not_modal);
LLNotificationPtr add(Error const& error,
std::string const& xml_desc, AIArgs const& args,
unsigned int suppress_mask = 0, modal_nt type = not_modal);
// Prepend it to an existing alert error.
LLNotificationPtr add(std::string const& xml_desc,
Error const& error,
unsigned int suppress_mask = 0, modal_nt type = not_modal);
LLNotificationPtr add(std::string const& xml_desc, AIArgs const& args,
Error const& error,
unsigned int suppress_mask = 0, modal_nt type = not_modal);
// Just show the caught alert error.
LLNotificationPtr add(Error const& error,
unsigned int suppress_mask = 0, modal_nt type = not_modal);
// Short cuts for enforcing modal alerts.
inline LLNotificationPtr add_modal(std::string const& xml_desc) { return add(xml_desc, modal); }
inline LLNotificationPtr add_modal(std::string const& xml_desc, AIArgs const& args) { return add(xml_desc, args, modal); }
inline LLNotificationPtr add_modal(Error const& error, std::string const& xml_desc, unsigned int suppress_mask = 0) { return add(error, xml_desc, suppress_mask, modal); }
inline LLNotificationPtr add_modal(Error const& error, std::string const& xml_desc, AIArgs const& args, unsigned int suppress_mask = 0) { return add(error, xml_desc, args, suppress_mask, modal); }
inline LLNotificationPtr add_modal(std::string const& xml_desc, Error const& error, unsigned int suppress_mask = 0) { return add(xml_desc, error, suppress_mask, modal); }
inline LLNotificationPtr add_modal(std::string const& xml_desc, AIArgs const& args, Error const& error, unsigned int suppress_mask = 0) { return add(xml_desc, args, error, suppress_mask, modal); }
inline LLNotificationPtr add_modal(Error const& error, unsigned int suppress_mask = 0) { return add(error, suppress_mask, modal); }
// Return the full, translated, texted of the alert (possibly suppressing certain output).
std::string text(Error const& error, int suppress_mask = 0);
}
namespace LLNotificationsUtil
{
LLNotificationPtr add(const std::string& name);

View File

@@ -530,11 +530,13 @@ BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *f
void LLPanel::initChildrenXML(LLXMLNodePtr node, LLUICtrlFactory* factory)
{
std::string kidstring(node->getName()->mString);
kidstring += ".string";
LLXMLNodePtr child;
for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
{
// look for string declarations for programmatic text
if (child->hasName("string"))
if (child->hasName("string") || child->hasName(kidstring))
{
std::string string_name;
child->getAttributeString("name", string_name);

View File

@@ -40,9 +40,10 @@ const S32 MIN_COLUMN_WIDTH = 20;
//---------------------------------------------------------------------------
// LLScrollColumnHeader
//---------------------------------------------------------------------------
LLScrollColumnHeader::LLScrollColumnHeader(const std::string& name, const LLRect& rect, LLScrollListColumn* column)
: LLButton(name, rect, "square_btn_32x128.tga", "square_btn_selected_32x128.tga", LLStringUtil::null, NULL, LLFontGL::getFontSansSerifSmall()),
LLScrollColumnHeader::LLScrollColumnHeader(const std::string& name, const LLRect& rect, LLScrollListColumn* column, const std::string& unselected_image_name, const std::string& selected_image_name)
: LLButton(name, rect, unselected_image_name, selected_image_name, LLStringUtil::null, NULL, LLFontGL::getFontSansSerifSmall()),
mColumn(column),
mDrawArrow(true),
mHasResizableElement(FALSE)
{
setClickedCallback(boost::bind(&LLScrollColumnHeader::onClick, this, _2));
@@ -65,20 +66,23 @@ LLScrollColumnHeader::~LLScrollColumnHeader()
void LLScrollColumnHeader::draw()
{
std::string sort_column = mColumn->mParentCtrl->getSortColumnName();
BOOL draw_arrow = !mColumn->mLabel.empty()
&& mColumn->mParentCtrl->isSorted()
// check for indirect sorting column as well as column's sorting name
&& (sort_column == mColumn->mSortingColumn || sort_column == mColumn->mName);
if (mDrawArrow)
{
std::string sort_column = mColumn->mParentCtrl->getSortColumnName();
BOOL draw_arrow = !mColumn->mLabel.empty()
&& mColumn->mParentCtrl->isSorted()
// check for indirect sorting column as well as column's sorting name
&& (sort_column == mColumn->mSortingColumn || sort_column == mColumn->mName);
BOOL is_ascending = mColumn->mParentCtrl->getSortAscending();
if (draw_arrow)
{
setImageOverlay(is_ascending ? "up_arrow.tga" : "down_arrow.tga", LLFontGL::RIGHT, LLColor4::white);
}
else
{
setImageOverlay(LLUUID::null);
BOOL is_ascending = mColumn->mParentCtrl->getSortAscending();
if (draw_arrow)
{
setImageOverlay(is_ascending ? "up_arrow.tga" : "down_arrow.tga", LLFontGL::RIGHT, LLColor4::white);
}
else
{
setImageOverlay(LLUUID::null);
}
}
// Draw children

View File

@@ -40,7 +40,7 @@ class LLScrollListCtrl;
class LLScrollColumnHeader : public LLButton
{
public:
LLScrollColumnHeader(const std::string& name, const LLRect& rect, LLScrollListColumn* column);
LLScrollColumnHeader(const std::string& name, const LLRect& rect, LLScrollListColumn* column, const std::string& unselected_image_name = "square_btn_32x128.tga", const std::string& selected_image_name = "square_btn_selected_32x128.tga");
~LLScrollColumnHeader();
/*virtual*/ void draw();
@@ -51,6 +51,8 @@ public:
/*virtual*/ void handleReshape(const LLRect& new_rect, bool by_user = false);
LLScrollListColumn* getColumn() { return mColumn; }
// Singu Note: Toggles drawing the sort arrow altogether
void setDrawArrow(bool draw_arrow) { mDrawArrow = draw_arrow; }
void setHasResizableElement(BOOL resizable);
void updateResizeBars();
BOOL canResize();
@@ -60,6 +62,7 @@ public:
private:
LLScrollListColumn* mColumn;
bool mDrawArrow;
LLResizeBar* mResizeBar;
BOOL mHasResizableElement;
};

View File

@@ -2848,24 +2848,29 @@ void LLScrollListCtrl::addColumn(const LLScrollListColumn::Params& column_params
LLRect temp_rect = LLRect(left,top+mHeadingHeight,right,top);
new_column->mHeader = new LLScrollColumnHeader("btn_" + name, temp_rect, new_column);
new_column->mHeader->setToolTip(column_params.tool_tip());
new_column->mHeader->setTabStop(false);
new_column->mHeader->setVisible(mDisplayColumnHeaders);
if(column_params.header.image.isProvided())
if (column_params.header.image.isProvided())
{
new_column->mHeader->setImages(column_params.header.image, column_params.header.image);
}
else if(column_params.header.image_overlay.isProvided())
{
new_column->mHeader->setImageOverlay(column_params.header.image_overlay);
new_column->mHeader = new LLScrollColumnHeader("btn_" + name, temp_rect, new_column, column_params.header.image, column_params.header.image);
new_column->mHeader->setDrawArrow(false);
}
else
{
new_column->mHeader->setLabel(column_params.header.label());
new_column->mHeader = new LLScrollColumnHeader("btn_" + name, temp_rect, new_column);
if (column_params.header.image_overlay.isProvided())
{
new_column->mHeader->setImageOverlay(column_params.header.image_overlay);
new_column->mHeader->setDrawArrow(false);
}
else
{
new_column->mHeader->setLabel(column_params.header.label());
}
}
new_column->mHeader->setToolTip(column_params.tool_tip());
new_column->mHeader->setTabStop(false);
new_column->mHeader->setVisible(mDisplayColumnHeaders);
addChild(new_column->mHeader);
sendChildToFront(mScrollbar);

View File

@@ -446,7 +446,7 @@ LLMenuGL *LLUICtrlFactory::buildMenu(const std::string &filename, LLView* parent
//-----------------------------------------------------------------------------
// buildMenu()
//-----------------------------------------------------------------------------
LLPieMenu *LLUICtrlFactory::buildPieMenu(const std::string &filename, LLView* parentp)
LLContextMenu* LLUICtrlFactory::buildContextMenu(const std::string& filename, LLView* parentp)
{
LLXMLNodePtr root;
@@ -465,9 +465,10 @@ LLPieMenu *LLUICtrlFactory::buildPieMenu(const std::string &filename, LLView* pa
std::string name("menu");
root->getAttributeString("name", name);
LLPieMenu *menu = new LLPieMenu(name);
static LLUICachedControl<bool> context("LiruUseContextMenus", false);
LLContextMenu* menu = context ? new LLContextMenu(name) : new LLPieMenu(name);
parentp->addChild(menu);
menu->initXML(root, parentp, this);
menu->initXML(root, parentp, this, context);
if (LLUI::sShowXUINames)
{

View File

@@ -106,7 +106,7 @@ public:
bool builtPanel(LLPanel* panelp) {return mBuiltPanels.find(panelp->getHandle()) != mBuiltPanels.end();}
class LLMenuGL *buildMenu(const std::string &filename, LLView* parentp);
class LLPieMenu *buildPieMenu(const std::string &filename, LLView* parentp);
class LLContextMenu* buildContextMenu(const std::string& filename, LLView* parentp);
// Does what you want for LLFloaters and LLPanels
// Returns 0 on success

View File

@@ -357,6 +357,11 @@ public:
BOOL focusNextRoot();
BOOL focusPrevRoot();
// Normally we want the app menus to get priority on accelerated keys
// However, sometimes we want to give specific views a first chance
// at handling them. (eg. the script editor)
virtual bool hasAccelerators() const { return false; }
virtual void deleteAllChildren();
virtual void setTentative(BOOL b);

View File

@@ -363,7 +363,11 @@ std::string LLDir::buildSLOSCacheDir() const
}
else
{
#if defined(_WIN64)
res = add(getOSCacheDir(), "SingularityViewer64");
#else
res = add(getOSCacheDir(), "SingularityViewer");
#endif
}
return res;
}

View File

@@ -749,7 +749,7 @@ void LLWindowWin32::close()
LL_DEBUGS("Window") << "Destroying Window" << LL_ENDL;
// Don't process events in our mainWindowProc any longer.
SetWindowLong(mWindowHandle, GWL_USERDATA, NULL);
SetWindowLongPtr(mWindowHandle, GWLP_USERDATA, NULL);
// Make sure we don't leave a blank toolbar button.
ShowWindow(mWindowHandle, SW_HIDE);
@@ -1660,7 +1660,7 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO
LL_DEBUGS("Window") << "Keeping vertical sync" << LL_ENDL;
}
SetWindowLong(mWindowHandle, GWL_USERDATA, (U32)this);
SetWindowLongPtr(mWindowHandle, GWLP_USERDATA, (LONG_PTR)this);
// register this window as handling drag/drop events from the OS
DragAcceptFiles( mWindowHandle, TRUE );
@@ -1983,7 +1983,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
// This helps prevent avatar walking after maximizing the window by double-clicking the title bar.
static bool sHandleLeftMouseUp = true;
LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLong(h_wnd, GWL_USERDATA);
LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLongPtr(h_wnd, GWLP_USERDATA);
if (NULL != window_imp)

View File

@@ -13,6 +13,7 @@ include_directories(
)
set(llxml_SOURCE_FILES
aixml.cpp
llcontrol.cpp
llxmlnode.cpp
llxmlparser.cpp
@@ -22,6 +23,7 @@ set(llxml_SOURCE_FILES
set(llxml_HEADER_FILES
CMakeLists.txt
aixml.h
llcontrol.h
llcontrolgroupreader.h
llxmlnode.h

609
indra/llxml/aixml.cpp Normal file
View File

@@ -0,0 +1,609 @@
/**
* @file aixml.cpp
* @brief XML serialization support.
*
* 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.
*
* 30/07/2013
* Initial version, written by Aleric Inglewood @ SL
*/
#include "sys.h"
#include "aixml.h"
#include "llmd5.h"
#include <boost/tokenizer.hpp>
#include "aifile.h"
//=============================================================================
// Overview
// The AIXML* classes provide an Object Oriented way to serialize objects
// to and from an XML file.
//
// The following classes are provided:
//
// AIXMLRootElement - Write an object to a file (including XML declaration at the top).
// AIXMLElement - Write an ojbect to an ostream (just one XML element).
//
// AIXMLParser - Read and deserialize an XML file written with AIXMLRootElement.
// AIXMLElementParser - Read and deserialize an XML stream written with AIXMLElement.
//
// Classes that need to be written to and from XML would typically
// supply two member functions. For example,
#ifdef EXAMPLE_CODE // undefined
class HelloWorld {
public:
// Write object to XML.
void toXML(std::ostream& os, int indentation) const;
// Read object from XML.
HelloWorld(AIXMLElementParser const& parser);
private:
// Example member variables...
Attribute1 mAttribute1;
Attribute2 mAttribute2;
// etc.
Custom1 mCustom;
std::vector<Custom2> mContainer;
LLDate mDate;
LLMD5 mMd5;
LLUUID mUUID;
};
// Typical serialization member function.
void HelloWorld::toXML(std::ostream& os, int indentation) const
{
AIXMLElement tag(os, "helloworld", indentation);
// Zero or more attributes:
tag.attribute("attributename1", mAttribute1); // Uses operator<<(std::ostream&, Attribute1 const&) to write mAttribute1.
tag.attribute("attributename2", mAttribute2); // Uses operator<<(std::ostream&, Attribute2 const&) to write mAttribute2.
// etc.
// Zero or more child elements:
tag.child("tagname", mChild1);
tag.child(mCustom); // Calls mCustom.toXML() to insert the object.
tag.child(mContainer.begin(), mContainer.end()); // Calls tag.child(element) for each element of the container.
// Special allowed cases:
tag.child(mDate); // Uses "date" as tag name.
tag.child(mMd5); // Uses "md5" as tag name.
tag.child(mUUID); // Uses "uuid" as tag name.
}
// Typical deserialization member function.
HelloWorld::HelloWorld(AIXMLElementParser const& parser)
{
// Zero or more attributes:
parser.attribute("attributename1", "foobar"); // Throws std::runtime_error is attributename1 is missing or does not have the value "foobar".
if (!parser.attribute("attributename2", mAttribute2)) // Reads value of attributename2 into mAttribute2 (throws if it could not be parsed).
{
throw std::runtime_error("..."); // Attribute was missing.
}
// Zero or more child elements:
parser.child("tagname", mChild1);
parser.child("custom1", mCustom);
parser.insert_children("custom2", mContainer);
// Special allowed cases:
parser.child(mDate);
parser.child(mMd5);
parser.child(mUUID);
}
// To actually write to an XML file one would do, for example:
LLFILE* fp = fopen(...);
AIXMLRootElement tag(fp, "rootname");
tag.attribute("version", "1.0");
tag.child(LLDate::now());
tag.child(mHelloWorld);
// And to read it again,
AIXMLParser helloworld(filename, "description of file used for error reporting", "rootname", 1);
helloworld.attribute("version", "1.0");
helloworld.child("helloworld", mHelloWorld);
// Of course, both would need to be in a try { } catch block.
#endif // EXAMPLE_CODE
// Do NOT change these - it would break old databases.
char const* const DEFAULT_LLUUID_NAME = "uuid";
char const* const DEFAULT_MD5STR_NAME = "md5";
char const* const DEFAULT_LLDATE_NAME = "date";
std::string const DEFAULT_MD5STR_ATTRIBUTE_NAME = DEFAULT_MD5STR_NAME;
std::string const DEFAULT_LLUUID_ATTRIBUTE_NAME = DEFAULT_LLUUID_NAME;
std::string const DEFAULT_LLDATE_ATTRIBUTE_NAME = DEFAULT_LLDATE_NAME;
std::string const DEFAULT_VERSION_ATTRIBUTE_NAME = "version";
struct xdigit {
bool isxdigit;
xdigit(void) : isxdigit(true) { }
void operator()(char c) { isxdigit = isxdigit && std::isxdigit(c); }
operator bool() const { return isxdigit; }
};
static bool is_valid_md5str(std::string const& str)
{
return str.length() == MD5HEX_STR_BYTES && std::for_each(str.begin(), str.end(), xdigit());
}
// Conversion routine that is a lot more strict then LLStringUtil::convertToU32.
// This version does not allow leading or trailing spaces, nor does it allow a leading minus sign.
// Leading zeroes are not allowed except a 0 by itself.
bool convertToU32strict(std::string const& str, U32& value)
{
bool first = true;
value = 0;
for (std::string::const_iterator i = str.begin(); i != str.end(); ++i)
{
if (value == 0 && !first || !std::isdigit(*i)) // Reject leading zeroes and non-digits.
return false;
value = value * 10 + *i - '0';
first = false;
}
return !first; // Reject empty string.
}
typedef boost::tokenizer<boost::char_separator<char> > boost_tokenizer;
bool decode_version(std::string const& version, U32& major, U32& minor)
{
boost_tokenizer tokens(version, boost::char_separator<char>("", "."));
boost_tokenizer::const_iterator itTok = tokens.begin();
return itTok != tokens.end() && convertToU32strict(*itTok++, major) &&
itTok != tokens.end() && *itTok++ == "." &&
itTok != tokens.end() && convertToU32strict(*itTok, minor);
}
bool md5strFromXML(LLXmlTreeNode* node, std::string& md5str_out)
{
static LLStdStringHandle const DEFAULT_MD5STR_ATTRIBUTE_NAME_HANDLE = LLXmlTree::addAttributeString(DEFAULT_MD5STR_ATTRIBUTE_NAME);
return node->getFastAttributeString(DEFAULT_MD5STR_ATTRIBUTE_NAME_HANDLE, md5str_out) && is_valid_md5str(md5str_out);
}
bool md5strFromXML(LLXmlTreeNode* node, std::string& md5str_out, std::string const& attribute_name)
{
return node->getAttributeString(attribute_name, md5str_out) && is_valid_md5str(md5str_out);
}
bool UUIDFromXML(LLXmlTreeNode* node, LLUUID& uuid_out)
{
static LLStdStringHandle const DEFAULT_LLUUID_ATTRIBUTE_NAME_HANDLE = LLXmlTree::addAttributeString(DEFAULT_LLUUID_ATTRIBUTE_NAME);
return node->getFastAttributeUUID(DEFAULT_LLUUID_ATTRIBUTE_NAME_HANDLE, uuid_out);
}
bool UUIDFromXML(LLXmlTreeNode* node, LLUUID& uuid_out, std::string const& attribute_name)
{
return node->getAttributeUUID(attribute_name, uuid_out);
}
bool dateFromXML(LLXmlTreeNode* node, LLDate& date_out)
{
static LLStdStringHandle const DEFAULT_LLDATE_ATTRIBUTE_NAME_HANDLE = LLXmlTree::addAttributeString(DEFAULT_LLDATE_ATTRIBUTE_NAME);
std::string date_s;
return node->getFastAttributeString(DEFAULT_LLDATE_ATTRIBUTE_NAME_HANDLE, date_s) && date_out.fromString(date_s);
}
bool dateFromXML(LLXmlTreeNode* node, LLDate& date_out, std::string const& attribute_name)
{
std::string date_s;
return node->getAttributeString(attribute_name, date_s) && date_out.fromString(date_s);
}
bool versionFromXML(LLXmlTreeNode* node, U32& major_out, U32& minor_out)
{
static LLStdStringHandle const DEFAULT_VERSION_ATTRIBUTE_NAME_HANDLE = LLXmlTree::addAttributeString(DEFAULT_VERSION_ATTRIBUTE_NAME);
major_out = minor_out = 0;
std::string version_s;
return node->getFastAttributeString(DEFAULT_VERSION_ATTRIBUTE_NAME_HANDLE, version_s) && decode_version(version_s, major_out, minor_out);
}
bool versionFromXML(LLXmlTreeNode* node, U32& major_out, U32& minor_out, std::string const& attribute_name)
{
major_out = minor_out = 0;
std::string version_s;
return node->getAttributeString(attribute_name, version_s) && decode_version(version_s, major_out, minor_out);
}
//-----------------------------------------------------------------------------
// AIXMLElement
AIXMLElement::AIXMLElement(std::ostream& os, char const* name, int indentation) :
mOs(os), mName(name), mIndentation(indentation), mHasChildren(false)
{
mOs << std::string(mIndentation, ' ') << '<' << mName;
if (!mOs.good())
{
THROW_ALERT("AIXMLElement_Failed_to_write_DATA", AIArgs("[DATA]", "<" + mName));
}
}
int AIXMLElement::open_child(void)
{
if (!mHasChildren)
{
mOs << ">\n";
if (!mOs.good())
{
THROW_ALERT("AIXMLElement_closing_child_Failed_to_write_DATA", AIArgs("[DATA]", ">\\n"));
}
mHasChildren = true;
}
mIndentation += 2;
return mIndentation;
}
void AIXMLElement::close_child(void)
{
mIndentation -= 2;
}
AIXMLElement::~AIXMLElement()
{
if (mHasChildren)
{
mOs << std::string(mIndentation, ' ') << "</" << mName << ">\n";
if (!mOs.good())
{
THROW_ALERT("AIXMLElement_closing_child_Failed_to_write_DATA",
AIArgs("[DATA]", "\\n" + std::string(mIndentation, ' ') + "</" + mName + ">\\n"));
}
}
else
{
mOs << " />\n";
if (!mOs.good())
{
THROW_ALERT("AIXMLElement_closing_child_Failed_to_write_DATA", AIArgs("[DATA]", " />\\n"));
}
}
}
template<>
void AIXMLElement::child(LLUUID const& element)
{
open_child();
write_child(DEFAULT_LLUUID_NAME, element);
close_child();
}
template<>
void AIXMLElement::child(LLMD5 const& element)
{
open_child();
write_child(DEFAULT_MD5STR_NAME, element);
close_child();
}
template<>
void AIXMLElement::child(LLDate const& element)
{
open_child();
write_child(DEFAULT_LLDATE_NAME, element);
close_child();
}
//-----------------------------------------------------------------------------
// AIXMLStream
AIXMLStream::AIXMLStream(LLFILE* fp, bool standalone) : mOfs(fp)
{
char const* sp = standalone ? " standalone=\"yes\"" : "";
int rc = fprintf(fp, "<?xml version=\"1.0\" encoding=\"utf-8\"%s ?>\n", sp);
if (rc < 0 || ferror(fp))
{
// I don't think that errno is set to anything else but EBADF here,
// so there is not really any informative message to add here.
THROW_MALERT("AIXMLStream_fprintf_failed_to_write_xml_header");
}
}
AIXMLStream::~AIXMLStream()
{
if (mOfs.is_open())
{
mOfs.close();
}
}
//-----------------------------------------------------------------------------
// AIXMLParser
AIXMLParser::AIXMLParser(std::string const& filename, char const* file_desc, std::string const& name, U32 major_version) :
AIXMLElementParser(mFilename, mFileDesc, major_version),
mFilename(filename), mFileDesc(file_desc)
{
char const* error = NULL;
AIArgs args;
if (!mXmlTree.parseFile(filename, TRUE))
{
AIFile dummy(filename, "rb"); // Check if the file can be opened at all (throws with a more descriptive error if not).
error = "AIXMLParser_Cannot_parse_FILEDESC_FILENAME";
}
else
{
mNode = mXmlTree.getRoot();
if (!mNode)
{
error = "AIXMLParser_No_root_node_found_in_FILEDESC_FILENAME";
}
else if (!mNode->hasName(name))
{
error = "AIXMLParser_Missing_header_NAME_invalid_FILEDESC_FILENAME";
args("[NAME]", name);
}
else if (!versionFromXML(mNode, mVersionMajor, mVersionMinor))
{
error = "AIXMLParser_Invalid_or_missing_NAME_version_attribute_in_FILEDESC_FILENAME";
args("[NAME]", name);
}
else if (mVersionMajor != major_version)
{
error = "AIXMLParser_Incompatible_NAME_version_MAJOR_MINOR_in";
args("[NAME]", name)("[MAJOR]", llformat("%u", mVersionMajor))("[MINOR]", llformat("%u", mVersionMinor));
}
}
if (error)
{
THROW_MALERT(error, args("[FILEDESC]", mFileDesc)("[FILENAME]", mFilename));
}
}
//-----------------------------------------------------------------------------
// AIXMLElementParser
template<>
LLMD5 AIXMLElementParser::read_string(std::string const& value) const
{
if (!is_valid_md5str(value))
{
THROW_MALERT("AIXMLElementParser_read_string_Invalid_MD5_VALUE_in_FILEDESC_FILENAME",
AIArgs("[VALUE]", value)("[FILEDESC]", mFileDesc)("[FILENAME]", mFilename));
}
unsigned char digest[16];
std::memset(digest, 0, sizeof(digest));
for (int i = 0; i < 32; ++i)
{
int x = value[i];
digest[i >> 1] += (x - (x & 0xf0) + (x >> 6) * 9) << ((~i & 1) << 2);
}
LLMD5 result;
result.clone(digest);
return result;
}
template<>
LLDate AIXMLElementParser::read_string(std::string const& value) const
{
LLDate result;
result.fromString(value);
return result;
}
template<typename T>
T AIXMLElementParser::read_integer(char const* type, std::string const& value) const
{
long long int result;
sscanf(value.c_str(),"%lld", &result);
if (result < (std::numeric_limits<T>::min)() || result > (std::numeric_limits<T>::max)())
{
THROW_MALERT("AIXMLElementParser_read_integer_Invalid_TYPE_VALUE_in_FILEDESC_FILENAME",
AIArgs("[TYPE]", type)("[VALUE]", value)("FILEDESC", mFileDesc)("[FILENAME]", mFilename));
}
return result;
}
template<>
U8 AIXMLElementParser::read_string(std::string const& value) const
{
return read_integer<U8>("U8", value);
}
template<>
S8 AIXMLElementParser::read_string(std::string const& value) const
{
return read_integer<S8>("S8", value);
}
template<>
U16 AIXMLElementParser::read_string(std::string const& value) const
{
return read_integer<U16>("U16", value);
}
template<>
S16 AIXMLElementParser::read_string(std::string const& value) const
{
return read_integer<S16>("S16", value);
}
template<>
U32 AIXMLElementParser::read_string(std::string const& value) const
{
return read_integer<U32>("U32", value);
}
template<>
S32 AIXMLElementParser::read_string(std::string const& value) const
{
return read_integer<S32>("S32", value);
}
double read_float(std::string const& value)
{
double result;
sscanf(value.c_str(),"%lf", &result);
return result;
}
template<>
F32 AIXMLElementParser::read_string(std::string const& value) const
{
return read_float(value);
}
template<>
F64 AIXMLElementParser::read_string(std::string const& value) const
{
return read_float(value);
}
template<>
bool AIXMLElementParser::read_string(std::string const& value) const
{
if (value == "true")
{
return true;
}
else if (value != "false")
{
THROW_MALERT("AIXMLElementParser_read_string_Invalid_boolean_VALUE_in_FILEDESC_FILENAME",
AIArgs("[VALUE]", value)("FILEDESC]", mFileDesc)("[FILENAME]", mFilename));
}
return false;
}
void AIXMLElementParser::attribute(char const* name, char const* required_value) const
{
char const* error = NULL;
AIArgs args;
std::string value;
if (!mNode->getAttributeString(name, value))
{
error = "AIXMLElementParser_attribute_Missing_NAME_attribute_in_NODENAME_of_FILEDESC_FILENAME";
}
else if (value != required_value)
{
error = "AIXMLElementParser_attribute_Invalid_NAME_attribute_should_be_REQUIRED_in_NODENAME_of_FILEDESC_FILENAME";
args("[REQUIRED]", required_value);
}
if (error)
{
THROW_MALERT(error, args("[NAME]", name)("[NODENAME]", node_name())("[FILEDESC]", mFileDesc)("[FILENAME]", mFilename));
}
}
template<>
LLUUID AIXMLElementParser::read_child(LLXmlTreeNode* node) const
{
LLUUID result;
if (!LLUUID::parseUUID(node->getContents(), &result))
{
THROW_MALERT("AIXMLElementParser_read_child_Invalid_uuid_in_FILEDESC_FILENAME",
AIArgs("[FILEDESC]", mFileDesc)("[FILENAME]", mFilename));
}
return result;
}
template<>
LLMD5 AIXMLElementParser::read_child(LLXmlTreeNode* node) const
{
return read_string<LLMD5>(node->getContents());
}
template<>
LLDate AIXMLElementParser::read_child(LLXmlTreeNode* node) const
{
LLDate result;
if (!result.fromString(node->getContents()))
{
THROW_MALERT("AIXMLElementParser_read_child_Invalid_date_DATE_in_FILEDESC_FILENAME",
AIArgs("[DATE]", node->getContents())("[FILEDESC]", mFileDesc)("[FILENAME]", mFilename));
}
return result;
}
template<>
S8 AIXMLElementParser::read_child(LLXmlTreeNode* node) const
{
return read_integer<S8>("S8", node->getContents());
}
template<>
U8 AIXMLElementParser::read_child(LLXmlTreeNode* node) const
{
return read_integer<U8>("U8", node->getContents());
}
template<>
S16 AIXMLElementParser::read_child(LLXmlTreeNode* node) const
{
return read_integer<S16>("S16", node->getContents());
}
template<>
U16 AIXMLElementParser::read_child(LLXmlTreeNode* node) const
{
return read_integer<U16>("U16", node->getContents());
}
template<>
S32 AIXMLElementParser::read_child(LLXmlTreeNode* node) const
{
return read_integer<S32>("S32", node->getContents());
}
template<>
U32 AIXMLElementParser::read_child(LLXmlTreeNode* node) const
{
return read_integer<U32>("U32", node->getContents());
}
template<>
F32 AIXMLElementParser::read_child(LLXmlTreeNode* node) const
{
return read_string<F32>(node->getContents());
}
template<>
F64 AIXMLElementParser::read_child(LLXmlTreeNode* node) const
{
return read_string<F64>(node->getContents());
}
template<>
bool AIXMLElementParser::read_child(LLXmlTreeNode* node) const
{
return read_string<bool>(node->getContents());
}
bool AIXMLElementParser::child(LLUUID& uuid) const
{
return child(DEFAULT_LLUUID_NAME, uuid);
}
bool AIXMLElementParser::child(LLMD5& md5) const
{
return child(DEFAULT_MD5STR_NAME, md5);
}
bool AIXMLElementParser::child(LLDate& date) const
{
return child(DEFAULT_LLDATE_NAME, date);
}

375
indra/llxml/aixml.h Normal file
View File

@@ -0,0 +1,375 @@
/**
* @file aixml.h
* @brief XML serialization support.
*
* 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.
*
* 30/07/2013
* Initial version, written by Aleric Inglewood @ SL
*/
#ifndef AIXML_H
#define AIXML_H
#include "llxmltree.h"
#include "llxmlnode.h"
#include "llfile.h"
#include <sstream>
#include "aialert.h"
extern char const* const DEFAULT_LLUUID_NAME;
extern char const* const DEFAULT_MD5STR_NAME;
extern char const* const DEFAULT_LLDATE_NAME;
class LLUUID;
class LLMD5;
class LLDate;
bool md5strFromXML(LLXmlTreeNode* node, std::string& md5str_out);
bool md5strFromXML(LLXmlTreeNode* node, std::string& md5str_out, std::string const& attribute_name);
bool UUIDFromXML(LLXmlTreeNode* node, LLUUID& uuid_out);
bool UUIDFromXML(LLXmlTreeNode* node, LLUUID& uuid_out, std::string const& attribute_name);
bool dateFromXML(LLXmlTreeNode* node, LLDate& date_out);
bool dateFromXML(LLXmlTreeNode* node, LLDate& date_out, std::string const& attribute_name);
bool versionFromXML(LLXmlTreeNode* node, U32& major_out, U32& minor_out);
bool versionFromXML(LLXmlTreeNode* node, U32& major_out, U32& minor_out, std::string const& attribute_name);
class AIXMLElement
{
private:
std::ostream& mOs;
std::string mName;
int mIndentation;
bool mHasChildren;
public:
AIXMLElement(std::ostream& os, char const* name, int indentation);
~AIXMLElement();
template<typename T>
void attribute(char const* name, T const& attribute);
template<typename T>
void child(T const& element);
template<typename T>
void child(char const* name, T const& element);
template<typename FWD_ITERATOR>
void child(FWD_ITERATOR i1, FWD_ITERATOR const& i2);
private:
template<typename T>
void write_child(char const* name, T const& element);
int open_child(void);
void close_child(void);
};
template<typename T>
void AIXMLElement::attribute(char const* name, T const& attribute)
{
std::ostringstream raw_attribute;
raw_attribute << attribute;
mOs << ' ' << name << "=\"" << LLXMLNode::escapeXML(raw_attribute.str()) << '"';
if (!mOs.good())
{
std::ostringstream ss;
ss << ' ' << name << "=\"" << LLXMLNode::escapeXML(raw_attribute.str()) << '"';
THROW_FALERT("AIXMLElement_attribute_Failed_to_write_DATA", AIArgs("[DATA]", ss.str()));
}
}
template<typename T>
void AIXMLElement::child(T const& element)
{
open_child();
element.toXML(mOs, mIndentation);
if (!mOs.good()) // Normally toXML will already have thrown.
{
THROW_FALERT("AIXMLElement_child_Bad_ostream");
}
close_child();
}
template<>
void AIXMLElement::child(LLUUID const& element);
template<>
void AIXMLElement::child(LLMD5 const& element);
template<>
void AIXMLElement::child(LLDate const& element);
template<typename T>
void AIXMLElement::write_child(char const* name, T const& element)
{
mOs << std::string(mIndentation, ' ') << '<' << name << '>' << element << "</" << name << ">\n";
if (!mOs.good())
{
std::ostringstream ss;
ss << std::string(mIndentation, ' ') << '<' << name << '>' << element << "</" << name << ">\\n";
THROW_FALERT("AIXMLElement_write_child_Failed_to_write_DATA", AIArgs("[DATA]", ss.str()));
}
}
template<typename T>
void AIXMLElement::child(char const* name, T const& element)
{
open_child();
write_child(name, element);
close_child();
}
template<typename FWD_ITERATOR>
void AIXMLElement::child(FWD_ITERATOR i1, FWD_ITERATOR const& i2)
{
while (i1 != i2)
{
child(*i1++);
}
}
// Helper class for AIXMLRootElement.
class AIXMLStream {
protected:
llofstream mOfs;
AIXMLStream(LLFILE* fp, bool standalone);
~AIXMLStream();
};
// Class to write XML files.
class AIXMLRootElement : public AIXMLStream, public AIXMLElement
{
public:
AIXMLRootElement(LLFILE* fp, char const* name, bool standalone = true) : AIXMLStream(fp, standalone), AIXMLElement(mOfs, name, 0) { }
};
class AIXMLElementParser
{
private:
U32 mVersion;
std::string const& mFilename;
std::string const& mFileDesc;
protected:
LLXmlTreeNode* mNode;
protected:
// Used by AIXMLParser, which initializes mNode directly.
AIXMLElementParser(std::string const& filename, std::string const& file_desc, U32 version) : mVersion(version), mFilename(filename), mFileDesc(file_desc) { }
virtual ~AIXMLElementParser() { }
// Used for error reporting.
virtual std::string node_name(void) const { return "node '" + mNode->getName() + "'"; }
// Parse the integer given as string 'value' and return it as type T (U8, S8, U16, S16, U32 or S32).
template<typename T>
T read_integer(char const* type, std::string const& value) const;
// Parse the string 'value' and return it as type T.
template<typename T>
T read_string(std::string const& value) const;
// Parse a child node and return it as type T.
template<typename T>
T read_child(LLXmlTreeNode* node) const;
public:
// Constructor for child member functions.
AIXMLElementParser(std::string const& filename, std::string const& file_desc, U32 version, LLXmlTreeNode* node) : mVersion(version), mFilename(filename), mFileDesc(file_desc), mNode(node) { }
// Require the existence of some attribute with given value.
void attribute(char const* name, char const* required_value) const;
// Read attribute. Returns true if attribute was found.
template<typename T>
bool attribute(char const* name, T& attribute) const;
// Read child element. Returns true if child was found.
template<typename T>
bool child(char const* name, T& child) const;
// Read Linden types. Return true if the child was found.
bool child(LLUUID& uuid) const;
bool child(LLMD5& md5) const;
bool child(LLDate& date) const;
// Append all elements with name 'name' to container.
template<typename CONTAINER>
void push_back_children(char const* name, CONTAINER& container) const;
// Insert all elements with name 'name' into container.
template<typename CONTAINER>
void insert_children(char const* name, CONTAINER& container) const;
// Set version of this particular element (if not set mVersion will be the version of the parent, all the way up to the xml header with a version of 1).
void setVersion(U32 version) { mVersion = version; }
// Accessors.
std::string const& filename(void) const { return mFilename; }
std::string const& filedesc(void) const { return mFileDesc; }
U32 version(void) const { return mVersion; }
};
template<typename T>
inline T AIXMLElementParser::read_string(std::string const& value) const
{
// Construct from string.
return T(value);
}
// Specializations.
template<>
LLMD5 AIXMLElementParser::read_string(std::string const& value) const;
template<>
LLDate AIXMLElementParser::read_string(std::string const& value) const;
template<>
U8 AIXMLElementParser::read_string(std::string const& value) const;
template<>
S8 AIXMLElementParser::read_string(std::string const& value) const;
template<>
U16 AIXMLElementParser::read_string(std::string const& value) const;
template<>
S16 AIXMLElementParser::read_string(std::string const& value) const;
template<>
U32 AIXMLElementParser::read_string(std::string const& value) const;
template<>
S32 AIXMLElementParser::read_string(std::string const& value) const;
template<>
F32 AIXMLElementParser::read_string(std::string const& value) const;
template<>
F64 AIXMLElementParser::read_string(std::string const& value) const;
template<>
bool AIXMLElementParser::read_string(std::string const& value) const;
template<typename T>
bool AIXMLElementParser::attribute(char const* name, T& attribute) const
{
std::string value;
if (!mNode->getAttributeString(name, value))
{
return false;
}
attribute = read_string<T>(value);
return true;
}
template<typename T>
inline T AIXMLElementParser::read_child(LLXmlTreeNode* node) const
{
return AIXMLElementParser(mFilename, mFileDesc, mVersion, node);
}
// Specializations.
template<>
inline std::string AIXMLElementParser::read_child(LLXmlTreeNode* node) const
{
return node->getContents();
}
template<>
LLMD5 AIXMLElementParser::read_child(LLXmlTreeNode* node) const;
template<>
LLUUID AIXMLElementParser::read_child(LLXmlTreeNode* node) const;
template<>
LLDate AIXMLElementParser::read_child(LLXmlTreeNode* node) const;
template<>
S32 AIXMLElementParser::read_child(LLXmlTreeNode* node) const;
template<>
F32 AIXMLElementParser::read_child(LLXmlTreeNode* node) const;
template<>
bool AIXMLElementParser::read_child(LLXmlTreeNode* node) const;
template<typename T>
bool AIXMLElementParser::child(char const* name, T& child) const
{
LLXmlTreeNode* node = mNode->getChildByName(name);
if (!node)
{
return false;
}
child = read_child<T>(node);
return true;
}
template<typename CONTAINER>
void AIXMLElementParser::insert_children(char const* name, CONTAINER& container) const
{
for (LLXmlTreeNode* node = mNode->getFirstChild(); node; node = mNode->getNextChild())
{
if (!node->hasName(name))
continue;
container.insert(read_child<typename CONTAINER::value_type>(node));
}
}
template<typename CONTAINER>
void AIXMLElementParser::push_back_children(char const* name, CONTAINER& container) const
{
for (LLXmlTreeNode* node = mNode->getFirstChild(); node; node = mNode->getNextChild())
{
if (!node->hasName(name))
continue;
container.push_back(read_child<typename CONTAINER::value_type>(node));
}
}
// Class to read XML files.
class AIXMLParser : public AIXMLElementParser
{
private:
std::string mFilename;
std::string mFileDesc;
LLXmlTree mXmlTree;
U32 mVersionMajor;
U32 mVersionMinor;
public:
AIXMLParser(std::string const& filename, char const* file_desc, std::string const& name, U32 major_version);
U32 version_major(void) const { return mVersionMajor; }
U32 version_minor(void) const { return mVersionMinor; }
protected:
/*virtual*/ std::string node_name(void) const { return "root node"; }
};
#endif // AIXML_H

View File

@@ -555,6 +555,36 @@ void XMLCALL EndXMLNode(void *userData,
node->setValue(value);
}
}
// Singu note: moved here from XMLData.
if (LLXMLNode::sStripEscapedStrings)
{
std::string value = node->getValue();
int len = value.length();
if (len > 1 && value[0] == '"' && value[len - 1] == '"')
{
// Special-case: Escaped string.
std::string unescaped_string;
for (S32 pos = 1; pos < len - 1; ++pos)
{
if (value[pos] == '\\' && value[pos + 1] == '\\')
{
unescaped_string += '\\';
++pos;
}
else if (value[pos] == '\\' && value[pos + 1] == '"')
{
unescaped_string += '"';
++pos;
}
else
{
unescaped_string += value[pos];
}
}
value += unescaped_string;
node->setValue(value);
}
}
}
void XMLCALL XMLData(void *userData,
@@ -563,6 +593,15 @@ void XMLCALL XMLData(void *userData,
{
LLXMLNode* current_node = (LLXMLNode *)userData;
std::string value = current_node->getValue();
#if 0
// Apparently also Lindens who write XML parsers can't read documentation.
// "A single block of contiguous text free of markup may still result in a sequence
// of calls to this handler. In other words, if you're searching for a pattern in
// the text, it may be split across calls to this handler."
// (http://sepp.oetiker.ch/expat-1.95.6-rs.SEPP/expat-1.95.6/doc/reference.html#XML_SetCharacterDataHandler)
//
// In other words, this is not guaranteed to work at all -- Aleric.
if (LLXMLNode::sStripEscapedStrings)
{
if (s[0] == '\"' && s[len-1] == '\"')
@@ -591,6 +630,7 @@ void XMLCALL XMLData(void *userData,
return;
}
}
#endif
value.append(std::string(s, len));
current_node->setValue(value);
}
@@ -928,12 +968,6 @@ bool LLXMLNode::getLayeredXMLNode(LLXMLNodePtr& root,
return true;
}
// static
void LLXMLNode::writeHeaderToFile(LLFILE *out_file)
{
fprintf(out_file, "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\" ?>\n");
}
void LLXMLNode::writeToFile(LLFILE *out_file, const std::string& indent, bool use_type_decorations)
{
if (isFullyDefault())

View File

@@ -157,11 +157,6 @@ public:
static bool getLayeredXMLNode(LLXMLNodePtr& root, const std::vector<std::string>& paths);
// Write standard XML file header:
// <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
static void writeHeaderToFile(LLFILE *out_file);
// Write XML to file with one attribute per line.
// XML escapes values as they are written.
void writeToFile(LLFILE *out_file, const std::string& indent = std::string(), bool use_type_decorations=true);

View File

@@ -38,6 +38,7 @@ include(LLXML)
#include(LScript)
include(Linking)
include(NDOF)
include(NVAPI)
include(StateMachine)
include(TemplateCheck)
include(UI)
@@ -47,6 +48,8 @@ include(LLAppearance)
if (WINDOWS)
include(CopyWinLibs)
set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP)
include(InstallRequiredSystemLibraries)
endif (WINDOWS)
include_directories(
@@ -80,6 +83,7 @@ include_directories(
set(viewer_SOURCE_FILES
NACLantispam.cpp
aihttpview.cpp
aixmllindengenepool.cpp
aoremotectrl.cpp
ascentfloatercontactgroups.cpp
ascentkeyword.cpp
@@ -597,6 +601,7 @@ set(viewer_HEADER_FILES
NACLantispam.h
aihttpview.h
aixmllindengenepool.h
aoremotectrl.h
ascentfloatercontactgroups.h
ascentkeyword.h
@@ -1429,21 +1434,11 @@ if (!DISABLE_TEMPLATE_CHECK)
check_message_template(${VIEWER_BINARY_NAME})
endif (!DISABLE_TEMPLATE_CHECK)
# We package by default on Linux so we can run from newview/packaged.
if (LINUX)
set(PACKAGE_DEFAULT ON)
else (LINUX)
set(PACKAGE_DEFAULT OFF)
endif (LINUX)
set(PACKAGE ${PACKAGE_DEFAULT} CACHE BOOL
set(PACKAGE OFF CACHE BOOL
"Add a package target that builds an installer package.")
if (WINDOWS)
if(MSVC10)
set(release_flags "/MAPRelease/${VIEWER_BINARY_NAME}.map")
else(MSVC10)
set(release_flags "/MAP:Release/${VIEWER_BINARY_NAME}.map")
endif(MSVC10)
set(release_flags "/MAPRelease/${VIEWER_BINARY_NAME}.map")
if (FMOD)
if(MANIFEST_LIBRARIES)
@@ -1453,12 +1448,18 @@ if (WINDOWS)
endif(MANIFEST_LIBRARIES)
endif (FMOD)
if (FMODEX)
if (WORD_SIZE EQUAL 32)
set(fmodex_dll_file "fmodex.dll")
else (WORD_SIZE EQUAL 32)
set(fmodex_dll_file "fmodex64.dll")
endif (WORD_SIZE EQUAL 32)
if(MANIFEST_LIBRARIES)
set(MANIFEST_LIBRARIES "${MANIFEST_LIBRARIES}|${FMODEX_BINARY_DIR}/fmodex.dll")
set(MANIFEST_LIBRARIES "${MANIFEST_LIBRARIES}|${FMODEX_BINARY_DIR}/${fmodex_dll_file}")
else(MANIFEST_LIBRARIES)
set(MANIFEST_LIBRARIES "--extra_libraries=${FMODEX_BINARY_DIR}/fmodex.dll")
set(MANIFEST_LIBRARIES "--extra_libraries=${FMODEX_BINARY_DIR}/${fmodex_dll_file}")
endif(MANIFEST_LIBRARIES)
set(EXTRA_LINKER_FLAGS "/DELAYLOAD:fmodex.dll")
set(EXTRA_LINKER_FLAGS "/DELAYLOAD:${fmodex_dll_file}")
endif (FMODEX)
set_target_properties(${VIEWER_BINARY_NAME}
@@ -1516,6 +1517,7 @@ if (WINDOWS)
COMMAND ${PYTHON_EXECUTABLE}
ARGS
${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
--arch=${ARCH}
--artwork=${ARTWORK_DIR}
--branding_id=${VIEWER_BRANDING_ID}
--build=${CMAKE_CURRENT_BINARY_DIR}
@@ -1537,6 +1539,7 @@ if (WINDOWS)
COMMAND ${PYTHON_EXECUTABLE}
ARGS
${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
--arch=${ARCH}
--artwork=${ARTWORK_DIR}
--actions=copy
--branding_id=${VIEWER_BRANDING_ID}
@@ -1590,6 +1593,7 @@ target_link_libraries(${VIEWER_BINARY_NAME}
${LLMATH_LIBRARIES}
${LLCOMMON_LIBRARIES}
${NDOF_LIBRARY}
${NVAPI_LIBRARY}
${viewer_LIBRARIES}
${Boost_CONTEXT_LIBRARY}
${Boost_FILESYSTEM_LIBRARY}
@@ -1857,6 +1861,21 @@ endif (LL_TESTS)
# Don't do these for DARWIN or LINUX here -- they're taken care of by viewer_manifest.py
if (WINDOWS)
IF(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS)
FOREACH(RUNTIME_LIB ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS})
add_custom_command(
TARGET ${VIEWER_BINARY_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND}
ARGS
-E
copy_if_different
${RUNTIME_LIB}
${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Copying ${RUNTIME_LIB} to the runtime folder."
)
ENDFOREACH(RUNTIME_LIB ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS})
ENDIF(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS)
get_target_property(BUILT_LLCOMMON llcommon LOCATION)
set_target_properties(llcommon
@@ -1912,7 +1931,7 @@ if (WINDOWS)
COMMENT "Copying Quicktime Plugin to the runtime folder."
)
get_target_property(BUILT_FILEPICKER_PLUGIN basic_plugin_filepicker LOCATION)
get_target_property(BUILT_FILEPICKER_PLUGIN basic_plugin_filepicker LOCATION)
add_custom_command(
TARGET ${VIEWER_BINARY_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND}
@@ -1924,7 +1943,9 @@ if (WINDOWS)
COMMENT "Copying filepicker Plugin to the runtime folder."
)
get_target_property(BUILT_WINMM_SHIM_PLUGIN winmm_shim LOCATION)
# winmm doesn't build on windows 64
if(WORD_SIZE EQUAL 32)
get_target_property(BUILT_WINMM_SHIM_PLUGIN winmm_shim LOCATION)
add_custom_command(
TARGET ${VIEWER_BINARY_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND}
@@ -1935,6 +1956,8 @@ if (WINDOWS)
${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}
COMMENT "Copying winmm.dll to the runtime folder."
)
endif(WORD_SIZE EQUAL 32)
# Copying the mime_types.xml file to app_settings
set(mime_types_source "${CMAKE_SOURCE_DIR}/newview/skins/default/xui/en-us")
set(mime_types_dest "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/app_settings")

View File

@@ -0,0 +1,205 @@
/**
* @file aixmllindengenepool.cpp
* @brief XML linden_genepool serialization support.
*
* 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.
*
* 01/11/2013
* Initial version, written by Aleric Inglewood @ SL
*/
// metaversion 1.0
// ===============
//
// Added as child of <linden_genepool>:
//
// <meta gridnick="secondlife" date="2013-07-16T16:49:00.40Z" />
//
// Optionally, as child of <archetype>, the following node may appear:
//
// <meta path="clothing/jackets" name="Purple jacket" description="A jacket with mainly the color purple" />
//
// Furthermore, metaversion 1.0 and higher allow the occurance of one or more <archetype> blocks.
// If this is used then it is strongly advised to use one <archetype> per wearable, so that
// the the <meta> node makes sense (it then refers to the wearable of that <archetype>).
//
// The reason for this clumsy way to link wearable to extra meta data is to stay
// compatible with the older format (no metaversion).
#include "llviewerprecompiledheaders.h"
#include "aixmllindengenepool.h"
#include "hippogridmanager.h"
#include "llvisualparam.h"
#include "llviewerwearable.h"
#include "llquantize.h"
extern void append_path_short(LLUUID const& id, std::string& path);
void AIXMLLindenGenepool::MetaData::toXML(std::ostream& os, int indentation) const
{
AIXMLElement tag(os, "meta", indentation);
tag.attribute("gridnick", mGridNick);
tag.attribute(DEFAULT_LLDATE_NAME, mDate);
}
AIXMLLindenGenepool::MetaData::MetaData(AIXMLElementParser const& parser)
{
parser.attribute("gridnick", mGridNick);
parser.attribute(DEFAULT_LLDATE_NAME, mDate);
}
AIXMLLindenGenepool::AIXMLLindenGenepool(LLFILE* fp) : AIXMLRootElement(fp, "linden_genepool")
{
attribute("version", "1.0");
attribute("metaversion", "1.0");
child(MetaData(gHippoGridManager->getConnectedGrid()->getGridNick(), LLDate::now()));
}
void AIVisualParamIDValuePair::toXML(std::ostream& os, int indentation) const
{
LLVisualParam const* visual_param = mVisualParam;
if (!visual_param && mWearable)
{
visual_param = mWearable->getVisualParam(mID);
}
if (visual_param)
{
AIXMLElement tag(os, "param", indentation);
tag.attribute("id", mID);
tag.attribute("name", visual_param->getName());
tag.attribute("value", mValue);
tag.attribute("u8", (U32)F32_to_U8(mValue, visual_param->getMinWeight(), visual_param->getMaxWeight()));
tag.attribute("type", visual_param->getTypeString());
tag.attribute("wearable", visual_param->getDumpWearableTypeName());
}
}
AIVisualParamIDValuePair::AIVisualParamIDValuePair(AIXMLElementParser const& parser)
{
// Only id and value are relevant. Ignore all other attributes.
parser.attribute("id", mID);
parser.attribute("value", mValue);
}
void AITextureIDUUIDPair::toXML(std::ostream& os, int indentation) const
{
AIXMLElement tag(os, "texture", indentation);
tag.attribute("te", mID);
tag.attribute(DEFAULT_LLUUID_NAME, mUUID);
}
AITextureIDUUIDPair::AITextureIDUUIDPair(AIXMLElementParser const& parser)
{
parser.attribute("te", mID);
parser.attribute(DEFAULT_LLUUID_NAME, mUUID);
}
void AIArchetype::MetaData::toXML(std::ostream& os, int indentation) const
{
AIXMLElement tag(os, "meta", indentation);
tag.attribute("path", mPath);
tag.attribute("name", mName);
tag.attribute("description", mDescription);
}
AIArchetype::MetaData::MetaData(AIXMLElementParser const& parser)
{
char const* missing = NULL;
if (!parser.attribute("path", mPath))
{
missing = "path";
}
if (!parser.attribute("name", mName))
{
missing = "name";
}
if (!parser.attribute("description", mDescription))
{
missing = "description";
}
if (missing)
{
THROW_ALERT("AIArchetype_MetaData_archetype_meta_has_no_ATTRIBUTE", AIArgs("[ATTRIBUTE]", missing));
}
}
AIArchetype::MetaData::MetaData(LLViewerWearable const* wearable) : mName(wearable->getName()), mDescription(wearable->getDescription())
{
append_path_short(wearable->getItemID(), mPath);
}
AIArchetype::AIArchetype(void) : mType(LLWearableType::WT_NONE)
{
}
AIArchetype::AIArchetype(LLWearableType::EType type) : mType(type)
{
}
AIArchetype::AIArchetype(LLViewerWearable const* wearable) : mType(wearable->getType()), mMetaData(wearable)
{
}
void AIArchetype::toXML(std::ostream& os, int indentation) const
{
AIXMLElement tag(os, "archetype", indentation);
if (mType == LLWearableType::WT_NONE)
{
tag.attribute("name", "???");
}
else
{
tag.attribute("name", LLWearableType::getTypeName(mType));
}
if (!mMetaData.mPath.empty())
{
tag.child(mMetaData);
}
tag.child(mParams.begin(), mParams.end());
tag.child(mTextures.begin(), mTextures.end());
}
AIArchetype::AIArchetype(AIXMLElementParser const& parser)
{
std::string name;
mType = LLWearableType::WT_NONE;
if (!parser.attribute("name", name))
{
llwarns << "The <archetype> tag in file \"" << parser.filename() << "\" is missing the 'name' parameter." << llendl;
}
else if (name != "???")
{
mType = LLWearableType::typeNameToType(name);
}
if (parser.version() >= 1)
{
if (!parser.child("meta", mMetaData))
{
THROW_ALERT("AIArchetype_archetype_has_no_meta");
}
}
parser.push_back_children("param", mParams);
parser.push_back_children("texture", mTextures);
}

View File

@@ -0,0 +1,150 @@
/**
* @file aixmllindengenepool.h
* @brief XML linden_genepool serialization support.
*
* 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.
*
* 01/11/2013
* Initial version, written by Aleric Inglewood @ SL
*/
#ifndef AIXMLLINDENGENEPOOL_H
#define AIXMLLINDENGENEPOOL_H
#include "aixml.h"
#include "llwearabletype.h"
#include "llviewervisualparam.h"
#include <vector>
class LLViewerWearable;
class AIXMLLindenGenepool : public AIXMLRootElement
{
public:
struct MetaData
{
std::string mGridNick;
LLDate mDate;
MetaData(void) { }
MetaData(std::string const& grid_nick, LLDate const& date) : mGridNick(grid_nick), mDate(date) { }
void toXML(std::ostream& os, int indentation) const;
MetaData(AIXMLElementParser const& parser);
};
AIXMLLindenGenepool(LLFILE* fp);
};
class AIVisualParamIDValuePair
{
private:
// A wearable + ID define the LLVisualParam, but it also possible to specify the LLVisualParam directly.
LLVisualParam const* mVisualParam; // Specific LLVisualParam, given at construction, or ...
LLViewerWearable const* mWearable; // Underlaying wearable, if any.
U32 mID; // The visual parameter id.
F32 mValue; // The value of the visual parameter.
public:
AIVisualParamIDValuePair(LLVisualParam const* visual_param) :
mVisualParam(visual_param), mWearable(NULL), mID(visual_param->getID()), mValue(visual_param->getWeight()) { }
AIVisualParamIDValuePair(LLVisualParam const* visual_param, F32 value) :
mVisualParam(visual_param), mWearable(NULL), mID(visual_param->getID()), mValue(value) { }
AIVisualParamIDValuePair(LLViewerWearable const* wearable, U32 id, F32 value) :
mVisualParam(NULL), mWearable(wearable), mID(id), mValue(value) { }
void toXML(std::ostream& os, int indentation) const;
AIVisualParamIDValuePair(AIXMLElementParser const& parser);
// Accessors.
U32 getID(void) const { return mID; }
F32 getValue(void) const { return mValue; }
};
class AITextureIDUUIDPair
{
private:
U32 mID;
LLUUID mUUID;
public:
AITextureIDUUIDPair(U32 id, LLUUID const& uuid) : mID(id), mUUID(uuid) { }
void toXML(std::ostream& os, int indentation) const;
AITextureIDUUIDPair(AIXMLElementParser const& parser);
// Accessors.
U32 getID(void) const { return mID; }
LLUUID const& getUUID(void) const { return mUUID; }
};
class AIArchetype
{
public:
struct MetaData
{
std::string mPath; // The wearable location in the inventory.
std::string mName; // The wearable name.
std::string mDescription; // The wearable description.
MetaData(void) { }
MetaData(LLViewerWearable const* wearable);
void toXML(std::ostream& os, int indentation) const;
MetaData(AIXMLElementParser const& parser);
};
typedef std::vector<AIVisualParamIDValuePair> params_type;
typedef std::vector<AITextureIDUUIDPair> textures_type;
private:
LLWearableType::EType mType; // The type of the wearable.
MetaData mMetaData;
params_type mParams;
textures_type mTextures;
public:
// Accessors.
LLWearableType::EType getType(void) const { return mType; }
MetaData const& getMetaData(void) const { return mMetaData; }
params_type const& getParams(void) const { return mParams; }
textures_type const& getTextures(void) const { return mTextures; }
public:
// An archtype without wearable has no (known) metadata. This is recognized because mPath will be empty.
// An archtype without type with get the attribute name="???".
AIArchetype(void); // <archetype name="???">
AIArchetype(LLWearableType::EType type); // <archetype name="shirt">
AIArchetype(LLViewerWearable const* wearable); // <archetype name="shirt"> <meta path="myclothes" name="blue shirt" description="Awesome blue shirt">
void add(AIVisualParamIDValuePair const& visual_param_id_value_pair) { mParams.push_back(visual_param_id_value_pair); }
void add(AITextureIDUUIDPair const& texture_id_uuid_pair) { mTextures.push_back(texture_id_uuid_pair); }
void toXML(std::ostream& os, int indentation) const;
AIArchetype(AIXMLElementParser const& parser);
};
#endif // AIXMLLINDENGENEPOOL_H

View File

@@ -40,7 +40,7 @@
</array>
<key>tags</key>
<array>
<string>ShaderLoading</string>
<!--string>ShaderLoading</string-->
<string>Openjpeg</string>
<!-- Debug output about messages received from plugins: -->
<string>Plugin</string> <!-- Everything except what is listed below -->

View File

@@ -8,7 +8,17 @@
<string>settings_sh.xml</string>
<string>settings_rlv.xml</string>
</array>
<key>SinguOffsetScrollKeys</key>
<map>
<key>Comment</key>
<string>Enable keys to modify camera and focus offsets</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>PhoenixIMAnnounceStealFocus</key>
<map>
<key>Comment</key>
@@ -210,17 +220,6 @@
<integer>100</integer>
</map>
<key>zmm_deffov</key>
<map>
<key>Comment</key>
<string>Default field of viewer for right click mouse zoom.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>1.0</real>
</map>
<key>zmm_mlfov</key>
<map>
<key>Comment</key>
@@ -232,28 +231,6 @@
<key>Value</key>
<real>1</real>
</map>
<key>zmm_isinml</key>
<map>
<key>Comment</key>
<string>mouselook</string>
<key>Persist</key>
<integer>0</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>zmm_rightmousedown</key>
<map>
<key>Comment</key>
<string>insert rude comment here</string>
<key>Persist</key>
<integer>0</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>AllowLargeSounds</key>
<map>
@@ -786,6 +763,17 @@
<key>Value</key>
<integer>0</integer>
</map>
<key>LiruMouselookMenu</key>
<map>
<key>Comment</key>
<string>Controls if holding Alt and right clicking in mouselook will bring up a menu</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<boolean>1</boolean>
</map>
<key>LiruNewARCLimit</key>
<map>
<key>Comment</key>
@@ -868,6 +856,17 @@ Found in Advanced->Rendering->Info Displays</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>LiruUseContextMenus</key>
<map>
<key>Comment</key>
<string>Use context menus instead of the default pie menus we all know and love.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<boolean>0</boolean>
</map>
<key>SLBShowFPS</key>
<map>
<key>Comment</key>
@@ -936,6 +935,17 @@ Found in Advanced->Rendering->Info Displays</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>FSSynchronizeTextureMaps</key>
<map>
<key>Comment</key>
<string>Align texture maps (texture, bumpy, shiny) across the faces of a prim</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<boolean>1</boolean>
</map>
<key>InstantMessageLogPathAnyAccount</key>
<map>
<key>Comment</key>
@@ -5703,6 +5713,39 @@ This should be as low as possible, but too low may break functionality</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>DefaultBlankNormalTexture</key>
<map>
<key>Comment</key>
<string>Texture used as 'Blank' in texture picker for normal map. (UUID texture reference)</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>String</string>
<key>Value</key>
<string>5b53359e-59dd-d8a2-04c3-9e65134da47a</string>
</map>
<key>DefaultObjectNormalTexture</key>
<map>
<key>Comment</key>
<string>Texture used as 'Default' in texture picker for normal map. (UUID texture reference)</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>String</string>
<key>Value</key>
<string>85f28839-7a1c-b4e3-d71d-967792970a7b</string>
</map>
<key>DefaultObjectSpecularTexture</key>
<map>
<key>Comment</key>
<string>Texture used as 'Default' in texture picker for specular map. (UUID texture reference)</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>String</string>
<key>Value</key>
<string>87e0e8f7-8729-1ea8-cfc9-8915773009db</string>
</map>
<key>DefaultObjectTexture</key>
<map>
<key>Comment</key>
@@ -13742,6 +13785,17 @@ This should be as low as possible, but too low may break functionality</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>RevokePermsOnStopAnimation</key>
<map>
<key>Comment</key>
<string>Clear animation permssions when choosing "Stop Animating Me"</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>RotateRight</key>
<map>
<key>Comment</key>
@@ -17735,7 +17789,7 @@ This should be as low as possible, but too low may break functionality</string>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>1</integer>
<integer>0</integer>
</map>
</map>
</llsd>

View File

@@ -277,7 +277,7 @@
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
<integer>0</integer>
</map>
<key>AscentShowOthersTagColor</key>
<map>

View File

@@ -23,7 +23,7 @@
* $/LicenseInfo$
*/
#extension GL_ARB_texture_rectangle : enable
//#extension GL_ARB_texture_rectangle : enable
#define INDEXED 1
#define NON_INDEXED 2

View File

@@ -23,7 +23,7 @@
* $/LicenseInfo$
*/
#extension GL_ARB_texture_rectangle : enable
//#extension GL_ARB_texture_rectangle : enable
#ifdef DEFINE_GL_FRAGCOLOR
out vec4 frag_color;

View File

@@ -23,7 +23,7 @@
* $/LicenseInfo$
*/
#extension GL_ARB_texture_rectangle : enable
//#extension GL_ARB_texture_rectangle : enable
#ifdef DEFINE_GL_FRAGCOLOR
out vec4 frag_color;

View File

@@ -23,7 +23,7 @@
* $/LicenseInfo$
*/
#extension GL_ARB_texture_rectangle : enable
//#extension GL_ARB_texture_rectangle : enable
#ifdef DEFINE_GL_FRAGCOLOR
out vec4 frag_color;

View File

@@ -23,7 +23,7 @@
* $/LicenseInfo$
*/
#extension GL_ARB_texture_rectangle : enable
//#extension GL_ARB_texture_rectangle : enable
#ifdef DEFINE_GL_FRAGCOLOR
out vec4 frag_color;

View File

@@ -23,7 +23,7 @@
* $/LicenseInfo$
*/
#extension GL_ARB_texture_rectangle : enable
//#extension GL_ARB_texture_rectangle : enable
#ifdef DEFINE_GL_FRAGCOLOR
out vec4 frag_color;

View File

@@ -22,8 +22,6 @@
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifdef DEFINE_GL_FRAGCOLOR
out vec4 frag_color;

Some files were not shown because too many files have changed in this diff Show More