diff --git a/include/sharpsoft/basic_types.hpp b/include/sharpsoft/basic_types.hpp index 21d1e8b..ac6ce20 100644 --- a/include/sharpsoft/basic_types.hpp +++ b/include/sharpsoft/basic_types.hpp @@ -29,6 +29,11 @@ namespace sharp double magnitude() const; operator float2() const; + + const int2 operator+(const int2& other) const; + const int2 operator-(const int2& other) const; + const int2 operator*(const int factor) const; + const int2 operator/(const int factor) const; }; struct float2 { @@ -40,6 +45,11 @@ namespace sharp double magnitude() const; operator int2() const; + + const float2 operator+(const float2& other) const; + const float2 operator-(const float2& other) const; + const float2 operator*(const double factor) const; + const float2 operator/(const double factor) const; }; struct int_rect diff --git a/include/sharpsoft/global_misc.hpp b/include/sharpsoft/global_misc.hpp index b980b1e..6b85976 100644 --- a/include/sharpsoft/global_misc.hpp +++ b/include/sharpsoft/global_misc.hpp @@ -36,4 +36,7 @@ namespace sharp void start(); void end(); bool is_started(); + + double get_delta_time(); + double get_elapsed_time(); } diff --git a/include/sharpsoft/internal.hpp b/include/sharpsoft/internal.hpp index 91bcca7..cd1bc8d 100644 --- a/include/sharpsoft/internal.hpp +++ b/include/sharpsoft/internal.hpp @@ -17,6 +17,7 @@ namespace sharp void render_iter(); void render_loop(); + void draw_global_pixel(const color& color, const int2& pos); void draw_global_line(const color& color, const int2& start, const int2& end); void draw_global_rectangle(const color& color, const int_rect& rect); void fill_global_rectangle(const color& color, const int_rect& rect); diff --git a/include/sharpsoft/windowing.hpp b/include/sharpsoft/windowing.hpp index 2747458..e83bb2f 100644 --- a/include/sharpsoft/windowing.hpp +++ b/include/sharpsoft/windowing.hpp @@ -10,9 +10,14 @@ namespace sharp WINDOW_ACTIVE = 0x01, WINDOW_VISIBLE = 0x02, WINDOW_HEADER_VALIDATED = 0x04, - WINDOW_CONTENT_VALIDATED = 0x08 + WINDOW_CONTENT_VALIDATED = 0x08, + WINDOW_IS_IN_PAINT_MODE = 0x10 }; + // Can't tell if these are good ideas. + // FIXME: Messing with the header here requires a full screen + // invalidation triggered by the user, because I can't + // detect when its variables are modified. struct window_features { static const window_features defaults; @@ -49,6 +54,8 @@ namespace sharp window_features win_features; window_styles styles; + double elapsed_time; + void paint_header() const; void paint_content_back() const; @@ -61,6 +68,12 @@ namespace sharp virtual void paint() = 0; virtual void tick() = 0; + void draw_pixel(const color& color, const int2& pos); + void draw_line(const color& color, const int2& start, const int2& end); + //void draw_rect(const color& color, const int_rect& rect); + + //void fill_rect(const color& color, const int_rect& rect); + public: const window_styles& style() const; window_styles& style(); @@ -68,6 +81,7 @@ namespace sharp const window_features& features() const; window_features& features(); + double get_elapsed_time() const; const int2 get_pos() const; const int2 get_size() const; const int_rect get_content_rect() const; @@ -83,6 +97,9 @@ namespace sharp void set_window_rect(const int_rect& new_rect); void set_title(const std::string& new_title); + const int2 to_screen(const int2& window_pos) const; + const int2 to_window(const int2& screen_pos) const; + void invalidate(); void show(); diff --git a/src/main.cpp b/src/main.cpp index a1c6abf..238e913 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,3 +1,4 @@ +#include #include "main.h" #include "sharpsoft/all.hpp" #include "sharpsoft/basic_types.hpp" @@ -6,12 +7,36 @@ // This library is intended to be referenced by the prefix `sharp::` // Including `using namespace sharp;` is not recommended. +using std::numbers::pi; + class test_window : public sharp::window_base -{ +{ protected: void paint() override { - + constexpr int points = 5; + + int bigRadius = 100, + smallRadius = 60; + + sharp::int2 center = get_size() / 2; + sharp::int2 arr[points * 2]; + + double time = get_elapsed_time(); + double offset = pi / points; + + for (int i = 0; i < points; i++) + { + arr[i * 2] = sharp::int2(bigRadius * cos(time + (offset * i * 2)), bigRadius * sin(time + (offset * i * 2))) + center; + arr[i * 2 + 1] = sharp::int2(smallRadius * cos(time + (offset * (i * 2 + 1))), smallRadius * sin(time + (offset * (i * 2 + 1)))) + center; + } + + for (int i = 0; i < points * 2; i++) + { + sharp::int2& this_point = arr[i], + next_point = arr[(i + 1) % (points * 2)]; + draw_line(0xABCDEF, this_point, next_point); + } } void tick() override { diff --git a/src/sharpsoft/basic_types.cpp b/src/sharpsoft/basic_types.cpp index 151d2ec..ef810de 100644 --- a/src/sharpsoft/basic_types.cpp +++ b/src/sharpsoft/basic_types.cpp @@ -67,6 +67,22 @@ sharp::int2::operator float2() const { return float2(x, y); } +const int2 sharp::int2::operator+(const int2& other) const +{ + return int2(x + other.x, y + other.y); +} +const int2 sharp::int2::operator-(const int2& other) const +{ + return int2(x - other.x, y - other.y); +} +const int2 sharp::int2::operator*(const int factor) const +{ + return int2(x * factor, y * factor); +} +const int2 sharp::int2::operator/(const int factor) const +{ + return int2(x / factor, y / factor); +} sharp::float2::float2() { @@ -86,6 +102,22 @@ sharp::float2::operator int2() const { return int2(x, y); }; +const float2 sharp::float2::operator+(const float2& other) const +{ + return float2(x + other.x, y + other.y); +} +const float2 sharp::float2::operator-(const float2& other) const +{ + return float2(x - other.x, y - other.y); +} +const float2 sharp::float2::operator*(const double factor) const +{ + return float2(x * factor, y * factor); +} +const float2 sharp::float2::operator/(const double factor) const +{ + return float2(x / factor, y / factor); +} sharp::int_rect::int_rect() { diff --git a/src/sharpsoft/global_manager.cpp b/src/sharpsoft/global_manager.cpp index dadf55c..8e4400a 100644 --- a/src/sharpsoft/global_manager.cpp +++ b/src/sharpsoft/global_manager.cpp @@ -22,6 +22,9 @@ color back_col; int render_wait_ms; thread* render_thread = nullptr; +double delta_time; +double elapsed_time; + vector windows; void sharp::initialize() @@ -34,6 +37,8 @@ void sharp::initialize(const global_properties& props) back_col = props.background_color; render_wait_ms = 1000 / props.refresh_rate; + delta_time = 0; + elapsed_time = 0; init = true; } @@ -49,6 +54,8 @@ void sharp::uninitialize() delete windows.at(i); } windows.clear(); + delta_time = 0; + elapsed_time = 0; init = false; } @@ -103,15 +110,20 @@ void sharp::internal::render_iter() if (!HAS_INTERNAL_FLAG(win, WINDOW_HEADER_VALIDATED) || (!HAS_INTERNAL_FLAG(win, WINDOW_CONTENT_VALIDATED) && win->win_features.update_header)) { + ON_INTERNAL_FLAG(win, WINDOW_IS_IN_PAINT_MODE); win->paint_header(); + OFF_INTERNAL_FLAG(win, WINDOW_IS_IN_PAINT_MODE); ON_INTERNAL_FLAG(win, WINDOW_HEADER_VALIDATED); } if (!HAS_INTERNAL_FLAG(win, WINDOW_CONTENT_VALIDATED)) { + ON_INTERNAL_FLAG(win, WINDOW_IS_IN_PAINT_MODE); win->paint_content_back(); win->paint(); + OFF_INTERNAL_FLAG(win, WINDOW_IS_IN_PAINT_MODE); ON_INTERNAL_FLAG(win, WINDOW_CONTENT_VALIDATED); } + win->elapsed_time += delta_time; } } void sharp::internal::render_loop() @@ -119,6 +131,9 @@ void sharp::internal::render_loop() thread::delay(50); // Wait a sec for the screen to be ready. while (true) { + // TODO: This could be improved with a proper chrono timer, but it's alright. + delta_time = 1.0 / render_wait_ms; + elapsed_time += delta_time; render_iter(); thread::delay(render_wait_ms); } @@ -151,6 +166,8 @@ void sharp::start() render_thread = new thread(internal::render_loop); render_thread->start(); + delta_time = 0; + elapsed_time = 0; started = true; } @@ -160,6 +177,8 @@ void sharp::end() render_thread->stop(); delete render_thread; + delta_time = 0; + elapsed_time = 0; started = false; } @@ -168,3 +187,12 @@ bool sharp::is_started() { return started; } + +double sharp::get_delta_time() +{ + return delta_time; +} +double sharp::get_elapsed_time() +{ + return elapsed_time; +} diff --git a/src/sharpsoft/rendering.cpp b/src/sharpsoft/rendering.cpp index 9848da6..4175786 100644 --- a/src/sharpsoft/rendering.cpp +++ b/src/sharpsoft/rendering.cpp @@ -11,7 +11,12 @@ using namespace sharp; #ifdef SH_PROS_ACTIVE -void internal::draw_global_line(const color &color, const int2 &start, const int2 &end) +void internal::draw_global_pixel(const color& color, const int2& pos) +{ + pros::screen::set_pen(color.get_value()); + pros::screen::draw_pixel(pos.x, pos.y); +} +void internal::draw_global_line(const color& color, const int2& start, const int2& end) { pros::screen::set_pen(color.get_value()); pros::screen::draw_line(start.x, start.y, end.x, end.y); @@ -56,3 +61,35 @@ void window_base::paint_content_back() const { internal::fill_global_rectangle(styles.background_color, get_content_rect()); } + +void window_base::draw_pixel(const color& color, const int2& win_pos) +{ + if (win_pos.x < 0 || win_pos.x >= width || + win_pos.y < 0 || win_pos.y >= height) return; // Out of window bounds. + + const int2 true_pos = to_screen(win_pos); + internal::draw_global_pixel(color, true_pos); +} +void window_base::draw_line(const color& color, const int2& pos_a, const int2& pos_b) +{ + // FIXME: This causes artifacts occasionally along the top and bottom of the window. + // Why? + + double slope = (double)(pos_b.y - pos_a.y) / (pos_b.x - pos_a.x), + inv_slope = (double)(pos_b.x - pos_a.x) / (pos_b.y - pos_a.y); // Prevent divide by zero errors. + + int2 a = pos_a, b = pos_b; + if (a.x < 0) a = int2(0, -a.x * slope + a.y); // Left wall truncate for A. + else if (a.x >= width) a = int2(width - 1, ((width - 1) - a.x) * slope + a.y); // Right wall truncate for A. + if (a.y < 0) a = int2(-a.y * inv_slope + a.x, 0); // Bottom wall truncate for A. + else if (a.y >= height) a = int2(((height - 1) - a.y) * inv_slope + a.x, height - 1); // Top wall truncate for A. + + if (b.x < 0) b = int2(0, -a.x * slope + a.y); // Left wall truncate for B. + else if (b.x >= width) b = int2(width - 1, ((width - 1) - a.x) * slope + a.y); // Right wall truncate for B. + if (b.y < 0) b = int2(-a.y * inv_slope + a.x, 0); // Bottom wall truncate for B. + else if (b.y >= height) b = int2(((height - 1) - a.y) * inv_slope + a.x, height - 1); // Top wall truncate for B. + + const int2 true_pos_a = to_screen(a), + true_pos_b = to_screen(b); + internal::draw_global_line(color, true_pos_a, true_pos_b); +} diff --git a/src/sharpsoft/window_base.cpp b/src/sharpsoft/window_base.cpp index 8da5f4d..c8be4ee 100644 --- a/src/sharpsoft/window_base.cpp +++ b/src/sharpsoft/window_base.cpp @@ -17,6 +17,8 @@ sharp::window_base::window_base(const string& title, const int2& pos, const int2 win_features = window_features::defaults; styles = window_styles::defaults; + + elapsed_time = 0; } sharp::window_base::~window_base() { @@ -40,6 +42,10 @@ window_features& sharp::window_base::features() { return win_features; } +double sharp::window_base::get_elapsed_time() const +{ + return elapsed_time; +} const int2 sharp::window_base::get_pos() const { return int2(posX, posY); @@ -137,3 +143,16 @@ void sharp::window_base::show() OFF_INTERNAL_FLAG(this, WINDOW_HEADER_VALIDATED); OFF_INTERNAL_FLAG(this, WINDOW_CONTENT_VALIDATED); } + +const int2 sharp::window_base::to_screen(const int2& window_pos) const +{ + int header_height = get_header_height(); + if (header_height > 0) return int2(window_pos.x + posX, window_pos.y + posY + header_height + 1); + else return int2(window_pos.x + posX, window_pos.y + posY); +} +const int2 sharp::window_base::to_window(const int2& screen_pos) const +{ + int header_height = get_header_height(); + if (header_height > 0) return int2(screen_pos.x - posX, screen_pos.y - posY - header_height - 1); + else return int2(screen_pos.x - posY, screen_pos.y - posY); +}