From 3a0593c3ff7a91114e82d25cc664a16e0be4b4fb Mon Sep 17 00:00:00 2001
From: Nanako <469449812@qq.com>
Date: Tue, 15 Oct 2024 10:11:53 +0800
Subject: [PATCH] init

---
 CMakeLists.txt                         | 15 +++++++
 cmake/retrieve_files.cmake             | 61 ++++++++++++++++++++++++++
 src/renderer/CMakeLists.txt            | 39 ++++++++++++++++
 src/renderer/backend/dx/dx_backend.cpp | 51 +++++++++++++++++++++
 src/renderer/backend/dx/dx_backend.h   | 22 ++++++++++
 src/renderer/backend/dx/dx_texture.cpp | 44 +++++++++++++++++++
 src/renderer/backend/dx/dx_texture.h   | 19 ++++++++
 src/renderer/renderer.cpp              | 29 ++++++++++++
 src/renderer/renderer.h                | 26 +++++++++++
 src/renderer/renderer_buffer.cpp       |  1 +
 src/renderer/renderer_buffer.h         |  5 +++
 src/renderer/renderer_texture.cpp      |  1 +
 src/renderer/renderer_texture.h        | 14 ++++++
 src/widget/CMakeLists.txt              |  0
 14 files changed, 327 insertions(+)
 create mode 100644 CMakeLists.txt
 create mode 100644 cmake/retrieve_files.cmake
 create mode 100644 src/renderer/CMakeLists.txt
 create mode 100644 src/renderer/backend/dx/dx_backend.cpp
 create mode 100644 src/renderer/backend/dx/dx_backend.h
 create mode 100644 src/renderer/backend/dx/dx_texture.cpp
 create mode 100644 src/renderer/backend/dx/dx_texture.h
 create mode 100644 src/renderer/renderer.cpp
 create mode 100644 src/renderer/renderer.h
 create mode 100644 src/renderer/renderer_buffer.cpp
 create mode 100644 src/renderer/renderer_buffer.h
 create mode 100644 src/renderer/renderer_texture.cpp
 create mode 100644 src/renderer/renderer_texture.h
 create mode 100644 src/widget/CMakeLists.txt

diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..4678e49
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,15 @@
+cmake_minimum_required(VERSION 3.10)
+project(aorii)
+
+include(cmake/retrieve_files.cmake)
+
+find_package(Eigen3 REQUIRED)
+find_package(spdlog REQUIRED)
+
+# 如果是Debug模式, 添加宏定义
+if (CMAKE_BUILD_TYPE STREQUAL "Debug")
+    add_definitions(-DDEBUG=1)
+endif()
+
+add_subdirectory(src/renderer)
+add_subdirectory(src/widget)
diff --git a/cmake/retrieve_files.cmake b/cmake/retrieve_files.cmake
new file mode 100644
index 0000000..756d614
--- /dev/null
+++ b/cmake/retrieve_files.cmake
@@ -0,0 +1,61 @@
+
+function(retrieve_files_custom path extension out_files)
+    message(STATUS "Retrieving files in ${path}")
+    set(EXTENSIONS "")
+    foreach(ext ${extension})
+        list(APPEND EXTENSIONS "${path}/*.${ext}")
+    endforeach ()
+
+    # 递归查找文件夹下的 .h .hpp. ini 文件保存到 HEAD_FILES
+    file(GLOB_RECURSE FIND_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} CONFIGURE_DEPENDS ${EXTENSIONS})
+    # 将 HEDADER_FILES 和 SRC_FILES 保存到 ALL_FILES 变量
+    set(ALL_FILES ${FIND_FILES})
+
+    set(RESULT "")
+
+    # 对 ALL_FILES 变量里面的所有文件分类(保留资源管理器的目录结构)
+    foreach(fileItem ${ALL_FILES})
+        # Get the directory of the source file
+        get_filename_component(PARENT_DIR "${fileItem}" DIRECTORY)
+
+        # 用于检查平台的条件
+        if(PARENT_DIR STREQUAL "windows")
+            if(WIN32)
+                set(RESULT "${RESULT};${fileItem}")
+            else()
+                continue()
+            endif()
+        elseif(PARENT_DIR STREQUAL "linux")
+            if(UNIX AND NOT APPLE)
+                set(RESULT "${RESULT};${fileItem}")
+            else()
+                continue()
+            endif()
+        elseif(PARENT_DIR STREQUAL "mac")
+            if(APPLE)
+                set(RESULT "${RESULT};${fileItem}")
+            else()
+                continue()
+            endif()
+        else()
+            # 如果文件夹名称不是平台,则始终包含
+            set(RESULT "${RESULT};${fileItem}")
+        endif()
+
+        # Remove common directory prefix to make the group
+        string(REPLACE "${path}" "" GROUP "${PARENT_DIR}")
+        # Make sure we are using windows slashes
+        string(REPLACE "/" "\\" GROUP "${GROUP}")
+        # Group into "Source Files" and "Header Files"
+        set(GROUP "${GROUP}")
+        source_group("${GROUP}" FILES "${fileItem}")
+    endforeach()
+
+    set(${out_files} ${RESULT} PARENT_SCOPE)
+endfunction()
+
+function(retrieve_files path out_files)
+    set(temp_files "")
+    retrieve_files_custom(${path} "h;hpp;ini;cpp;c;ixx" temp_files)
+    set(${out_files} ${${out_files}} ${temp_files} PARENT_SCOPE)
+endfunction()
diff --git a/src/renderer/CMakeLists.txt b/src/renderer/CMakeLists.txt
new file mode 100644
index 0000000..36c9a57
--- /dev/null
+++ b/src/renderer/CMakeLists.txt
@@ -0,0 +1,39 @@
+project(renderer)
+
+set(GL_BACKEND FALSE CACHE BOOL "OpenGL backend to use")
+set(DX_BACKEND FALSE CACHE BOOL "DirectX backend to use")
+set(VK_BACKEND FALSE CACHE BOOL "Vulkan backend to use")
+
+if (NOT GL_BACKEND AND NOT DX_BACKEND AND NOT VK_BACKEND)
+    message(FATAL_ERROR "No backend selected")
+endif()
+
+set(RENDERER_SOURCES
+        renderer.cpp
+        renderer.h
+        renderer_buffer.cpp
+        renderer_buffer.h
+        renderer_texture.cpp
+        renderer_texture.h
+)
+
+if (GL_BACKEND)
+    retrieve_files(backend/gl RENDERER_SOURCES)
+    add_definitions(-DGL_BACKEND=1)
+endif()
+if (DX_BACKEND)
+    retrieve_files(backend/dx RENDERER_SOURCES)
+    add_definitions(-DDX_BACKEND=1)
+endif ()
+if (VK_BACKEND)
+    retrieve_files(backend/vk RENDERER_SOURCES)
+    add_definitions(-DVK_BACKEND=1)
+endif ()
+
+add_library(${PROJECT_NAME} STATIC ${RENDERER_SOURCES})
+target_link_libraries(${PROJECT_NAME} Eigen3::Eigen spdlog::spdlog)
+target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
+
+if (DX_BACKEND)
+    target_link_libraries(${PROJECT_NAME} d3d11 d3dcompiler dxgi)
+endif ()
diff --git a/src/renderer/backend/dx/dx_backend.cpp b/src/renderer/backend/dx/dx_backend.cpp
new file mode 100644
index 0000000..90559f9
--- /dev/null
+++ b/src/renderer/backend/dx/dx_backend.cpp
@@ -0,0 +1,51 @@
+#include "dx_backend.h"
+
+#include "dx_texture.h"
+#include "spdlog/spdlog.h"
+
+std::shared_ptr<renderer_texture> dx_backend::create_texture(const Eigen::Vector2i& size) {
+    D3D11_TEXTURE2D_DESC desc = {};
+    desc.Width = size.x();
+    desc.Height = size.y();
+    desc.MipLevels = 1;
+    desc.ArraySize = 1;
+    desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+    desc.SampleDesc.Count = 1;
+    desc.SampleDesc.Quality = 0;
+    desc.Usage = D3D11_USAGE_DYNAMIC;
+    desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
+    desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+    desc.MiscFlags = 0;
+
+    ID3D11Texture2D* texture = nullptr;
+    if (FAILED(device->CreateTexture2D(&desc, nullptr, &texture))) {
+        return nullptr;
+    }
+
+    return std::make_shared<dx_texture>(texture);
+}
+
+void dx_backend::destroy_texture(renderer_texture* texture) {
+#ifdef DEBUG
+    spdlog::info("Destroying texture");
+#endif
+}
+
+bool dx_backend::init() {
+    if (!create_device())
+        return false;
+    if (!create_context())
+        return false;
+    return true;
+}
+
+bool dx_backend::create_device() {
+    D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_11_1 };
+    const auto result = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, featureLevels, 2, D3D11_SDK_VERSION, &device, nullptr, nullptr);
+    return SUCCEEDED(result);
+}
+
+bool dx_backend::create_context() {
+    device->GetImmediateContext(&context);
+    return true;
+}
diff --git a/src/renderer/backend/dx/dx_backend.h b/src/renderer/backend/dx/dx_backend.h
new file mode 100644
index 0000000..8c6887f
--- /dev/null
+++ b/src/renderer/backend/dx/dx_backend.h
@@ -0,0 +1,22 @@
+#pragma once
+#include "renderer.h"
+#include <d3d11.h>
+
+class dx_backend : public renderer {
+    inline static dx_backend* instance = nullptr;
+public:
+    static dx_backend* get_instance() {
+        return static_cast<dx_backend*>(aorii::s_renderer);
+    }
+    bool init() override;
+
+    std::shared_ptr<renderer_texture> create_texture(const Eigen::Vector2i& size) override;
+    void destroy_texture(renderer_texture* texture) override;
+private:
+    bool create_device();
+    bool create_context();
+
+    ID3D11Device* device = nullptr;
+    ID3D11DeviceContext* context = nullptr;
+};
+
diff --git a/src/renderer/backend/dx/dx_texture.cpp b/src/renderer/backend/dx/dx_texture.cpp
new file mode 100644
index 0000000..dd3173f
--- /dev/null
+++ b/src/renderer/backend/dx/dx_texture.cpp
@@ -0,0 +1,44 @@
+#include "dx_texture.h"
+
+#include "dx_backend.h"
+
+dx_texture::dx_texture(ID3D11Texture2D* texture) {
+    m_texture = texture;
+}
+
+dx_texture::~dx_texture() {
+    // 如果是Debug模式, 检查m_data是否被释放
+#if defined(DEBUG)
+    assert(!m_data);
+#endif
+    free(m_data);
+}
+
+void* dx_texture::lock() {
+    D3D11_TEXTURE2D_DESC desc;
+    m_texture->GetDesc(&desc);
+    m_data = new char[desc.Width * desc.Height * 4];
+    return m_data;
+}
+
+void dx_texture::unlock() {
+    D3D11_TEXTURE2D_DESC desc;
+    m_texture->GetDesc(&desc);
+    D3D11_MAPPED_SUBRESOURCE mappedResource;
+    auto context = dx_backend::get_instance();
+    context->Map(m_texture.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
+    memcpy(mappedResource.pData, m_data, desc.Width * desc.Height * 4);
+    context->Unmap(m_texture.get(), 0);
+    delete[] m_data;
+    m_data = nullptr;
+}
+
+bool dx_texture::resize(const Eigen::Vector2i& size) {
+    return true;
+}
+
+Eigen::Vector2i dx_texture::size() {
+    D3D11_TEXTURE2D_DESC desc;
+    m_texture->GetDesc(&desc);
+    return { desc.Width, desc.Height };
+}
diff --git a/src/renderer/backend/dx/dx_texture.h b/src/renderer/backend/dx/dx_texture.h
new file mode 100644
index 0000000..ec26d23
--- /dev/null
+++ b/src/renderer/backend/dx/dx_texture.h
@@ -0,0 +1,19 @@
+#pragma once
+#include "renderer_texture.h"
+#include <d3d11.h>
+#include <memory>
+
+// DX11纹理
+class dx_texture : public renderer_texture {
+public:
+    explicit dx_texture(ID3D11Texture2D* texture);
+    ~dx_texture() override;
+    void* lock() override;
+    void unlock() override;
+
+    bool resize(const Eigen::Vector2i& size) override;
+    Eigen::Vector2i size() override;
+private:
+    void* m_data = nullptr;
+    ID3D11Texture2D* m_texture;
+};
diff --git a/src/renderer/renderer.cpp b/src/renderer/renderer.cpp
new file mode 100644
index 0000000..6f2c98e
--- /dev/null
+++ b/src/renderer/renderer.cpp
@@ -0,0 +1,29 @@
+#include "renderer.h"
+
+#ifdef DX_BACKEND
+#include "backend/dx/dx_backend.h"
+#endif
+
+bool aorii::create_renderer(renderer_api api) {
+    if (s_renderer)
+        return true;
+    switch (api) {
+#ifdef DX_BACKEND
+    case renderer_api::dx11:
+        s_renderer = new dx_backend();
+        break;
+#endif
+#ifdef GL_BACKEND
+    case renderer_api::opengl:
+        break;
+#endif
+#ifdef VK_BACKEND
+    case renderer_api::vulkan:
+        break;
+#endif
+    default:
+        assert(false);
+        break;
+    }
+    return s_renderer->init();
+}
diff --git a/src/renderer/renderer.h b/src/renderer/renderer.h
new file mode 100644
index 0000000..ef6e304
--- /dev/null
+++ b/src/renderer/renderer.h
@@ -0,0 +1,26 @@
+#pragma once
+#include <memory>
+#include <Eigen/Eigen>
+
+class renderer_texture;
+
+enum class renderer_api {
+    dx11,
+    opengl,
+    vulkan,
+};
+
+class renderer {
+public:
+    virtual ~renderer() = default;
+
+    virtual std::shared_ptr<renderer_texture> create_texture(const Eigen::Vector2i& size) = 0;
+    virtual void destroy_texture(renderer_texture* texture) = 0;
+
+    virtual bool init() = 0;
+};
+
+namespace aorii {
+    inline static renderer* s_renderer = nullptr;
+    bool create_renderer(renderer_api api);
+}
diff --git a/src/renderer/renderer_buffer.cpp b/src/renderer/renderer_buffer.cpp
new file mode 100644
index 0000000..c70f4d9
--- /dev/null
+++ b/src/renderer/renderer_buffer.cpp
@@ -0,0 +1 @@
+#include "renderer_buffer.h"
diff --git a/src/renderer/renderer_buffer.h b/src/renderer/renderer_buffer.h
new file mode 100644
index 0000000..4d7ccc0
--- /dev/null
+++ b/src/renderer/renderer_buffer.h
@@ -0,0 +1,5 @@
+#pragma once
+
+class renderer_buffer {
+
+};
diff --git a/src/renderer/renderer_texture.cpp b/src/renderer/renderer_texture.cpp
new file mode 100644
index 0000000..a80fe0a
--- /dev/null
+++ b/src/renderer/renderer_texture.cpp
@@ -0,0 +1 @@
+#include "renderer_texture.h"
diff --git a/src/renderer/renderer_texture.h b/src/renderer/renderer_texture.h
new file mode 100644
index 0000000..eb37a69
--- /dev/null
+++ b/src/renderer/renderer_texture.h
@@ -0,0 +1,14 @@
+#pragma once
+#include <Eigen/Eigen>
+
+class renderer_texture {
+public:
+    virtual ~renderer_texture() = default;
+
+
+    virtual void* lock() = 0;
+    virtual void unlock() = 0;
+
+    virtual bool resize(const Eigen::Vector2i& size) = 0;
+    virtual Eigen::Vector2i size() = 0;
+};
diff --git a/src/widget/CMakeLists.txt b/src/widget/CMakeLists.txt
new file mode 100644
index 0000000..e69de29