diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ee2727..5797c6e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,90 +1,87 @@ cmake_minimum_required(VERSION 3.10) include(FetchContent) -project(2DComputerGraphicsAndAnimation) +project(HexagonPaint + LANGUAGES CXX C) set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") +#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") set(FETCHCONTENT_QUIET OFF) +set(BUILD_SHARED_LIBS FALSE) + # SFML set(SFML_VERSION "2.5.1") FetchContent_Declare( - sfml - GIT_REPOSITORY "https://github.com/SFML/SFML.git" - GIT_TAG "${SFML_VERSION}" + sfml + GIT_REPOSITORY "https://github.com/SFML/SFML.git" + GIT_TAG "${SFML_VERSION}" ) FetchContent_GetProperties(sfml) -if(NOT sfml_POPULATED) +if (NOT sfml_POPULATED) FetchContent_Populate(sfml) add_subdirectory("${sfml_SOURCE_DIR}" "${sfml_BINARY_DIR}") -endif() +endif () # ImGui set(IMGUI_VERSION "1.74") FetchContent_Declare( imgui GIT_REPOSITORY "https://github.com/ocornut/imgui.git" - GIT_TAG "v${IMGUI_VERSION}" + GIT_TAG "v${IMGUI_VERSION}" ) FetchContent_GetProperties(imgui) -if(NOT imgui_POPULATED) +if (NOT imgui_POPULATED) FetchContent_Populate(imgui) #add_subdirectory("${imgui_SOURCE_DIR}" "${imgui_BINARY_DIR}") -endif() +endif () # ImGui-SFML set(IMGUI_SFML_VERSION "2.1") FetchContent_Declare( imgui_sfml GIT_REPOSITORY "https://github.com/eliasdaler/imgui-sfml.git" - GIT_TAG "v${IMGUI_SFML_VERSION}" + GIT_TAG "v${IMGUI_SFML_VERSION}" ) set(IMGUI_DIR ${imgui_SOURCE_DIR}) set(IMGUI_SFML_FIND_SFML CACHE BOOL FALSE) FetchContent_GetProperties(imgui_sfml) -if(NOT imgui_sfml_POPULATED) +if (NOT imgui_sfml_POPULATED) FetchContent_Populate(imgui_sfml) add_subdirectory("${imgui_sfml_SOURCE_DIR}" "${imgui_sfml_BINARY_DIR}") -endif() +endif () -set(SOURCE - "src/main.cpp" -) +add_executable(HexagonPaint -add_executable(2DComputerGraphicsAndAnimationApp - "${SOURCE}" -) + "lib/tinyfiledialogs/tinyfiledialogs.c" + "lib/lodepng/lodepng.cpp" + "lib/lodepng/lodepng_fuzzer.cpp" + "lib/lodepng/lodepng_util.cpp" -target_link_libraries(2DComputerGraphicsAndAnimationApp - PRIVATE - "sfml-graphics" - "sfml-system" - "sfml-window" - ImGui-SFML::ImGui-SFML -) + "src/main.cpp" + "src/helpers.cpp" + "src/helpers.hpp" + "src/canvas.cpp" + "src/canvas.hpp" + "src/color.hpp" + "src/shape/line.cpp" + "src/shape/line.hpp" + "src/fps.cpp" + "src/fps.hpp" + "src/application.cpp" + "src/application.hpp") + +target_include_directories(HexagonPaint + PRIVATE "lib/tinyfiledialogs" + PRIVATE "lib/stb" + PRIVATE "lib/lodepng") -if(MSVC) - configure_file( - ${imgui_sfml_BINARY_DIR}/ImGui-SFML.dll - ImGui-SFML.dll - COPYONLY - ) - configure_file( - ${sfml_BINARY_DIR}/lib/sfml-graphics-d-2.dll - sfml-graphics-d-2.dll - COPYONLY - ) - configure_file( - ${sfml_BINARY_DIR}/lib/sfml-window-d-2.dll - sfml-window-d-2.dll - COPYONLY - ) - configure_file( - ${sfml_BINARY_DIR}/lib/sfml-system-d-2.dll - sfml-system-d-2.dll - COPYONLY - ) -endif() \ No newline at end of file +target_link_libraries(HexagonPaint + PUBLIC + # "sfml-graphics" + # "sfml-system" + # "sfml-window" + ImGui-SFML::ImGui-SFML + ) \ No newline at end of file diff --git a/README.md b/README.md index 054139e..b047904 100644 --- a/README.md +++ b/README.md @@ -22,12 +22,28 @@ You cannot use the bulit-in line drawing procedure. https://drive.google.com/open?id=1KWUTyayYVD_g-uJN614gGsWqAmayvnhp -## Prerequisites +## Features + +- Draw using pen tool +- Draw line +- Clear canvas +- Color selection +- Load and save image in PNG format + +## Screenshot + +![Draw using pen tool](assets/1.gif) +![Draw lines](assets/2.gif) +![Clear canvas](assets/3.gif) + +## Building + +### Prerequisites - CMake >= 3.10 - C++17 supported compiler -## Installation +### Installation - Clone to local - Pull the dependencies diff --git a/assets/1.gif b/assets/1.gif new file mode 100644 index 0000000..7217606 Binary files /dev/null and b/assets/1.gif differ diff --git a/assets/2.gif b/assets/2.gif new file mode 100644 index 0000000..6f0baf9 Binary files /dev/null and b/assets/2.gif differ diff --git a/assets/3.gif b/assets/3.gif new file mode 100644 index 0000000..2851f02 Binary files /dev/null and b/assets/3.gif differ diff --git a/src/application.cpp b/src/application.cpp new file mode 100644 index 0000000..9d77236 --- /dev/null +++ b/src/application.cpp @@ -0,0 +1,416 @@ +#include "application.hpp" + +#include +#include +#include +#include +#include +#include + +#include "canvas.hpp" +#include "helpers.hpp" +#include "shape/line.hpp" + +Application::Application(const unsigned int window_width, const unsigned int window_height, + sf::String title) +{ + this->window = new sf::RenderWindow(sf::VideoMode(window_width, window_height, 32), + title); + + sf::Image window_icon; + window_icon.loadFromFile("../assets/icon-32x32.png"); + this->window->setIcon(32, 32, window_icon.getPixelsPtr()); + + // 100 FPS should be enough + this->window->setFramerateLimit(60); + this->state = State::Nothing; + ImGui::SFML::Init(*(this->window)); + ImGui::GetIO().IniFilename = nullptr; +} + +Application::~Application() +{ + ImGui::SFML::Shutdown(); + delete this->canvas; + delete this->window; +} + +void Application::dispatch() +{ + + this->canvas = new Canvas(800, this->window->getSize().y); + this->canvas->setPosition(sf::Vector2f(200, 0)); + + sf::Clock delta_clock; + sf::Event event{}; + bool line_is_dotted = false; + int line_width_size = 1; + float chosen_rgb_color[3] = { 0, 0, 0 }; + float main_menu_bar_height = 0; + + int my_image_width = 0; + int my_image_height = 0; + GLuint texture_icon_line = 0; + GLuint texture_icon_pen = 0; + LoadTextureFromFile("../assets/line.png", &texture_icon_line, &my_image_width, &my_image_height); + LoadTextureFromFile("../assets/pen.png", &texture_icon_pen, &my_image_width, &my_image_height); + + int x1, y1; + + while (this->window->isOpen()) + { + sf::Vector2i mouse_position = sf::Mouse::getPosition(*this->window); + Color chosen_color(chosen_rgb_color); + + fps.start(); + this->window->clear(); + + while (this->window->pollEvent(event)) + { + ImGui::SFML::ProcessEvent(event); + + if (event.type == sf::Event::Closed) + { + window->close(); + } + + if (event.type == sf::Event::LostFocus) + { + break; + } + + if (mouse_position.x >= 200 && mouse_position.x <= 200 + this->canvas->getWidth() + && mouse_position.y >= 0 && mouse_position.y <= 0 + this->canvas->getHeight()) + { + if (!sf::Mouse::isButtonPressed(sf::Mouse::Button::Left)) + { + if (this->state == State::PenDraw) + { + this->state = State::PenIdle; + } + } + + if (sf::Mouse::isButtonPressed(sf::Mouse::Button::Left)) + { + if (this->state == State::PenIdle) + { + this->canvas->setPixel(mouse_position.x - 200, mouse_position.y, chosen_color); + x1 = mouse_position.x - 200; + y1 = mouse_position.y; + this->state = State::PenDraw; + } + else if (this->state == State::PenDraw) + { + shape::Line line = shape::Line::from(x1, y1) + .to(mouse_position.x - 200, mouse_position.y) + .withColor(chosen_color) + .build(); + this->canvas->drawShape(&line); + x1 = mouse_position.x - 200; + y1 = mouse_position.y; +// this->canvas->setPixel(mouse_position.x - 200, mouse_position.y, chosen_color); + this->state = State::PenDraw; + } + } + + if (event.type == sf::Event::MouseButtonPressed) + { + if (this->state == State::LineFrom) + { + x1 = mouse_position.x - 200; + y1 = mouse_position.y; + this->state = State::LineTo; + } + else if (this->state == State::LineTo) + { + this->canvas->alternateEnd(); + auto line_pending = shape::Line::from(x1, y1) + .to(mouse_position.x - 200, mouse_position.y) + .withWidth(line_width_size) + .withColor(chosen_color); + + if (line_is_dotted) + { + shape::Line line_from_to_mouse_position = line_pending.isDotted(true).build(); + this->canvas->drawShape(&line_from_to_mouse_position); + } + else + { + shape::Line line_from_to_mouse_position = line_pending.build(); + this->canvas->drawShape(&line_from_to_mouse_position); + } + + this->state = State::LineDone; + } + } + } + } + + if (this->canvas->isAlternateOn()) + { + this->canvas->alternateFromMain(); + } + + ImGui::SFML::Update(*this->window, delta_clock.restart()); + + // Main menu + if (ImGui::BeginMainMenuBar()) + { + main_menu_bar_height = ImGui::GetWindowHeight(); + if (ImGui::BeginMenu("File")) + { + if (ImGui::MenuItem("Open")) + { + char const* filter_pattern[1] = { "*.png" }; + char const* file_name = tinyfd_openFileDialog( + "Open file", + nullptr, + 1, + filter_pattern, + "PNG", + false); + if (!this->canvas->load(file_name)) + { +// MessageBox::error("File could not be loaded. It may not have PNG encoding or have different width and height"); + } + } + if (ImGui::MenuItem("Save")) + { + char const* filter_pattern[1] = { "*.png" }; + char default_file_name[22]; + defaultPNGFilename(default_file_name); + char const* file_name = tinyfd_saveFileDialog( + "Save file", + default_file_name, + 1, + filter_pattern, + "PNG"); + this->canvas->save(file_name); + } + if (ImGui::MenuItem("Close")) + { + this->window->close(); + } + ImGui::EndMenu(); + } + } + ImGui::EndMainMenuBar(); + // End main menu + + ImGui::SetNextWindowPos(ImVec2(0, main_menu_bar_height)); + ImGui::SetNextWindowSize(ImVec2(200, 500)); + if (ImGui::Begin("Toolbox", nullptr, + ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize)) + { + if (ImGui::BeginTabBar("#tab_toolbox")) + { + if (ImGui::BeginTabItem("Shape")) + { + // Pen + if (ImGui::ImageButton(texture_icon_pen, ImVec2(32, 32))) + { + this->state = State::PenIdle; + } + if (ImGui::IsItemHovered()) + ImGui::SetTooltip("Pen"); + + ImGui::SameLine(); + + // Line + if (ImGui::ImageButton(texture_icon_line, ImVec2(32, 32))) + { + this->canvas->alternateBegin(); + this->state = State::LineFrom; + } + if (ImGui::IsItemHovered()) + ImGui::SetTooltip("Line shape"); + } + ImGui::EndTabItem(); + } + ImGui::EndTabBar(); + + if (this->state == State::LineFrom || this->state == State::LineTo) + { + if (ImGui::CollapsingHeader("Line Options", ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::Checkbox("Dotted", &line_is_dotted); + + ImGui::SameLine(); + + ImGui::SliderInt("Width", &line_width_size, 1, 5, "%d px"); + } + } + + if (ImGui::CollapsingHeader("Color", ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::ColorPicker3("Color", chosen_rgb_color); + } + if (ImGui::CollapsingHeader("Layer Tools", ImGuiTreeNodeFlags_DefaultOpen)) + { + if (ImGui::Button("Clear")) + { + this->canvas->clear(); + } + } + } + ImGui::End(); + + if (mouse_position.x >= 200 && mouse_position.x <= 200 + this->canvas->getWidth() + && mouse_position.y >= 0 && mouse_position.y <= this->canvas->getHeight()) + { + if (this->state == State::LineTo) + { + auto line_pending = shape::Line::from(x1, y1) + .to(mouse_position.x - 200, mouse_position.y) + .withWidth(line_width_size) + .withColor(chosen_color); + + printf("size: %d\n", line_width_size); + + if (line_is_dotted) + { + shape::Line line_from_to_mouse_position = line_pending.isDotted(true).build(); + this->canvas->drawShape(&line_from_to_mouse_position); + } + else + { + shape::Line line_from_to_mouse_position = line_pending.build(); + this->canvas->drawShape(&line_from_to_mouse_position); + } + } + } + + // Begin canvas draw + +// sf::Vector2i mouse_pos = sf::Mouse::getPosition(*(this->window)); +// auto l = shape::Line::from(300, 300).isDotted(true).to(mouse_pos.x - 200, mouse_pos.y).build(); + +// int xc = 300; +// int yc = 50; +// +// int x = 0; +// int y = 0; +// int d = (x * x) + (2 * x) - (100 * y) - 49; +// while(x <= 50) +// { +// if (d >= 0) +// { +// d += 2 * x - 97; +// y++; +// } +// else +// { +// d += 2 * x + 3; +// } +// x++; +// this->canvas->setPixel(xc + x, yc + y, Color::Red()); +// this->canvas->setPixel(xc - x, yc + y, Color::Red()); +// if (x == 50) +// { +// break; +// } +// } + +// int x_ = 50; +// int y_ = 25; +// int d_ = 4 * (x_ * x_) + 4 * x_ - 400 * y_ - 399; +// while(y_ <= 400) +// { +// if (d_ >= 0) +// { +// d_ += -400; +// } +// else +// { +// d_ += 8 * x_ - 392; +// x_++; +// } +// y_++; +// this->canvas->setPixel(xc + x_, yc + y_, Color::Red()); +// this->canvas->setPixel(xc - x_, yc + y_, Color::Red()); +// } + +// auto l3 = shape::Line::from(300, 300).isDotted(false).to(400, 300).withWidth(5).build(); +// this->canvas->drawShape(&l3); +// +// auto l4 = shape::Line::from(300, 300).isDotted(false).to(200, 300).withWidth(5).build(); +// this->canvas->drawShape(&l4); +// +// auto l5 = shape::Line::from(300, 300).isDotted(false).to(300, 400).withWidth(5).build(); +// this->canvas->drawShape(&l5); +// +// auto l6 = shape::Line::from(300, 300).isDotted(false).to(300, 200).withWidth(5).build(); +// this->canvas->drawShape(&l6); +// +// // Diagonal +// +// auto l = shape::Line::from(300, 300).isDotted(false).to(400, 400).withWidth(5).build(); +// this->canvas->drawShape(&l); +// +// auto l2 = shape::Line::from(300, 300).isDotted(false).to(200, 200).withWidth(5).build(); +// this->canvas->drawShape(&l2); +// +// auto l7 = shape::Line::from(300, 300).isDotted(false).to(400, 200).withWidth(5).build(); +// this->canvas->drawShape(&l7); +// +// auto l8 = shape::Line::from(300, 300).isDotted(false).to(200, 400).withWidth(5).build(); +// this->canvas->drawShape(&l8); +// +// // Quadrant 1 +// +// // Sharp +// auto l9 = shape::Line::from(300, 300).isDotted(false).to(400, 350).withWidth(5).build(); +// this->canvas->drawShape(&l9); +// +// // Steep +// auto l10 = shape::Line::from(300, 300).isDotted(false).to(350, 400).withWidth(5).build(); +// this->canvas->drawShape(&l10); +// +// // Quadrant 2 +// +// // Sharp +// auto l12 = shape::Line::from(300, 300).isDotted(false).to(200, 350).withWidth(5).build(); +// this->canvas->drawShape(&l12); +// +// // Steep +// auto l11 = shape::Line::from(300, 300).isDotted(false).to(250, 400).withWidth(5).build(); +// this->canvas->drawShape(&l11); +// +// // Quadrant 3 +// +// // Sharp +// auto l13 = shape::Line::from(300, 300).isDotted(false).to(200, 250).withWidth(5).build(); +// this->canvas->drawShape(&l13); +// +// // Steep +// auto l14 = shape::Line::from(300, 300).isDotted(false).to(250, 200).withWidth(5).build(); +// this->canvas->drawShape(&l14); +// +// // Quadrant 4 +// +// // Sharp +// auto l15 = shape::Line::from(300, 300).isDotted(false).to(350, 200).withWidth(5).build(); +// this->canvas->drawShape(&l15); +// +// // Steep +// auto l16 = shape::Line::from(300, 300).isDotted(false).to(400, 250).withWidth(5).build(); +// this->canvas->drawShape(&l16); + + // End canvas draw + + if (this->canvas->isAlternateOn()) + { + this->canvas->alternateUpdate(); + } + else + { + this->canvas->update(); + } + + this->window->draw(*this->canvas); +// this->window->draw(fps); + + ImGui::SFML::Render(*this->window); + this->window->display(); + } +} \ No newline at end of file diff --git a/src/application.hpp b/src/application.hpp index 9724129..84dbc80 100644 --- a/src/application.hpp +++ b/src/application.hpp @@ -1,18 +1,13 @@ -#pragma once +#ifndef _APPLICATION_HPP +#define _APPLICATION_HPP -#include -#include -#include - -#include -#include #include #include -#include #include "fps.hpp" #include "canvas.hpp" #include "helpers.hpp" +#include "shape/line.hpp" class Application { @@ -35,407 +30,11 @@ class Application public: Application(const unsigned int window_width, const unsigned int window_height, - sf::String title) - { - this->window = new sf::RenderWindow(sf::VideoMode(window_width, window_height, 32), - title); - - sf::Image window_icon; - window_icon.loadFromFile("../assets/icon-32x32.png"); - this->window->setIcon(32, 32, window_icon.getPixelsPtr()); - - // 100 FPS should be enough - this->window->setFramerateLimit(60); - this->state = State::Nothing; - ImGui::SFML::Init(*(this->window)); - ImGui::GetIO().IniFilename = nullptr; - } - - ~Application() - { - ImGui::SFML::Shutdown(); - delete this->canvas; - delete this->window; - } - - void dispatch() - { - - this->canvas = new Canvas(800, this->window->getSize().y); - this->canvas->setPosition(sf::Vector2f(200, 0)); - - sf::Clock delta_clock; - sf::Event event{}; - bool line_is_dotted = false; - int line_width_size = 1; - float chosen_rgb_color[3] = {0, 0, 0}; - float main_menu_bar_height = 0; - - int my_image_width = 0; - int my_image_height = 0; - GLuint texture_icon_line = 0; - GLuint texture_icon_pen = 0; - LoadTextureFromFile("../assets/line.png", &texture_icon_line, &my_image_width, &my_image_height); - LoadTextureFromFile("../assets/pen.png", &texture_icon_pen, &my_image_width, &my_image_height); - - int x1, y1; - - while (this->window->isOpen()) - { - sf::Vector2i mouse_position = sf::Mouse::getPosition(*this->window); - Color chosen_color(chosen_rgb_color); - - fps.start(); - this->window->clear(); - - while (this->window->pollEvent(event)) - { - ImGui::SFML::ProcessEvent(event); - - if (event.type == sf::Event::Closed) - { - window->close(); - } - - if (event.type == sf::Event::LostFocus) - { - break; - } - - if (mouse_position.x >= 200 && mouse_position.x <= 200 + this->canvas->getWidth() - && mouse_position.y >= 0 && mouse_position.y <= 0 + this->canvas->getHeight()) - { - if (!sf::Mouse::isButtonPressed(sf::Mouse::Button::Left)) - { - if (this->state == State::PenDraw) - { - this->state = State::PenIdle; - } - } - - if (sf::Mouse::isButtonPressed(sf::Mouse::Button::Left)) - { - if (this->state == State::PenIdle) - { - this->canvas->setPixel(mouse_position.x - 200, mouse_position.y, chosen_color); - x1 = mouse_position.x - 200; - y1 = mouse_position.y; - this->state = State::PenDraw; - } - else if (this->state == State::PenDraw) - { - shape::Line line = shape::Line::from(x1, y1) - .to(mouse_position.x - 200, mouse_position.y) - .withColor(chosen_color) - .build(); - this->canvas->drawShape(&line); - x1 = mouse_position.x - 200; - y1 = mouse_position.y; -// this->canvas->setPixel(mouse_position.x - 200, mouse_position.y, chosen_color); - this->state = State::PenDraw; - } - } - - if (event.type == sf::Event::MouseButtonPressed) - { - if (this->state == State::LineFrom) - { - x1 = mouse_position.x - 200; - y1 = mouse_position.y; - this->state = State::LineTo; - } - else if (this->state == State::LineTo) - { - this->canvas->alternateEnd(); - auto line_pending = shape::Line::from(x1, y1) - .to(mouse_position.x - 200, mouse_position.y) - .withWidth(line_width_size) - .withColor(chosen_color); - - if (line_is_dotted) - { - shape::Line line_from_to_mouse_position = line_pending.isDotted(true).build(); - this->canvas->drawShape(&line_from_to_mouse_position); - } - else - { - shape::Line line_from_to_mouse_position = line_pending.build(); - this->canvas->drawShape(&line_from_to_mouse_position); - } - - this->state = State::LineDone; - } - } - } - } - - if (this->canvas->isAlternateOn()) - { - this->canvas->alternateFromMain(); - } - - ImGui::SFML::Update(*this->window, delta_clock.restart()); - - // Main menu - if (ImGui::BeginMainMenuBar()) - { - main_menu_bar_height = ImGui::GetWindowHeight(); - if (ImGui::BeginMenu("File")) - { - if (ImGui::MenuItem("Open")) - { - char const* filter_pattern[1] = { "*.png" }; - char const* file_name = tinyfd_openFileDialog( - "Open file", - nullptr, - 1, - filter_pattern, - "PNG", - false); - if (!this->canvas->load(file_name)) - { -// MessageBox::error("File could not be loaded. It may not have PNG encoding or have different width and height"); - } - } - if (ImGui::MenuItem("Save")) - { - char const* filter_pattern[1] = { "*.png" }; - char default_file_name[22]; - defaultPNGFilename(default_file_name); - char const* file_name = tinyfd_saveFileDialog( - "Save file", - default_file_name, - 1, - filter_pattern, - "PNG"); - this->canvas->save(file_name); - } - if (ImGui::MenuItem("Close")) - { - this->window->close(); - } - ImGui::EndMenu(); - } - } - ImGui::EndMainMenuBar(); - // End main menu - - ImGui::SetNextWindowPos(ImVec2(0, main_menu_bar_height)); - ImGui::SetNextWindowSize(ImVec2(200, 500)); - if (ImGui::Begin("Toolbox", nullptr, - ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize)) - { - if (ImGui::BeginTabBar("#tab_toolbox")) - { - if (ImGui::BeginTabItem("Shape")) - { - // Pen - if (ImGui::ImageButton(texture_icon_pen, ImVec2(32, 32))) - { - this->state = State::PenIdle; - } - if (ImGui::IsItemHovered()) - ImGui::SetTooltip("Pen"); - - ImGui::SameLine(); - - // Line - if (ImGui::ImageButton(texture_icon_line, ImVec2(32, 32))) - { - this->canvas->alternateBegin(); - this->state = State::LineFrom; - } - if (ImGui::IsItemHovered()) - ImGui::SetTooltip("Line shape"); - } - ImGui::EndTabItem(); - } - ImGui::EndTabBar(); - - if (this->state == State::LineFrom || this->state == State::LineTo) - { - if (ImGui::CollapsingHeader("Line Options", ImGuiTreeNodeFlags_DefaultOpen)) - { - ImGui::Checkbox("Dotted", &line_is_dotted); - - ImGui::SameLine(); - - ImGui::SliderInt("Width", &line_width_size, 1, 5, "%d px"); - } - } - - if (ImGui::CollapsingHeader("Color", ImGuiTreeNodeFlags_DefaultOpen)) - { - ImGui::ColorPicker3("Color", chosen_rgb_color); - } - if (ImGui::CollapsingHeader("Layer Tools", ImGuiTreeNodeFlags_DefaultOpen)) - { - if (ImGui::Button("Clear")) - { - this->canvas->clear(); - } - } - } - ImGui::End(); - - - if (mouse_position.x >= 200 && mouse_position.x <= 200 + this->canvas->getWidth() - && mouse_position.y >= 0 && mouse_position.y <= this->canvas->getHeight()) - { - if (this->state == State::LineTo) - { - auto line_pending = shape::Line::from(x1, y1) - .to(mouse_position.x - 200, mouse_position.y) - .withWidth(line_width_size) - .withColor(chosen_color); - - printf("size: %d\n", line_width_size); - - if (line_is_dotted) - { - shape::Line line_from_to_mouse_position = line_pending.isDotted(true).build(); - this->canvas->drawShape(&line_from_to_mouse_position); - } - else - { - shape::Line line_from_to_mouse_position = line_pending.build(); - this->canvas->drawShape(&line_from_to_mouse_position); - } - } - } - - // Begin canvas draw - -// sf::Vector2i mouse_pos = sf::Mouse::getPosition(*(this->window)); -// auto l = shape::Line::from(300, 300).isDotted(true).to(mouse_pos.x - 200, mouse_pos.y).build(); - -// int xc = 300; -// int yc = 50; -// -// int x = 0; -// int y = 0; -// int d = (x * x) + (2 * x) - (100 * y) - 49; -// while(x <= 50) -// { -// if (d >= 0) -// { -// d += 2 * x - 97; -// y++; -// } -// else -// { -// d += 2 * x + 3; -// } -// x++; -// this->canvas->setPixel(xc + x, yc + y, Color::Red()); -// this->canvas->setPixel(xc - x, yc + y, Color::Red()); -// if (x == 50) -// { -// break; -// } -// } - -// int x_ = 50; -// int y_ = 25; -// int d_ = 4 * (x_ * x_) + 4 * x_ - 400 * y_ - 399; -// while(y_ <= 400) -// { -// if (d_ >= 0) -// { -// d_ += -400; -// } -// else -// { -// d_ += 8 * x_ - 392; -// x_++; -// } -// y_++; -// this->canvas->setPixel(xc + x_, yc + y_, Color::Red()); -// this->canvas->setPixel(xc - x_, yc + y_, Color::Red()); -// } - -// auto l3 = shape::Line::from(300, 300).isDotted(false).to(400, 300).withWidth(5).build(); -// this->canvas->drawShape(&l3); -// -// auto l4 = shape::Line::from(300, 300).isDotted(false).to(200, 300).withWidth(5).build(); -// this->canvas->drawShape(&l4); -// -// auto l5 = shape::Line::from(300, 300).isDotted(false).to(300, 400).withWidth(5).build(); -// this->canvas->drawShape(&l5); -// -// auto l6 = shape::Line::from(300, 300).isDotted(false).to(300, 200).withWidth(5).build(); -// this->canvas->drawShape(&l6); -// -// // Diagonal -// -// auto l = shape::Line::from(300, 300).isDotted(false).to(400, 400).withWidth(5).build(); -// this->canvas->drawShape(&l); -// -// auto l2 = shape::Line::from(300, 300).isDotted(false).to(200, 200).withWidth(5).build(); -// this->canvas->drawShape(&l2); -// -// auto l7 = shape::Line::from(300, 300).isDotted(false).to(400, 200).withWidth(5).build(); -// this->canvas->drawShape(&l7); -// -// auto l8 = shape::Line::from(300, 300).isDotted(false).to(200, 400).withWidth(5).build(); -// this->canvas->drawShape(&l8); -// -// // Quadrant 1 -// -// // Sharp -// auto l9 = shape::Line::from(300, 300).isDotted(false).to(400, 350).withWidth(5).build(); -// this->canvas->drawShape(&l9); -// -// // Steep -// auto l10 = shape::Line::from(300, 300).isDotted(false).to(350, 400).withWidth(5).build(); -// this->canvas->drawShape(&l10); -// -// // Quadrant 2 -// -// // Sharp -// auto l12 = shape::Line::from(300, 300).isDotted(false).to(200, 350).withWidth(5).build(); -// this->canvas->drawShape(&l12); -// -// // Steep -// auto l11 = shape::Line::from(300, 300).isDotted(false).to(250, 400).withWidth(5).build(); -// this->canvas->drawShape(&l11); -// -// // Quadrant 3 -// -// // Sharp -// auto l13 = shape::Line::from(300, 300).isDotted(false).to(200, 250).withWidth(5).build(); -// this->canvas->drawShape(&l13); -// -// // Steep -// auto l14 = shape::Line::from(300, 300).isDotted(false).to(250, 200).withWidth(5).build(); -// this->canvas->drawShape(&l14); -// -// // Quadrant 4 -// -// // Sharp -// auto l15 = shape::Line::from(300, 300).isDotted(false).to(350, 200).withWidth(5).build(); -// this->canvas->drawShape(&l15); -// -// // Steep -// auto l16 = shape::Line::from(300, 300).isDotted(false).to(400, 250).withWidth(5).build(); -// this->canvas->drawShape(&l16); - - // End canvas draw + sf::String title); - if (this->canvas->isAlternateOn()) - { - this->canvas->alternateUpdate(); - } - else - { - this->canvas->update(); - } + ~Application(); - this->window->draw(*this->canvas); -// this->window->draw(fps); + void dispatch(); +}; - ImGui::SFML::Render(*this->window); - this->window->display(); - } - } -}; \ No newline at end of file +#endif diff --git a/src/canvas.cpp b/src/canvas.cpp new file mode 100644 index 0000000..e99a9e3 --- /dev/null +++ b/src/canvas.cpp @@ -0,0 +1,144 @@ +#include "canvas.hpp" + +#include + +Canvas::Canvas(const unsigned int width, const unsigned int height, sf::Vector2f position) +{ + this->is_alternate_on = false; + this->width = width; + this->height = height; + this->position = position; + this->sprite.setPosition(position); + this->pixels = new sf::Uint8[this->width * this->height * 4]; + this->texture.create(this->width, this->height); + this->sprite.setTexture(this->texture); + this->clear(); +} + +unsigned int Canvas::getWidth() const +{ + return this->width; +} + +unsigned int Canvas::getHeight() const +{ + return this->height; +} + +bool Canvas::isAlternateOn() +{ + return this->is_alternate_on; +} + +void Canvas::alternateBegin() +{ + this->is_alternate_on = true; + this->pixels_alternate = new sf::Uint8[this->width * this->height * 4]; + std::copy(this->pixels, this->pixels + (this->width * this->height * 4), this->pixels_alternate); +} + +void Canvas::alternateFromMain() +{ + std::copy(this->pixels, this->pixels + (this->width * this->height * 4), this->pixels_alternate); +} + +void Canvas::alternateEnd() +{ + this->is_alternate_on = false; + delete this->pixels_alternate; +} + +void Canvas::alternateSetPixel(int x, int y, Color color) +{ + const int current_pixel_pos = (x + (y * this->width)) * 4; + this->pixels_alternate[current_pixel_pos] = color.getRed(); + this->pixels_alternate[current_pixel_pos + 1] = color.getGreen(); + this->pixels_alternate[current_pixel_pos + 2] = color.getBlue(); + this->pixels_alternate[current_pixel_pos + 3] = color.getAlpha(); +} + +void Canvas::alternateUpdate() +{ + this->texture.update(this->pixels_alternate); +} + +bool Canvas::save(const char* const file_name) +{ + return (bool) lodepng_encode32_file(file_name, this->pixels, this->width, this->height); +} + +bool Canvas::load(const char* const file_name) +{ + sf::Uint8 *temp_source; + unsigned int loaded_width, loaded_height; + if (lodepng_decode32_file(&temp_source, &loaded_width, &loaded_height, file_name)) + { + printf("Can't load image, it may not encoded in PNG\n"); + return false; + } + + if (this->width != loaded_width || this->height != loaded_height) + { + printf("Invalid width and height\n"); + return false; + } + + std::memcpy(this->pixels, temp_source, this->width * this->height * 4); + std::free(temp_source); + return true; +} + + +void Canvas::setPosition(sf::Vector2f position) +{ + this->position = position; + this->sprite.setPosition(position); +} + +sf::Vector2f Canvas::getPosition() +{ + return this->sprite.getPosition(); +} + +Canvas::~Canvas() +{ + delete pixels; +} + +void Canvas::setPixel(int x, int y, Color color) +{ + const int current_pixel_pos = (x + (y * this->width)) * 4; + this->pixels[current_pixel_pos] = color.getRed(); + this->pixels[current_pixel_pos + 1] = color.getGreen(); + this->pixels[current_pixel_pos + 2] = color.getBlue(); + this->pixels[current_pixel_pos + 3] = color.getAlpha(); +} + +void Canvas::update() +{ + this->texture.update(this->pixels); +} + +void Canvas::clear() +{ + std::memset(this->pixels, 255, this->width * this->height * 4); +} + +void Canvas::drawShapes(std::vector canvas_drawables) +{ + for (std::vector::iterator it = canvas_drawables.begin(); + it != canvas_drawables.end(); ++it) + { + (*it)->draw(this); + } +} + +void Canvas::drawShape(CanvasDrawable* canvas_drawable) +{ + canvas_drawable->draw(this); +} + +void Canvas::draw(sf::RenderTarget& target, sf::RenderStates states) const +{ + target.draw(sprite); +} \ No newline at end of file diff --git a/src/canvas.hpp b/src/canvas.hpp index 1d84d65..362bbd2 100644 --- a/src/canvas.hpp +++ b/src/canvas.hpp @@ -1,4 +1,5 @@ -#pragma once +#ifndef _CANVAS_HPP +#define _CANVAS_HPP #include @@ -11,17 +12,7 @@ #include "color.hpp" -#include "../lib/lodepng/lodepng.h" -// Set it up manually by renaming the lodepng.cpp to lodepng.c -#include "../lib/lodepng/lodepng.c" - -class Canvas; - -class CanvasDrawable -{ - public: - virtual void draw(Canvas*) = 0; -}; +class CanvasDrawable; class Canvas: public sf::Drawable { @@ -36,146 +27,53 @@ class Canvas: public sf::Drawable bool is_alternate_on; public: - Canvas(const unsigned int width, const unsigned int height, sf::Vector2f position = sf::Vector2f(0.0f, 0.0f)) - { - this->is_alternate_on = false; - this->width = width; - this->height = height; - this->position = position; - this->sprite.setPosition(position); - this->pixels = new sf::Uint8[this->width * this->height * 4]; - this->texture.create(this->width, this->height); - this->sprite.setTexture(this->texture); - this->clear(); - } - - unsigned int getWidth() const - { - return this->width; - } - - inline unsigned int getHeight() const - { - return this->height; - } - - inline bool isAlternateOn() - { - return this->is_alternate_on; - } - - inline void alternateBegin() - { - this->is_alternate_on = true; - this->pixels_alternate = new sf::Uint8[this->width * this->height * 4]; - std::copy(this->pixels, this->pixels + (this->width * this->height * 4), this->pixels_alternate); - } - - inline void alternateFromMain() - { - std::copy(this->pixels, this->pixels + (this->width * this->height * 4), this->pixels_alternate); - } - - inline void alternateEnd() - { - this->is_alternate_on = false; - delete this->pixels_alternate; - } - - inline void alternateSetPixel(int x, int y, Color color) - { - const int current_pixel_pos = (x + (y * this->width)) * 4; - this->pixels_alternate[current_pixel_pos] = color.getRed(); - this->pixels_alternate[current_pixel_pos + 1] = color.getGreen(); - this->pixels_alternate[current_pixel_pos + 2] = color.getBlue(); - this->pixels_alternate[current_pixel_pos + 3] = color.getAlpha(); - } - - inline void alternateUpdate() - { - this->texture.update(this->pixels_alternate); - } - - inline bool save(const char* const file_name) - { - return (bool) lodepng_encode32_file(file_name, this->pixels, this->width, this->height); - } - - inline bool load(const char* const file_name) - { - sf::Uint8 *temp_source; - unsigned int loaded_width, loaded_height; - if (lodepng_decode32_file(&temp_source, &loaded_width, &loaded_height, file_name)) - { - printf("Can't load image, it may not encoded in PNG\n"); - return false; - } - - if (this->width != loaded_width || this->height != loaded_height) - { - printf("Invalid width and height\n"); - return false; - } - - std::memcpy(this->pixels, temp_source, this->width * this->height * 4); - std::free(temp_source); - return true; - } - - - inline void setPosition(sf::Vector2f position) - { - this->position = position; - this->sprite.setPosition(position); - } - - inline sf::Vector2f getPosition() - { - return this->sprite.getPosition(); - } - - ~Canvas() - { - delete pixels; - } - - inline void setPixel(int x, int y, Color color) - { - const int current_pixel_pos = (x + (y * this->width)) * 4; - this->pixels[current_pixel_pos] = color.getRed(); - this->pixels[current_pixel_pos + 1] = color.getGreen(); - this->pixels[current_pixel_pos + 2] = color.getBlue(); - this->pixels[current_pixel_pos + 3] = color.getAlpha(); - } - - void update() - { - this->texture.update(this->pixels); - } - - void clear() - { - std::memset(this->pixels, 255, this->width * this->height * 4); - } - - void drawShapes(std::vector canvas_drawables) - { - for (std::vector::iterator it = canvas_drawables.begin(); - it != canvas_drawables.end(); ++it) - { - (*it)->draw(this); - } - } - - inline void drawShape(CanvasDrawable* canvas_drawable) - { - canvas_drawable->draw(this); - } - - void draw(sf::RenderTarget& target, sf::RenderStates states) const - { - target.draw(sprite); - } + Canvas(const unsigned int width, const unsigned int height, sf::Vector2f position = sf::Vector2f(0.0f, 0.0f)); + + unsigned int getWidth() const; + + unsigned int getHeight() const; + + bool isAlternateOn(); + + void alternateBegin(); + + void alternateFromMain(); + + void alternateEnd(); + + void alternateSetPixel(int x, int y, Color color); + + void alternateUpdate(); + + bool save(const char* const file_name); + + bool load(const char* const file_name); + + + void setPosition(sf::Vector2f position); + + sf::Vector2f getPosition(); + + ~Canvas(); + + void setPixel(int x, int y, Color color); + + void update(); + + void clear(); + + void drawShapes(std::vector canvas_drawables); + + void drawShape(CanvasDrawable* canvas_drawable); + + void draw(sf::RenderTarget& target, sf::RenderStates states) const; +}; + + +class CanvasDrawable +{ +public: + virtual void draw(Canvas*) = 0; }; -#include "shape/line.hpp" +#endif diff --git a/src/color.hpp b/src/color.hpp index 4c9eb52..1e4a7ef 100644 --- a/src/color.hpp +++ b/src/color.hpp @@ -1,4 +1,7 @@ -#pragma once +#ifndef _COLOR_HPP +#define _COLOR_HPP + +#include class Color { @@ -75,4 +78,6 @@ class Color Color color(255, 255, 255, 255); return color; } -}; \ No newline at end of file +}; + +#endif diff --git a/src/fps.cpp b/src/fps.cpp new file mode 100644 index 0000000..a9ff0e7 --- /dev/null +++ b/src/fps.cpp @@ -0,0 +1,29 @@ +#include "fps.hpp" + +#include + +FPS::FPS(unsigned int character_size, const char* font_file_location) +{ + this->current_time = 0; + this->character_size = character_size; + this->frame_per_second_font.loadFromFile(font_file_location); +} + +void FPS::start() +{ + current_time = clock.restart().asSeconds(); +} + +void FPS::draw(sf::RenderTarget& target, sf::RenderStates states) const +{ + float current_frame_per_second = 1.0 / current_time; + + // Convert to C string + char frame_per_second_string[10]; + std::sprintf(frame_per_second_string, "FPS: %d", (int)current_frame_per_second); + + sf::Text frame_per_second_text(sf::String(frame_per_second_string), + this->frame_per_second_font, this->character_size); + frame_per_second_text.setPosition(sf::Vector2f(0, 500)); + target.draw(frame_per_second_text); +} \ No newline at end of file diff --git a/src/fps.hpp b/src/fps.hpp index c7b42df..a74a6c1 100644 --- a/src/fps.hpp +++ b/src/fps.hpp @@ -1,4 +1,5 @@ -#pragma once +#ifndef _FPS_HPP +#define _FPS_HPP #include @@ -11,33 +12,13 @@ class FPS: public sf::Drawable unsigned int character_size; public: - FPS(unsigned int character_size = 15, const char * font_file_location = "../fonts/OpenSans-Regular.ttf") - { - this->current_time = 0; - this->character_size = character_size; - this->frame_per_second_font.loadFromFile(font_file_location); - } + FPS(unsigned int character_size = 15, const char * font_file_location = "../fonts/OpenSans-Regular.ttf"); - ~FPS() - { - } + ~FPS() = default; - void start() - { - current_time = clock.restart().asSeconds(); - } + void start(); - void draw(sf::RenderTarget& target, sf::RenderStates states) const - { - float current_frame_per_second = 1.0 / current_time; - - // Convert to C string - char frame_per_second_string[10]; - std::sprintf(frame_per_second_string, "FPS: %d", (int) current_frame_per_second); - - sf::Text frame_per_second_text(sf::String(frame_per_second_string), - this->frame_per_second_font, this->character_size); - frame_per_second_text.setPosition(sf::Vector2f(0, 500)); - target.draw(frame_per_second_text); - } + void draw(sf::RenderTarget& target, sf::RenderStates states) const; }; + +#endif diff --git a/src/helpers.cpp b/src/helpers.cpp new file mode 100644 index 0000000..8f3d06f --- /dev/null +++ b/src/helpers.cpp @@ -0,0 +1,46 @@ +#include +#include + +#include + +#include + +// Simple helper function to load an image into a OpenGL texture with common settings +bool LoadTextureFromFile(const char* filename, unsigned int* out_texture, int* out_width, int* out_height) +{ + // Load from file + int image_width = 0; + int image_height = 0; + unsigned char* image_data = stbi_load(filename, &image_width, &image_height, NULL, 4); + if (image_data == NULL) + return false; + + // Create a OpenGL texture identifier + GLuint image_texture; + glGenTextures(1, &image_texture); + glBindTexture(GL_TEXTURE_2D, image_texture); + + // Setup filtering parameters for display + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + // Upload pixels into texture + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image_width, image_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data); + stbi_image_free(image_data); + + *out_texture = image_texture; + *out_width = image_width; + *out_height = image_height; + + return true; +} + +void defaultPNGFilename(char string[22]) +{ + std::time_t now = std::time(nullptr); + std::tm* time_s = std::localtime(&now); + std::sprintf(string, "%d-%d-%d-%d-%d-%d.png", + time_s->tm_year + 1900, + time_s->tm_mon + 1, time_s->tm_mday, time_s->tm_hour + 1, time_s->tm_min + 1, time_s->tm_sec + 1); +} \ No newline at end of file diff --git a/src/helpers.hpp b/src/helpers.hpp index 4786cce..645f34a 100644 --- a/src/helpers.hpp +++ b/src/helpers.hpp @@ -1,52 +1,9 @@ -#pragma once - -#include - -#include - -#define STB_IMAGE_IMPLEMENTATION -#include "../lib/stb/stb_image.h" - -#include "../lib/tinyfiledialogs/tinyfiledialogs.c" - -#include "../lib/lodepng/lodepng.h" +#ifndef _HELPERS_HPP +#define _HELPERS_HPP // Simple helper function to load an image into a OpenGL texture with common settings -bool LoadTextureFromFile(const char* filename, unsigned int* out_texture, int* out_width, int* out_height) -{ - // Load from file - int image_width = 0; - int image_height = 0; - unsigned char* image_data = stbi_load(filename, &image_width, &image_height, NULL, 4); - if (image_data == NULL) - return false; - - // Create a OpenGL texture identifier - GLuint image_texture; - glGenTextures(1, &image_texture); - glBindTexture(GL_TEXTURE_2D, image_texture); - - // Setup filtering parameters for display - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - // Upload pixels into texture - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image_width, image_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data); - stbi_image_free(image_data); - - *out_texture = image_texture; - *out_width = image_width; - *out_height = image_height; +bool LoadTextureFromFile(const char* filename, unsigned int* out_texture, int* out_width, int* out_height); - return true; -} +void defaultPNGFilename(char string[22]); -void defaultPNGFilename(char string[22]) -{ - std::time_t now = std::time(nullptr); - std::tm* time_s = std::localtime(&now); - std::sprintf(string, "%d-%d-%d-%d-%d-%d.png", - time_s->tm_year + 1900, - time_s->tm_mon + 1, time_s->tm_mday, time_s->tm_hour + 1, time_s->tm_min + 1, time_s->tm_sec + 1); -} \ No newline at end of file +#endif diff --git a/src/main.cpp b/src/main.cpp index 04820cb..a73249f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,15 +1,10 @@ -#include -#include - -#define PI 3.14159265 -#include - // 0. Naive // Have a problem // 1. EQUATION // TODO // 2. DDA // 3. MID // TODO -#define _LINE_ALGORITHM 2 +//#define _LINE_ALGORITHM 2 +#define STB_IMAGE_IMPLEMENTATION #include "application.hpp" int main(int argc, char *argv[]) diff --git a/src/shape/line.cpp b/src/shape/line.cpp new file mode 100644 index 0000000..e05bca0 --- /dev/null +++ b/src/shape/line.cpp @@ -0,0 +1,631 @@ +#include "line.hpp" + +#include + +namespace shape +{ + void Line::draw(Canvas* canvas) + { + int delta_y = y2 - y1; + int delta_x = x2 - x1; + float m = (float)delta_y / (float)delta_x; + float n = (float)delta_x / (float)delta_y; + + int max_width = this->width - 1; + int min_width = -(this->width - 1); + + if (!canvas->isAlternateOn()) + { + // Horizontal case + if (delta_y == 0) + { + // To left + if (x1 > x2) + { + for (int x = x2; x <= x1; ++x) + { + if ((this->is_dotted && x % 9 < 4) || !this->is_dotted) + { + for (int y_width = min_width; y_width <= max_width; ++y_width) + { + canvas->setPixel(x, y1 - y_width, this->color); + } + } + } + } + // To right + else + { + for (int x = x1; x <= x2; ++x) + { + if ((this->is_dotted && x % 9 < 4) || !this->is_dotted) + { + for (int y_width = min_width; y_width <= max_width; ++y_width) + { + canvas->setPixel(x, y1 + y_width, this->color); + } + } + } + } + } + // Vertical case + else if (delta_x == 0) + { + // To down + if (y1 > y2) + { + for (int y = y2; y <= y1; ++y) + { + if ((this->is_dotted && y % 9 < 4) || !this->is_dotted) + { + for (int x_width = min_width; x_width <= max_width; ++x_width) + { + canvas->setPixel(x1 + x_width, y, this->color); + } + } + } + } + // To up + else + { + for (int y = y1; y <= y2; ++y) + { + if ((this->is_dotted && y % 9 < 4) || !this->is_dotted) + { + for (int x_width = min_width; x_width <= max_width; ++x_width) + { + canvas->setPixel(x1 + x_width, y, this->color); + } + } + } + } + } + // Diagonal + else if (delta_x == delta_y) + { + // To left down + if (delta_x < 0) + { + int total = x1 - x2; + for (int x = 0; x <= total; ++x) + { + if ((this->is_dotted && x % 9 < 4) || !this->is_dotted) + { + for (int x_width = min_width; x_width <= max_width; ++x_width) + { + canvas->setPixel(x1 - x + x_width, y1 - x, this->color); + } + } + } + } + // To right up + else + { + int total = x2 - x1; + for (int x = 0; x <= total; ++x) + { + if ((this->is_dotted && x % 9 < 4) || !this->is_dotted) + { + for (int x_width = min_width; x_width <= max_width; ++x_width) + { + canvas->setPixel(x1 + x + x_width, y1 + x, this->color); + } + } + } + } + } + // Diagonal + else if (delta_x == -delta_y) + { + // To left up + if (delta_x < 0) + { + int total = x1 - x2; + for (int x = 0; x <= total; ++x) + { + if ((this->is_dotted && x % 9 < 4) || !this->is_dotted) + { + for (int x_width = min_width; x_width <= max_width; ++x_width) + { + canvas->setPixel(x1 - x + x_width, y1 + x, this->color); + } + } + } + } + // To right down + else + { + int total = x2 - x1; + for (int x = 0; x <= total; ++x) + { + if ((this->is_dotted && x % 9 < 4) || !this->is_dotted) + { + for (int x_width = min_width; x_width <= max_width; ++x_width) + { + canvas->setPixel(x1 + x + x_width, y1 - x, this->color); + } + } + } + } + } + // Quadrant 1 sharp + else if (delta_x > delta_y && delta_x > 0 & delta_y > 0) + { + float y = y1; + + for (int x = x1; x <= x2; ++x) + { + if ((this->is_dotted && x % 9 < 4) || !this->is_dotted) + { + for (int x_width = min_width; x_width <= max_width; ++x_width) + { + canvas->setPixel(x, (int)std::round(y) + x_width, this->color); + } + } + y += m; + } + } + // Quadrant 1 steep + else if (delta_x < delta_y && delta_x > 0 & delta_y > 0) + { + float x = x1; + + for (int y = y1; y <= y2; ++y) + { + if ((this->is_dotted && y % 9 < 4) || !this->is_dotted) + { + for (int y_width = min_width; y_width <= max_width; ++y_width) + { + canvas->setPixel((int)std::round(x) + y_width, y, this->color); + } + } + x += n; + } + } + // Quadrant 2 steep + else if (-delta_x < delta_y && delta_x < 0 & delta_y > 0) + { + float x = x1; + + for (int y = y1; y <= y2; ++y) + { + if ((this->is_dotted && y % 9 < 4) || !this->is_dotted) + { + for (int y_width = min_width; y_width <= max_width; ++y_width) + { + canvas->setPixel((int)std::round(x) + y_width, y, this->color); + } + } + x += n; + } + } + // Quadrant 2 sharp + else if (-delta_x > delta_y && delta_x < 0 & delta_y > 0) + { + float y = y2; + + for (int x = x2; x <= x1; ++x) + { + if ((this->is_dotted && x % 9 < 4) || !this->is_dotted) + { + for (int x_width = min_width; x_width <= max_width; ++x_width) + { + canvas->setPixel(x, (int)std::round(y) + x_width, this->color); + } + } + y += m; + } + } + // Quadrant 3 steep + else if (-delta_x < -delta_y && delta_x < 0 & delta_y < 0) + { + float x = x2; + + for (int y = y2; y <= y1; ++y) + { + if ((this->is_dotted && y % 9 < 4) || !this->is_dotted) + { + for (int y_width = min_width; y_width <= max_width; ++y_width) + { + canvas->setPixel((int)std::round(x) + y_width, y, this->color); + } + } + x += n; + } + } + // Quadrant 3 sharp + else if (-delta_x > -delta_y && delta_x < 0 & delta_y < 0) + { + float y = y2; + + for (int x = x2; x <= x1; ++x) + { + if ((this->is_dotted && x % 9 < 4) || !this->is_dotted) + { + for (int x_width = min_width; x_width <= max_width; ++x_width) + { + canvas->setPixel(x, (int)std::round(y) + x_width, this->color); + } + } + y += m; + } + } + // Quadrant 4 steep + else if (delta_x < -delta_y && delta_x > 0 & delta_y < 0) + { + float x = x2; + + for (int y = y2; y <= y1; ++y) + { + if ((this->is_dotted && y % 9 < 4) || !this->is_dotted) + { + for (int y_width = min_width; y_width <= max_width; ++y_width) + { + canvas->setPixel((int)std::round(x) + y_width, y, this->color); + } + } + x += n; + } + } + // Quadrant 4 sharp + else if (delta_x > -delta_y && delta_x > 0 & delta_y < 0) + { + float y = y1; + + for (int x = x1; x <= x2; ++x) + { + if ((this->is_dotted && x % 9 < 4) || !this->is_dotted) + { + for (int x_width = min_width; x_width <= max_width; ++x_width) + { + canvas->setPixel(x, (int)std::round(y) + x_width, this->color); + } + } + y += m; + } + } + } + else + { + // Horizontal case + if (delta_y == 0) + { + // To left + if (x1 > x2) + { + for (int x = x2; x <= x1; ++x) + { + if ((this->is_dotted && x % 9 < 4) || !this->is_dotted) + { + for (int y_width = min_width; y_width <= max_width; ++y_width) + { + canvas->alternateSetPixel(x, y1 - y_width, this->color); + } + } + } + } + // To right + else + { + for (int x = x1; x <= x2; ++x) + { + if ((this->is_dotted && x % 9 < 4) || !this->is_dotted) + { + for (int y_width = min_width; y_width <= max_width; ++y_width) + { + canvas->alternateSetPixel(x, y1 + y_width, this->color); + } + } + } + } + } + // Vertical case + else if (delta_x == 0) + { + // To down + if (y1 > y2) + { + for (int y = y2; y <= y1; ++y) + { + if ((this->is_dotted && y % 9 < 4) || !this->is_dotted) + { + for (int x_width = min_width; x_width <= max_width; ++x_width) + { + canvas->alternateSetPixel(x1 + x_width, y, this->color); + } + } + } + } + // To up + else + { + for (int y = y1; y <= y2; ++y) + { + if ((this->is_dotted && y % 9 < 4) || !this->is_dotted) + { + for (int x_width = min_width; x_width <= max_width; ++x_width) + { + canvas->alternateSetPixel(x1 + x_width, y, this->color); + } + } + } + } + } + // Diagonal + else if (delta_x == delta_y) + { + // To left down + if (delta_x < 0) + { + int total = x1 - x2; + for (int x = 0; x <= total; ++x) + { + if ((this->is_dotted && x % 9 < 4) || !this->is_dotted) + { + for (int x_width = min_width; x_width <= max_width; ++x_width) + { + canvas->alternateSetPixel(x1 - x + x_width, y1 - x, this->color); + } + } + } + } + // To right up + else + { + int total = x2 - x1; + for (int x = 0; x <= total; ++x) + { + if ((this->is_dotted && x % 9 < 4) || !this->is_dotted) + { + for (int x_width = min_width; x_width <= max_width; ++x_width) + { + canvas->alternateSetPixel(x1 + x + x_width, y1 + x, this->color); + } + } + } + } + } + // Diagonal + else if (delta_x == -delta_y) + { + // To left up + if (delta_x < 0) + { + int total = x1 - x2; + for (int x = 0; x <= total; ++x) + { + if ((this->is_dotted && x % 9 < 4) || !this->is_dotted) + { + for (int x_width = min_width; x_width <= max_width; ++x_width) + { + canvas->alternateSetPixel(x1 - x + x_width, y1 + x, this->color); + } + } + } + } + // To right down + else + { + int total = x2 - x1; + for (int x = 0; x <= total; ++x) + { + if ((this->is_dotted && x % 9 < 4) || !this->is_dotted) + { + for (int x_width = min_width; x_width <= max_width; ++x_width) + { + canvas->alternateSetPixel(x1 + x + x_width, y1 - x, this->color); + } + } + } + } + } + // Quadrant 1 sharp + else if (delta_x > delta_y && delta_x > 0 & delta_y > 0) + { + float y = y1; + + for (int x = x1; x <= x2; ++x) + { + if ((this->is_dotted && x % 9 < 4) || !this->is_dotted) + { + for (int x_width = min_width; x_width <= max_width; ++x_width) + { + canvas->alternateSetPixel(x, (int)std::round(y) + x_width, this->color); + } + } + y += m; + } + } + // Quadrant 1 steep + else if (delta_x < delta_y && delta_x > 0 & delta_y > 0) + { + float x = x1; + + for (int y = y1; y <= y2; ++y) + { + if ((this->is_dotted && y % 9 < 4) || !this->is_dotted) + { + for (int y_width = min_width; y_width <= max_width; ++y_width) + { + canvas->alternateSetPixel((int)std::round(x) + y_width, y, this->color); + } + } + x += n; + } + } + // Quadrant 2 steep + else if (-delta_x < delta_y && delta_x < 0 & delta_y > 0) + { + float x = x1; + + for (int y = y1; y <= y2; ++y) + { + if ((this->is_dotted && y % 9 < 4) || !this->is_dotted) + { + for (int y_width = min_width; y_width <= max_width; ++y_width) + { + canvas->alternateSetPixel((int)std::round(x) + y_width, y, this->color); + } + } + x += n; + } + } + // Quadrant 2 sharp + else if (-delta_x > delta_y && delta_x < 0 & delta_y > 0) + { + float y = y2; + + for (int x = x2; x <= x1; ++x) + { + if ((this->is_dotted && x % 9 < 4) || !this->is_dotted) + { + for (int x_width = min_width; x_width <= max_width; ++x_width) + { + canvas->alternateSetPixel(x, (int)std::round(y) + x_width, this->color); + } + } + y += m; + } + } + // Quadrant 3 steep + else if (-delta_x < -delta_y && delta_x < 0 & delta_y < 0) + { + float x = x2; + + for (int y = y2; y <= y1; ++y) + { + if ((this->is_dotted && y % 9 < 4) || !this->is_dotted) + { + for (int y_width = min_width; y_width <= max_width; ++y_width) + { + canvas->alternateSetPixel((int)std::round(x) + y_width, y, this->color); + } + } + x += n; + } + } + // Quadrant 3 sharp + else if (-delta_x > -delta_y && delta_x < 0 & delta_y < 0) + { + float y = y2; + + for (int x = x2; x <= x1; ++x) + { + if ((this->is_dotted && x % 9 < 4) || !this->is_dotted) + { + for (int x_width = min_width; x_width <= max_width; ++x_width) + { + canvas->alternateSetPixel(x, (int)std::round(y) + x_width, this->color); + } + } + y += m; + } + } + // Quadrant 4 steep + else if (delta_x < -delta_y && delta_x > 0 & delta_y < 0) + { + float x = x2; + + for (int y = y2; y <= y1; ++y) + { + if ((this->is_dotted && y % 9 < 4) || !this->is_dotted) + { + for (int y_width = min_width; y_width <= max_width; ++y_width) + { + canvas->alternateSetPixel((int)std::round(x) + y_width, y, this->color); + } + } + x += n; + } + } + // Quadrant 4 sharp + else if (delta_x > -delta_y && delta_x > 0 & delta_y < 0) + { + float y = y1; + + for (int x = x1; x <= x2; ++x) + { + if ((this->is_dotted && x % 9 < 4) || !this->is_dotted) + { + for (int x_width = min_width; x_width <= max_width; ++x_width) + { + canvas->alternateSetPixel(x, (int)std::round(y) + x_width, this->color); + } + } + y += m; + } + } + } + } + + Line::LineBuilder::LineBuilder() + { + this->is_dotted = false; + this->color = Color::Red(); + this->width = 1; + } + + Line::LineBuilder Line::LineBuilder::from(int x1, int y1) + { + this->x1 = x1; + this->y1 = y1; + return *this; + } + + Line::LineBuilder Line::LineBuilder::to(int x2, int y2) + { + this->x2 = x2; + this->y2 = y2; + return *this; + } + + Line::LineBuilder Line::LineBuilder::withColor(Color color) + { + this->color = color; + return *this; + } + + Line::LineBuilder Line::LineBuilder::withWidth(int width) + { + this->width = width; + return *this; + } + + Line::LineBuilder Line::LineBuilder::isDotted(bool is_dotted) + { + this->is_dotted = is_dotted; + return *this; + } + + Line Line::LineBuilder::build() + { + Line line(this->x1, this->y1, this->x2, this->y2, this->color, this->is_dotted, this->width); + return line; + } + + Line::Line(int x1, int y1, int x2, int y2, Color color, bool is_dotted, int width) + { + this->x1 = x1; + this->y1 = y1; + this->x2 = x2; + this->y2 = y2; + this->color = color; + this->is_dotted = is_dotted; + this->width = width; + } + + Line::LineBuilder Line::from(int x1, int y1) + { + Line::LineBuilder line_builder; + line_builder.from(x1, y1); + return line_builder; + } + + float Line::slope(int x1, int y1, int x2, int y2) + { + float delta_y = (float)(y2 - y1); + float delta_x = (float)(x2 - x1); + float gradient = delta_y / delta_x; + return std::atan(gradient); + } +} \ No newline at end of file diff --git a/src/shape/line.hpp b/src/shape/line.hpp index 2d37bb6..41bc95c 100644 --- a/src/shape/line.hpp +++ b/src/shape/line.hpp @@ -1,12 +1,8 @@ -#pragma once - -#include - -#include -#include -#include +#ifndef _SHAPE_LINE_HPP +#define _SHAPE_LINE_HPP #include "../canvas.hpp" +#include "../color.hpp" namespace shape { @@ -21,559 +17,7 @@ namespace shape int width; bool is_dotted; - void draw(Canvas* canvas) override - { - int delta_y = y2 - y1; - int delta_x = x2 - x1; - float m = (float) delta_y / (float) delta_x; - float n = (float) delta_x / (float) delta_y; - - int max_width = this->width - 1; - int min_width = -(this->width - 1); - - if (!canvas->isAlternateOn()) - { - // Horizontal case - if (delta_y == 0) - { - // To left - if (x1 > x2) - { - for (int x = x2; x <= x1; ++x) - { - if ((this->is_dotted && x % 9 < 4) || !this->is_dotted) - { - for (int y_width = min_width; y_width <= max_width; ++y_width) - { - canvas->setPixel(x, y1 - y_width, this->color); - } - } - } - } - // To right - else - { - for (int x = x1; x <= x2; ++x) - { - if ((this->is_dotted && x % 9 < 4) || !this->is_dotted) - { - for (int y_width = min_width; y_width <= max_width; ++y_width) - { - canvas->setPixel(x, y1 + y_width, this->color); - } - } - } - } - } - // Vertical case - else if (delta_x == 0) - { - // To down - if (y1 > y2) - { - for (int y = y2; y <= y1; ++y) - { - if ((this->is_dotted && y % 9 < 4) || !this->is_dotted) - { - for (int x_width = min_width; x_width <= max_width; ++x_width) - { - canvas->setPixel(x1 + x_width, y, this->color); - } - } - } - } - // To up - else - { - for (int y = y1; y <= y2; ++y) - { - if ((this->is_dotted && y % 9 < 4) || !this->is_dotted) - { - for (int x_width = min_width; x_width <= max_width; ++x_width) - { - canvas->setPixel(x1 + x_width, y, this->color); - } - } - } - } - } - // Diagonal - else if (delta_x == delta_y) - { - // To left down - if (delta_x < 0) - { - int total = x1 - x2; - for (int x = 0; x <= total; ++x) - { - if ((this->is_dotted && x % 9 < 4) || !this->is_dotted) - { - for (int x_width = min_width; x_width <= max_width; ++x_width) - { - canvas->setPixel(x1 - x + x_width, y1 - x, this->color); - } - } - } - } - // To right up - else - { - int total = x2 - x1; - for (int x = 0; x <= total; ++x) - { - if ((this->is_dotted && x % 9 < 4) || !this->is_dotted) - { - for (int x_width = min_width; x_width <= max_width; ++x_width) - { - canvas->setPixel(x1 + x + x_width, y1 + x, this->color); - } - } - } - } - } - // Diagonal - else if (delta_x == -delta_y) - { - // To left up - if (delta_x < 0) - { - int total = x1 - x2; - for (int x = 0; x <= total; ++x) - { - if ((this->is_dotted && x % 9 < 4) || !this->is_dotted) - { - for (int x_width = min_width; x_width <= max_width; ++x_width) - { - canvas->setPixel(x1 - x + x_width, y1 + x, this->color); - } - } - } - } - // To right down - else - { - int total = x2 - x1; - for (int x = 0; x <= total; ++x) - { - if ((this->is_dotted && x % 9 < 4) || !this->is_dotted) - { - for (int x_width = min_width; x_width <= max_width; ++x_width) - { - canvas->setPixel(x1 + x + x_width, y1 - x, this->color); - } - } - } - } - } - // Quadrant 1 sharp - else if (delta_x > delta_y && delta_x > 0 & delta_y > 0) - { - float y = y1; - - for (int x = x1; x <= x2; ++x) - { - if ((this->is_dotted && x % 9 < 4) || !this->is_dotted) - { - for (int x_width = min_width; x_width <= max_width; ++x_width) - { - canvas->setPixel(x, (int) std::round(y) + x_width, this->color); - } - } - y += m; - } - } - // Quadrant 1 steep - else if (delta_x < delta_y && delta_x > 0 & delta_y > 0) - { - float x = x1; - - for (int y = y1; y <= y2; ++y) - { - if ((this->is_dotted && y % 9 < 4) || !this->is_dotted) - { - for (int y_width = min_width; y_width <= max_width; ++y_width) - { - canvas->setPixel((int)std::round(x) + y_width, y, this->color); - } - } - x += n; - } - } - // Quadrant 2 steep - else if (-delta_x < delta_y && delta_x < 0 & delta_y > 0) - { - float x = x1; - - for (int y = y1; y <= y2; ++y) - { - if ((this->is_dotted && y % 9 < 4) || !this->is_dotted) - { - for (int y_width = min_width; y_width <= max_width; ++y_width) - { - canvas->setPixel((int) std::round(x) + y_width, y, this->color); - } - } - x += n; - } - } - // Quadrant 2 sharp - else if (-delta_x > delta_y && delta_x < 0 & delta_y > 0) - { - float y = y2; - - for (int x = x2; x <= x1; ++x) - { - if ((this->is_dotted && x % 9 < 4) || !this->is_dotted) - { - for (int x_width = min_width; x_width <= max_width; ++x_width) - { - canvas->setPixel(x, (int) std::round(y) + x_width, this->color); - } - } - y += m; - } - } - // Quadrant 3 steep - else if (-delta_x < -delta_y && delta_x < 0 & delta_y < 0) - { - float x = x2; - - for (int y = y2; y <= y1; ++y) - { - if ((this->is_dotted && y % 9 < 4) || !this->is_dotted) - { - for (int y_width = min_width; y_width <= max_width; ++y_width) - { - canvas->setPixel((int) std::round(x) + y_width, y, this->color); - } - } - x += n; - } - } - // Quadrant 3 sharp - else if (-delta_x > -delta_y && delta_x < 0 & delta_y < 0) - { - float y = y2; - - for (int x = x2; x <= x1; ++x) - { - if ((this->is_dotted && x % 9 < 4) || !this->is_dotted) - { - for (int x_width = min_width; x_width <= max_width; ++x_width) - { - canvas->setPixel(x, (int) std::round(y) + x_width, this->color); - } - } - y += m; - } - } - // Quadrant 4 steep - else if (delta_x < -delta_y && delta_x > 0 & delta_y < 0) - { - float x = x2; - - for (int y = y2; y <= y1; ++y) - { - if ((this->is_dotted && y % 9 < 4) || !this->is_dotted) - { - for (int y_width = min_width; y_width <= max_width; ++y_width) - { - canvas->setPixel((int)std::round(x) + y_width, y, this->color); - } - } - x += n; - } - } - // Quadrant 4 sharp - else if (delta_x > -delta_y && delta_x > 0 & delta_y < 0) - { - float y = y1; - - for (int x = x1; x <= x2; ++x) - { - if ((this->is_dotted && x % 9 < 4) || !this->is_dotted) - { - for (int x_width = min_width; x_width <= max_width; ++x_width) - { - canvas->setPixel(x, (int) std::round(y) + x_width, this->color); - } - } - y += m; - } - } - } - else - { - // Horizontal case - if (delta_y == 0) - { - // To left - if (x1 > x2) - { - for (int x = x2; x <= x1; ++x) - { - if ((this->is_dotted && x % 9 < 4) || !this->is_dotted) - { - for (int y_width = min_width; y_width <= max_width; ++y_width) - { - canvas->alternateSetPixel(x, y1 - y_width, this->color); - } - } - } - } - // To right - else - { - for (int x = x1; x <= x2; ++x) - { - if ((this->is_dotted && x % 9 < 4) || !this->is_dotted) - { - for (int y_width = min_width; y_width <= max_width; ++y_width) - { - canvas->alternateSetPixel(x, y1 + y_width, this->color); - } - } - } - } - } - // Vertical case - else if (delta_x == 0) - { - // To down - if (y1 > y2) - { - for (int y = y2; y <= y1; ++y) - { - if ((this->is_dotted && y % 9 < 4) || !this->is_dotted) - { - for (int x_width = min_width; x_width <= max_width; ++x_width) - { - canvas->alternateSetPixel(x1 + x_width, y, this->color); - } - } - } - } - // To up - else - { - for (int y = y1; y <= y2; ++y) - { - if ((this->is_dotted && y % 9 < 4) || !this->is_dotted) - { - for (int x_width = min_width; x_width <= max_width; ++x_width) - { - canvas->alternateSetPixel(x1 + x_width, y, this->color); - } - } - } - } - } - // Diagonal - else if (delta_x == delta_y) - { - // To left down - if (delta_x < 0) - { - int total = x1 - x2; - for (int x = 0; x <= total; ++x) - { - if ((this->is_dotted && x % 9 < 4) || !this->is_dotted) - { - for (int x_width = min_width; x_width <= max_width; ++x_width) - { - canvas->alternateSetPixel(x1 - x + x_width, y1 - x, this->color); - } - } - } - } - // To right up - else - { - int total = x2 - x1; - for (int x = 0; x <= total; ++x) - { - if ((this->is_dotted && x % 9 < 4) || !this->is_dotted) - { - for (int x_width = min_width; x_width <= max_width; ++x_width) - { - canvas->alternateSetPixel(x1 + x + x_width, y1 + x, this->color); - } - } - } - } - } - // Diagonal - else if (delta_x == -delta_y) - { - // To left up - if (delta_x < 0) - { - int total = x1 - x2; - for (int x = 0; x <= total; ++x) - { - if ((this->is_dotted && x % 9 < 4) || !this->is_dotted) - { - for (int x_width = min_width; x_width <= max_width; ++x_width) - { - canvas->alternateSetPixel(x1 - x + x_width, y1 + x, this->color); - } - } - } - } - // To right down - else - { - int total = x2 - x1; - for (int x = 0; x <= total; ++x) - { - if ((this->is_dotted && x % 9 < 4) || !this->is_dotted) - { - for (int x_width = min_width; x_width <= max_width; ++x_width) - { - canvas->alternateSetPixel(x1 + x + x_width, y1 - x, this->color); - } - } - } - } - } - // Quadrant 1 sharp - else if (delta_x > delta_y && delta_x > 0 & delta_y > 0) - { - float y = y1; - - for (int x = x1; x <= x2; ++x) - { - if ((this->is_dotted && x % 9 < 4) || !this->is_dotted) - { - for (int x_width = min_width; x_width <= max_width; ++x_width) - { - canvas->alternateSetPixel(x, (int) std::round(y) + x_width, this->color); - } - } - y += m; - } - } - // Quadrant 1 steep - else if (delta_x < delta_y && delta_x > 0 & delta_y > 0) - { - float x = x1; - - for (int y = y1; y <= y2; ++y) - { - if ((this->is_dotted && y % 9 < 4) || !this->is_dotted) - { - for (int y_width = min_width; y_width <= max_width; ++y_width) - { - canvas->alternateSetPixel((int)std::round(x) + y_width, y, this->color); - } - } - x += n; - } - } - // Quadrant 2 steep - else if (-delta_x < delta_y && delta_x < 0 & delta_y > 0) - { - float x = x1; - - for (int y = y1; y <= y2; ++y) - { - if ((this->is_dotted && y % 9 < 4) || !this->is_dotted) - { - for (int y_width = min_width; y_width <= max_width; ++y_width) - { - canvas->alternateSetPixel((int) std::round(x) + y_width, y, this->color); - } - } - x += n; - } - } - // Quadrant 2 sharp - else if (-delta_x > delta_y && delta_x < 0 & delta_y > 0) - { - float y = y2; - - for (int x = x2; x <= x1; ++x) - { - if ((this->is_dotted && x % 9 < 4) || !this->is_dotted) - { - for (int x_width = min_width; x_width <= max_width; ++x_width) - { - canvas->alternateSetPixel(x, (int) std::round(y) + x_width, this->color); - } - } - y += m; - } - } - // Quadrant 3 steep - else if (-delta_x < -delta_y && delta_x < 0 & delta_y < 0) - { - float x = x2; - - for (int y = y2; y <= y1; ++y) - { - if ((this->is_dotted && y % 9 < 4) || !this->is_dotted) - { - for (int y_width = min_width; y_width <= max_width; ++y_width) - { - canvas->alternateSetPixel((int) std::round(x) + y_width, y, this->color); - } - } - x += n; - } - } - // Quadrant 3 sharp - else if (-delta_x > -delta_y && delta_x < 0 & delta_y < 0) - { - float y = y2; - - for (int x = x2; x <= x1; ++x) - { - if ((this->is_dotted && x % 9 < 4) || !this->is_dotted) - { - for (int x_width = min_width; x_width <= max_width; ++x_width) - { - canvas->alternateSetPixel(x, (int) std::round(y) + x_width, this->color); - } - } - y += m; - } - } - // Quadrant 4 steep - else if (delta_x < -delta_y && delta_x > 0 & delta_y < 0) - { - float x = x2; - - for (int y = y2; y <= y1; ++y) - { - if ((this->is_dotted && y % 9 < 4) || !this->is_dotted) - { - for (int y_width = min_width; y_width <= max_width; ++y_width) - { - canvas->alternateSetPixel((int)std::round(x) + y_width, y, this->color); - } - } - x += n; - } - } - // Quadrant 4 sharp - else if (delta_x > -delta_y && delta_x > 0 & delta_y < 0) - { - float y = y1; - - for (int x = x1; x <= x2; ++x) - { - if ((this->is_dotted && x % 9 < 4) || !this->is_dotted) - { - for (int x_width = min_width; x_width <= max_width; ++x_width) - { - canvas->alternateSetPixel(x, (int) std::round(y) + x_width, this->color); - } - } - y += m; - } - } - } - } + void draw(Canvas* canvas) override; class LineBuilder { @@ -587,77 +31,28 @@ namespace shape int width; public: - LineBuilder() - { - this->is_dotted = false; - this->color = Color::Red(); - this->width = 1; - } + LineBuilder(); - LineBuilder from(int x1, int y1) - { - this->x1 = x1; - this->y1 = y1; - return *this; - } + LineBuilder from(int x1, int y1); - LineBuilder to(int x2, int y2) - { - this->x2 = x2; - this->y2 = y2; - return *this; - } + LineBuilder to(int x2, int y2); - LineBuilder withColor(Color color) - { - this->color = color; - return *this; - } + LineBuilder withColor(Color color); - LineBuilder withWidth(int width) - { - this->width = width; - return *this; - } + LineBuilder withWidth(int width); - LineBuilder isDotted(bool is_dotted) - { - this->is_dotted = is_dotted; - return *this; - } + LineBuilder isDotted(bool is_dotted); - Line build() - { - Line line(this->x1, this->y1, this->x2, this->y2, this->color, this->is_dotted, this->width); - return line; - } + Line build(); }; public: - Line(int x1, int y1, int x2, int y2, Color color = Color::Red(), bool is_dotted = false, int width = 1) - { - this->x1 = x1; - this->y1 = y1; - this->x2 = x2; - this->y2 = y2; - this->color = color; - this->is_dotted = is_dotted; - this->width = width; - } + Line(int x1, int y1, int x2, int y2, Color color = Color::Red(), bool is_dotted = false, int width = 1); - static LineBuilder from(int x1, int y1) - { - LineBuilder line_builder; - line_builder.from(x1, y1); - return line_builder; - } + static LineBuilder from(int x1, int y1); - static float slope(int x1, int y1, int x2, int y2) - { - float delta_y = (float)(y2 - y1); - float delta_x = (float)(x2 - x1); - float gradient = delta_y / delta_x; - return std::atan(gradient); - } + static float slope(int x1, int y1, int x2, int y2); }; -} \ No newline at end of file +} + +#endif