From 5e3a2492c7bb73daa4e27398daaf490d09980ff3 Mon Sep 17 00:00:00 2001 From: Jon Santmyer Date: Wed, 22 Jun 2022 17:41:59 -0400 Subject: Base system viewer with data loaded from csv files --- include/camera.hpp | 96 +++++++++++++ include/csv.hpp | 115 ++++++++++++++++ include/ecs.hpp | 139 +++++++++++++++++++ include/entitycomponents.hpp | 58 ++++++++ include/game.hpp | 52 ++++++++ include/input.hpp | 71 ++++++++++ include/keybind.hpp | 71 ++++++++++ include/shape.hpp | 197 +++++++++++++++++++++++++++ include/straw.hpp | 312 +++++++++++++++++++++++++++++++++++++++++++ include/system.hpp | 82 ++++++++++++ include/timeman.hpp | 27 ++++ include/units.hpp | 166 +++++++++++++++++++++++ include/util.hpp | 45 +++++++ include/vex.hpp | 104 +++++++++++++++ include/window.hpp | 69 ++++++++++ 15 files changed, 1604 insertions(+) create mode 100644 include/camera.hpp create mode 100644 include/csv.hpp create mode 100644 include/ecs.hpp create mode 100644 include/entitycomponents.hpp create mode 100644 include/game.hpp create mode 100644 include/input.hpp create mode 100644 include/keybind.hpp create mode 100644 include/shape.hpp create mode 100644 include/straw.hpp create mode 100644 include/system.hpp create mode 100644 include/timeman.hpp create mode 100644 include/units.hpp create mode 100644 include/util.hpp create mode 100644 include/vex.hpp create mode 100644 include/window.hpp (limited to 'include') diff --git a/include/camera.hpp b/include/camera.hpp new file mode 100644 index 0000000..9a8bc00 --- /dev/null +++ b/include/camera.hpp @@ -0,0 +1,96 @@ +#ifndef CAMERA_HPP +#define CAMERA_HPP 1 + +#include "vex.hpp" +#include "shape.hpp" +#include "straw.hpp" + +#include +#include +#include + +class Camera; +struct RenderBatchEntry { + shapes::shapes_variant shape; + straw::color fg, bg; + char c; + + template + constexpr RenderBatchEntry(T Shape) : shape(Shape), fg(straw::WHITE), bg(straw::BLACK), c('#') {} + template + constexpr RenderBatchEntry(T Shape, char C) : shape(Shape), fg(straw::WHITE), bg(straw::BLACK), c(C) {} + template + constexpr RenderBatchEntry(T Shape, straw::color Fg, char C) : shape(Shape), fg(Fg), bg(straw::BLACK), c(C) {} + template + constexpr RenderBatchEntry(T Shape, straw::color Fg, straw::color Bg, char C) : shape(Shape), fg(Fg), bg(Bg), c(C) {} + + void translate(Camera *camera); + void plot(Camera *camera); +private: + void plotPoint(shapes::point point, Camera *camera); + void plotLine(shapes::line line, Camera *camera); + void plotRectangle(shapes::rectangle rectangle, Camera *camera); + void plotCircle(shapes::circle circle, Camera *camera); + void plotEllipse(shapes::ellipse ellipse, Camera *camera); +}; + +class Camera +{ + friend struct RenderBatchEntry; + + vex::vec2 m_position; + vex::vec2 m_origin; + shapes::rectangle m_frustum; + + std::vector m_shapeBatch; + + long m_scale; + bool m_dirty; + + straw::screen *m_viewport; + + void updateFrustum(); + + template + void translateShape(T &shape); +public: + Camera(straw::screen *viewport) : + m_position(0, 0), + m_origin(0, 0), + m_frustum(0, 0, 0, 0), + m_scale(16384), + m_dirty(true), + m_viewport(viewport) {} + ~Camera() {} + + constexpr long getscale() const { return m_scale; } + constexpr vex::vec2 getpos() const { return m_position; } + constexpr vex::vec2 getorigin() const { return m_origin; } + + constexpr bool dirty() const { return m_dirty; } + void markDirty() { m_dirty = true; } + + void zoom(long by) { m_scale = std::max((unsigned)((int)m_scale + by), (unsigned)1); m_dirty = true; } + void setscale(long scale) { m_scale = std::max(scale, (long)1); m_dirty = true; } + + void move(const vex::vec2 &pos) { m_position += pos; m_dirty = true; } + void move(long x, long y) { move(vex::vec2(x, y)); } + + void setpos(const vex::vec2 &pos) { m_position = pos; m_dirty = true; } + void setpos(long x, long y) { setpos(vex::vec2(x, y)); } + + void setorigin(const vex::vec2 &origin) { m_origin = origin; m_dirty = true; } + + template + void batchShape(T shape) { m_shapeBatch.emplace_back(shape); } + template + void batchShape(T shape, char c) { m_shapeBatch.emplace_back(shape, c); } + template + void batchShape(T shape, straw::color fg, char c) { m_shapeBatch.emplace_back(shape, fg, c); } + template + void batchShape(T shape, straw::color fg, straw::color bg, char c) { m_shapeBatch.emplace_back(shape, fg, bg, c); } + + void draw(); +}; + +#endif diff --git a/include/csv.hpp b/include/csv.hpp new file mode 100644 index 0000000..18e30b0 --- /dev/null +++ b/include/csv.hpp @@ -0,0 +1,115 @@ +#ifndef CSV_HPP +#define CSV_HPP 1 + +#include +#include +#include +#include +#include +#include + +namespace csv { + +template +struct csv_delim : std::ctype { + csv_delim() : std::ctype(get_table()) {} + static mask const *get_table() { + static mask rc[table_size]; + rc[T] = std::ctype_base::space; + rc['\n'] = std::ctype_base::space; + return &rc[0]; + } +}; + +template +class CSVFile { +public: + struct CSVLine { + std::tuple data; + + CSVLine(const std::string &line) { + std::istringstream in(line); + in.imbue(std::locale(std::locale(), new csv_delim)); + read_elements(in, std::make_index_sequence{}); + } + + template + void read_elements(std::istream &in, std::index_sequence) { + std::initializer_list{read_element(in, std::get(data))...}; + } + + template + bool read_element(std::istream &in, T &value) { + in >> value; return true; + } + }; + struct Reader { + private: + std::vector m_lines; + public: + Reader() {} + Reader(CSVFile *parent) { + for(std::string line; std::getline(parent->m_rfile, line);) { + m_lines.emplace_back(line); + } + } + std::vector> get() const { + std::vector> r; + for(auto &line : m_lines) r.push_back(line.data); + return r; + } + + }; + struct Writer { + private: + std::vector> m_data; + public: + void put(std::tuple line) { m_data.push_back(line); } + void write(CSVFile *parent) { + for(auto &line : m_data) { + write_line(parent, line, std::make_index_sequence{}); + parent->m_wfile.seekp(-1, std::ios_base::end); + parent->m_wfile << "\n"; + } + } + template + void write_line(CSVFile *parent, std::tuple line, std::index_sequence) { + std::initializer_list{write_element(parent, std::get(line))...}; + } + template + bool write_element(CSVFile *parent, T &value) { + parent->m_wfile << value << Seperator; return true; + } + }; + + friend struct Reader; + friend struct Writer; + + CSVFile(const std::string &path, bool write = false) { + //std::ios_base::iostate emask = m_file.exceptions() | std::ios::failbit; + if(!write) { + m_rfile.open(path); + m_reader = Reader(this); + }else{ + m_wfile.open(path); + } + } + ~CSVFile() { m_rfile.close(); m_wfile.close(); } + + const std::tuple operator[](std::size_t i) { return m_reader.m_lines[i].data; } + std::size_t size() const { return m_reader.m_lines.size(); } + + std::vector> get() const { return m_reader.get(); } + void put(std::tuple vals) { m_writer.put(vals); } + void write() { m_writer.write(this); } + +protected: + std::ifstream m_rfile; + std::ofstream m_wfile; + Reader m_reader; + Writer m_writer; +}; + +} + +#endif diff --git a/include/ecs.hpp b/include/ecs.hpp new file mode 100644 index 0000000..ab5e2b2 --- /dev/null +++ b/include/ecs.hpp @@ -0,0 +1,139 @@ +#ifndef ECS_HPP +#define ECS_HPP 1 + +#include "entitycomponents.hpp" +#include "util.hpp" +#include +#include +#include +#include +#include +#include +#include + +namespace ecs { + +struct ComponentContainer { + std::vector packed{}; + std::vector sparse{}; + std::queue free{}; + + void resize(size_t n) { sparse.resize(n, -1); } + + template + void insert(unsigned id, const T &c) { + assert(sparse.size() > id); + if(free.empty()) { + sparse[id] = (int)packed.size(); + packed.push_back(c); + }else { + sparse[id] = (int)free.front(); + packed[sparse[id]] = c; + free.pop(); + } + } + + void remove(unsigned id) { + assert(sparse.size() > id); + if(sparse[id] > -1) { + free.push((unsigned)sparse[id]); + } + sparse[id] = -1; + } + + template + T &reduce(unsigned id) { + assert(sparse.size() > id); + assert(sparse[id] > -1); + return std::get(packed[sparse[id]]); + } +}; + +class EntityMan; +struct Entity { + EntityMan *man; + component_sig sig{}; + unsigned id; + + Entity(const Entity &e) = default; + Entity(EntityMan *Man, unsigned Id) : + man(Man), sig(0), id(Id) {} + + + template + constexpr bool contains() { return sig.test(get_index()); } + + template + T &get(); + + template + Entity &addComponent(const T &component); +}; + +class EntityMan { + std::array> m_components; + std::vector m_entities; + std::queue m_free; +public: + Entity &operator[](std::size_t i) { return m_entities[i]; } + + Entity newEntity() { + std::size_t newid = 0; + if(!m_free.empty()) { + newid = m_free.front(); + m_free.pop(); + }else{ + newid = m_entities.size(); + m_entities.emplace_back(this, newid); + for(auto &container : m_components) container.resize(m_entities.size()); + } + return m_entities[newid]; + } + + void deleteEntity(Entity &e) { + for(auto &container : m_components) container.remove(e.id); + e.sig.reset(); + m_free.push(e.id); + } + + template + T &get(const Entity &e) { + constexpr unsigned cid = get_index(); + return m_components[cid].reduce(e.id); + } + + template + auto getWith() { + constexpr unsigned cid = get_index(); + auto e_hc = [](Entity const e) { return e.sig[cid]; }; + return std::ranges::views::filter(m_entities, e_hc); + } + + std::span all() { + return std::span(m_entities.begin(), m_entities.end()); + } + + std::size_t size() { return m_entities.size(); } + + template + Entity &addComponent(Entity &entity, const T& component) { + constexpr unsigned cid = get_index(); + m_components[cid].insert(entity.id, component); + m_entities[entity.id].sig[cid] = 1; + return entity; + } +}; + +template +T &Entity::get() { + return man->get(*this); +} + +template +Entity &Entity::addComponent(const T& component) { + return man->addComponent(*this, component); +} + +} + +#endif diff --git a/include/entitycomponents.hpp b/include/entitycomponents.hpp new file mode 100644 index 0000000..a263ebf --- /dev/null +++ b/include/entitycomponents.hpp @@ -0,0 +1,58 @@ +#ifndef ENTITY_COMPONENT_HPP +#define ENTITY_COMPONENT_HPP 1 + +#include "vex.hpp" +#include "units.hpp" +#include + +namespace ecs { +struct PositionComponent { + vex::vec2 position{}; +}; + +struct VelocityComponent { + vex::vec2 velocity{}; +}; + +struct MassComponent { + unit::Mass mass; +}; + +struct NameComponent { + std::string name; +}; + +struct OrbitalComponent { + unsigned origin; + long a; + double e; + double w; + double M; + double T; + double v; +}; + +struct RenderCircleComponent { + unsigned radius; +}; + +using component_variant = std::variant< + std::monostate, + PositionComponent, + VelocityComponent, + MassComponent, + NameComponent, + OrbitalComponent, + RenderCircleComponent +>; + +using component_sig = + std::bitset>; + +template +concept component_type = + is_variant_v; + +} + +#endif diff --git a/include/game.hpp b/include/game.hpp new file mode 100644 index 0000000..9454318 --- /dev/null +++ b/include/game.hpp @@ -0,0 +1,52 @@ +#ifndef GAME_HPP +#define GAME_HPP 1 + +#include "window.hpp" +#include "camera.hpp" +#include "ecs.hpp" +#include "system.hpp" +#include "timeman.hpp" +#include "input.hpp" + +#include + +#define WINCTX_GAME "Game" + +class Game +{ +public: + enum class State { + STOPPED, RUNNING, RUNNING_INPUT, PAUSED, PAUSED_INPUT + }; + + static void setup(unsigned w, unsigned h); + static void cleanup(); + + static void turn(); + static void setState(State state) { m_state = state; } + static void setContext(const std::string &id) { m_currentContext = id; } + + static bool running() { return m_state != State::STOPPED; } + static bool paused() { return m_state == State::PAUSED || m_state == State::PAUSED_INPUT; } + static bool inputMode() { return m_state == State::RUNNING_INPUT || m_state == State::PAUSED_INPUT; } + + struct WindowContexts { + WindowContext &operator[](const std::string &id) { return Game::m_contexts.at(id); } + WindowContext &operator()() { return Game::m_contexts.at(Game::m_currentContext); } + }; + static WindowContexts contexts; +private: + static std::unordered_map m_contexts; + static std::string m_currentContext; + + static std::unique_ptr m_camera; + static std::unique_ptr m_system; + static SystemView m_systemView; + + static input::Context m_inputContext; + + static double m_delta; + static State m_state; +}; + +#endif diff --git a/include/input.hpp b/include/input.hpp new file mode 100644 index 0000000..ed5155c --- /dev/null +++ b/include/input.hpp @@ -0,0 +1,71 @@ +#ifndef INPUT_HPP +#define INPUT_HPP 1 + +namespace input +{ + +enum extkeys { + CTRL_RANGE_START = 256, + CTRL_KEY_ARROWUP = 321, + CTRL_KEY_ARROWDOWN, + CTRL_KEY_ARROWRIGHT, + CTRL_KEY_ARROWLEFT, + CTRL_KEY_END = 326, + CTRL_KEY_HOME = 328, + CTRL_KEY_PAGEUP, + CTRL_KEY_PAGEDOWN +}; + +#ifdef __unix__ +#include +#include + +class Context +{ + struct termios m_termold; + struct termios m_termnow; +public: + Context() { + tcgetattr(STDIN_FILENO, &m_termold); + m_termnow = m_termold; + } + ~Context() { + tcsetattr(STDIN_FILENO, TCSADRAIN, &m_termold); + } + + void echo(bool mode) { + if(mode){ + m_termnow.c_lflag |= ECHO; + }else{ + m_termnow.c_lflag &= ~ECHO; + } + tcsetattr(STDIN_FILENO, TCSANOW, &m_termnow); + } + + void canon(bool mode) { + if(mode) { + m_termnow.c_lflag |= ICANON; + }else{ + m_termnow.c_lflag &= ~ICANON; + } + tcsetattr(STDIN_FILENO, TCSANOW, &m_termnow); + } + + void cbreak(bool mode) { + if(mode){ + m_termnow.c_cc[VMIN] = m_termold.c_cc[VMIN]; + m_termnow.c_cc[VTIME] = m_termold.c_cc[VTIME]; + }else{ + m_termnow.c_cc[VMIN] = 1; + m_termnow.c_cc[VTIME] = 0; + } + tcsetattr(STDIN_FILENO, TCSANOW, &m_termnow); + } +}; + +#endif + +extern int getcode(); +} + +#endif diff --git a/include/keybind.hpp b/include/keybind.hpp new file mode 100644 index 0000000..6541a21 --- /dev/null +++ b/include/keybind.hpp @@ -0,0 +1,71 @@ +#ifndef KEYBIND_HPP +#define KEYBIND_HPP 1 + +#include +#include +#include +#include + +#define CTX_GLOBAL "Global" +#define CTX_SYSTEMVIEW "System View" +#define CTX_TIMEMAN "Time Manager" + +#define BIND_G_QUIT "G_Quit" +#define BIND_G_NEXTWIN "G_NextWindow" +#define BIND_G_PREVWIN "G_PrevWindow" +#define BIND_G_EDITBINDS "G_EditBinds" +#define BIND_G_ESCAPE "G_Escape" +#define BIND_G_SELECT "G_Select" + +#define BIND_SYSTEMVIEW_PANUP "Systemview_PanUp" +#define BIND_SYSTEMVIEW_PANDOWN "Systemview_PanDown" +#define BIND_SYSTEMVIEW_PANLEFT "Systemview_PanLeft" +#define BIND_SYSTEMVIEW_PANRIGHT "Systemview_PanRight" +#define BIND_SYSTEMVIEW_DECSCALE "Systemview_DecScale" +#define BIND_SYSTEMVIEW_INCSCALE "Systemview_IncScale" +#define BIND_SYSTEMVIEW_SEARCH "Systemview_Search" + +#define BIND_SYSTEMVIEW_SEARCH_PREV "Systemview_Search_Prev" +#define BIND_SYSTEMVIEW_SEARCH_NEXT "Systemview_Search_Next" +#define BIND_SYSTEMVIEW_SEARCH_TOP "Systemview_Search_Top" +#define BIND_SYSTEMVIEW_SEARCH_BOTTOM "Systemview_Search_Bottom" +#define BIND_SYSTEMVIEW_SEARCH_COLLAPSE "Systemview_Search_Collapse" + +#define BIND_TIMEMAN_STEP "Timeman_Step" +#define BIND_TIMEMAN_INCSTEP "Timeman_IncStep" +#define BIND_TIMEMAN_DECSTEP "Timeman_DecStep" +#define BIND_TIMEMAN_TOGGLEAUTO "Timeman_ToggleAuto" + +class KeyMan { +public: + struct Bind { + int code; + std::string name; + std::string ctx; + std::string desc; + }; + + struct Binds { + std::vector operator()() { + std::vector bindList; + std::transform( + KeyMan::m_keybinds.begin(), + KeyMan::m_keybinds.end(), + std::back_inserter(bindList), [](auto &pair){return pair.second;}); + return bindList; + } + Bind &operator[](const std::string &name) { return KeyMan::m_keybinds[name]; } + }; + static Binds binds; + + static void registerBind(int def, const std::string &name, const std::string &context, const std::string &desc); + static void loadKeybindsFrom(const std::string &csvPath); + static void writeKeybindsTo(const std::string &csvPath); + static std::string translateCode(int code); + +private: + static std::unordered_map m_keybinds; + static std::unordered_map m_keybindContexts; +}; + +#endif diff --git a/include/shape.hpp b/include/shape.hpp new file mode 100644 index 0000000..0d9db96 --- /dev/null +++ b/include/shape.hpp @@ -0,0 +1,197 @@ +#ifndef SHAPE_HPP +#define SHAPE_HPP 1 + +#include "vex.hpp" +#include +#include + +namespace shapes { + +template +struct shape +{ + vex::vec2 position; + + constexpr shape(const vex::vec2 p) : position(p) {} + constexpr shape(T x, T y) : position(x, y) {} + + virtual void scale(T by) = 0; + virtual void translate(vex::vec2 by) { position += by; } +}; + +template +struct point : public shape +{ + constexpr point(T x, T y) : shape(vex::vec2(x, y)) {} + constexpr point(const vex::vec2 &pos) : shape(pos) {} + + void scale(T by) override { (void)by; } +}; + +template +struct line : public shape +{ + vex::vec2 end; + constexpr line(T x, T y, T z, T w) : shape(vex::vec2(x, y)), end(z, w){} + constexpr line(const vex::vec2 &pos, const vex::vec2 End) : shape(pos), end(End) {} + + void translate(vex::vec2 by) + { + this->position += by; + end += by; + } + void scale(T by) override { + end = vex::vec2( + (T)std::floor((double)end[0] / (double)by), + (T)std::floor((double)end[1] / (double)by)); + } +}; + +template +struct circle : public shape +{ + T radius; + constexpr circle(T x, T y, T r) : shape(vex::vec2(x, y)), radius(r) {} + constexpr circle(const vex::vec2 &pos, T r) : shape(pos), radius(r) {} + + void scale(T by) override { radius /= by; } +}; + +template +struct ellipse : public shape +{ + T a, b; + constexpr ellipse(T x, T y, T A, T B) : shape(x, y), a(A), b(B) {} + constexpr ellipse(const vex::vec2 &pos, T A, T B) : shape(pos), a(A), b(B) {} + + void scale(T by) override {a /= by; b /= by; } +}; + +template +struct rectangle : public shape +{ + vex::vec2 bounds; + constexpr rectangle(T x, T y, T w, T h) : shape(vex::vec2(x, y)), bounds(w, h) {} + constexpr rectangle(const vex::vec2 &pos, const vex::vec2 &wh) : shape(pos), bounds(wh) {} + + void scale(T by) override { bounds /= by; } +}; + +template +using shapes_variant = std::variant< + point, line, circle, ellipse, rectangle +>; + +template +static bool +intersects(const circle &lhs, const point &rhs) +{ + vex::vec2 dist = rhs.position - lhs.position; + //std::cout << dist.magnitude() << ' ' << lhs.radius << ' ' << dist.magnitude() - lhs.radius << std::endl; + return dist.magnitude() < lhs.radius; +} +template +static bool intersects(const point &lhs, const circle &rhs) { return intersects(rhs, lhs); } + +template +static bool +intersects(const ellipse &lhs, const point &rhs) +{ + auto ds = lhs.position - rhs.position; + auto d2 = ds * ds; + L a2 = lhs.a * lhs.a; + L b2 = lhs.b * lhs.b; + + return (((double)d2[0] / a2) + ((double)d2[1] / b2)) <= 1; +} +template +static bool intersects(const point &lhs, const ellipse &rhs) { return intersects(rhs, lhs); } + +template +static bool +intersects(const rectangle &lhs, const point &rhs) +{ + vex::vec2 corner = lhs.position + lhs.bounds; + return (rhs.position[0] > lhs.position[0] && rhs.position[0] < corner[0] && + rhs.position[1] > lhs.position[1] && rhs.position[1] < corner[1]); +} +template +static bool intersects(const point &lhs, const rectangle &rhs) { return intersects(rhs, lhs); } + +template +static bool +intersects(const line &lhs, const line &rhs) +{ + double x1 = lhs.position[0], x2 = lhs.end[0], x3 = rhs.position[0], x4 = rhs.end[0]; + double y1 = lhs.position[1], y2 = lhs.end[1], y3 = rhs.position[1], y4 = rhs.end[1]; + double uA = ((x4-x3)*(y1-y3) - (y4-y3)*(x1-x3)) / ((y4-y3)*(x2-x1) - (x4-x3)*(y2-y1)); + double uB = ((x2-x1)*(y1-y3) - (y2-y1)*(x1-x3)) / ((y4-y3)*(x2-x1) - (x4-x3)*(y2-y1)); + + if(uA >= 0 && uA <= 1 && uB >= 0 && uB <= 1) return true; + return false; +} + +template +static bool +intersects(const rectangle &lhs, const line &rhs) +{ + vex::vec2 corner = lhs.position + lhs.bounds; + line l(lhs.position, lhs.position + vex::vec2(0, lhs.bounds[1])); + line r(lhs.position + vex::vec2(lhs.bounds[0], 0), corner); + line d(lhs.position, lhs.position + vex::vec2(lhs.bounds[0], 0)); + line u(lhs.position + vex::vec2(0, lhs.bounds[1]), corner); + + if(intersects(rhs, l) || intersects(rhs, r) || intersects(rhs, d) || intersects(rhs, u)) return true; + return (rhs.position[0] > lhs.position[0] && rhs.position[0] < corner[0] && + rhs.position[1] > lhs.position[1] && rhs.position[1] < corner[1]) && + (rhs.end[0] > lhs.position[0] && rhs.end[0] < corner[0] && + rhs.end[1] > lhs.position[1] && rhs.end[1] < corner[1]); +} +template +static bool intersects(const line &lhs, const rectangle &rhs) { return intersects(rhs, lhs); } + +template +static bool +intersects(const rectangle &lhs, const circle &rhs) +{ + vex::vec2 dist{ + rhs.position[0] - std::max(lhs.position[0], std::min(rhs.position[0], lhs.position[0] + lhs.bounds[0])), + rhs.position[1] - std::max(lhs.position[1], std::min(rhs.position[1], lhs.position[1] + lhs.bounds[1])), + }; + return (dist[0] * dist[0]) + (dist[1] * dist[1]) < (rhs.radius * rhs.radius); +} +template +static bool intersects(const circle &lhs, const rectangle &rhs) { return intersects(rhs, lhs); } + +template +static bool +intersects(const rectangle &lhs, const ellipse &rhs) +{ + vex::vec2 dist{ + rhs.position[0] - std::max(lhs.position[0], std::min(rhs.position[0], lhs.position[0] + lhs.bounds[0])), + rhs.position[1] - std::max(lhs.position[1], std::min(rhs.position[1], lhs.position[1] + lhs.bounds[1])), + }; + vex::vec2 ab2 { + std::max(1, rhs.a * rhs.a), + std::max(1, rhs.b * rhs.b) + }; + return ((dist[0] * dist[0]) / ab2[0]) + ((dist[1] * dist[1]) / ab2[1]) <= 1.0; +} +template +static bool intersects(const ellipse &lhs, const rectangle &rhs) { return intersects(rhs, lhs); } + +template +static bool +intersects(const rectangle &lhs, const rectangle &rhs) +{ + return ( + (lhs.position[0] < rhs.position[0] + rhs.bounds[0]) && + (lhs.position[0] + lhs.bounds[0] > rhs.position[0]) && + (lhs.position[1] + lhs.bounds[1] < rhs.position[1]) && + (lhs.position[1] > rhs.position[1] + rhs.position[1]) + ); +} + +} + +#endif diff --git a/include/straw.hpp b/include/straw.hpp new file mode 100644 index 0000000..c147b06 --- /dev/null +++ b/include/straw.hpp @@ -0,0 +1,312 @@ +#ifndef STRAW_HPP +#define STRAW_HPP 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace straw +{ + +struct color { + std::uint8_t r{}, g{}, b{}; + constexpr color(std::uint8_t R, std::uint8_t G, std::uint8_t B) : r(R), g(G), b(B) {} + constexpr color(std::uint8_t A) : r(A), g(A), b(A) {} + + constexpr uint32_t single() { return (uint32_t)r << 16 | (uint32_t)g << 8 | (uint32_t)b; } + + constexpr bool operator==(const color &o) const = default; +}; + +static constexpr color WHITE{255, 255, 255}; +static constexpr color BLACK{0, 0, 0}; + +struct attribs { + color bg{0, 0, 0}, fg{255, 255, 255}; + bool bold, underline; + constexpr attribs() = default; + constexpr attribs(color Fg) : fg(Fg) {} + constexpr attribs(color Bg, color Fg) : bg(Bg), fg(Fg) {} + constexpr attribs(color Bg, color Fg, bool B, bool U) : bg(Bg), fg(Fg), bold(B), underline(U) {} + + constexpr bool operator==(const attribs &o) const = default; +}; + +template +concept char_type = std::integral; + +template +struct cell { + chartype chr{}; + attribs attr{}; + + constexpr cell() = default; + constexpr cell(chartype Chr) : chr(Chr) {} + constexpr cell(chartype Chr, color Fg) : chr(Chr), attr(Fg) {} + constexpr cell(chartype Chr, color Bg, color Fg) : chr(Chr), attr(Bg, Fg) {} + constexpr cell(chartype Chr, color Bg, color Fg, bool B, bool U) : chr(Chr), attr(Bg, Fg, B, U) {} + constexpr cell(chartype Chr, attribs Attr) : chr(Chr), attr(Attr) {} + + constexpr bool operator==(const cell &o) const = default; +}; + +const std::string ANSI_ESCAPE = "\E["; +static void ANSI_MOVE(unsigned x, unsigned y) { std::cout << ANSI_ESCAPE << y+1 << ';' << x+1 << 'H' << std::flush; } +static void ANSI_COLOR_FG(color c) { std::cout << ANSI_ESCAPE << "38;2;" << (unsigned)c.r << ';' << (unsigned)c.g << ';' << (unsigned)c.b << 'm' << std::flush; } +static void ANSI_COLOR_BG(color c) { std::cout << ANSI_ESCAPE << "48;2;" << (unsigned)c.r << ';' << (unsigned)c.g << ';' << (unsigned)c.b << 'm' << std::flush; } + +class screen_command_base {}; + +template +class screen { +public: + explicit screen(unsigned X, unsigned Y, unsigned W, unsigned H, chartype C, color B, color F) : + m_x(X), m_y(Y), m_width(W), m_height(H), m_front(W * H, cell{C, B, F}), m_back(m_front), + m_cursorAttribs(B,F), m_fillChar(C) + { + redraw(); + } + + explicit screen(unsigned X, unsigned Y, unsigned W, unsigned H, chartype C) : + screen(X, Y, W, H, C, color{0, 0, 0}, color{255, 255, 255}) {} + explicit screen(unsigned X, unsigned Y, unsigned W, unsigned H) : + screen(X, Y, W, H, ' ') {} + + constexpr void setcursorxy(unsigned x, unsigned y) { m_cursorX = x; m_cursorY = y; } + constexpr void setcursorfg(uint8_t r, uint8_t g, uint8_t b) { m_cursorAttribs.fg = color{r, g, b}; } + constexpr void setcursorbg(uint8_t r, uint8_t g, uint8_t b) { m_cursorAttribs.bg = color{r, g, b}; } + constexpr void setcursorfg(color c) { m_cursorAttribs.fg = c; } + constexpr void setcursorbg(color c) { m_cursorAttribs.bg = c; } + constexpr void setcursorbold(bool bold) { m_cursorAttribs.bold = bold; } + constexpr void setcursorunderline(bool underline) { m_cursorAttribs.underline = underline; } + + constexpr unsigned getcursorx() { return m_cursorX; } + constexpr unsigned getcursory() { return m_cursorY; } + constexpr unsigned getx() { return m_x; } + constexpr unsigned gety() { return m_y; } + constexpr unsigned getwidth() { return m_width; } + constexpr unsigned getheight() { return m_height; } + + void clear(const chartype c) { std::fill(m_front.begin(), m_front.end(), cell{c, m_cursorAttribs}); } + + void clearrow(unsigned y, const chartype c) { + assert(y < m_height); + std::fill(m_front.begin() + (y * m_width), + m_front.begin() + (y * m_width) + m_width, + cell{c, m_cursorAttribs}); + } + + void scroll() { + m_cursorY = m_height - 1; + std::copy(m_front.begin() + m_width, m_front.end(), m_front.begin()); + std::fill(m_front.end() - m_width, m_front.end(), cell{m_fillChar, m_cursorAttribs}); + } + + void setc(unsigned x, unsigned y, chartype c) { + assert(x < m_width); + assert(y < m_height); + m_front[x + (y * m_width)] = cell{c, m_cursorAttribs}; + } + + void putc(chartype c){ + if(m_cursorY == m_height) { + scroll(); + } + switch(c) { + case '\n': + m_cursorX = 0; m_cursorY++; + break; + default: + (*this)[m_cursorY][m_cursorX++] = + cell{c, m_cursorAttribs}; + break; + } + if(m_cursorX == m_width) { + m_cursorY++; + m_cursorX = 0; + } + } + + void puts(const std::basic_string &s){ + for(const chartype &c : s) this->putc(c); + } + + void redraw() { + attribs cattr = (*this)[0][0].attr; + ANSI_COLOR_BG(cattr.bg); + ANSI_COLOR_FG(cattr.fg); + for(unsigned y = 0; y < m_height; y++) { + ANSI_MOVE(m_x, m_y + y); + for(cell c : (*this)[y]) { + if(cattr != c.attr) { + cattr = c.attr; + ANSI_COLOR_FG(cattr.fg); + ANSI_COLOR_BG(cattr.bg); + } + std::cout << c.chr; + } + std::cout.clear(); + } + m_back = m_front; + } + + void flush() { + attribs currAttr = m_front[0].attr; + ANSI_COLOR_FG(currAttr.fg); + ANSI_COLOR_BG(currAttr.bg); + for(unsigned y = 0; y < m_height; y++) { + auto backspan = std::span>( + m_back.begin() + (y * m_width), + m_back.begin() + (y * m_width) + m_width); + auto frontspan = (*this)[y]; + bool change = false; + if(std::equal(backspan.begin(), backspan.end(), frontspan.begin(), frontspan.end())) continue; + for(unsigned x = 0; x < m_width; x++) { + cell c = frontspan[x]; + if(c == backspan[x]) continue; + ANSI_MOVE(x + m_x, y + m_y); + if(c.attr != currAttr) { + ANSI_COLOR_FG(c.attr.fg); + ANSI_COLOR_BG(c.attr.bg); + currAttr = c.attr; + } + change = true; + std::cout << c.chr; + } + if(change) std::cout.clear(); + } + m_back = m_front; + } + + std::span> operator[](std::size_t i) { + assert(i < m_width * m_height); + return std::span>( + m_front.begin() + (i * m_width), + m_front.begin() + (i * m_width) + m_width); + } + + template + requires(!std::is_base_of::value) + friend screen &operator<<(screen &o, const T &rhs) { + std::basic_stringstream ss; + ss << rhs; + o.puts(ss.str()); + return o; + } + +private: + unsigned m_x{}, m_y{}; + unsigned m_width{}, m_height{}; + + std::vector> m_front; + std::vector> m_back; + + unsigned m_cursorX{}, m_cursorY{}; + attribs m_cursorAttribs; + chartype m_fillChar; +}; + +struct screen_command_flush : public screen_command_base { + explicit screen_command_flush() = default; + template + friend screen &operator<<(screen &o, const screen_command_flush &cmd) { + (void)cmd; + o.flush(); + return o; + } +}; +[[nodiscard]] static screen_command_flush flush() { return screen_command_flush{}; } + +struct screen_command_redraw : public screen_command_base { + explicit screen_command_redraw() = default; + template + friend screen &operator<<(screen &o, const screen_command_redraw &cmd) { + (void)cmd; + o.redraw(); + return o; + } +}; +[[nodiscard]] static screen_command_redraw redraw() { return screen_command_redraw{}; } + +template +struct screen_command_clear : public screen_command_base { + chartype c; + explicit screen_command_clear(chartype C) : c(C) {} + friend screen &operator<<(screen &o, const screen_command_clear &cmd) { + o.clear(cmd.c); + return o; + } +}; +template +[[nodiscard]] static screen_command_clear clear() { return screen_command_clear{chartype{}}; } +template +[[nodiscard]] static screen_command_clear clear(chartype c) { return screen_command_clear{c}; } + +struct screen_command_move : public screen_command_base { + unsigned x, y; + explicit screen_command_move(unsigned X, unsigned Y) : x(X), y(Y) {} + template + friend screen &operator<<(screen &o, const screen_command_move &cmd) { + o.setcursorxy(cmd.x, cmd.y); + return o; + } +}; +[[nodiscard]] static screen_command_move move(unsigned x, unsigned y) { return screen_command_move{x, y}; } + +template +struct screen_command_plot : public screen_command_base { + chartype c; + unsigned x, y; + explicit screen_command_plot(unsigned X, unsigned Y, chartype C) : c(C), x(X), y(Y) {} + friend screen &operator<<(screen &o, const screen_command_plot &cmd) { + o.setc(cmd.x, cmd.y, cmd.c); + return o; + } +}; +template +[[nodiscard]] static screen_command_plot plot(unsigned x, unsigned y, T c) { return screen_command_plot{x, y, c}; } + +struct screen_command_recolor : public screen_command_base { + color fg, bg; + bool rfg, rbg; + explicit screen_command_recolor(color Fg, bool side) : fg(Fg), bg(Fg), rfg(side ? true : false), rbg(side ? false : true) {} + explicit screen_command_recolor(color Fg, color Bg) : fg(Fg), bg(Bg), rfg(true), rbg(true) {} + + template + friend screen &operator<<(screen &o, const screen_command_recolor &cmd) { + if(cmd.rbg) o.setcursorbg(cmd.bg); + if(cmd.rfg) o.setcursorfg(cmd.fg); + return o; + } +}; +[[nodiscard]] static screen_command_recolor setfg(uint8_t r, uint8_t g, uint8_t b) { return screen_command_recolor{color{r, g, b}, true}; } +[[nodiscard]] static screen_command_recolor setbg(uint8_t r, uint8_t g, uint8_t b) { return screen_command_recolor{color{r, g, b}, false}; } +[[nodiscard]] static screen_command_recolor setcolor(color fg, color bg) { return screen_command_recolor{fg, bg}; } +[[nodiscard]] static screen_command_recolor resetcolor() { return screen_command_recolor{WHITE, BLACK}; } + +template +struct screen_command_fillrow : public screen_command_base { + unsigned row; + chartype c; + + friend screen &operator<<(screen &o, const screen_command_fillrow &cmd) { + o.clearrow(cmd.row, cmd.c); + return o; + } +}; + +template +[[nodiscard]] static screen_command_fillrow fillrow(unsigned row) { return screen_command_fillrow{.row = row, .c = ' '}; } +template +[[nodiscard]] static screen_command_fillrow fillrow(unsigned row, T c) { return screen_command_fillrow{.row = row, .c = c}; } + +} + +#endif diff --git a/include/system.hpp b/include/system.hpp new file mode 100644 index 0000000..9de10bc --- /dev/null +++ b/include/system.hpp @@ -0,0 +1,82 @@ +#ifndef SYSTEM_HPP +#define SYSTEM_HPP 1 + +#include "ecs.hpp" +#include "camera.hpp" +#include "window.hpp" + +#include + +class System { +private: + friend class SystemView; + struct SystemTreeNode { + unsigned entityId; + std::list children; + }; + SystemTreeNode m_systemTree; + ecs::EntityMan m_entityMan; + + ecs::Entity &addOrbital(const std::string &name, const std::string &orbitingName, unsigned long a, double e, unit::Mass m, unsigned r, double M, double w); + void tickOrbitals(unit::Time time); + + SystemTreeNode *traverseSystemTree(SystemTreeNode &node, const std::string &name); + SystemTreeNode *getNode(const std::string &name); +public: + System(); + + void update(); + + ecs::Entity &getBody(std::size_t id); +}; + +class SystemView { +private: + System *m_system; + System::SystemTreeNode *m_focus; + + class Search { + private: + struct SystemTreeDisplayNode { + System::SystemTreeNode *node; + std::list children; + SystemTreeDisplayNode *parent; + + unsigned index; + bool collapsed; + bool hidden; + }; + SystemView *m_systemView; + SystemTreeDisplayNode m_displayTree; + std::vector m_displayTreeFlat; + + unsigned m_selectionIndex; + std::string m_query; + bool m_dirty; + + void addNodeToTree(SystemTreeDisplayNode &root, System::SystemTreeNode *node); + void drawNode(SystemTreeDisplayNode &root, Window &searchWindow, unsigned indent); + void rebuild(); + public: + Search(SystemView *systemView); + + void finish(); + void keypress(int key); + void draw(); + }; + std::unique_ptr m_focusSearch; +public: + SystemView(System *system) : m_system(system), m_focusSearch(nullptr) {} + + void keypress(Camera *camera, int key); + void update(Camera *camera); + void draw(Camera *camera); + void drawOver(Camera *camera); + + void view(System *system); + + ecs::Entity &getBody(int id) const; + int getBodyIdByName(const std::string &name); +}; + +#endif diff --git a/include/timeman.hpp b/include/timeman.hpp new file mode 100644 index 0000000..ac5113e --- /dev/null +++ b/include/timeman.hpp @@ -0,0 +1,27 @@ +#ifndef TIME_MANAGER_H +#define TIME_MANAGER_H 1 + +#include "util.hpp" +#include "units.hpp" +#include "straw.hpp" +#include "window.hpp" + +class TimeMan { + static unit::Time m_time; + static unit::Time m_step; + static bool m_auto; + static bool m_changed; +public: + + static void init(); + + static void update(int c); + static void draw(); + + static unit::Time time() { return m_time; } + static bool automatic() { return m_auto; } + static void interrupt() { m_auto = false; } + static bool changed() { return m_changed; } +}; + +#endif diff --git a/include/units.hpp b/include/units.hpp new file mode 100644 index 0000000..5f2fd67 --- /dev/null +++ b/include/units.hpp @@ -0,0 +1,166 @@ +#ifndef UNIT_HPP +#define UNIT_HPP 1 + +#include "util.hpp" +#include + +namespace unit { + +constexpr long MINUTE_SECONDS = 60; +constexpr long HOUR_SECONDS = 3600; +constexpr long DAY_SECONDS = 86400; +constexpr long WEEK_SECONDS = 604800; +constexpr long YEAR_SECONDS = 31556952; +constexpr long CYEAR_SECONDS = 31536000; + +class Mass { + double m_kg; +public: + explicit constexpr Mass(double kg) : m_kg(kg) {} + constexpr ~Mass() = default; + + constexpr double operator()() { return m_kg; } + + constexpr Mass &operator+=(const Mass &rhs) { this->m_kg += rhs.m_kg; return *this; } + constexpr Mass &operator-=(const Mass &rhs) { this->m_kg -= rhs.m_kg; return *this; } + constexpr Mass &operator/=(const Mass &rhs) { this->m_kg *= rhs.m_kg; return *this; } + constexpr Mass &operator*=(const Mass &rhs) { this->m_kg /= rhs.m_kg; return *this; } + + friend Mass operator+(Mass lhs, const Mass &rhs) { lhs += rhs; return lhs; } + friend Mass operator-(Mass lhs, const Mass &rhs) { lhs -= rhs; return lhs; } + friend Mass operator*(Mass lhs, const Mass &rhs) { lhs *= rhs; return lhs; } + friend Mass operator/(Mass lhs, const Mass &rhs) { lhs /= rhs; return lhs; } + + friend inline bool operator<=>(const Mass &lhs, const Mass &rhs) = default; + + constexpr Mass &operator+=(const double &rhs) { this->m_kg += rhs; return *this; } + constexpr Mass &operator-=(const double &rhs) { this->m_kg -= rhs; return *this; } + constexpr Mass &operator*=(const double &rhs) { this->m_kg *= rhs; return *this; } + constexpr Mass &operator/=(const double &rhs) { this->m_kg /= rhs; return *this; } + + friend Mass operator+(Mass lhs, const double &rhs) { lhs += rhs; return lhs; } + friend Mass operator-(Mass lhs, const double &rhs) { lhs -= rhs; return lhs; } + friend Mass operator*(Mass lhs, const double &rhs) { lhs *= rhs; return lhs; } + friend Mass operator/(Mass lhs, const double &rhs) { lhs /= rhs; return lhs; } +}; + +class Time { + long m_seconds; +public: + static constexpr unsigned char month_days[12] = { + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + }; + static constexpr unsigned char month_days_leap[12] = { + 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + }; + static const inline std::string month_str[12] = { + "January", "Febuary", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" + }; + + explicit constexpr Time(long seconds) : m_seconds(seconds) {} + + constexpr long operator()() { return m_seconds; } + + constexpr Time &operator+=(const Time &rhs) { this->m_seconds += rhs.m_seconds; return *this; } + constexpr Time &operator-=(const Time &rhs) { this->m_seconds -= rhs.m_seconds; return *this; } + constexpr Time &operator/=(const Time &rhs) { this->m_seconds *= rhs.m_seconds; return *this; } + constexpr Time &operator*=(const Time &rhs) { this->m_seconds /= rhs.m_seconds; return *this; } + + friend Time operator+(Time lhs, const Time &rhs) { lhs += rhs; return lhs; } + friend Time operator-(Time lhs, const Time &rhs) { lhs -= rhs; return lhs; } + friend Time operator*(Time lhs, const Time &rhs) { lhs *= rhs; return lhs; } + friend Time operator/(Time lhs, const Time &rhs) { lhs /= rhs; return lhs; } + + friend inline bool operator<=>(const Time &lhs, const Time &rhs) = default; + + constexpr Time &operator+=(const long &rhs) { this->m_seconds += rhs; return *this; } + constexpr Time &operator-=(const long &rhs) { this->m_seconds -= rhs; return *this; } + constexpr Time &operator*=(const long &rhs) { this->m_seconds *= rhs; return *this; } + constexpr Time &operator/=(const long &rhs) { this->m_seconds /= rhs; return *this; } + + friend Time operator+(Time lhs, const long &rhs) { lhs += rhs; return lhs; } + friend Time operator-(Time lhs, const long &rhs) { lhs -= rhs; return lhs; } + friend Time operator*(Time lhs, const long &rhs) { lhs *= rhs; return lhs; } + friend Time operator/(Time lhs, const long &rhs) { lhs /= rhs; return lhs; } + + constexpr bool leap_year() { return (m_seconds % YEAR_SECONDS) % 4 == 0; } + + constexpr Time current_year() { + return Time((m_seconds % YEAR_SECONDS) + (m_seconds < 0 ? YEAR_SECONDS : 0)); + } + constexpr Time current_month() { + Time year = current_year(); + if(year.m_seconds < 0) { + year.m_seconds = YEAR_SECONDS + year.m_seconds; + } + unsigned month = 0; + const unsigned char *month_days_view = month_days; + if(years() % 4 == 0 && years() % 100 == 0 && years() % 400 != 0) month_days_view = month_days_leap; + for(month; year.days() > month_days_view[month]; month = (month + 1) % 12) year -= month_days_view[month] * DAY_SECONDS; + return year; + } + constexpr Time current_week() { return Time(m_seconds % WEEK_SECONDS); } + constexpr Time current_day() { return Time(m_seconds % DAY_SECONDS); } + constexpr Time current_hour() { return Time(m_seconds % HOUR_SECONDS); } + constexpr Time current_minute() { return Time(m_seconds % MINUTE_SECONDS); } + + constexpr long seconds() { return m_seconds; } + constexpr long minutes() { return m_seconds / MINUTE_SECONDS; } + constexpr long hours() { return m_seconds / HOUR_SECONDS; } + constexpr long days() { return m_seconds / DAY_SECONDS; } + constexpr long weeks() { return m_seconds / WEEK_SECONDS; } + constexpr long months() { + Time copy(*this); + if(copy.m_seconds < 0) { + copy.m_seconds = -copy.m_seconds; + } + unsigned month = 0; + const unsigned char *month_days_view = month_days; + if(years() % 4 == 0) month_days_view = month_days_leap; + for(month; copy.days() > month_days_view[month]; month = (month + 1) % 12) copy -= month_days_view[month] * DAY_SECONDS; + return month; + } + constexpr long years() { return ((m_seconds < 0 ? m_seconds - CYEAR_SECONDS : m_seconds) / CYEAR_SECONDS) + 2000; } + constexpr long real_years() { return (m_seconds < 0 ? m_seconds - YEAR_SECONDS : m_seconds) / YEAR_SECONDS; } + + /* %% = '%' + * %Y = real year + * %C = calendar year + * %S = month string + * %M = month + * %W = week + * %D = day + * %H = hour + * %m = minute + * %s = second + * */ + std::string format(const char *fmt); +}; + +constexpr long Mm = 1000; +constexpr long Gm = cxpow_v; +constexpr long Tm = cxpow_v; +constexpr long Pm = cxpow_v; +constexpr long Em = cxpow_v; +constexpr long Zm = cxpow_v; + +constexpr long AU = 149597871; + +constexpr Mass kg{1}; +constexpr Mass Mg{cxpow_v}; +constexpr Mass Gg{cxpow_v}; +constexpr Mass Tg{cxpow_v}; +constexpr Mass Pg{cxpow_v}; +constexpr Mass Eg{cxpow_v}; +constexpr Mass Zg{cxpow_v}; +constexpr Mass Yg{cxpow_v}; + +constexpr Mass lunarMass{7.342 * cxpow_v}; +constexpr Mass earthMass{5.97237 * cxpow_v}; +constexpr Mass jovMass{1.89813 * cxpow_v}; +constexpr Mass solMass{1.98847 * cxpow_v}; + +constexpr double earthRad = 6371; +} + +#endif diff --git a/include/util.hpp b/include/util.hpp new file mode 100644 index 0000000..3c795d1 --- /dev/null +++ b/include/util.hpp @@ -0,0 +1,45 @@ +#include +#ifndef UTIL_HPP +#define UTIL_HPP 1 + +#include +#include + +#if UNICODE == 1 +using screenchr = wchar_t; +#else +using screenchr = char; +#endif + +/*Shamelessly stolen from stackoverflow + * https://stackoverflow.com/questions/52303316/get-index-by-type-in-stdvariant + * by Barry*/ +template struct tag { }; +template +struct get_index; +template +struct get_index> + : std::integral_constant...>(tag()).index()> +{ }; + +template +struct is_variant : std::false_type {}; +template +struct is_variant> + : std::disjunction...> {}; +template +constexpr bool is_variant_v = is_variant::value; + +template +struct cxpow { static constexpr T value = (T)base * cxpow::value; }; +template +struct cxpow { static constexpr T value = 1; }; +template +constexpr T cxpow_v = cxpow::value; + +template +struct cxrt { static constexpr T value = (T)base / cxpow::value; }; +template +constexpr T cxrt_v = cxrt::value; + +#endif diff --git a/include/vex.hpp b/include/vex.hpp new file mode 100644 index 0000000..0a3bb24 --- /dev/null +++ b/include/vex.hpp @@ -0,0 +1,104 @@ +#ifndef VEX_H +#define VEX_H 1 + +#include +#include +#include +#include +#include + +namespace vex +{ + +template +concept arithmetic = std::is_arithmetic::value; + +template + requires (D > 1) +struct vec_dimd +{ + std::array v; + + explicit vec_dimd() = default; + template + explicit vec_dimd(Args&&... args) : v{args...} {} + explicit vec_dimd(T args[D]) : v(args) {} + explicit vec_dimd(T fill) { v.fill(fill); } + + T operator[](std::size_t i) { return v[i]; } + T operator[](std::size_t i) const { return v[i]; } + + vec_dimd operator+=(const vec_dimd &rhs) { for(size_t i = 0; i < D; i++) v[i] += rhs.v[i]; return *this; } + vec_dimd operator-=(const vec_dimd &rhs) { for(size_t i = 0; i < D; i++) v[i] -= rhs.v[i]; return *this; } + vec_dimd operator*=(const vec_dimd &rhs) { for(size_t i = 0; i < D; i++) v[i] *= rhs.v[i]; return *this; } + vec_dimd operator/=(const vec_dimd &rhs) { for(size_t i = 0; i < D; i++) v[i] /= rhs.v[i]; return *this; } + + vec_dimd operator*=(const T &rhs) { for(size_t i = 0; i < D; i++) v[i] *= rhs; return *this; } + vec_dimd operator/=(const T &rhs) { for(size_t i = 0; i < D; i++) v[i] /= rhs; return *this; } + + vec_dimd operator-() { return vec_dimd(0) - *this; } + + auto operator<=>(const vec_dimd &rhs) const { return magnitude() <=> rhs.magnitude(); } + bool operator==(const vec_dimd &rhs) const { for(unsigned i = 0; i < D; i++) if(v[i] != rhs.v[i]) return false; return true; } + + friend vec_dimd operator+(vec_dimd lhs, const vec_dimd &rhs) { lhs += rhs; return lhs; } + friend vec_dimd operator-(vec_dimd lhs, const vec_dimd &rhs) { lhs -= rhs; return lhs; } + friend vec_dimd operator*(vec_dimd lhs, const vec_dimd &rhs) { lhs *= rhs; return lhs; } + friend vec_dimd operator/(vec_dimd lhs, const vec_dimd &rhs) { lhs /= rhs; return lhs; } + + friend vec_dimd operator*(vec_dimd lhs, const T &rhs) { lhs *= rhs; return lhs; } + friend vec_dimd operator/(vec_dimd lhs, const T &rhs) { lhs /= rhs; return lhs; } + + friend std::ostream &operator<<(std::ostream &os, const vec_dimd obj) { + os << '{'; + for(std::size_t i = 0; i < D; i++) os << obj.v[i] << ((i < (D - 1)) ? ',' : '}'); + return os; + } + + /*Finds the distance from the origin to the ray cast in D dimension space using components of vec*/ + T sqrMagnitude() const { T t{}; for(size_t i = 0; i < D; i++) t += v[i] * v[i]; return t; } + T magnitude() const { return std::sqrt(sqrMagnitude()); } + + /*Finds the dot product of itself and another vec of same T and D*/ + T dot(const vec_dimd &b) const { T t; for(size_t i = 0; i < D; i++) t += (v[i] * b.v[i]); return t; } + friend T dot(const vec_dimd &lhs, const vec_dimd &rhs) { return lhs.dot(rhs); } + + vex::vec_dimd normalize() const { return *this / magnitude(); } + vex::vec_dimd abs() const { vex::vec_dimd copy(*this); for(unsigned i = 0; i < D; i++) copy.v[i] = std::abs(copy.v[i]); return copy; } + + auto cross(const vec_dimd &o) const { + if constexpr(D == 2) return v[0]*o[0] - v[1]*o[1]; + if constexpr(D == 3) return vec_dimd{v[1]*o[2]-v[2]*o[1], v[2]*o[0]-v[0]*o[2],v[0]*o[1]-v[1]*o[0]}; + } +}; + +template +using vec2 = vec_dimd; + +template +using vec3 = vec_dimd; + +/*(x, y) -> (r, theta)*/ +template +static vec2 +polar(const vec2

&in) +{ + return vec2( + std::sqrt(in[0] * in[0] + in[1] * in[1]), + std::atan2(in[1], in[0]) + ); +} +/*(r, theta) -> (x, y)*/ +template +static vec2 +cartesian(const vec2

&in) +{ + return vec2( + (R)(cos(in[1]) * in[0]), + (R)(sin(in[1]) * in[0]) + ); +} + +}; + +#endif diff --git a/include/window.hpp b/include/window.hpp new file mode 100644 index 0000000..78001ea --- /dev/null +++ b/include/window.hpp @@ -0,0 +1,69 @@ +#ifndef WINDOW_HPP +#define WINDOW_HPP 1 + +#include "util.hpp" +#include "straw.hpp" +#include +#include + +//Wrapper for screens that act like windows +class Window { + straw::screen m_border; + straw::screen m_screen; + std::string m_title; + bool m_hidden; +public: + explicit Window(const std::string Title, unsigned X, unsigned Y, unsigned W, unsigned H, bool hidden = false) : + m_border(X, Y, W, 1), m_screen(X, Y+1, W, H-1), m_title(Title), m_hidden(hidden) {} + ~Window() = default; + + template + friend Window &operator<<(Window &o, const T &t) { + o.m_screen << t; + return o; + } + + straw::screen *screen() { return &m_screen; } + std::string title() const { return m_title; } + + void draw(bool focus); + + void setHidden(bool mode) { m_hidden = mode; } + bool hidden() const { return m_hidden; } +}; + +#define WINDOW_SYSTEMVIEW_ID "Systemview" +#define WINDOW_SYSTEMVIEW_SEARCH_ID "SystemviewSearch" +#define WINDOW_BODYINFO_ID "Bodyinfo" +#define WINDOW_EVENTS_ID "Events" +#define WINDOW_TIMEMAN_ID "Timeman" + +class WindowContext { + std::unordered_map m_windows; + std::vector m_windowOrder; + unsigned m_focus; +public: + WindowContext() : m_focus(0) {} + ~WindowContext() {} + + void registerWindow(const std::string &id, + const std::string &title, + unsigned x, unsigned y, + unsigned w, unsigned h, + bool hidden = false); + + Window &operator[](const std::string &id) { return m_windows.at(id); } + Window &operator[](unsigned id) { return m_windows.at(m_windowOrder[id]); } + Window &operator()() { return m_windows.at(m_windowOrder[m_focus]); } + + void update(int code); + void draw(); + + void setWindowHidden(const std::string &id, bool mode); + void focus(const std::string &id); + + unsigned getFocused() { return m_focus; } + std::string getFocusedString() { return m_windowOrder[m_focus]; } +}; + +#endif -- cgit v1.2.1