From 2e151b87c6105e0d44da323cb0c6153826e649ce Mon Sep 17 00:00:00 2001 From: Hartmut Seichter Date: Sat, 5 Jan 2019 10:13:16 +0100 Subject: [PATCH] trying to find a consistent and C++1x styled graph representation --- CMakeLists.txt | 2 +- src/core/include/pw/core/log.hpp | 164 +++++++++++++++++ src/core/include/pw/core/timer.hpp | 57 ++++++ src/core/src/log.cpp | 204 +++++++++++++++++++++ src/core/src/timer.cpp | 41 +++++ src/scene/include/pw/scene/node.hpp | 18 +- src/scene/include/pw/scene/transform.hpp | 2 + src/scene/src/node.cpp | 38 ++-- src/scene/src/transform.cpp | 7 +- src/scene/tests/pwscene_test_node.cpp | 7 +- src/scene/tests/pwscene_test_traverser.cpp | 11 +- src/scripting/src/script_scene.cpp | 2 +- src/scripts/demos/simple_000.lua | 6 +- 13 files changed, 528 insertions(+), 31 deletions(-) create mode 100644 src/core/include/pw/core/log.hpp create mode 100644 src/core/include/pw/core/timer.hpp create mode 100644 src/core/src/log.cpp create mode 100644 src/core/src/timer.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index f304ab2..2b70f98 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,6 @@ cmake_minimum_required(VERSION 3.8) project(pixwerx) -set (CMAKE_CXX_STANDARD 14) +set (CMAKE_CXX_STANDARD 17) add_subdirectory(src) diff --git a/src/core/include/pw/core/log.hpp b/src/core/include/pw/core/log.hpp new file mode 100644 index 0000000..6a9a059 --- /dev/null +++ b/src/core/include/pw/core/log.hpp @@ -0,0 +1,164 @@ +/* + * Copyright (C) 1999-2017 Hartmut Seichter + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef PW_CORE_LOG_HPP_ +#define PW_CORE_LOG_HPP_ + +#include + +#include +#include + +namespace pw { + +class Log; + +/** + * @brief the streaming interface for the logger + */ +class LogStream { +public: + + + LogStream(Log* log = nullptr); + ~LogStream(); + LogStream(const LogStream& other); + + + LogStream &operator << (const bool &value); + LogStream &operator << (const char *value); + LogStream& operator << (const std::string& value); ///! log a string + + LogStream& operator << (const float &value); ///! log a float value + LogStream& operator << (const double &value); ///! log a double value + + LogStream& operator << (const int &value); ///! log a int value + LogStream& operator << (const unsigned int &value); ///! log a int value + + LogStream& operator << (const long &value); ///! log a long value + LogStream& operator << (const unsigned long &value); ///! log a int value + + LogStream& operator << (const void *value); ///! pointer + +protected: + + Log* _log; + std::string _line; +}; + +/** + * @brief multipurpose logger used internally + */ +class Log { +public: + + enum LogLevel { + kNone, //!< nothing will be logged, even no errors + kError, //!< only errors will be logged + kWarning, //!< log warnings (non-critical errors) + kMessage, //!< log messages (something to note but not an error) + kNotify, //!< log some more information + kInfo, //!< log verbose information + kAll = 0xFF //!< log absolutely everything + }; + + + /** sets the logging level */ + void setLevel(LogLevel level) {_level = level;} + + /** gets the logging level */ + LogLevel level() const { return _level; } + + /** + * @brief get the stream interface of the logger + * @return return a temporary object that will write and flush the logger + */ + static LogStream s(LogLevel level = kInfo); + + inline static LogStream d() { return s(Log::kInfo); } + inline static LogStream e() { return s(Log::kError); } + inline static LogStream w() { return s(Log::kWarning); } + + /** + * @brief returns the instance of the logger + * @return + */ + static Log& get(); + + /** + * @brief write a message to the log + * @param message string + */ + void write(const std::string &message); + + typedef std::function Callback; + typedef std::vector CallbackList; + +protected: + + Log(); + ~Log(); + + CallbackList _callbacks; + LogLevel _level; +}; + +/** + * @brief helper for changing the log level in a scope + */ +struct ScopeLogLevel +{ + Log::LogLevel levelOutside; + explicit ScopeLogLevel(Log::LogLevel level) + { + levelOutside = Log::get().level(); + Log::get().setLevel(level); + } + ~ScopeLogLevel() + { + Log::get().setLevel(levelOutside); + } +}; + +template +struct tpScopeLog { + const char* info; + explicit tpScopeLog(const char* i) : info(i) { + Log::s(level) << info; + } + + ~tpScopeLog() { + Log::s(level) << info; + } +}; + +// some macros + +#define LOG_INFO() Log::s() +#define LOG_FUNC() LOG_INFO() << __FUNCTION__ << " " << __LINE__ << " " +} + + +#endif diff --git a/src/core/include/pw/core/timer.hpp b/src/core/include/pw/core/timer.hpp new file mode 100644 index 0000000..2520d1a --- /dev/null +++ b/src/core/include/pw/core/timer.hpp @@ -0,0 +1,57 @@ +/* vim: set tabstop=4:softtabstop=4:shiftwidth=4:noexpandtab */ +/* + * SSTT - Simplified Spatial Target Tracker + * + * (c) Copyrights 2007-2018 Hartmut Seichter + */ + +#ifndef PW_CORE_TIMER_HPP_ +#define PW_CORE_TIMER_HPP_ + + +#include + +#include + +namespace pw { + +/** + * @brief A simple timer + */ +class timer { +public: + + const static unsigned int UnitMicroSeconds = 1000000; + const static unsigned int UnitMilliSeconds = 1000; + const static unsigned int UnitSeconds = 1; + + typedef std::chrono::time_point tick_t; + + timer(); /// c'tor + ~timer(); /// d'tor + + void reset(); /// reset the timer + + /** + * @brief elapsed time based on the scale + * @param scale units the time will be reported + * @return value of the time since last @see reset + */ + double elapsed(unsigned int scale = UnitMilliSeconds) const; + + /** + * @brief Now + * @param scale + * @return + */ + static double now(unsigned int scale = UnitMicroSeconds); + +protected: + + tick_t _start; +}; + +} + + +#endif diff --git a/src/core/src/log.cpp b/src/core/src/log.cpp new file mode 100644 index 0000000..a21bba6 --- /dev/null +++ b/src/core/src/log.cpp @@ -0,0 +1,204 @@ +/* vim: set tabstop=4:softtabstop=4:shiftwidth=4:noexpandtab */ +/* + * SSTT - Simplified Spatial Target Tracker + * + * (c) Copyrights 2007-2018 Hartmut Seichter + */ +#include "pw/core/log.hpp" + +#include +#include + +#include +#include + + +namespace pw { + +#if defined(ANDROID) + +#include + + +struct tpConsoleLog : tpLogCallback +{ + void operator()(const char* cstr) + { + __android_log_print(ANDROID_LOG_INFO, "libsstt", "%s", cstr); + } +}; + +#else +struct tpConsoleLog +{ + void operator()(const char* cstr) const + { + ::fputs(cstr,stdout); + ::fflush(stdout); + } +}; +#endif + + +struct tpFileLog { + FILE* m_file; + + tpFileLog() : m_file(fopen("libsstt.txt","a+")) + { + } + + ~tpFileLog() + { + if (m_file != nullptr) fclose(m_file); + } + + void operator()(const char* stuff) { + if (m_file) ::fputs(stuff,m_file); + } +}; + + + +Log::Log() : + _level(Log::kNotify) +{ +#if defined(_WINCE) + _callbacks.add(new tpFileLog()); +#else + _callbacks.push_back(tpConsoleLog()); +#endif + // drop some info + LogStream stream(this); + +// stream << "SSTT " << versionString(kVersionFull) << " " << std::thread::hardware_concurrency() << " threads"; + +} + +Log::~Log() +{ +} + +void Log::write(const std::string& message) +{ + for (CallbackList::iterator i = _callbacks.begin(); + i != _callbacks.end(); + ++i) + { + if (message.length()) (*i)(message.c_str()); + } +} + + +/* static */ +LogStream Log::s(Log::LogLevel level) { + return LogStream(&Log::get()); +} + +Log &Log::get() { + static Log the_log; + return the_log; +} + + +// +// tpLogStream +// + +LogStream::LogStream(Log *log) + : _log(log) +{ +// _line.append(std::to_string(Timer::now(Timer::UnitSeconds)) + " "); +} + +LogStream::~LogStream() +{ + _log->write(_line + "\n"); +} + +LogStream::LogStream(const LogStream &other) + : _log(other._log) + , _line(other._line) +{ +} + +LogStream &LogStream::operator <<(const bool &value) +{ + _line.append(value ? "true" : "false"); + return *this; +} + +LogStream &LogStream::operator <<(const char* value) +{ + _line.append(value); + return *this; +} + +LogStream &LogStream::operator <<(const std::string &value) +{ + _line.append(value); + return *this; +} + +LogStream &LogStream::operator <<(const float &value) +{ + std::stringstream ss; + ss << value; + (*this) << ss.str(); + + return *this; +} + +LogStream &LogStream::operator <<(const double &value) +{ + std::stringstream ss; + ss << value; + (*this) << ss.str(); + + return *this; +} + +LogStream &LogStream::operator <<(const int &value) +{ + std::stringstream ss; + ss << value; + (*this) << ss.str(); + + return *this; +} + +LogStream &LogStream::operator <<(const unsigned int &value) +{ + std::stringstream ss; + ss << value; + (*this) << ss.str(); + + return *this; +} + +LogStream &LogStream::operator <<(const long &value) +{ + std::stringstream ss; + ss << value; + (*this) << ss.str(); + + return *this; +} + +LogStream &LogStream::operator <<(const unsigned long &value) +{ + std::stringstream ss; + ss << value; + (*this) << ss.str(); + + return *this; +} + +LogStream &LogStream::operator <<(const void *value) +{ + std::stringstream ss; + ss << value; + (*this) << ss.str(); + + return *this; +} +} diff --git a/src/core/src/timer.cpp b/src/core/src/timer.cpp new file mode 100644 index 0000000..6f1e405 --- /dev/null +++ b/src/core/src/timer.cpp @@ -0,0 +1,41 @@ +/* vim: set tabstop=4:softtabstop=4:shiftwidth=4:noexpandtab */ +/* + * SSTT - Simplified Spatial Target Tracker + * + * (c) Copyrights 2007-2018 Hartmut Seichter + */ + +#include "pw/core/timer.hpp" + + +namespace pw { + +static timer global_timer; + +timer::timer() +{ + reset(); +} + +timer::~timer() +{ +} + +void timer::reset() +{ + _start = std::chrono::high_resolution_clock::now(); +} + +double timer::elapsed( unsigned int scale ) const +{ + std::chrono::duration elapsed_seconds = std::chrono::high_resolution_clock::now() - _start; + return elapsed_seconds.count() * scale; +} + +double timer::now( unsigned int scale ) +{ + return global_timer.elapsed(scale); +} + +} + diff --git a/src/scene/include/pw/scene/node.hpp b/src/scene/include/pw/scene/node.hpp index bf0c516..9d44f1d 100644 --- a/src/scene/include/pw/scene/node.hpp +++ b/src/scene/include/pw/scene/node.hpp @@ -31,6 +31,8 @@ namespace pw { +class transform; + /** * @brief nodes represent the structure for the scene graph * @@ -50,16 +52,16 @@ public: friend class component; //! standard c'tor - node(const std::string& name = ""); + node(); //! copy c'tor node(const node& node); //! d'tor - virtual ~node(); + ~node(); //! cloning interface - virtual ref clone(const unsigned short& copymode) const; + ref clone(const unsigned short& copymode) const; std::string name() const; //!< get name void set_name(const std::string &name); //!< set name @@ -68,7 +70,7 @@ public: inline ptr parent() const { return _path.back(); } //! add a child node - ref add_child(ref anode); + ref add_child(); //! remove a child void remove_child(ref child_node); @@ -89,7 +91,7 @@ public: const component::array& components() const; //! add a node component - void add_component(component::ref c); + void add_component(component::ref new_component); //! remove a node component void remove_component(component::ref c); @@ -111,6 +113,10 @@ public: } + const transform* transform() const { return _transform; } + class transform* transform() { return _transform; } + + protected: ref_array _children; //!< list of children @@ -118,6 +124,8 @@ protected: component::array _components; // namespace pw { -node::node(const std::string &name) - : _name(name) +node::node() { + // generate node-name from cache generate +// add_component(std::make_shared()); } node::node(const node &node) : _children(node.children()) + , _components(node.components()) , _name(node._name) { } @@ -28,21 +33,22 @@ void node::set_name(const std::string &name) _name = name; } -node::ref node::add_child(ref anode) +node::ref node::add_child() { - // remove old nodepath - anode->_path.clear(); + // create new node + node::ref new_node = std::make_shared(); // take parent nodepath ... - if (!this->is_root()) anode->_path = this->_path; + if (!this->is_root()) new_node->_path = this->_path; + // add itself - anode->_path.push_back(this); + new_node->_path.push_back(this); // add as child - _children.push_back(anode); + _children.push_back(new_node); // return - return anode; + return new_node; } void node::remove_child(ref child_node) @@ -62,9 +68,19 @@ node::~node() // // components // -void node::add_component(component::ref c) +void node::add_component(component::ref new_component) { - _components.push_back(c); + if (new_component->singular()) { + for (auto c : _components) { + if (typeid(c.get()) == typeid (new_component.get())) { + // warn and/or override? + c = new_component; + std::cout << "Meh!" << std::endl; + return; + } + } + } + _components.push_back(new_component); } void node::remove_component(component::ref c) diff --git a/src/scene/src/transform.cpp b/src/scene/src/transform.cpp index 47e1ad0..526ebda 100644 --- a/src/scene/src/transform.cpp +++ b/src/scene/src/transform.cpp @@ -1,12 +1,17 @@ #include "pw/scene/transform.hpp" +#include "pw/scene/node.hpp" namespace pw { - void transform::set_local(const matrix44 &local) { // TODO need to rebuild the transforms: both -> global down and global up _local = local; + + // update the global transform + if (_node && _node->parent() && _node->parent()->find()) { +// this->_global = _node->find()->_global * _local; + } } void transform::set_global(const matrix44 &global) diff --git a/src/scene/tests/pwscene_test_node.cpp b/src/scene/tests/pwscene_test_node.cpp index a065ed6..e9aee35 100644 --- a/src/scene/tests/pwscene_test_node.cpp +++ b/src/scene/tests/pwscene_test_node.cpp @@ -22,11 +22,12 @@ int main(int argc,char **argv) { using namespace pw; - node::ref n(new node("test")); + node::ref n = std::make_shared(); + n->set_name("root"); // check { - n->add_child(std::make_shared("sub")); + n->add_child()->set_name("node"); } std::cout << "n name: " << n->name() << std::endl; @@ -49,7 +50,7 @@ int main(int argc,char **argv) { print_node_path((n)); - auto t = n->find(); + auto t = n->transform(); if (t) std::cout << t->local().at(0,0) << std::endl; diff --git a/src/scene/tests/pwscene_test_traverser.cpp b/src/scene/tests/pwscene_test_traverser.cpp index eacc4eb..6eb30f8 100644 --- a/src/scene/tests/pwscene_test_traverser.cpp +++ b/src/scene/tests/pwscene_test_traverser.cpp @@ -40,13 +40,14 @@ int main(int argc,char **argv) { using namespace pw; - node::ref root(std::make_shared("root")); - root->add_child(std::make_shared("sub-1")); + node::ref root(std::make_shared()); + root->set_name("root"); + root->add_child()->set_name("sub-1"); - node::ref sub_2_1 = std::make_shared("sub-2-1"); +// node::ref sub_2_1 = std::make_shared("sub-2-1"); - root->add_child(std::make_shared("sub-3"))->add_child(sub_2_1); - root->add_child(std::make_shared("sub-2"))->add_child(std::make_shared("sub-2-2")); +// root->add_child(std::make_shared("sub-3"))->add_child(sub_2_1); +// root->add_child(std::make_shared("sub-2"))->add_child(std::make_shared("sub-2-2")); // std::cout << "sub-2-1 parent count: " << sub_2_1->parents().size() << std::endl; diff --git a/src/scripting/src/script_scene.cpp b/src/scripting/src/script_scene.cpp index c4c5faa..eda1d87 100644 --- a/src/scripting/src/script_scene.cpp +++ b/src/scripting/src/script_scene.cpp @@ -8,7 +8,7 @@ void script_scene::load(sol::table &ns) { ns.new_usertype("node", - sol::constructors(), + sol::constructors(), "add_child",&node::add_child, "children",sol::readonly_property(&node::children), "child_count",sol::readonly_property(&node::child_count), diff --git a/src/scripts/demos/simple_000.lua b/src/scripts/demos/simple_000.lua index 41c3016..ad1348d 100644 --- a/src/scripts/demos/simple_000.lua +++ b/src/scripts/demos/simple_000.lua @@ -39,12 +39,10 @@ local aa = pw.axisangle.new(v1,0.707) print("aa.axis",aa.axis.x,aa.axis.y,aa.axis.z) print("aa.angle",aa.angle) - -local n_1 = pw.node.new("node-1") -local n_2 = pw.node.new("node-2") +local n_1 = pw.node.create() +n_1.name = "root" print("node 1: ", n_1.name) -print("node 2: ", n_2.name) --print(pw.node.create())