todo
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
cmake_policy(SET CMP0167 NEW)
|
||||
project(aorii)
|
||||
project(aorii LANGUAGES C CXX)
|
||||
set(CMAKE_CXX_STANDARD 26)
|
||||
if (APPLE)
|
||||
enable_language(OBJC OBJCXX)
|
||||
endif ()
|
||||
|
||||
set(MSDFGEN_USE_SKIA OFF CACHE BOOL "Use Skia for MSDFGen" FORCE)
|
||||
set(MSDFGEN_USE_VCPKG OFF CACHE BOOL "Use VCPKG for MSDFGen" FORCE)
|
||||
@@ -13,6 +16,21 @@ include(cmake/detect_os.cmake)
|
||||
include(cmake/configure_glfw_native.cmake)
|
||||
include(cmake/compile_shaders.cmake)
|
||||
|
||||
# 如果是Macos
|
||||
if (APPLE)
|
||||
# 获取 Homebrew 安装的 libomp 路径
|
||||
execute_process(
|
||||
COMMAND brew --prefix libomp
|
||||
OUTPUT_VARIABLE HOMEBREW_LIBOMP_PATH
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
# 设置 OpenMP 路径变量
|
||||
set(OpenMP_CXX_FLAGS "-Xpreprocessor -fopenmp -I${HOMEBREW_LIBOMP_PATH}/include")
|
||||
set(OpenMP_CXX_LIB_NAMES "omp")
|
||||
set(OpenMP_omp_LIBRARY "${HOMEBREW_LIBOMP_PATH}/lib/libomp.dylib")
|
||||
endif ()
|
||||
|
||||
# 如果是Debug模式, 添加宏定义
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
add_definitions(-DDEBUG=1)
|
||||
@@ -23,7 +41,6 @@ endif ()
|
||||
add_subdirectory(third_party/LLGL)
|
||||
add_subdirectory(third_party/msdfgen)
|
||||
add_subdirectory(src/core)
|
||||
add_subdirectory(src/renderer)
|
||||
add_subdirectory(src/widget)
|
||||
|
||||
set(BUILD_EXAMPLE FALSE CACHE BOOL "Build example")
|
||||
|
||||
@@ -28,7 +28,7 @@ function(compile_slang_shaders input_file stage entry_point)
|
||||
endif()
|
||||
|
||||
# 为每个后台创建自定义命令
|
||||
if(GL_BACKEND)
|
||||
if(LLGL_BUILD_RENDERER_OPENGL OR LLGL_BUILD_RENDERER_OPENGL_ES3 OR LLGL_BUILD_RENDERER_WEBGL)
|
||||
set(output_file ${output_dir}/${filename}_${entry_point}.glsl)
|
||||
add_custom_command(
|
||||
OUTPUT ${output_file}
|
||||
@@ -39,7 +39,7 @@ function(compile_slang_shaders input_file stage entry_point)
|
||||
list(APPEND output_files ${output_file})
|
||||
endif()
|
||||
|
||||
if(DX_BACKEND)
|
||||
if(LLGL_BUILD_RENDERER_DIRECT3D11 OR LLGL_BUILD_RENDERER_DIRECT3D12)
|
||||
set(output_file ${output_dir}/${filename}_${entry_point}.dxbc)
|
||||
add_custom_command(
|
||||
OUTPUT ${output_file}
|
||||
@@ -50,7 +50,7 @@ function(compile_slang_shaders input_file stage entry_point)
|
||||
list(APPEND output_files ${output_file})
|
||||
endif()
|
||||
|
||||
if(VK_BACKEND)
|
||||
if(LLGL_BUILD_RENDERER_VULKAN)
|
||||
set(output_file ${output_dir}/${filename}_${entry_point}.spirv)
|
||||
add_custom_command(
|
||||
OUTPUT ${output_file}
|
||||
@@ -61,11 +61,11 @@ function(compile_slang_shaders input_file stage entry_point)
|
||||
list(APPEND output_files ${output_file})
|
||||
endif()
|
||||
|
||||
if(METAL_BACKEND)
|
||||
if(LLGL_BUILD_RENDERER_METAL)
|
||||
set(output_file ${output_dir}/${filename}_${entry_point}.metal)
|
||||
add_custom_command(
|
||||
OUTPUT ${output_file}
|
||||
COMMAND slangc -target msl -entry ${entry_point} -stage ${stage} ${extra_args} -o ${output_file} ${input_file} -DUSE_METAL=1
|
||||
COMMAND slangc -target metal -entry ${entry_point} -stage ${stage} ${extra_args} -o ${output_file} ${input_file} -DUSE_METAL=1
|
||||
DEPENDS ${input_file}
|
||||
COMMENT "Compiling ${input_file} to Metal Shading Language (${stage}, ${entry_point})"
|
||||
)
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
function(add_os_definitions target)
|
||||
# 初始化所有平台宏为 0
|
||||
set(PLATFORMS WINDOWS MACOS LINUX FREEBSD)
|
||||
set(PLATFORMS WINDOWS MACOS LINUX FREEBSD IOS ANDROID)
|
||||
|
||||
# 检测操作系统并设置相应的宏为 1
|
||||
if(WIN32)
|
||||
target_compile_definitions(${target} PRIVATE WINDOWS=1)
|
||||
message(STATUS "Detected Windows operating system")
|
||||
list(REMOVE_ITEM PLATFORMS WINDOWS)
|
||||
elseif(APPLE)
|
||||
elseif(APPLE AND UNIX)
|
||||
target_compile_definitions(${target} PRIVATE MACOS=1)
|
||||
message(STATUS "Detected macOS operating system")
|
||||
list(REMOVE_ITEM PLATFORMS MACOS)
|
||||
@@ -25,6 +25,14 @@ function(add_os_definitions target)
|
||||
else()
|
||||
message(WARNING "Detected unknown Unix-like operating system")
|
||||
endif()
|
||||
elseif(ANDROID)
|
||||
target_compile_definitions(${target} PRIVATE ANDROID=1)
|
||||
message(STATUS "Detected Android operating system")
|
||||
list(REMOVE_ITEM PLATFORMS ANDROID)
|
||||
elseif(IOS)
|
||||
target_compile_definitions(${target} PRIVATE IOS=1)
|
||||
message(STATUS "Detected iOS operating system")
|
||||
list(REMOVE_ITEM PLATFORMS IOS)
|
||||
else()
|
||||
message(WARNING "Unknown operating system")
|
||||
endif()
|
||||
@@ -55,4 +63,11 @@ function(add_os_definitions target)
|
||||
else()
|
||||
target_compile_definitions(${target} PRIVATE POSIX=0)
|
||||
endif()
|
||||
|
||||
# 设置IS_MOBILE宏
|
||||
if(ANDROID OR IOS)
|
||||
target_compile_definitions(${target} PRIVATE IS_MOBILE=1)
|
||||
else()
|
||||
target_compile_definitions(${target} PRIVATE IS_MOBILE=0)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
@@ -56,6 +56,10 @@ endfunction()
|
||||
|
||||
function(retrieve_files path out_files)
|
||||
set(temp_files "")
|
||||
retrieve_files_custom(${path} "h;hpp;ini;cpp;c;ixx" temp_files)
|
||||
if (APPLE)
|
||||
retrieve_files_custom(${path} "h;hpp;ini;cpp;c;ixx;mm" temp_files)
|
||||
else ()
|
||||
retrieve_files_custom(${path} "h;hpp;ini;cpp;c;ixx" temp_files)
|
||||
endif ()
|
||||
set(${out_files} ${${out_files}} ${temp_files} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
@@ -4,4 +4,4 @@ set(CMAKE_CXX_STANDARD 23)
|
||||
set(SRC_FILES "")
|
||||
retrieve_files(src SRC_FILES)
|
||||
add_executable(${PROJECT_NAME} ${SRC_FILES})
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE aorii_renderer)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE aorii_core)
|
||||
|
||||
@@ -3,22 +3,20 @@
|
||||
#include <iostream>
|
||||
|
||||
#include "async/thread_pool.h"
|
||||
#include "core/renderer/renderer.h"
|
||||
#include "core/window/window_manager.h"
|
||||
#include "core/window/renderer_window.h"
|
||||
#include "renderer/renderer.h"
|
||||
#include "window/window_manager.h"
|
||||
#include "window/renderer_window.h"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
aorii::create_renderer(renderer_api::DX11);
|
||||
aorii::create_window_manager();
|
||||
aorii::init(renderer_api::metal);
|
||||
|
||||
auto window = aorii::create_window({1280, 1280}, "hello world");
|
||||
auto glfw_window = window->get_glfw_window();
|
||||
while (!glfwWindowShouldClose(glfw_window)) {
|
||||
thread_pool::global().process_main_thread_callbacks();
|
||||
glfwPollEvents();
|
||||
renderer_window::desc_type desc{};
|
||||
desc.resolution = { 1280, 1280 };
|
||||
auto window = aorii::create_renderer_window(desc);
|
||||
|
||||
while (!aorii::should_exit()) {
|
||||
aorii::update();
|
||||
}
|
||||
|
||||
aorii::destroy_window_manager();
|
||||
aorii::destroy_renderer();
|
||||
aorii::destroy();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,90 @@
|
||||
project(aorii_core)
|
||||
|
||||
set(SRC_FILES "")
|
||||
retrieve_files(${CMAKE_CURRENT_SOURCE_DIR} SRC_FILES)
|
||||
add_library(${PROJECT_NAME} STATIC ${SRC_FILES})
|
||||
find_package(harfbuzz REQUIRED)
|
||||
find_package(Eigen3 REQUIRED)
|
||||
find_package(spdlog REQUIRED)
|
||||
find_package(Boost REQUIRED)
|
||||
find_package(Freetype REQUIRED)
|
||||
|
||||
if (APPLE)
|
||||
find_library(COCOA_LIBRARY Cocoa)
|
||||
endif ()
|
||||
|
||||
set(RENDERER_SOURCES "")
|
||||
retrieve_files(${CMAKE_CURRENT_SOURCE_DIR} RENDERER_SOURCES)
|
||||
|
||||
add_library(${PROJECT_NAME} STATIC ${RENDERER_SOURCES})
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC Freetype::Freetype harfbuzz::harfbuzz Eigen3::Eigen spdlog::spdlog msdfgen-full Boost::boost LLGL)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE NOMINMAX)
|
||||
add_os_definitions(${PROJECT_NAME})
|
||||
if (APPLE)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC ${COCOA_LIBRARY})
|
||||
endif ()
|
||||
|
||||
|
||||
|
||||
if (LLGL_BUILD_RENDERER_NULL)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC LLGL_Null)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE LLGL_BUILD_RENDERER_NULL)
|
||||
endif ()
|
||||
if (LLGL_BUILD_RENDERER_OPENGL)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC LLGL_OpenGL)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE LLGL_BUILD_RENDERER_OPENGL)
|
||||
endif ()
|
||||
if (LLGL_BUILD_RENDERER_OPENGL_ES3)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC LLGL_OpenGLES3)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE LLGL_BUILD_RENDERER_OPENGL_ES3)
|
||||
endif ()
|
||||
if (LLGL_BUILD_RENDERER_WEBGL)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC LLGL_WebGL)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE LLGL_BUILD_RENDERER_WEBGL)
|
||||
endif ()
|
||||
if (LLGL_BUILD_RENDERER_DIRECT3D11)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC LLGL_Direct3D11)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE LLGL_BUILD_RENDERER_DIRECT3D11)
|
||||
endif ()
|
||||
if (LLGL_BUILD_RENDERER_DIRECT3D12)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC LLGL_Direct3D12)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE LLGL_BUILD_RENDERER_DIRECT3D12)
|
||||
endif ()
|
||||
if (LLGL_BUILD_RENDERER_VULKAN)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC LLGL_Vulkan)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE LLGL_BUILD_RENDERER_VULKAN)
|
||||
endif ()
|
||||
if (LLGL_BUILD_RENDERER_METAL)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC LLGL_Metal)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE LLGL_BUILD_RENDERER_METAL)
|
||||
endif ()
|
||||
|
||||
# 添加编译shader的自定义命令
|
||||
if (NOT DEFINED SHADER_OUTPUT_DIR)
|
||||
set(SHADER_OUTPUT_DIR ${CMAKE_BINARY_DIR}/shaders CACHE PATH "Output directory for compiled shaders")
|
||||
message(STATUS "SHADER_OUTPUT_DIR not defined, using default: ${SHADER_OUTPUT_DIR}")
|
||||
endif ()
|
||||
function(compile_aorii_shader SHADER_FILE)
|
||||
compile_slang_shaders("${CMAKE_CURRENT_SOURCE_DIR}/shader/${SHADER_FILE}.slang" "vertex" "vertex_main")
|
||||
compile_slang_shaders("${CMAKE_CURRENT_SOURCE_DIR}/shader/${SHADER_FILE}.slang" "pixel" "pixel_main")
|
||||
endfunction()
|
||||
compile_aorii_shader(aorii_rect)
|
||||
compile_aorii_shader(aorii_rounded_rect)
|
||||
compile_aorii_shader(aorii_texture)
|
||||
compile_aorii_shader(aorii_segment)
|
||||
compile_aorii_shader(aorii_sdf_text)
|
||||
add_compile_shaders_target("compile_aorii_shaders" ${PROJECT_NAME})
|
||||
|
||||
# 如果需要编译example, 添加自定义命令用于拷贝shader文件
|
||||
if (BUILD_EXAMPLE)
|
||||
# 复制${SHADER_OUTPUT_DIR}文件到${CMAKE_CURRENT_BINARY_DIR}/example/resource/shaders
|
||||
set(SOURCE_DIR ${SHADER_OUTPUT_DIR})
|
||||
set(DEST_DIR ${CMAKE_BINARY_DIR}/example/resource/shaders)
|
||||
|
||||
# 添加自定义命令, 当外部目标compile_aorii_shaders被编译时, 将${SOURCE_DIR}文件复制到${DEST_DIR}
|
||||
add_custom_command(
|
||||
TARGET compile_aorii_shaders
|
||||
POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${DEST_DIR}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${SOURCE_DIR} ${DEST_DIR}
|
||||
COMMENT "Copying shaders to ${DEST_DIR}"
|
||||
)
|
||||
endif ()
|
||||
@@ -18,8 +18,8 @@ namespace cache {
|
||||
template<typename key_t, typename value_t>
|
||||
class lru_cache {
|
||||
public:
|
||||
typedef typename std::pair<key_t, value_t> key_value_pair_t;
|
||||
typedef typename std::list<key_value_pair_t>::iterator list_iterator_t;
|
||||
using key_value_pair_t = std::pair<key_t, value_t>;
|
||||
using list_iterator_t = typename std::list<key_value_pair_t>::iterator;
|
||||
|
||||
lru_cache(size_t max_size) :
|
||||
_max_size(max_size) {
|
||||
@@ -36,7 +36,7 @@ public:
|
||||
|
||||
if (_cache_items_map.size() > _max_size) {
|
||||
auto last = _cache_items_list.end();
|
||||
last--;
|
||||
--last;
|
||||
_cache_items_map.erase(last->first);
|
||||
_cache_items_list.pop_back();
|
||||
}
|
||||
@@ -46,17 +46,21 @@ public:
|
||||
auto it = _cache_items_map.find(key);
|
||||
if (it == _cache_items_map.end()) {
|
||||
throw std::range_error("There is no such key in cache");
|
||||
} else {
|
||||
_cache_items_list.splice(_cache_items_list.begin(), _cache_items_list, it->second);
|
||||
return it->second->second;
|
||||
}
|
||||
_cache_items_list.splice(_cache_items_list.begin(), _cache_items_list, it->second);
|
||||
return it->second->second;
|
||||
}
|
||||
|
||||
value_t* find(const key_t& key) {
|
||||
auto it = _cache_items_map.find(key);
|
||||
return it == _cache_items_map.end() ? nullptr : &it->second->second;
|
||||
}
|
||||
|
||||
bool exists(const key_t& key) const {
|
||||
return _cache_items_map.find(key) != _cache_items_map.end();
|
||||
return _cache_items_map.contains(key);
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
[[nodiscard]] size_t size() const {
|
||||
return _cache_items_map.size();
|
||||
}
|
||||
|
||||
|
||||
@@ -3,9 +3,6 @@
|
||||
#include <boost/flyweight.hpp>
|
||||
#include <boost/flyweight/key_value.hpp>
|
||||
#include <boost/flyweight/no_tracking.hpp>
|
||||
#include <unicode/uscript.h>
|
||||
#include <unicode/uloc.h>
|
||||
#include <harfbuzz/hb-icu.h>
|
||||
|
||||
enum class font_style {
|
||||
regular = 1 << 1, // 正常
|
||||
@@ -22,11 +19,11 @@ enum class font_style {
|
||||
};
|
||||
|
||||
using font_family = boost::flyweight<
|
||||
boost::flyweights::key_value<std::string, std::string>,
|
||||
std::string,
|
||||
boost::flyweights::no_tracking
|
||||
>;
|
||||
|
||||
using font_path = boost::flyweight<
|
||||
boost::flyweights::key_value<std::string, std::string>,
|
||||
std::string,
|
||||
boost::flyweights::no_tracking
|
||||
>;
|
||||
63
src/core/fonts/glyph_cache.cpp
Normal file
63
src/core/fonts/glyph_cache.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
//
|
||||
// Created by Administrator on 25-2-2.
|
||||
//
|
||||
#include "glyph_cache.h"
|
||||
|
||||
glyph_cache::~glyph_cache() {
|
||||
clear();
|
||||
}
|
||||
|
||||
void glyph_cache::initialize(LLGL::RenderSystem& in_render_system) {
|
||||
render_system = &in_render_system;
|
||||
}
|
||||
|
||||
void glyph_cache::clear() {
|
||||
if (!render_system)
|
||||
return;
|
||||
for (auto& page : active_atlases)
|
||||
render_system->Release(*page.texture);
|
||||
active_atlases.clear();
|
||||
}
|
||||
|
||||
glyph_metadata glyph_cache::get_glyph(const glyph_key& in_key) {
|
||||
if (const auto find = metadata_cache.find(in_key))
|
||||
return *find;
|
||||
auto glyph = make_glyph(in_key);
|
||||
metadata_cache.put(in_key, glyph);
|
||||
return glyph;
|
||||
}
|
||||
|
||||
bool glyph_cache::atlas_page::put_glyph(const LLGL::TextureRegion& in_size, const LLGL::ImageView& in_data,
|
||||
Eigen::AlignedBox2f& out_uv_rect) {
|
||||
if (current_x + in_size.offset.x > texture->GetDesc().extent.width) {
|
||||
current_x = 0;
|
||||
current_y += row_height;
|
||||
row_height = 0;
|
||||
}
|
||||
if (current_y + in_size.offset.y > texture->GetDesc().extent.height)
|
||||
return false;
|
||||
|
||||
render_system->WriteTexture(*texture, in_size, in_data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
glyph_cache::atlas_page glyph_cache::allocate_space(uint32_t in_width, uint32_t in_height) {
|
||||
LLGL::TextureDescriptor descriptor{};
|
||||
descriptor.type = LLGL::TextureType::Texture2D;
|
||||
descriptor.cpuAccessFlags = LLGL::CPUAccessFlags::Write;
|
||||
descriptor.extent.width = in_width;
|
||||
descriptor.extent.height = in_height;
|
||||
|
||||
atlas_page page{};
|
||||
page.texture = render_system->CreateTexture(descriptor);
|
||||
|
||||
active_atlases.push_back(page);
|
||||
return page;
|
||||
}
|
||||
|
||||
glyph_metadata glyph_cache::make_glyph(const glyph_key& in_key) {
|
||||
glyph_metadata out{};
|
||||
// out.atlas_texture = ;
|
||||
return out;
|
||||
}
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
struct glyph_key {
|
||||
font_family family{};
|
||||
uint32_t code_point{};
|
||||
char32_t code_point{};
|
||||
float font_size{};
|
||||
float dpi_scale{};
|
||||
|
||||
@@ -48,20 +48,28 @@ struct glyph_metadata {
|
||||
|
||||
class glyph_cache {
|
||||
public:
|
||||
~glyph_cache();
|
||||
|
||||
void initialize(LLGL::RenderSystem& in_render_system);
|
||||
void clear();
|
||||
glyph_metadata get_glyph(const glyph_key& in_key);
|
||||
private:
|
||||
struct atlas_page {
|
||||
LLGL::Texture* texture = nullptr;
|
||||
LLGL::RenderSystem* render_system = nullptr;
|
||||
uint32_t current_x = 0;
|
||||
uint32_t current_y = 0;
|
||||
uint32_t row_height = 0;
|
||||
|
||||
bool put_glyph(const LLGL::TextureRegion& in_size, const LLGL::ImageView& in_data, Eigen::AlignedBox2f& out_uv_rect);
|
||||
};
|
||||
|
||||
cache::lru_cache<glyph_key, glyph_metadata> metadata_cache;
|
||||
cache::lru_cache<glyph_key, glyph_metadata> metadata_cache{500};
|
||||
std::vector<atlas_page> active_atlases;
|
||||
std::mutex atlas_mutex;
|
||||
LLGL::RenderSystem* render_system = nullptr;
|
||||
|
||||
atlas_page* allocate_space(uint32_t in_width, uint32_t in_height);
|
||||
atlas_page allocate_space(uint32_t in_width, uint32_t in_height);
|
||||
glyph_metadata make_glyph(const glyph_key& in_key);
|
||||
};
|
||||
|
||||
7988
src/core/misc/stb_image.h
Normal file
7988
src/core/misc/stb_image.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,16 +1,16 @@
|
||||
#include "pipeline.h"
|
||||
|
||||
#include "core/renderer/renderer.h"
|
||||
#include "renderer/renderer.h"
|
||||
|
||||
bool pipeline::init() {
|
||||
vertex_buffer = aorii::get_renderer_raw()->create_vertex_buffer();
|
||||
index_buffer = aorii::get_renderer_raw()->create_index_buffer();
|
||||
// vertex_buffer = aorii::get_renderer_raw()->create_vertex_buffer();
|
||||
// index_buffer = aorii::get_renderer_raw()->create_index_buffer();
|
||||
return true;
|
||||
}
|
||||
|
||||
void pipeline::destroy() {
|
||||
aorii::get_renderer_raw()->destroy_buffer(vertex_buffer);
|
||||
aorii::get_renderer_raw()->destroy_buffer(index_buffer);
|
||||
// aorii::get_renderer_raw()->destroy_buffer(vertex_buffer);
|
||||
// aorii::get_renderer_raw()->destroy_buffer(index_buffer);
|
||||
}
|
||||
|
||||
void pipeline::set_triangle(const std::span<const aorii_vertex>& in_vertexes,
|
||||
@@ -3,8 +3,8 @@
|
||||
#include <string>
|
||||
#include <Eigen/Eigen>
|
||||
|
||||
#include "core/renderer/renderer_buffer.h"
|
||||
#include "../../../core/misc/color.h"
|
||||
#include "misc/color.h"
|
||||
#include "renderer/renderer_buffer.h"
|
||||
|
||||
struct aorii_vertex_param {
|
||||
float param_a1;
|
||||
@@ -1,15 +1,15 @@
|
||||
#include "rect_pipeline.h"
|
||||
|
||||
#include "core/renderer/renderer.h"
|
||||
#include "renderer/renderer.h"
|
||||
|
||||
bool rect_pipeline::init() {
|
||||
param_buffer = aorii::get_renderer_raw()->create_buffer(buffer_type::CONSTANT, sizeof(param), 1);
|
||||
// param_buffer = aorii::get_renderer_raw()->create_buffer(buffer_type::CONSTANT, sizeof(param), 1);
|
||||
return pipeline::init();
|
||||
}
|
||||
|
||||
void rect_pipeline::destroy() {
|
||||
pipeline::destroy();
|
||||
aorii::get_renderer_raw()->destroy_buffer(param_buffer);
|
||||
// aorii::get_renderer_raw()->destroy_buffer(param_buffer);
|
||||
}
|
||||
|
||||
void rect_pipeline::set_param(const param& in_param) {
|
||||
@@ -1,15 +1,15 @@
|
||||
#include "rounded_rect_pipeline.h"
|
||||
|
||||
#include "core/renderer/renderer.h"
|
||||
#include "renderer/renderer.h"
|
||||
|
||||
bool rounded_rect_pipeline::init() {
|
||||
param_buffer = aorii::get_renderer_raw()->create_buffer(buffer_type::CONSTANT, sizeof(param), 1);
|
||||
// param_buffer = aorii::get_renderer_raw()->create_buffer(buffer_type::CONSTANT, sizeof(param), 1);
|
||||
return pipeline::init();
|
||||
}
|
||||
|
||||
void rounded_rect_pipeline::destroy() {
|
||||
pipeline::destroy();
|
||||
aorii::get_renderer_raw()->destroy_buffer(param_buffer);
|
||||
// aorii::get_renderer_raw()->destroy_buffer(param_buffer);
|
||||
}
|
||||
|
||||
void rounded_rect_pipeline::set_param(const param& in_param) {
|
||||
22
src/core/pipeline/sdf_text_pipeline.cpp
Normal file
22
src/core/pipeline/sdf_text_pipeline.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#include "sdf_text_pipeline.h"
|
||||
|
||||
#include "renderer/renderer.h"
|
||||
|
||||
bool sdf_text_pipeline::init() {
|
||||
// param_buffer = aorii::get_renderer_raw()->create_buffer(buffer_type::CONSTANT, sizeof(param), 1);
|
||||
// sdf_font_param_buffer = aorii::get_renderer_raw()->create_buffer(buffer_type::CONSTANT, sizeof(sdf_font_param), 1);
|
||||
return pipeline::init();
|
||||
}
|
||||
void sdf_text_pipeline::destroy() {
|
||||
pipeline::destroy();
|
||||
// aorii::get_renderer_raw()->destroy_buffer(param_buffer);
|
||||
// aorii::get_renderer_raw()->destroy_buffer(sdf_font_param_buffer);
|
||||
}
|
||||
|
||||
void sdf_text_pipeline::set_param(const param& in_param) {
|
||||
param_buffer->set_data(in_param);
|
||||
}
|
||||
|
||||
void sdf_text_pipeline::set_sdf_font_param(const sdf_font_param& in_param) {
|
||||
sdf_font_param_buffer->set_data(in_param);
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
#include "segment_pipeline.h"
|
||||
|
||||
#include "core/renderer/renderer.h"
|
||||
#include "renderer/renderer.h"
|
||||
|
||||
bool segment_pipeline::init() {
|
||||
pipeline::init();
|
||||
param_buffer = aorii::get_renderer_raw()->create_buffer(buffer_type::CONSTANT, sizeof(param), 1);
|
||||
// param_buffer = aorii::get_renderer_raw()->create_buffer(buffer_type::CONSTANT, sizeof(param), 1);
|
||||
return true;
|
||||
}
|
||||
void segment_pipeline::destroy() {
|
||||
aorii::get_renderer_raw()->destroy_buffer(param_buffer);
|
||||
// aorii::get_renderer_raw()->destroy_buffer(param_buffer);
|
||||
pipeline::destroy();
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
#include "texture_pipeline.h"
|
||||
|
||||
#include "core/renderer/renderer.h"
|
||||
#include "renderer/renderer.h"
|
||||
|
||||
bool texture_pipeline::init() {
|
||||
param_buffer = aorii::get_renderer_raw()->create_buffer(buffer_type::CONSTANT, sizeof(param), 1);
|
||||
// param_buffer = aorii::get_renderer_raw()->create_buffer(buffer_type::CONSTANT, sizeof(param), 1);
|
||||
return pipeline::init();
|
||||
}
|
||||
void texture_pipeline::destroy() {
|
||||
pipeline::destroy();
|
||||
aorii::get_renderer_raw()->destroy_buffer(param_buffer);
|
||||
// aorii::get_renderer_raw()->destroy_buffer(param_buffer);
|
||||
}
|
||||
|
||||
void texture_pipeline::set_param(const param& in_param) {
|
||||
165
src/core/renderer/renderer.cpp
Normal file
165
src/core/renderer/renderer.cpp
Normal file
@@ -0,0 +1,165 @@
|
||||
#include "renderer.h"
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include "window/renderer_window.h"
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#define STBI_FAILURE_USERMSG
|
||||
#include "renderer_text.h"
|
||||
#include "async/thread_pool.h"
|
||||
#include "window/window_manager.h"
|
||||
#include "misc/stb_image.h"
|
||||
|
||||
#if DX_BACKEND
|
||||
#include "backend/dx/dx_renderer.h"
|
||||
#endif
|
||||
|
||||
using time_type = decltype(std::chrono::high_resolution_clock::now());
|
||||
std::chrono::duration<double> delta_time = {};
|
||||
time_type begin_time = {};
|
||||
time_type last_time = {};
|
||||
LLGL::RenderSystemPtr s_renderer{};
|
||||
LLGL::CommandBuffer* command_buffer{};
|
||||
LLGL::CommandBuffer* static_command_buffer{};
|
||||
LLGL::CommandBuffer* postprocess_command_buffer{};
|
||||
|
||||
// renderer_texture* renderer::load_image(const std::string& file_path, texture_format in_format) {
|
||||
// int width, height, channels;
|
||||
// const auto result = stbi_load(file_path.c_str(), &width, &height, &channels, 0);
|
||||
// if (!result) {
|
||||
// const char* reason = stbi_failure_reason();
|
||||
// spdlog::critical("加载图片 {0} 失败: {1}", file_path, reason);
|
||||
// return nullptr;
|
||||
// }
|
||||
// int target_channel_count = get_format_channel_count(in_format);
|
||||
// unsigned int row_pitch = 0;
|
||||
//
|
||||
// auto texture = create_texture(width, height, in_format, device_memory_type::GPU);
|
||||
// auto data = texture->lock(&row_pitch);
|
||||
// for (int y = 0; y < height; ++y) {
|
||||
// for (int x = 0; x < width; ++x) {
|
||||
// unsigned char* src = result + (y * width + x) * channels;
|
||||
// unsigned char* dst = static_cast<unsigned char*>(data) + y * row_pitch + x * target_channel_count;
|
||||
// switch (channels) {
|
||||
// case 1:
|
||||
// dst[0] = src[0];
|
||||
// dst[1] = 0;
|
||||
// dst[2] = 0;
|
||||
// dst[3] = 255;
|
||||
// break;
|
||||
// case 2:
|
||||
// dst[0] = src[0];
|
||||
// dst[1] = src[1];
|
||||
// dst[2] = 0;
|
||||
// dst[3] = 255;
|
||||
// break;
|
||||
// case 3:
|
||||
// dst[0] = src[0];
|
||||
// dst[1] = src[1];
|
||||
// dst[2] = src[2];
|
||||
// dst[3] = 255;
|
||||
// break;
|
||||
// case 4:
|
||||
// dst[0] = src[0];
|
||||
// dst[1] = src[1];
|
||||
// dst[2] = src[2];
|
||||
// dst[3] = src[3];
|
||||
// break;
|
||||
// default:
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// texture->unlock();
|
||||
// stbi_image_free(result);
|
||||
//
|
||||
// return texture;
|
||||
// }
|
||||
|
||||
bool aorii::init(renderer_api in_api) {
|
||||
create_renderer(in_api);
|
||||
create_window_manager();
|
||||
}
|
||||
|
||||
void aorii::destroy() {
|
||||
destroy_window_manager();
|
||||
destroy_renderer();
|
||||
}
|
||||
|
||||
LLGL::RenderSystem* aorii::get_renderer() {
|
||||
return s_renderer.get();
|
||||
}
|
||||
|
||||
LLGL::CommandBuffer* aorii::get_command_buffer() {
|
||||
return command_buffer;
|
||||
}
|
||||
|
||||
LLGL::CommandQueue* aorii::get_command_queue() {
|
||||
return s_renderer->GetCommandQueue();
|
||||
}
|
||||
|
||||
bool aorii::create_renderer(renderer_api api) {
|
||||
if (!aorii_text::init_freetype())
|
||||
return false;
|
||||
begin_time = std::chrono::high_resolution_clock::now();
|
||||
if (s_renderer) return true;
|
||||
|
||||
LLGL::RenderSystemDescriptor desc;
|
||||
switch (api) {
|
||||
case renderer_api::DX11:
|
||||
desc.moduleName = "Direct3D11";
|
||||
break;
|
||||
case renderer_api::DX12:
|
||||
desc.moduleName = "Direct3D12";
|
||||
break;
|
||||
case renderer_api::vulkan:
|
||||
desc.moduleName = "Vulkan";
|
||||
break;
|
||||
case renderer_api::opengl:
|
||||
desc.moduleName = "OpenGL";
|
||||
break;
|
||||
case renderer_api::metal:
|
||||
desc.moduleName = "Metal";
|
||||
break;
|
||||
default: spdlog::critical("Failed to create renderer!");
|
||||
assert(false);
|
||||
}
|
||||
|
||||
s_renderer = LLGL::RenderSystem::Load(desc);
|
||||
command_buffer = s_renderer->CreateCommandBuffer();
|
||||
last_time = std::chrono::high_resolution_clock::now();
|
||||
return s_renderer != nullptr;
|
||||
}
|
||||
|
||||
void aorii::destroy_renderer() {
|
||||
if (!s_renderer) return;
|
||||
|
||||
LLGL::RenderSystem::Unload(std::move(s_renderer));
|
||||
aorii_text::destroy_freetype();
|
||||
}
|
||||
|
||||
void aorii::update() {
|
||||
thread_pool::global().process_main_thread_callbacks();
|
||||
|
||||
const auto& current_time = std::chrono::high_resolution_clock::now();
|
||||
delta_time = current_time - last_time;
|
||||
last_time = current_time;
|
||||
|
||||
LLGL::Surface::ProcessEvents();
|
||||
s_window_manager->update();
|
||||
|
||||
command_buffer->Begin();
|
||||
command_buffer->;
|
||||
command_buffer->End();
|
||||
get_command_queue()->Submit(*command_buffer);
|
||||
|
||||
std::this_thread::yield();
|
||||
}
|
||||
|
||||
const std::chrono::duration<double>& aorii::get_delta_time() {
|
||||
return delta_time;
|
||||
}
|
||||
|
||||
std::chrono::duration<double> aorii::get_total_time() {
|
||||
return std::chrono::high_resolution_clock::now() - begin_time;
|
||||
}
|
||||
43
src/core/renderer/renderer.h
Normal file
43
src/core/renderer/renderer.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
#include <chrono>
|
||||
#include <filesystem>
|
||||
|
||||
#include "LLGL/RenderSystem.h"
|
||||
|
||||
enum class renderer_api {
|
||||
opengl,
|
||||
opengl_es,
|
||||
webgl,
|
||||
vulkan,
|
||||
DX11,
|
||||
DX12,
|
||||
metal
|
||||
};
|
||||
|
||||
struct postprocess_render_pass {
|
||||
LLGL::RenderTarget* input_render_target;
|
||||
LLGL::RenderTarget* output_render_target;
|
||||
LLGL::Texture* result_texture;
|
||||
LLGL::PipelineState* pipeline_state;
|
||||
LLGL::ResourceHeap* resource;
|
||||
};
|
||||
|
||||
namespace aorii {
|
||||
bool init(renderer_api in_api);
|
||||
void destroy();
|
||||
|
||||
LLGL::RenderSystem* get_renderer();
|
||||
LLGL::CommandBuffer* get_command_buffer();
|
||||
LLGL::CommandQueue* get_command_queue();
|
||||
|
||||
bool create_renderer(renderer_api api);
|
||||
void destroy_renderer();
|
||||
void update();
|
||||
|
||||
const std::chrono::duration<double>& get_delta_time();
|
||||
std::chrono::duration<double> get_total_time();
|
||||
|
||||
inline std::filesystem::path s_shader_relative_path = "resource/shaders";
|
||||
inline void set_shader_relative_path(const std::filesystem::path& path) { s_shader_relative_path = path; }
|
||||
inline std::filesystem::path get_shader_path(const std::string& shader_name) { return std::filesystem::current_path() / s_shader_relative_path / shader_name; }
|
||||
}
|
||||
20
src/core/renderer/renderer_buffer.cpp
Normal file
20
src/core/renderer/renderer_buffer.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#include "renderer_buffer.h"
|
||||
|
||||
void renderer_buffer::resize(const uint64_t new_size) {
|
||||
if (new_size == get_size())
|
||||
return;
|
||||
if (new_size < 1) {
|
||||
return;
|
||||
}
|
||||
void* temp_buffer = malloc(new_size);
|
||||
ON_SCOPE_EXIT {
|
||||
free(temp_buffer);
|
||||
};
|
||||
auto new_desc = get_desc();
|
||||
new_desc.size = new_size;
|
||||
const auto new_buffer = aorii::get_renderer()->CreateBuffer(new_desc, temp_buffer);
|
||||
|
||||
aorii::get_command_buffer()->CopyBuffer(*new_buffer, 0, *buffer, 0, std::min(get_size(), new_size));
|
||||
aorii::get_renderer()->Release(*buffer);
|
||||
buffer = new_buffer;
|
||||
}
|
||||
46
src/core/renderer/renderer_buffer.h
Normal file
46
src/core/renderer/renderer_buffer.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
#include <span>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include "LLGL/Buffer.h"
|
||||
#include "LLGL/RenderSystem.h"
|
||||
#include "renderer.h"
|
||||
#include "misc/scope_exit.h"
|
||||
|
||||
class renderer_buffer {
|
||||
public:
|
||||
explicit renderer_buffer(const LLGL::BufferDescriptor& in_desc) {
|
||||
buffer = aorii::get_renderer()->CreateBuffer(in_desc);
|
||||
}
|
||||
|
||||
virtual ~renderer_buffer() {
|
||||
aorii::get_renderer()->Release(*buffer);
|
||||
}
|
||||
|
||||
virtual void* lock(const LLGL::CPUAccess access = LLGL::CPUAccess::WriteDiscard) {
|
||||
return aorii::get_renderer()->MapBuffer(*buffer, access);
|
||||
}
|
||||
virtual void unlock() {
|
||||
return aorii::get_renderer()->UnmapBuffer(*buffer);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void set_data(const T& in_data) {
|
||||
aorii::get_command_buffer()->UpdateBuffer(*buffer, 0, &in_data, sizeof(T));
|
||||
}
|
||||
template<class T>
|
||||
void set_data(const std::span<const T>& in_data) {
|
||||
aorii::get_command_buffer()->UpdateBuffer(*buffer, 0, in_data.data(), sizeof(T) * in_data.size());
|
||||
}
|
||||
|
||||
void resize(uint64_t new_size);
|
||||
|
||||
[[nodiscard]] auto get_desc() const {
|
||||
return buffer->GetDesc();
|
||||
}
|
||||
[[nodiscard]] auto get_size() const {
|
||||
return get_desc().size;
|
||||
}
|
||||
protected:
|
||||
LLGL::Buffer* buffer;
|
||||
};
|
||||
@@ -2,14 +2,16 @@
|
||||
|
||||
#include "renderer.h"
|
||||
#include "renderer_text.h"
|
||||
#include "backend/dx/dx_renderer.h"
|
||||
#include "pipeline/sdf_text_pipeline.h"
|
||||
#include "pipeline/segment_pipeline.h"
|
||||
#include "pipeline/texture_pipeline.h"
|
||||
|
||||
aorii_text* text = nullptr;
|
||||
void renderer_context::init() {
|
||||
text = new aorii_text();
|
||||
// D:\Projects\aorii\JetBrainsMono-Regular.ttf
|
||||
text->initialize(LR"(C:\Windows\Fonts\Deng.ttf)");
|
||||
text->add_font(LR"(C:\Windows\Fonts\seguiemj.ttf)");
|
||||
// text->initialize(LR"(C:\Windows\Fonts\Deng.ttf)");
|
||||
// text->add_font(LR"(C:\Windows\Fonts\seguiemj.ttf)");
|
||||
// text->precache_common_characters();
|
||||
}
|
||||
|
||||
@@ -21,7 +23,9 @@ void renderer_context::draw_rectangle(const Eigen::Vector2f& in_pos, const Eigen
|
||||
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传入的是角度, 需要转换为弧度
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
in_angle = in_angle * M_PI / 180;
|
||||
|
||||
make_rect(in_pos, in_size, in_color, in_angle);
|
||||
@@ -42,96 +46,96 @@ void renderer_context::draw_texture(const Eigen::Vector2f& in_pos, const Eigen::
|
||||
}
|
||||
|
||||
void renderer_context::draw_string(const Eigen::Vector2f& in_pos, const std::u32string& in_str, float in_height, const linear_color& in_color) {
|
||||
to_text_pipeline(in_color);
|
||||
|
||||
const auto& measure = text->measure_text(in_str, in_height);
|
||||
|
||||
for (const auto& mch: measure) {
|
||||
const auto info = mch.item;
|
||||
if (!info)
|
||||
continue;
|
||||
const Eigen::Vector2f pos = mch.offset + in_pos;
|
||||
const Eigen::Vector2f size = Eigen::Vector2f{ info->get_width(), info->get_height() } * mch.size_scale;
|
||||
|
||||
aorii_vertex_param param{};
|
||||
param.param_a1 = info->tex_u;
|
||||
param.param_a2 = info->tex_v;
|
||||
param.param_a3 = info->tex_z;
|
||||
param.param_b1 = info->u_size;
|
||||
param.param_b2 = info->v_size;
|
||||
// param.param_b3 = info->get_width() * mch.size_scale > 15 ? 0.01 : 0;
|
||||
param.param_b3 = info->get_width() * mch.size_scale > 15 ? 0.01 : 0;
|
||||
|
||||
make_rect(pos, size, in_color, 0, param);
|
||||
}
|
||||
// to_text_pipeline(in_color);
|
||||
//
|
||||
// const auto& measure = text->measure_text(in_str, in_height);
|
||||
//
|
||||
// for (const auto& mch: measure) {
|
||||
// const auto info = mch.item;
|
||||
// if (!info)
|
||||
// continue;
|
||||
// const Eigen::Vector2f pos = mch.offset + in_pos;
|
||||
// const Eigen::Vector2f size = Eigen::Vector2f{ info->get_width(), info->get_height() } * mch.size_scale;
|
||||
//
|
||||
// aorii_vertex_param param{};
|
||||
// param.param_a1 = info->tex_u;
|
||||
// param.param_a2 = info->tex_v;
|
||||
// param.param_a3 = info->tex_z;
|
||||
// param.param_b1 = info->u_size;
|
||||
// param.param_b2 = info->v_size;
|
||||
// // param.param_b3 = info->get_width() * mch.size_scale > 15 ? 0.01 : 0;
|
||||
// param.param_b3 = info->get_width() * mch.size_scale > 15 ? 0.01 : 0;
|
||||
//
|
||||
// make_rect(pos, size, in_color, 0, param);
|
||||
// }
|
||||
}
|
||||
|
||||
void renderer_context::set_projection_matrix(const Eigen::Matrix4f& in_matrix, const Eigen::Vector2i& in_framebuffer_size) {
|
||||
projection_matrix = in_matrix;
|
||||
framebuffer_size = in_framebuffer_size;
|
||||
|
||||
// 更新默认管线的投影矩阵
|
||||
const auto rect_p = aorii::get_renderer<dx_renderer>()->get_rect_pipeline();
|
||||
rect_p->set_param({ in_matrix });
|
||||
// 更新纹理管线的投影矩阵
|
||||
const auto texture_p = aorii::get_renderer<dx_renderer>()->get_texture_pipeline();
|
||||
texture_p->set_param({ in_matrix });
|
||||
// // 更新默认管线的投影矩阵
|
||||
// const auto rect_p = aorii::get_renderer_raw()->get_rect_pipeline();
|
||||
// rect_p->set_param({ in_matrix });
|
||||
// // 更新纹理管线的投影矩阵
|
||||
// const auto texture_p = aorii::get_renderer_raw()->get_texture_pipeline();
|
||||
// texture_p->set_param({ in_matrix });
|
||||
|
||||
// 圆角矩形管线的投影矩阵不需要更新, 因为它在每次绘制时都会更新
|
||||
// 线段管线的投影矩阵不需要更新, 因为它在每次绘制时都会更新
|
||||
}
|
||||
|
||||
void renderer_context::to_rect_pipeline() {
|
||||
const auto rect_p = aorii::get_renderer<dx_renderer>()->get_rect_pipeline();
|
||||
switch_pipeline(rect_p);
|
||||
// const auto rect_p = aorii::get_renderer_raw()->get_rect_pipeline();
|
||||
// switch_pipeline(rect_p);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
rounded_rect_pipeline::param param;
|
||||
param.projection_matrix = projection_matrix;
|
||||
param.size = in_size;
|
||||
param.pos = in_pos;
|
||||
param.radius = in_radius;
|
||||
rounded_rect_p->set_param(param);
|
||||
// const auto rounded_rect_p = aorii::get_renderer_raw()->get_rounded_rect_pipeline();
|
||||
// switch_pipeline(rounded_rect_p);
|
||||
//
|
||||
// rounded_rect_pipeline::param param;
|
||||
// param.projection_matrix = projection_matrix;
|
||||
// param.size = in_size;
|
||||
// param.pos = in_pos;
|
||||
// param.radius = in_radius;
|
||||
// rounded_rect_p->set_param(param);
|
||||
}
|
||||
|
||||
void renderer_context::to_texture_pipeline(renderer_texture* in_texture) {
|
||||
const auto texture_p = aorii::get_renderer<dx_renderer>()->get_texture_pipeline();
|
||||
switch_pipeline(texture_p);
|
||||
texture_p->set_texture(in_texture);
|
||||
// const auto texture_p = aorii::get_renderer_raw()->get_texture_pipeline();
|
||||
// switch_pipeline(texture_p);
|
||||
// texture_p->set_texture(in_texture);
|
||||
}
|
||||
|
||||
void renderer_context::to_segment_pipeline(const Eigen::Vector2f& in_pos_p1, const Eigen::Vector2f& in_pos_p2, float in_thickness) {
|
||||
const auto segment_p = aorii::get_renderer<dx_renderer>()->get_segment_pipeline();
|
||||
switch_pipeline(segment_p);
|
||||
|
||||
segment_pipeline::param param;
|
||||
param.projection_matrix = projection_matrix;
|
||||
param.point_a = in_pos_p1;
|
||||
param.point_b = in_pos_p2;
|
||||
param.thickness = in_thickness;
|
||||
segment_p->set_param(param);
|
||||
// const auto segment_p = aorii::get_renderer_raw()->get_segment_pipeline();
|
||||
// switch_pipeline(segment_p);
|
||||
//
|
||||
// segment_pipeline::param param;
|
||||
// param.projection_matrix = projection_matrix;
|
||||
// param.point_a = in_pos_p1;
|
||||
// param.point_b = in_pos_p2;
|
||||
// param.thickness = in_thickness;
|
||||
// segment_p->set_param(param);
|
||||
}
|
||||
|
||||
void renderer_context::to_text_pipeline(const linear_color& in_color) {
|
||||
const auto text_p = aorii::get_renderer<dx_renderer>()->get_text_pipeline();
|
||||
switch_pipeline(text_p);
|
||||
// const auto text_p = aorii::get_renderer_raw()->get_text_pipeline();
|
||||
// switch_pipeline(text_p);
|
||||
//
|
||||
// sdf_text_pipeline::param param;
|
||||
// param.projection_matrix = projection_matrix;
|
||||
// text_p->set_param(param);
|
||||
//
|
||||
// sdf_text_pipeline::sdf_font_param font_param;
|
||||
// font_param.smoothing = 1;
|
||||
// font_param.thickness = 1;
|
||||
// font_param.outline_width = 0;
|
||||
// font_param.outline_color = in_color;
|
||||
// text_p->set_sdf_font_param(font_param);
|
||||
|
||||
sdf_text_pipeline::param param;
|
||||
param.projection_matrix = projection_matrix;
|
||||
text_p->set_param(param);
|
||||
|
||||
sdf_text_pipeline::sdf_font_param font_param;
|
||||
font_param.smoothing = 1;
|
||||
font_param.thickness = 1;
|
||||
font_param.outline_width = 0;
|
||||
font_param.outline_color = in_color;
|
||||
text_p->set_sdf_font_param(font_param);
|
||||
|
||||
text_p->set_glyph_texture(text->get_texture_array());
|
||||
// text_p->set_glyph_texture(text->get_texture_array());
|
||||
}
|
||||
|
||||
void renderer_context::make_rect(const Eigen::Vector2f& in_pos, const Eigen::Vector2f& in_size,
|
||||
@@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include "core/pipeline/pipeline.h"
|
||||
#include "core/pipeline/rect_pipeline.h"
|
||||
#include "core/pipeline/rounded_rect_pipeline.h"
|
||||
#include "pipeline/pipeline.h"
|
||||
#include "pipeline/rect_pipeline.h"
|
||||
#include "pipeline/rounded_rect_pipeline.h"
|
||||
|
||||
class renderer_texture;
|
||||
|
||||
30
src/core/renderer/renderer_text.cpp
Normal file
30
src/core/renderer/renderer_text.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
#include "renderer_text.h"
|
||||
|
||||
#include <future>
|
||||
#include <utility>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include "renderer.h"
|
||||
|
||||
#include "misc/scope_exit.h"
|
||||
|
||||
// 在SDFFontCache.cpp中添加实现
|
||||
const std::u32string aorii_text::COMMON_ASCII =
|
||||
U"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
|
||||
const std::u32string aorii_text::COMMON_CHINESE =
|
||||
U"的一是在不了有和人这中大为上个国我以要他时来用们生到作地于出就分对成会可主发年动同工也能下过子说产种面而方后多定行学法所民得经十三之进着等部度家电力里如水化高自二理起小物现实加量都两体制机当使点从业本去把性好应开它合还因由其些然前外天政四日那社义事平形相全表间样与关各重新线内数正心反你明看原又么利比或但质气第向道命此变条只没结解问意建月公无系军很情者最立代想已通并提直题党程展五果料象员革位入常文总次品式活设及管特件长求老头基资边流路级少图山统接知较将组见计别她手角期根论运农指几九区强放决西被干做必战先回则任取据处队南给色光门即保治北造百规热领七海口东导器压志世金增争济阶油思术极交受联什认六共权收证改清己美再采转更单风切打白教速花带安场身车例真务具万每目至达走积示议声报斗完类八离华名确才科张信马节话米整空元况今集温传土许步群广石记需段研界拉林律叫且究观越织装影算低持音众书布复容儿须际商非验连断深难近矿千周委素技备半办青省列习响约支般史感劳便团往酸历市克何除消构府称太准精值号率族维划选标写存候毛亲快效斯院查江型眼王按格养易置派层片始却专状育厂京识适属圆包火住调满县局照参红细引听该铁价严";
|
||||
|
||||
const std::u32string aorii_text::COMMON_PUNCTUATION =
|
||||
U",。!?:;''""《》【】()、";
|
||||
|
||||
const std::u32string aorii_text::COMMON_NUMBERS =
|
||||
U"0123456789";
|
||||
|
||||
bool aorii_text::init_freetype() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void aorii_text::destroy_freetype() {
|
||||
|
||||
}
|
||||
38
src/core/renderer/renderer_text.h
Normal file
38
src/core/renderer/renderer_text.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
#include "../misc/pixel.h"
|
||||
#include "misc/mapped_file.h"
|
||||
#include <unordered_map>
|
||||
|
||||
class renderer_texture_array;
|
||||
|
||||
class aorii_text {
|
||||
public:
|
||||
aorii_text();
|
||||
|
||||
~aorii_text();
|
||||
|
||||
static bool init_freetype();
|
||||
|
||||
static void destroy_freetype();
|
||||
|
||||
// 预缓存一组字符
|
||||
bool precache_characters(const std::u32string &characters) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 预缓存常用字符集
|
||||
void precache_common_characters() {
|
||||
precache_characters(COMMON_ASCII);
|
||||
precache_characters(COMMON_PUNCTUATION);
|
||||
precache_characters(COMMON_NUMBERS);
|
||||
precache_characters(COMMON_CHINESE);
|
||||
}
|
||||
private:
|
||||
renderer_texture_array *texture_array;
|
||||
|
||||
// 常用字符集定义
|
||||
static const std::u32string COMMON_ASCII; // ASCII字符
|
||||
static const std::u32string COMMON_PUNCTUATION; // 常用标点符号
|
||||
static const std::u32string COMMON_NUMBERS; // 数字
|
||||
static const std::u32string COMMON_CHINESE; // 常用汉字
|
||||
};
|
||||
12
src/core/window/mac/renderer_window_mac.mm
Normal file
12
src/core/window/mac/renderer_window_mac.mm
Normal file
@@ -0,0 +1,12 @@
|
||||
#include "window/renderer_window.h"
|
||||
|
||||
#include "LLGL/Platform/MacOS/MacOSNativeHandle.h"
|
||||
|
||||
void* renderer_window::get_native_handle() const {
|
||||
if (auto surface = get_surface()) {
|
||||
LLGL::NativeHandle native_handle;
|
||||
surface->GetNativeHandle(&native_handle, sizeof(LLGL::NativeHandle));
|
||||
return native_handle.responder;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
72
src/core/window/renderer_window.h
Normal file
72
src/core/window/renderer_window.h
Normal file
@@ -0,0 +1,72 @@
|
||||
#pragma once
|
||||
#include "renderer/renderer.h"
|
||||
#include "LLGL/SwapChain.h"
|
||||
#include "LLGL/Window.h"
|
||||
|
||||
#if MACOS
|
||||
#elif WINDOWS
|
||||
#include "LLGL/Platform/Win32/Win32NativeHandle.h"
|
||||
#elif LINUX
|
||||
#include "LLGL/Platform/Linux/LinuxNativeHandle.h"
|
||||
#endif
|
||||
|
||||
class renderer_window {
|
||||
friend class window_manager;
|
||||
public:
|
||||
using desc_type = LLGL::SwapChainDescriptor;
|
||||
|
||||
#if IS_MOBILE
|
||||
using surface_type = LLGL::Canvas;
|
||||
using event_listener = LLGL::Canvas::EventListener;
|
||||
#else
|
||||
using surface_type = LLGL::Window;
|
||||
using event_listener = LLGL::Window::EventListener;
|
||||
#endif
|
||||
|
||||
explicit renderer_window(const desc_type& in_desc);
|
||||
|
||||
virtual ~renderer_window();
|
||||
|
||||
void set_title(const std::wstring& in_title) const;
|
||||
|
||||
void close() const;
|
||||
|
||||
[[nodiscard]] auto get_surface() const { return surface; }
|
||||
|
||||
[[nodiscard]] void* get_native_handle() const;
|
||||
private:
|
||||
surface_type* surface = nullptr;
|
||||
LLGL::SwapChain* swap_chain = nullptr;
|
||||
};
|
||||
|
||||
inline renderer_window::renderer_window(const desc_type& in_desc) {
|
||||
swap_chain = aorii::get_renderer()->CreateSwapChain(in_desc);
|
||||
surface = static_cast<surface_type*>(&swap_chain->GetSurface());
|
||||
}
|
||||
|
||||
inline renderer_window::~renderer_window() { if (swap_chain) { aorii::get_renderer()->Release(*swap_chain); } }
|
||||
|
||||
inline void renderer_window::set_title(const std::wstring& in_title) const {
|
||||
if (const auto window = get_surface()) { window->SetTitle(in_title.c_str()); }
|
||||
}
|
||||
|
||||
inline void renderer_window::close() const {
|
||||
#if !IS_MOBILE
|
||||
if (const auto window = get_surface()) { window->Show(false); }
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !MACOS
|
||||
inline void* renderer_window::get_native_handle() const {
|
||||
#if !IS_MOBILE
|
||||
if (auto surface = get_surface()) {
|
||||
#if WINDOWS
|
||||
return native_handle.window;
|
||||
#elif LINUX
|
||||
return native_handle.window;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
57
src/core/window/window_manager.cpp
Normal file
57
src/core/window/window_manager.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
#include "window_manager.h"
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include "renderer_window.h"
|
||||
#include "renderer/renderer.h"
|
||||
|
||||
class manager_window_event_listener : public LLGL::Window::EventListener {
|
||||
public:
|
||||
explicit manager_window_event_listener(window_manager* in_manager) :
|
||||
manager(in_manager) {
|
||||
}
|
||||
protected:
|
||||
virtual void OnQuit(LLGL::Window& sender, bool& veto) override {
|
||||
EventListener::OnQuit(sender, veto);
|
||||
manager->on_window_close(sender);
|
||||
}
|
||||
|
||||
window_manager* manager;
|
||||
};
|
||||
|
||||
window_manager::~window_manager() {
|
||||
windows.clear();
|
||||
windows_to_remove.clear();
|
||||
}
|
||||
|
||||
std::weak_ptr<renderer_window> window_manager::create_window(const LLGL::SwapChainDescriptor& in_desc) {
|
||||
auto window = std::make_shared<renderer_window>(in_desc);
|
||||
#if !IS_MOBILE
|
||||
const auto& manager_listener = std::make_shared<manager_window_event_listener>(this);
|
||||
window->get_surface()->AddEventListener(manager_listener);
|
||||
#endif
|
||||
windows.push_back(window);
|
||||
return window;
|
||||
}
|
||||
|
||||
void window_manager::update() {
|
||||
windows_to_remove.clear();
|
||||
}
|
||||
|
||||
void window_manager::on_window_close(LLGL::Window& in_sender) {
|
||||
auto has_removed = std::ranges::remove_if(windows, [&in_sender](const std::shared_ptr<renderer_window>& w) {
|
||||
return w->get_surface() == &in_sender;
|
||||
});
|
||||
|
||||
if (has_removed.begin() != has_removed.end()) {
|
||||
windows_to_remove.push_back(*has_removed.begin());
|
||||
windows.erase(has_removed.begin(), has_removed.end());
|
||||
spdlog::info("Window begin close");
|
||||
} else {
|
||||
spdlog::error("Failed to close window!");
|
||||
}
|
||||
}
|
||||
|
||||
bool aorii::should_exit() {
|
||||
return s_window_manager->should_exit();
|
||||
}
|
||||
37
src/core/window/window_manager.h
Normal file
37
src/core/window/window_manager.h
Normal file
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
#include "renderer_window.h"
|
||||
|
||||
class renderer_window;
|
||||
|
||||
class window_manager {
|
||||
friend class manager_window_event_listener;
|
||||
public:
|
||||
~window_manager();
|
||||
|
||||
std::weak_ptr<renderer_window> create_window(const LLGL::SwapChainDescriptor& in_desc);
|
||||
|
||||
const auto& get_windows() const { return windows; }
|
||||
void update();
|
||||
|
||||
[[nodiscard]] bool should_exit() const {
|
||||
return windows.empty() && windows_to_remove.empty();
|
||||
}
|
||||
|
||||
private:
|
||||
void on_window_close(LLGL::Window& in_sender);
|
||||
std::vector<std::shared_ptr<renderer_window>> windows;
|
||||
std::vector<std::shared_ptr<renderer_window>> windows_to_remove;
|
||||
};
|
||||
|
||||
namespace aorii {
|
||||
inline window_manager* s_window_manager;
|
||||
inline void create_window_manager() { s_window_manager = new window_manager(); }
|
||||
inline void destroy_window_manager() { delete s_window_manager; }
|
||||
bool should_exit();
|
||||
|
||||
inline auto create_renderer_window(const LLGL::SwapChainDescriptor& in_desc) {
|
||||
return s_window_manager->create_window(in_desc);
|
||||
}
|
||||
|
||||
inline const auto& get_all_window() { return s_window_manager->get_windows(); }
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
project(aorii_renderer)
|
||||
|
||||
find_package(harfbuzz REQUIRED)
|
||||
find_package(Eigen3 REQUIRED)
|
||||
find_package(spdlog REQUIRED)
|
||||
find_package(glfw3 REQUIRED)
|
||||
find_package(Boost REQUIRED COMPONENTS flyweight)
|
||||
find_package(Freetype REQUIRED)
|
||||
|
||||
set(RENDERER_SOURCES "")
|
||||
retrieve_files(${CMAKE_CURRENT_SOURCE_DIR} RENDERER_SOURCES)
|
||||
|
||||
add_library(${PROJECT_NAME} STATIC ${RENDERER_SOURCES})
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC harfbuzz Eigen3::Eigen spdlog::spdlog glfw aorii_core msdfgen-full Boost::boost LLGL)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE NOMINMAX)
|
||||
add_os_definitions(${PROJECT_NAME})
|
||||
configure_glfw_native(${PROJECT_NAME})
|
||||
|
||||
# 添加编译shader的自定义命令
|
||||
if (NOT DEFINED SHADER_OUTPUT_DIR)
|
||||
set(SHADER_OUTPUT_DIR ${CMAKE_BINARY_DIR}/shaders CACHE PATH "Output directory for compiled shaders")
|
||||
message(STATUS "SHADER_OUTPUT_DIR not defined, using default: ${SHADER_OUTPUT_DIR}")
|
||||
endif ()
|
||||
function(compile_aorii_shader SHADER_FILE)
|
||||
compile_slang_shaders("${CMAKE_CURRENT_SOURCE_DIR}/shader/${SHADER_FILE}.slang" "vertex" "vertex_main")
|
||||
compile_slang_shaders("${CMAKE_CURRENT_SOURCE_DIR}/shader/${SHADER_FILE}.slang" "pixel" "pixel_main")
|
||||
endfunction()
|
||||
compile_aorii_shader(aorii_rect)
|
||||
compile_aorii_shader(aorii_rounded_rect)
|
||||
compile_aorii_shader(aorii_texture)
|
||||
compile_aorii_shader(aorii_segment)
|
||||
compile_aorii_shader(aorii_sdf_text)
|
||||
add_compile_shaders_target("compile_aorii_shaders" ${PROJECT_NAME})
|
||||
|
||||
# 如果需要编译example, 添加自定义命令用于拷贝shader文件
|
||||
if (BUILD_EXAMPLE)
|
||||
# 复制${SHADER_OUTPUT_DIR}文件到${CMAKE_CURRENT_BINARY_DIR}/example/resource/shaders
|
||||
set(SOURCE_DIR ${SHADER_OUTPUT_DIR})
|
||||
set(DEST_DIR ${CMAKE_BINARY_DIR}/example/resource/shaders)
|
||||
|
||||
# 添加自定义命令, 当外部目标compile_aorii_shaders被编译时, 将${SOURCE_DIR}文件复制到${DEST_DIR}
|
||||
add_custom_command(
|
||||
TARGET compile_aorii_shaders
|
||||
POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${DEST_DIR}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${SOURCE_DIR} ${DEST_DIR}
|
||||
COMMENT "Copying shaders to ${DEST_DIR}"
|
||||
)
|
||||
endif ()
|
||||
@@ -1,97 +0,0 @@
|
||||
#pragma once
|
||||
#include <d3d11.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include "dx_renderer.h"
|
||||
#include "core/renderer/renderer_buffer.h"
|
||||
|
||||
class dx_buffer : public renderer_buffer {
|
||||
public:
|
||||
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();
|
||||
int32_t byte_size = in_element_byte * in_size;
|
||||
// 对齐到16字节
|
||||
byte_size = (byte_size + 15) & ~15;
|
||||
|
||||
D3D11_BUFFER_DESC buffer_desc = {};
|
||||
buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
|
||||
buffer_desc.ByteWidth = byte_size;
|
||||
buffer_desc.BindFlags = get_dx_buffer_type();
|
||||
buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||
|
||||
auto hr = d3d_device->CreateBuffer(&buffer_desc, nullptr, &buffer);
|
||||
if (FAILED(hr)) {
|
||||
spdlog::critical("无法创建缓冲区: {0}", hr);
|
||||
}
|
||||
}
|
||||
|
||||
~dx_buffer() override { if (buffer) { buffer->Release(); } }
|
||||
|
||||
void* lock() override {
|
||||
const auto d3d_context = aorii::get_renderer<dx_renderer>()->get_d3d_context();
|
||||
D3D11_MAPPED_SUBRESOURCE mapped_resource;
|
||||
HRESULT hr = d3d_context->Map(buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource);
|
||||
if (SUCCEEDED(hr)) { return mapped_resource.pData; }
|
||||
return {};
|
||||
}
|
||||
void unlock() override {
|
||||
const auto d3d_context = aorii::get_renderer<dx_renderer>()->get_d3d_context();
|
||||
d3d_context->Unmap(buffer, 0);
|
||||
}
|
||||
|
||||
[[nodiscard]] unsigned int get_dx_buffer_type() const {
|
||||
switch (this->get_type()) {
|
||||
case buffer_type::VERTEX:
|
||||
return D3D11_BIND_VERTEX_BUFFER;
|
||||
case buffer_type::INDEX:
|
||||
return D3D11_BIND_INDEX_BUFFER;
|
||||
case buffer_type::CONSTANT:
|
||||
return D3D11_BIND_CONSTANT_BUFFER;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
[[nodiscard]] void* get_native_handle() override {
|
||||
return buffer;
|
||||
}
|
||||
protected:
|
||||
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();
|
||||
// 获取原始缓冲区的描述
|
||||
D3D11_BUFFER_DESC old_desc = {};
|
||||
if (buffer) {
|
||||
buffer->GetDesc(&old_desc);
|
||||
}
|
||||
int32_t byte_size = element_byte * new_count;
|
||||
// 对齐到16字节
|
||||
byte_size = (byte_size + 15) & ~15;
|
||||
|
||||
D3D11_BUFFER_DESC buffer_desc = old_desc;
|
||||
buffer_desc.ByteWidth = byte_size;
|
||||
ID3D11Buffer* new_buffer = nullptr;
|
||||
auto hr = d3d_device->CreateBuffer(&buffer_desc, nullptr, &new_buffer);
|
||||
if (FAILED(hr)) {
|
||||
spdlog::critical("无法创建缓冲区: {0}", hr);
|
||||
return;
|
||||
}
|
||||
if (new_buffer && buffer) {
|
||||
// 计算要复制的实际大小(取原始大小和新大小的较小值)
|
||||
const auto copy_size = std::min(old_desc.ByteWidth, buffer_desc.ByteWidth);
|
||||
// 复制旧数据到新缓冲区
|
||||
D3D11_BOX source_region;
|
||||
source_region.left = 0;
|
||||
source_region.right = copy_size;
|
||||
source_region.top = 0;
|
||||
source_region.bottom = 1;
|
||||
source_region.front = 0;
|
||||
source_region.back = 1;
|
||||
d3d_context->CopySubresourceRegion(new_buffer, 0, 0, 0, 0, buffer, 0, &source_region);
|
||||
}
|
||||
if (buffer)
|
||||
buffer->Release();
|
||||
buffer = new_buffer;
|
||||
}
|
||||
private:
|
||||
ID3D11Buffer* buffer = nullptr;
|
||||
};
|
||||
@@ -1,116 +0,0 @@
|
||||
#include "dx_renderer.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include "dx_buffer.h"
|
||||
#include "dx_texture.h"
|
||||
#include "dx_texture_array.h"
|
||||
#include "dx_window.h"
|
||||
#include "core/window/window_manager.h"
|
||||
#include "spdlog/spdlog.h"
|
||||
|
||||
bool dx_renderer::init() {
|
||||
if (!glfwInit()) return false;
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||
|
||||
if (!create_device()) return false;
|
||||
|
||||
D3D11_BLEND_DESC blend_desc = {};
|
||||
blend_desc.RenderTarget[0].BlendEnable = TRUE;
|
||||
blend_desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
|
||||
blend_desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
|
||||
blend_desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
|
||||
blend_desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
|
||||
blend_desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
|
||||
blend_desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
|
||||
blend_desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
|
||||
|
||||
auto hr = device->CreateBlendState(&blend_desc, &blend_state);
|
||||
if (FAILED(hr)) {
|
||||
spdlog::critical("无法创建混合状态, 错误: {0}", hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
rect_p.init();
|
||||
rounded_rect_p.init();
|
||||
texture_p.init();
|
||||
segment_p.init();
|
||||
text_p.init();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void dx_renderer::destroy() {
|
||||
if (blend_state) blend_state->Release();
|
||||
rect_p.destroy();
|
||||
rounded_rect_p.destroy();
|
||||
texture_p.destroy();
|
||||
glfwTerminate();
|
||||
}
|
||||
|
||||
bool dx_renderer::render() {
|
||||
const auto& all_window = aorii::get_all_window();
|
||||
for (const auto& window : all_window) {
|
||||
window->begin_frame();
|
||||
window->end_frame();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
renderer_texture* dx_renderer::create_texture(uint32_t in_size_width, uint32_t in_size_height, texture_format in_format, device_memory_type in_memory_type) {
|
||||
return new dx_texture({ in_size_width, in_size_height }, in_format, in_memory_type);
|
||||
}
|
||||
|
||||
renderer_texture_array* dx_renderer::create_texture_array(uint32_t in_size_width, uint32_t in_size_height, uint32_t in_count, texture_format in_format, device_memory_type in_memory_type) {
|
||||
return new dx_texture_array({ in_size_width, in_size_height }, in_format, in_count, in_memory_type);
|
||||
}
|
||||
|
||||
Eigen::Matrix4f dx_renderer::make_projection_matrix(const Eigen::Vector2i& size) {
|
||||
// 创建一个单位矩阵
|
||||
Eigen::Matrix4f matrix = Eigen::Matrix4f::Identity();
|
||||
|
||||
// 缩放因子
|
||||
const float scale_x = 2.0f / static_cast<float>(size.x());
|
||||
const float scale_y = -2.0f / static_cast<float>(size.y()); // Y轴翻转,因为窗口坐标系Y轴向下
|
||||
|
||||
// 平移因子
|
||||
constexpr float translate_x = -1.0f;
|
||||
constexpr float translate_y = 1.0f;
|
||||
|
||||
// 设置缩放
|
||||
matrix(0, 0) = scale_x;
|
||||
matrix(1, 1) = scale_y;
|
||||
|
||||
// 设置平移
|
||||
matrix(0, 3) = translate_x;
|
||||
matrix(1, 3) = translate_y;
|
||||
|
||||
return matrix;
|
||||
}
|
||||
|
||||
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, int32_t in_element_byte, int32_t in_size) {
|
||||
return new dx_buffer(in_buffer_type, in_element_byte, in_size);
|
||||
}
|
||||
|
||||
renderer_window* dx_renderer::create_window() {
|
||||
return new dx_window();
|
||||
}
|
||||
|
||||
bool dx_renderer::create_device() {
|
||||
constexpr D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_11_1 };
|
||||
#ifdef DEBUG
|
||||
int flags = D3D11_CREATE_DEVICE_DEBUG;
|
||||
#else
|
||||
int flags = 0;
|
||||
#endif
|
||||
const auto result = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, flags, featureLevels, 2,
|
||||
D3D11_SDK_VERSION, &device, nullptr, &context);
|
||||
return SUCCEEDED(result);
|
||||
}
|
||||
@@ -1,184 +0,0 @@
|
||||
#pragma once
|
||||
#include <d3d11.h>
|
||||
|
||||
#include "core/renderer/renderer.h"
|
||||
#include "pipeline/dx_rect_pipeline.h"
|
||||
#include "pipeline/dx_rounded_rect_pipeline.h"
|
||||
#include "pipeline/dx_sdf_text_pipeline.h"
|
||||
#include "pipeline/dx_segment_pipeline.h"
|
||||
#include "pipeline/dx_texture_pipeline.h"
|
||||
|
||||
class dx_window;
|
||||
|
||||
class dx_renderer : public renderer {
|
||||
public:
|
||||
bool init() override;
|
||||
void destroy() override;
|
||||
bool render() override;
|
||||
|
||||
renderer_texture* create_texture(uint32_t in_size_width, uint32_t in_size_height, texture_format in_format, device_memory_type in_memory_type) override;
|
||||
renderer_texture_array* create_texture_array(uint32_t in_size_width, uint32_t in_size_height, uint32_t in_count, texture_format in_format, device_memory_type in_memory_type) override;
|
||||
|
||||
[[nodiscard]] ID3D11Device* get_d3d_device() const { return device; }
|
||||
[[nodiscard]] ID3D11DeviceContext* get_d3d_context() const { return context; }
|
||||
|
||||
rect_pipeline* get_rect_pipeline() override { return &rect_p; }
|
||||
rounded_rect_pipeline* get_rounded_rect_pipeline() override { return &rounded_rect_p; }
|
||||
texture_pipeline* get_texture_pipeline() override { return &texture_p; }
|
||||
segment_pipeline* get_segment_pipeline() override { return &segment_p; }
|
||||
sdf_text_pipeline* get_text_pipeline() override { return &text_p; }
|
||||
|
||||
Eigen::Matrix4f make_projection_matrix(const Eigen::Vector2i& size) override;
|
||||
|
||||
[[nodiscard]] ID3D11BlendState* get_blend_state() const { return blend_state; }
|
||||
|
||||
std::vector<int8_t> load_shader(const std::string& shader_name) 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;
|
||||
|
||||
bool create_device();
|
||||
|
||||
ID3D11Device* device = nullptr;
|
||||
ID3D11DeviceContext* context = nullptr;
|
||||
ID3D11BlendState* blend_state = nullptr;
|
||||
|
||||
dx_rect_pipeline rect_p;
|
||||
dx_rounded_rect_pipeline rounded_rect_p;
|
||||
dx_texture_pipeline texture_p;
|
||||
dx_segment_pipeline segment_p;
|
||||
dx_sdf_text_pipeline text_p;
|
||||
};
|
||||
|
||||
inline DXGI_FORMAT get_dxgi_format(texture_format format) {
|
||||
switch (format) {
|
||||
// 8-bit formats
|
||||
case texture_format::R8_UNORM:
|
||||
return DXGI_FORMAT_R8_UNORM;
|
||||
case texture_format::R8_SNORM:
|
||||
return DXGI_FORMAT_R8_SNORM;
|
||||
case texture_format::R8_UINT:
|
||||
return DXGI_FORMAT_R8_UINT;
|
||||
case texture_format::R8_SINT:
|
||||
return DXGI_FORMAT_R8_SINT;
|
||||
|
||||
// 16-bit formats
|
||||
case texture_format::RG8_UNORM:
|
||||
return DXGI_FORMAT_R8G8_UNORM;
|
||||
case texture_format::RG8_SNORM:
|
||||
return DXGI_FORMAT_R8G8_SNORM;
|
||||
case texture_format::RG8_UINT:
|
||||
return DXGI_FORMAT_R8G8_UINT;
|
||||
case texture_format::RG8_SINT:
|
||||
return DXGI_FORMAT_R8G8_SINT;
|
||||
|
||||
// 24-bit formats
|
||||
case texture_format::RGB8_UNORM:
|
||||
return DXGI_FORMAT_B8G8R8X8_UNORM; // Note: DXGI doesn't have a direct RGB8 format
|
||||
|
||||
// 32-bit formats
|
||||
case texture_format::RGBA8_UNORM:
|
||||
return DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
case texture_format::RGBA8_SNORM:
|
||||
return DXGI_FORMAT_R8G8B8A8_SNORM;
|
||||
case texture_format::RGBA8_UINT:
|
||||
return DXGI_FORMAT_R8G8B8A8_UINT;
|
||||
case texture_format::RGBA8_SINT:
|
||||
return DXGI_FORMAT_R8G8B8A8_SINT;
|
||||
|
||||
// SRGB formats
|
||||
case texture_format::SRGB8:
|
||||
return DXGI_FORMAT_B8G8R8X8_UNORM_SRGB; // Note: Approximation
|
||||
case texture_format::SRGB8_ALPHA8:
|
||||
return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
|
||||
|
||||
// 16-bit float formats
|
||||
case texture_format::R16_FLOAT:
|
||||
return DXGI_FORMAT_R16_FLOAT;
|
||||
case texture_format::RG16_FLOAT:
|
||||
return DXGI_FORMAT_R16G16_FLOAT;
|
||||
case texture_format::RGBA16_FLOAT:
|
||||
return DXGI_FORMAT_R16G16B16A16_FLOAT;
|
||||
|
||||
// 32-bit float formats
|
||||
case texture_format::R32_FLOAT:
|
||||
return DXGI_FORMAT_R32_FLOAT;
|
||||
case texture_format::RG32_FLOAT:
|
||||
return DXGI_FORMAT_R32G32_FLOAT;
|
||||
case texture_format::RGB32_FLOAT:
|
||||
return DXGI_FORMAT_R32G32B32_FLOAT;
|
||||
case texture_format::RGBA32_FLOAT:
|
||||
return DXGI_FORMAT_R32G32B32A32_FLOAT;
|
||||
|
||||
// Integer formats
|
||||
case texture_format::R16_UINT:
|
||||
return DXGI_FORMAT_R16_UINT;
|
||||
case texture_format::R16_SINT:
|
||||
return DXGI_FORMAT_R16_SINT;
|
||||
case texture_format::RG16_UINT:
|
||||
return DXGI_FORMAT_R16G16_UINT;
|
||||
case texture_format::RG16_SINT:
|
||||
return DXGI_FORMAT_R16G16_SINT;
|
||||
case texture_format::RGBA16_UINT:
|
||||
return DXGI_FORMAT_R16G16B16A16_UINT;
|
||||
case texture_format::RGBA16_SINT:
|
||||
return DXGI_FORMAT_R16G16B16A16_SINT;
|
||||
case texture_format::R32_UINT:
|
||||
return DXGI_FORMAT_R32_UINT;
|
||||
case texture_format::R32_SINT:
|
||||
return DXGI_FORMAT_R32_SINT;
|
||||
case texture_format::RG32_UINT:
|
||||
return DXGI_FORMAT_R32G32_UINT;
|
||||
case texture_format::RG32_SINT:
|
||||
return DXGI_FORMAT_R32G32_SINT;
|
||||
case texture_format::RGBA32_UINT:
|
||||
return DXGI_FORMAT_R32G32B32A32_UINT;
|
||||
case texture_format::RGBA32_SINT:
|
||||
return DXGI_FORMAT_R32G32B32A32_SINT;
|
||||
|
||||
// Depth/stencil formats
|
||||
case texture_format::D16_UNORM:
|
||||
return DXGI_FORMAT_D16_UNORM;
|
||||
case texture_format::D24_UNORM_S8_UINT:
|
||||
return DXGI_FORMAT_D24_UNORM_S8_UINT;
|
||||
case texture_format::D32_FLOAT:
|
||||
return DXGI_FORMAT_D32_FLOAT;
|
||||
case texture_format::D32_FLOAT_S8X24_UINT:
|
||||
return DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
|
||||
|
||||
// Compressed formats
|
||||
case texture_format::BC1_UNORM:
|
||||
return DXGI_FORMAT_BC1_UNORM;
|
||||
case texture_format::BC1_UNORM_SRGB:
|
||||
return DXGI_FORMAT_BC1_UNORM_SRGB;
|
||||
case texture_format::BC2_UNORM:
|
||||
return DXGI_FORMAT_BC2_UNORM;
|
||||
case texture_format::BC2_UNORM_SRGB:
|
||||
return DXGI_FORMAT_BC2_UNORM_SRGB;
|
||||
case texture_format::BC3_UNORM:
|
||||
return DXGI_FORMAT_BC3_UNORM;
|
||||
case texture_format::BC3_UNORM_SRGB:
|
||||
return DXGI_FORMAT_BC3_UNORM_SRGB;
|
||||
case texture_format::BC4_UNORM:
|
||||
return DXGI_FORMAT_BC4_UNORM;
|
||||
case texture_format::BC4_SNORM:
|
||||
return DXGI_FORMAT_BC4_SNORM;
|
||||
case texture_format::BC5_UNORM:
|
||||
return DXGI_FORMAT_BC5_UNORM;
|
||||
case texture_format::BC5_SNORM:
|
||||
return DXGI_FORMAT_BC5_SNORM;
|
||||
case texture_format::BC6H_UF16:
|
||||
return DXGI_FORMAT_BC6H_UF16;
|
||||
case texture_format::BC6H_SF16:
|
||||
return DXGI_FORMAT_BC6H_SF16;
|
||||
case texture_format::BC7_UNORM:
|
||||
return DXGI_FORMAT_BC7_UNORM;
|
||||
case texture_format::BC7_UNORM_SRGB:
|
||||
return DXGI_FORMAT_BC7_UNORM_SRGB;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
return DXGI_FORMAT_UNKNOWN;
|
||||
}
|
||||
}
|
||||
@@ -1,222 +0,0 @@
|
||||
#include "dx_texture.h"
|
||||
|
||||
#include "dx_renderer.h"
|
||||
#include "misc/scope_exit.h"
|
||||
|
||||
int get_cpu_access_flag(device_memory_type in_memory_type) {
|
||||
switch (in_memory_type) {
|
||||
case device_memory_type::GPU:
|
||||
return 0;
|
||||
case device_memory_type::SHARED:
|
||||
return D3D11_CPU_ACCESS_WRITE;
|
||||
case device_memory_type::CPU:
|
||||
return D3D11_CPU_ACCESS_WRITE;
|
||||
default:
|
||||
return D3D11_CPU_ACCESS_WRITE;
|
||||
}
|
||||
}
|
||||
|
||||
dx_texture::dx_texture(const Eigen::Vector2i& size, const texture_format format, device_memory_type in_memory_type, uint32_t count) : renderer_texture(format) {
|
||||
memory_type = in_memory_type;
|
||||
create_texture(size, format, in_memory_type, count);
|
||||
}
|
||||
|
||||
dx_texture::~dx_texture() {
|
||||
release_texture();
|
||||
}
|
||||
|
||||
void* dx_texture::lock(uint32_t* out_row_pitch) {
|
||||
return lock(0, out_row_pitch);
|
||||
}
|
||||
|
||||
void dx_texture::unlock() {
|
||||
return unlock(0);
|
||||
}
|
||||
|
||||
void* dx_texture::lock(uint32_t index, uint32_t* out_row_pitch) {
|
||||
auto r = aorii::get_renderer<dx_renderer>();
|
||||
auto hr = r->get_d3d_device()->CreateTexture2D(&upload_desc, nullptr, &upload_texture);
|
||||
if (FAILED(hr)) {
|
||||
spdlog::critical("无法创建上传纹理, 错误: 0x{:08X}", static_cast<unsigned int>(hr));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
D3D11_MAPPED_SUBRESOURCE mappedResource;
|
||||
const auto context = aorii::get_renderer<dx_renderer>()->get_d3d_context();
|
||||
hr = context->Map(upload_texture, index, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
|
||||
if (FAILED(hr)) {
|
||||
spdlog::critical("无法映射纹理, 错误: 0x{:08X}", static_cast<unsigned int>(hr));
|
||||
return nullptr;
|
||||
}
|
||||
if (out_row_pitch) *out_row_pitch = mappedResource.RowPitch;
|
||||
return mappedResource.pData;
|
||||
}
|
||||
|
||||
void dx_texture::unlock(uint32_t index) const {
|
||||
const auto context = aorii::get_renderer<dx_renderer>()->get_d3d_context();
|
||||
context->Unmap(upload_texture, index);
|
||||
// 复制到目标纹理
|
||||
context->CopyResource(m_texture, upload_texture);
|
||||
}
|
||||
|
||||
void dx_texture::update_subresource(const Eigen::AlignedBox2i& in_area, const void* in_buffer, const uint32_t in_row_pitch) {
|
||||
update_subresource(0, in_area, in_buffer, in_row_pitch);
|
||||
}
|
||||
|
||||
void dx_texture::update_subresource(uint32_t index, const Eigen::AlignedBox2i& in_area, const void* in_buffer, const uint32_t in_row_pitch) {
|
||||
auto r = aorii::get_renderer<dx_renderer>();
|
||||
const auto context = r->get_d3d_context();
|
||||
auto device = r->get_d3d_device();
|
||||
const auto& size = in_area.sizes();
|
||||
|
||||
// 更新上传纹理描述符
|
||||
upload_desc.Width = size.x();
|
||||
upload_desc.Height = size.y();
|
||||
|
||||
// 定义目标区域
|
||||
D3D11_BOX box{};
|
||||
box.left = in_area.min().x();
|
||||
box.top = in_area.min().y();
|
||||
box.right = in_area.max().x();
|
||||
box.bottom = in_area.max().y();
|
||||
box.front = 0;
|
||||
box.back = 1;
|
||||
|
||||
// 定义源区域
|
||||
D3D11_BOX src_box{};
|
||||
src_box.left = 0;
|
||||
src_box.top = 0;
|
||||
src_box.right = size.x();
|
||||
src_box.bottom = size.y();
|
||||
src_box.front = 0;
|
||||
src_box.back = 1;
|
||||
|
||||
// 创建临时上传纹理
|
||||
auto hr = device->CreateTexture2D(&upload_desc, nullptr, &upload_texture);
|
||||
if (FAILED(hr)) {
|
||||
spdlog::critical("无法创建上传纹理, 错误: 0x{:08X}", static_cast<unsigned int>(hr));
|
||||
return;
|
||||
}
|
||||
ON_SCOPE_EXIT{
|
||||
// 删除临时纹理
|
||||
upload_texture->Release();
|
||||
upload_texture = nullptr;
|
||||
};
|
||||
|
||||
// 映射上传纹理
|
||||
D3D11_MAPPED_SUBRESOURCE mapped;
|
||||
hr = context->Map(upload_texture, 0, D3D11_MAP_WRITE, 0, &mapped);
|
||||
if (FAILED(hr)) {
|
||||
spdlog::critical("无法映射上传纹理, 错误: 0x{:08X}", static_cast<unsigned int>(hr));
|
||||
return;
|
||||
}
|
||||
|
||||
// 复制数据到上传纹理
|
||||
const auto src_data = static_cast<const uint8_t*>(in_buffer);
|
||||
const auto dst_data = static_cast<uint8_t*>(mapped.pData);
|
||||
|
||||
for (int y = 0; y < size.y(); ++y) {
|
||||
memcpy(
|
||||
dst_data + mapped.RowPitch * y,
|
||||
src_data + in_row_pitch * y,
|
||||
size.x()
|
||||
);
|
||||
}
|
||||
|
||||
// 解除映射
|
||||
context->Unmap(upload_texture, 0);
|
||||
|
||||
// 复制到目标纹理
|
||||
context->CopySubresourceRegion(
|
||||
m_texture, // 目标纹理
|
||||
index, // 目标子资源索引
|
||||
box.left, box.top, 0, // 目标位置
|
||||
upload_texture, // 源纹理
|
||||
0, // 源子资源索引
|
||||
&src_box // 源区域
|
||||
);
|
||||
}
|
||||
|
||||
bool dx_texture::resize(const Eigen::Vector2i& size) {
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
m_texture->GetDesc(&desc);
|
||||
if (desc.Width == size.x() && desc.Height == size.y()) {
|
||||
return true;
|
||||
}
|
||||
return create_texture(size, get_format(), memory_type, get_count());
|
||||
}
|
||||
|
||||
Eigen::Vector2i dx_texture::size() {
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
m_texture->GetDesc(&desc);
|
||||
return { desc.Width, desc.Height };
|
||||
}
|
||||
|
||||
uint32_t dx_texture::get_count() const {
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
m_texture->GetDesc(&desc);
|
||||
return desc.ArraySize;
|
||||
}
|
||||
|
||||
void dx_texture::set_count(const uint32_t in_count) {
|
||||
if (in_count == get_count()) {
|
||||
return;
|
||||
}
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
m_texture->GetDesc(&desc);
|
||||
desc.ArraySize = in_count;
|
||||
create_texture({ desc.Width, desc.Height }, get_format(), memory_type, in_count);
|
||||
}
|
||||
|
||||
bool dx_texture::create_texture(const Eigen::Vector2i& in_size, texture_format in_format, device_memory_type in_memory_type, uint32_t in_count) {
|
||||
// 释放旧资源
|
||||
release_texture();
|
||||
|
||||
// 创建新资源
|
||||
auto d3d_device = aorii::get_renderer<dx_renderer>()->get_d3d_device();
|
||||
D3D11_TEXTURE2D_DESC desc = {};
|
||||
desc.Width = in_size.x();
|
||||
desc.Height = in_size.y();
|
||||
desc.MipLevels = 1;
|
||||
desc.ArraySize = in_count;
|
||||
desc.Format = get_dxgi_format(in_format);
|
||||
desc.SampleDesc.Count = 1;
|
||||
desc.SampleDesc.Quality = 0;
|
||||
desc.Usage = D3D11_USAGE_DEFAULT;
|
||||
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
|
||||
desc.CPUAccessFlags = get_cpu_access_flag(in_memory_type);
|
||||
desc.MiscFlags = 0;
|
||||
auto hr = d3d_device->CreateTexture2D(&desc, nullptr, &m_texture);
|
||||
if (FAILED(hr)) {
|
||||
spdlog::critical("无法创建纹理, 错误: 0x{:08X}", static_cast<unsigned int>(hr));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 创建临时的上传纹理
|
||||
upload_desc = desc;
|
||||
upload_desc.ArraySize = 1;
|
||||
upload_desc.Usage = D3D11_USAGE_STAGING; // 用于CPU到GPU的传输
|
||||
upload_desc.BindFlags = 0;
|
||||
upload_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc = {};
|
||||
srv_desc.Format = desc.Format;
|
||||
srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
||||
srv_desc.Texture2D.MostDetailedMip = 0;
|
||||
srv_desc.Texture2D.MipLevels = 1;
|
||||
hr = d3d_device->CreateShaderResourceView(m_texture, &srv_desc, &srv);
|
||||
if (FAILED(hr)) {
|
||||
spdlog::critical("无法创建着色器资源视图, 错误: 0x{:08X}", static_cast<unsigned int>(hr));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void dx_texture::release_texture() {
|
||||
if (srv) srv->Release();
|
||||
if (m_texture) m_texture->Release();
|
||||
if (upload_texture) upload_texture->Release();
|
||||
srv = nullptr;
|
||||
m_texture = nullptr;
|
||||
upload_texture = nullptr;
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
#pragma once
|
||||
#include <d3d11.h>
|
||||
#include <memory>
|
||||
|
||||
#include "core/renderer/renderer_texture.h"
|
||||
|
||||
// DX11纹理
|
||||
class dx_texture : public renderer_texture {
|
||||
public:
|
||||
dx_texture(const Eigen::Vector2i& size, texture_format format, device_memory_type in_memory_type, uint32_t count = 1);
|
||||
~dx_texture() override;
|
||||
|
||||
void* lock(uint32_t* out_row_pitch) override;
|
||||
void unlock() override;
|
||||
|
||||
void* lock(uint32_t index, uint32_t* out_row_pitch);
|
||||
void unlock(uint32_t index) const;
|
||||
|
||||
void update_subresource(const Eigen::AlignedBox2i& in_area, const void* in_buffer, uint32_t in_row_pitch) override;
|
||||
void update_subresource(uint32_t index, const Eigen::AlignedBox2i& in_area, const void* in_buffer, uint32_t in_row_pitch);
|
||||
|
||||
bool resize(const Eigen::Vector2i& size) override;
|
||||
Eigen::Vector2i size() override;
|
||||
|
||||
[[nodiscard]] ID3D11ShaderResourceView* get_srv() const { return srv; }
|
||||
void* get_native_handle() override { return m_texture; }
|
||||
void* get_shader_resource_view() override { return srv; }
|
||||
|
||||
[[nodiscard]] uint32_t get_count() const;
|
||||
void set_count(uint32_t in_count);
|
||||
private:
|
||||
bool create_texture(const Eigen::Vector2i& in_size, texture_format in_format, device_memory_type in_memory_type, uint32_t in_count = 1);
|
||||
void release_texture();
|
||||
|
||||
ID3D11Texture2D* m_texture{};
|
||||
ID3D11ShaderResourceView* srv{};
|
||||
device_memory_type memory_type;
|
||||
|
||||
D3D11_TEXTURE2D_DESC upload_desc;
|
||||
ID3D11Texture2D* upload_texture{};
|
||||
};
|
||||
@@ -1 +0,0 @@
|
||||
#include "dx_texture_array.h"
|
||||
@@ -1,32 +0,0 @@
|
||||
#pragma once
|
||||
#include "dx_texture.h"
|
||||
#include "core/renderer/renderer_texture_array.h"
|
||||
|
||||
class dx_texture;
|
||||
|
||||
class dx_texture_array : public renderer_texture_array {
|
||||
public:
|
||||
dx_texture_array(const Eigen::Vector2i& size, texture_format format, const uint32_t count, device_memory_type in_memory_type): renderer_texture_array(format) {
|
||||
texture = new dx_texture(size, format, in_memory_type, count);
|
||||
}
|
||||
~dx_texture_array() override { delete texture; }
|
||||
|
||||
void* lock(const uint32_t index, uint32_t* out_row_pitch) override { return texture->lock(index, out_row_pitch); }
|
||||
void unlock(const uint32_t index) override { texture->unlock(index); }
|
||||
void update_subresource(const uint32_t index, const Eigen::AlignedBox2i& in_area, const void* in_buffer, uint32_t in_buffer_size) override {
|
||||
texture->update_subresource(index, in_area, in_buffer, in_buffer_size);
|
||||
}
|
||||
|
||||
bool resize(const Eigen::Vector2i& size) override { return texture->resize(size); }
|
||||
Eigen::Vector2i size() override { return texture->size(); }
|
||||
|
||||
void* get_native_handle() override { return texture->get_native_handle(); }
|
||||
void* get_shader_resource_view() override { return texture->get_shader_resource_view(); }
|
||||
|
||||
[[nodiscard]] uint32_t get_count() override { return texture->get_count(); }
|
||||
protected:
|
||||
void on_set_count(const uint32_t in_count) override { texture->set_count(in_count); }
|
||||
|
||||
private:
|
||||
dx_texture* texture;
|
||||
};
|
||||
@@ -1,182 +0,0 @@
|
||||
#include "dx_window.h"
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include "dx_renderer.h"
|
||||
#include "core/pixel_format/pixel.h"
|
||||
#include "core/renderer/renderer_text.h"
|
||||
#include "core/renderer/renderer_texture.h"
|
||||
#include "misc/scope_exit.h"
|
||||
|
||||
using namespace aorii;
|
||||
|
||||
renderer_texture* test_texture = nullptr;
|
||||
// text_font* text = nullptr;
|
||||
wchar_t current_char = u'a';
|
||||
void delta_char_texture(int in_delta) {
|
||||
current_char -= in_delta;
|
||||
// current_char = std::clamp(current_char, 33, 126);
|
||||
// const auto& character = text->glyphs[current_char];
|
||||
// test_texture = character.glyph_texture;
|
||||
}
|
||||
void on_mouse_scroll(GLFWwindow* window, double xoffset, double yoffset) {
|
||||
delta_char_texture(yoffset);
|
||||
}
|
||||
|
||||
bool dx_window::create_surface(GLFWwindow* in_window) {
|
||||
auto dx = aorii::get_renderer<dx_renderer>();
|
||||
const auto d3d_device = dx->get_d3d_device();
|
||||
|
||||
IDXGIDevice* dxgi_device = nullptr;
|
||||
auto hr = d3d_device->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void**>(&dxgi_device));
|
||||
if (FAILED(hr)) {
|
||||
spdlog::critical("无法获取IDXGIDevice, 错误: {0}", hr);
|
||||
return false;
|
||||
}
|
||||
ON_SCOPE_EXIT{
|
||||
if (dxgi_device) dxgi_device->Release();
|
||||
};
|
||||
|
||||
IDXGIAdapter* dxgi_adapter = nullptr;
|
||||
hr = dxgi_device->GetAdapter(&dxgi_adapter);
|
||||
if (FAILED(hr)) {
|
||||
spdlog::critical("无法获取IDXGIAdapter, 错误: {0}", hr);
|
||||
return false;
|
||||
}
|
||||
ON_SCOPE_EXIT{
|
||||
if (dxgi_adapter) dxgi_adapter->Release();
|
||||
};
|
||||
|
||||
IDXGIFactory2* dxgi_factory = nullptr;
|
||||
hr = dxgi_adapter->GetParent(__uuidof(IDXGIFactory2), reinterpret_cast<void**>(&dxgi_factory));
|
||||
if (FAILED(hr)) {
|
||||
spdlog::critical("无法获取IDXGIFactory, 错误: {0}", hr);
|
||||
return false;
|
||||
}
|
||||
ON_SCOPE_EXIT{
|
||||
if (dxgi_factory) dxgi_factory->Release();
|
||||
};
|
||||
|
||||
DXGI_SWAP_CHAIN_DESC1 sd = {};
|
||||
sd.Width = 0; // 使用窗口宽度
|
||||
sd.Height = 0; // 使用窗口高度
|
||||
sd.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
sd.SampleDesc.Count = 1;
|
||||
sd.SampleDesc.Quality = 0;
|
||||
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
sd.BufferCount = 2;
|
||||
sd.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
|
||||
sd.Flags = 0;
|
||||
|
||||
const auto hwnd = static_cast<HWND>(get_window_handle());
|
||||
hr = dxgi_factory->CreateSwapChainForHwnd(d3d_device, hwnd, &sd, nullptr, nullptr, &swap_chain);
|
||||
if (FAILED(hr)) {
|
||||
spdlog::critical("无法创建交换链, 错误: {0}", hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
context.init();
|
||||
|
||||
hr = build_render_target_view();
|
||||
if (FAILED(hr)) {
|
||||
spdlog::critical("无法创建渲染模板视图, 错误: {0}", hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
// test_texture = dx->load_image(R"(D:\69054578_p0.jpg)", texture_format::RGBA8_UNORM);
|
||||
glfwSetScrollCallback(get_glfw_window(), on_mouse_scroll);
|
||||
// text = aorii_text::load_font("C:/Windows/Fonts/simsunb.ttf", 32);
|
||||
// delta_char_texture(0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void dx_window::begin_frame() {
|
||||
glfwMakeContextCurrent(get_glfw_window());
|
||||
const auto render = aorii::get_renderer<dx_renderer>();
|
||||
const auto d3d_context = render->get_d3d_context();
|
||||
|
||||
d3d_context->OMSetRenderTargets(1, &render_target_view, nullptr);
|
||||
d3d_context->OMSetBlendState(render->get_blend_state(), nullptr, 0xffffffff);
|
||||
d3d_context->ClearRenderTargetView(render_target_view, clear_color);
|
||||
context.set_projection_matrix(projection_matrix, get_framebuffer_size());
|
||||
|
||||
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()) * 45;
|
||||
context.draw_rounded_rectangle({ 500, 500 }, { 100, 400 }, { 1, 0, 0, 1 }, angle, {10, 20, 30, 40});
|
||||
|
||||
double mouse_x, mouse_y;
|
||||
glfwGetCursorPos(get_glfw_window(), &mouse_x, &mouse_y);
|
||||
// auto height = sin(get_total_time().count()) * 100;
|
||||
// context.draw_line( { 600, 600 }, { mouse_x, mouse_y }, { 1, 0, 1, 1 }, thickness);
|
||||
|
||||
// if (test_texture) context.draw_texture({ 0.f, 0.f }, test_texture->size().cast<float>(), test_texture);
|
||||
// context.draw_string({0, 0}, U"你好,世界!全是水群大师\n测试换行\n测试Unicode: 😀\nТест по русскому языку\nテスト日本語", 32, {0, 0, 0, 1});
|
||||
float font_height = 64;
|
||||
context.draw_string({0, 100}, U"你好,世界!\nТест по русскому языку\nテスト", font_height, {0, 0, 0, 1});
|
||||
context.draw_rectangle({ 0, 100 }, { 2048, 1 }, { 1, 0, 1, 1 });
|
||||
context.draw_rectangle({ 0, 100 + font_height }, { 2048, 1 }, { 1, 0, 1, 1 });
|
||||
context.draw_rectangle({ 0, 100 + font_height * 2 }, { 2048, 1 }, { 1, 0, 1, 1 });
|
||||
context.draw_rectangle({ 0, 100 + font_height * 3 }, { 2048, 1 }, { 1, 0, 1, 1 });
|
||||
|
||||
context.flush();
|
||||
|
||||
swap_chain->Present(1, 0);
|
||||
}
|
||||
|
||||
void dx_window::end_frame() {
|
||||
|
||||
}
|
||||
|
||||
void dx_window::on_resize(const Eigen::Vector2i& in_size) {
|
||||
if (in_size.isZero())
|
||||
return;
|
||||
if (render_target_view) {
|
||||
render_target_view->Release();
|
||||
render_target_view = nullptr;
|
||||
}
|
||||
|
||||
auto hr = swap_chain->ResizeBuffers(0, in_size.x(), in_size.y(), DXGI_FORMAT_UNKNOWN, 0);
|
||||
if (FAILED(hr)) {
|
||||
spdlog::critical("Failed to resize window. Error: {0}", hr);
|
||||
return;
|
||||
}
|
||||
build_render_target_view();
|
||||
}
|
||||
|
||||
HRESULT dx_window::build_render_target_view() {
|
||||
const auto d3d_device = aorii::get_renderer<dx_renderer>()->get_d3d_device();
|
||||
const auto d3d_context = aorii::get_renderer<dx_renderer>()->get_d3d_context();
|
||||
|
||||
ID3D11Texture2D* back_buffer = nullptr;
|
||||
auto hr = swap_chain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&back_buffer);
|
||||
if (FAILED(hr)) {
|
||||
spdlog::critical("Failed to get back buffer. Error: {0}", hr);
|
||||
return hr;
|
||||
}
|
||||
ON_SCOPE_EXIT{
|
||||
if (back_buffer) back_buffer->Release();
|
||||
};
|
||||
|
||||
hr = d3d_device->CreateRenderTargetView(back_buffer, nullptr, &render_target_view);
|
||||
if (FAILED(hr)) {
|
||||
spdlog::critical("Failed to create render target. Error: {0}", hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
auto framebuffer_size = get_framebuffer_size();
|
||||
|
||||
D3D11_VIEWPORT viewport = {};
|
||||
viewport.Width = (float)framebuffer_size.x();
|
||||
viewport.Height = (float)framebuffer_size.y();
|
||||
viewport.MinDepth = 0.0f;
|
||||
viewport.MaxDepth = 1.0f;
|
||||
viewport.TopLeftX = 0.0f;
|
||||
viewport.TopLeftY = 0.0f;
|
||||
d3d_context->RSSetViewports(1, &viewport);
|
||||
|
||||
projection_matrix = get_projection_matrix().transpose();
|
||||
|
||||
return hr;
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
#pragma once
|
||||
#include <d3d11.h>
|
||||
#include <dxgi1_2.h>
|
||||
|
||||
#include "core/renderer/renderer_context.h"
|
||||
#include "core/window/renderer_window.h"
|
||||
|
||||
class dx_window : public renderer_window {
|
||||
public:
|
||||
void begin_frame() override;
|
||||
void end_frame() override;
|
||||
protected:
|
||||
bool create_surface(GLFWwindow* in_window) override;
|
||||
void on_resize(const Eigen::Vector2i& in_size) override;
|
||||
|
||||
HRESULT build_render_target_view();
|
||||
|
||||
private:
|
||||
renderer_context context;
|
||||
IDXGISwapChain1* swap_chain = nullptr;
|
||||
ID3D11RenderTargetView* render_target_view = nullptr;
|
||||
Eigen::Matrix4f projection_matrix;
|
||||
|
||||
};
|
||||
@@ -1,45 +0,0 @@
|
||||
#include "dx_pipeline_loader.h"
|
||||
|
||||
#include "backend/dx/dx_renderer.h"
|
||||
|
||||
bool dx_pipeline_loader::load(const char* vertex_shader_name, const char* pixel_shader_name) {
|
||||
auto renderer = aorii::get_renderer<dx_renderer>();
|
||||
const auto d3d_device = renderer->get_d3d_device();
|
||||
|
||||
const auto& vertex_shader_code = renderer->load_shader(vertex_shader_name);
|
||||
const auto& pixel_shader_code = renderer->load_shader(pixel_shader_name);
|
||||
|
||||
auto hr = d3d_device->CreateVertexShader(vertex_shader_code.data(), vertex_shader_code.size(), nullptr, &vertex_shader);
|
||||
if (FAILED(hr)) {
|
||||
spdlog::critical("rect_pipeline 无法创建顶点着色器: {0}", hr);
|
||||
return false;
|
||||
}
|
||||
hr = d3d_device->CreatePixelShader(pixel_shader_code.data(), pixel_shader_code.size(), nullptr, &pixel_shader);
|
||||
if (FAILED(hr)) {
|
||||
spdlog::critical("rect_pipeline 无法创建像素着色器: {0}", hr);
|
||||
return false;
|
||||
}
|
||||
uint32_t offset = 0;
|
||||
D3D11_INPUT_ELEMENT_DESC layout_desc[] = {
|
||||
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
||||
{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0},
|
||||
{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 16, D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
||||
{ "TEXCOORD", 1, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 32, D3D11_INPUT_PER_VERTEX_DATA, 0},
|
||||
{ "TEXCOORD", 2, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 48, D3D11_INPUT_PER_VERTEX_DATA, 0},
|
||||
{ "TEXCOORD", 3, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 64, D3D11_INPUT_PER_VERTEX_DATA, 0},
|
||||
};
|
||||
constexpr int32_t element_count = sizeof(layout_desc) / sizeof(D3D11_INPUT_ELEMENT_DESC);
|
||||
hr = d3d_device->CreateInputLayout(layout_desc, element_count, vertex_shader_code.data(), vertex_shader_code.size(), &input_layout);
|
||||
if (FAILED(hr)) {
|
||||
spdlog::critical("{0} 无法创建输入布局: {1}", vertex_shader_name, hr);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void dx_pipeline_loader::use() const {
|
||||
const auto d3d_context = aorii::get_renderer<dx_renderer>()->get_d3d_context();
|
||||
d3d_context->VSSetShader(vertex_shader, nullptr, 0);
|
||||
d3d_context->PSSetShader(pixel_shader, nullptr, 0);
|
||||
d3d_context->IASetInputLayout(input_layout);
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
#pragma once
|
||||
#include <d3d11.h>
|
||||
|
||||
class dx_pipeline_loader {
|
||||
public:
|
||||
bool load(const char* vertex_shader_name, const char* pixel_shader_name);
|
||||
void use() const;
|
||||
|
||||
ID3D11VertexShader* vertex_shader = nullptr;
|
||||
ID3D11PixelShader* pixel_shader = nullptr;
|
||||
ID3D11InputLayout* input_layout = nullptr;
|
||||
};
|
||||
@@ -1,33 +0,0 @@
|
||||
#include "dx_rect_pipeline.h"
|
||||
|
||||
#include "backend/dx/dx_renderer.h"
|
||||
|
||||
bool dx_rect_pipeline::init() {
|
||||
rect_pipeline::init();
|
||||
loader.load("aorii_rect_vertex_main", "aorii_rect_pixel_main");
|
||||
return true;
|
||||
}
|
||||
|
||||
void dx_rect_pipeline::use() {
|
||||
loader.use();
|
||||
}
|
||||
|
||||
void dx_rect_pipeline::draw(uint32_t in_index_count) {
|
||||
const auto d3d_context = aorii::get_renderer<dx_renderer>()->get_d3d_context();
|
||||
|
||||
// 设置顶点缓冲区
|
||||
constexpr UINT stride = sizeof(aorii_vertex);
|
||||
constexpr UINT offset = 0;
|
||||
auto* v_buffer = static_cast<ID3D11Buffer*>(vertex_buffer->get_native_handle());
|
||||
auto* i_buffer = static_cast<ID3D11Buffer*>(index_buffer->get_native_handle());
|
||||
auto* c_buffer = static_cast<ID3D11Buffer*>(param_buffer->get_native_handle());
|
||||
d3d_context->IASetVertexBuffers(0, 1, &v_buffer, &stride, &offset);
|
||||
d3d_context->IASetIndexBuffer(i_buffer, DXGI_FORMAT_R32_UINT, 0);
|
||||
d3d_context->VSSetConstantBuffers(0, 1, &c_buffer);
|
||||
|
||||
// 设置图元拓扑
|
||||
d3d_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
|
||||
// 绘制矩形
|
||||
d3d_context->DrawIndexed(in_index_count, 0, 0);
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
#pragma once
|
||||
#include <d3d11.h>
|
||||
|
||||
#include "dx_pipeline_loader.h"
|
||||
#include "core/pipeline/rect_pipeline.h"
|
||||
|
||||
class dx_rect_pipeline : public rect_pipeline {
|
||||
public:
|
||||
bool init() override;
|
||||
void use() override;
|
||||
void draw(uint32_t in_index_count) override;
|
||||
private:
|
||||
dx_pipeline_loader loader;
|
||||
};
|
||||
@@ -1,33 +0,0 @@
|
||||
#include "dx_rounded_rect_pipeline.h"
|
||||
|
||||
#include "backend/dx/dx_renderer.h"
|
||||
|
||||
bool dx_rounded_rect_pipeline::init() {
|
||||
rounded_rect_pipeline::init();
|
||||
return loader.load("aorii_rounded_rect_vertex_main", "aorii_rounded_rect_pixel_main");
|
||||
}
|
||||
|
||||
void dx_rounded_rect_pipeline::use() {
|
||||
loader.use();
|
||||
}
|
||||
|
||||
void dx_rounded_rect_pipeline::draw(uint32_t in_index_count) {
|
||||
const auto d3d_context = aorii::get_renderer<dx_renderer>()->get_d3d_context();
|
||||
|
||||
// 设置顶点缓冲区
|
||||
constexpr UINT stride = sizeof(aorii_vertex);
|
||||
constexpr UINT offset = 0;
|
||||
auto* v_buffer = static_cast<ID3D11Buffer*>(vertex_buffer->get_native_handle());
|
||||
auto* i_buffer = static_cast<ID3D11Buffer*>(index_buffer->get_native_handle());
|
||||
auto* c_buffer = static_cast<ID3D11Buffer*>(param_buffer->get_native_handle());
|
||||
d3d_context->IASetVertexBuffers(0, 1, &v_buffer, &stride, &offset);
|
||||
d3d_context->IASetIndexBuffer(i_buffer, DXGI_FORMAT_R32_UINT, 0);
|
||||
d3d_context->VSSetConstantBuffers(0, 1, &c_buffer);
|
||||
d3d_context->PSSetConstantBuffers(0, 1, &c_buffer);
|
||||
|
||||
// 设置图元拓扑
|
||||
d3d_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
|
||||
// 绘制矩形
|
||||
d3d_context->DrawIndexed(in_index_count, 0, 0);
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
#pragma once
|
||||
#include <d3d11.h>
|
||||
|
||||
#include "dx_pipeline_loader.h"
|
||||
#include "core/pipeline/rounded_rect_pipeline.h"
|
||||
|
||||
class dx_rounded_rect_pipeline : public rounded_rect_pipeline {
|
||||
public:
|
||||
bool init() override;
|
||||
void use() override;
|
||||
void draw(uint32_t in_index_count) override;
|
||||
private:
|
||||
dx_pipeline_loader loader;
|
||||
};
|
||||
@@ -1,57 +0,0 @@
|
||||
#include "dx_sdf_text_pipeline.h"
|
||||
|
||||
#include "backend/dx/dx_renderer.h"
|
||||
#include "core/renderer/renderer_texture_array.h"
|
||||
|
||||
bool dx_sdf_text_pipeline::init() {
|
||||
sdf_text_pipeline::init();
|
||||
|
||||
const auto d3d_device = aorii::get_renderer<dx_renderer>()->get_d3d_device();
|
||||
|
||||
D3D11_SAMPLER_DESC sampler_desc = {};
|
||||
sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
|
||||
sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||
sampler_desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||
sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||
sampler_desc.ComparisonFunc = D3D11_COMPARISON_NEVER;
|
||||
sampler_desc.MinLOD = 0;
|
||||
sampler_desc.MaxLOD = D3D11_FLOAT32_MAX;
|
||||
sampler_desc.MaxAnisotropy = 1;
|
||||
d3d_device->CreateSamplerState(&sampler_desc, &sampler_state);
|
||||
|
||||
loader.load("aorii_sdf_text_vertex_main", "aorii_sdf_text_pixel_main");
|
||||
return true;
|
||||
}
|
||||
|
||||
void dx_sdf_text_pipeline::use() {
|
||||
loader.use();
|
||||
}
|
||||
|
||||
void dx_sdf_text_pipeline::draw(uint32_t in_index_count) {
|
||||
if (!glyph_texture)
|
||||
return;
|
||||
const auto d3d_context = aorii::get_renderer<dx_renderer>()->get_d3d_context();
|
||||
|
||||
// 设置顶点缓冲区
|
||||
constexpr UINT stride = sizeof(aorii_vertex);
|
||||
constexpr UINT offset = 0;
|
||||
auto* v_buffer = static_cast<ID3D11Buffer*>(vertex_buffer->get_native_handle());
|
||||
auto* i_buffer = static_cast<ID3D11Buffer*>(index_buffer->get_native_handle());
|
||||
auto* c_buffer = static_cast<ID3D11Buffer*>(param_buffer->get_native_handle());
|
||||
auto* c2_buffer = static_cast<ID3D11Buffer*>(sdf_font_param_buffer->get_native_handle());
|
||||
auto* srv = static_cast<ID3D11ShaderResourceView*>(glyph_texture->get_shader_resource_view());
|
||||
|
||||
d3d_context->IASetVertexBuffers(0, 1, &v_buffer, &stride, &offset);
|
||||
d3d_context->IASetIndexBuffer(i_buffer, DXGI_FORMAT_R32_UINT, 0);
|
||||
|
||||
d3d_context->PSSetSamplers(0, 1, &sampler_state);
|
||||
d3d_context->VSSetConstantBuffers(0, 1, &c_buffer);
|
||||
d3d_context->PSSetConstantBuffers(0, 1, &c2_buffer);
|
||||
d3d_context->PSSetShaderResources(0, 1, &srv);
|
||||
|
||||
// 设置图元拓扑
|
||||
d3d_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
|
||||
// 绘制矩形
|
||||
d3d_context->DrawIndexed(in_index_count, 0, 0);
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
#pragma once
|
||||
#include "dx_pipeline_loader.h"
|
||||
#include "core/pipeline/sdf_text_pipeline.h"
|
||||
#include "core/renderer/renderer_texture.h"
|
||||
|
||||
class dx_sdf_text_pipeline : public sdf_text_pipeline {
|
||||
public:
|
||||
bool init() override;
|
||||
|
||||
void use() override;
|
||||
void draw(uint32_t in_index_count) override;
|
||||
private:
|
||||
dx_pipeline_loader loader;
|
||||
|
||||
ID3D11SamplerState* sampler_state = nullptr;
|
||||
};
|
||||
@@ -1,34 +0,0 @@
|
||||
#include "dx_segment_pipeline.h"
|
||||
|
||||
#include "backend/dx/dx_renderer.h"
|
||||
|
||||
bool dx_segment_pipeline::init() {
|
||||
segment_pipeline::init();
|
||||
loader.load("aorii_segment_vertex_main", "aorii_segment_pixel_main");
|
||||
return true;
|
||||
}
|
||||
|
||||
void dx_segment_pipeline::use() {
|
||||
loader.use();
|
||||
}
|
||||
|
||||
void dx_segment_pipeline::draw(uint32_t in_index_count) {
|
||||
const auto d3d_context = aorii::get_renderer<dx_renderer>()->get_d3d_context();
|
||||
|
||||
// 设置顶点缓冲区
|
||||
constexpr UINT stride = sizeof(aorii_vertex);
|
||||
constexpr UINT offset = 0;
|
||||
auto* v_buffer = static_cast<ID3D11Buffer*>(vertex_buffer->get_native_handle());
|
||||
auto* i_buffer = static_cast<ID3D11Buffer*>(index_buffer->get_native_handle());
|
||||
auto* c_buffer = static_cast<ID3D11Buffer*>(param_buffer->get_native_handle());
|
||||
d3d_context->IASetVertexBuffers(0, 1, &v_buffer, &stride, &offset);
|
||||
d3d_context->IASetIndexBuffer(i_buffer, DXGI_FORMAT_R32_UINT, 0);
|
||||
d3d_context->VSSetConstantBuffers(0, 1, &c_buffer);
|
||||
d3d_context->PSSetConstantBuffers(0, 1, &c_buffer);
|
||||
|
||||
// 设置图元拓扑
|
||||
d3d_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
|
||||
// 绘制矩形
|
||||
d3d_context->DrawIndexed(in_index_count, 0, 0);
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
#pragma once
|
||||
#include "dx_pipeline_loader.h"
|
||||
#include "core/pipeline/segment_pipeline.h"
|
||||
|
||||
class dx_segment_pipeline : public segment_pipeline {
|
||||
public:
|
||||
bool init() override;
|
||||
void use() override;
|
||||
void draw(uint32_t in_index_count) override;
|
||||
private:
|
||||
dx_pipeline_loader loader;
|
||||
};
|
||||
@@ -1,49 +0,0 @@
|
||||
#include "dx_texture_pipeline.h"
|
||||
|
||||
#include "backend/dx/dx_renderer.h"
|
||||
#include "backend/dx/dx_texture.h"
|
||||
|
||||
bool dx_texture_pipeline::init() {
|
||||
texture_pipeline::init();
|
||||
const auto d3d_device = aorii::get_renderer<dx_renderer>()->get_d3d_device();
|
||||
|
||||
D3D11_SAMPLER_DESC sampler_desc = {};
|
||||
sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
|
||||
sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||
sampler_desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||
sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||
sampler_desc.ComparisonFunc = D3D11_COMPARISON_NEVER;
|
||||
sampler_desc.MinLOD = 0;
|
||||
sampler_desc.MaxLOD = D3D11_FLOAT32_MAX;
|
||||
d3d_device->CreateSamplerState(&sampler_desc, &sampler_state);
|
||||
|
||||
return loader.load("aorii_texture_vertex_main", "aorii_texture_pixel_main");
|
||||
}
|
||||
|
||||
void dx_texture_pipeline::use() {
|
||||
loader.use();
|
||||
}
|
||||
|
||||
void dx_texture_pipeline::draw(uint32_t in_index_count) {
|
||||
if (!texture) return;
|
||||
const auto d3d_context = aorii::get_renderer<dx_renderer>()->get_d3d_context();
|
||||
|
||||
// 设置顶点缓冲区
|
||||
constexpr UINT stride = sizeof(aorii_vertex);
|
||||
constexpr UINT offset = 0;
|
||||
auto* v_buffer = static_cast<ID3D11Buffer*>(vertex_buffer->get_native_handle());
|
||||
auto* i_buffer = static_cast<ID3D11Buffer*>(index_buffer->get_native_handle());
|
||||
auto* c_buffer = static_cast<ID3D11Buffer*>(param_buffer->get_native_handle());
|
||||
auto* srv = (ID3D11ShaderResourceView*)texture->get_shader_resource_view();
|
||||
d3d_context->IASetVertexBuffers(0, 1, &v_buffer, &stride, &offset);
|
||||
d3d_context->IASetIndexBuffer(i_buffer, DXGI_FORMAT_R32_UINT, 0);
|
||||
d3d_context->PSSetSamplers(0, 1, &sampler_state);
|
||||
d3d_context->VSSetConstantBuffers(0, 1, &c_buffer);
|
||||
d3d_context->PSSetShaderResources(0, 1, &srv);
|
||||
|
||||
// 设置图元拓扑
|
||||
d3d_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
|
||||
// 绘制矩形
|
||||
d3d_context->DrawIndexed(in_index_count, 0, 0);
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
#pragma once
|
||||
#include <d3d11.h>
|
||||
|
||||
#include "dx_pipeline_loader.h"
|
||||
#include "core/pipeline/texture_pipeline.h"
|
||||
|
||||
class dx_texture_pipeline : public texture_pipeline {
|
||||
public:
|
||||
bool init() override;
|
||||
void use() override;
|
||||
void draw(uint32_t in_index_count) override;
|
||||
private:
|
||||
dx_pipeline_loader loader;
|
||||
|
||||
ID3D11SamplerState* sampler_state = nullptr;
|
||||
};
|
||||
@@ -1,18 +0,0 @@
|
||||
//
|
||||
// Created by Administrator on 25-2-2.
|
||||
//
|
||||
#include "glyph_cache.h"
|
||||
|
||||
void glyph_cache::initialize(LLGL::RenderSystem& in_render_system) {
|
||||
render_system = &in_render_system;
|
||||
}
|
||||
|
||||
glyph_metadata glyph_cache::get_glyph(const glyph_key& in_key) {
|
||||
|
||||
}
|
||||
|
||||
glyph_cache::atlas_page* glyph_cache::allocate_space(uint32_t in_width, uint32_t in_height) {
|
||||
LLGL::TextureDescriptor descriptor{};
|
||||
descriptor.type = LLGL::TextureType::Texture2D;
|
||||
render_system->CreateTexture(descriptor);
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
#include "sdf_text_pipeline.h"
|
||||
|
||||
#include "core/renderer/renderer.h"
|
||||
|
||||
bool sdf_text_pipeline::init() {
|
||||
param_buffer = aorii::get_renderer_raw()->create_buffer(buffer_type::CONSTANT, sizeof(param), 1);
|
||||
sdf_font_param_buffer = aorii::get_renderer_raw()->create_buffer(buffer_type::CONSTANT, sizeof(sdf_font_param), 1);
|
||||
return pipeline::init();
|
||||
}
|
||||
void sdf_text_pipeline::destroy() {
|
||||
pipeline::destroy();
|
||||
aorii::get_renderer_raw()->destroy_buffer(param_buffer);
|
||||
aorii::get_renderer_raw()->destroy_buffer(sdf_font_param_buffer);
|
||||
}
|
||||
|
||||
void sdf_text_pipeline::set_param(const param& in_param) {
|
||||
param_buffer->set_data(in_param);
|
||||
}
|
||||
|
||||
void sdf_text_pipeline::set_sdf_font_param(const sdf_font_param& in_param) {
|
||||
sdf_font_param_buffer->set_data(in_param);
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
#include "renderer.h"
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include "renderer_texture.h"
|
||||
#include "core/window/renderer_window.h"
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#define STBI_FAILURE_USERMSG
|
||||
#include "renderer_text.h"
|
||||
#include "renderer_texture_array.h"
|
||||
#include "stb_image.h"
|
||||
|
||||
#if DX_BACKEND
|
||||
#include "backend/dx/dx_renderer.h"
|
||||
#endif
|
||||
|
||||
using time_type = decltype(std::chrono::high_resolution_clock::now());
|
||||
std::chrono::duration<double> delta_time = {};
|
||||
time_type begin_time = {};
|
||||
time_type last_time = {};
|
||||
renderer* s_renderer = nullptr;
|
||||
|
||||
void renderer::tick() {
|
||||
}
|
||||
|
||||
void renderer::destroy_texture(renderer_texture* texture) { delete texture; }
|
||||
|
||||
void renderer::destroy_texture_array(renderer_texture_array* texture_array) { delete texture_array; }
|
||||
|
||||
renderer_texture* renderer::load_image(const std::string& file_path, texture_format in_format) {
|
||||
int width, height, channels;
|
||||
const auto result = stbi_load(file_path.c_str(), &width, &height, &channels, 0);
|
||||
if (!result) {
|
||||
const char* reason = stbi_failure_reason();
|
||||
spdlog::critical("加载图片 {0} 失败: {1}", file_path, reason);
|
||||
return nullptr;
|
||||
}
|
||||
int target_channel_count = get_format_channel_count(in_format);
|
||||
unsigned int row_pitch = 0;
|
||||
|
||||
auto texture = create_texture(width, height, in_format, device_memory_type::GPU);
|
||||
auto data = texture->lock(&row_pitch);
|
||||
for (int y = 0; y < height; ++y) {
|
||||
for (int x = 0; x < width; ++x) {
|
||||
unsigned char* src = result + (y * width + x) * channels;
|
||||
unsigned char* dst = static_cast<unsigned char*>(data) + y * row_pitch + x * target_channel_count;
|
||||
switch (channels) {
|
||||
case 1:
|
||||
dst[0] = src[0];
|
||||
dst[1] = 0;
|
||||
dst[2] = 0;
|
||||
dst[3] = 255;
|
||||
break;
|
||||
case 2:
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[1];
|
||||
dst[2] = 0;
|
||||
dst[3] = 255;
|
||||
break;
|
||||
case 3:
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[1];
|
||||
dst[2] = src[2];
|
||||
dst[3] = 255;
|
||||
break;
|
||||
case 4:
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[1];
|
||||
dst[2] = src[2];
|
||||
dst[3] = src[3];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
texture->unlock();
|
||||
stbi_image_free(result);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
void renderer::destroy_window(renderer_window* window) {
|
||||
delete window;
|
||||
}
|
||||
|
||||
renderer* aorii::get_renderer_raw() {
|
||||
return s_renderer;
|
||||
}
|
||||
|
||||
bool aorii::create_renderer(renderer_api api) {
|
||||
if (!aorii_text::init_freetype())
|
||||
return false;
|
||||
begin_time = std::chrono::high_resolution_clock::now();
|
||||
if (s_renderer) return true;
|
||||
switch (api) {
|
||||
#if DX_BACKEND
|
||||
case renderer_api::DX11: s_renderer = new dx_renderer();
|
||||
break;
|
||||
#endif
|
||||
#if GL_BACKEND
|
||||
case renderer_api::opengl:
|
||||
break;
|
||||
#endif
|
||||
#if VK_BACKEND
|
||||
case renderer_api::vulkan:
|
||||
break;
|
||||
#endif
|
||||
default: spdlog::critical("Failed to create renderer!");
|
||||
assert(false);
|
||||
}
|
||||
|
||||
if (!s_renderer->init()) {
|
||||
delete s_renderer;
|
||||
s_renderer = nullptr;
|
||||
}
|
||||
last_time = std::chrono::high_resolution_clock::now();
|
||||
return s_renderer != nullptr;
|
||||
}
|
||||
|
||||
void aorii::destroy_renderer() {
|
||||
if (!s_renderer) return;
|
||||
|
||||
s_renderer->destroy();
|
||||
delete s_renderer;
|
||||
s_renderer = nullptr;
|
||||
|
||||
aorii_text::destroy_freetype();
|
||||
}
|
||||
|
||||
void aorii::update() {
|
||||
const auto& current_time = std::chrono::high_resolution_clock::now();
|
||||
delta_time = current_time - last_time;
|
||||
last_time = current_time;
|
||||
|
||||
s_renderer->tick();
|
||||
s_renderer->render();
|
||||
|
||||
std::this_thread::yield();
|
||||
}
|
||||
|
||||
const std::chrono::duration<double>& aorii::get_delta_time() {
|
||||
return delta_time;
|
||||
}
|
||||
|
||||
std::chrono::duration<double> aorii::get_total_time() {
|
||||
return std::chrono::high_resolution_clock::now() - begin_time;
|
||||
}
|
||||
@@ -1,290 +0,0 @@
|
||||
#pragma once
|
||||
#include <chrono>
|
||||
#include <Eigen/Eigen>
|
||||
#include <filesystem>
|
||||
|
||||
#include "renderer_buffer.h"
|
||||
#include "core/pipeline/pipeline.h"
|
||||
|
||||
class renderer_texture_array;
|
||||
class sdf_text_pipeline;
|
||||
class segment_pipeline;
|
||||
class texture_pipeline;
|
||||
class rounded_rect_pipeline;
|
||||
class rect_pipeline;
|
||||
class renderer_window;
|
||||
class renderer_texture;
|
||||
|
||||
enum class renderer_api {
|
||||
DX11,
|
||||
OPENGL,
|
||||
VULKAN,
|
||||
METAL,
|
||||
};
|
||||
|
||||
enum class device_memory_type {
|
||||
GPU, // 显存
|
||||
SHARED, // 共享内存
|
||||
CPU, // 内存
|
||||
};
|
||||
|
||||
enum class texture_format {
|
||||
// 未压缩的颜色格式
|
||||
|
||||
// 单通道 8 位
|
||||
R8_UNORM,
|
||||
R8_SNORM,
|
||||
R8_UINT,
|
||||
R8_SINT,
|
||||
|
||||
// 双通道 8 位
|
||||
RG8_UNORM,
|
||||
RG8_SNORM,
|
||||
RG8_UINT,
|
||||
RG8_SINT,
|
||||
|
||||
// 三通道 8 位
|
||||
RGB8_UNORM,
|
||||
RGB8_SNORM,
|
||||
RGB8_UINT,
|
||||
RGB8_SINT,
|
||||
|
||||
// 四通道 8 位
|
||||
RGBA8_UNORM,
|
||||
RGBA8_SNORM,
|
||||
RGBA8_UINT,
|
||||
RGBA8_SINT,
|
||||
|
||||
// SRGB 格式
|
||||
SRGB8,
|
||||
SRGB8_ALPHA8,
|
||||
|
||||
// 16 位浮点格式
|
||||
R16_FLOAT,
|
||||
RG16_FLOAT,
|
||||
RGB16_FLOAT,
|
||||
RGBA16_FLOAT,
|
||||
|
||||
// 32 位浮点格式
|
||||
R32_FLOAT,
|
||||
RG32_FLOAT,
|
||||
RGB32_FLOAT,
|
||||
RGBA32_FLOAT,
|
||||
|
||||
// 整数格式
|
||||
R16_UINT,
|
||||
R16_SINT,
|
||||
RG16_UINT,
|
||||
RG16_SINT,
|
||||
RGBA16_UINT,
|
||||
RGBA16_SINT,
|
||||
R32_UINT,
|
||||
R32_SINT,
|
||||
RG32_UINT,
|
||||
RG32_SINT,
|
||||
RGBA32_UINT,
|
||||
RGBA32_SINT,
|
||||
|
||||
// 深度/模板格式
|
||||
D16_UNORM,
|
||||
D24_UNORM_S8_UINT,
|
||||
D32_FLOAT,
|
||||
D32_FLOAT_S8X24_UINT,
|
||||
|
||||
// 压缩格式(以 DXGI 格式为例)
|
||||
BC1_UNORM, // DXT1
|
||||
BC1_UNORM_SRGB,
|
||||
BC2_UNORM, // DXT3
|
||||
BC2_UNORM_SRGB,
|
||||
BC3_UNORM, // DXT5
|
||||
BC3_UNORM_SRGB,
|
||||
BC4_UNORM,
|
||||
BC4_SNORM,
|
||||
BC5_UNORM,
|
||||
BC5_SNORM,
|
||||
BC6H_UF16,
|
||||
BC6H_SF16,
|
||||
BC7_UNORM,
|
||||
BC7_UNORM_SRGB,
|
||||
};
|
||||
|
||||
inline int get_format_channel_count(texture_format format) {
|
||||
switch (format) {
|
||||
case texture_format::R8_UNORM:
|
||||
case texture_format::R8_SNORM:
|
||||
case texture_format::R8_UINT:
|
||||
case texture_format::R8_SINT:
|
||||
case texture_format::R16_FLOAT:
|
||||
case texture_format::R16_UINT:
|
||||
case texture_format::R16_SINT:
|
||||
case texture_format::R32_FLOAT:
|
||||
case texture_format::R32_UINT:
|
||||
case texture_format::R32_SINT:
|
||||
return 1;
|
||||
case texture_format::RG8_UNORM:
|
||||
case texture_format::RG8_SNORM:
|
||||
case texture_format::RG8_UINT:
|
||||
case texture_format::RG8_SINT:
|
||||
case texture_format::RG16_FLOAT:
|
||||
case texture_format::RG16_UINT:
|
||||
case texture_format::RG16_SINT:
|
||||
case texture_format::RG32_FLOAT:
|
||||
case texture_format::RG32_UINT:
|
||||
case texture_format::RG32_SINT:
|
||||
return 2;
|
||||
case texture_format::RGB8_UNORM:
|
||||
case texture_format::RGB8_SNORM:
|
||||
case texture_format::RGB8_UINT:
|
||||
case texture_format::RGB8_SINT:
|
||||
case texture_format::RGB16_FLOAT:
|
||||
case texture_format::RGB32_FLOAT:
|
||||
return 3;
|
||||
case texture_format::RGBA8_UNORM:
|
||||
case texture_format::RGBA8_SNORM:
|
||||
case texture_format::RGBA8_UINT:
|
||||
case texture_format::RGBA8_SINT:
|
||||
case texture_format::RGBA16_FLOAT:
|
||||
case texture_format::RGBA32_FLOAT:
|
||||
case texture_format::RGBA32_UINT:
|
||||
case texture_format::RGBA32_SINT:
|
||||
return 4;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
inline int get_format_bits_pre_channel(texture_format format) {
|
||||
switch (format) {
|
||||
case texture_format::R8_UNORM:
|
||||
case texture_format::R8_SNORM:
|
||||
case texture_format::R8_UINT:
|
||||
case texture_format::R8_SINT:
|
||||
case texture_format::RG8_UNORM:
|
||||
case texture_format::RG8_SNORM:
|
||||
case texture_format::RG8_UINT:
|
||||
case texture_format::RG8_SINT:
|
||||
case texture_format::RGB8_UNORM:
|
||||
case texture_format::RGB8_SNORM:
|
||||
case texture_format::RGB8_UINT:
|
||||
case texture_format::RGB8_SINT:
|
||||
case texture_format::RGBA8_UNORM:
|
||||
case texture_format::RGBA8_SNORM:
|
||||
case texture_format::RGBA8_UINT:
|
||||
case texture_format::RGBA8_SINT:
|
||||
case texture_format::SRGB8:
|
||||
case texture_format::SRGB8_ALPHA8:
|
||||
case texture_format::BC1_UNORM:
|
||||
case texture_format::BC1_UNORM_SRGB:
|
||||
case texture_format::BC2_UNORM:
|
||||
case texture_format::BC2_UNORM_SRGB:
|
||||
case texture_format::BC3_UNORM:
|
||||
case texture_format::BC3_UNORM_SRGB:
|
||||
case texture_format::BC4_UNORM:
|
||||
case texture_format::BC4_SNORM:
|
||||
case texture_format::BC5_UNORM:
|
||||
case texture_format::BC5_SNORM:
|
||||
case texture_format::BC6H_UF16:
|
||||
case texture_format::BC6H_SF16:
|
||||
case texture_format::BC7_UNORM:
|
||||
case texture_format::BC7_UNORM_SRGB:
|
||||
return 8;
|
||||
case texture_format::R16_FLOAT:
|
||||
case texture_format::R16_UINT:
|
||||
case texture_format::R16_SINT:
|
||||
case texture_format::RG16_FLOAT:
|
||||
case texture_format::RG16_UINT:
|
||||
case texture_format::RG16_SINT:
|
||||
case texture_format::RGB16_FLOAT:
|
||||
case texture_format::RGBA16_FLOAT:
|
||||
case texture_format::D16_UNORM:
|
||||
return 16;
|
||||
case texture_format::R32_FLOAT:
|
||||
case texture_format::R32_UINT:
|
||||
case texture_format::R32_SINT:
|
||||
case texture_format::RG32_FLOAT:
|
||||
case texture_format::RG32_UINT:
|
||||
case texture_format::RG32_SINT:
|
||||
case texture_format::RGB32_FLOAT:
|
||||
case texture_format::RGBA32_FLOAT:
|
||||
return 32;
|
||||
case texture_format::D24_UNORM_S8_UINT:
|
||||
case texture_format::D32_FLOAT:
|
||||
case texture_format::D32_FLOAT_S8X24_UINT:
|
||||
return 24;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
class renderer {
|
||||
friend class window_manager;
|
||||
public:
|
||||
virtual ~renderer() = default;
|
||||
|
||||
virtual bool init() = 0;
|
||||
virtual void destroy() = 0;
|
||||
virtual void tick();
|
||||
virtual bool render() = 0;
|
||||
|
||||
template<typename T>
|
||||
renderer_texture* create_texture(const Eigen::Vector2<T>& in_size, texture_format in_format, device_memory_type in_memory_type) {
|
||||
return create_texture(in_size.x(), in_size.y(), in_format, in_memory_type);
|
||||
}
|
||||
virtual renderer_texture* create_texture(uint32_t in_size_width, uint32_t in_size_height, texture_format in_format, device_memory_type in_memory_type) = 0;
|
||||
virtual void destroy_texture(renderer_texture* texture);
|
||||
template<typename T>
|
||||
renderer_texture_array* create_texture_array(const Eigen::Vector2<T>& in_size, const int in_count, const texture_format in_format) {
|
||||
return create_texture_array(in_size.x(), in_size.y(), in_count, in_format);
|
||||
}
|
||||
virtual renderer_texture_array* create_texture_array(uint32_t in_size_width, uint32_t in_size_height, uint32_t in_count, texture_format in_format, device_memory_type in_memory_type) = 0;
|
||||
virtual void destroy_texture_array(renderer_texture_array* texture_array);
|
||||
|
||||
renderer_texture* load_image(const std::string& file_path, texture_format in_format);
|
||||
|
||||
/**
|
||||
* 读取着色器代码
|
||||
* @param shader_name 着色器文件名称, 不需要路径和后缀, 会使用aorii::get_shader_path获取路径, 在不同的图形API下会自动添加后缀
|
||||
* @return 着色器代码
|
||||
*/
|
||||
virtual std::vector<int8_t> load_shader(const std::string& shader_name) = 0;
|
||||
|
||||
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 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, 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;
|
||||
virtual rounded_rect_pipeline* get_rounded_rect_pipeline() = 0;
|
||||
virtual texture_pipeline* get_texture_pipeline() = 0;
|
||||
virtual segment_pipeline* get_segment_pipeline() = 0;
|
||||
virtual sdf_text_pipeline* get_text_pipeline() = 0;
|
||||
|
||||
virtual Eigen::Matrix4f make_projection_matrix(const Eigen::Vector2i& size) = 0;
|
||||
private:
|
||||
virtual renderer_window* create_window() = 0;
|
||||
virtual void destroy_window(renderer_window* window);
|
||||
};
|
||||
|
||||
namespace aorii {
|
||||
renderer* get_renderer_raw();
|
||||
|
||||
template<typename T>
|
||||
static T* get_renderer() {
|
||||
return static_cast<T*>(get_renderer_raw());
|
||||
}
|
||||
|
||||
bool create_renderer(renderer_api api);
|
||||
void destroy_renderer();
|
||||
void update();
|
||||
|
||||
const std::chrono::duration<double>& get_delta_time();
|
||||
std::chrono::duration<double> get_total_time();
|
||||
|
||||
inline std::filesystem::path s_shader_relative_path = "resource/shaders";
|
||||
inline void set_shader_relative_path(const std::filesystem::path& path) { s_shader_relative_path = path; }
|
||||
inline std::filesystem::path get_shader_path(const std::string& shader_name) { return std::filesystem::current_path() / s_shader_relative_path / shader_name; }
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
#pragma once
|
||||
#include <span>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
enum class buffer_type {
|
||||
VERTEX,
|
||||
INDEX,
|
||||
CONSTANT,
|
||||
};
|
||||
|
||||
class renderer_buffer {
|
||||
public:
|
||||
explicit renderer_buffer(buffer_type in_type, const int in_element_byte, const int in_size = 1) : size(in_size),
|
||||
element_byte(in_element_byte), type(in_type) {
|
||||
}
|
||||
|
||||
virtual ~renderer_buffer() = default;
|
||||
|
||||
virtual void* lock() = 0;
|
||||
virtual void unlock() = 0;
|
||||
|
||||
template<class T>
|
||||
bool set_data(const T& in_data) {
|
||||
if (auto data = lock()) {
|
||||
memcpy(data, &in_data, sizeof(T));
|
||||
unlock();
|
||||
return true;
|
||||
}
|
||||
#if DEBUG
|
||||
spdlog::error("Failed to set param buffer data");
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
template<class T>
|
||||
bool set_data(const std::span<const T>& in_data) {
|
||||
if (auto data = lock()) {
|
||||
memcpy(data, in_data.data(), sizeof(T) * in_data.size());
|
||||
unlock();
|
||||
return true;
|
||||
}
|
||||
#if DEBUG
|
||||
spdlog::error("Failed to set param buffer data");
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
void resize(const int new_size) {
|
||||
if (new_size == size)
|
||||
return;
|
||||
if (new_size < 1) {
|
||||
return;
|
||||
}
|
||||
size = new_size;
|
||||
on_resize(new_size);
|
||||
}
|
||||
[[nodiscard]] int get_size() const {
|
||||
return size;
|
||||
}
|
||||
[[nodiscard]] buffer_type get_type() const {
|
||||
return type;
|
||||
}
|
||||
[[nodiscard]] virtual void* get_native_handle() = 0;
|
||||
protected:
|
||||
virtual void on_resize(int new_size) = 0;
|
||||
int size;
|
||||
const int element_byte;
|
||||
const buffer_type type;
|
||||
};
|
||||
@@ -1,387 +0,0 @@
|
||||
#include "renderer_text.h"
|
||||
|
||||
#include <future>
|
||||
#include <utility>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include "renderer.h"
|
||||
#include "renderer_texture_array.h"
|
||||
|
||||
#define STB_TRUETYPE_IMPLEMENTATION
|
||||
#include <stb_truetype.h>
|
||||
|
||||
#include "misc/scope_exit.h"
|
||||
|
||||
// 在SDFFontCache.cpp中添加实现
|
||||
const std::u32string aorii_text::COMMON_ASCII =
|
||||
U"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
|
||||
const std::u32string aorii_text::COMMON_CHINESE =
|
||||
U"的一是在不了有和人这中大为上个国我以要他时来用们生到作地于出就分对成会可主发年动同工也能下过子说产种面而方后多定行学法所民得经十三之进着等部度家电力里如水化高自二理起小物现实加量都两体制机当使点从业本去把性好应开它合还因由其些然前外天政四日那社义事平形相全表间样与关各重新线内数正心反你明看原又么利比或但质气第向道命此变条只没结解问意建月公无系军很情者最立代想已通并提直题党程展五果料象员革位入常文总次品式活设及管特件长求老头基资边流路级少图山统接知较将组见计别她手角期根论运农指几九区强放决西被干做必战先回则任取据处队南给色光门即保治北造百规热领七海口东导器压志世金增争济阶油思术极交受联什认六共权收证改清己美再采转更单风切打白教速花带安场身车例真务具万每目至达走积示议声报斗完类八离华名确才科张信马节话米整空元况今集温传土许步群广石记需段研界拉林律叫且究观越织装影算低持音众书布复容儿须际商非验连断深难近矿千周委素技备半办青省列习响约支般史感劳便团往酸历市克何除消构府称太准精值号率族维划选标写存候毛亲快效斯院查江型眼王按格养易置派层片始却专状育厂京识适属圆包火住调满县局照参红细引听该铁价严";
|
||||
|
||||
const std::u32string aorii_text::COMMON_PUNCTUATION =
|
||||
U",。!?:;''""《》【】()、";
|
||||
|
||||
const std::u32string aorii_text::COMMON_NUMBERS =
|
||||
U"0123456789";
|
||||
|
||||
aorii_text::font_data::~font_data() {
|
||||
delete font;
|
||||
}
|
||||
|
||||
aorii_text::aorii_text() : texture_array(nullptr),
|
||||
current_x(0), current_y(0),
|
||||
current_texture_index(0) {
|
||||
}
|
||||
|
||||
aorii_text::~aorii_text() {
|
||||
}
|
||||
|
||||
bool aorii_text::init_freetype() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void aorii_text::destroy_freetype() {
|
||||
}
|
||||
|
||||
bool aorii_text::initialize(const std::wstring& in_font_path) {
|
||||
// 预计需要的纹理数量(8张纹理几乎可以容纳所有字符)
|
||||
constexpr uint32_t expected_textures = 8;
|
||||
texture_array = aorii::get_renderer_raw()->create_texture_array(2048, 2048, expected_textures, texture_format::R8_UNORM, device_memory_type::GPU);
|
||||
if (!texture_array) {
|
||||
spdlog::error("无法创建字符缓冲纹理");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!add_font(in_font_path)) {
|
||||
spdlog::error("添加主要字体失败");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
float aorii_text::get_kerning(char32_t ch1, char32_t ch2) const {
|
||||
font_data const* left_ch_font = nullptr;
|
||||
int g1 = 0, g2 = 0;
|
||||
|
||||
// 在所有字体中查找字符对的字距调整
|
||||
for (const auto& font : fonts) {
|
||||
g1 = stbtt_FindGlyphIndex(font.font, ch1);
|
||||
g2 = stbtt_FindGlyphIndex(font.font, ch2);
|
||||
|
||||
if (g1 != 0) {
|
||||
left_ch_font = &font;
|
||||
}
|
||||
if (g1 != 0 && g2 != 0) {
|
||||
return stbtt_GetGlyphKernAdvance(font.font, g1, g2);
|
||||
}
|
||||
}
|
||||
if (!left_ch_font)
|
||||
return 0.0f;
|
||||
|
||||
int x0, x1;
|
||||
stbtt_GetGlyphBox(left_ch_font->font, g1, &x0, nullptr, &x1, nullptr);
|
||||
return x1 - x0;
|
||||
}
|
||||
|
||||
bool aorii_text::add_font(const std::wstring& font_path) {
|
||||
font_data new_font{};
|
||||
new_font.font = new stbtt_fontinfo();
|
||||
|
||||
// 映射字体文件
|
||||
if (!new_font.file.map_file(font_path)) {
|
||||
delete new_font.font;
|
||||
spdlog::error("Failed to map font file");
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto* font_buffer = static_cast<uint8_t*>(new_font.file.get_data());
|
||||
if (!stbtt_InitFont(new_font.font, font_buffer, stbtt_GetFontOffsetForIndex(font_buffer, 0))) {
|
||||
new_font.file.unmap();
|
||||
delete new_font.font;
|
||||
spdlog::error("Failed to initialize font");
|
||||
return false;
|
||||
}
|
||||
|
||||
int temp_space_width, temp_tab_width;
|
||||
stbtt_GetCodepointHMetrics(new_font.font, ' ', &temp_space_width, nullptr);
|
||||
stbtt_GetCodepointHMetrics(new_font.font, '\t', &temp_tab_width, nullptr);
|
||||
new_font.space_width = temp_space_width;
|
||||
new_font.tab_width = temp_tab_width;
|
||||
|
||||
int ascent, descent, line_gap;
|
||||
stbtt_GetFontVMetrics(new_font.font, &ascent, &descent, &line_gap);
|
||||
new_font.ascent = ascent;
|
||||
new_font.descent = descent;
|
||||
new_font.line_gap = line_gap;
|
||||
|
||||
fonts.emplace_back(std::move(new_font));
|
||||
return true;
|
||||
}
|
||||
|
||||
ch_atlas_item const* aorii_text::get_atlas_item(const char32_t ch) {
|
||||
if (const auto it = character_map.find(ch); it != character_map.end()) {
|
||||
return &it->second;
|
||||
}
|
||||
return cache_ch_to_atlas(ch);
|
||||
}
|
||||
|
||||
bool aorii_text::precache_characters(const std::u32string& characters) {
|
||||
// 创建进度通知回调的函数指针类型
|
||||
using ProgressCallback = std::function<void(float progress, const wchar_t currentChar)>;
|
||||
|
||||
bool success = true;
|
||||
|
||||
// 使用线程池并行生成SDF数据
|
||||
const size_t max_threads = std::thread::hardware_concurrency();
|
||||
std::vector<std::future<std::vector<uint8_t>>> futures;
|
||||
std::mutex map_mutex;
|
||||
|
||||
for (size_t i = 0; i < characters.length(); i++) {
|
||||
auto ch = characters[i];
|
||||
if (!get_atlas_item(ch))
|
||||
spdlog::error("Failed to create character U+{:04X}", (uint32_t)ch);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool aorii_text::precache_common_characters() {
|
||||
std::u32string all_common_chars;
|
||||
all_common_chars.reserve(COMMON_ASCII.length() +
|
||||
COMMON_CHINESE.length() +
|
||||
COMMON_PUNCTUATION.length() +
|
||||
COMMON_NUMBERS.length());
|
||||
|
||||
all_common_chars += COMMON_ASCII;
|
||||
all_common_chars += COMMON_CHINESE;
|
||||
all_common_chars += COMMON_PUNCTUATION;
|
||||
all_common_chars += COMMON_NUMBERS;
|
||||
|
||||
return precache_characters(all_common_chars);
|
||||
}
|
||||
|
||||
uint32_t aorii_text::get_font_char_count() const {
|
||||
uint32_t result = 0;
|
||||
for (const auto& font : fonts) {
|
||||
result += font.font->numGlyphs;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t aorii_text::get_texture_size() const {
|
||||
return texture_array->size().x();
|
||||
}
|
||||
|
||||
std::vector<measured_ch> aorii_text::measure_text(const std::u32string& text, float height) {
|
||||
// 获取主字体
|
||||
font_data const& primary_font = fonts[0];
|
||||
const float scale = stbtt_ScaleForPixelHeight(primary_font.font, height);
|
||||
const float scale_padding = padding * (height / pixel_height);
|
||||
|
||||
// 基线和行高信息
|
||||
const int32_t ascent = primary_font.ascent;
|
||||
const int32_t descent = primary_font.descent;
|
||||
const float line_gap = primary_font.line_gap * scale;
|
||||
const float line_height = height;
|
||||
const float space_width = primary_font.space_width * scale;
|
||||
const float tab_width = primary_font.tab_width * scale;
|
||||
|
||||
struct line_data {
|
||||
std::u32string text;
|
||||
int32_t max_top{};
|
||||
int32_t min_top{};
|
||||
int32_t max_bottom{};
|
||||
int32_t min_bottom{};
|
||||
};
|
||||
std::vector<line_data> lines;
|
||||
// 按照\n分割文本
|
||||
std::u32string text_copy = text;
|
||||
for (size_t i = 0; i < text_copy.length(); i++) {
|
||||
if (text_copy[i] == U'\n') {
|
||||
lines.emplace_back(text_copy.substr(0, i));
|
||||
text_copy = text_copy.substr(i + 1);
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
if (!text_copy.empty())
|
||||
lines.emplace_back(text_copy);
|
||||
|
||||
for (auto& data: lines) {
|
||||
int32_t min_top = 0;
|
||||
int32_t min_bottom = 0;
|
||||
int32_t max_top = 0;
|
||||
int32_t max_bottom = 0;
|
||||
for (const auto& ch: data.text) {
|
||||
const auto item = get_atlas_item(ch);
|
||||
if (!item)
|
||||
continue;
|
||||
min_top = std::min(min_top, item->top);
|
||||
min_bottom = std::min(min_bottom, item->bottom);
|
||||
max_top = std::max(max_top, item->top);
|
||||
max_bottom = std::max(max_bottom, item->bottom);
|
||||
}
|
||||
data.min_top = min_top;
|
||||
data.min_bottom = min_bottom;
|
||||
data.max_top = max_top;
|
||||
data.max_bottom = max_bottom;
|
||||
}
|
||||
|
||||
std::vector<measured_ch> result;
|
||||
Eigen::Vector2f pos{0, 0};
|
||||
|
||||
for (const auto& line : lines) {
|
||||
// 计算这一行顶部和底部的最大和最小值,然后进行垂直居中
|
||||
const float top_offset = (line_height - (line.max_bottom - line.min_top) * scale) / 2;
|
||||
|
||||
for (const auto& ch : line.text) {
|
||||
if (ch == U' ') {
|
||||
pos.x() += space_width;
|
||||
continue;
|
||||
}
|
||||
if (ch == U'\t') {
|
||||
pos.x() += tab_width;
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto item = get_atlas_item(ch);
|
||||
measured_ch mch{};
|
||||
mch.item = item;
|
||||
mch.offset = pos;
|
||||
mch.size_scale = scale;
|
||||
if (item) {
|
||||
// 如果字符高度大于行高, 则缩放
|
||||
const float item_height = item->get_height() * scale;
|
||||
if (item_height > line_height) {
|
||||
mch.size_scale = line_height / item_height * scale;
|
||||
}
|
||||
|
||||
// 将字符底部对齐到行底部
|
||||
const float bottom_offset = item->bottom - line.max_bottom;
|
||||
mch.offset.y() -= bottom_offset * mch.size_scale;
|
||||
// mch.offset.y() += line_height;
|
||||
|
||||
mch.offset.y() += top_offset;
|
||||
// mch.offset.x() -= item->left_side_bearing * mch.size_scale;
|
||||
|
||||
pos.x() += item->x_advance * mch.size_scale;
|
||||
// pos.x() -= item->left * mch.size_scale;
|
||||
}
|
||||
result.push_back(mch);
|
||||
}
|
||||
|
||||
pos.x() = 0;
|
||||
pos.y() += line_height;
|
||||
pos.y() += line_gap;
|
||||
// pos.y() -= scale_padding * 2;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ch_atlas_item const* aorii_text::cache_ch_to_atlas(char32_t ch) {
|
||||
font_data const* current_font = nullptr;
|
||||
int glyph_index = 0;
|
||||
for (const auto& font : fonts) {
|
||||
glyph_index = stbtt_FindGlyphIndex(font.font, ch);
|
||||
if (glyph_index) {
|
||||
current_font = &font;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!current_font) {
|
||||
return nullptr;
|
||||
}
|
||||
const auto font = current_font->font;
|
||||
const uint32_t texture_size = get_texture_size();
|
||||
|
||||
constexpr uint8_t on_edge_value = 128;
|
||||
const float pixel_dist_scale = (float)on_edge_value / padding;
|
||||
const float scale = stbtt_ScaleForPixelHeight(font, pixel_height - padding * 2);
|
||||
|
||||
// 获取SDF尺寸和位图
|
||||
int32_t width, height, x_offset, y_offset;
|
||||
auto* sdf_bitmap = stbtt_GetGlyphSDF(
|
||||
font,
|
||||
scale,
|
||||
glyph_index,
|
||||
padding,
|
||||
on_edge_value,
|
||||
pixel_dist_scale,
|
||||
&width, &height,
|
||||
&x_offset, &y_offset
|
||||
);
|
||||
|
||||
if (!sdf_bitmap) {
|
||||
return nullptr;
|
||||
}
|
||||
ON_SCOPE_EXIT {
|
||||
stbtt_FreeSDF(sdf_bitmap, font->userdata);
|
||||
};
|
||||
|
||||
// 检查当前行是否有足够空间
|
||||
if (current_x + width > texture_size) {
|
||||
// 移动到下一行
|
||||
current_x = 0;
|
||||
current_y = next_row_y;
|
||||
}
|
||||
|
||||
// 检查是否需要新的纹理
|
||||
if (current_y + height > texture_size) {
|
||||
current_texture_index++;
|
||||
if (current_texture_index >= texture_array->get_count()) {
|
||||
spdlog::error("Texture array capacity exceeded");
|
||||
return nullptr;
|
||||
}
|
||||
current_x = 0;
|
||||
current_y = 0;
|
||||
next_row_y = 0;
|
||||
}
|
||||
|
||||
// 更新纹理
|
||||
Eigen::AlignedBox2i box;
|
||||
box.min() = Eigen::Vector2i(current_x, current_y);
|
||||
box.max() = Eigen::Vector2i(current_x + width, current_y + height);
|
||||
|
||||
texture_array->update_subresource(current_texture_index, box, sdf_bitmap, width);
|
||||
|
||||
// 获取字形度量信息
|
||||
int advance_width, left_side_bearing;
|
||||
stbtt_GetGlyphHMetrics(font, glyph_index, &advance_width, &left_side_bearing);
|
||||
int ch_x0, ch_y0, ch_x1, ch_y1;
|
||||
stbtt_GetGlyphBox(font, glyph_index, &ch_x0, &ch_y0, &ch_x1, &ch_y1);
|
||||
|
||||
int width_log = ch_x1 - ch_x0;
|
||||
int height_log = ch_y1 - ch_y0;
|
||||
spdlog::info("left: {}, right: {}, top: {}, bottom: {}, width: {}, height: {}, x_advance: {}, left_side_bearing: {}",
|
||||
ch_x0, ch_x1, ch_y0, ch_y1, width_log, height_log, advance_width, left_side_bearing);
|
||||
|
||||
// 将x_offset和y_offset转换到字体空间
|
||||
x_offset = x_offset / scale;
|
||||
y_offset = y_offset / scale;
|
||||
|
||||
// 创建并存储字符信息
|
||||
ch_atlas_item info{};
|
||||
info.tex_u = current_x / static_cast<float>(texture_size);
|
||||
info.tex_v = current_y / static_cast<float>(texture_size);
|
||||
info.tex_z = static_cast<float>(current_texture_index);
|
||||
info.u_size = width / static_cast<float>(texture_size);
|
||||
info.v_size = height / static_cast<float>(texture_size);
|
||||
|
||||
info.x_offset = x_offset;
|
||||
info.y_offset = y_offset;
|
||||
|
||||
info.left = ch_x0;
|
||||
info.right = ch_x1;
|
||||
info.top = ch_y0;
|
||||
info.bottom = ch_y1;
|
||||
|
||||
info.x_advance = advance_width;
|
||||
info.left_side_bearing = left_side_bearing;
|
||||
|
||||
// 更新位置和下一行的y坐标
|
||||
current_x += width;
|
||||
next_row_y = std::max(next_row_y, current_y + height);
|
||||
|
||||
return &(character_map[ch] = info);
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
#pragma once
|
||||
#include "core/pixel_format/pixel.h"
|
||||
#include "misc/mapped_file.h"
|
||||
#include <unordered_map>
|
||||
|
||||
class renderer_texture_array;
|
||||
struct stbtt_fontinfo;
|
||||
|
||||
struct ch_atlas_item {
|
||||
float tex_u; // 图集中的U位置
|
||||
float tex_v; // 图集中的V位置
|
||||
uint8_t tex_z; // 图集索引
|
||||
float u_size; // U方向尺寸
|
||||
float v_size; // V方向尺寸
|
||||
|
||||
int32_t x_offset; // SDF纹理的X偏移量
|
||||
int32_t y_offset; // SDF纹理的Y偏移量
|
||||
|
||||
int32_t left; // 字形的左边界
|
||||
int32_t right; // 字形的右边界
|
||||
int32_t top; // 字形的顶部
|
||||
int32_t bottom; // 字形的底部
|
||||
[[nodiscard]] int32_t get_width() const { return right - left; }
|
||||
[[nodiscard]] int32_t get_height() const { return bottom - top; }
|
||||
|
||||
int32_t x_advance; // 字形的X进度
|
||||
int32_t left_side_bearing; // 字形的左侧轴承
|
||||
};
|
||||
|
||||
struct measured_ch {
|
||||
ch_atlas_item const* item;
|
||||
Eigen::Vector2f offset;
|
||||
float size_scale;
|
||||
};
|
||||
|
||||
class aorii_text {
|
||||
struct font_data {
|
||||
font_data() = default;
|
||||
font_data(font_data&& other) noexcept {
|
||||
file = std::move(other.file);
|
||||
|
||||
font = other.font;
|
||||
space_width = other.space_width;
|
||||
tab_width = other.tab_width;
|
||||
ascent = other.ascent;
|
||||
descent = other.descent;
|
||||
line_gap = other.line_gap;
|
||||
|
||||
other.font = nullptr;
|
||||
other.space_width = 0;
|
||||
other.tab_width = 0;
|
||||
other.ascent = 0;
|
||||
other.descent = 0;
|
||||
other.line_gap = 0;
|
||||
}
|
||||
~font_data();
|
||||
|
||||
stbtt_fontinfo* font{};
|
||||
mapped_file file;
|
||||
int32_t space_width{};
|
||||
int32_t tab_width{};
|
||||
int32_t ascent{}; // 字体从基线到顶部的高度
|
||||
int32_t descent{}; // 基线到字体底部的高度
|
||||
int32_t line_gap{}; // 行间距
|
||||
};
|
||||
public:
|
||||
aorii_text();
|
||||
~aorii_text();
|
||||
|
||||
static bool init_freetype();
|
||||
static void destroy_freetype();
|
||||
|
||||
bool initialize(const std::wstring& in_font_path);
|
||||
bool add_font(const std::wstring& font_path);
|
||||
ch_atlas_item const* get_atlas_item(char32_t ch);
|
||||
|
||||
// 预缓存一组字符
|
||||
bool precache_characters(const std::u32string& characters);
|
||||
|
||||
// 预缓存常用字符集
|
||||
bool precache_common_characters();
|
||||
|
||||
// 获取缓存状态
|
||||
[[nodiscard]] size_t get_cached_character_count() const { return character_map.size(); }
|
||||
|
||||
// 获取字体字符数量
|
||||
[[nodiscard]] uint32_t get_font_char_count() const;
|
||||
|
||||
[[nodiscard]] renderer_texture_array* get_texture_array() const { return texture_array; }
|
||||
[[nodiscard]] uint32_t get_texture_size() const;
|
||||
|
||||
[[nodiscard]] float get_kerning(char32_t ch1, char32_t ch2) const;
|
||||
[[nodiscard]] std::vector<measured_ch> measure_text(const std::u32string& text, float height);
|
||||
private:
|
||||
ch_atlas_item const* cache_ch_to_atlas(char32_t ch);
|
||||
std::vector<font_data> fonts;
|
||||
const float pixel_height = 128;
|
||||
const int padding = 5;
|
||||
|
||||
renderer_texture_array* texture_array;
|
||||
|
||||
uint32_t current_x;
|
||||
uint32_t current_y;
|
||||
uint32_t next_row_y = 0; // 跟踪当前行的最大高度
|
||||
uint8_t current_texture_index;
|
||||
|
||||
std::unordered_map<char32_t, ch_atlas_item> character_map;
|
||||
|
||||
// 常用字符集定义
|
||||
static const std::u32string COMMON_ASCII; // ASCII字符
|
||||
static const std::u32string COMMON_CHINESE; // 常用汉字
|
||||
static const std::u32string COMMON_PUNCTUATION; // 常用标点符号
|
||||
static const std::u32string COMMON_NUMBERS; // 数字
|
||||
};
|
||||
@@ -1 +0,0 @@
|
||||
#include "renderer_texture.h"
|
||||
@@ -1,44 +0,0 @@
|
||||
#pragma once
|
||||
#include <Eigen/Eigen>
|
||||
#include <vector>
|
||||
|
||||
#include "renderer.h"
|
||||
|
||||
class renderer_texture {
|
||||
public:
|
||||
explicit renderer_texture(const texture_format in_format) : format(in_format) {}
|
||||
virtual ~renderer_texture() = default;
|
||||
|
||||
virtual void* lock(uint32_t* out_row_pitch) = 0;
|
||||
virtual void unlock() = 0;
|
||||
|
||||
virtual void update_subresource(const Eigen::AlignedBox2i& in_area, const void* in_buffer, uint32_t in_row_pitch) = 0;
|
||||
|
||||
virtual bool resize(const Eigen::Vector2i& size) = 0;
|
||||
virtual Eigen::Vector2i size() = 0;
|
||||
|
||||
virtual void* get_native_handle() = 0;
|
||||
virtual void* get_shader_resource_view() = 0;
|
||||
[[nodiscard]] texture_format get_format() const { return format; }
|
||||
|
||||
static void convert_rgb_to_rgba(const unsigned char* rgb, unsigned char* rgba, int width, int height) {
|
||||
for (int i = 0; i < width * height; ++i) {
|
||||
rgba[i * 4 + 0] = rgb[i * 3 + 0]; // R
|
||||
rgba[i * 4 + 1] = rgb[i * 3 + 1]; // G
|
||||
rgba[i * 4 + 2] = rgb[i * 3 + 2]; // B
|
||||
rgba[i * 4 + 3] = 255; // A (完全不透明)
|
||||
}
|
||||
}
|
||||
private:
|
||||
const texture_format format;
|
||||
};
|
||||
|
||||
class texture_format_converter {
|
||||
public:
|
||||
texture_format_converter(Eigen::Vector2i size, texture_format in_format, texture_format out_format) : size(size), in_format(in_format), out_format(out_format) {}
|
||||
|
||||
private:
|
||||
Eigen::Vector2i size;
|
||||
texture_format in_format;
|
||||
texture_format out_format;
|
||||
};
|
||||
@@ -1 +0,0 @@
|
||||
#include "renderer_texture_array.h"
|
||||
@@ -1,43 +0,0 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
#include "renderer.h"
|
||||
|
||||
class renderer_texture_array {
|
||||
public:
|
||||
explicit renderer_texture_array(const texture_format in_format) : format(in_format) {}
|
||||
virtual ~renderer_texture_array() = default;
|
||||
|
||||
virtual void* lock(const uint32_t index, uint32_t* out_row_pitch) = 0;
|
||||
virtual void unlock(const uint32_t index) = 0;
|
||||
|
||||
virtual void update_subresource(const uint32_t index, const Eigen::AlignedBox2i& in_area, const void* in_buffer, uint32_t in_buffer_size) = 0;
|
||||
|
||||
void set_count(const uint32_t in_count) {
|
||||
if (in_count > MAX_TEXTURE_SIZE) {
|
||||
throw std::runtime_error("Texture array size is too large.");
|
||||
}
|
||||
if (in_count == 0) {
|
||||
throw std::runtime_error("Texture array size must be greater than 0.");
|
||||
}
|
||||
if (in_count == get_count()) {
|
||||
return;
|
||||
}
|
||||
on_set_count(in_count);
|
||||
}
|
||||
|
||||
virtual bool resize(const Eigen::Vector2i& size) = 0;
|
||||
virtual Eigen::Vector2i size() = 0;
|
||||
|
||||
virtual void* get_native_handle() = 0;
|
||||
virtual void* get_shader_resource_view() = 0;
|
||||
|
||||
[[nodiscard]] virtual uint32_t get_count() = 0;
|
||||
[[nodiscard]] texture_format get_format() const { return format; }
|
||||
protected:
|
||||
virtual void on_set_count(uint32_t in_count) = 0;
|
||||
private:
|
||||
const uint32_t MAX_TEXTURE_SIZE = 256;
|
||||
|
||||
const texture_format format;
|
||||
};
|
||||
@@ -1,32 +0,0 @@
|
||||
#include "renderer_window.h"
|
||||
|
||||
#include "core/renderer/renderer.h"
|
||||
#include "GLFW/glfw3native.h"
|
||||
|
||||
renderer_window::~renderer_window() { if (window) glfwDestroyWindow(window); }
|
||||
|
||||
bool renderer_window::init(const Eigen::Vector2i& in_size, const std::string& in_title) {
|
||||
window = glfwCreateWindow(in_size.x(), in_size.y(), in_title.c_str(), nullptr, nullptr);
|
||||
if (!window) return false;
|
||||
return create_surface(window);
|
||||
}
|
||||
|
||||
Eigen::Matrix4f renderer_window::get_projection_matrix() const {
|
||||
return aorii::get_renderer_raw()->make_projection_matrix(get_window_size());
|
||||
}
|
||||
|
||||
void* renderer_window::get_window_handle() const {
|
||||
#if WINDOWS
|
||||
return glfwGetWin32Window(window);
|
||||
#elif MACOS
|
||||
return glfwGetCocoaWindow(window);
|
||||
#elif LINUX
|
||||
#if GLFW_EXPOSE_NATIVE_WAYLAND
|
||||
return glfwGetWaylandWindow(window);
|
||||
#else
|
||||
return (void*)glfwGetX11Window(window);
|
||||
#endif
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
#pragma once
|
||||
#include "Eigen/Eigen"
|
||||
#include "GLFW/glfw3.h"
|
||||
|
||||
class renderer_window {
|
||||
friend class window_manager;
|
||||
public:
|
||||
const float clear_color[4] = {1.f, 1.f, 1.f, 1.f};
|
||||
|
||||
virtual ~renderer_window();
|
||||
|
||||
virtual bool init(const Eigen::Vector2i& in_size, const std::string& in_title);
|
||||
|
||||
virtual void begin_frame() = 0;
|
||||
virtual void end_frame() = 0;
|
||||
|
||||
void resize(const Eigen::Vector2i& in_size) {
|
||||
if (in_size == get_window_size()) return;
|
||||
on_resize(in_size);
|
||||
}
|
||||
|
||||
[[nodiscard]] Eigen::Vector2i get_window_size() const {
|
||||
int w, h;
|
||||
glfwGetWindowSize(window, &w, &h);
|
||||
return { w, h };
|
||||
}
|
||||
|
||||
[[nodiscard]] Eigen::Vector2i get_framebuffer_size() const {
|
||||
int w, h;
|
||||
glfwGetFramebufferSize(window, &w, &h);
|
||||
return { w, h };
|
||||
}
|
||||
[[nodiscard]] Eigen::Matrix4f get_projection_matrix() const;
|
||||
|
||||
[[nodiscard]] void* get_window_handle() const;
|
||||
[[nodiscard]] GLFWwindow* get_glfw_window() const { return window; }
|
||||
protected:
|
||||
virtual bool create_surface(GLFWwindow* in_window) = 0;
|
||||
virtual void on_resize(const Eigen::Vector2i& in_size) = 0;
|
||||
private:
|
||||
GLFWwindow* window = nullptr;
|
||||
};
|
||||
@@ -1,44 +0,0 @@
|
||||
#include "window_manager.h"
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include "renderer_window.h"
|
||||
#include "core/renderer/renderer.h"
|
||||
|
||||
void on_window_size_change(GLFWwindow* changed_window, int width, int height) {
|
||||
aorii::s_window_manager->on_glfw_window_size_callback(changed_window, width, height);
|
||||
}
|
||||
|
||||
window_manager::~window_manager() {
|
||||
for (const auto window : windows) {
|
||||
aorii::get_renderer_raw()->destroy_window(window);
|
||||
}
|
||||
windows.clear();
|
||||
}
|
||||
|
||||
renderer_window* window_manager::create_window(const Eigen::Vector2i& in_size, const std::string& in_title) {
|
||||
const auto window = aorii::get_renderer_raw()->create_window();
|
||||
if (!window->init(in_size, in_title)) {
|
||||
delete window;
|
||||
spdlog::error("Failed to create window");
|
||||
return nullptr;
|
||||
}
|
||||
const auto glfw_window = window->get_glfw_window();
|
||||
glfwSetFramebufferSizeCallback(glfw_window, on_window_size_change);
|
||||
windows.push_back(window);
|
||||
return window;
|
||||
}
|
||||
|
||||
void window_manager::on_glfw_window_size_callback(GLFWwindow* in_window, int width, int height) {
|
||||
auto find = find_window(in_window);
|
||||
if (!find) return;
|
||||
find->on_resize({ width, height });
|
||||
}
|
||||
|
||||
renderer_window* window_manager::find_window(GLFWwindow* in_window) {
|
||||
auto it = std::find_if(windows.begin(), windows.end(), [in_window](renderer_window* w) {
|
||||
return w->get_glfw_window() == in_window;
|
||||
});
|
||||
if (it != windows.end()) { return *it; }
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
#pragma once
|
||||
#include "Eigen/Eigen"
|
||||
#include "GLFW/glfw3.h"
|
||||
|
||||
class renderer_window;
|
||||
|
||||
class window_manager {
|
||||
public:
|
||||
~window_manager();
|
||||
renderer_window* create_window(const Eigen::Vector2i& in_size, const std::string& in_title);
|
||||
|
||||
const auto& get_windows() const { return windows; }
|
||||
|
||||
void on_glfw_window_size_callback(GLFWwindow* in_window, int width, int height);
|
||||
private:
|
||||
renderer_window* find_window(GLFWwindow* in_window);
|
||||
std::vector<renderer_window*> windows;
|
||||
};
|
||||
|
||||
namespace aorii {
|
||||
inline window_manager* s_window_manager;
|
||||
inline void create_window_manager() { s_window_manager = new window_manager(); }
|
||||
inline void destroy_window_manager() { delete s_window_manager; }
|
||||
|
||||
inline renderer_window* create_window(const Eigen::Vector2i& in_size, const std::string& in_title) {
|
||||
return s_window_manager->create_window(in_size, in_title);
|
||||
}
|
||||
|
||||
inline const auto& get_all_window() { return s_window_manager->get_windows(); }
|
||||
}
|
||||
Reference in New Issue
Block a user