diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..baa0af25
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,23 @@
+.vs
+Debug
+Release
+x64
+__pycache__
+*Moc.cpp
+*.dll
+*.lib
+boost/bin.v2
+boost/stage
+boost/b2.exe
+boost/project-config.jam
+boost/tools/build/src/engine/*.obj
+boost/tools/build/src/engine/*.exe
+CodeSubWars/.vs
+CodeSubWars/log
+CodeSubWars/doc/html
+CodeSubWars/records
+CodeSubWars/x64
+CodeSubWars/*.exe
+CodeSubWars/*.exp
+solid-3.5.4/lib
+ARSTD/Lib
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 00000000..0f701d56
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "boost"]
+ path = boost
+ url = https://github.com/boostorg/boost
diff --git a/ARSTD/ARSTD.vcxproj b/ARSTD/ARSTD.vcxproj
new file mode 100644
index 00000000..d731cb92
--- /dev/null
+++ b/ARSTD/ARSTD.vcxproj
@@ -0,0 +1,290 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ {963EE443-32FB-412F-B7D3-38E0053704B1}
+
+
+ MFCProj
+
+
+
+ StaticLibrary
+ v143
+ Dynamic
+
+
+ StaticLibrary
+ v143
+ false
+ Unicode
+
+
+ StaticLibrary
+ v143
+ Dynamic
+ MultiByte
+
+
+ StaticLibrary
+ v143
+ false
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <_ProjectFileVersion>16.0.32002.118
+
+
+ .\Release\
+ .\Release\
+
+
+
+ .\Debug\
+ .\Debug\
+
+
+
+ MaxSpeed
+ AnySuitable
+ Speed
+ false
+ ../boost;../arstd;../arstd/include;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)
+ true
+ MultiThreadedDLL
+ true
+ StreamingSIMDExtensions
+ true
+ .\Release/ARSTD.pch
+ .\Release/
+ .\Release/
+ .\Release/
+ Level3
+ true
+ Default
+
+
+ Lib\ARSTD.lib
+ true
+
+
+ NDEBUG;%(PreprocessorDefinitions)
+ 0x0407
+
+
+
+
+ MaxSpeed
+ AnySuitable
+ Speed
+ false
+ ../boost;../arstd;../arstd/include;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)
+ true
+ MultiThreadedDLL
+ true
+ StreamingSIMDExtensions
+ true
+ .\Release/ARSTD.pch
+ .\Release/
+ .\Release/
+ .\Release/
+ Level3
+ true
+ Default
+
+
+ Lib\ARSTD.lib
+ true
+
+
+ NDEBUG;%(PreprocessorDefinitions)
+ 0x0407
+
+
+
+
+ Disabled
+ ../boost;../arstd;../arstd/include;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)
+ EnableFastChecks
+ MultiThreadedDebugDLL
+ true
+ .\Debug/ARSTD.pch
+ .\Debug/
+ .\Debug/
+ .\Debug/
+ Level3
+ true
+ EditAndContinue
+ Default
+
+
+ Lib\ARSTDD.lib
+ true
+
+
+ _DEBUG;%(PreprocessorDefinitions)
+ 0x0407
+
+
+
+
+ Disabled
+ ../boost;../arstd;../arstd/include;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)
+ EnableFastChecks
+ MultiThreadedDebugDLL
+ true
+ .\Debug/ARSTD.pch
+ .\Debug/
+ .\Debug/
+ .\Debug/
+ Level3
+ true
+ ProgramDatabase
+ Default
+
+
+ Lib\ARSTDD.lib
+ true
+
+
+ _DEBUG;%(PreprocessorDefinitions)
+ 0x0407
+
+
+
+
+
+ Disabled
+ Disabled
+ EnableFastChecks
+ EnableFastChecks
+ MaxSpeed
+ MaxSpeed
+
+
+
+ Disabled
+ Disabled
+ EnableFastChecks
+ EnableFastChecks
+ MaxSpeed
+ MaxSpeed
+
+
+
+
+
+ Disabled
+ Disabled
+ EnableFastChecks
+ EnableFastChecks
+ MaxSpeed
+ MaxSpeed
+
+
+
+ Disabled
+ Disabled
+ EnableFastChecks
+ EnableFastChecks
+ MaxSpeed
+ MaxSpeed
+
+
+ Disabled
+ Disabled
+ EnableFastChecks
+ EnableFastChecks
+ MaxSpeed
+ MaxSpeed
+
+
+ Disabled
+ Disabled
+ EnableFastChecks
+ EnableFastChecks
+ MaxSpeed
+ MaxSpeed
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ARSTD/ARSTD.vcxproj.filters b/ARSTD/ARSTD.vcxproj.filters
new file mode 100644
index 00000000..a149082c
--- /dev/null
+++ b/ARSTD/ARSTD.vcxproj.filters
@@ -0,0 +1,185 @@
+
+
+
+
+ {4009fbd6-0269-4a00-886a-dd330da8daeb}
+ *.h,*.cpp
+
+
+ {9bd08d33-a63d-4f90-a0c8-9806acbf90d5}
+ *.h,*.cpp
+
+
+ {05b62ac4-3f93-47c4-af49-14f66a29db95}
+
+
+ {18656066-59f1-428a-b604-3f93d0a98427}
+
+
+ {ef8242ee-cb48-4905-9dbe-05d5652f92ea}
+
+
+ {3309d5c7-84ab-43b2-abc6-99a8eac7b9d0}
+
+
+ {317120b1-d591-48f0-803b-c1ac669a3a54}
+
+
+ {f5c53ba2-79c2-46d5-9a9f-eb546d4d418a}
+
+
+
+
+ Structures
+
+
+ Structures
+
+
+ Misc
+
+
+ Misc
+
+
+ Misc
+
+
+ Command
+
+
+ Command
+
+
+ Command
+
+
+ Command
+
+
+ OpenGL
+
+
+ Geometry
+
+
+ Math
+
+
+
+
+ Structures
+
+
+ Structures
+
+
+ Misc
+
+
+ Misc
+
+
+ Misc
+
+
+ Misc
+
+
+ Command
+
+
+ Command
+
+
+ Command
+
+
+ Command
+
+
+ Command
+
+
+ Command
+
+
+ Message
+
+
+ OpenGL
+
+
+ Common
+
+
+ Common
+
+
+ Geometry
+
+
+ Geometry
+
+
+ Geometry
+
+
+ Geometry
+
+
+ Geometry
+
+
+ Geometry
+
+
+ Geometry
+
+
+ Geometry
+
+
+ Math
+
+
+ Math
+
+
+ Math
+
+
+ Math
+
+
+ Math
+
+
+ Math
+
+
+ Math
+
+
+ Math
+
+
+ Math
+
+
+ Math
+
+
+ Math
+
+
+ Math
+
+
+ Math
+
+
+ Math
+
+
+
\ No newline at end of file
diff --git a/ARSTD/ARSTD.vcxproj.user b/ARSTD/ARSTD.vcxproj.user
new file mode 100644
index 00000000..88a55094
--- /dev/null
+++ b/ARSTD/ARSTD.vcxproj.user
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/ARSTD/ARSTD/Command/BasicCommands.cpp b/ARSTD/ARSTD/Command/BasicCommands.cpp
new file mode 100644
index 00000000..ed2a3bfb
--- /dev/null
+++ b/ARSTD/ARSTD/Command/BasicCommands.cpp
@@ -0,0 +1,304 @@
+// Copyright (c) 2005-2022 Andreas Rose. All rights reserved.
+// Released under the MIT license. (see license.txt)
+
+
+#include
+#include "BasicCommands.h"
+#include "CommandProcessor.h"
+
+
+namespace ARSTD
+{
+
+ RepeatCommand::PtrType RepeatCommand::create(int nCycles)
+ {
+ return PtrType(new RepeatCommand(nCycles));
+ }
+
+
+ RepeatCommand::~RepeatCommand()
+ {
+ }
+
+
+ ARSTD::Command::PtrType RepeatCommand::copy() const
+ {
+ return PtrType(new RepeatCommand(*this));
+ }
+
+
+ void RepeatCommand::initialize()
+ {
+ }
+
+
+ void RepeatCommand::step()
+ {
+ bool bRepeatSuccessful = false;
+ if (m_nCurrentCycles != 0)
+ {
+ getCommandProcessor()->repeat();
+ bRepeatSuccessful = true;
+
+ if (m_nCurrentCycles > 0)
+ --m_nCurrentCycles;
+ }
+
+ if (m_nCycles < 0)
+ setProgress(0.5);
+ else
+ setProgress(static_cast(m_nCycles - m_nCurrentCycles)/m_nCycles);
+
+ //only if the repeating could not be "started" the command must finished directly otherwise this will done automaticaly
+ //by the repeat method call
+ if (!bRepeatSuccessful)
+ {
+ m_nCurrentCycles = m_nCycles;
+ getCommandProcessor()->finished();
+ }
+ }
+
+
+ void RepeatCommand::cleanup()
+ {
+ }
+
+
+ uint64 RepeatCommand::getRessourceID() const
+ {
+ return 0;
+ }
+
+
+ std::string RepeatCommand::getName() const
+ {
+ return "Repeat";
+ }
+
+
+ std::string RepeatCommand::getDetails() const
+ {
+ std::stringstream ss;
+ ss << "Repeats previous commands: cycle " << m_nCurrentCycles << " of " << m_nCycles;
+ return ss.str();
+ }
+
+
+ RepeatCommand::RepeatCommand(int nCycles)
+ : m_nCycles(nCycles)
+ {
+ if (m_nCycles < 0)
+ m_nCycles = -1;
+ m_nCurrentCycles = m_nCycles;
+ }
+
+
+ RepeatCommand::RepeatCommand(const RepeatCommand& other)
+ : ARSTD::Command(other),
+ m_nCycles(other.m_nCycles),
+ m_nCurrentCycles(other.m_nCurrentCycles)
+ {
+ }
+
+
+
+
+
+ PushCommand::PtrType PushCommand::create()
+ {
+ return PtrType(new PushCommand());
+ }
+
+
+ PushCommand::~PushCommand()
+ {
+ }
+
+
+ ARSTD::Command::PtrType PushCommand::copy() const
+ {
+ return PtrType(new PushCommand(*this));
+ }
+
+
+ void PushCommand::initialize()
+ {
+ }
+
+
+ void PushCommand::step()
+ {
+ getCommandProcessor()->push();
+ setProgress(1);
+ getCommandProcessor()->finished();
+ }
+
+
+ void PushCommand::cleanup()
+ {
+ }
+
+
+ uint64 PushCommand::getRessourceID() const
+ {
+ return 0;
+ }
+
+
+ std::string PushCommand::getName() const
+ {
+ return "Push";
+ }
+
+
+ std::string PushCommand::getDetails() const
+ {
+ return "Pushs the current command processor context to a stack";
+ }
+
+
+ PushCommand::PushCommand()
+ {
+ }
+
+
+ PushCommand::PushCommand(const PushCommand& other)
+ : ARSTD::Command(other)
+ {
+ }
+
+
+
+
+
+ PopCommand::PtrType PopCommand::create()
+ {
+ return PtrType(new PopCommand());
+ }
+
+
+ PopCommand::~PopCommand()
+ {
+ }
+
+
+ ARSTD::Command::PtrType PopCommand::copy() const
+ {
+ return PtrType(new PopCommand(*this));
+ }
+
+
+ void PopCommand::initialize()
+ {
+ }
+
+
+ void PopCommand::step()
+ {
+ setProgress(1);
+ if (!getCommandProcessor()->pop())
+ getCommandProcessor()->finished();
+ }
+
+
+ void PopCommand::cleanup()
+ {
+ }
+
+
+ uint64 PopCommand::getRessourceID() const
+ {
+ return 0;
+ }
+
+
+ std::string PopCommand::getName() const
+ {
+ return "Pop";
+ }
+
+
+ std::string PopCommand::getDetails() const
+ {
+ return "Pops the command processor context from a stack and make it current";
+ }
+
+
+ PopCommand::PopCommand()
+ {
+ }
+
+
+ PopCommand::PopCommand(const PopCommand& other)
+ : ARSTD::Command(other)
+ {
+ }
+
+
+
+
+
+ CleanupHistoryCommand::PtrType CleanupHistoryCommand::create()
+ {
+ return PtrType(new CleanupHistoryCommand());
+ }
+
+
+ CleanupHistoryCommand::~CleanupHistoryCommand()
+ {
+ }
+
+
+ ARSTD::Command::PtrType CleanupHistoryCommand::copy() const
+ {
+ return PtrType(new CleanupHistoryCommand(*this));
+ }
+
+
+ void CleanupHistoryCommand::initialize()
+ {
+ }
+
+
+ void CleanupHistoryCommand::step()
+ {
+ getCommandProcessor()->cleanupHistory();
+ setProgress(1);
+ getCommandProcessor()->finished();
+ }
+
+
+ void CleanupHistoryCommand::cleanup()
+ {
+ }
+
+
+ uint64 CleanupHistoryCommand::getRessourceID() const
+ {
+ return 0;
+ }
+
+
+ std::string CleanupHistoryCommand::getName() const
+ {
+ return "CleanupHistory";
+ }
+
+
+ std::string CleanupHistoryCommand::getDetails() const
+ {
+ return "Cleans up the history of the command processor context";
+ }
+
+
+ CleanupHistoryCommand::CleanupHistoryCommand()
+ {
+ }
+
+
+ CleanupHistoryCommand::CleanupHistoryCommand(const CleanupHistoryCommand& other)
+ : ARSTD::Command(other)
+ {
+ }
+
+} //namespace ARSTD
diff --git a/ARSTD/ARSTD/Command/BasicCommands.h b/ARSTD/ARSTD/Command/BasicCommands.h
new file mode 100644
index 00000000..2f0d8858
--- /dev/null
+++ b/ARSTD/ARSTD/Command/BasicCommands.h
@@ -0,0 +1,166 @@
+// Copyright (c) 2005-2022 Andreas Rose. All rights reserved.
+// Released under the MIT license. (see license.txt)
+
+
+#pragma once
+
+#include
+#include "Command.h"
+
+
+namespace ARSTD
+{
+
+ /**
+ * This command makes commands executing again until the given number of cycles is reached.
+ * Its behavior is depend on how the command is executed.\n
+ * 1. The command is executed directly by the command processor: All previously _executed_ commands
+ * are executed again.\n
+ * 2. The command is part of macro command: All previously _attached_ commands are executed again.
+ * That means the repeat command attached to a macro command repeats only commands of this command
+ * also if this macro is attached to another macro.\n
+ *
+ * Example: two loops in one command plus a seperate repeat. 2 times 2 times 2 (8) torpedos with
+ * litte pauses are fired. (in python)
+ \code
+ * innerLoop = MacroCommand.create('InnerLoop')
+ * innerLoop.attach(CSWFireCommand.create(self.getFrontLeftWeaponBattery(), None))
+ * innerLoop.attach(CSWWaitCommand.create(2.5))
+ * innerLoop.attach(RepeatCommand.create(1))
+ *
+ * outerLoop = MacroCommand.create('OuterLoop')
+ * outerLoop.attach(CSWWaitCommand.create(5))
+ * outerLoop.attach(innerLoop)
+ * outerLoop.attach(RepeatCommand.create(1))
+ *
+ * self.getCommandProcessor().execute(outerLoop)
+ * self.getCommandProcessor().execute(RepeatCommand.create(1))
+ \endcode
+ */
+ class RepeatCommand : public Command
+ {
+ public:
+ typedef std::shared_ptr PtrType;
+
+ /**
+ * Creates a new repeat command.
+ * @param nCycles The number of cycles that all previous commands should repeat. If a negativ value is given
+ * the repeating does not terminate automatically.
+ * @return Returns the new constructed command.
+ */
+ static PtrType create(int nCycles = -1);
+
+ virtual ~RepeatCommand();
+
+ virtual ARSTD::Command::PtrType copy() const;
+ virtual void initialize();
+ virtual void step();
+ virtual void cleanup();
+ virtual uint64 getRessourceID() const;
+ virtual std::string getName() const;
+ virtual std::string getDetails() const;
+
+ protected:
+ RepeatCommand(int nCycles);
+ RepeatCommand(const RepeatCommand& other);
+
+ int m_nCycles;
+ int m_nCurrentCycles;
+ };
+
+
+
+ /**
+ * This command makes the current command processor context beeing copied and stored to the top of a stack.
+ */
+ class PushCommand : public Command
+ {
+ public:
+ typedef std::shared_ptr PtrType;
+
+ /**
+ * Creates a new PushCommand command.
+ * @return Returns the new constructed command.
+ */
+ static PtrType create();
+
+ virtual ~PushCommand();
+
+ virtual ARSTD::Command::PtrType copy() const;
+ virtual void initialize();
+ virtual void step();
+ virtual void cleanup();
+ virtual uint64 getRessourceID() const;
+ virtual std::string getName() const;
+ virtual std::string getDetails() const;
+
+ protected:
+ PushCommand();
+ PushCommand(const PushCommand& other);
+ };
+
+
+
+ /**
+ * This command makes the topmost stored command processor context from a stack beeing restored and used as current context.
+ * If the stack is empty nothing will be done.
+ * @warning All commands that are in queue after this command are not executed.
+ */
+ class PopCommand : public Command
+ {
+ public:
+ typedef std::shared_ptr PtrType;
+
+ /**
+ * Creates a new PopCommand command.
+ * @return Returns the new constructed command.
+ */
+ static PtrType create();
+
+ virtual ~PopCommand();
+
+ virtual ARSTD::Command::PtrType copy() const;
+ virtual void initialize();
+ virtual void step();
+ virtual void cleanup();
+ virtual uint64 getRessourceID() const;
+ virtual std::string getName() const;
+ virtual std::string getDetails() const;
+
+ protected:
+ PopCommand();
+ PopCommand(const PopCommand& other);
+ };
+
+
+
+ /**
+ * This command makes the history (the list of executed commands) from the current command processor context beeing cleared.
+ */
+ class CleanupHistoryCommand : public Command
+ {
+ public:
+ typedef std::shared_ptr PtrType;
+
+ /**
+ * Creates a new CleanupHistoryCommand command.
+ * @return Returns the new constructed command.
+ */
+ static PtrType create();
+
+ virtual ~CleanupHistoryCommand();
+
+ virtual ARSTD::Command::PtrType copy() const;
+ virtual void initialize();
+ virtual void step();
+ virtual void cleanup();
+ virtual uint64 getRessourceID() const;
+ virtual std::string getName() const;
+ virtual std::string getDetails() const;
+
+ protected:
+ CleanupHistoryCommand();
+ CleanupHistoryCommand(const CleanupHistoryCommand& other);
+ };
+
+} //namespace ARSTD
\ No newline at end of file
diff --git a/ARSTD/ARSTD/Command/Command.h b/ARSTD/ARSTD/Command/Command.h
new file mode 100644
index 00000000..ea5581e1
--- /dev/null
+++ b/ARSTD/ARSTD/Command/Command.h
@@ -0,0 +1,105 @@
+// Copyright (c) 2005-2022 Andreas Rose. All rights reserved.
+// Released under the MIT license. (see license.txt)
+
+
+#pragma once
+
+#include
+#include
+#include "arstd/Common/Types.h"
+#include "arstd/Command/ICommandHandler.h"
+
+
+namespace ARSTD
+{
+ class CommandProcessor;
+ class MacroCommand;
+
+ /**
+ * The base class of all Commands that can be executed by the CommandProcessor.
+ * @warning An instance of a command must _not_ used more than ones. To execute the same command again copy it first.
+ */
+ class Command
+ {
+ public:
+ typedef std::shared_ptr PtrType;
+
+ virtual ~Command() {}
+
+ /**
+ * Returns a copy of the command.
+ * @return The copied command.
+ */
+ virtual PtrType copy() const = 0;
+
+ //This is called directly before execution (before the first step() is called).
+ virtual void initialize() = 0;
+
+ //This is called periodically about every 10ms while executing. If the command is done
+ //finished() must be called. If finished() is never called the command never stops executing.
+ virtual void step() = 0;
+
+ //This is called directly after finishing of execution or on breaking.
+ virtual void cleanup() = 0;
+
+ //returns the or-combined ids of the used resources
+ virtual ARSTD::uint64 getRessourceID() const { return 0; }
+
+ /**
+ * Returns the name of the command.
+ * @return The name of the command.
+ */
+ virtual std::string getName() const = 0;
+
+ //Returns some interesting stuff about the current command state.
+ //@return The detailed state depend command description.
+ virtual std::string getDetails() const { return "n.a."; }
+
+ /**
+ * Returns whether the command was already executed.
+ * @return Returns true if the command was successfully executed otherwise false.
+ * If the progress has not reached 1 (or 100%) false is returned.
+ */
+ virtual bool wasExecuted() const { return m_fProgress >= 1; }
+
+ //is called if repeating will be initialized
+ virtual void resetProgress() { setProgress(0); }
+
+ /**
+ * Returns the progress of command execution.
+ * @return The progress of the execution in range [0, 1].
+ */
+ virtual double getProgress() const { return m_fProgress; }
+
+ friend CommandProcessor;
+ friend MacroCommand;
+
+ protected:
+ Command() {}
+ Command(const Command& other)
+ : m_pCommandprocessor(other.m_pCommandprocessor),
+ m_fProgress(other.m_fProgress)
+ {
+ }
+
+ ICommandHandler* getCommandProcessor() const { return m_pCommandprocessor; }
+
+ //Sets the progress of command execution.
+ //@param fProgress The new progress of the execution in range [0, 1].
+ void setProgress(double fProgress)
+ {
+ m_fProgress = fProgress;
+ if (m_fProgress < 0) m_fProgress = 0;
+ if (m_fProgress > 1) m_fProgress = 1;
+ }
+
+ //This indicates the execution environment that the command is done.
+ //@warning This method is only valid to call inside step().
+ void finished() { m_pCommandprocessor->finished(); }
+
+
+ ICommandHandler* m_pCommandprocessor;
+ double m_fProgress;
+ };
+
+} //namespace ARSTD
diff --git a/ARSTD/ARSTD/Command/CommandProcessor.cpp b/ARSTD/ARSTD/Command/CommandProcessor.cpp
new file mode 100644
index 00000000..82b857ae
--- /dev/null
+++ b/ARSTD/ARSTD/Command/CommandProcessor.cpp
@@ -0,0 +1,224 @@
+// Copyright (c) 2005-2022 Andreas Rose. All rights reserved.
+// Released under the MIT license. (see license.txt)
+
+#include
+#include
+
+#include "Command.h"
+#include "CommandProcessorContext.h"
+#include "CommandProcessor.h"
+
+
+namespace ARSTD
+{
+
+ CommandProcessor::PtrType CommandProcessor::create()
+ {
+ return PtrType(new CommandProcessor());
+ }
+
+
+ CommandProcessor::~CommandProcessor()
+ {
+ }
+
+
+ void CommandProcessor::execute(Command::PtrType pCommand)
+ {
+ if (!m_pContext || !pCommand)
+ return;
+
+ pCommand->m_pCommandprocessor = this;
+ pCommand->resetProgress();
+ m_pContext->addCommand(pCommand);
+
+ if (!m_pContext->getCurrentExecutingCommand())
+ executeNext();
+ }
+
+
+ void CommandProcessor::finished()
+ {
+ executeNext();
+ }
+
+
+ void CommandProcessor::repeat()
+ {
+ if (!m_pContext)
+ return;
+
+ if (m_pContext->getCurrentExecutingCommand())
+ m_pContext->getCurrentExecutingCommand()->cleanup();
+
+ m_pContext->setAllCommandsToNotExecuted();
+ ICommandHandler::CommandRange range = m_pContext->getWaitingCommands();
+ ICommandHandler::CommandIterator it = range.first;
+ for (; it != range.second; ++it)
+ {
+ (*it)->resetProgress();
+ }
+ executeNext();
+ }
+
+
+ bool CommandProcessor::push()
+ {
+ if (!m_pContext)
+ return false;
+
+ if (m_ContextStack.size() > 30)
+ throw std::runtime_error("ARSTD::CommandProcessor::push(): maximum context stack depth exceeded");
+
+ m_ContextStack.push_back(m_pContext->copy());
+ return true;
+ }
+
+
+ bool CommandProcessor::pop()
+ {
+ if (m_ContextStack.empty())
+ return false;
+
+ if (m_pContext && m_pContext->getCurrentExecutingCommand())
+ m_pContext->getCurrentExecutingCommand()->cleanup();
+
+ m_pContext = m_ContextStack.back();
+ m_ContextStack.pop_back();
+ return true;
+ }
+
+
+ void CommandProcessor::step()
+ {
+ if (!m_pContext)
+ return;
+
+ if (m_pContext->getCurrentExecutingCommand())
+ m_pContext->getCurrentExecutingCommand()->step();
+ else
+ executeNext();
+ }
+
+
+ void CommandProcessor::cleanup()
+ {
+ if (!m_pContext)
+ return;
+
+ if (m_pContext->getCurrentExecutingCommand())
+ m_pContext->getCurrentExecutingCommand()->cleanup();
+
+ m_pContext->cleanup();
+ }
+
+
+ void CommandProcessor::cleanupStack()
+ {
+ cleanup();
+ m_ContextStack.clear();
+ }
+
+
+ void CommandProcessor::cleanupHistory()
+ {
+ if (!m_pContext)
+ return;
+
+ m_pContext->cleanupHistory();
+ }
+
+
+ void CommandProcessor::skipCurrent()
+ {
+ executeNext();
+ }
+
+
+ bool CommandProcessor::isBusy()
+ {
+ if (!m_pContext)
+ return false;
+
+ return m_pContext->getCurrentExecutingCommand() != nullptr;
+ }
+
+
+ double CommandProcessor::getCurrentCommandProgress() const
+ {
+ if (!m_pContext || !m_pContext->getCurrentExecutingCommand())
+ return -1;
+ return m_pContext->getCurrentExecutingCommand()->getProgress();
+ }
+
+
+ std::string CommandProcessor::getCurrentCommandName() const
+ {
+ if (!m_pContext || !m_pContext->getCurrentExecutingCommand())
+ return "";
+ return m_pContext->getCurrentExecutingCommand()->getName();
+ }
+
+
+ std::string CommandProcessor::getCurrentCommandDetails() const
+ {
+ if (!m_pContext || !m_pContext->getCurrentExecutingCommand())
+ return "";
+ return m_pContext->getCurrentExecutingCommand()->getDetails();
+ }
+
+
+ unsigned int CommandProcessor::getNumWaitingCommands() const
+ {
+ if (!m_pContext)
+ return 0;
+ return m_pContext->getNumWaitingCommands();
+ }
+
+
+ CommandProcessor::CommandConstRange CommandProcessor::getWaitingCommands() const
+ {
+ if (!m_pContext)
+ return std::make_pair(CommandConstIterator(), CommandConstIterator());
+ return m_pContext->getWaitingCommands();
+ }
+
+
+ unsigned int CommandProcessor::getCurrentStackDepth() const
+ {
+ return static_cast(m_ContextStack.size());
+ }
+
+
+ unsigned int CommandProcessor::getNumExecutedCommands() const
+ {
+ if (!m_pContext)
+ return 0;
+ return m_pContext->getNumExecutedCommands();
+ }
+
+
+ CommandProcessor::CommandProcessor()
+ : m_pContext(CommandProcessorContext::create())
+ {
+ }
+
+
+ void CommandProcessor::executeNext()
+ {
+ if (!m_pContext)
+ return;
+
+ if (m_pContext->getCurrentExecutingCommand())
+ m_pContext->getCurrentExecutingCommand()->cleanup();
+
+ m_pContext->incrementCurrentExecutingCommand();
+
+ if (m_pContext->getCurrentExecutingCommand())
+ {
+ m_pContext->getCurrentExecutingCommand()->resetProgress();
+ m_pContext->getCurrentExecutingCommand()->initialize();
+ }
+ }
+
+} //namespace ARSTD
diff --git a/ARSTD/ARSTD/Command/CommandProcessor.h b/ARSTD/ARSTD/Command/CommandProcessor.h
new file mode 100644
index 00000000..27026610
--- /dev/null
+++ b/ARSTD/ARSTD/Command/CommandProcessor.h
@@ -0,0 +1,118 @@
+// Copyright (c) 2005-2022 Andreas Rose. All rights reserved.
+// Released under the MIT license. (see license.txt)
+
+
+#pragma once
+
+#include
+#include
+#include "ICommandHandler.h"
+
+
+namespace ARSTD
+{
+
+ class Command;
+ class CommandProcessorContext;
+
+ /**
+ * This class encapsulates the management of commands. If commands are executed by the commandprocessor, they will be stored
+ * and executed one after another till all done.
+ */
+ class CommandProcessor : public ICommandHandler
+ {
+ public:
+ typedef std::shared_ptr PtrType;
+
+ static PtrType create();
+
+ ~CommandProcessor();
+
+ /**
+ * Execute the given command. If other commands are currently executed this command will be stored and executed next.
+ * @param pCommand The command that will be added to the execution queue.
+ */
+ void execute(std::shared_ptr pCommand);
+
+ virtual void finished();
+
+ /**
+ * Repeates all commands that were previously executed.
+ */
+ virtual void repeat();
+
+ /**
+ * Copies the current context to a stack.
+ * @return True on success.
+ */
+ virtual bool push();
+
+ /**
+ * Restores the topmost context from a stack and makes it current.
+ * @return True on success.
+ */
+ virtual bool pop();
+
+ /**
+ * Removes only executed commands that are stored.
+ */
+ virtual void cleanupHistory();
+
+ void step();
+
+ /**
+ * Removes all (executed and waiting) stored commands from the queue.
+ * @post isBusy() is false
+ */
+ void cleanup();
+
+ //cleans up the stack and removes all (executed and waiting) stored commands from the queue.
+ //@post isBusy() is false
+ void cleanupStack();
+
+ /**
+ * Removes the currently executing command and do the next (if available).
+ */
+ void skipCurrent();
+
+ /**
+ * Returns true if the processor is currently executing a command otherwise false.
+ * @return True if currently executing a command otherwise false.
+ */
+ bool isBusy();
+
+ /**
+ * Returns the progress of the currently executing command.
+ * @return The progress of the executing command in range [0, 1]. If the processor is not busy -1 is returned.
+ */
+ double getCurrentCommandProgress() const;
+
+ /**
+ * Returns the name of the currently executing command.
+ * @return The current executing command name. If the processor is not busy "" is returned.
+ */
+ std::string getCurrentCommandName() const;
+ std::string getCurrentCommandDetails() const;
+
+ /**
+ * Returns the number of commands that currently waits of its execution.
+ * @return The number of currently waiting commands.
+ */
+ unsigned int getNumWaitingCommands() const;
+
+ ICommandHandler::CommandConstRange getWaitingCommands() const;
+
+ unsigned int getCurrentStackDepth() const;
+
+ unsigned int getNumExecutedCommands() const;
+
+ protected:
+ CommandProcessor();
+
+ void executeNext();
+
+ std::shared_ptr m_pContext;
+ std::vector > m_ContextStack;
+ };
+
+} //namespace ARSTD
\ No newline at end of file
diff --git a/ARSTD/ARSTD/Command/CommandProcessorContext.cpp b/ARSTD/ARSTD/Command/CommandProcessorContext.cpp
new file mode 100644
index 00000000..57b0ca8b
--- /dev/null
+++ b/ARSTD/ARSTD/Command/CommandProcessorContext.cpp
@@ -0,0 +1,158 @@
+// Copyright (c) 2005-2022 Andreas Rose. All rights reserved.
+// Released under the MIT license. (see license.txt)
+
+
+#include "CommandProcessorContext.h"
+#include "Command.h"
+#include "CommandProcessor.h"
+
+
+namespace ARSTD
+{
+
+ CommandProcessorContext::PtrType CommandProcessorContext::create()
+ {
+ return PtrType(new CommandProcessorContext());
+ }
+
+
+ CommandProcessorContext::~CommandProcessorContext()
+ {
+ }
+
+
+ CommandProcessorContext::PtrType CommandProcessorContext::copy()
+ {
+ return PtrType(new CommandProcessorContext(*this));
+ }
+
+
+ bool CommandProcessorContext::addCommand(Command::PtrType pCommand)
+ {
+ m_WaitingCommands.push_back(pCommand);
+ return true;
+ }
+
+
+ Command::PtrType CommandProcessorContext::getCurrentExecutingCommand() const
+ {
+ return m_pCurrentExecutingCommand;
+ }
+
+
+ void CommandProcessorContext::cleanup()
+ {
+ m_ExecutedCommands.clear();
+ m_pCurrentExecutingCommand.reset();
+ m_WaitingCommands.clear();
+ }
+
+
+ void CommandProcessorContext::cleanupHistory()
+ {
+ m_ExecutedCommands.clear();
+ }
+
+
+ void CommandProcessorContext::setCommandProcessor(CommandProcessor* pCommandProcessor)
+ {
+// if (m_pCurrentExecutingCommand) m_pCurrentExecutingCommand->setCommandProcessor(pCommandProcessor);
+//
+// ICommandHandler::CommandContainer::const_iterator it = other.m_WaitingCommands.begin();
+// ICommandHandler::CommandContainer::const_iterator itEnd = other.m_WaitingCommands.end();
+// for (; it != itEnd; ++it)
+// {
+// (*it)->setCommandProcessor(pCommandProcessor);
+// }
+ }
+
+
+ int CommandProcessorContext::getNumExecutedCommands() const
+ {
+ return static_cast(m_ExecutedCommands.size());
+ }
+
+
+ int CommandProcessorContext::getNumWaitingCommands() const
+ {
+ return static_cast(m_WaitingCommands.size());
+ }
+
+
+ ICommandHandler::CommandRange CommandProcessorContext::getWaitingCommands()
+ {
+ return std::make_pair(m_WaitingCommands.begin(), m_WaitingCommands.end());
+ }
+
+
+ ICommandHandler::CommandConstRange CommandProcessorContext::getWaitingCommands() const
+ {
+ return std::make_pair(m_WaitingCommands.begin(), m_WaitingCommands.end());
+ }
+
+
+ void CommandProcessorContext::incrementCurrentExecutingCommand()
+ {
+ if (m_pCurrentExecutingCommand)
+ m_ExecutedCommands.push_back(m_pCurrentExecutingCommand);
+ if (!m_WaitingCommands.empty())
+ {
+ m_pCurrentExecutingCommand = m_WaitingCommands.front();
+ m_WaitingCommands.pop_front();
+ }
+ else
+ m_pCurrentExecutingCommand.reset();
+ }
+
+
+ void CommandProcessorContext::setAllCommandsToNotExecuted()
+ {
+ ICommandHandler::CommandContainer newWaitingCommands;
+
+ ICommandHandler::CommandConstIterator it = m_ExecutedCommands.begin();
+ for (; it != m_ExecutedCommands.end(); ++it)
+ {
+ newWaitingCommands.push_back(*it);
+ }
+
+ if (m_pCurrentExecutingCommand)
+ newWaitingCommands.push_back(m_pCurrentExecutingCommand);
+
+ it = m_WaitingCommands.begin();
+ for (; it != m_WaitingCommands.end(); ++it)
+ {
+ newWaitingCommands.push_back(*it);
+ }
+
+ cleanup();
+ m_WaitingCommands.swap(newWaitingCommands);
+ }
+
+
+ CommandProcessorContext::CommandProcessorContext()
+ {
+ }
+
+
+ CommandProcessorContext::CommandProcessorContext(const CommandProcessorContext& other)
+ {
+ ICommandHandler::CommandContainer::const_iterator it = other.m_ExecutedCommands.begin();
+ ICommandHandler::CommandContainer::const_iterator itEnd = other.m_ExecutedCommands.end();
+ for (; it != itEnd; ++it)
+ {
+ m_ExecutedCommands.push_back((*it)->copy());
+ }
+
+ if (other.m_pCurrentExecutingCommand) m_pCurrentExecutingCommand = other.m_pCurrentExecutingCommand->copy();
+
+ it = other.m_WaitingCommands.begin();
+ itEnd = other.m_WaitingCommands.end();
+ for (; it != itEnd; ++it)
+ {
+ m_WaitingCommands.push_back((*it)->copy());
+ }
+ }
+
+
+
+} //namespace ARSTD
\ No newline at end of file
diff --git a/ARSTD/ARSTD/Command/CommandProcessorContext.h b/ARSTD/ARSTD/Command/CommandProcessorContext.h
new file mode 100644
index 00000000..236feb58
--- /dev/null
+++ b/ARSTD/ARSTD/Command/CommandProcessorContext.h
@@ -0,0 +1,71 @@
+// Copyright (c) 2005-2022 Andreas Rose. All rights reserved.
+// Released under the MIT license. (see license.txt)
+
+
+#pragma once
+
+#include
+#include "ICommandHandler.h"
+
+
+namespace ARSTD
+{
+
+ class Command;
+ class CommandProcessor;
+
+ //the context that is mainly managed through a command processor
+ class CommandProcessorContext
+ {
+ public:
+ typedef std::shared_ptr PtrType;
+
+ //creates a new empty context
+ static PtrType create();
+
+ ~CommandProcessorContext();
+
+ //makes a deep copy
+ PtrType copy();
+
+ //adds a command to the end
+ bool addCommand(std::shared_ptr pCommand);
+
+ //returns the command the is currently executing. returns NULL if no command is currently executing.
+ std::shared_ptr getCurrentExecutingCommand() const;
+
+ //empties the whole context
+ void cleanup();
+
+ //empties only the executed command container
+ void cleanupHistory();
+
+ //sets the commandprocessor to all commands
+ void setCommandProcessor(CommandProcessor* pCommandProcessor);
+
+ //returns the number of executed commands
+ int getNumExecutedCommands() const;
+
+ //returns the number of waiting commands
+ int getNumWaitingCommands() const;
+
+ //returns a range of all waiting commands
+ ICommandHandler::CommandRange getWaitingCommands();
+ ICommandHandler::CommandConstRange getWaitingCommands() const;
+
+ //makes the current executing command to be the next available
+ void incrementCurrentExecutingCommand();
+
+ //marks all commands to not be executed
+ void setAllCommandsToNotExecuted();
+
+ protected:
+ CommandProcessorContext();
+ CommandProcessorContext(const CommandProcessorContext& other);
+
+ ICommandHandler::CommandContainer m_ExecutedCommands;
+ std::shared_ptr m_pCurrentExecutingCommand;
+ ICommandHandler::CommandContainer m_WaitingCommands;
+ };
+
+} //namespace ARSTD
\ No newline at end of file
diff --git a/ARSTD/ARSTD/Command/ICommandHandler.h b/ARSTD/ARSTD/Command/ICommandHandler.h
new file mode 100644
index 00000000..7a91835f
--- /dev/null
+++ b/ARSTD/ARSTD/Command/ICommandHandler.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2005-2022 Andreas Rose. All rights reserved.
+// Released under the MIT license. (see license.txt)
+
+
+#pragma once
+
+#include
+#include
+
+namespace ARSTD
+{
+
+ class Command;
+
+ class ICommandHandler
+ {
+ public:
+ typedef std::shared_ptr PtrType;
+ typedef std::deque > CommandContainer;
+ typedef CommandContainer::iterator CommandIterator;
+ typedef CommandContainer::const_iterator CommandConstIterator;
+ typedef std::pair CommandRange;
+ typedef std::pair CommandConstRange;
+
+ virtual ~ICommandHandler() {}
+
+ //callback method that will be executed by the executing command to report finishing of itself
+ virtual void finished() = 0;
+
+ //Repeates all commands that were previously executed.
+ virtual void repeat() = 0;
+
+ //these methods are routed through to the "real" command processor if call in macrocommand
+ virtual bool push() = 0;
+ virtual bool pop() = 0;
+ virtual void cleanupHistory() = 0;
+
+ };
+}
\ No newline at end of file
diff --git a/ARSTD/ARSTD/Command/MacroCommand.cpp b/ARSTD/ARSTD/Command/MacroCommand.cpp
new file mode 100644
index 00000000..8c48e025
--- /dev/null
+++ b/ARSTD/ARSTD/Command/MacroCommand.cpp
@@ -0,0 +1,331 @@
+// Copyright (c) 2005-2022 Andreas Rose. All rights reserved.
+// Released under the MIT license. (see license.txt)
+
+
+#include
+#include
+#include
+#include
+
+#include
+
+#include "MacroCommand.h"
+
+
+namespace ARSTD
+{
+
+
+ MacroCommand::PtrType MacroCommand::create(const std::string& name)
+ {
+ return PtrType(new MacroCommand(name));
+ }
+
+
+ Command::PtrType MacroCommand::copy() const
+ {
+ return PtrType(new MacroCommand(*this));
+ }
+
+
+ void MacroCommand::initialize()
+ {
+ if (m_CommandContainer.empty())
+ {
+ m_itCurrentExecutingCommand = m_CommandContainer.end();
+ }
+ else
+ {
+ m_itCurrentExecutingCommand = m_CommandContainer.begin();
+ assert(*m_itCurrentExecutingCommand);
+ (*m_itCurrentExecutingCommand)->initialize();
+ }
+ }
+
+
+ void MacroCommand::step()
+ {
+ if (m_itCurrentExecutingCommand != m_CommandContainer.end())
+ {
+ (*m_itCurrentExecutingCommand)->step();
+ }
+ else
+ {
+ finished();
+ }
+ }
+
+
+ void MacroCommand::cleanup()
+ {
+ if (m_itCurrentExecutingCommand != m_CommandContainer.end())
+ {
+ (*m_itCurrentExecutingCommand)->cleanup();
+ }
+ }
+
+
+ std::string MacroCommand::getName() const
+ {
+ return getName(0);
+ }
+
+
+ std::string MacroCommand::getDetails() const
+ {
+ return getDetails(0);
+ }
+
+
+ bool MacroCommand::wasExecuted() const
+ {
+ return getProgress() >= 1;
+ }
+
+
+ double MacroCommand::getProgress() const
+ {
+ double fProgress = 0;
+
+ CommandContainer::const_iterator it = m_CommandContainer.begin();
+ for (; it != m_CommandContainer.end(); ++it)
+ {
+ fProgress += (*it)->getProgress();
+ }
+ if (!m_CommandContainer.empty())
+ fProgress /= m_CommandContainer.size();
+
+ return fProgress;
+ }
+
+
+ void MacroCommand::resetProgress()
+ {
+ CommandContainer::iterator it = m_CommandContainer.begin();
+ for (; it != m_CommandContainer.end(); ++it)
+ {
+ (*it)->resetProgress();
+ }
+ }
+
+
+ ARSTD::uint64 MacroCommand::getRessourceID() const
+ {
+ ARSTD::uint64 id = 0;
+
+ CommandContainer::const_iterator it = m_CommandContainer.begin();
+ for (; it != m_CommandContainer.end(); ++it)
+ {
+ id += (*it)->getRessourceID();
+ }
+
+ return id;
+ }
+
+
+ void MacroCommand::finished()
+ {
+ if (m_itCurrentExecutingCommand != m_CommandContainer.end())
+ (*m_itCurrentExecutingCommand)->cleanup();
+
+ if (m_itCurrentExecutingCommand != m_CommandContainer.end() &&
+ m_itCurrentExecutingCommand != boost::prior(m_CommandContainer.end()))
+ {
+ ++m_itCurrentExecutingCommand;
+ (*m_itCurrentExecutingCommand)->resetProgress();
+ (*m_itCurrentExecutingCommand)->initialize();
+ }
+ else
+ {
+ m_itCurrentExecutingCommand = m_CommandContainer.end();
+ getCommandProcessor()->finished();
+ }
+ }
+
+
+ void MacroCommand::repeat()
+ {
+ if (m_CommandContainer.empty())
+ {
+ m_itCurrentExecutingCommand = m_CommandContainer.end();
+ return;
+ }
+
+ if (m_itCurrentExecutingCommand != m_CommandContainer.end())
+ (*m_itCurrentExecutingCommand)->cleanup();
+
+ m_itCurrentExecutingCommand = m_CommandContainer.begin();
+ MacroCommand::resetProgress();
+ (*m_itCurrentExecutingCommand)->initialize();
+ }
+
+
+ bool MacroCommand::push()
+ {
+ return getCommandProcessor()->push();
+ }
+
+
+ bool MacroCommand::pop()
+ {
+ return getCommandProcessor()->pop();
+ }
+
+
+ void MacroCommand::cleanupHistory()
+ {
+ getCommandProcessor()->cleanupHistory();
+ }
+
+
+ double MacroCommand::getCurrentCommandProgress()
+ {
+ if (m_itCurrentExecutingCommand == m_CommandContainer.end())
+ return -1;
+ return (*m_itCurrentExecutingCommand)->getProgress();
+ }
+
+
+ std::string MacroCommand::getCurrentCommandName()
+ {
+ if (m_itCurrentExecutingCommand == m_CommandContainer.end())
+ return "";
+ return (*m_itCurrentExecutingCommand)->getName();
+ }
+
+
+ std::string MacroCommand::getCurrentCommandDetails()
+ {
+ if (m_itCurrentExecutingCommand == m_CommandContainer.end())
+ return "";
+ return (*m_itCurrentExecutingCommand)->getDetails();
+ }
+
+
+ void MacroCommand::attach(Command::PtrType pCommand)
+ {
+ if (!pCommand)
+ return;
+ pCommand->m_pCommandprocessor = this;
+ pCommand->resetProgress();
+ m_CommandContainer.push_back(pCommand);
+ m_itCurrentExecutingCommand = m_CommandContainer.end();
+ }
+
+
+ void MacroCommand::detach(Command::PtrType pCommand)
+ {
+ CommandContainer::iterator itFound = std::find(m_CommandContainer.begin(), m_CommandContainer.end(), pCommand);
+ if (itFound != m_CommandContainer.end())
+ m_CommandContainer.erase(itFound);
+ m_itCurrentExecutingCommand = m_CommandContainer.end();
+ }
+
+
+ MacroCommand::MacroCommand(const std::string& name)
+ : m_Name(name)
+ {
+ m_itCurrentExecutingCommand = m_CommandContainer.end();
+ }
+
+
+ MacroCommand::MacroCommand(const MacroCommand& other)
+ : Command(other),
+ m_Name(other.m_Name)
+ {
+ CommandContainer::const_iterator itOther = other.m_CommandContainer.begin();
+ for (; itOther != other.m_CommandContainer.end(); ++itOther)
+ {
+ Command::PtrType pCopyCommand = (*itOther)->copy();
+ pCopyCommand->m_pCommandprocessor = this;
+ m_CommandContainer.push_back(pCopyCommand);
+ }
+
+ assert(m_CommandContainer.size() == other.m_CommandContainer.size());
+ itOther = other.m_CommandContainer.begin();
+ CommandContainer::iterator it = m_CommandContainer.begin();
+ for (; itOther != other.m_CommandContainer.end() && it != m_CommandContainer.end(); ++itOther, ++it)
+ {
+ if (other.m_itCurrentExecutingCommand == itOther)
+ {
+ m_itCurrentExecutingCommand = it;
+ }
+ }
+ }
+
+
+ std::string MacroCommand::getName(int nHiearchy) const
+ {
+ std::string strSingleSpace = " ";
+ std::string strSingleSpaceMinOne = " ";
+ std::string strSpace = "";
+ for (int i = 0; i < nHiearchy; ++i) strSpace += strSingleSpace;
+
+ std::stringstream ss;
+ ss << strSpace;
+ if (nHiearchy != 0) ss << "+-";
+ ss << m_Name << "\n";
+ CommandContainer::const_iterator it = m_CommandContainer.begin();
+ for (; it != m_CommandContainer.end(); ++it)
+ {
+ MacroCommand::PtrType pMC = std::dynamic_pointer_cast(*it);
+ if (pMC)
+ ss << pMC->getName(nHiearchy + 1);
+ else
+ {
+ if (it == m_itCurrentExecutingCommand)
+ {
+ ss << ">" << strSpace << strSingleSpaceMinOne;
+ }
+ else
+ {
+ ss << strSpace << strSingleSpace;
+ }
+ ss << "+-" << (*it)->getName() << "\n";
+ }
+ }
+
+ return ss.str();
+ }
+
+
+ std::string MacroCommand::getDetails(int nHiearchy) const
+ {
+ std::string strSingleSpace = " ";
+ std::string strSingleSpaceMinOne = " ";
+ std::string strSpace = "";
+ for (int i = 0; i < nHiearchy; ++i) strSpace += strSingleSpace;
+
+ std::stringstream ss;
+ ss << strSpace;
+ if (nHiearchy != 0) ss << "+-";
+ ss << m_Name << "\n";
+ CommandContainer::const_iterator it = m_CommandContainer.begin();
+ for (; it != m_CommandContainer.end(); ++it)
+ {
+ MacroCommand::PtrType pMC = std::dynamic_pointer_cast(*it);
+ if (pMC)
+ ss << pMC->getDetails(nHiearchy + 1);
+ else
+ {
+ if (it == m_itCurrentExecutingCommand)
+ {
+ ss << ">" << strSpace << strSingleSpaceMinOne;
+ }
+ else
+ {
+ ss << strSpace << strSingleSpace;
+ }
+ ss << "+-" << (*it)->getDetails() << "\n";
+ }
+ }
+
+ return ss.str();
+ }
+
+
+ MacroCommand::~MacroCommand()
+ {
+ }
+
+} //namespace ARSTD
\ No newline at end of file
diff --git a/ARSTD/ARSTD/Command/MacroCommand.h b/ARSTD/ARSTD/Command/MacroCommand.h
new file mode 100644
index 00000000..1446638d
--- /dev/null
+++ b/ARSTD/ARSTD/Command/MacroCommand.h
@@ -0,0 +1,77 @@
+// Copyright (c) 2005-2022 Andreas Rose. All rights reserved.
+// Released under the MIT license. (see license.txt)
+
+
+#pragma once
+
+#include "Command.h"
+#include "ICommandHandler.h"
+
+namespace ARSTD
+{
+
+ /**
+ * This class provides functionality for defining macro commands. Macro commands are a list of other commands. These commands
+ * can also be MacroCommands. The order of the list is the same as the execution order.
+ */
+ class MacroCommand : public Command, public ICommandHandler
+ {
+ public:
+ typedef std::shared_ptr PtrType;
+
+ /**
+ * Creates a new MacroCommand.
+ * @param strName The name of the MacroCommand.
+ */
+ static PtrType create(const std::string& strName);
+
+ virtual ~MacroCommand();
+
+ virtual Command::PtrType copy() const;
+ virtual void initialize();
+ virtual void step();
+ virtual void cleanup();
+ virtual ARSTD::uint64 getRessourceID() const;
+ virtual std::string getName() const;
+ virtual std::string getDetails() const;
+
+ virtual bool wasExecuted() const;
+ virtual void resetProgress();
+ virtual double getProgress() const;
+
+ virtual void finished();
+ virtual void repeat();
+ virtual bool push();
+ virtual bool pop();
+ virtual void cleanupHistory();
+
+ double getCurrentCommandProgress();
+ std::string getCurrentCommandName();
+ std::string getCurrentCommandDetails();
+
+ /**
+ * Attaches a command or MacroCommand.
+ * @param pCommand The command that should be attached.
+ */
+ void attach(Command::PtrType pCommand);
+ /**
+ * Detaches a command or MacroCommand.
+ * @param pCommand The command that should be detached.
+ */
+ void detach(Command::PtrType pCommand);
+
+ protected:
+ MacroCommand(const std::string& name);
+ MacroCommand(const MacroCommand& other);
+
+ CommandRange getAttachedCommands();
+
+ std::string getName(int nHiearchy = 0) const;
+ std::string getDetails(int nHiearchy = 0) const;
+
+ CommandContainer m_CommandContainer;
+ CommandIterator m_itCurrentExecutingCommand;
+ std::string m_Name;
+ };
+
+} //namespace ARSTD
\ No newline at end of file
diff --git a/ARSTD/ARSTD/Common/Size3.h b/ARSTD/ARSTD/Common/Size3.h
new file mode 100644
index 00000000..4b97f44b
--- /dev/null
+++ b/ARSTD/ARSTD/Common/Size3.h
@@ -0,0 +1,161 @@
+// Copyright (c) 2005-2022 Andreas Rose. All rights reserved.
+// Released under the MIT license. (see license.txt)
+
+#pragma once
+
+#include "arstd/Math/Math.h"
+
+
+namespace ARSTD
+{
+
+ template
+ class Size3
+ {
+ public:
+ Size3(const Type& width = 0, const Type& height = 0, const Type& depth = 0);
+ explicit Size3(const Vector3& vecSize);
+
+ template
+ explicit Size3(const Size3& other)
+ : m_Width(static_cast(other.getWidth())),
+ m_Height(static_cast(other.getHeight())),
+ m_Depth(static_cast(other.getDepth()))
+ {
+ }
+
+ const Type& getWidth() const;
+ void setWidth(const Type& width);
+
+ const Type& getHeight() const;
+ void setHeight(const Type& height);
+
+ const Type& getDepth() const;
+ void setDepth(const Type& depth);
+
+ const Type getVolume() const;
+
+ Size3& operator *= (const Size3& size);
+ Size3& operator /= (const Size3& size);
+
+ protected:
+ Type m_Width;
+ Type m_Height;
+ Type m_Depth;
+ };
+
+
+ typedef Size3 Size3I;
+ typedef Size3 Size3UI;
+ typedef Size3 Size3F;
+ typedef Size3 Size3D;
+
+
+ template
+ Size3::Size3(const Type& width, const Type& height, const Type& depth)
+ : m_Width(width),
+ m_Height(height),
+ m_Depth(depth)
+ {
+ }
+
+
+ template
+ Size3::Size3(const Vector3& vecSize)
+ : m_Width(vecSize.x),
+ m_Height(vecSize.y),
+ m_Depth(vecSize.z)
+ {
+ }
+
+
+ template
+ const Type& Size3::getWidth() const
+ {
+ return m_Width;
+ }
+
+
+ template
+ void Size3::setWidth(const Type& width)
+ {
+ m_Width = width;
+ }
+
+
+ template
+ const Type& Size3::getHeight() const
+ {
+ return m_Height;
+ }
+
+
+ template
+ void Size3::setHeight(const Type& height)
+ {
+ m_Height = height;
+ }
+
+
+ template
+ const Type& Size3::getDepth() const
+ {
+ return m_Depth;
+ }
+
+
+ template
+ void Size3::setDepth(const Type& depth)
+ {
+ m_Depth = depth;
+ }
+
+
+ template
+ const Type Size3::getVolume() const
+ {
+ return m_Width*m_Height*m_Depth;
+ }
+
+
+ template
+ Size3& Size3::operator /= (const Size3& size)
+ {
+ m_Width /= size.m_Width;
+ m_Height /= size.m_Height;
+ m_Depth /= size.m_Depth;
+ return *this;
+ }
+
+
+ template
+ const Size3 operator * (const Size3& lhs, const Type& rhs)
+ {
+ return Size3(lhs.getWidth() * rhs, lhs.getHeight() * rhs, lhs.getDepth() * rhs);
+ }
+
+
+ template
+ const Size3 operator / (const Size3& lhs, const Size3& rhs)
+ {
+ return Size3(lhs) /= rhs;
+ }
+
+
+ template
+ bool equals(const Size3& lhs, const Size3& rhs, double fEpsilon)
+ {
+ return fabs(lhs.getWidth() - rhs.getWidth()) < fEpsilon &&
+ fabs(lhs.getHeight() - rhs.getHeight()) < fEpsilon &&
+ fabs(lhs.getDepth() - rhs.getDepth()) < fEpsilon;
+ }
+
+
+ template
+ bool operator == (const Size3& lhs, const Size3& rhs)
+ {
+ return equals(lhs, rhs, EPSILON);
+ }
+
+
+} // namespace ARSTD
diff --git a/ARSTD/ARSTD/Common/Types.h b/ARSTD/ARSTD/Common/Types.h
new file mode 100644
index 00000000..57e9ea5e
--- /dev/null
+++ b/ARSTD/ARSTD/Common/Types.h
@@ -0,0 +1,22 @@
+// Copyright (c) 2005-2022 Andreas Rose. All rights reserved.
+// Released under the MIT license. (see license.txt)
+
+#pragma once
+
+
+namespace ARSTD
+{
+ typedef unsigned char uchar;
+ typedef unsigned short ushort;
+ typedef unsigned int uint;
+
+ typedef char int8;
+ typedef short int16;
+ typedef int int32;
+ typedef __int64 int64;
+
+ typedef unsigned char uint8;
+ typedef unsigned short uint16;
+ typedef unsigned int uint32;
+ typedef unsigned __int64 uint64;
+};
diff --git a/ARSTD/ARSTD/Geometry/AxisAlignedBoundingBox.h b/ARSTD/ARSTD/Geometry/AxisAlignedBoundingBox.h
new file mode 100644
index 00000000..21431d0d
--- /dev/null
+++ b/ARSTD/ARSTD/Geometry/AxisAlignedBoundingBox.h
@@ -0,0 +1,141 @@
+// Copyright (c) 2005-2022 Andreas Rose. All rights reserved.
+// Released under the MIT license. (see license.txt)
+
+#pragma once
+
+#include
+#include "arstd/Common/Size3.h"
+
+namespace ARSTD
+{
+
+ template
+ class AxisAlignedBoundingBox
+ {
+ public:
+ static const AxisAlignedBoundingBox buildAroundPoints(const std::vector>& pointContainer);
+
+ AxisAlignedBoundingBox();
+ AxisAlignedBoundingBox(const Vector3& vecMin, const Vector3& vecMax);
+ AxisAlignedBoundingBox(const Vector3& vecMin, const Size3& size);
+
+ template
+ explicit AxisAlignedBoundingBox(const AxisAlignedBoundingBox& other)
+ : m_vecMin(static_cast>(other.getMin())),
+ m_vecMax(static_cast>(other.getMax()))
+ {
+ }
+
+ const Vector3& getMin() const;
+ void setMin(const Vector3& vecMin);
+
+ const Vector3& getMax() const;
+ void setMax(const Vector3& vecMax);
+
+ const Size3 getSize() const;
+
+ const Type getWidth() const;
+ const Type getHeight() const;
+ const Type getDepth() const;
+
+ protected:
+ Vector3 m_vecMin;
+ Vector3 m_vecMax;
+ };
+
+
+ typedef AxisAlignedBoundingBox AxisAlignedBoundingBoxD;
+
+
+
+ template
+ AxisAlignedBoundingBox::AxisAlignedBoundingBox()
+ {
+ }
+
+
+ template
+ AxisAlignedBoundingBox::AxisAlignedBoundingBox(const Vector3& vecMin, const Vector3& vecMax)
+ : m_vecMin(vecMin),
+ m_vecMax(vecMax)
+ {
+ }
+
+
+ template
+ AxisAlignedBoundingBox::AxisAlignedBoundingBox(const Vector3& vecMin, const Size3& size)
+ : m_vecMin(vecMin),
+ m_vecMax(vecMin + Vector3(size.getWidth(), size.getHeight(), size.getDepth()))
+ {
+ assert(size.getWidth() >= 0 && size.getHeight() >= 0 && size.getDepth() >= 0);
+ }
+
+
+ template
+ const Vector3& AxisAlignedBoundingBox::getMin() const
+ {
+ return m_vecMin;
+ }
+
+
+ template
+ void AxisAlignedBoundingBox::setMin(const Vector3& vecMin)
+ {
+ m_vecMin = vecMin;
+ }
+
+
+ template
+ const Vector3& AxisAlignedBoundingBox::getMax() const
+ {
+ return m_vecMax;
+ }
+
+
+ template
+ void AxisAlignedBoundingBox::setMax(const Vector3& vecMax)
+ {
+ m_vecMax = vecMax;
+ }
+
+
+ template
+ const Size3 AxisAlignedBoundingBox::getSize() const
+ {
+ return Size3(m_vecMax - m_vecMin);
+ }
+
+
+ template
+ const Type AxisAlignedBoundingBox::getWidth() const
+ {
+ return m_vecMax.x - m_vecMin.x;
+ }
+
+
+ template
+ const Type AxisAlignedBoundingBox::getHeight() const
+ {
+ return m_vecMax.y - m_vecMin.y;
+ }
+
+
+ template
+ const Type AxisAlignedBoundingBox::getDepth() const
+ {
+ return m_vecMax.z - m_vecMin.z;
+ }
+
+
+ template
+ const AxisAlignedBoundingBox AxisAlignedBoundingBox::buildAroundPoints(const std::vector>& points)
+ {
+ if (points.empty())
+ return AxisAlignedBoundingBox();
+
+ auto minmax = getMinMax(points.begin(), points.end());
+ return AxisAlignedBoundingBox(minmax.first, minmax.second);
+ }
+
+
+} // namespace ARSTD
diff --git a/ARSTD/ARSTD/Geometry/BoundingBox.h b/ARSTD/ARSTD/Geometry/BoundingBox.h
new file mode 100644
index 00000000..0e6a10d6
--- /dev/null
+++ b/ARSTD/ARSTD/Geometry/BoundingBox.h
@@ -0,0 +1,231 @@
+// Copyright (c) 2005-2022 Andreas Rose. All rights reserved.
+// Released under the MIT license. (see license.txt)
+
+#pragma once
+
+#include
+#include "arstd/Common/Size3.h"
+#include "arstd/Geometry/Rectangle3.h"
+#include "arstd/Geometry/Segment3.h"
+#include "arstd/Geometry/AxisAlignedBoundingBox.h"
+
+
+namespace ARSTD
+{
+
+ template
+ class BoundingBox
+ {
+ public:
+ BoundingBox();
+ BoundingBox(const Matrix44& matCoordSys, const Size3& size);
+ explicit BoundingBox(const AxisAlignedBoundingBox& aabb);
+
+ template
+ explicit BoundingBox(const BoundingBox& other)
+ : m_matCoordSys(static_cast< Matrix44 >(other.getCoordSystem())),
+ m_Size(static_cast< Size3 >(other.getSize())),
+ m_vecScalingCenter(static_cast>(other.getScalingCenter()))
+ {
+ validate();
+ }
+
+ void set(const Matrix44& matCoordSys, const Size3& size);
+
+ const Matrix44& getCoordSystem() const;
+
+ const Type getWidth() const;
+ const Type getHeight() const;
+ const Type getDepth() const;
+
+ const Size3& getSize() const;
+ const Type getDiagonalLength() const;
+
+ const Rectangle3 getRectangle(const unsigned int idx) const;
+ const Segment3 getSegment(const unsigned int idx) const;
+ const Vector3& getPoint(const unsigned int idx) const;
+
+ bool isValid() const;
+ const Vector3 getCenter() const;
+
+ void transform(const Matrix44& mat);
+
+
+ protected:
+ void validate();
+
+ Matrix44 m_matCoordSys;
+ Size3 m_Size;
+ Vector3 m_pPoints[8];
+ };
+
+
+ typedef BoundingBox BoundingBoxD;
+
+
+ template
+ BoundingBox::BoundingBox()
+ {
+ set(Matrix44(true), Size3(0, 0, 0));
+ }
+
+
+ template
+ BoundingBox::BoundingBox(const Matrix44& matCoordSys, const Size3& size)
+ {
+ set(matCoordSys, size);
+ }
+
+
+ template
+ BoundingBox::BoundingBox(const AxisAlignedBoundingBox& aabb)
+ {
+ set(Matrix44(aabb.getMin()), Size3(aabb.getMax() - aabb.getMin()));
+ }
+
+
+ template
+ void BoundingBox::set(const Matrix44& matCoordSys, const Size3& size)
+ {
+ assert(size.getWidth() >= 0.0f && size.getHeight() >= 0.0f && size.getDepth() >= 0.0f);
+
+ m_matCoordSys = matCoordSys;
+ m_Size = size;
+ validate();
+ }
+
+
+ template
+ inline const Vector3& BoundingBox::getPoint(const unsigned int idx) const
+ {
+ assert(idx < 8);
+
+ return m_pPoints[idx];
+ }
+
+
+ template
+ const Matrix44& BoundingBox::getCoordSystem() const
+ {
+ return m_matCoordSys;
+ }
+
+
+ template
+ const Size3& BoundingBox::getSize() const
+ {
+ return m_Size;
+ }
+
+
+ template
+ inline const Rectangle3 BoundingBox::getRectangle(const unsigned int idx) const
+ {
+ assert(idx < 6);
+
+ switch (idx) {
+ case 0: return Rectangle3(getPoint(0), getPoint(1), getPoint(2), getPoint(3)); break;
+ case 1: return Rectangle3(getPoint(0), getPoint(4), getPoint(5), getPoint(1)); break;
+ case 2: return Rectangle3(getPoint(0), getPoint(3), getPoint(7), getPoint(4)); break;
+ case 3: return Rectangle3(getPoint(4), getPoint(7), getPoint(6), getPoint(5)); break;
+ case 4: return Rectangle3(getPoint(3), getPoint(2), getPoint(6), getPoint(7)); break;
+ case 5: return Rectangle3(getPoint(1), getPoint(5), getPoint(6), getPoint(2)); break;
+ default: return Rectangle3(getPoint(0), getPoint(1), getPoint(2), getPoint(3)); break;
+ }
+ }
+
+
+ template
+ inline const Segment3 BoundingBox::getSegment(const unsigned int idx) const
+ {
+ assert(idx < 12);
+
+ switch (idx) {
+ case 0: return Segment3(getPoint(0), getPoint(1)); break;
+ case 1: return Segment3(getPoint(1), getPoint(2)); break;
+ case 2: return Segment3(getPoint(2), getPoint(3)); break;
+ case 3: return Segment3(getPoint(3), getPoint(0)); break;
+ case 4: return Segment3(getPoint(4), getPoint(5)); break;
+ case 5: return Segment3(getPoint(5), getPoint(6)); break;
+ case 6: return Segment3(getPoint(6), getPoint(7)); break;
+ case 7: return Segment3(getPoint(7), getPoint(4)); break;
+ case 8: return Segment3(getPoint(0), getPoint(4)); break;
+ case 9: return Segment3(getPoint(1), getPoint(5)); break;
+ case 10: return Segment3(getPoint(2), getPoint(6)); break;
+ case 11: return Segment3(getPoint(3), getPoint(7)); break;
+ default: return Segment3(getPoint(0), getPoint(1)); break;
+ }
+ }
+
+
+ template
+ void BoundingBox::transform(const Matrix44& mat)
+ {
+ m_matCoordSys = mat * m_matCoordSys;
+ validate();
+ }
+
+
+ template
+ inline bool BoundingBox::isValid() const
+ {
+ return static_cast(getDiagonalLength() > 0.0);
+ }
+
+
+ template
+ inline const Type BoundingBox::getWidth() const
+ {
+ return m_Size.getWidth();
+ }
+
+
+ template
+ inline const Type BoundingBox::getHeight() const
+ {
+ return m_Size.getHeight();
+ }
+
+
+ template
+ inline const Type BoundingBox::getDepth() const
+ {
+ return m_Size.getDepth();
+ }
+
+
+ template
+ inline const Type BoundingBox::getDiagonalLength() const
+ {
+ return static_cast((m_matCoordSys.getXAxis() * m_Size.getWidth() +
+ m_matCoordSys.getYAxis() * m_Size.getHeight() +
+ m_matCoordSys.getZAxis() * m_Size.getDepth()).getLength());
+ }
+
+
+ template
+ inline const Vector3 BoundingBox::getCenter() const
+ {
+ return m_matCoordSys.getTranslation() + m_matCoordSys.getXAxis() * m_Size.getWidth() * 0.5
+ + m_matCoordSys.getYAxis() * m_Size.getHeight() * 0.5
+ + m_matCoordSys.getZAxis() * m_Size.getDepth() * 0.5;
+ }
+
+
+ template
+ inline void BoundingBox::validate()
+ {
+ m_pPoints[0] = m_matCoordSys.getTranslation();
+ m_pPoints[1] = m_pPoints[0] + m_matCoordSys.getXAxis() * m_Size.getWidth();
+ m_pPoints[2] = m_pPoints[1] + m_matCoordSys.getZAxis() * m_Size.getDepth();
+ m_pPoints[3] = m_pPoints[0] + m_matCoordSys.getZAxis() * m_Size.getDepth();
+
+ Vector3 vec(m_matCoordSys.getYAxis() * m_Size.getHeight());
+ m_pPoints[4] = m_pPoints[0] + vec;
+ m_pPoints[5] = m_pPoints[1] + vec;
+ m_pPoints[6] = m_pPoints[2] + vec;
+ m_pPoints[7] = m_pPoints[3] + vec;
+ }
+
+
+} //namespace ARSTD
diff --git a/ARSTD/ARSTD/Geometry/Line3.h b/ARSTD/ARSTD/Geometry/Line3.h
new file mode 100644
index 00000000..29731ccc
--- /dev/null
+++ b/ARSTD/ARSTD/Geometry/Line3.h
@@ -0,0 +1,83 @@
+// Copyright (c) 2005-2022 Andreas Rose. All rights reserved.
+// Released under the MIT license. (see license.txt)
+
+#pragma once
+
+
+#include "arstd/Math/Math.h"
+#include
+#include
+
+
+namespace ARSTD
+{
+
+ template
+ class Line3
+ {
+ public:
+ Line3(const Vector3& vecPointOnLine, const Vector3& vecDir);
+
+ explicit Line3(const Ray3& ray);
+
+ explicit Line3(const Segment3& segment);
+
+ template