diff --git a/.gitignore b/.gitignore index 2cd3dd4..a207396 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +cmake-wsl-build-debug cmake-build-debug/ .idea/ build/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ae16ea..20325b5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -163,4 +163,5 @@ message(STATUS ${summary}) #add_subdirectory(docs) # Additional applications -add_subdirectory(source/applications) \ No newline at end of file +add_subdirectory(source/applications) +add_subdirectory(source/creator) \ No newline at end of file diff --git a/cmake/external/glad.cmake b/cmake/external/glad.cmake index 1b7dde9..663275b 100644 --- a/cmake/external/glad.cmake +++ b/cmake/external/glad.cmake @@ -3,7 +3,13 @@ include(${CMAKE_SOURCE_DIR}/cmake/tools/CPM.cmake) CPMAddPackage( NAME glad GIT_REPOSITORY https://github.com/Dav1dde/glad.git + #VERSION 2.0.2 VERSION 0.1.36 GIT_PROGRESS TRUE OPTIONS "GLAD_EXPORT ON" "GLAD_INSTALL ON" ) + +#if(glad_ADDED) +# add_subdirectory("${glad_SOURCE_DIR}/cmake" glad_cmake) +# glad_add_library(glad REPRODUCIBLE API gl:core=3.3) +#endif() \ No newline at end of file diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt deleted file mode 100644 index 4754a98..0000000 --- a/source/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -add_subdirectory(hpr) -#add_subdirectory(creator) -#add_subdirectory(applications) \ No newline at end of file diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index 1d65362..bbe1c42 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -1,6 +1,6 @@ project( - hyporo + hyporo-creator VERSION 0.1.0 LANGUAGES CXX ) @@ -13,40 +13,49 @@ set(CMAKE_CXX_STANDARD 20) include(GNUInstallDirs) -add_executable(${PROJECT_NAME} - creator.cpp +#add_executable(${PROJECT_NAME} +# creator.cpp +#) - ../hpr/window_system/window_system.cpp - ../hpr/window_system/monitor.cpp - ../hpr/window_system/window.cpp - ../hpr/window_system/glfw/window_system.cpp - ../hpr/window_system/glfw/monitor.cpp - ../hpr/window_system/glfw/window.cpp -) +include(${CMAKE_SOURCE_DIR}/cmake/external/imgui.cmake) +#message(STATUS "project name: ${PROJECT_NAME}") +#target_link_libraries(${PROJECT_NAME} +# hpr::hpr +# imgui +#) -include(${CMAKE_SOURCE_DIR}/cmake/imgui.cmake) -message(STATUS "project name: ${PROJECT_NAME}") -target_link_libraries(${PROJECT_NAME} - hpr::hpr - imgui -) +#target_include_directories(${PROJECT_NAME} +# PRIVATE +# ../ +#) -target_include_directories(${PROJECT_NAME} - PRIVATE - ../ -) +#set(CMAKE_CXX_STANDARD 20) +#add_executable(testi +# test.cpp +#) +#target_include_directories(testi +# PRIVATE +# ../ +#) + +#target_link_libraries(testi +# hpr::hpr +# imgui +#) set(CMAKE_CXX_STANDARD 20) -add_executable(testi - test.cpp -) -target_include_directories(testi - PRIVATE - ../ -) +add_executable(hyporo-creator + test2.cpp + ) -target_link_libraries(testi - hpr::hpr - imgui -) +target_include_directories(hyporo-creator + PRIVATE + ../ + ) + +target_link_libraries(hyporo-creator + hpr::gpu + hpr::window-system + imgui + ) diff --git a/source/creator/test.cpp b/source/creator/test.cpp index 5e4befa..719463b 100644 --- a/source/creator/test.cpp +++ b/source/creator/test.cpp @@ -25,7 +25,24 @@ const char *fragmentShaderSource = "#version 330 core\n" "{\n" " FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n" "}\n\0"; - +const GLchar* vertexSource = R"glsl( + #version 150 core + in vec3 position; + in vec3 color; + in vec2 texcoord; + out vec3 Color; + out vec2 Texcoord; + uniform mat4 model; + uniform mat4 view; + uniform mat4 proj; + uniform vec3 overrideColor; + void main() + { + Color = overrideColor * color; + Texcoord = texcoord; + gl_Position = proj * view * model * vec4(position, 1.0); + } +)glsl"; int main() { using namespace hpr; diff --git a/source/creator/test2.cpp b/source/creator/test2.cpp new file mode 100644 index 0000000..f388132 --- /dev/null +++ b/source/creator/test2.cpp @@ -0,0 +1,133 @@ + +#include "hpr/gpu.hpp" +#include "hpr/window_system/window_system.hpp" +#include "hpr/window_system/glfw/window_system.hpp" +#include "hpr/window_system/glfw/window.hpp" +#include "hpr/math.hpp" +#include "hpr/mesh.hpp" + +#include +#include +#include +#include + +const char *vertexShaderSource = "#version 330 core\n" + "layout (location = 0) in vec3 aPos;\n" + "void main()\n" + "{\n" + " gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n" + "}\0"; +const char *fragmentShaderSource = "#version 330 core\n" + "out vec4 FragColor;\n" + "void main()\n" + "{\n" + " FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n" + "}\n\0"; + +int main() +{ + using namespace hpr; + + gpu::WindowSystem *ws = gpu::WindowSystem::create(gpu::WindowContext::Provider::GLFW); + gpu::Window *w = ws->newWindow(); + w->init("test", gpu::Window::Style::Windowed, 0, 0, 600, 400, nullptr, nullptr); + + if (!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress)) + throw std::runtime_error("Cannot initialize gl context"); + + gpu::Shader vshader {gpu::Shader::Type::Vertex, vertexShaderSource}; + gpu::Shader fshader {gpu::Shader::Type::Fragment, fragmentShaderSource}; + gpu::ShaderProgram sprogram {}; + + vshader.create(); + fshader.create(); + sprogram.create(); + sprogram.attach(vshader); + sprogram.attach(fshader); + sprogram.link(); + for (auto& sh : sprogram.shaders()) + std::cout << sh.index() << std::endl; + + + darray vertices { + 0.5f, 0.5f, 0.0f, // top right + 0.5f, -0.5f, 0.0f, // bottom right + -0.5f, -0.5f, 0.0f, // bottom left + -0.5f, 0.5f, 0.0f // top left + }; + darray indices2 { // note that we start from 0! + 0, 1, 3, // first Triangle + 1, 2, 3 // second Triangle + }; + + gpu::ArrayObject vao {}; + gpu::BufferObject vbo {gpu::BufferObject::Type::Vertex}; + gpu::BufferObject ebo {gpu::BufferObject::Type::Index}; + + vao.create(); + vao.bind(); + vbo.create(vertices); + ebo.create(indices2); + vao.attribPointer(vbo, 0, 3); + vao.unbind(); + + gpu::Viewport viewport {{0, 0}, {600, 400}}; + gpu::ColorBuffer colorBuffer; + gpu::DepthBuffer depthBuffer {true}; + + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + + ImGuiIO& io = ImGui::GetIO(); + io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; + io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; + + ImGui::StyleColorsDark(); + + ImGui_ImplGlfw_InitForOpenGL(dynamic_cast(w)->instance(), true); + ImGui_ImplOpenGL3_Init("#version 420"); + + while (w->isOpen()) + { + viewport.set(); + + colorBuffer.clear({0.8f, 0.2f, 0.2f, 1.0f}); + depthBuffer.clear(); + + sprogram.bind(); + vao.bind(); + + glDrawArrays(GL_TRIANGLES, 0, 6); + + ImGui_ImplOpenGL3_NewFrame(); + ImGui_ImplGlfw_NewFrame(); + ImGui::NewFrame(); + + bool yes = true; + ImGui::ShowDemoWindow(&yes); + + ImGui::Begin("Hello, world!"); + { + if (ImGui::Button("Exit")) + w->state(gpu::Window::State::Closed); + ImGui::End(); + } + + ImGui::Render(); + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); + dynamic_cast(w)->swapBuffers(); + dynamic_cast(w)->pollEvents(); + } + + sprogram.destroy(); + vshader.destroy(); + fshader.destroy(); + vbo.destroy(); + ebo.destroy(); + vao.destroy(); + + ws->destroyWindow(w); + gpu::WindowSystem::destroy(ws); + + return 0; +} \ No newline at end of file diff --git a/source/hpr/CMakeLists.txt b/source/hpr/CMakeLists.txt index 878571b..c4c542b 100644 --- a/source/hpr/CMakeLists.txt +++ b/source/hpr/CMakeLists.txt @@ -5,6 +5,8 @@ add_subdirectory(containers) add_subdirectory(math) add_subdirectory(io) add_subdirectory(mesh) +add_subdirectory(geometry) + if(WITH_CSG) include(${CMAKE_SOURCE_DIR}/cmake/external/occt.cmake) add_subdirectory(csg) diff --git a/source/hpr/containers/array/static_array.hpp b/source/hpr/containers/array/static_array.hpp index f7fe2ff..76783d6 100644 --- a/source/hpr/containers/array/static_array.hpp +++ b/source/hpr/containers/array/static_array.hpp @@ -4,6 +4,7 @@ #include #include +#include namespace hpr @@ -170,7 +171,7 @@ public: return const_iterator(p_end); } - [[nodiscard]] virtual + [[nodiscard]] virtual constexpr size_type size() const { return size_type(p_end - p_start); diff --git a/source/hpr/csg/shape.hpp b/source/hpr/csg/shape.hpp index 6492b12..e8dadb0 100644 --- a/source/hpr/csg/shape.hpp +++ b/source/hpr/csg/shape.hpp @@ -364,7 +364,7 @@ public: Shape rotate(const vec3& pos, const vec3& axis, double angle) { gp_Trsf transform; - transform.SetRotation(gp_Ax1({pos[0], pos[1], pos[2]}, {axis[0], axis[1], axis[2]}), radians(angle)); + transform.SetRotation(gp_Ax1({pos[0], pos[1], pos[2]}, {axis[0], axis[1], axis[2]}), rad(angle)); BRepBuilderAPI_Transform builder {p_shape, transform, true}; return builder.Shape(); diff --git a/source/hpr/geometry.hpp b/source/hpr/geometry.hpp new file mode 100644 index 0000000..d3e9d51 --- /dev/null +++ b/source/hpr/geometry.hpp @@ -0,0 +1,5 @@ +#pragma once + +#include "geometry/polytope.hpp" +#include "geometry/triangle.hpp" +#include "geometry/tetrahedron.hpp" diff --git a/source/hpr/geometry/CMakeLists.txt b/source/hpr/geometry/CMakeLists.txt new file mode 100644 index 0000000..475011b --- /dev/null +++ b/source/hpr/geometry/CMakeLists.txt @@ -0,0 +1,57 @@ +cmake_minimum_required(VERSION 3.16) + +project(geometry + VERSION "${HPR_PROJECT_VERSION}" + LANGUAGES CXX +) + +add_library(${PROJECT_NAME} INTERFACE) +add_library(${CMAKE_PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) +add_module(${PROJECT_NAME}) + +file(GLOB ${CMAKE_PROJECT_NAME}_${PROJECT_NAME}_HEADERS + "../geometry.hpp" "*.hpp" +) + +foreach(_header_path ${${CMAKE_PROJECT_NAME}_${PROJECT_NAME}_HEADERS}) + list(APPEND ${CMAKE_PROJECT_NAME}_${PROJECT_NAME}_HEADERS_INTERFACE "$") +endforeach() + +target_sources(${PROJECT_NAME} + INTERFACE + ${${CMAKE_PROJECT_NAME}_${PROJECT_NAME}_HEADERS_INTERFACE} + $ +) + +install( + TARGETS ${PROJECT_NAME} + EXPORT ${PROJECT_NAME}Targets + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/${PROJECT_NAME} + NAMELINK_SKIP + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} +) +install( + EXPORT ${PROJECT_NAME}Targets + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${CMAKE_PROJECT_NAME}-${HPR_PROJECT_VERSION} + NAMESPACE ${CMAKE_PROJECT_NAME}:: +) +install( + TARGETS ${PROJECT_NAME} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/${PROJECT_NAME} + NAMELINK_ONLY + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} +) +install( + DIRECTORY ${PROJECT_SOURCE_DIR} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${CMAKE_PROJECT_NAME} + COMPONENT devel + FILES_MATCHING + PATTERN "*.h" + PATTERN "*.hpp" + PATTERN "tests" EXCLUDE +) +install( + FILES ../${PROJECT_NAME}.hpp + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${CMAKE_PROJECT_NAME} + COMPONENT devel +) diff --git a/source/hpr/geometry/polytope.hpp b/source/hpr/geometry/polytope.hpp new file mode 100644 index 0000000..e614614 --- /dev/null +++ b/source/hpr/geometry/polytope.hpp @@ -0,0 +1,48 @@ +#pragma once + +#include "../containers.hpp" +#include "../math.hpp" + + +namespace hpr::geometry +{ + +template +class Polytope +{ + +public: + + enum class Type + { + Nullitope = -1, + Monon, + Dion, + Polygon, + Polyhedron, + Polychoron, + Unknown + }; + +protected: + + const int p_dimension; + const int p_space; + Type p_type; + darray> p_points; + +public: + + Polytope() : + p_dimension {Dim}, + p_space {Space}, + p_type {Type::Unknown}, + p_points {} + {} + + virtual + ~Polytope() = default; + +}; + +} \ No newline at end of file diff --git a/source/hpr/gpu.hpp b/source/hpr/gpu.hpp index 877f184..08ec17a 100644 --- a/source/hpr/gpu.hpp +++ b/source/hpr/gpu.hpp @@ -1,15 +1,15 @@ #pragma once -#include "gpu/context.hpp" + +#include "gpu/array_object.hpp" +#include "gpu/buffer_object.hpp" +#include "gpu/color_buffer.hpp" +#include "gpu/cull_face.hpp" +#include "gpu/depth_buffer.hpp" +#include "gpu/framebuffer.hpp" +#include "gpu/renderbuffer.hpp" #include "gpu/shader.hpp" #include "gpu/shader_program.hpp" -#include "gpu/buffer.hpp" -#include "gpu/device.hpp" +#include "gpu/stencil_buffer.hpp" #include "gpu/texture.hpp" - -#include "gpu/opengl/context.hpp" -#include "gpu/opengl/shader.hpp" -#include "gpu/opengl/shader_program.hpp" -#include "gpu/opengl/buffer.hpp" -#include "gpu/opengl/device.hpp" -#include "gpu/opengl/texture.hpp" +#include "gpu/viewport.hpp" diff --git a/source/hpr/gpu/CMakeLists.txt b/source/hpr/gpu/CMakeLists.txt index 8c8e520..0a76d9e 100644 --- a/source/hpr/gpu/CMakeLists.txt +++ b/source/hpr/gpu/CMakeLists.txt @@ -10,7 +10,7 @@ add_library(${CMAKE_PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) add_module(${PROJECT_NAME}) file(GLOB ${CMAKE_PROJECT_NAME}_${PROJECT_NAME}_HEADERS - "../gpu.hpp" "*.hpp" "opengl/*.hpp" + "../gpu.hpp" "*.hpp" ) foreach(_header_path ${${CMAKE_PROJECT_NAME}_${PROJECT_NAME}_HEADERS}) @@ -18,7 +18,7 @@ foreach(_header_path ${${CMAKE_PROJECT_NAME}_${PROJECT_NAME}_HEADERS}) endforeach() file(GLOB ${CMAKE_PROJECT_NAME}_${PROJECT_NAME}_SOURCES - "*.cpp" "opengl/*.cpp" + "*.cpp" ) target_sources(${PROJECT_NAME} diff --git a/source/hpr/gpu/array_object.cpp b/source/hpr/gpu/array_object.cpp new file mode 100644 index 0000000..462e940 --- /dev/null +++ b/source/hpr/gpu/array_object.cpp @@ -0,0 +1,2 @@ +#include +#include "array_object.hpp" diff --git a/source/hpr/gpu/array_object.hpp b/source/hpr/gpu/array_object.hpp new file mode 100644 index 0000000..ec98aff --- /dev/null +++ b/source/hpr/gpu/array_object.hpp @@ -0,0 +1,104 @@ +#pragma once + +#include "buffer_object.hpp" + +#include + +#ifndef __gl_h_ +#include +#endif + +namespace hpr::gpu +{ + + class ArrayObject + { + + + protected: + + unsigned int p_index; + int p_size; + int p_stride; + bool p_binded; + + public: + + inline + ArrayObject() : + p_index {0}, + p_size {0}, + p_stride {0}, + p_binded {false} + {} + + virtual + ~ArrayObject() = default; + + [[nodiscard]] + int size() const + { + return p_size; + } + + [[nodiscard]] + unsigned int index() const + { + return p_index; + } + + void create() + { + glGenVertexArrays(1, &p_index); + } + + void bind() + { + glBindVertexArray(p_index); + p_binded = true; + } + + void unbind() + { + glBindVertexArray(0); + p_binded = false; + } + + bool binded() const + { + return p_binded; + } + + void destroy() + { + glDeleteVertexArrays(1, &p_index); + } + + void attribPointer(BufferObject& buffer, unsigned int location, unsigned int size) + { + if (buffer.type() == BufferObject::Type::Unknown) + throw std::runtime_error("Unknown buffer type"); + if (!binded()) + throw std::runtime_error("ArrayObject is not binded"); + if (!buffer.valid()) + throw std::runtime_error("BufferObject is invalid"); + + buffer.bind(); + glVertexAttribPointer(location, size, GL_FLOAT, GL_FALSE, sizeof(float) * buffer.offset(), static_cast(nullptr)); + glEnableVertexAttribArray(location); + buffer.unbind(); + } + + void draw() + { + + } + + inline + bool valid() const + { + return p_index > 0; + } + }; + +} diff --git a/source/hpr/gpu/buffer.cpp b/source/hpr/gpu/buffer.cpp deleted file mode 100644 index 7d2183c..0000000 --- a/source/hpr/gpu/buffer.cpp +++ /dev/null @@ -1,36 +0,0 @@ - -#include "buffer.hpp" - - -namespace hpr::gpu -{ - -Buffer::Buffer() : - Context {DeviceAPI::Unknown}, - p_type {BufferType::Undefined}, - p_size {0}, - p_stride {0} -{} - -Buffer::Buffer(DeviceAPI api) : - Context {api}, - p_type {BufferType::Undefined}, - p_size {0}, - p_stride {0} -{} - -Buffer::~Buffer() = default; - -// Member functions - -int Buffer::size() const -{ - return p_size; -} - -Buffer::BufferType Buffer::type() const -{ - return p_type; -} - -} \ No newline at end of file diff --git a/source/hpr/gpu/buffer.hpp b/source/hpr/gpu/buffer.hpp deleted file mode 100644 index 765ba4e..0000000 --- a/source/hpr/gpu/buffer.hpp +++ /dev/null @@ -1,52 +0,0 @@ -#pragma once - -#include "context.hpp" - -#include - - -namespace hpr::gpu -{ - -class Buffer : public Context -{ - friend class Device; - -public: - - enum class BufferType - { - Undefined, - Vertex, - Index, - Uniform, - BufferTypeCount - }; - -protected: - - BufferType p_type; - int p_size; - int p_stride; - -public: - - // Constructors - - Buffer(); - - explicit - Buffer(DeviceAPI api); - - ~Buffer() override; - - // Member functions - - [[nodiscard]] - int size() const; - - [[nodiscard]] - BufferType type() const; -}; - -} // end namespace hpr::gpu \ No newline at end of file diff --git a/source/hpr/gpu/buffer_object.cpp b/source/hpr/gpu/buffer_object.cpp new file mode 100644 index 0000000..1d4a436 --- /dev/null +++ b/source/hpr/gpu/buffer_object.cpp @@ -0,0 +1,27 @@ + +#include +#include "buffer_object.hpp" + +namespace hpr::gpu +{ + + void BufferObject::bind() + { + glBindBuffer((GLenum)p_type, p_index); + p_binded = true; + } + + void BufferObject::unbind() + { + glBindBuffer((GLenum)p_type, 0); + p_binded = false; + } + + void BufferObject::destroy() + { + if (p_type == Type::Unknown) + std::runtime_error("Unknown buffer type"); + + glDeleteBuffers(1, &p_index); + } +} diff --git a/source/hpr/gpu/buffer_object.hpp b/source/hpr/gpu/buffer_object.hpp new file mode 100644 index 0000000..02001df --- /dev/null +++ b/source/hpr/gpu/buffer_object.hpp @@ -0,0 +1,134 @@ +#pragma once + +#include "../containers.hpp" + +#include +#ifndef __gl_h_ +#include +#endif + + +namespace hpr::gpu +{ + +class BufferObject +{ + +public: + + enum class Type + { + Vertex = 0x8892, //GL_ARRAY_BUFFER, + Index = 0x8893, //GL_ELEMENT_ARRAY_BUFFER, + Uniform = 0x8A11, //GL_UNIFORM_BUFFER, + Unknown = -1 + }; + +protected: + + Type p_type; + unsigned int p_index; + int p_size; + int p_offset; + bool p_binded; + +public: + + inline + BufferObject() : + p_type {Type::Unknown}, + p_index {0}, + p_size {0}, + p_offset {0}, + p_binded {false} + {} + + explicit inline + BufferObject(Type type) : + p_type {type}, + p_index {0}, + p_size {0}, + p_offset {0}, + p_binded {false} + {} + + virtual + ~BufferObject() = default; + + [[nodiscard]] + int size() const + { + return p_size; + } + + [[nodiscard]] + Type type() const + { + return p_type; + } + + [[nodiscard]] + unsigned int index() const + { + return p_index; + } + + [[nodiscard]] + unsigned int offset() const + { + return p_offset; + } + + void bind() ; + + void unbind(); + + [[nodiscard]] + bool binded() const + { + return p_binded; + } + + template + void create(const darray& data, unsigned int offset = 0) + { + if (p_type == Type::Unknown) + std::runtime_error("Unknown buffer type"); + + unsigned int drawType; + + if (p_type == Type::Uniform) + drawType = GL_DYNAMIC_DRAW; + else + drawType = GL_STATIC_DRAW; + + glGenBuffers(1, &p_index); + bind(); + glBufferData((GLenum)p_type, sizeof(T) * data.size(), data.data(), drawType); + unbind(); + + p_offset = offset; + } + + template + void edit(const darray& data, unsigned int offset = 0) + { + if (p_type == Type::Unknown) + std::runtime_error("Unknown buffer type"); + + bind(); + glBufferSubData(p_type, offset, sizeof(T) * data.size(), data.data()); + unbind(); + } + + void destroy(); + + [[nodiscard]] + inline + bool valid() const + { + return p_index > 0; + } +}; + +} \ No newline at end of file diff --git a/source/hpr/gpu/camera.hpp b/source/hpr/gpu/camera.hpp new file mode 100644 index 0000000..e11d835 --- /dev/null +++ b/source/hpr/gpu/camera.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include "../math.hpp" + + +namespace hpr::gpu +{ + +class Camera +{ + +protected: + + vec3 p_front; + vec3 p_up; + vec3 p_left; + + scalar p_yaw; + scalar p_pitch; + scalar p_roll; + + vec3 p_position; + vec3 p_target; + + scalar p_distance; + +public: + + Camera() : + p_front {0., 0., -1.}, + p_up {0., 0., 1.}, + p_left {1., 0., 0.} + {} + + virtual + ~Camera() = default; + +}; + +} \ No newline at end of file diff --git a/source/hpr/gpu/color_buffer.hpp b/source/hpr/gpu/color_buffer.hpp new file mode 100644 index 0000000..6201485 --- /dev/null +++ b/source/hpr/gpu/color_buffer.hpp @@ -0,0 +1,68 @@ +#pragma once + +#include "../math/vector.hpp" +#ifndef __gl_h_ +#include +#endif + + + +namespace hpr::gpu +{ + + class ColorBuffer + { + + protected: + + bool p_enabledRed; + bool p_enabledGreen; + bool p_enabledBlue; + bool p_enabledAlpha; + vec4 p_color; + + public: + + inline + ColorBuffer() : + p_enabledRed {true}, + p_enabledGreen {true}, + p_enabledBlue {true}, + p_enabledAlpha {true}, + p_color {} + {} + + inline + ColorBuffer(bool red, bool green, bool blue, bool alpha) : + p_enabledRed {red}, + p_enabledGreen {green}, + p_enabledBlue {blue}, + p_enabledAlpha {alpha}, + p_color {} + {} + + virtual + ~ColorBuffer() = default; + + void mask(bool red, bool green, bool blue, bool alpha) + { + glColorMask(red, green, blue, alpha); + } + + inline + void clear(const vec4& color) + { + p_color = color; + glClearColor(color[0], color[1], color[2], color[3]); + glClear(GL_COLOR_BUFFER_BIT); + } + + inline + void clear() + { + clear(p_color); + } + }; + +} + diff --git a/source/hpr/gpu/common.hpp b/source/hpr/gpu/common.hpp new file mode 100644 index 0000000..2b382c7 --- /dev/null +++ b/source/hpr/gpu/common.hpp @@ -0,0 +1,4 @@ +#pragma once + +#include + diff --git a/source/hpr/gpu/context.cpp b/source/hpr/gpu/context.cpp deleted file mode 100644 index d3b46e9..0000000 --- a/source/hpr/gpu/context.cpp +++ /dev/null @@ -1,23 +0,0 @@ - -#include "context.hpp" - - -namespace hpr::gpu -{ - -Context::Context() : - p_api {DeviceAPI::Unknown} -{} - -Context::Context(DeviceAPI api) : - p_api {api} -{} - -Context::~Context() = default; - -bool Context::checkCompability(const Context* ctx) const -{ - return (ctx != nullptr) ? ctx->p_api == p_api : true; -} - -} \ No newline at end of file diff --git a/source/hpr/gpu/context.hpp b/source/hpr/gpu/context.hpp deleted file mode 100644 index 440ad6d..0000000 --- a/source/hpr/gpu/context.hpp +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - - -namespace hpr::gpu -{ - -class Context -{ - -public: - - enum class DeviceAPI - { - Unknown, - OpenGL, - DeviceAPICount - }; - -private: - - DeviceAPI p_api; - -public: - - // Constructors - - Context(); - - explicit - Context(DeviceAPI api); - - virtual - ~Context(); - - // Member functions - - bool checkCompability(const Context* ctx) const; -}; - -} \ No newline at end of file diff --git a/source/hpr/gpu/cull_face.hpp b/source/hpr/gpu/cull_face.hpp new file mode 100644 index 0000000..e6e9faa --- /dev/null +++ b/source/hpr/gpu/cull_face.hpp @@ -0,0 +1,76 @@ +#pragma once + +#ifndef __gl_h_ +#include +#endif + + + +namespace hpr::gpu +{ + +class CullFace +{ + + enum class Mode + { + Front = GL_FRONT, + Back = GL_BACK, + FrontAndBack = GL_FRONT_AND_BACK, + None = GL_NONE + }; + +protected: + + bool p_binded; + Mode p_mode; + +public: + + inline + CullFace() : + p_binded {false}, + p_mode {Mode::FrontAndBack} + {} + + inline + CullFace(Mode mode) : + p_binded {false}, + p_mode {mode} + {} + + virtual + ~CullFace() = default; + + inline + void bind() + { + p_binded = true; + glEnable(GL_CULL_FACE); + } + + inline + void unbind() + { + p_binded = false; + glDisable(GL_CULL_FACE); + + } + + inline + bool binded() const + { + return p_binded; + } + + inline + void set(Mode mode) + { + p_mode = mode; + glCullFace(static_cast(mode)); + } + +}; + +} + diff --git a/source/hpr/gpu/depth_buffer.hpp b/source/hpr/gpu/depth_buffer.hpp new file mode 100644 index 0000000..21187ee --- /dev/null +++ b/source/hpr/gpu/depth_buffer.hpp @@ -0,0 +1,84 @@ +#pragma once + +#ifndef __gl_h_ +#include +#endif + + +namespace hpr::gpu +{ + +class DepthBuffer +{ + +protected: + + bool p_enabled; + bool p_binded; + +public: + + inline + DepthBuffer() : + p_enabled {true}, + p_binded {false} + {} + + inline + DepthBuffer(bool enabled) : + p_enabled {enabled}, + p_binded {false} + {} + + virtual + ~DepthBuffer() = default; + + inline + void bind() + { + p_binded = true; + glEnable(GL_DEPTH_TEST); + } + + inline + void unbind() + { + p_binded = false; + glDisable(GL_DEPTH_TEST); + } + + inline + bool binded() const + { + return p_binded; + } + + inline + void enable() + { + p_enabled = true; + glDepthMask(GL_TRUE); + } + + inline + void disable() + { + p_enabled = false; + glDepthMask(GL_FALSE); + } + + [[nodiscard]] + inline + bool enabled() const + { + return p_enabled; + } + + inline + void clear() const + { + glClear(GL_DEPTH_BUFFER_BIT); + } +}; + +} diff --git a/source/hpr/gpu/device.cpp b/source/hpr/gpu/device.cpp deleted file mode 100644 index 0a92943..0000000 --- a/source/hpr/gpu/device.cpp +++ /dev/null @@ -1,245 +0,0 @@ - -#include "device.hpp" -#include "opengl/device.hpp" - - -namespace hpr::gpu -{ - -Device::Device() : - Context {DeviceAPI::Unknown}, - p_currentVertexBuffer {}, - p_currentIndexBuffer {}, - p_currentUniformBuffer {}, - p_currentShaderProgram {} -{} - -Device::Device(DeviceAPI api) : - Context {api}, - p_currentVertexBuffer {}, - p_currentIndexBuffer {}, - p_currentUniformBuffer {}, - p_currentShaderProgram {} -{} - -Device::~Device() -{ - for (auto& shader : p_shaders) - delete shader; - for (auto& buffer : p_buffers) - delete buffer; - for (auto& shaderProgram : p_shaderPrograms) - delete shaderProgram; - for (auto& texture : p_textures) - delete texture; -} - -// Global functions - -void Device::create(Device** device, DeviceAPI api) -{ - if (device == nullptr) - throw std::invalid_argument("Invalid parameter 'nullptr'"); - if (api == DeviceAPI::Unknown) - throw std::invalid_argument("Cannot create device for 'Unknown'"); - - *device = nullptr; - - if (api == DeviceAPI::OpenGL) - *device = new opengl::Device; - else - throw std::invalid_argument("Unsupported device"); -} - -// Render targets - -void Device::moveRenderTarget(RenderTarget* target, int x, int y) -{ - if (target == nullptr) - throw std::invalid_argument("Invalid parameter"); - target->p_posX = x; - target->p_posY = y; -} - -void Device::scaleRenderTarget(RenderTarget* target, int width, int height) -{ - if (target == nullptr) - throw std::invalid_argument("Invalid parameter"); - - target->p_width = width; - target->p_height = height; -} - -void Device::destroyRenderTarget(RenderTarget*& target) -{ - if (!target) - throw std::runtime_error("Invalid parameter"); - - for (auto iter = p_renderTargets.begin(); iter != p_renderTargets.end(); ++iter) - if (*iter == target) - { - delete target; - target = nullptr; - p_renderTargets.remove(iter); - break; - } -} - -// Buffers - -void Device::useVertexBuffer(Buffer* buffer, int stride, int offset) -{ - if (buffer) - { - if (buffer->p_type == Buffer::BufferType::Vertex) - { - p_currentVertexBuffer = buffer; - p_currentVertexBuffer->p_stride = stride; - } - else - throw std::runtime_error("Incompatible buffer"); - } - else - p_currentVertexBuffer = nullptr; -} - -void Device::useIndexBuffer(Buffer* buffer, int offset) -{ - if (buffer) - { - if (buffer->p_type == Buffer::BufferType::Index) - { - p_currentIndexBuffer = buffer; - } - else - throw std::runtime_error("Incompatible buffer"); - } - else - p_currentIndexBuffer = nullptr; -} - -void Device::useUniformBuffer(Buffer* buffer, int slot) -{ - if (buffer) - { - if (buffer->p_type == Buffer::BufferType::Uniform) - p_currentUniformBuffer = buffer; - else - throw std::runtime_error("Incompatible buffer"); - } - else - p_currentUniformBuffer = nullptr; -} - -void Device::destroyBuffer(Buffer*& buffer) -{ - if (!buffer) - throw std::runtime_error("Invalid parameter"); - - for (auto iter = p_buffers.begin(); iter != p_buffers.end(); ++iter) - if (*iter == buffer) - { - delete buffer; - buffer = nullptr; - p_buffers.remove(iter); - break; - } -} - -Buffer* Device::activeBuffer(Buffer::BufferType type) -{ - switch (type) - { - case Buffer::BufferType::Vertex: - return p_currentVertexBuffer; - case Buffer::BufferType::Index: - return p_currentIndexBuffer; - case Buffer::BufferType::Uniform: - return p_currentUniformBuffer; - default: - return nullptr; - } -} - -// Shaders - -void Device::destroyShader(Shader* shader) -{ - if (shader == nullptr) - throw std::runtime_error("Invalid parameter"); - - for (auto iter = p_shaders.begin(); iter != p_shaders.end(); ++iter) - if (*iter == shader) - { - delete shader; - shader = nullptr; - p_shaders.remove(iter); - break; - } -} - -// Shader programs - -void Device::attachShader(ShaderProgram *program, Shader *shader) -{ - if (program == nullptr || shader == nullptr) - throw std::runtime_error("Invalid parameter"); - if (program->p_isLinked) - throw std::runtime_error("Shader program already linked"); - - program->p_slots[(int)shader->p_type] = shader; -} - -void Device::linkProgram(ShaderProgram *program) -{ - if (program == nullptr) - throw std::runtime_error("Invalid parameter"); - if (program->p_isLinked) - throw std::runtime_error("Shader program already linked"); - - program->p_isLinked = true; -} - -void Device::useShaderProgram(ShaderProgram *program) -{ - if (program != nullptr) - if (!program->p_isLinked) - throw std::runtime_error("Shader program is not linked"); - - p_currentShaderProgram = program; -} - -void Device::destroyShaderProgram(ShaderProgram *&program, bool withShaders) -{ - if (program == p_currentShaderProgram) - useShaderProgram(nullptr); - - if (withShaders) - for (size_t n = 0; n < (size_t)Shader::ShaderType::ShaderTypeCount; n++) - destroyShader(program->p_slots[n]); - - for (auto iter = p_shaderPrograms.begin(); iter != p_shaderPrograms.end(); ++iter) - if (*iter == program) - { - delete program; - program = nullptr; - p_shaderPrograms.remove(iter); - break; - } -} - -// Textures - -void Device::destroyTexture(Texture *&texture) -{ - for (auto iter = p_textures.begin(); iter != p_textures.end(); ++iter) - if (*iter == texture) - { - delete texture; - texture = nullptr; - p_textures.remove(iter); - break; - } -} - -} \ No newline at end of file diff --git a/source/hpr/gpu/device.hpp b/source/hpr/gpu/device.hpp deleted file mode 100644 index 6c0fb1a..0000000 --- a/source/hpr/gpu/device.hpp +++ /dev/null @@ -1,148 +0,0 @@ -#pragma once - -#include "context.hpp" -#include "buffer.hpp" -#include "shader.hpp" -#include "shader_program.hpp" -#include "texture.hpp" -#include "render_target.hpp" - -#include "../containers/array.hpp" - -#include "../window_system/window_system.hpp" - - -namespace hpr::gpu -{ - -class Device : public Context -{ - -public: - - enum class CullMode - { - Front, - Back, - FrontAndBack, - None - }; - -protected: - - darray p_buffers; - darray p_shaders; - darray p_shaderPrograms; - darray p_textures; - - Buffer* p_currentVertexBuffer; - Buffer* p_currentIndexBuffer; - Buffer* p_currentUniformBuffer; - ShaderProgram* p_currentShaderProgram; - - darray p_renderTargets; -protected: - - // Constructors - - Device(); - - explicit - Device(DeviceAPI api); - - ~Device() override; - -public: - - // Global functions - - static - void create(Device** device, DeviceAPI api); - - // Member functions - - // Setup - - virtual - bool initialize() = 0; - virtual - bool destroy() = 0; - - // State - - virtual - void faceCulling(bool enableFaceCulling, CullMode faceCullingMode) = 0; - - // Render targets - - virtual - void createScreenRenderTarget(RenderTarget** target, Window* window) = 0; - virtual - void createFramebufferRenderTarget(RenderTarget** target, int width, int height) = 0; - virtual - void createSubRenderTarget(RenderTarget** target, RenderTarget* parent, int x, int y, int width, int height) = 0; - virtual - void moveRenderTarget(RenderTarget* target, int x, int y); - virtual - void scaleRenderTarget(RenderTarget* target, int width, int height); - virtual - void destroyRenderTarget(RenderTarget*& target); - - // Buffers - - virtual - void createVertexBuffer(Buffer **buffer, int size, char* data) = 0; - virtual - void createIndexBuffer(Buffer **buffer, int size, char* data) = 0; - virtual - void createUniformBuffer(Buffer **buffer, int size, char* data) = 0; - virtual - void useVertexBuffer(Buffer* buffer, int stride, int offset); - virtual - void useIndexBuffer(Buffer* buffer, int offset); - virtual - void useUniformBuffer(Buffer* buffer, int slot); - virtual - void editBuffer(Buffer* buffer, char* data, int size, int offset) = 0; - virtual - void editBuffer(Buffer* buffer, char* data) = 0; - virtual - void destroyBuffer(Buffer*& buffer); - Buffer* activeBuffer(Buffer::BufferType type); - - - // Shaders - - virtual - void createVertexShader(Shader** shader, const std::string& filename, const std::string& label) = 0; - virtual - void createFragmentShader(Shader** shader, const std::string& filename, const std::string& label) = 0; - virtual - void createGeometryShader(Shader** shader, const std::string& filename, const std::string& label) = 0; - virtual - void destroyShader(Shader* shader); - - // Shader programs - - virtual - void createShaderProgram(ShaderProgram** program) = 0; - virtual - void attachShader(ShaderProgram* program, Shader* shader); - virtual - void linkProgram(ShaderProgram* program); - virtual - void useShaderProgram(ShaderProgram* program); - virtual - void destroyShaderProgram(ShaderProgram*& program, bool withShaders); - - // Textures - - virtual - void createTexture(Texture** texture, const std::string& filename) = 0; - virtual - void useTexture(Texture* texture, int slot) = 0; - virtual - void destroyTexture(Texture*& texture); -}; - -} diff --git a/source/hpr/gpu/framebuffer.hpp b/source/hpr/gpu/framebuffer.hpp new file mode 100644 index 0000000..7534e65 --- /dev/null +++ b/source/hpr/gpu/framebuffer.hpp @@ -0,0 +1,131 @@ +#pragma once + +#include "texture.hpp" +#include "renderbuffer.hpp" + +#ifndef __gl_h_ +#include +#endif + +namespace hpr::gpu +{ + +class Framebuffer +{ + +protected: + + Texture p_texture; + Renderbuffer p_renderbuffer; + unsigned int p_index; + bool p_binded; + +public: + + inline + Framebuffer() : + p_index {0}, + p_texture {}, + p_renderbuffer {} + {} + + virtual + ~Framebuffer() = default; + + [[nodiscard]] + unsigned int index() const + { + return p_index; + } + + void bind() + { + glBindFramebuffer(GL_FRAMEBUFFER, p_index); + p_binded = true; + } + + void unbind() + { + glBindFramebuffer(GL_FRAMEBUFFER, 0); + p_binded = false; + } + + bool binded() const + { + return p_binded; + } + + void attach(const Texture& texture) + { + if (!binded() && valid()) + std::runtime_error("Framebuffer not binded or invalid"); + if (!texture.valid()) + std::runtime_error("Texture is not valid"); + + p_texture = texture; + p_texture.bind(); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, p_texture.index(), 0); + + p_texture.unbind(); + } + + void attach(const Renderbuffer& renderbuffer) + { + if (!binded() && valid()) + std::runtime_error("Framebuffer not binded or invalid"); + if (!renderbuffer.valid()) + std::runtime_error("Renderbuffer is not valid"); + + p_renderbuffer = renderbuffer; + p_renderbuffer.bind(); + p_renderbuffer.storage(p_texture.width(), p_texture.height()); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, p_renderbuffer.index()); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + throw std::runtime_error("Framebuffer is not complete"); + + p_renderbuffer.unbind(); + } + + void create() + { + glGenFramebuffers(1, &p_index); + bind(); + + if (!p_texture.valid()) + p_texture.create(); + attach(p_texture); + + if (!p_renderbuffer.valid()) + p_renderbuffer.create(); + attach(p_renderbuffer); + + unbind(); + } + + void rescale(int width, int height) + { + p_texture.bind(); + p_texture.rescale(width, height); + + p_renderbuffer.bind(); + p_renderbuffer.storage(p_texture.width(), p_texture.height()); + + p_texture.unbind(); + p_renderbuffer.unbind(); + } + + void destroy() + { + p_texture.destroy(); + p_renderbuffer.destroy(); + glDeleteFramebuffers(1, &p_index); + } + + bool valid() const + { + return p_index != 0; + } +}; + +} \ No newline at end of file diff --git a/source/hpr/gpu/gpu.cpp b/source/hpr/gpu/gpu.cpp new file mode 100644 index 0000000..d2e1102 --- /dev/null +++ b/source/hpr/gpu/gpu.cpp @@ -0,0 +1,3 @@ +// +// Created by L-Nafaryus on 12/16/2022. +// diff --git a/source/hpr/gpu/opengl/buffer.cpp b/source/hpr/gpu/opengl/buffer.cpp deleted file mode 100644 index 72b0418..0000000 --- a/source/hpr/gpu/opengl/buffer.cpp +++ /dev/null @@ -1,31 +0,0 @@ - -#include "buffer.hpp" - -#include - - -namespace hpr::gpu::opengl -{ - -Buffer::Buffer() : - gpu::Buffer(DeviceAPI::OpenGL), - p_bufferIndex {0}, - p_vertexArrayIndex {0} -{} - -Buffer::~Buffer() = default; - -int Buffer::target() const -{ - switch (p_type) - { - case BufferType::Vertex: - return GL_ARRAY_BUFFER; - case BufferType::Index: - return GL_ELEMENT_ARRAY_BUFFER; - default: - return GL_NONE; - } -} - -} \ No newline at end of file diff --git a/source/hpr/gpu/opengl/buffer.hpp b/source/hpr/gpu/opengl/buffer.hpp deleted file mode 100644 index ca7969e..0000000 --- a/source/hpr/gpu/opengl/buffer.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include "../buffer.hpp" - - -namespace hpr::gpu::opengl -{ - -class Buffer : public gpu::Buffer -{ - friend class Device; - -protected: - unsigned int p_bufferIndex; - unsigned int p_vertexArrayIndex; - -public: - - // Constructors - - Buffer(); - - virtual ~Buffer(); - - // Member functions - - int target() const; -}; - -} diff --git a/source/hpr/gpu/opengl/context.cpp b/source/hpr/gpu/opengl/context.cpp deleted file mode 100644 index d24eea0..0000000 --- a/source/hpr/gpu/opengl/context.cpp +++ /dev/null @@ -1,5 +0,0 @@ -// -// Created by L-Nafaryus on 10/3/2022. -// - -#include "context.hpp" diff --git a/source/hpr/gpu/opengl/context.hpp b/source/hpr/gpu/opengl/context.hpp deleted file mode 100644 index 962de0b..0000000 --- a/source/hpr/gpu/opengl/context.hpp +++ /dev/null @@ -1,8 +0,0 @@ -// -// Created by L-Nafaryus on 10/3/2022. -// - -#ifndef HYPORO_CONTEXT_HPP -#define HYPORO_CONTEXT_HPP - -#endif //HYPORO_CONTEXT_HPP diff --git a/source/hpr/gpu/opengl/device.cpp b/source/hpr/gpu/opengl/device.cpp deleted file mode 100644 index d0b7121..0000000 --- a/source/hpr/gpu/opengl/device.cpp +++ /dev/null @@ -1,597 +0,0 @@ - -#include "device.hpp" -#include "buffer.hpp" -#include "shader.hpp" -#include "shader_program.hpp" -#include "texture.hpp" -#include "render_target.hpp" - -#include "../../io/file.hpp" - -#include -#define STB_IMAGE_IMPLEMENTATION -#include -#include - -#include - - -namespace hpr::gpu::opengl -{ - -Device::Device() : - gpu::Device {DeviceAPI::OpenGL}, - p_isInitialized {false} -{} - -Device::~Device() = default; - -// Setup - -bool Device::initialize() -{ - return p_isInitialized = true; -} - -bool Device::destroy() -{ - return p_isInitialized = false; -} - -bool Device::loadLoader() -{ - return !gladLoadGLLoader((GLADloadproc) glfwGetProcAddress); -} - -// State - -void Device::faceCulling(bool enableFaceCulling, CullMode faceCullingMode) -{ - if (enableFaceCulling) - glEnable(GL_CULL_FACE); - else - glDisable(GL_CULL_FACE); - - switch (faceCullingMode) - { - case CullMode::Front: - glCullFace(GL_FRONT); - break; - case CullMode::Back: - glCullFace(GL_BACK); - break; - case CullMode::FrontAndBack: - glCullFace(GL_FRONT_AND_BACK); - break; - case CullMode::None: - glCullFace(GL_NONE); - break; - } -} - -// Render targets - -void Device::createScreenRenderTarget(gpu::RenderTarget** target, Window* window) -{ - if (target == nullptr) - throw std::invalid_argument("Invalid parameter"); - *target = nullptr; - p_renderTargets.push(new opengl::RenderTarget()); - auto* newTarget = dynamic_cast(p_renderTargets.back()); - - newTarget->p_type = RenderTarget::Type::Screen; - newTarget->p_posX = 0; - newTarget->p_posY = 0; - newTarget->p_width = window->width(); - newTarget->p_height = window->height(); - - *target = newTarget; -} - -void Device::createFramebufferRenderTarget(gpu::RenderTarget** target, int width, int height) -{ - if (target == nullptr) - throw std::invalid_argument("Invalid parameter"); - unsigned int texture; - glGenTextures(GL_TEXTURE_2D, &texture); - glBindTexture(GL_TEXTURE_2D, texture); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); - - unsigned int framebuffer; - glGenFramebuffers(1, &framebuffer); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer); - - p_renderTargets.push(new opengl::RenderTarget()); - auto* newTarget = dynamic_cast(p_renderTargets.back()); - - newTarget->p_type = RenderTarget::Type::Framebuffer; - newTarget->p_posX = 0; - newTarget->p_posY = 0; - newTarget->p_width = width; - newTarget->p_height = height; - newTarget->p_frameBufferIndex = framebuffer; - newTarget->p_textureIndex = texture; - - *target = newTarget; -} - -void Device::createSubRenderTarget(gpu::RenderTarget** target, gpu::RenderTarget* parent, int x, int y, int width, int height) -{ - -} - -void Device::moveRenderTarget(gpu::RenderTarget* target, int x, int y) -{ - -} - -void Device::scaleRenderTarget(gpu::RenderTarget* target, int width, int height) -{ - -} - -void Device::destroyRenderTarget(gpu::RenderTarget*& target) -{ - -} - -// Buffers - - -void Device::createVertexBuffer(gpu::Buffer **buffer, int size, char *data) -{ - if (buffer == nullptr) - throw std::invalid_argument("Invalid parameter"); - - *buffer = nullptr; - p_buffers.push(new opengl::Buffer()); - auto* newBuffer = dynamic_cast(p_buffers.back()); - - newBuffer->p_type = Buffer::BufferType::Vertex; - newBuffer->p_size = size; - - glGenVertexArrays(1, &newBuffer->p_vertexArrayIndex); - glBindVertexArray(newBuffer->p_vertexArrayIndex); - - glGenBuffers(1, &newBuffer->p_bufferIndex); - glBindBuffer(GL_ARRAY_BUFFER, newBuffer->p_bufferIndex); - glBufferData(GL_ARRAY_BUFFER, size, (void*)data, GL_STATIC_DRAW); - - *buffer = static_cast(newBuffer); -} - -void Device::createIndexBuffer(gpu::Buffer **buffer, int size, char *data) -{ - if (buffer == nullptr) - throw std::invalid_argument("Invalid parameter"); - - *buffer = nullptr; - p_buffers.push(new opengl::Buffer()); - auto* newBuffer = dynamic_cast(p_buffers.back()); - - newBuffer->p_type = Buffer::BufferType::Index; - newBuffer->p_size = size; - - glGenVertexArrays(1, &newBuffer->p_vertexArrayIndex); - glBindVertexArray(newBuffer->p_vertexArrayIndex); - - glGenBuffers(1, &newBuffer->p_bufferIndex); - glBindBuffer(GL_UNIFORM_BUFFER, newBuffer->p_bufferIndex); - glBufferData(GL_UNIFORM_BUFFER, size, (void*)data, GL_STATIC_DRAW); - - *buffer = static_cast(newBuffer); -} - -void Device::createUniformBuffer(gpu::Buffer** buffer, int size, char* data) -{ - if (buffer == nullptr) - throw std::invalid_argument("Invalid parameter"); - - *buffer = nullptr; - p_buffers.push(new opengl::Buffer()); - auto* newBuffer = dynamic_cast(p_buffers.back()); - - newBuffer->p_type = Buffer::BufferType::Uniform; - newBuffer->p_size = size; - - glGenBuffers(1, &newBuffer->p_bufferIndex); - glBindBuffer(GL_UNIFORM_BUFFER, newBuffer->p_bufferIndex); - glBufferData(GL_UNIFORM_BUFFER, size, (void*)data, GL_DYNAMIC_DRAW); - - *buffer = static_cast(newBuffer); -} - -void Device::useVertexBuffer(gpu::Buffer *buffer, int stride, int offset) -{ - if (buffer == nullptr) - { - glBindVertexArray(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - } - else - { - auto* curBuffer = dynamic_cast(buffer); - - if (curBuffer->p_type == Buffer::BufferType::Vertex && p_currentVertexBuffer != buffer) - { - glBindVertexArray(curBuffer->p_vertexArrayIndex); - glBindBuffer(GL_ARRAY_BUFFER, curBuffer->p_bufferIndex); - - auto* curIndexBuffer = dynamic_cast(p_currentIndexBuffer); - - if (curIndexBuffer != nullptr) - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, curIndexBuffer->p_bufferIndex); - } - } - gpu::Device::useVertexBuffer(buffer, stride, offset); -} - -void Device::useIndexBuffer(gpu::Buffer *buffer, int offset) -{ - if (buffer == nullptr) - { - glBindVertexArray(0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - } - else - { - auto* curBuffer = dynamic_cast(buffer); - - if (curBuffer->p_type == Buffer::BufferType::Index && p_currentVertexBuffer != buffer) - { - glBindVertexArray(curBuffer->p_vertexArrayIndex); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, curBuffer->p_bufferIndex); - } - } - gpu::Device::useIndexBuffer(buffer, offset); -} - -void Device::useUniformBuffer(gpu::Buffer* buffer, int slot) -{ - if (buffer == nullptr) - { - glBindBuffer(GL_UNIFORM_BUFFER, 0); - } - else - { - auto* curBuffer = dynamic_cast(buffer); - glBindBufferRange(GL_UNIFORM_BUFFER, slot, curBuffer->p_bufferIndex, 0, buffer->size()); - } - gpu::Device::useUniformBuffer(buffer, slot); -} - -void Device::editBuffer(gpu::Buffer* buffer, char* data, int size, int offset) -{ - if (!checkCompability(buffer)) - throw std::runtime_error("Incompatible platform"); - if (buffer == nullptr || data == nullptr) - throw std::invalid_argument("Invalid argument"); - if (size + offset > buffer->size() || size < 0 || offset < 0) - throw std::out_of_range("Out of bounds"); - - auto* prevBuffer = dynamic_cast(activeBuffer(buffer->type())); - - auto* buffer_ = dynamic_cast(buffer); - glBindBuffer(buffer_->target(), buffer_->p_bufferIndex); - glBufferSubData(buffer_->target(), offset, size, data); - - if (prevBuffer != buffer_) - glBindBuffer(buffer_->target(), prevBuffer ? prevBuffer->p_bufferIndex : 0); - -} - -void Device::editBuffer(gpu::Buffer* buffer, char* data) -{ - editBuffer(buffer, data, buffer->size(), 0); -} - -void Device::destroyBuffer(gpu::Buffer *&buffer) -{ - if (buffer == nullptr) - throw std::invalid_argument("Invalid parameter"); - - auto* curBuffer = dynamic_cast(buffer); - glDeleteBuffers(1, &curBuffer->p_bufferIndex); - - if (curBuffer->p_type == Buffer::BufferType::Vertex) - glDeleteVertexArrays(1, &curBuffer->p_vertexArrayIndex); - - gpu::Device::destroyBuffer(buffer); -} - -// Shaders - -void Device::createVertexShader(gpu::Shader **shader, const std::string &filename, const std::string &label) -{ - if (shader == nullptr) - throw std::invalid_argument("Invalid parameter"); - - *shader = nullptr; - - unsigned int shaderIndex = glCreateShader(GL_VERTEX_SHADER); - if (shaderIndex == 0) - throw std::runtime_error("Could not create shader"); - - File file; - file.open(filename, File::Binary | File::Read); - std::string content = file.read().str(); - const char* shaderSource = content.c_str(); - - glShaderSource(shaderIndex, 1, &shaderSource, nullptr); - GLenum result = glGetError(); - glCompileShader(shaderIndex); - - int shaderStatus; - glGetShaderiv(shaderIndex, GL_COMPILE_STATUS, &shaderStatus); - if (!shaderStatus) - { - char error[2048 + 1]; - glGetShaderInfoLog(shaderIndex, 2048, nullptr, error); - - throw std::runtime_error(error); - } - - p_shaders.push(new opengl::Shader()); - auto* newShader = dynamic_cast(p_shaders.back()); - newShader->p_type = Shader::ShaderType::Vertex; - newShader->p_filename = filename; - newShader->p_shaderIndex = shaderIndex; - newShader->p_label = "VertexShader"; - - *shader = static_cast(newShader); -} - - -void Device::createFragmentShader(gpu::Shader **shader, const std::string &filename, const std::string &label) -{ - if (shader == nullptr) - throw std::invalid_argument("Invalid parameter"); - - *shader = nullptr; - - unsigned int shaderIndex = glCreateShader(GL_FRAGMENT_SHADER); - if (shaderIndex == 0) - throw std::runtime_error("Could not create shader"); - - File file; - file.open(filename, File::Binary | File::Read); - std::string content = file.read().str(); - const char* shaderSource = content.c_str(); - - glShaderSource(shaderIndex, 1, &shaderSource, nullptr); - GLenum result = glGetError(); - glCompileShader(shaderIndex); - - int shaderStatus; - glGetShaderiv(shaderIndex, GL_COMPILE_STATUS, &shaderStatus); - if (!shaderStatus) - { - char error[2048 + 1]; - glGetShaderInfoLog(shaderIndex, 2048, nullptr, error); - - throw std::runtime_error(error); - } - - p_shaders.push(new opengl::Shader()); - auto* newShader = dynamic_cast(p_shaders.back()); - newShader->p_type = Shader::ShaderType::Fragment; - newShader->p_filename = filename; - newShader->p_shaderIndex = shaderIndex; - newShader->p_label = "FragmentShader"; - - *shader = static_cast(newShader); -} - - -void Device::createGeometryShader(gpu::Shader **shader, const std::string &filename, const std::string &label) -{ - if (shader == nullptr) - throw std::invalid_argument("Invalid parameter"); - - *shader = nullptr; - - unsigned int shaderIndex = glCreateShader(GL_GEOMETRY_SHADER); - if (shaderIndex == 0) - throw std::runtime_error("Could not create shader"); - - File file; - file.open(filename, File::Binary | File::Read); - std::string content = file.read().str(); - const char* shaderSource = content.c_str(); - - glShaderSource(shaderIndex, 1, &shaderSource, nullptr); - GLenum result = glGetError(); - glCompileShader(shaderIndex); - - int shaderStatus; - glGetShaderiv(shaderIndex, GL_COMPILE_STATUS, &shaderStatus); - if (!shaderStatus) - { - char error[2048 + 1]; - glGetShaderInfoLog(shaderIndex, 2048, nullptr, error); - - throw std::runtime_error(error); - } - - p_shaders.push(new opengl::Shader()); - auto* newShader = dynamic_cast(p_shaders.back()); - newShader->p_type = Shader::ShaderType::Geometry; - newShader->p_filename = filename; - newShader->p_shaderIndex = shaderIndex; - newShader->p_label = "FragmentShader"; - - *shader = static_cast(newShader); -} - -void Device::destroyShader(gpu::Shader* shader) -{ - if (shader == nullptr) - throw std::invalid_argument("Invalid parameter"); - - auto* shader_ = dynamic_cast(shader); - glDeleteShader(shader_->p_shaderIndex); - - gpu::Device::destroyShader(shader); -} - -void Device::createShaderProgram(gpu::ShaderProgram** program) -{ - if (program == nullptr) - throw std::invalid_argument("Invalid parameter"); - - *program = nullptr; - - p_shaderPrograms.push(new opengl::ShaderProgram()); - auto* newProgram = dynamic_cast(p_shaderPrograms.back()); - newProgram->p_shaderProgramIndex = glCreateProgram(); - - *program = static_cast(newProgram); -} - -void Device::attachShader(gpu::ShaderProgram* program, gpu::Shader* shader) -{ - gpu::Device::attachShader(program, shader); - auto* program_ = dynamic_cast(program); - auto* shader_ = dynamic_cast(shader); - glAttachShader(program_->p_shaderProgramIndex, shader_->p_shaderIndex); -} - - -void Device::linkProgram(gpu::ShaderProgram* program) -{ - gpu::Device::linkProgram(program); - auto* program_ = dynamic_cast(program); - glLinkProgram(program_->p_shaderProgramIndex); - - GLint status; - glGetProgramiv(program_->p_shaderProgramIndex, GL_LINK_STATUS, &status); - - if (status == GL_FALSE) - throw std::runtime_error("Shader program link error"); -} - -void Device::useShaderProgram(gpu::ShaderProgram* program) -{ - gpu::ShaderProgram* currentProgram = p_currentShaderProgram; - gpu::Device::useShaderProgram(program); - - if (currentProgram == program) - return; - if (program == nullptr) - glUseProgram(0); - else - { - auto* program_ = dynamic_cast(program); - glUseProgram(program_->p_shaderProgramIndex); - } -} - -void Device::destroyShaderProgram(gpu::ShaderProgram*& program, bool withShaders) -{ - if (program == nullptr) - throw std::invalid_argument("Invalid parameter"); - - auto* program_ = dynamic_cast(program); - - for (int n = 0; n < static_cast(Shader::ShaderType::ShaderTypeCount); ++n) - { - auto* shader = dynamic_cast(program_->p_slots[n]); - if (shader != nullptr) - glDetachShader(program_->p_shaderProgramIndex, shader->p_shaderIndex); - } - glDeleteProgram(program_->p_shaderProgramIndex); - gpu::Device::destroyShaderProgram(program, withShaders); -} - -void Device::createTexture(gpu::Texture** texture, const std::string& filename) -{ - if (texture == nullptr) - throw std::invalid_argument("Invalid parameter"); - if (filename.empty()) - throw std::invalid_argument("Invalid parameter"); - - *texture = nullptr; - bool alphaChannel = true; - int internalFormat = GL_RGBA; - int imageFormat = GL_RGBA; - int width; - int height; - int channelsCount; - - stbi_set_flip_vertically_on_load(true); - unsigned char* source = stbi_load(filename.c_str(), &width, &height, &channelsCount, 0); - - if (!source) - throw std::runtime_error("Failed to load texture source"); - else - { - p_textures.push(new opengl::Texture()); - auto* texture_ = dynamic_cast(p_textures.back()); - texture_->p_filename = filename; - texture_->p_width = width; - texture_->p_height = height; - - glGenTextures(1, &texture_->p_textureIndex); - glBindTexture(GL_TEXTURE_2D, texture_->p_textureIndex); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - if (alphaChannel) - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - else - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - - glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, imageFormat, GL_UNSIGNED_BYTE, source); - glGenerateMipmap(GL_TEXTURE_2D); - - glBindTexture(GL_TEXTURE_2D, 0); - - *texture = static_cast(texture_); - } - - stbi_image_free(source); -} - -void Device::useTexture(gpu::Texture* texture, int slot) -{ - //gpu::Device::useTexture(texture, slot); - - if (texture == nullptr) - { - glActiveTexture(GL_TEXTURE0 + slot); - glBindTexture(GL_TEXTURE_2D, 0); - } - else - { - auto* texture_ = dynamic_cast(texture); - glActiveTexture(GL_TEXTURE0 + slot); - glBindTexture(GL_TEXTURE_2D, texture_->p_textureIndex); - } -} - -void Device::destroyTexture(gpu::Texture*& texture) -{ - if (texture == nullptr) - throw std::invalid_argument("Invalid parameter"); - - auto* texture_ = dynamic_cast(texture); - - glDeleteTextures(1, &texture_->p_textureIndex); - gpu::Device::destroyTexture(texture); -} - - -void Device::Draw(int numFaces, int indexOffset, int vertexOffset) -{ - if (p_currentVertexBuffer != nullptr) - glDrawElementsBaseVertex(GL_TRIANGLES, numFaces * 3, GL_UNSIGNED_SHORT, (void*)(indexOffset * 2), vertexOffset); -} - -} \ No newline at end of file diff --git a/source/hpr/gpu/opengl/device.hpp b/source/hpr/gpu/opengl/device.hpp deleted file mode 100644 index f99617a..0000000 --- a/source/hpr/gpu/opengl/device.hpp +++ /dev/null @@ -1,106 +0,0 @@ -#pragma once - -#include "../device.hpp" - -#include - - -namespace hpr::gpu::opengl -{ - -class Device : public gpu::Device -{ - -protected: - - bool p_isInitialized; - -public: - - // Constructors - - Device(); - - ~Device() override; - - - // Member functions - - // Setup - - bool initialize() override; - bool destroy() override; - - static - bool loadLoader(); - - // State - - void faceCulling(bool enableFaceCulling, CullMode faceCullingMode) override; - - // Render targets - - void createScreenRenderTarget(RenderTarget** target, Window* window) override; - void createFramebufferRenderTarget(RenderTarget** target, int width, int height) override; - void createSubRenderTarget(RenderTarget** target, RenderTarget* parent, int x, int y, int width, int height) override; - void moveRenderTarget(RenderTarget* target, int x, int y) override; - void scaleRenderTarget(RenderTarget* target, int width, int height) override; - void destroyRenderTarget(RenderTarget*& target) override; - - // Buffers - - virtual - void createVertexBuffer(Buffer **buffer, int size, char* data); - virtual - void createIndexBuffer(Buffer **buffer, int size, char* data); - virtual - void createUniformBuffer(Buffer **buffer, int size, char* data); - virtual - void useVertexBuffer(Buffer* buffer, int stride, int offset); - virtual - void useIndexBuffer(Buffer* buffer, int offset); - virtual - void useUniformBuffer(Buffer* buffer, int slot); - virtual - void editBuffer(Buffer* buffer, char* data, int size, int offset); - virtual - void editBuffer(Buffer* buffer, char* data); - virtual - void destroyBuffer(Buffer*& buffer); - - // Shaders - - virtual - void createVertexShader(Shader** shader, const std::string& filename, const std::string& label); - virtual - void createFragmentShader(Shader** shader, const std::string& filename, const std::string& label); - virtual - void createGeometryShader(Shader** shader, const std::string& filename, const std::string& label); - virtual - void destroyShader(Shader* shader); - - // Shader programs - - virtual - void createShaderProgram(ShaderProgram** program); - virtual - void attachShader(ShaderProgram* program, Shader* shader); - virtual - void linkProgram(ShaderProgram* program); - virtual - void useShaderProgram(ShaderProgram* program); - virtual - void destroyShaderProgram(ShaderProgram*& program, bool withShaders); - - // Textures - - void createTexture(Texture** texture, const std::string& filename) override; - void useTexture(Texture* texture, int slot) override; - void destroyTexture(Texture*& texture) override; - - // - - void Draw(int numFaces, int indexOffset, int vertexOffset); -}; - -} \ No newline at end of file diff --git a/source/hpr/gpu/opengl/render_target.cpp b/source/hpr/gpu/opengl/render_target.cpp deleted file mode 100644 index a6f26ee..0000000 --- a/source/hpr/gpu/opengl/render_target.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include "render_target.hpp" - - -namespace hpr::gpu::opengl -{ - -RenderTarget::RenderTarget() : - gpu::RenderTarget {DeviceAPI::OpenGL} -{} - -RenderTarget::~RenderTarget() = default; - -} \ No newline at end of file diff --git a/source/hpr/gpu/opengl/render_target.hpp b/source/hpr/gpu/opengl/render_target.hpp deleted file mode 100644 index f4a6164..0000000 --- a/source/hpr/gpu/opengl/render_target.hpp +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once - -#include "../render_target.hpp" - - -namespace hpr::gpu::opengl -{ - -class RenderTarget : public gpu::RenderTarget -{ - friend class Device; - -protected: - - unsigned int p_frameBufferIndex; - unsigned int p_depthBufferIndex; - unsigned int p_textureIndex; - -public: - - RenderTarget(); - - ~RenderTarget() override; - - unsigned int frameBuffer() const - { - return p_frameBufferIndex; - } - - unsigned int depthBuffer() const - { - return p_depthBufferIndex; - } - - unsigned int texture() const - { - return p_textureIndex; - } - -}; - -} \ No newline at end of file diff --git a/source/hpr/gpu/opengl/shader.cpp b/source/hpr/gpu/opengl/shader.cpp deleted file mode 100644 index 482c605..0000000 --- a/source/hpr/gpu/opengl/shader.cpp +++ /dev/null @@ -1,18 +0,0 @@ -// -// Created by L-Nafaryus on 10/3/2022. -// - -#include "shader.hpp" - - -namespace hpr::gpu::opengl -{ - -Shader::Shader() : - gpu::Shader(DeviceAPI::OpenGL), - p_shaderIndex {0} -{} - -Shader::~Shader() = default; - -} \ No newline at end of file diff --git a/source/hpr/gpu/opengl/shader.hpp b/source/hpr/gpu/opengl/shader.hpp deleted file mode 100644 index 5e359dd..0000000 --- a/source/hpr/gpu/opengl/shader.hpp +++ /dev/null @@ -1,26 +0,0 @@ - -#include "../shader.hpp" - - -namespace hpr::gpu::opengl -{ - -class Shader : public gpu::Shader -{ - friend class Device; - -protected: - - unsigned int p_shaderIndex; - -public: - - // Constructors - - Shader(); - - ~Shader() override; - -}; - -} diff --git a/source/hpr/gpu/opengl/shader_program.cpp b/source/hpr/gpu/opengl/shader_program.cpp deleted file mode 100644 index c6d2f67..0000000 --- a/source/hpr/gpu/opengl/shader_program.cpp +++ /dev/null @@ -1,22 +0,0 @@ - -#include "shader_program.hpp" -#include "shader.hpp" - - -namespace hpr::gpu::opengl -{ - -ShaderProgram::ShaderProgram() : - gpu::ShaderProgram {DeviceAPI::OpenGL}, - p_shaderProgramIndex {0} -{} - -ShaderProgram::~ShaderProgram() -{} - -Shader* ShaderProgram::shader(gpu::Shader::ShaderType type) -{ - return static_cast(p_slots[(size_t)type]); -} - -} \ No newline at end of file diff --git a/source/hpr/gpu/opengl/shader_program.hpp b/source/hpr/gpu/opengl/shader_program.hpp deleted file mode 100644 index bfb91ff..0000000 --- a/source/hpr/gpu/opengl/shader_program.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include "../shader_program.hpp" - - -namespace hpr::gpu::opengl -{ - -// Forward declarations - -class Shader; - -// - -class ShaderProgram : public gpu::ShaderProgram -{ - friend class Device; - -protected: - - unsigned int p_shaderProgramIndex; - -public: - - ShaderProgram(); - - ~ShaderProgram(); - -protected: - - Shader* shader(gpu::Shader::ShaderType type); - -}; - -} diff --git a/source/hpr/gpu/opengl/texture.cpp b/source/hpr/gpu/opengl/texture.cpp deleted file mode 100644 index 6fa139c..0000000 --- a/source/hpr/gpu/opengl/texture.cpp +++ /dev/null @@ -1,15 +0,0 @@ - -#include "texture.hpp" - - -namespace hpr::gpu::opengl -{ - -Texture::Texture() : - gpu::Texture {DeviceAPI::OpenGL}, - p_textureIndex {0} -{} - -Texture::~Texture() = default; - -} \ No newline at end of file diff --git a/source/hpr/gpu/opengl/texture.hpp b/source/hpr/gpu/opengl/texture.hpp deleted file mode 100644 index 89b2fe4..0000000 --- a/source/hpr/gpu/opengl/texture.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include "../texture.hpp" - - -namespace hpr::gpu::opengl -{ - -class Texture : public gpu::Texture -{ - friend class Device; - -protected: - - unsigned int p_textureIndex; - -public: - - Texture(); - - ~Texture() override; - -}; - -} \ No newline at end of file diff --git a/source/hpr/gpu/render_target.cpp b/source/hpr/gpu/render_target.cpp deleted file mode 100644 index b3d2738..0000000 --- a/source/hpr/gpu/render_target.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "render_target.hpp" - - -namespace hpr::gpu -{ - -RenderTarget::RenderTarget() : - Context {DeviceAPI::Unknown}, - p_posX {}, - p_posY {}, - p_width {}, - p_height {}, - p_type {Type::Unknown}, - p_hasColorData {true}, - p_hasDepthBuffer {false}, - p_depthTestEnabled {false}, - p_parent {nullptr} -{} - -RenderTarget::RenderTarget(DeviceAPI api) : - Context {api}, - p_posX {}, - p_posY {}, - p_width {}, - p_height {}, - p_type {Type::Unknown}, - p_hasColorData {true}, - p_hasDepthBuffer {false}, - p_depthTestEnabled {false}, - p_parent {nullptr} -{} - -RenderTarget::~RenderTarget() = default; - -} diff --git a/source/hpr/gpu/render_target.hpp b/source/hpr/gpu/render_target.hpp deleted file mode 100644 index 66758ec..0000000 --- a/source/hpr/gpu/render_target.hpp +++ /dev/null @@ -1,98 +0,0 @@ -#pragma once - -#include "context.hpp" - - -namespace hpr::gpu -{ - -class RenderTarget : public Context -{ - friend class Device; - -public: - - enum class Type - { - Unknown, - Screen, - Framebuffer - }; - -protected: - - int p_posX; - int p_posY; - int p_width; - int p_height; - - Type p_type; - - bool p_hasColorData; - bool p_hasDepthBuffer; - bool p_depthTestEnabled; - - RenderTarget* p_parent; - -public: - - RenderTarget(); - - RenderTarget(DeviceAPI api); - - virtual - ~RenderTarget(); - - int posX() const - { - return p_posX; - } - - int posY() const - { - return p_posY; - } - - int width() const - { - return p_width; - } - - int height() const - { - return p_height; - } - - Type type() const - { - return p_type; - } - - bool hasColorData() const - { - return p_hasColorData; - } - - bool hasDepthBuffer() const - { - return p_hasDepthBuffer; - } - - bool isDepthTestEnabled() const - { - return p_depthTestEnabled; - } - - void depthTest(bool enable) - { - p_depthTestEnabled = enable; - } - - RenderTarget* parent() - { - return p_parent; - } - -}; - -} \ No newline at end of file diff --git a/source/hpr/gpu/renderbuffer.hpp b/source/hpr/gpu/renderbuffer.hpp new file mode 100644 index 0000000..b38c079 --- /dev/null +++ b/source/hpr/gpu/renderbuffer.hpp @@ -0,0 +1,69 @@ +#pragma once + +#ifndef __gl_h_ +#include +#endif + + + +namespace hpr::gpu +{ + + class Renderbuffer + { + + protected: + + unsigned int p_index; + + public: + + inline + Renderbuffer() : + p_index {0} + {} + + virtual + ~Renderbuffer() = default; + + [[nodiscard]] + unsigned int index() const + { + return p_index; + } + + void bind() + { + glBindRenderbuffer(GL_RENDERBUFFER, p_index); + } + + void unbind() + { + glBindRenderbuffer(GL_RENDERBUFFER, 0); + } + + void create() + { + glGenRenderbuffers(1, &p_index); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, p_index); + } + + void storage(int width, int height) + { + glBindRenderbuffer(GL_RENDERBUFFER, p_index); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + } + + void destroy() + { + glDeleteRenderbuffers(1, &p_index); + } + + bool valid() const + { + return p_index != 0; + } + }; + +} diff --git a/source/hpr/gpu/scene.hpp b/source/hpr/gpu/scene.hpp new file mode 100644 index 0000000..8049e89 --- /dev/null +++ b/source/hpr/gpu/scene.hpp @@ -0,0 +1,8 @@ +// +// Created by L-Nafaryus on 12/16/2022. +// + +#ifndef HPR_SCENE_HPP +#define HPR_SCENE_HPP + +#endif //HPR_SCENE_HPP diff --git a/source/hpr/gpu/shader.cpp b/source/hpr/gpu/shader.cpp deleted file mode 100644 index 6204790..0000000 --- a/source/hpr/gpu/shader.cpp +++ /dev/null @@ -1,39 +0,0 @@ - -#include "shader.hpp" - - -namespace hpr::gpu -{ - -Shader::Shader() : - Context {DeviceAPI::Unknown}, - p_filename {}, - p_label {}, - p_type {ShaderType::Vertex} -{} - -Shader::Shader(DeviceAPI api) : - Context {api}, - p_filename {}, - p_label {}, - p_type {ShaderType::Vertex} -{} - -Shader::~Shader() = default; - -std::string Shader::filename() const -{ - return p_filename; -} - -std::string Shader::label() const -{ - return p_label; -} - -Shader::ShaderType Shader::type() const -{ - return p_type; -} - -} \ No newline at end of file diff --git a/source/hpr/gpu/shader.hpp b/source/hpr/gpu/shader.hpp index a780fbe..17380a0 100644 --- a/source/hpr/gpu/shader.hpp +++ b/source/hpr/gpu/shader.hpp @@ -1,54 +1,129 @@ #pragma once -#include "context.hpp" - #include +#ifndef __gl_h_ +#include +#endif namespace hpr::gpu { -class Shader : public Context +class Shader { - friend class Device; public: - enum class ShaderType + enum class Type { - Vertex, - Geometry, - Fragment, - ShaderTypeCount + Vertex = GL_VERTEX_SHADER, + TessControl = GL_TESS_CONTROL_SHADER, + TessEvaluation = GL_TESS_EVALUATION_SHADER, + Geometry = GL_GEOMETRY_SHADER, + Fragment = GL_FRAGMENT_SHADER, + Compute = GL_COMPUTE_SHADER, + Unknown = -1 }; protected: std::string p_filename; + std::string p_source; std::string p_label; - ShaderType p_type; + Type p_type; + + unsigned int p_index; public: // Constructors - Shader(); + inline + Shader() : + p_filename {}, + p_source {}, + p_label {}, + p_type {Type::Unknown}, + p_index {0} + {} - explicit - Shader(DeviceAPI api); + inline + Shader(Type type) : + p_filename {}, + p_source {}, + p_label {}, + p_type {type} + {} - ~Shader() override; + inline + Shader(Type type, const std::string& source) : + p_filename {}, + p_source {source}, + p_label {}, + p_type {type}, + p_index {0} + {} + + virtual + ~Shader() = default; // Member functions [[nodiscard]] - std::string filename() const; + std::string filename() const + { + return p_filename; + } [[nodiscard]] - std::string label() const; + std::string label() const + { + return p_label; + } [[nodiscard]] - ShaderType type() const; + Type type() const + { + return p_type; + } + + [[nodiscard]] + unsigned int index() const + { + return p_index; + } + + void create(const std::string& label = "") + { + if (p_type == Type::Unknown) + throw std::runtime_error("Unknown shader type"); + + p_index = glCreateShader(static_cast(p_type)); + if (p_index == 0) + throw std::runtime_error("Cannot create shader"); + + const char* shaderSource = p_source.c_str(); + glShaderSource(p_index, 1, &shaderSource, nullptr); + GLenum result = glGetError(); + glCompileShader(p_index); + + int shaderStatus; + glGetShaderiv(p_index, GL_COMPILE_STATUS, &shaderStatus); + if (!shaderStatus) + { + char error[2048 + 1]; + glGetShaderInfoLog(p_index, 2048, nullptr, error); + + throw std::runtime_error(error); + } + + p_label = label; + } + + void destroy() + { + glDeleteShader(p_index); + } }; -} // end namespace hpr::gpu \ No newline at end of file +} \ No newline at end of file diff --git a/source/hpr/gpu/shader_program.cpp b/source/hpr/gpu/shader_program.cpp deleted file mode 100644 index 87f5b64..0000000 --- a/source/hpr/gpu/shader_program.cpp +++ /dev/null @@ -1,20 +0,0 @@ - -#include "shader_program.hpp" - - -namespace hpr::gpu -{ - -ShaderProgram::ShaderProgram() : - Context {DeviceAPI::Unknown}, - p_isLinked {false} -{} - -ShaderProgram::ShaderProgram(DeviceAPI api) : - Context {api}, - p_isLinked {false} -{} - -ShaderProgram::~ShaderProgram() = default; - -} \ No newline at end of file diff --git a/source/hpr/gpu/shader_program.hpp b/source/hpr/gpu/shader_program.hpp index 7f3cad9..c5d76cb 100644 --- a/source/hpr/gpu/shader_program.hpp +++ b/source/hpr/gpu/shader_program.hpp @@ -1,37 +1,96 @@ #pragma once -#include "context.hpp" -#include "shader.hpp" +#include "../containers.hpp" -#include "../containers/array.hpp" +#include +#ifndef __gl_h_ +#include +#endif namespace hpr::gpu { -class ShaderProgram : public Context -{ - friend class Device; + class ShaderProgram + { -protected: + protected: - sarray p_slots; - bool p_isLinked; + unsigned int p_index; + darray p_shaders; -public: + public: - // Constructors + // Constructors - ShaderProgram(); + inline + ShaderProgram() : + p_index {0} + {} - explicit - ShaderProgram(DeviceAPI api); + virtual + ~ShaderProgram() = default; - ~ShaderProgram() override; + [[nodiscard]] + unsigned int index() const + { + return p_index; + } - // Member functions + darray shaders() + { + return p_shaders; + } - const Shader* getShader(Shader::ShaderType type) const; -}; + void create(const std::string& label = "") + { + p_index = glCreateProgram(); + } -} \ No newline at end of file + void attach(const Shader& shader) + { + glAttachShader(p_index, shader.index()); + p_shaders.push(shader); + } + + void detach(const Shader& shader) + { + // WARNING: segfault, destroy_at (char) + p_shaders.remove([shader](const Shader& _shader) + { + return shader.index() == _shader.index(); + }); + + glDetachShader(p_index, shader.index()); + } + + void link() + { + glLinkProgram(p_index); + + GLint status; + glGetProgramiv(p_index, GL_LINK_STATUS, &status); + + if (status == GL_FALSE) + throw std::runtime_error("Shader program link error"); + } + + void destroy() + { + //for (auto& shader : p_shaders) + // detach(shader); + glDeleteShader(p_index); + } + + void bind() + { + glUseProgram(p_index); + } + + void unbind() + { + glUseProgram(0); + } + }; + +} diff --git a/source/hpr/gpu/stencil_buffer.hpp b/source/hpr/gpu/stencil_buffer.hpp new file mode 100644 index 0000000..c7bbb65 --- /dev/null +++ b/source/hpr/gpu/stencil_buffer.hpp @@ -0,0 +1,84 @@ +#pragma once + +#ifndef __gl_h_ +#include +#endif + +namespace hpr::gpu +{ + + class StencilBuffer + { + + protected: + + bool p_enabled; + bool p_binded; + + public: + + inline + StencilBuffer() : + p_enabled {false}, + p_binded {false} + {} + + inline + StencilBuffer(bool enabled) : + p_enabled {enabled}, + p_binded {false} + {} + + virtual + ~StencilBuffer() = default; + + + inline + void bind() + { + p_binded = true; + glEnable(GL_STENCIL_TEST); + } + + inline + void unbind() + { + p_binded = false; + glDisable(GL_STENCIL_TEST); + } + + inline + bool binded() const + { + return p_binded; + } + + inline + void enable() + { + p_enabled = true; + glStencilMask(GL_TRUE); + } + + inline + void disable() + { + p_enabled = false; + glStencilMask(GL_FALSE); + } + + [[nodiscard]] + inline + bool enabled() const + { + return p_enabled; + } + + inline + void clear() const + { + glClear(GL_STENCIL_BUFFER_BIT); + } + }; + +} diff --git a/source/hpr/gpu/texture.cpp b/source/hpr/gpu/texture.cpp deleted file mode 100644 index bcf414c..0000000 --- a/source/hpr/gpu/texture.cpp +++ /dev/null @@ -1,40 +0,0 @@ - -#include "texture.hpp" - - -namespace hpr::gpu -{ - -Texture::Texture() : - Context {DeviceAPI::Unknown}, - p_filename {}, - p_width {0}, - p_height {0} -{} - - -Texture::Texture(DeviceAPI api) : - Context {api}, - p_filename {}, - p_width {0}, - p_height {0} -{} - -Texture::~Texture() = default; - -std::string Texture::filename() const -{ - return p_filename; -} - -int Texture::width() const -{ - return p_width; -} - -int Texture::height() const -{ - return p_height; -} - -} diff --git a/source/hpr/gpu/texture.hpp b/source/hpr/gpu/texture.hpp index b78af12..0194f5b 100644 --- a/source/hpr/gpu/texture.hpp +++ b/source/hpr/gpu/texture.hpp @@ -1,42 +1,193 @@ #pragma once -#include "context.hpp" +#include "../containers.hpp" #include +#include +#define STB_IMAGE_IMPLEMENTATION +#include +#ifndef __gl_h_ +#include +#endif namespace hpr::gpu { -class Texture : public Context -{ -protected: + class Texture + { - std::string p_filename; - int p_width; - int p_height; + public: -public: + using ustring = std::basic_string; - // Constructors + public: - Texture(); + enum class Format + { + RGB = GL_RGB, + RGBA = GL_RGBA + }; - explicit - Texture(DeviceAPI api); + protected: - ~Texture() override; + unsigned int p_index; + std::string p_filename; + ustring p_source; - // Member functions + int p_width; + int p_height; + Format p_internalFormat; + Format p_imageFormat; - [[nodiscard]] - std::string filename() const; + public: - [[nodiscard]] - int width() const; + inline + Texture() : + p_index {0}, + p_filename {}, + p_source {}, + p_width {}, + p_height {}, + p_internalFormat {Format::RGBA}, + p_imageFormat {Format::RGBA} + {} - [[nodiscard]] - int height() const; -}; + inline + Texture(const std::string& filename) : + p_index {0}, + p_filename {filename}, + p_source {}, + p_width {}, + p_height {}, + p_internalFormat {Format::RGB}, + p_imageFormat {Format::RGB} + {} + + virtual + ~Texture() = default; + + [[nodiscard]] + unsigned int index() const + { + return p_index; + } + + [[nodiscard]] + unsigned int width() const + { + return p_width; + } + + [[nodiscard]] + unsigned int height() const + { + return p_height; + } + + void active() + { + glActiveTexture(GL_TEXTURE0 + p_index); + } + + void bind() + { + glBindTexture(GL_TEXTURE_2D, p_index); + } + + void unbind() + { + glBindTexture(GL_TEXTURE_2D, 0); + } + + void alphaChannel(bool enabled) + { + if (enabled) + { + p_internalFormat = Format::RGBA; + p_imageFormat = Format::RGBA; + } + else + { + p_internalFormat = Format::RGB; + p_imageFormat = Format::RGB; + } + } + + void load(const std::string& filename) + { + auto filepath = std::filesystem::canonical(std::filesystem::path(filename)).string(); + + stbi_set_flip_vertically_on_load(true); + int channelsCount; + unsigned char* source = stbi_load(filepath.c_str(), &p_width, &p_height, &channelsCount, 0); + + if (!source) + throw std::runtime_error("Failed to load texture source"); + else + create(source); + + stbi_image_free(source); + } + + void load() + { + load(p_filename); + } + + void create() + { + glGenTextures(1, &p_index); + bind(); + + glTexImage2D(GL_TEXTURE_2D, 0, (GLint)p_internalFormat, p_width, p_height, 0, (GLint)p_imageFormat, GL_UNSIGNED_BYTE, nullptr); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + unbind(); + } + + void create(const ustring& source) + { + glGenTextures(1, &p_index); + bind(); + + glTexImage2D(GL_TEXTURE_2D, 0, (GLint)p_internalFormat, p_width, p_height, 0, (GLint)p_imageFormat, GL_UNSIGNED_BYTE, source.data()); + + p_source = source; + + glGenerateMipmap(GL_TEXTURE_2D); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + unbind(); + } + + void rescale(int width, int height) + { + bind(); + glTexImage2D(GL_TEXTURE_2D, 0, (GLint)p_internalFormat, p_width, p_height, 0, (GLint)p_imageFormat, GL_UNSIGNED_BYTE, !p_source.empty() ? p_source.data() : nullptr); + unbind(); + } + + void destroy() + { + glDeleteTextures(1, &p_index); + } + + bool valid() const + { + return p_index != 0; + } + }; + +} -} // end namespace hpr::gpu \ No newline at end of file diff --git a/source/hpr/gpu/viewer.hpp b/source/hpr/gpu/viewer.hpp new file mode 100644 index 0000000..1cf0c0f --- /dev/null +++ b/source/hpr/gpu/viewer.hpp @@ -0,0 +1,8 @@ +// +// Created by L-Nafaryus on 12/16/2022. +// + +#ifndef HPR_VIEWER_HPP +#define HPR_VIEWER_HPP + +#endif //HPR_VIEWER_HPP diff --git a/source/hpr/gpu/viewport.hpp b/source/hpr/gpu/viewport.hpp new file mode 100644 index 0000000..4e71440 --- /dev/null +++ b/source/hpr/gpu/viewport.hpp @@ -0,0 +1,45 @@ +#pragma once + +#include "../math/vector.hpp" +#ifndef __gl_h_ +#include +#endif + + +namespace hpr::gpu +{ + +class Viewport +{ + +protected: + + vec2 p_pos; + vec2 p_size; + +public: + + inline + Viewport() : + p_pos {0.f, 0.f}, + p_size {0.f, 0.f} + {} + + inline + Viewport(const vec2& pos, const vec2& size) : + p_pos {pos}, + p_size {size} + {} + + virtual + ~Viewport() = default; + + inline + void set() + { + glViewport(p_pos[0], p_pos[1], p_size[0], p_size[1]); + } + +}; + +} \ No newline at end of file diff --git a/source/hpr/io/CMakeLists.txt b/source/hpr/io/CMakeLists.txt index 91c58f5..6085647 100644 --- a/source/hpr/io/CMakeLists.txt +++ b/source/hpr/io/CMakeLists.txt @@ -63,4 +63,6 @@ install( ) - +if(HPR_TEST) + add_subdirectory(tests) +endif() diff --git a/source/hpr/io/logger.hpp b/source/hpr/io/logger.hpp index fb37385..b6f8ece 100644 --- a/source/hpr/io/logger.hpp +++ b/source/hpr/io/logger.hpp @@ -1,35 +1,274 @@ #pragma once -#include - +#include "../containers/array.hpp" +#include +#include +#include +#include namespace hpr { + + +namespace logging +{ + enum Severity + { + Emergency, + Alert, + Critical, + Error, + Warning, + Notice, + Info, + Debug + }; + + class Sink + { + //friend class Logger; + + protected: + + Severity p_severity; + std::string_view p_message; + + public: + + Sink() : + p_severity {Emergency}, + p_message {} + {} + + Sink(Severity severity) : + p_severity {severity}, + p_message {} + {} + + void addMessage(const std::string_view& message) + { + p_message = message; + } + + virtual + void flush() = 0; + + + virtual + ~Sink() = default; + + }; + + class StandardOutput : public Sink + { + + public: + + StandardOutput() : + Sink() + {} + + explicit + StandardOutput(Severity severity) : + Sink(severity) + {} + + void flush() override + { + if (p_severity < Error) + std::cerr << p_message << "\n"; + if (p_severity < Debug) + std::cout << p_message << "\n"; + std::cout.flush(); + } + + + ~StandardOutput() override = default; + + }; + + enum class LoggerState + { + Endline, + Flush, + Exception, + Exit + }; + class Logger { - public: - enum Severity - { - None, - Error, - Warning, - Info, - Debug - }; - static Severity severity; + static Logger g_instance; + static darray g_sinks; - template - friend - Logger& operator<<(Logger& l, const T& data) - { - if (severity == Info) - std::cout << data << std::endl; - else if (severity == Error) - std::cerr << data << std::endl; + protected: - return l; + Severity p_severity; + std::ostringstream p_stream; + int p_exitcode; + sarray p_levelNames; + darray p_buffer; + + protected: + + Logger() : + p_severity {Emergency}, + p_stream {}, + p_exitcode {-1}, + p_levelNames { "Emergency", "Alert", "Critical", "Error", "Warning", "Notice", "Info", "Debug"} + {} + + static Logger& instance() + { + return g_instance; } + + public: + + static void destroy() + { + for (Sink* sink : g_sinks) + delete sink; + g_sinks.clear(); + } + + static darray& sinks() + { + return g_sinks; + } + + static void addSink(Sink* sink) + { + if (sink != nullptr) + g_sinks.push(sink); + } + + static Severity severity() + { + return g_instance.p_severity; + } + + static void severity(Severity severity) + { + g_instance.p_severity = severity; + } + + // begin functions + friend + std::ostringstream&& log(Severity severity); + + + + // end functions + friend + LoggerState endl(); + + friend + LoggerState flush(); + + friend + LoggerState exception(); + + friend + LoggerState exit(int code); + + // + friend + std::ostream& operator<<(std::ostream& stream, const LoggerState& state); }; - Logger::Severity Logger::severity = Logger::Warning; - Logger logger; + + // + Logger Logger::g_instance; + darray Logger::g_sinks; + + // + std::ostringstream&& log(Severity severity) + { + Logger& instance = Logger::instance(); + instance.p_severity = severity; + //std::ostringstream oss; + //return instance.p_stream; + return std::move(std::ostringstream());// oss;//std::forward(oss); + } + + std::ostringstream&& error() + { + return log(Error); + } + + // + LoggerState endl() + { + return LoggerState::Endline; + } + + LoggerState flush() + { + return LoggerState::Flush; + } + + LoggerState exception() + { + return LoggerState::Exception; + } + + LoggerState exit(int code) + { + Logger& instance = Logger::instance(); + instance.p_exitcode = code; + return LoggerState::Exit; + } + + + std::ostream& operator<<(std::ostream& stream, const LoggerState& state) + { + stream << std::endl; + std::ostringstream oss; + oss << stream.rdbuf(); + std::string test = oss.str(); + std::cout << test << std::endl; + //static std::mutex mtx; + //std::lock_guard lock(mtx); + Logger& instance = Logger::instance(); + + if (state >= LoggerState::Endline) + { + stream << "\n"; + } + + //instance.p_stream << stream.rdbuf(); + + + if (state >= LoggerState::Flush) + { + // default sink + if (Logger::sinks().is_empty()) + { + std::unique_ptr sink = std::make_unique(Logger::severity()); + sink->addMessage(oss.str()); + sink->flush(); + //delete sink; + } + + // global sinks + for (Sink* sink : Logger::sinks()) + { + sink->addMessage(oss.str()); + sink->flush(); + } + } + + if (state == LoggerState::Exception) + { + throw std::runtime_error(oss.str()); + } + + if (state == LoggerState::Exit) + { + std::exit(instance.p_exitcode); + } + + //instance.p_stream.flush(); + return stream; + } +} } diff --git a/source/hpr/io/tests/CMakeLists.txt b/source/hpr/io/tests/CMakeLists.txt new file mode 100644 index 0000000..1644c07 --- /dev/null +++ b/source/hpr/io/tests/CMakeLists.txt @@ -0,0 +1,14 @@ +file(GLOB tests_cpp "*.cpp") + +add_executable(${PROJECT_NAME}-tests + ${tests_cpp} +) + +target_link_libraries(${PROJECT_NAME}-tests + PUBLIC + hpr::${PROJECT_NAME} + PRIVATE + GTest::gtest_main +) + +gtest_add_tests(TARGET ${PROJECT_NAME}-tests) diff --git a/source/hpr/io/tests/io-test.cpp b/source/hpr/io/tests/io-test.cpp new file mode 100644 index 0000000..ed615a5 --- /dev/null +++ b/source/hpr/io/tests/io-test.cpp @@ -0,0 +1,23 @@ +#include + +#include "../logger.hpp" +#include + +void task1() +{ + using namespace hpr; + logging::error() << "Not error: thread " << std::this_thread::get_id() << logging::flush(); + //std::cout << (logging::error() << "Not error: thread " << std::this_thread::get_id()).str() << std::endl;// << logging::flush(); + //std::cout << "Not error: thread " << std::this_thread::get_id() << std::endl; +} + +TEST(io, Logger) +{ + using namespace hpr; + logging::error() << "Not error: main thread" << logging::flush(); + std::cout << "Main thread " << std::this_thread::get_id() << std::endl; + /*std::thread t1 {task1}; + std::thread t2 {task1}; + t1.join(); + t2.join();*/ +} \ No newline at end of file diff --git a/source/hpr/math/CMakeLists.txt b/source/hpr/math/CMakeLists.txt index 89c5e47..781214f 100644 --- a/source/hpr/math/CMakeLists.txt +++ b/source/hpr/math/CMakeLists.txt @@ -10,7 +10,7 @@ add_library(${CMAKE_PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) add_module(${PROJECT_NAME}) file(GLOB ${CMAKE_PROJECT_NAME}_${PROJECT_NAME}_HEADERS - "../math.hpp" "*.hpp" "scalar/*.hpp" "vector/*.hpp" "matrix/*.hpp" + "../math.hpp" "*.hpp" "scalar/*.hpp" "vector/*.hpp" "matrix/*.hpp" "quaternion/*.hpp" ) foreach(_header_path ${${CMAKE_PROJECT_NAME}_${PROJECT_NAME}_HEADERS}) diff --git a/source/hpr/math/integer.hpp b/source/hpr/math/integer.hpp new file mode 100644 index 0000000..28c1742 --- /dev/null +++ b/source/hpr/math/integer.hpp @@ -0,0 +1,4 @@ +#pragma once + +#include "integer/integer.hpp" +#include "integer/size.hpp" diff --git a/source/hpr/math/integer/integer.hpp b/source/hpr/math/integer/integer.hpp new file mode 100644 index 0000000..270559a --- /dev/null +++ b/source/hpr/math/integer/integer.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include + + +namespace hpr +{ + // type traits + + template + struct is_integer : public std::is_integral {}; + + // concepts + + template + concept IsInteger = is_integer::value; +} \ No newline at end of file diff --git a/source/hpr/math/integer/size.hpp b/source/hpr/math/integer/size.hpp new file mode 100644 index 0000000..ca5e851 --- /dev/null +++ b/source/hpr/math/integer/size.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include + +namespace hpr +{ + + using Size = std::size_t; + + // type traits + + template + struct is_size : public std::integral_constant::value && std::is_unsigned::value> {}; + + // concepts + + template + concept IsSize = is_size::value || std::convertible_to; + + + //using Size = typename IsSize::type; +} \ No newline at end of file diff --git a/source/hpr/math/matrix/clip_space.hpp b/source/hpr/math/matrix/clip_space.hpp index eba6fd9..9b3b15e 100644 --- a/source/hpr/math/matrix/clip_space.hpp +++ b/source/hpr/math/matrix/clip_space.hpp @@ -6,11 +6,11 @@ namespace hpr { -template +template inline -MatrixSpace ortho(Type left, Type right, Type bottom, Type top) +Matrix ortho(T left, T right, T bottom, T top) { - MatrixSpace ms; + Matrix ms; ms.fill(1); ms(0, 0) = 2 / (right - left); ms(1, 1) = 2 / (top - bottom); @@ -20,12 +20,12 @@ MatrixSpace ortho(Type left, Type right, Type bottom, Type top) return ms; } -template +template inline -MatrixSpace ortho(Type left, Type right, Type bottom, Type top, Type zNear, Type zFar) +Matrix ortho(T left, T right, T bottom, T top, T zNear, T zFar) { - MatrixSpace ms; - ms.fill(1); + Matrix ms {1}; + //ms.fill(1); ms(0, 0) = 2 / (right - left); ms(1, 1) = 2 / (top - bottom); ms(2, 2) = 2 / (zFar - zNear); @@ -35,13 +35,13 @@ MatrixSpace ortho(Type left, Type right, Type bottom, Type top, Type return ms; } -template +template inline -MatrixSpace perspective(Type fovy, Type aspect, Type zNear, Type zFar) +Matrix perspective(T fovy, T aspect, T zNear, T zFar) { - assert(abs(aspect - std::numeric_limits::epsilon()) > 0); - MatrixSpace ms; - const Type halfFovyTan = tan(fovy / 2); + assert(abs(aspect - std::numeric_limits::epsilon()) > 0); + Matrix ms; + const T halfFovyTan = tan(fovy / 2); ms(0, 0) = 1 / (aspect * halfFovyTan); ms(1, 1) = 1 / halfFovyTan; ms(2, 2) = (zFar + zNear) / (zFar - zNear); diff --git a/source/hpr/math/matrix/matrix_space.hpp b/source/hpr/math/matrix/matrix_space.hpp index b793945..f14167c 100644 --- a/source/hpr/math/matrix/matrix_space.hpp +++ b/source/hpr/math/matrix/matrix_space.hpp @@ -1,23 +1,49 @@ #pragma once -#include "../vector.hpp" +#include "../integer.hpp" +#include "../scalar.hpp" +#include "../../containers/array/static_array.hpp" namespace hpr { -template -class MatrixSpace : public VectorSpace -{ - static_assert(Rows >= 1); - static_assert(Cols >= 1); - using base = VectorSpace; +// forward declarations + +template requires (Rows >= 0 && Cols >= 0) +class Matrix; + +template +using SubMatrix = typename std::conditional<(Rows >= 2 && Cols >= 2), Matrix, Matrix>::type; + +// type traits + +template +struct is_matrix : public std::false_type {}; + +template +struct is_matrix> : public std::true_type {}; + +// concepts + +template +concept IsMatrix = is_matrix::value; + +} + +namespace hpr +{ + +template requires (Rows >= 0 && Cols >= 0) +class Matrix : public StaticArray +{ + + using base = StaticArray; - using Minor = typename std::conditional<(Rows >= 2 && Cols >= 2), MatrixSpace, MatrixSpace>::type; public: using value_type = Type; - using size_type = size_t; + using size_type = Size; using pointer = Type*; using reference = Type&; using iterator = Iterator; @@ -26,82 +52,101 @@ public: protected: - static - const size_type p_mrows = Rows - 1; - static - const size_type p_mcols = Cols - 1; size_type p_rows; size_type p_cols; public: inline - MatrixSpace() : + Matrix() : base {}, p_rows {Rows}, p_cols {Cols} {} inline - MatrixSpace(const MatrixSpace& ms) : + Matrix(const Matrix& ms) : base {static_cast(ms)}, p_rows {Rows}, p_cols {Cols} {} - inline explicit - MatrixSpace(const base& ms) : - base {ms}, + inline + Matrix(Matrix&& ms) noexcept: + base {std::forward(static_cast(ms))}, p_rows {Rows}, p_cols {Cols} {} inline - MatrixSpace(MatrixSpace&& ms) noexcept : - base {std::move(static_cast(ms))}, - p_rows {Rows}, - p_cols {Cols} - {} - - inline - MatrixSpace& operator=(const MatrixSpace& ms) + Matrix& operator=(const Matrix& ms) { base::operator=(ms); return *this; } + inline explicit + Matrix(const base& vs) : + base {vs}, + p_rows {Rows}, + p_cols {Cols} + {} + + inline explicit + Matrix(base&& vs) noexcept: + base {std::forward(vs)}, + p_rows {Rows}, + p_cols {Cols} + {} + inline - MatrixSpace(typename base::iterator start, typename base::iterator end) : + Matrix(typename base::iterator start, typename base::iterator end) : base {start, end}, p_rows {Rows}, p_cols {Cols} {} inline - MatrixSpace(typename base::const_iterator start, typename base::const_iterator end) : + Matrix(typename base::const_iterator start, typename base::const_iterator end) : base {start, end}, p_rows {Rows}, p_cols {Cols} {} inline - MatrixSpace(std::initializer_list list) : + Matrix(std::initializer_list list) : base {list}, p_rows {Rows}, p_cols {Cols} {} - template ... Args> + template inline - MatrixSpace(value_type&& v, Args&& ...args) : + Matrix(value_type&& v, Args&& ...args) requires (1 + sizeof...(args) == Rows * Cols): base {v, static_cast(std::forward(args))...}, p_rows {Rows}, p_cols {Cols} + {} + + inline + Matrix(const value_type& v) : + base {}, + p_rows {Rows}, + p_cols {Cols} { - static_assert(1 + sizeof...(args) == Rows * Cols, "Number of arguments must be equal to rows * cols of matrix"); + for (Size n = 0; n < Rows * Cols; ++n) + (*this)[n] = v; } - // Member functions + inline + Matrix& operator=(const value_type& v) + { + for (Size n = 0; n < Rows * Cols; ++n) + (*this)[n] = v; + return *this; + } + + // access inline reference operator()(size_type row, size_type col) @@ -123,154 +168,56 @@ public: return (*this)[col + p_rows * row]; } - VectorSpace row(size_type row) + Vector row(size_type row) { - VectorSpace vs; + Vector vs; for (auto n = 0; n < Cols; ++n) vs[n] = (*this)(row, n); return vs; } - VectorSpace row(size_type row) const + Vector row(size_type row) const { - VectorSpace vs; + Vector vs; for (auto n = 0; n < Cols; ++n) vs[n] = (*this)(row, n); return vs; } - void row(size_type row, const VectorSpace& vs) + void row(size_type row, const Vector& vs) { for (auto n = 0; n < Cols; ++n) (*this)(n, row) = vs[n]; } - VectorSpace col(size_type col) + Vector col(size_type col) { - VectorSpace vs; + Vector vs; for (auto n = 0; n < Rows; ++n) vs[n] = (*this)(n, col); return vs; } - void col(size_type col, const VectorSpace& vs) + void col(size_type col, const Vector& vs) { for (auto n = 0; n < Rows; ++n) (*this)(n, col) = vs[n]; } - size_type rows() const { return p_rows; } - size_type cols() const { return p_cols; } + [[nodiscard]] constexpr size_type rows() const { return p_rows; } + [[nodiscard]] constexpr size_type cols() const { return p_cols; } + + // member functions [[nodiscard]] - inline + constexpr bool is_square() const { return p_rows == p_cols; } inline - Minor minor(size_type row, size_type col) - { - if (this->size() < 4) - throw std::runtime_error("Impossible to find minor for matrix with size less than 2x2"); - Minor minor; - auto minor_iter = minor.begin(); - for (auto n = 0; n < Rows; ++n) - for (auto k = 0; k < Cols; ++k) - if (k != col && n != row) - *(minor_iter++) = (*this)[k + p_rows * n]; - return minor; - } - - inline - value_type det() - { - if (!is_square()) - throw std::runtime_error("Matrix must be square"); - if (this->size() == 1) - return (*this)[0]; - else if (this->size() == 4) - return (*this)(0, 0) * (*this)(1, 1) - (*this)(0, 1) * (*this)(1, 0); - else { - auto res = 0; - for (auto m = 0; m < Cols; ++m) - res += std::pow(-1, m) * (*this)(0, m) * minor(0, m).det(); - return res; - } - } - - inline - MatrixSpace transpose() - { - MatrixSpace ms; - for (auto n = 0; n < Rows; ++n) - for (auto k = 0; k < Cols; ++k) - ms(k, n) = (*this)(n, k); - return ms; - } - - inline - MatrixSpace adj() - { - MatrixSpace ms; - for (auto n = 0; n < Rows; ++n) - for (auto k = 0; k < Cols; ++k) - { - ms(n, k) = std::pow(-1, n + k) * minor(n, k).det(); - } - return ms.transpose(); - } - - inline - MatrixSpace inv() - { - return MatrixSpace(adj() / det()); - } - - // Friend functions - - friend inline - bool operator==(const MatrixSpace& lhs, const MatrixSpace& rhs) - { - for (auto n = 0; n < lhs.size(); ++n) - if (lhs[n] != rhs[n]) - return false; - return true; - } - - friend inline - bool operator!=(const MatrixSpace& lhs, const MatrixSpace& rhs) - { - return !(lhs == rhs); - } - - template - friend inline - bool operator==(const MatrixSpace& lhs, const VectorSpace& rhs) - { - return false; - } - - friend inline - VectorSpace operator*(const VectorSpace& vs, const MatrixSpace& ms) - { - VectorSpace res; - for (auto n = 0; n < Cols; ++n) - res[0] = sum(ms.col(n) * vs); - return res; - } - - friend inline - VectorSpace operator*(const MatrixSpace& ms, const VectorSpace& vs) - { - VectorSpace res; - for (auto n = 0; n < Rows; ++n) - res[0] = sum(ms.row(n) * vs); - return res; - } - - MatrixSpace& fill(value_type value) + Matrix& fill(value_type value) { for (auto n = 0; n < this->size(); ++n) (*this)[n] = value; @@ -280,9 +227,9 @@ public: // Global functions static inline - MatrixSpace identity() + Matrix identity() { - MatrixSpace ms; + Matrix ms; for (auto n = 0; n < Rows; ++n) for (auto k = 0; k < Cols; ++k) ms(n, k) = 1; @@ -290,13 +237,128 @@ public: } }; +// global operators + +template inline Matrix operator+(const Matrix& lhs) { Matrix ms; for (Size n = 0; n < lhs.size(); ++n) ms[n] = lhs[n]; return ms; } +template inline Matrix operator-(const Matrix& lhs) { Matrix ms; for (Size n = 0; n < lhs.size(); ++n) ms[n] = -lhs[n]; return ms; } + +template inline Matrix& operator+=(Matrix& lhs, const Matrix& rhs) { for (Size n = 0; n < lhs.size(); ++n) lhs[n] += rhs[n]; return lhs; } +template inline Matrix& operator-=(Matrix& lhs, const Matrix& rhs) { for (Size n = 0; n < lhs.size(); ++n) lhs[n] -= rhs[n]; return lhs; } +template requires (R == C2 && R2 == C) inline Matrix& operator*=(Matrix& lhs, const Matrix& rhs) { Matrix temp {lhs}; for (Size n = 0; n < R; ++n) for (Size k = 0; k < C; ++k) lhs(n, k) = sum(temp.col(k) * rhs.row(n)); return lhs; } + +template inline Matrix operator+(const Matrix& lhs, const Matrix& rhs) { Matrix ms {lhs}; for (Size n = 0; n < lhs.size(); ++n) ms[n] += rhs[n]; return ms; } +template inline Matrix operator-(const Matrix& lhs, const Matrix& rhs) { Matrix ms {lhs}; for (Size n = 0; n < lhs.size(); ++n) ms[n] -= rhs[n]; return ms; } +template requires (R == C2 && R2 == C) inline Matrix operator*(const Matrix& lhs, const Matrix& rhs) { Matrix ms; for (Size n = 0; n < R; ++n) for (Size k = 0; k < C; ++k) ms(n, k) = sum(lhs.col(k) * rhs.row(n)); return ms; } + +template inline bool operator==(const Matrix& lhs, const Matrix& rhs) { for (Size n = 0; n < lhs.size(); ++n) if (lhs[n] != rhs[n]) return false; return true; } +template inline bool operator!=(const Matrix& lhs, const Matrix& rhs) { for (Size n = 0; n < lhs.size(); ++n) if (lhs[n] == rhs[n]) return false; return true; } + + +template inline Matrix& operator+=(Matrix& lhs, const T& rhs) { for (Size n = 0; n < lhs.size(); ++n) lhs[n] += rhs; return lhs; } +template inline Matrix& operator-=(Matrix& lhs, const T& rhs) { for (Size n = 0; n < lhs.size(); ++n) lhs[n] -= rhs; return lhs; } +template inline Matrix& operator*=(Matrix& lhs, const T& rhs) { for (Size n = 0; n < lhs.size(); ++n) lhs[n] *= rhs; return lhs; } +template inline Matrix& operator/=(Matrix& lhs, const T& rhs) { for (Size n = 0; n < lhs.size(); ++n) lhs[n] /= rhs; return lhs; } + +template inline Matrix operator+(const Matrix& lhs, const T& rhs) { Matrix ms {lhs}; for (Size n = 0; n < lhs.size(); ++n) ms[n] += rhs; return ms; } +template inline Matrix operator-(const Matrix& lhs, const T& rhs) { Matrix ms {lhs}; for (Size n = 0; n < lhs.size(); ++n) ms[n] -= rhs; return ms; } +template inline Matrix operator*(const Matrix& lhs, const T& rhs) { Matrix ms {lhs}; for (Size n = 0; n < lhs.size(); ++n) ms[n] *= rhs; return ms; } +template inline Matrix operator/(const Matrix& lhs, const T& rhs) { Matrix ms {lhs}; for (Size n = 0; n < lhs.size(); ++n) ms[n] /= rhs; return ms; } + + +template inline Vector operator*(const Matrix& ms, const Vector& vs) { Vector res; for (Size n = 0; n < R; ++n) res[0] = sum(ms.row(n) * vs); return res; } +template inline Vector operator*(const Vector& vs, const Matrix& ms) { Vector res; for (Size n = 0; n < C; ++n) res[0] = sum(ms.col(n) * vs); return res; } + +template inline bool operator==(const Matrix& lhs, const Vector& rhs) { return false; } +template inline bool operator!=(const Matrix& lhs, const Vector& rhs) { return true; } + +// matrix operations + +//! Transpose matrix +template +inline +Matrix transpose(const Matrix& ms) +{ + Matrix res; + for (Size n = 0; n < R; ++n) + for (Size k = 0; k < C; ++k) + res(k, n) = ms(n, k); + return res; +} + +//! Trace of a matrix +template +inline +T trace(const Matrix& ms) requires (R == C) +{ + T res; + for (auto n = 0; n < R; ++n) + res += ms(n, n); + return res; +} + +//! Minor of a matrix +template +inline +SubMatrix minor(const Matrix& ms, Size row, Size col) +{ + if (ms.size() < 4) + throw std::runtime_error("Matrix should be greater 2x2"); + + SubMatrix minor; + auto minor_iter = minor.begin(); + for (auto n = 0; n < R; ++n) + for (auto k = 0; k < C; ++k) + if (k != col && n != row) + *(minor_iter++) = ms[k + ms.rows() * n]; + return minor; +} + +//! Determinant of a matrix +template +inline +scalar det(const Matrix& ms) requires (R == C) +{ + if (ms.size() == 1) + return ms[0]; + + else if (ms.size() == 4) + return ms(0, 0) * ms(1, 1) - ms(0, 1) * ms(1, 0); + + else { + scalar res = 0; + for (auto n = 0; n < ms.cols(); ++n) + res += pow(-1, n) * ms(0, n) * det(minor(ms, 0, n)); + return res; + } +} + +//! Adjoint matrix +template +inline +Matrix adj(const Matrix& ms) +{ + Matrix res; + for (auto n = 0; n < R; ++n) + for (auto k = 0; k < C; ++k) + res(n, k) = pow(-1, n + k) * det(minor(ms, n, k)); + return transpose(res); +} + +//! Inverse matrix +template +inline +Matrix inv(const Matrix& ms) +{ + return adj(ms) / det(ms); +} + // Aliases template -using mat = MatrixSpace; +using mat = Matrix; -using mat2 = MatrixSpace; -using mat3 = MatrixSpace; -using mat4 = MatrixSpace; +using mat2 = Matrix; +using mat3 = Matrix; +using mat4 = Matrix; } \ No newline at end of file diff --git a/source/hpr/math/matrix/transform.hpp b/source/hpr/math/matrix/transform.hpp index 2c6de63..9836ddd 100644 --- a/source/hpr/math/matrix/transform.hpp +++ b/source/hpr/math/matrix/transform.hpp @@ -6,37 +6,37 @@ namespace hpr { -template +template inline -mat translate(const mat& ms, const vec& vs) +Matrix translate(const Matrix& ms, const Vector& vs) { - mat res {ms}; + Matrix res {ms}; res.col(3, ms.row(0) * vs[0] + ms.row(1) * vs[1] + ms.row(2) * vs[2] + ms.row(3)); return res; } -template +template inline -vec translate(const vec& vs1, const vec& vs2) +Vector translate(const Vector& vs1, const Vector& vs2) { - mat res = mat::identity(); - res.row(3, vec(vs1, 0.)); + Matrix res = Matrix::identity(); + res.row(3, Vector(vs1, 0.)); res = translate(res, vs2); - return vec(res.row(3)); + return Vector(res.row(3)); } -template +template inline -mat rotate(const mat& ms, const vec& vs, Type angle) +Matrix rotate(const Matrix& ms, const Vector& vs, T angle) { - const Type cosv = cos(angle); - const Type sinv = sin(angle); - vec axis {normalize(vs)}; - vec temp {(1. - cosv) * axis}; + const T cosv = cos(angle); + const T sinv = sin(angle); + Vector axis {normalize(vs)}; + Vector temp {(1. - cosv) * axis}; - mat rot; + Matrix rot; rot(0, 0) = cosv + temp[0] * axis[0]; rot(0, 1) = temp[0] * axis[1] + sinv * axis[2]; rot(0, 2) = temp[0] * axis[2] - sinv * axis[1]; @@ -47,7 +47,7 @@ mat rotate(const mat& ms, const vec& vs, Type a rot(2, 1) = temp[2] * axis[1] - sinv * axis[0]; rot(2, 2) = cosv + temp[2] * axis[2]; - mat res {ms}; + Matrix res {ms}; res.row(0, ms.row(0) * rot(0, 0) + ms.row(1) * rot(0, 1) + ms.row(2) * rot(0, 2)); res.row(1, ms.row(0) * rot(1, 0) + ms.row(1) * rot(1, 1) + ms.row(2) * rot(1, 2)); res.row(2, ms.row(0) * rot(2, 0) + ms.row(1) * rot(2, 1) + ms.row(2) * rot(2, 2)); @@ -56,22 +56,22 @@ mat rotate(const mat& ms, const vec& vs, Type a return res; } -template +template inline -vec rotate(const vec& vs1, const vec& vs2, Type angle) +Vector rotate(const Vector& vs1, const Vector& vs2, T angle) { - mat res = mat::identity(); - res.row(3, vec(vs1, 0.)); + Matrix res = Matrix::identity(); + res.row(3, Vector(vs1, 0.)); res = rotate(res, vs2, angle); - return vec(res.row(3)); + return Vector(res.row(3)); } -template +template inline -mat scale(const mat& ms, const vec& vs) +Matrix scale(const Matrix& ms, const Vector& vs) { - mat res; + Matrix res; res.row(0, ms.row(0) * vs[0]); res.row(1, ms.row(1) * vs[1]); res.row(2, ms.row(2) * vs[2]); @@ -81,19 +81,19 @@ mat scale(const mat& ms, const vec& vs) } -template +template inline -mat lookAt(const mat& ms, const vec& eye, const vec& center, const vec& up) +Matrix lookAt(const Matrix& ms, const Vector& eye, const Vector& center, const Vector& up) { - const vec forward {normalize(center - eye)}; - const vec left {normalize(cross(up, forward))}; - const vec nup {cross(forward, left)}; + const Vector forward {normalize(center - eye)}; + const Vector left {normalize(cross(up, forward))}; + const Vector nup {cross(forward, left)}; - mat res; - res.col(0, vec(left, 0)); - res.col(1, vec(nup, 0)); - res.col(2, vec(forward, 0)); - res.row(3, -vec(dot(left, eye), dot(nup, eye), dot(forward, eye), -1.)); + Matrix res; + res.col(0, Vector(left, 0)); + res.col(1, Vector(nup, 0)); + res.col(2, Vector(forward, 0)); + res.row(3, -Vector(dot(left, eye), dot(nup, eye), dot(forward, eye), -1.)); return res; } diff --git a/source/hpr/math/quaternion.hpp b/source/hpr/math/quaternion.hpp new file mode 100644 index 0000000..b488e42 --- /dev/null +++ b/source/hpr/math/quaternion.hpp @@ -0,0 +1,3 @@ +#pragma once + +#include "quaternion/quaternion.hpp" \ No newline at end of file diff --git a/source/hpr/math/quaternion/quaternion.hpp b/source/hpr/math/quaternion/quaternion.hpp new file mode 100644 index 0000000..1180e33 --- /dev/null +++ b/source/hpr/math/quaternion/quaternion.hpp @@ -0,0 +1,259 @@ +#pragma once + +#include "../vector.hpp" + + +namespace hpr +{ + +// Forward declaration + +class Quaternion; + +inline +Quaternion inverse(const Quaternion& q); + +inline +Quaternion operator*(const Quaternion& lhs, const Quaternion& rhs); + +// Class declaration +class Quaternion +{ + +public: + + enum RotationSequence + { + ZYX, ZYZ, ZXY, ZXZ, YXZ, YXY, YZX, YZY, XYZ, XYX, XZY, XZX + }; + +protected: + + scalar p_real; + vec3 p_imag; + +public: + + inline + Quaternion() : + p_real{}, + p_imag{} + {} + + inline + Quaternion(const scalar real, const vec3& imag) : + p_real {real}, + p_imag {imag} + {} + + inline explicit + Quaternion(const scalar real) : + p_real {real}, + p_imag {} + {} + + inline explicit + Quaternion(const vec3& imag) : + p_real {}, + p_imag {imag} + {} + + inline + Quaternion(const vec3& vs, const scalar& theta) : + p_real {cos(0.5 * theta)}, + p_imag {sin(0.5 * theta) * vs / mag(vs)} + {} + + static inline + Quaternion unit(const vec3& vs) + { + return Quaternion(sqrt(1 - norm(vs)), vs); + } + + inline + Quaternion(const RotationSequence rs, const vec3& angles) + { + switch (rs) + { + case XYZ: + *this = Quaternion(vec3(0, 1, 0), angles[0]) * + Quaternion(vec3(0, 1, 0), angles[1]) * + Quaternion(vec3(0, 0, 1), angles[2]); + break; + + default: + throw std::runtime_error("Unknown rotation sequence"); + } + } + + inline + scalar real() const + { + return p_real; + } + + inline + scalar& real() + { + return p_real; + } + + inline + vec3 imag() const + { + return p_imag; + } + + inline + vec3& imag() + { + return p_imag; + } + + inline + void operator+=(const Quaternion& q) + { + p_real += q.p_real; + p_imag += q.p_imag; + } + + inline + void operator-=(const Quaternion& q) + { + p_real -= q.p_real; + p_imag -= q.p_imag; + } + + inline + void operator*=(const Quaternion& q) + { + scalar temp = p_real; + p_real = p_real * q.p_real - dot(p_imag, q.p_imag); + p_imag = temp * q.p_imag + q.p_real * p_imag + cross(p_imag, q.p_imag); + } + + inline + void operator/=(const Quaternion& q) + { + operator*=(inverse(q)); + } + + inline + void operator*=(const scalar s) + { + p_real *= s; + p_imag *= s; + } + + inline + void operator/=(const scalar s) + { + p_real /= s; + p_imag /= s; + } +}; + +inline +bool equal(const Quaternion& lhs, const Quaternion& rhs) +{ + return lhs.real() == rhs.real() && lhs.imag() == rhs.imag(); +} + +inline +bool operator==(const Quaternion& lhs, const Quaternion& rhs) +{ + return equal(lhs, rhs); +} + +inline +bool operator!=(const Quaternion& lhs, const Quaternion& rhs) +{ + return !equal(lhs, rhs); +} + +inline +Quaternion operator+(const Quaternion& lhs, const Quaternion& rhs) +{ + return {lhs.real() + rhs.real(), lhs.imag() + rhs.imag()}; +} + +inline +Quaternion operator-(const Quaternion& q) +{ + return {q.real(), q.imag()}; +} + +inline +Quaternion operator-(const Quaternion& lhs, const Quaternion& rhs) +{ + return {lhs.real() - rhs.real(), lhs.imag() - rhs.imag()}; +} + +inline +Quaternion operator*(const Quaternion& lhs, const Quaternion& rhs) +{ + return {lhs.real() * rhs.real() - dot(lhs.imag(), rhs.imag()), + lhs.real() * rhs.imag() + rhs.real() * lhs.imag() + cross(lhs.imag(), rhs.imag())}; +} + +inline +Quaternion operator/(const Quaternion& lhs, const Quaternion& rhs) +{ + return lhs * inverse(rhs); +} + +inline +Quaternion operator*(const scalar s, const Quaternion& q) +{ + return {s * q.real(), s * q.imag()}; +} + +inline +Quaternion operator*(const Quaternion& q, const scalar s) +{ + return {q.real() * s, q.imag() * s}; +} + +inline +Quaternion operator/(const Quaternion& q, const scalar s) +{ + return {q.real() / s, q.imag() / s}; +} + +inline +scalar norm(const Quaternion& q) +{ + return sqrt(pow(q.real(), 2) + dot(q.imag(), q.imag())); +} + +inline +Quaternion conjugate(const Quaternion& q) +{ + return {q.real(), -q.imag()}; +} + +inline +Quaternion inverse(const Quaternion& q) +{ + return conjugate(q) / pow(norm(q), 2); +} + +inline +Quaternion normalize(const Quaternion& q) +{ + return q / norm(q); +} + +inline +vec3 rotate(const vec3& point, const vec3& axis, const scalar& angle) +{ + Quaternion p {point}; + Quaternion q {normalize(axis), angle}; + return (q * p * inverse(q)).imag(); +} + +// Aliases + +using quat = Quaternion; + +} \ No newline at end of file diff --git a/source/hpr/math/scalar/scalar.hpp b/source/hpr/math/scalar/scalar.hpp index 2025d5b..3583857 100644 --- a/source/hpr/math/scalar/scalar.hpp +++ b/source/hpr/math/scalar/scalar.hpp @@ -3,93 +3,306 @@ #include #include +namespace hpr +{ + +// type traits + +template +struct is_scalar : public std::is_floating_point {}; + +// concepts + +template +concept IsScalar = is_scalar::value; + +template +concept IsReal = is_integer::value || is_scalar::value; + +// forward declaration + +template +class Scalar; + +} + +namespace std +{ + template struct is_floating_point> : true_type {}; +} namespace hpr { -#define PRECISION_DOUBLE -#if defined(PRECISION_FLOAT) +// class declaration -using scalar = float; +template +class Scalar +{ -#elif defined(PRECISION_DOUBLE) +public: -using scalar = double; + using type = Scalar; + using value_type = T; -#elif defined(PRECISION_LONGDOUBLE) +protected: -using scalar = long double; + value_type p_value; +public: + + // constructors + + constexpr Scalar() : p_value {} {} + + template constexpr Scalar(const Scalar& value) : p_value {static_cast(value.p_value)} {} + + template constexpr Scalar(const X& value) : p_value {static_cast(value)} {} + + template constexpr type& operator=(const Scalar& value) { p_value = static_cast(value.p_value); return *this; } + + template constexpr type& operator=(const X& value) { p_value = static_cast(value); return *this; } + + virtual constexpr ~Scalar() = default; + + // conversion + + constexpr operator double() const { return static_cast(p_value); } + + constexpr operator float() const { return static_cast(p_value); } + + constexpr operator long double() const { return static_cast(p_value); } + + constexpr operator bool() const { return static_cast(p_value); } + + // access + + [[nodiscard]] constexpr value_type value() const { return p_value; } + + constexpr value_type& value() { return p_value; } + + // properties + +protected: + + static value_type s_precision; + +public: + + static constexpr Scalar precision() { return s_precision; } + + static constexpr void precision(const value_type& precision) { s_precision = precision; } + + static constexpr Scalar inf() { return std::numeric_limits::infinity(); } + + static constexpr Scalar epsilon() { return std::numeric_limits::epsilon(); } +}; + +// specialization type + +#if defined(HPR_SCALAR_LONGDOUBLE) + using scalar = Scalar; +#elif defined(HPR_SCALAR_DOUBLE) + using scalar = Scalar; +#elif defined(HPR_SCALAR_FLOAT) + using scalar = Scalar; #else - -using scalar = float; - + using scalar = Scalar; #endif -static -const scalar small = std::numeric_limits::epsilon(); -static -const scalar great = static_cast(1.0) / small; -static -const scalar valueSmall = std::numeric_limits::min(); -static -const scalar valueGreat = std::numeric_limits::max() * 0.1; -static -const scalar NaN = std::numeric_limits::signaling_NaN(); +// +template<> scalar::value_type scalar::s_precision = static_cast(1e-15); +// global operators -//- Return 1 if s is positive or 0 otherwise -1 -inline -int sign(const scalar s) +/// scalar vs scalar + +constexpr scalar operator+(const scalar& s) { return s; } +constexpr scalar operator-(const scalar& s) { return -s.value(); } +constexpr bool operator!(const scalar& s) { return !static_cast(s.value()); } + +constexpr scalar& operator+=(scalar& lhs, const scalar& rhs) { lhs.value() += static_cast(rhs.value()); return lhs; } +constexpr scalar& operator-=(scalar& lhs, const scalar& rhs) { lhs.value() -= static_cast(rhs.value()); return lhs; } +constexpr scalar& operator*=(scalar& lhs, const scalar& rhs) { lhs.value() *= static_cast(rhs.value()); return lhs; } +constexpr scalar& operator/=(scalar& lhs, const scalar& rhs) { lhs.value() /= static_cast(rhs.value()); return lhs; } + +constexpr scalar operator+(const scalar& lhs, const scalar& rhs) { return lhs.value() + rhs.value(); } +constexpr scalar operator-(const scalar& lhs, const scalar& rhs) { return lhs.value() - rhs.value(); } +constexpr scalar operator*(const scalar& lhs, const scalar& rhs) { return lhs.value() * rhs.value(); } +constexpr scalar operator/(const scalar& lhs, const scalar& rhs) { return lhs.value() / rhs.value(); } + +constexpr bool operator==(const scalar& lhs, const scalar& rhs) { return lhs.value() == rhs.value(); } +constexpr bool operator!=(const scalar& lhs, const scalar& rhs) { return lhs.value() != rhs.value(); } +constexpr bool operator&&(const scalar& lhs, const scalar& rhs) { return static_cast(lhs) && static_cast(rhs); } +constexpr bool operator||(const scalar& lhs, const scalar& rhs) { return static_cast(lhs) || static_cast(rhs); } +constexpr bool operator>(const scalar& lhs, const scalar& rhs) { return lhs.value() > rhs.value(); } +constexpr bool operator<(const scalar& lhs, const scalar& rhs) { return lhs.value() < rhs.value(); } +constexpr bool operator>=(const scalar& lhs, const scalar& rhs) { return lhs.value() >= rhs.value(); } +constexpr bool operator<=(const scalar& lhs, const scalar& rhs) { return lhs.value() <= rhs.value(); } + +/// scalar vs Scalar + +template constexpr scalar& operator+=(scalar& lhs, const Scalar& rhs) { lhs.value() += static_cast(rhs.value()); return lhs; } +template constexpr scalar& operator-=(scalar& lhs, const Scalar& rhs) { lhs.value() -= static_cast(rhs.value()); return lhs; } +template constexpr scalar& operator*=(scalar& lhs, const Scalar& rhs) { lhs.value() *= static_cast(rhs.value()); return lhs; } +template constexpr scalar& operator/=(scalar& lhs, const Scalar& rhs) { lhs.value() /= static_cast(rhs.value()); return lhs; } + +template constexpr scalar operator+(const scalar& lhs, const Scalar& rhs) { return lhs.value() + static_cast(rhs.value()); } +template constexpr scalar operator+(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) + rhs.value(); } +template constexpr scalar operator-(const scalar& lhs, const Scalar& rhs) { return lhs.value() - static_cast(rhs.value()); } +template constexpr scalar operator-(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) - rhs.value(); } +template constexpr scalar operator*(const scalar& lhs, const Scalar& rhs) { return lhs.value() * static_cast(rhs.value()); } +template constexpr scalar operator*(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) * rhs.value(); } +template constexpr scalar operator/(const scalar& lhs, const Scalar& rhs) { return lhs.value() / static_cast(rhs.value()); } +template constexpr scalar operator/(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) / rhs.value(); } + +template constexpr bool operator==(const scalar& lhs, const Scalar& rhs) { return lhs.value() == static_cast(rhs.value()); } +template constexpr bool operator==(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) == rhs.value(); } +template constexpr bool operator!=(const scalar& lhs, const Scalar& rhs) { return lhs.value() != static_cast(rhs.value()); } +template constexpr bool operator!=(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) != rhs.value(); } +template constexpr bool operator&&(const scalar& lhs, const Scalar& rhs) { return static_cast(lhs) && static_cast(rhs); } +template constexpr bool operator&&(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs) && static_cast(rhs); } +template constexpr bool operator||(const scalar& lhs, const Scalar& rhs) { return static_cast(lhs) || static_cast(rhs); } +template constexpr bool operator||(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs) || static_cast(rhs); } +template constexpr bool operator>(const scalar& lhs, const Scalar& rhs) { return lhs.value() > static_cast(rhs.value()); } +template constexpr bool operator>(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) > rhs.value(); } +template constexpr bool operator<(const scalar& lhs, const Scalar& rhs) { return lhs.value() < static_cast(rhs.value()); } +template constexpr bool operator<(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) < rhs.value(); } +template constexpr bool operator>=(const scalar& lhs, const Scalar& rhs) { return lhs.value() >= static_cast(rhs.value()); } +template constexpr bool operator>=(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) >= rhs.value(); } +template constexpr bool operator<=(const scalar& lhs, const Scalar& rhs) { return lhs.value() <= static_cast(rhs.value()); } +template constexpr bool operator<=(const Scalar& lhs, const scalar& rhs) { return static_cast(lhs.value()) <= rhs.value(); } + +template std::ostream& operator<<(std::ostream& stream, const Scalar& s) { return stream << s.value(); } +template std::istream& operator>>(std::istream& stream, Scalar& s) { return stream >> s.value(); } + +/// scalar vs real + +template constexpr scalar& operator+=(scalar& lhs, const T& rhs) { lhs.value() += static_cast(rhs); return lhs; } +template constexpr scalar& operator-=(scalar& lhs, const T& rhs) { lhs.value() -= static_cast(rhs); return lhs; } +template constexpr scalar& operator*=(scalar& lhs, const T& rhs) { lhs.value() *= static_cast(rhs); return lhs; } +template constexpr scalar& operator/=(scalar& lhs, const T& rhs) { lhs.value() /= static_cast(rhs); return lhs; } + +template constexpr T& operator+=(T& lhs, const scalar& rhs) { lhs += static_cast(rhs); return lhs; } +template constexpr T& operator-=(T& lhs, const scalar& rhs) { lhs -= static_cast(rhs); return lhs; } +template constexpr T& operator*=(T& lhs, const scalar& rhs) { lhs *= static_cast(rhs); return lhs; } +template constexpr T& operator/=(T& lhs, const scalar& rhs) { lhs /= static_cast(rhs); return lhs; } + +template constexpr scalar operator+(const scalar& lhs, const T& rhs) { return lhs.value() + static_cast(rhs); } +template constexpr scalar operator+(const T& lhs, const scalar& rhs) { return static_cast(lhs) + rhs.value(); } +template constexpr scalar operator-(const scalar& lhs, const T& rhs) { return lhs.value() - static_cast(rhs); } +template constexpr scalar operator-(const T& lhs, const scalar& rhs) { return static_cast(lhs) - rhs.value(); } +template constexpr scalar operator*(const scalar& lhs, const T& rhs) { return lhs.value() * static_cast(rhs); } +template constexpr scalar operator*(const T& lhs, const scalar& rhs) { return static_cast(lhs) * rhs.value(); } +template constexpr scalar operator/(const scalar& lhs, const T& rhs) { return lhs.value() / static_cast(rhs); } +template constexpr scalar operator/(const T& lhs, const scalar& rhs) { return static_cast(lhs) / rhs.value(); } + +template constexpr bool operator==(const scalar& lhs, const T& rhs) { return lhs.value() == static_cast(rhs); } +template constexpr bool operator==(const T& lhs, const scalar& rhs) { return static_cast(lhs) == rhs.value(); } +template constexpr bool operator!=(const scalar& lhs, const T& rhs) { return lhs.value() != static_cast(rhs); } +template constexpr bool operator!=(const T& lhs, const scalar& rhs) { return static_cast(lhs) != rhs.value(); } +template constexpr bool operator&&(const scalar& lhs, const T& rhs) { return static_cast(lhs) && static_cast(rhs); } +template constexpr bool operator&&(const T& lhs, const scalar& rhs) { return static_cast(lhs) && static_cast(rhs); } +template constexpr bool operator||(const scalar& lhs, const T& rhs) { return static_cast(lhs) || static_cast(rhs); } +template constexpr bool operator||(const T& lhs, const scalar& rhs) { return static_cast(lhs) || static_cast(rhs); } +template constexpr bool operator>(const scalar& lhs, const T& rhs) { return lhs.value() > static_cast(rhs); } +template constexpr bool operator>(const T& lhs, const scalar& rhs) { return static_cast(lhs) > rhs.value(); } +template constexpr bool operator<(const scalar& lhs, const T& rhs) { return lhs.value() < static_cast(rhs); } +template constexpr bool operator<(const T& lhs, const scalar& rhs) { return static_cast(lhs) < rhs.value(); } +template constexpr bool operator>=(const scalar& lhs, const T& rhs) { return lhs.value() >= static_cast(rhs); } +template constexpr bool operator>=(const T& lhs, const scalar& rhs) { return static_cast(lhs) >= rhs.value(); } +template constexpr bool operator<=(const scalar& lhs, const T& rhs) { return lhs.value() <= static_cast(rhs); } +template constexpr bool operator<=(const T& lhs, const scalar& rhs) { return static_cast(lhs) <= rhs.value(); } + +// transcendentals + +template constexpr scalar cos(const T& s) { return std::cos(static_cast(s));} + +template constexpr scalar acos(const T& s) { return std::acos(scalar(s).value()); } + +template constexpr scalar cosh(const T& s) { return std::cosh(scalar(s).value()); } + +template constexpr scalar acosh(const T& s) { return std::acosh(scalar(s).value()); } + +template constexpr scalar sin(const T& s) { return std::sin(scalar(s).value()); } + +template constexpr scalar asin(const T& s) { return std::asin(scalar(s).value()); } + +template constexpr scalar sinh(const T& s) { return std::sinh(scalar(s).value()); } + +template constexpr scalar asinh(const T& s) { return std::asinh(scalar(s).value()); } + +template constexpr scalar tan(const T& s) { return std::tan(scalar(s).value()); } + +template constexpr scalar atan(const T& s) { return std::atan(scalar(s).value()); } + +template constexpr scalar tanh(const T& s) { return std::tanh(scalar(s).value()); } + +template constexpr scalar atanh(const T& s) { return std::atanh(scalar(s).value()); } + +template constexpr scalar exp(const T& s) { return std::exp(scalar(s).value()); } + +template constexpr scalar log(const T& s) { return std::log(scalar(s).value()); } + +template constexpr scalar log10(const T& s) { return std::log10(scalar(s).value()); } + +template constexpr scalar pow(const T& s, const X& d) { return std::pow(scalar(s).value(), scalar(d).value()); } + +template constexpr scalar sqrt(const T& s) { return std::sqrt(scalar(s).value()); } + +template constexpr scalar isqrt(const T& s) { return static_cast(1) / sqrt(scalar(s).value()); } + +// constants + +constexpr inline scalar pi() { return std::numbers::pi_v; } + +constexpr inline scalar e() { return std::numbers::e_v; } + +// etc + +constexpr scalar abs(const scalar& s) { return std::abs(s.value()); } + +constexpr scalar mag(const scalar& s) { return std::abs(s.value()); } + +constexpr bool equal(const scalar& lhs, const scalar& rhs, const scalar& precision = scalar::precision()) { return abs(lhs - rhs) < precision; } + +//! Convert degrees to radians +constexpr scalar rad(const scalar& s) { return s * pi() / static_cast(180); } + +//! Convert radians to degrees +constexpr scalar deg(const scalar& s) { return s * static_cast(180) / pi(); } + +constexpr scalar min(const scalar& s1, const scalar& s2) { return std::min(s1.value(),s2.value());} + +constexpr scalar max(const scalar& s1, const scalar& s2) { return std::max(s1.value(), s2.value()); } + +constexpr scalar clip(const scalar& s, const scalar& sMin, const scalar& sMax) { return min(sMax, max(s, sMin)); } + +} + +/*namespace std { - return (s >= 0) ? 1: -1; -} + // compatibility with std -inline -scalar mag(const scalar s) -{ - return std::fabs(s); -} - -template -inline -bool equal(Type lhs, Type rhs, Type precision = 1e-5) -{ - return mag(lhs - rhs) < precision; -} - -inline -scalar clip(scalar value, scalar valueMin, scalar valueMax) -{ - return std::min(valueMax, std::max(value, valueMin)); -} - -template -Type inversesqrt( Type n ) -{ - return static_cast(1) / sqrt(n); -} - -// trigonometric - -static -const scalar PI = static_cast(M_PIl); - -template -inline -Type radians(Type degrees) -{ - static_assert(std::numeric_limits::is_iec559); - return degrees * PI / static_cast(180); -} - -template -inline -Type degrees(Type radians) -{ - static_assert(std::numeric_limits::is_iec559); - return radians * static_cast(180) / PI; -} - -} + template constexpr hpr::Scalar cos(const hpr::Scalar& s) { return hpr::cos(s); } + template constexpr hpr::Scalar acos(const hpr::Scalar& s) { return hpr::acos(s); } + template constexpr hpr::Scalar cosh(const hpr::Scalar& s) { return hpr::cosh(s); } + template constexpr hpr::Scalar acosh(const hpr::Scalar& s) { return hpr::acosh(s); } + template constexpr hpr::Scalar sin(const hpr::Scalar& s) { return hpr::sin(s); } + template constexpr hpr::Scalar asin(const hpr::Scalar& s) { return hpr::asin(s); } + template constexpr hpr::Scalar sinh(const hpr::Scalar& s) { return hpr::sinh(s); } + template constexpr hpr::Scalar asinh(const hpr::Scalar& s) { return hpr::asinh(s); } + template constexpr hpr::Scalar tan(const hpr::Scalar& s) { return hpr::tan(s); } + template constexpr hpr::Scalar atan(const hpr::Scalar& s) { return hpr::atan(s); } + template constexpr hpr::Scalar tanh(const hpr::Scalar& s) { return hpr::tanh(s); } + template constexpr hpr::Scalar atanh(const hpr::Scalar& s) { return hpr::atanh(s); } + template constexpr hpr::Scalar exp(const hpr::Scalar& s) { return hpr::exp(s); } + template constexpr hpr::Scalar log(const hpr::Scalar& s) { return hpr::log(s); } + template constexpr hpr::Scalar log10(const hpr::Scalar& s) { return hpr::log10(s); } + template constexpr hpr::Scalar sqrt(const hpr::Scalar& s) { return hpr::sqrt(s); } + template constexpr hpr::Scalar abs(const hpr::Scalar& s) { return hpr::abs(s); } + template constexpr hpr::Scalar pow(const hpr::Scalar& s, const hpr::Scalar& d) { return hpr::pow(s, d); } + template constexpr hpr::Scalar pow(const hpr::Scalar& s, const X& d) { return hpr::pow(s, d); } + template constexpr hpr::Scalar pow(const T& s, const hpr::Scalar& d) { return hpr::pow(s, d); } +}*/ diff --git a/source/hpr/math/tests/math-test.cpp b/source/hpr/math/tests/math-test.cpp index f9a9aac..26e8df8 100644 --- a/source/hpr/math/tests/math-test.cpp +++ b/source/hpr/math/tests/math-test.cpp @@ -2,14 +2,46 @@ #include "../vector.hpp" #include "../matrix.hpp" +#include "../quaternion.hpp" +#include +TEST(math, Scalar) +{ + EXPECT_EQ(hpr::scalar(5) + hpr::scalar(7), hpr::scalar(12)); + EXPECT_TRUE(std::is_floating_point_v>); + EXPECT_TRUE(std::is_arithmetic_v>); + EXPECT_EQ(5.f, hpr::Scalar(5)); + EXPECT_EQ(hpr::rad(180), hpr::pi()); + EXPECT_EQ(hpr::deg(hpr::pi()), 180); + EXPECT_EQ(hpr::cos(0), 1); + EXPECT_EQ(hpr::sin(0), 0); + EXPECT_EQ(hpr::abs(hpr::scalar(-1)), 1); + EXPECT_EQ(hpr::pow(2, 2), 4); + + EXPECT_TRUE(typeid(static_cast(hpr::scalar(5))) == typeid(float)); + EXPECT_FALSE(!hpr::scalar(-1.)); + + std::stringstream oss; + oss << hpr::cos(0); + EXPECT_EQ(oss.str(), "1"); + hpr::scalar s; + oss >> s; + EXPECT_EQ(s, 1); + + EXPECT_TRUE(hpr::equal(5.5453535353535395818593, 5.5453535353535395817592, 1e-18)); + EXPECT_EQ(hpr::min(7., 5), 5); + EXPECT_EQ(hpr::max(7., 5), 7); + EXPECT_EQ(hpr::clip(7., 5, 10), 7); + EXPECT_EQ(hpr::clip(1., 5, 10), 5); + EXPECT_EQ(hpr::clip(72., 5, 10), 10); +} TEST(math, Vector) { hpr::vec3 v1 {1, 3, 2}; hpr::vec3 v2 {5, 7, -1}; hpr::vec2 v31 {13, -2}; - hpr::vec3 v32 {v31, 9}; + hpr::vec3 v32 (v31, 9); EXPECT_EQ((hpr::vec3(v2.begin(), v2.end())), v2); EXPECT_EQ(v32, hpr::vec3(13, -2, 9)); EXPECT_EQ(-v1, hpr::vec3(-1, -3, -2)); @@ -17,7 +49,7 @@ TEST(math, Vector) EXPECT_EQ(v1 - v2, hpr::vec3(-4, -4, 3)); EXPECT_EQ((hpr::dot(v1, v2) ), 24); EXPECT_EQ((hpr::cross(hpr::vec3(1, 0, 0), hpr::vec3(0, 1, 0))), hpr::vec3(0, 0, 1)); - EXPECT_EQ((hpr::angle(hpr::vec3(1, 0, 0), hpr::vec3(0, 0, 1))), hpr::PI * 0.5); + EXPECT_EQ((hpr::angle(hpr::vec3(1, 0, 0), hpr::vec3(0, 0, 1))), hpr::pi() * 0.5); EXPECT_EQ((hpr::normalize(hpr::vec3(1, 1, 1))), hpr::vec3(0.5773502691896258, 0.5773502691896258, 0.5773502691896258)); } @@ -26,6 +58,7 @@ TEST(math, Matrix) hpr::mat2 m1; hpr::vec4 v1; EXPECT_FALSE(v1 == m1); + EXPECT_FALSE(m1 == v1); hpr::mat2 m2 {3, 2, 7, 4}; hpr::vec2 v2 {2, 4}; EXPECT_EQ(m2.col(1), v2); @@ -34,14 +67,24 @@ TEST(math, Matrix) EXPECT_EQ(m2.col(1), v3); hpr::mat3 m4 {1, 2, 3, 4, 5, 6, 7, 8, 9}; hpr::mat2 m41 {5, 6, 8, 9}; - EXPECT_EQ(m41.minor(0, 0), 9); + //EXPECT_EQ(minor(m41, 0, 0), 9); hpr::mat2 m5 {1, 2, 3, 4}; - EXPECT_EQ((m4.det()), 0); - EXPECT_EQ(hpr::mat3(-9, 23, 3, 5, 5, 6, 7, -3, 9).det(), -786); + EXPECT_EQ(det(m4), 0); + EXPECT_EQ(hpr::det(m4), 0); + EXPECT_EQ(det(hpr::mat3(-9, 23, 3, 5, 5, 6, 7, -3, 9)), -786); hpr::mat2 m6 {2, 1, 7, 4}; - EXPECT_EQ(m6.inv(), hpr::mat2(4, -1, -7, 2)); - EXPECT_EQ(hpr::mat3(1, 0, 0, 0, 1, 0, 0, 0, 1).det(), 1.); + EXPECT_EQ(det(m6), 1); + EXPECT_EQ(adj(m6), hpr::mat2(4, -1, -7, 2)); + EXPECT_EQ(inv(m6), hpr::mat2(4, -1, -7, 2)); + EXPECT_EQ(det(hpr::mat3(1, 0, 0, 0, 1, 0, 0, 0, 1)), 1.); //EXPECT_EQ(m4.det(), 0); +} + +TEST(math, Quaternion) +{ + hpr::quat q; + hpr::vec3 np = hpr::rotate(hpr::vec3(0, 1, 0), {1, 0, 0}, hpr::pi() * 0.5); + EXPECT_TRUE(hpr::all(hpr::equal(np, hpr::vec3(0, 0, 1)))); } \ No newline at end of file diff --git a/source/hpr/math/vector/vector_space.hpp b/source/hpr/math/vector/vector_space.hpp index 218624b..fe37183 100644 --- a/source/hpr/math/vector/vector_space.hpp +++ b/source/hpr/math/vector/vector_space.hpp @@ -1,5 +1,6 @@ #pragma once +#include "../integer.hpp" #include "../scalar.hpp" #include "../../containers/array/static_array.hpp" @@ -7,18 +8,42 @@ namespace hpr { -template -class VectorSpace : public StaticArray +// forward declarations + +template requires (S >= 0) +class Vector; + +template +using SubVector = typename std::conditional= 2, Vector, Vector>::type; + +// type traits + +template +struct is_vector : public std::false_type {}; + +template +struct is_vector> : public std::true_type {}; + +// concepts + +template +concept IsVector = is_vector::value; + +} + +namespace hpr { - static_assert(std::is_arithmetic::value, "Type must be numeric"); - using base = StaticArray; +template requires (S >= 0) +class Vector : public StaticArray +{ + + using base = StaticArray; - using SubVector = typename std::conditional= 2, VectorSpace, VectorSpace>::type; public: using value_type = Type; - using size_type = size_t; + using size_type = Size; using pointer = Type*; using reference = Type&; using iterator = Iterator; @@ -26,361 +51,156 @@ public: public: - inline - VectorSpace() : + //! null constructor + constexpr + Vector() : base {} {} - inline - VectorSpace(const VectorSpace& vs) : + //! copy constructor + constexpr + Vector(const Vector& vs) : base {static_cast(vs)} {} - inline - VectorSpace(VectorSpace&& vs) noexcept : + //! move constructor + constexpr + Vector(Vector&& vs) noexcept : base {std::forward(static_cast(vs))} {} - inline - VectorSpace& operator=(const VectorSpace& vs) + //! copy assignment operator + constexpr + Vector& operator=(const Vector& vs) { base::operator=(vs); return *this; } - inline - VectorSpace& operator=(VectorSpace&& vs) noexcept + //! move assignment operator + constexpr + Vector& operator=(Vector&& vs) noexcept { - swap(*this, vs);//std::forward(static_cast(*this)), std::forward(static_cast(vs))); - //std::swap(*this, vs); + swap(*this, vs); return *this; } + //! destructor virtual - ~VectorSpace() = default; + ~Vector() = default; - inline - VectorSpace(typename base::iterator start, typename base::iterator end) : + //! copy constructor from base + constexpr + Vector(const base& arr) : + base {arr} + {} + + //! move constructor from base + constexpr + Vector(base&& arr) : + base {std::forward(arr)} + {} + + //! construct from iterators + constexpr + Vector(typename base::iterator start, typename base::iterator end) : base {start, end} {} - inline - VectorSpace(typename base::const_iterator start, typename base::const_iterator end) : + //! construct from constant iterators + constexpr + Vector(typename base::const_iterator start, typename base::const_iterator end) : base {start, end} {} - inline - VectorSpace(std::initializer_list list) : + //! construct from initializer list + constexpr + Vector(std::initializer_list list) : base {list} {} - template ... Args> - inline - VectorSpace(const value_type& v, const Args& ...args) : + //! copy constructor with variadic args + template + constexpr + Vector(const value_type& v, const Args& ...args) requires (S == 1 + sizeof...(args)): base {v, static_cast(args)...} - { - static_assert(1 + sizeof...(args) == Size, "Number of arguments must be equal to size of vector"); - } + {} - template ... Args> - inline - VectorSpace(value_type&& v, Args&& ...args) : + //! move constructor with variadic args + template + constexpr + Vector(value_type&& v, Args&& ...args) requires (S == 1 + sizeof...(args)): base {v, static_cast(std::forward(args))...} - { - static_assert(1 + sizeof...(args) == Size, "Number of arguments must be equal to size of vector"); - } + {} - /*template ... Args> - inline - VectorSpace(const VectorSpace& subvec, const value_type& v, const Args& ...args) : - base {static_cast>(subvec), v, - static_cast(std::forward(args))...} - {}*/ - - inline - VectorSpace(const SubVector& subvs, const value_type& v) : + //! copy constructor with sub vector and value + constexpr + Vector(const SubVector& svs, const value_type& v) requires (S >= 1): base {} { - for (auto n = 0; n < subvs.size(); ++n) - (*this)[n] = subvs[n]; - (*this)[subvs.size()] = v; - } - - template - inline - VectorSpace(const VectorSpace& vs) : - base {vs.begin(), vs.begin() + Size} - { - static_assert(BiggerSize > Size, "Size should be bigger"); - } - - // Member functions - - // vector versus scalar (per element operations) - - friend inline - VectorSpace operator-(const VectorSpace& rhs) - { - VectorSpace vs {rhs}; - for (value_type& v : vs) - v = -v; - return vs; - } - - inline - void operator*=(const value_type& val) - { - //for (value_type& v : *this) - // v *= val; - for (auto n = 0; n < Size; ++n) - (*this)[n] *= val; - } - - inline - void operator+=(const value_type& val) - { - for (auto n = 0; n < Size; ++n) - (*this)[n] += val; - } - - inline - void operator-=(const value_type& val) - { - //for (value_type& v : *this) - // v -= val; - for (auto n = 0; n < Size; ++n) - (*this)[n] -= val; - } - - inline - void operator/=(const value_type& val) - { - for (value_type& v : *this) - v /= val; - } - - friend inline - VectorSpace operator+(const VectorSpace& lhs, const value_type& rhs) - { - VectorSpace vs {lhs}; - vs += rhs; - return vs; - } - - friend inline - VectorSpace operator+(const value_type& lhs, const VectorSpace& rhs) - { - return operator+(rhs, lhs); - } - - friend inline - VectorSpace operator*(const VectorSpace& lhs, const value_type& rhs) - { - VectorSpace vs {lhs}; - vs *= rhs; - return vs; - } - - friend inline - VectorSpace operator*(const value_type& lhs, const VectorSpace& rhs) - { - return operator*(rhs, lhs); - } - - friend inline - VectorSpace operator/(const VectorSpace& lhs, const value_type& rhs) - { - VectorSpace vs {lhs}; - vs /= rhs; - return vs; - } - - friend inline - VectorSpace operator/(const value_type& lhs, const VectorSpace& rhs) - { - VectorSpace vs; - for (auto n = 0; n < vs.size(); ++n) - vs[n] = lhs / rhs[n]; - return vs; - } - - // vector versus vector (per element operations) - - inline - void operator*=(const VectorSpace& vs) - { - for (auto n = 0; n < Size; ++n) - (*this)[n] *= vs[n]; - } - - inline - void operator+=(const VectorSpace& vs) - { - for (auto n = 0; n < Size; ++n) - (*this)[n] += vs[n]; - } - - inline - void operator-=(const VectorSpace& vs) - { - for (auto n = 0; n < Size; ++n) - (*this)[n] -= vs[n]; - } - - inline - void operator/=(const VectorSpace& vs) - { - for (auto n = 0; n < Size; ++n) - (*this)[n] /= vs[n]; - } - - friend inline - VectorSpace operator+(const VectorSpace& lhs, const VectorSpace& rhs) - { - VectorSpace vs {lhs}; - vs += rhs; - return vs; - } - - friend inline - VectorSpace operator-(const VectorSpace& lhs, const VectorSpace& rhs) - { - VectorSpace vs {lhs}; - vs -= rhs; - return vs; - } - - friend inline - VectorSpace operator*(const VectorSpace& lhs, const VectorSpace& rhs) - { - VectorSpace vs {lhs}; - vs *= rhs; - return vs; - } - - friend inline - VectorSpace operator/(const VectorSpace& lhs, const VectorSpace& rhs) - { - VectorSpace vs {lhs}; - vs /= rhs; - return vs; - } - - friend inline - bool operator==(const VectorSpace& lhs, const VectorSpace& rhs) - { - for (auto n = 0; n < Size; ++n) - if (lhs[n] != rhs[n]) - return false; - return true; - } - - friend inline - bool operator!=(const VectorSpace& lhs, const VectorSpace& rhs) - { - return !(lhs == rhs); + for (auto n = 0; n < svs.size(); ++n) + (*this)[n] = svs[n]; + (*this)[svs.size()] = v; } + //! copy constructor from greater vector + template requires (GS > S) + constexpr explicit + Vector(const Vector& vs) : + base {vs.begin(), vs.begin() + S} + {} }; -template +// global operators + +template inline Vector operator+(const Vector& lhs) { Vector vs; for (Size n = 0; n < S; ++n) vs[n] = lhs[n]; return vs; } +template inline Vector operator-(const Vector& lhs) { Vector vs; for (Size n = 0; n < S; ++n) vs[n] = -lhs[n]; return vs; } + +template inline Vector& operator+=(Vector& lhs, const Vector& rhs) { for (Size n = 0; n < S; ++n) lhs[n] += rhs[n]; return lhs; } +template inline Vector& operator-=(Vector& lhs, const Vector& rhs) { for (Size n = 0; n < S; ++n) lhs[n] -= rhs[n]; return lhs; } +template inline Vector& operator*=(Vector& lhs, const Vector& rhs) { for (Size n = 0; n < S; ++n) lhs[n] *= rhs[n]; return lhs; } +template inline Vector& operator/=(Vector& lhs, const Vector& rhs) { for (Size n = 0; n < S; ++n) lhs[n] /= rhs[n]; return lhs; } + +template inline Vector operator+(const Vector& lhs, const Vector& rhs) { Vector vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] += rhs[n]; return vs; } +template inline Vector operator-(const Vector& lhs, const Vector& rhs) { Vector vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] -= rhs[n]; return vs; } +template inline Vector operator*(const Vector& lhs, const Vector& rhs) { Vector vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] *= rhs[n]; return vs; } +template inline Vector operator/(const Vector& lhs, const Vector& rhs) { Vector vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] /= rhs[n]; return vs; } + +template inline bool operator==(const Vector& lhs, const Vector& rhs) { for (Size n = 0; n < S; ++n) if (lhs[n] != rhs[n]) return false; return true; } +template inline bool operator!=(const Vector& lhs, const Vector& rhs) { for (Size n = 0; n < S; ++n) if (lhs[n] == rhs[n]) return false; return true; } + + +template inline Vector& operator+=(Vector& lhs, const T& rhs) { for (Size n = 0; n < S; ++n) lhs[n] += rhs; return lhs; } +template inline Vector& operator-=(Vector& lhs, const T& rhs) { for (Size n = 0; n < S; ++n) lhs[n] -= rhs; return lhs; } +template inline Vector& operator*=(Vector& lhs, const T& rhs) { for (Size n = 0; n < S; ++n) lhs[n] *= rhs; return lhs; } +template inline Vector& operator/=(Vector& lhs, const T& rhs) { for (Size n = 0; n < S; ++n) lhs[n] /= rhs; return lhs; } + +template inline Vector operator+(const Vector& lhs, const T& rhs) { Vector vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] += rhs; return vs; } +template inline Vector operator-(const Vector& lhs, const T& rhs) { Vector vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] -= rhs; return vs; } +template inline Vector operator*(const Vector& lhs, const T& rhs) { Vector vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] *= rhs; return vs; } +template inline Vector operator/(const Vector& lhs, const T& rhs) { Vector vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] /= rhs; return vs; } + +template inline Vector operator+(const T& lhs, const Vector& rhs) { Vector vs {rhs}; for (Size n = 0; n < S; ++n) vs[n] += lhs; return vs; } +template inline Vector operator-(const T& lhs, const Vector& rhs) { Vector vs {rhs}; for (Size n = 0; n < S; ++n) vs[n] -= lhs; return vs; } +template inline Vector operator*(const T& lhs, const Vector& rhs) { Vector vs {rhs}; for (Size n = 0; n < S; ++n) vs[n] *= lhs; return vs; } +template inline Vector operator/(const T& lhs, const Vector& rhs) { Vector vs {rhs}; for (Size n = 0; n < S; ++n) vs[n] /= lhs; return vs; } + +// boolean operations + +template inline -VectorSpace equal(const VectorSpace& lhs, const VectorSpace& rhs, scalar precision = 1e-5) +Vector equal(const Vector& lhs, const Vector& rhs, const scalar& precision = scalar::precision()) { - VectorSpace res; - for (auto n = 0; n < Size; ++n) - res[n] = equal(lhs[n], rhs[n], precision); - return res; + Vector vs; + for (auto n = 0; n < S; ++n) + vs[n] = equal(lhs[n], rhs[n], precision); + return vs; } -template +template inline -Type sum(const VectorSpace& vs) -{ - Type sum {}; - for (const Type& v : vs) - sum += v; - return sum; -} - -template -constexpr -Type dot(const VectorSpace& lhs, const VectorSpace& rhs) -{ - return sum(lhs * rhs); -} - -template -inline -Type length(const VectorSpace& vs) -{ - return sqrt(dot(vs, vs)); -} - -template -inline -Type distance(const VectorSpace& point1, const VectorSpace& point2) -{ - return length(point1 - point2); -} - -template -constexpr -VectorSpace cross(const VectorSpace& lhs, const VectorSpace& rhs) -{ - return VectorSpace( - lhs[1] * rhs[2] - lhs[2] * rhs[1], - lhs[2] * rhs[0] - lhs[0] * rhs[2], - lhs[0] * rhs[1] - lhs[1] * rhs[0] - ); -} - -template -constexpr -VectorSpace pow(const VectorSpace& vs, scalar degree) -{ - VectorSpace res; - for (auto n = 0; n < Size; ++n) - res[n] = std::pow(vs[n], degree); - return res; -} - -template -constexpr -VectorSpace abs(const VectorSpace& vs) -{ - VectorSpace res; - for (auto n = 0; n < Size; ++n) - res[n] = std::abs(vs[n]); - return res; -} - -template -constexpr -Type norm(const VectorSpace& vs) -{ - return sqrt(sum(pow(abs(vs), 2))); -} - -template -constexpr -Type angle(const VectorSpace& lhs, const VectorSpace& rhs) -{ - scalar cos = dot(lhs, rhs) / (norm(lhs) * norm(rhs)); - return acos(cos); //clip(cos, -1., 1.)); -} - -template -inline -VectorSpace normalize(const VectorSpace& vs) -{ - return vs * inversesqrt(dot(vs, vs)); -} - -template -constexpr -bool any(const VectorSpace& vs) +bool any(const Vector& vs) { bool res = false; for (auto e : vs) @@ -388,9 +208,9 @@ bool any(const VectorSpace& vs) return res; } -template -constexpr -bool all(const VectorSpace& vs) +template +inline +bool all(const Vector& vs) { bool res = true; for (auto e : vs) @@ -398,13 +218,111 @@ bool all(const VectorSpace& vs) return res; } -// Aliases +// per element operations -template -using vec = VectorSpace; +template +inline +Vector abs(const Vector& vs) +{ + Vector res; + for (auto n = 0; n < S; ++n) + res[n] = abs(vs[n]); + return res; +} -using vec2 = VectorSpace; -using vec3 = VectorSpace; -using vec4 = VectorSpace; +template +inline +Type sum(const Vector& vs) +{ + Type sum {}; + for (const Type& v : vs) + sum += v; + return sum; +} + +template +inline +Vector pow(const Vector& vs, scalar degree) +{ + Vector res; + for (auto n = 0; n < S; ++n) + res[n] = pow(vs[n], degree); + return res; +} + +// vector operations + +template +inline +Type norm(const Vector& vs) +{ + return sqrt(sum(pow(abs(vs), 2))); +} + +template +inline +Type dot(const Vector& lhs, const Vector& rhs) +{ + return sum(lhs * rhs); +} + +template +inline +Type length(const Vector& vs) +{ + return sqrt(dot(vs, vs)); +} + +template +inline +Type mag(const Vector& vs) +{ + return length(vs); +} + +template +inline +Type distance(const Vector& vs1, const Vector& vs2) +{ + return length(vs1 - vs2); +} + +template +inline +Vector normalize(const Vector& vs) +{ + return vs * isqrt(dot(vs, vs)); +} + +template +inline +Type angle(const Vector& lhs, const Vector& rhs) +{ + scalar cos = dot(lhs, rhs) / (norm(lhs) * norm(rhs)); + return acos(cos); //clip(cos, -1., 1.)); +} + +// vector 3 operations + +template +inline +Vector cross(const Vector& lhs, const Vector& rhs) +{ + return Vector( + lhs[1] * rhs[2] - lhs[2] * rhs[1], + lhs[2] * rhs[0] - lhs[0] * rhs[2], + lhs[0] * rhs[1] - lhs[1] * rhs[0] + ); +} + + +// aliases + +template +using vec = Vector; + +using vec2 = Vector; +using vec3 = Vector; +using vec4 = Vector; }