diff --git a/CMakeLists.txt b/CMakeLists.txt index b5c2d44..6761fa8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.15) project(aorii) -set(CMAKE_CXX_STANDARD 23) +set(CMAKE_CXX_STANDARD 26) include(cmake/retrieve_files.cmake) include(cmake/detect_os.cmake) diff --git a/src/renderer/backend/dx/dx_buffer.h b/src/renderer/backend/dx/dx_buffer.h index 81f742e..eca02fa 100644 --- a/src/renderer/backend/dx/dx_buffer.h +++ b/src/renderer/backend/dx/dx_buffer.h @@ -7,7 +7,7 @@ class dx_buffer : public renderer_buffer { public: - explicit dx_buffer(buffer_type in_type, int in_element_byte, int in_size): renderer_buffer(in_type, in_element_byte, in_size) { + explicit dx_buffer(buffer_type in_type, int32_t in_element_byte, int32_t in_size): renderer_buffer(in_type, in_element_byte, in_size) { const auto d3d_device = aorii::get_renderer<dx_renderer>()->get_d3d_device(); D3D11_BUFFER_DESC buffer_desc = {}; @@ -50,7 +50,7 @@ public: return buffer; } protected: - void on_resize(int new_count) override { + void on_resize(int32_t new_count) override { const auto d3d_device = aorii::get_renderer<dx_renderer>()->get_d3d_device(); const auto d3d_context = aorii::get_renderer<dx_renderer>()->get_d3d_context(); // 获取原始缓冲区的描述 diff --git a/src/renderer/backend/dx/dx_renderer.cpp b/src/renderer/backend/dx/dx_renderer.cpp index 9e64088..85a9b6e 100644 --- a/src/renderer/backend/dx/dx_renderer.cpp +++ b/src/renderer/backend/dx/dx_renderer.cpp @@ -83,13 +83,13 @@ Eigen::Matrix4f dx_renderer::make_projection_matrix(const Eigen::Vector2i& size) return matrix; } -std::vector<char> dx_renderer::load_shader(const std::string& shader_name) { +std::vector<int8_t> dx_renderer::load_shader(const std::string& shader_name) { auto file_pathname = aorii::get_shader_path(shader_name).generic_string() + ".dxbc"; std::ifstream file(file_pathname, std::ios::binary); return { (std::istreambuf_iterator(file)), std::istreambuf_iterator<char>() }; } -renderer_buffer* dx_renderer::create_buffer(buffer_type in_buffer_type, int in_element_byte, int in_size) { +renderer_buffer* dx_renderer::create_buffer(buffer_type in_buffer_type, int32_t in_element_byte, int32_t in_size) { return new dx_buffer(in_buffer_type, in_element_byte, in_size); } diff --git a/src/renderer/backend/dx/dx_renderer.h b/src/renderer/backend/dx/dx_renderer.h index 4e84ea0..5063986 100644 --- a/src/renderer/backend/dx/dx_renderer.h +++ b/src/renderer/backend/dx/dx_renderer.h @@ -29,9 +29,9 @@ public: [[nodiscard]] ID3D11BlendState* get_blend_state() const { return blend_state; } - std::vector<char> load_shader(const std::string& shader_name) override; + std::vector<int8_t> load_shader(const std::string& shader_name) override; - renderer_buffer* create_buffer(buffer_type in_buffer_type, int in_element_byte, int in_size) override; + renderer_buffer* create_buffer(buffer_type in_buffer_type, int32_t in_element_byte, int32_t in_size) override; private: renderer_window* create_window() override; diff --git a/src/renderer/backend/dx/dx_window.cpp b/src/renderer/backend/dx/dx_window.cpp index fa2c7d3..dd8f2c6 100644 --- a/src/renderer/backend/dx/dx_window.cpp +++ b/src/renderer/backend/dx/dx_window.cpp @@ -51,7 +51,7 @@ bool dx_window::create_surface(GLFWwindow* in_window) { sd.SampleDesc.Quality = 0; sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; sd.BufferCount = 2; - sd.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; + sd.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; sd.Flags = 0; const auto hwnd = static_cast<HWND>(get_window_handle()); @@ -88,8 +88,8 @@ void dx_window::begin_frame() { context.draw_rectangle({ 400, 0 }, { 100, 100 }, { 0, 1, 0, 1 }); auto radius = abs(sin(get_total_time().count())) * 50; - auto angle = sin(get_total_time().count() * 0.001) * 45; - context.draw_rounded_rectangle({ 100, 100 }, { 200, 400 }, { 1, 0, 0, 1 }, angle, 10); + auto angle = sin(get_total_time().count()) * 45; + context.draw_rounded_rectangle({ 500, 500 }, { 100, 400 }, { 1, 0, 0, 1 }, 10, {10, 20, 30, 40}); double mouse_x, mouse_y; glfwGetCursorPos(get_glfw_window(), &mouse_x, &mouse_y); diff --git a/src/renderer/core/pipeline/pipeline.h b/src/renderer/core/pipeline/pipeline.h index 07329a1..492ad9b 100644 --- a/src/renderer/core/pipeline/pipeline.h +++ b/src/renderer/core/pipeline/pipeline.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include <span> #include <string> #include <Eigen/Eigen> diff --git a/src/renderer/core/pipeline/rounded_rect_pipeline.h b/src/renderer/core/pipeline/rounded_rect_pipeline.h index b4f481d..722d3aa 100644 --- a/src/renderer/core/pipeline/rounded_rect_pipeline.h +++ b/src/renderer/core/pipeline/rounded_rect_pipeline.h @@ -5,10 +5,9 @@ class rounded_rect_pipeline : public pipeline { public: struct param { Eigen::Matrix4f projection_matrix; - Eigen::Vector2f p1; - Eigen::Vector2f p2; - float radius; - float thickness; + Eigen::Vector2f size; + Eigen::Vector2f pos; + Eigen::Vector4f radius; // 左上, 右上, 左下, 右下 }; bool init() override; diff --git a/src/renderer/core/renderer/renderer.h b/src/renderer/core/renderer/renderer.h index 3d8a346..44c4021 100644 --- a/src/renderer/core/renderer/renderer.h +++ b/src/renderer/core/renderer/renderer.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include <chrono> #include <Eigen/Eigen> #include <filesystem> @@ -228,15 +228,15 @@ public: * @param shader_name 着色器文件名称, 不需要路径和后缀, 会使用aorii::get_shader_path获取路径, 在不同的图形API下会自动添加后缀 * @return 着色器代码 */ - virtual std::vector<char> load_shader(const std::string& shader_name) = 0; + virtual std::vector<int8_t> load_shader(const std::string& shader_name) = 0; - renderer_buffer* create_vertex_buffer(const int in_size = 4) { + renderer_buffer* create_vertex_buffer(const int32_t in_size = 4) { return create_buffer(buffer_type::vertex, sizeof(aorii_vertex), in_size); } - renderer_buffer* create_index_buffer(const int in_size = 2) { + renderer_buffer* create_index_buffer(const int32_t in_size = 2) { return create_buffer(buffer_type::index, sizeof(aorii_triangle), in_size); } - virtual renderer_buffer* create_buffer(buffer_type in_buffer_type, int in_element_byte, int in_element_count) = 0; + virtual renderer_buffer* create_buffer(buffer_type in_buffer_type, int32_t in_element_byte, int32_t in_element_count) = 0; virtual void destroy_buffer(renderer_buffer* buffer) { delete buffer; } virtual rect_pipeline* get_rect_pipeline() = 0; diff --git a/src/renderer/core/renderer/renderer_context.cpp b/src/renderer/core/renderer/renderer_context.cpp index 2022918..438a91d 100644 --- a/src/renderer/core/renderer/renderer_context.cpp +++ b/src/renderer/core/renderer/renderer_context.cpp @@ -1,4 +1,4 @@ -#include "renderer_context.h" +#include "renderer_context.h" #include "renderer.h" #include "backend/dx/dx_renderer.h" @@ -11,10 +11,16 @@ void renderer_context::draw_rectangle(const Eigen::Vector2f& in_pos, const Eigen make_rect(in_pos, in_size, in_color); } -void renderer_context::draw_rounded_rectangle(const Eigen::Vector2f& in_pos, const Eigen::Vector2f& in_size, const linear_color& in_color, float in_angle, float in_radius) { - to_rounded_rect_pipeline(in_pos, in_size, in_angle, in_radius); +void renderer_context::draw_rounded_rectangle(const Eigen::Vector2f& in_pos, const Eigen::Vector2f& in_size, const linear_color& in_color, float in_angle, const rect_radius& in_radius) { + to_rounded_rect_pipeline(in_pos, in_size, in_radius); + // in_angle传入的是角度, 需要转换为弧度 + in_angle = in_angle * M_PI / 180; make_rect(in_pos, in_size, in_color, in_angle); + if (in_angle != 0) { + auto center = in_pos + in_size / 2; + rotate_vertex(in_angle, center); + } // 立刻绘制并重置管线, 因为下一个绘制命令的参数可能不同, 所以无法合批 flush(); } @@ -51,32 +57,16 @@ void renderer_context::to_rect_pipeline() { switch_pipeline(rect_p); } -void renderer_context::to_rounded_rect_pipeline(const Eigen::Vector2f& in_pos, const Eigen::Vector2f& in_size, float in_angle, float in_radius) { +void renderer_context::to_rounded_rect_pipeline(const Eigen::Vector2f& in_pos, const Eigen::Vector2f& in_size, const rect_radius& in_radius) { const auto rounded_rect_p = aorii::get_renderer<dx_renderer>()->get_rounded_rect_pipeline(); switch_pipeline(rounded_rect_p); - Eigen::Vector2f top_middle = in_pos + Eigen::Vector2f(in_size.x() / 2, 0); - Eigen::Vector2f bottom_middle = in_pos + Eigen::Vector2f(in_size.x() / 2, in_size.y()); - - // 如果角度不为0, 则需要计算旋转后的坐标 - if (in_angle != 0) { - // 将top_middle和bottom_middle绕盒子中心旋转 - const Eigen::Vector2f& center = in_pos + in_size / 2; - Eigen::Affine2f transform = - Eigen::Translation<float, 2>(center) * // 平移到旋转中心 - Eigen::Rotation2D<float>(in_angle) * // 旋转 - Eigen::Translation<float, 2>(-center); // 平移回原点 - - top_middle = transform * top_middle; - bottom_middle = transform * bottom_middle; - } rounded_rect_pipeline::param param; param.projection_matrix = projection_matrix; - param.p1 = top_middle; - param.p2 = bottom_middle; + param.size = in_size; + param.pos = in_pos; param.radius = in_radius; - param.thickness = in_size.x(); rounded_rect_p->set_param(param); } @@ -100,58 +90,33 @@ void renderer_context::to_segment_pipeline(const Eigen::Vector2f& in_pos_p1, con void renderer_context::make_rect(const Eigen::Vector2f& in_pos, const Eigen::Vector2f& in_size, const linear_color& in_color, float in_angle) { - // 如果角度不为0, 则需要计算旋转后的坐标 - if (in_angle != 0) { - // 绕盒子中心旋转 - // 创建仿射变换矩阵(先平移,后旋转,再平移回去) - const Eigen::Vector2f& center = in_pos + in_size / 2; - Eigen::Affine2f transform = - Eigen::Translation<float, 2>(center) * // 平移到旋转中心 - Eigen::Rotation2D<float>(in_angle) * // 旋转 - Eigen::Translation<float, 2>(-center); // 平移回原点 + const aorii_vertex v1{ { in_pos.x(), in_pos.y() }, { -1, 1 }, in_color }; // 左上角 + const aorii_vertex v2{ { in_pos.x() + in_size.x(), in_pos.y() }, { 1, 1 }, in_color }; // 右上角 + const aorii_vertex v3{ { in_pos.x(), in_pos.y() + in_size.y() }, { -1, -1 }, in_color }; // 左下角 + const aorii_vertex v4{ { in_pos.x() + in_size.x(), in_pos.y() + in_size.y() }, { 1, -1 }, in_color }; // 右下角 - const Eigen::Vector2f top_left = transform * in_pos; - const Eigen::Vector2f top_right = transform * Eigen::Vector2f(in_pos.x() + in_size.x(), in_pos.y()); - const Eigen::Vector2f bottom_left = transform * Eigen::Vector2f(in_pos.x(), in_pos.y() + in_size.y()); - const Eigen::Vector2f bottom_right = transform * (in_pos + in_size); + const uint32_t index1 = vertices.size(); + vertices.push_back(v1); + const uint32_t index2 = vertices.size(); + vertices.push_back(v2); + const uint32_t index3 = vertices.size(); + vertices.push_back(v3); + const uint32_t index4 = vertices.size(); + vertices.push_back(v4); - const aorii_vertex v1{ { top_left.x(), top_left.y() }, { 0, 0 }, in_color }; // 左上角 - const aorii_vertex v2{ { top_right.x(), top_right.y() }, { 1, 0 }, in_color }; // 右上角 - const aorii_vertex v3{ { bottom_left.x(), bottom_left.y() }, { 0, 1 }, in_color }; // 左下角 - const aorii_vertex v4{ { bottom_right.x(), bottom_right.y() }, { 1, 1 }, in_color }; // 右下角 + const aorii_triangle t1 = { index1, index2, index3 }; + const aorii_triangle t2 = { index2, index3, index4 }; + triangles.push_back(t1); + triangles.push_back(t2); +} - const uint32_t index1 = vertices.size(); - vertices.push_back(v1); - const uint32_t index2 = vertices.size(); - vertices.push_back(v2); - const uint32_t index3 = vertices.size(); - vertices.push_back(v3); - const uint32_t index4 = vertices.size(); - vertices.push_back(v4); +void renderer_context::rotate_vertex(const float in_angle, const Eigen::Vector2f& in_center) { + const Eigen::Affine2f transform = + Eigen::Translation<float, 2>(in_center) * // 平移到旋转中心 + Eigen::Rotation2D<float>(in_angle) * // 旋转 + Eigen::Translation<float, 2>(-in_center); // 平移回原点 - const aorii_triangle t1 = { index1, index2, index3 }; - const aorii_triangle t2 = { index2, index3, index4 }; - triangles.push_back(t1); - triangles.push_back(t2); - } - else { - const aorii_vertex v1{ { in_pos.x(), in_pos.y() }, { 0, 0 }, in_color }; // 左上角 - const aorii_vertex v2{ { in_pos.x() + in_size.x(), in_pos.y() }, { 1, 0 }, in_color }; // 右上角 - const aorii_vertex v3{ { in_pos.x(), in_pos.y() + in_size.y() }, { 0, 1 }, in_color }; // 左下角 - const aorii_vertex v4{ { in_pos.x() + in_size.x(), in_pos.y() + in_size.y() }, { 1, 1 }, in_color }; // 右下角 - - const uint32_t index1 = vertices.size(); - vertices.push_back(v1); - const uint32_t index2 = vertices.size(); - vertices.push_back(v2); - const uint32_t index3 = vertices.size(); - vertices.push_back(v3); - const uint32_t index4 = vertices.size(); - vertices.push_back(v4); - - const aorii_triangle t1 = { index1, index2, index3 }; - const aorii_triangle t2 = { index2, index3, index4 }; - triangles.push_back(t1); - triangles.push_back(t2); + for (auto& vertex : vertices) { + vertex.position = transform * vertex.position; } } diff --git a/src/renderer/core/renderer/renderer_context.h b/src/renderer/core/renderer/renderer_context.h index 90d327d..09d331a 100644 --- a/src/renderer/core/renderer/renderer_context.h +++ b/src/renderer/core/renderer/renderer_context.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include <spdlog/spdlog.h> #include "core/pipeline/pipeline.h" @@ -7,6 +7,21 @@ class renderer_texture; +struct rect_radius { + rect_radius(float radius) : top_left(radius), top_right(radius), bottom_left(radius), bottom_right(radius) {} + rect_radius(float top, float bottom) : top_left(top), top_right(top), bottom_left(bottom), bottom_right(bottom) {} + rect_radius(float top_left, float top_right, float bottom_left, float bottom_right) : top_left(top_left), top_right(top_right), bottom_left(bottom_left), bottom_right(bottom_right) {} + + float top_left; + float top_right; + float bottom_left; + float bottom_right; + + operator Eigen::Vector4f() const { + return { top_left, top_right, bottom_left, bottom_right }; + } +}; + class renderer_context { public: void init(); @@ -26,7 +41,7 @@ public: * @param in_angle * @param in_radius 圆角半径(像素) */ - void draw_rounded_rectangle(const Eigen::Vector2f& in_pos, const Eigen::Vector2f& in_size, const linear_color& in_color, float in_angle, float in_radius); + void draw_rounded_rectangle(const Eigen::Vector2f& in_pos, const Eigen::Vector2f& in_size, const linear_color& in_color, float in_angle, const rect_radius& in_radius); /** * 绘制一条线 @@ -80,7 +95,7 @@ protected: } void to_rect_pipeline(); - void to_rounded_rect_pipeline(const Eigen::Vector2f& in_pos, const Eigen::Vector2f& in_size, float in_angle, float in_radius); + void to_rounded_rect_pipeline(const Eigen::Vector2f& in_pos, const Eigen::Vector2f& in_size, const rect_radius& in_radius); void to_texture_pipeline(renderer_texture* in_texture); void to_segment_pipeline(const Eigen::Vector2f& in_pos_p1, const Eigen::Vector2f& in_pos_p2, float in_thickness); private: @@ -92,4 +107,5 @@ private: Eigen::Vector2i framebuffer_size; private: void make_rect(const Eigen::Vector2f& in_pos, const Eigen::Vector2f& in_size, const linear_color& in_color, float in_angle = 0); + void rotate_vertex(float in_angle, const Eigen::Vector2f& in_center); }; diff --git a/src/renderer/shader/aorii_rounded_rect.slang b/src/renderer/shader/aorii_rounded_rect.slang index 67940ba..a3a5c37 100644 --- a/src/renderer/shader/aorii_rounded_rect.slang +++ b/src/renderer/shader/aorii_rounded_rect.slang @@ -1,10 +1,9 @@ cbuffer ParamBuffer : register(b0) { matrix transform; - float2 p1; // 点1位置 - float2 p2; // 点2位置 - float radius; // 圆角像素单位 - float thickness; // 线段的宽度 + float2 size; // 矩形大小 像素单位 + float2 pos; // 矩形位置 像素单位 + float4 radius; // 四角圆角像素单位 左上 右上 左下 右下 }; struct VSInput { @@ -28,33 +27,25 @@ PSInput vertex_main(VSInput input) return output; } -// 圆角矩形像素着色器 -float4 pixel_main(PSInput input) : SV_TARGET -{ - // 计算input.position到线段p1p2的最短距离 - float2 p = input.uv; - return float4(p, 0, 1); - - // 计算当前片段到线段的距离 - float2 ba = p2 - p1; - float2 pa = p - p1; - float2 ba_norm = normalize(ba); - float h = clamp(dot(pa, ba_norm), 0.0, length(ba)); - float2 pb = p1 + ba_norm * h; - - float dist = length(p - pb); // 点到线段的距离 - float half_thickness = thickness / 2; - // 抗锯齿 - float alpha = smoothstep(half_thickness - 1, half_thickness, dist); - // 圆角 - float2 corner = float2(radius, radius); - float2 d = abs(p - pb) - corner; - float2 max_d = max(d, 0); - - // float corner_dist = length(max_d); - // float corner_alpha = smoothstep(0, 1, corner_dist); - - float4 color = input.color; - color.a *= (1 - alpha); - return color; +float distance_from_rect_uv(float2 p, float corner_radius) { + corner_radius *= 2; + float2 corner_radius_uv = corner_radius / size; + float2 inner_rect = float2(1) - corner_radius_uv; // 圆心 + float2 q = abs(p) - inner_rect; + q *= size; + return length(max(q, 0.0)) + min(max(q.x, q.y), 0.0) - corner_radius; +} + +float4 pixel_main(PSInput input) : SV_Target +{ + float2 p = input.uv; + + // 象限 + int2 quadrant = sign(p); + int idx = (quadrant.x > 0 ? 1 : 0) + (quadrant.y > 0 ? 0 : 2); + float r = radius[idx]; + float d = distance_from_rect_uv(p, r); + // TODO 抗锯齿 + + return input.color * -d; }