1
0

finish buggy dx11 code

This commit is contained in:
2026-01-04 23:11:58 +08:00
parent a66d3dee8b
commit 7b234ec405
12 changed files with 432 additions and 219 deletions

View File

@@ -24,8 +24,9 @@ option(BASALT_PIPE_DELIVER "Build with system pipe data deliver support." OFF)
# 3D Objects Loaders # 3D Objects Loaders
option(BASALT_OBJ_OBJECT_LOADER "Build with Wavefront OBJ 3D object loader support." OFF) option(BASALT_OBJ_OBJECT_LOADER "Build with Wavefront OBJ 3D object loader support." OFF)
option(BASALT_GLTF_OBJECT_LOADER "Build with glTF 3D object loader support." OFF) option(BASALT_GLTF_OBJECT_LOADER "Build with glTF 3D object loader support." OFF)
option(BASALT_ASSIMP_OBJECT_LOADER "Build with Assimp 3D object loader support." OFF)
# Camera Motion Loaders # Camera Motion Loaders
option(BASALT_UNKNOWN_ANIME_LOADER "Build with Unknown camera motion loader support." OFF) option(BASALT_homemade_ANIME_LOADER "Build with homemade camera motion loader support." OFF)
# Set C++ standards # Set C++ standards
set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD 23)
@@ -35,10 +36,11 @@ set(CMAKE_CXX_EXTENSIONS OFF)
# Include some essential CMake components # Include some essential CMake components
include(GNUInstallDirs) include(GNUInstallDirs)
# Find required packages based on options # Add out CMake in module found path
set(CMAKE_MODULE_PATH set(CMAKE_MODULE_PATH
"${CMAKE_CURRENT_LIST_DIR}/CMake" "${CMAKE_CURRENT_LIST_DIR}/CMake"
) )
# Find required packages based on options
if (BASALT_CUDA_DELIVER) if (BASALT_CUDA_DELIVER)
find_package(CUDA REQUIRED) find_package(CUDA REQUIRED)
endif () endif ()

View File

@@ -1,27 +1,27 @@
# Create shared library # Create shared library
add_library(PipeDeliver SHARED "") add_library(BasaltPipeDeliver SHARED "")
# Setup sources # Setup sources
target_sources(PipeDeliver target_sources(BasaltPipeDeliver
PRIVATE PRIVATE
main.cpp main.cpp
) )
# Setup header infomation # Setup header infomation
target_include_directories(PipeDeliver target_include_directories(BasaltPipeDeliver
PRIVATE PRIVATE
"${CMAKE_CURRENT_LIST_DIR}" "${CMAKE_CURRENT_LIST_DIR}"
) )
# Setup linked library infomation # Setup linked library infomation
target_link_libraries(PipeDeliver target_link_libraries(BasaltPipeDeliver
PRIVATE PRIVATE
BasaltShared BasaltShared
) )
# Enable export macro # Enable export macro
target_compile_definitions(PipeDeliver target_compile_definitions(BasaltPipeDeliver
PRIVATE PRIVATE
BS_EXPORTING BS_EXPORTING
) )
# Install PipeDeliver only on Release mode # Install BasaltPipeDeliver only on Release mode
install(TARGETS PipeDeliver install(TARGETS BasaltPipeDeliver
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}/plugins/engine" RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}/plugin/deliver"
) )

View File

@@ -1,28 +1,28 @@
# Create shared library # Create shared library
add_library(DirectX11Engine SHARED "") add_library(BasaltDirectX11Engine SHARED "")
# Setup sources # Setup sources
target_sources(DirectX11Engine target_sources(BasaltDirectX11Engine
PRIVATE PRIVATE
main.cpp main.cpp
) )
# Setup header infomation # Setup header infomation
target_include_directories(DirectX11Engine target_include_directories(BasaltDirectX11Engine
PRIVATE PRIVATE
"${CMAKE_CURRENT_LIST_DIR}" "${CMAKE_CURRENT_LIST_DIR}"
) )
# Setup linked library infomation # Setup linked library infomation
target_link_libraries(DirectX11Engine target_link_libraries(BasaltDirectX11Engine
PRIVATE PRIVATE
BasaltShared BasaltShared
${DirectX11_LIBRARY} ${DirectX11_LIBRARY}
) )
# Enable export macro # Enable export macro
target_compile_definitions(DirectX11Engine target_compile_definitions(BasaltDirectX11Engine
PRIVATE PRIVATE
BS_EXPORTING BS_EXPORTING
) )
# Install DirectX11Engine only on Release mode # Install BasaltDirectX11Engine only on Release mode
install(TARGETS DirectX11Engine install(TARGETS BasaltDirectX11Engine
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}/plugins/engine" RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}/plugin/engine"
) )

View File

@@ -1,4 +1,5 @@
#include <basalt_export.hpp> #include <basalt_export.hpp>
#include <directx_util.hpp>
#include <engine.hpp> #include <engine.hpp>
#include <windows.h> #include <windows.h>
#include <d3d11.h> #include <d3d11.h>
@@ -8,204 +9,78 @@
#include <iostream> #include <iostream>
using Microsoft::WRL::ComPtr; using Microsoft::WRL::ComPtr;
#define DXCHK(condition) \
if (FAILED(condition)) { \
throw std::runtime_error("bad DirectX calling"); \
}
// 常量 // 立方体顶点(位置)
constexpr UINT Width = 800;
constexpr UINT Height = 600;
constexpr const wchar_t* PipeName = L"\\\\.\\pipe\\54da494c-301a-47a9-9d67-4fbebaeda8cf";
// 立方体顶点(位置)
struct Vertex { struct Vertex {
float x, y, z; float x, y, z;
}; };
// 立方体顶点
Vertex CubeVertices[] = { Vertex CubeVertices[] = {
// 前面 // 前面
{-1, -1, -1}, {-1, -1, -1},
{1, -1, -1}, {1, -1, -1},
{1, 1, -1}, {1, 1, -1},
{-1, -1, -1}, {-1, -1, -1},
{1, 1, -1}, {1, 1, -1},
{-1, 1, -1}, {-1, 1, -1},
// 后面 // 后面
{-1, -1, 1}, {-1, -1, 1},
{-1, 1, 1}, {-1, 1, 1},
{1, 1, 1}, {1, 1, 1},
{-1, -1, 1}, {-1, -1, 1},
{1, 1, 1}, {1, 1, 1},
{1, -1, 1}, {1, -1, 1},
// 其他面...(为简化,此处略,或用完整立方体) // 左面
// 实际建议使用完整12个三角面36顶点 {-1, -1, -1},
{-1, -1, 1},
{-1, 1, 1},
{-1, -1, -1},
{-1, 1, 1},
{-1, 1, -1},
// 右面
{1, -1, -1},
{1, 1, -1},
{1, 1, 1},
{1, -1, -1},
{1, 1, 1},
{1, -1, 1},
// 顶面
{-1, 1, -1},
{1, 1, -1},
{1, 1, 1},
{-1, 1, -1},
{1, 1, 1},
{-1, 1, 1},
// 底面
{-1, -1, -1},
{-1, -1, 1},
{1, -1, 1},
{-1, -1, -1},
{1, -1, 1},
{1, -1, -1}
}; };
// 为简化,这里只渲染前面,实际请补全
// 简单顶点着色器(只传位置) // 简单顶点着色器(只传位置)
const char* g_VS = R"( const char* g_VS = R"(
float4 main(float3 pos : POSITION) : SV_POSITION { float4 main(float3 pos : POSITION) : SV_POSITION {
return float4(pos, 1.0f); return float4(pos, 1.0f);
} }
)"; )";
// 简单像素着色器(返回固定颜色) // 简单像素着色器(返回固定颜色)
const char* g_PS = R"( const char* g_PS = R"(
float4 main() : SV_TARGET { float4 main() : SV_TARGET {
return float4(0.2f, 0.4f, 0.8f, 1.0f); return float4(0.2f, 0.4f, 0.8f, 1.0f);
} }
)"; )";
int main() {
// 初始化 COM
CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
// 创建设备和上下文
ComPtr<ID3D11Device> device;
ComPtr<ID3D11DeviceContext> context;
D3D11CreateDevice(
nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, D3D11_CREATE_DEVICE_DEBUG, nullptr, 0, D3D11_SDK_VERSION, &device, nullptr, &context);
// 创建交换链(窗口可选,这里仅用于渲染上下文)
ComPtr<IDXGISwapChain> swapChain;
DXGI_SWAP_CHAIN_DESC sd = {};
sd.BufferDesc.Width = Width;
sd.BufferDesc.Height = Height;
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
sd.SampleDesc.Count = 1;
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
sd.BufferCount = 1;
sd.OutputWindow = GetConsoleWindow(); // 或创建窗口
sd.Windowed = TRUE;
ComPtr<IDXGIDevice> dxgiDevice;
device.As(&dxgiDevice);
ComPtr<IDXGIAdapter> adapter;
dxgiDevice->GetAdapter(&adapter);
ComPtr<IDXGIFactory> factory;
adapter->GetParent(IID_PPV_ARGS(&factory));
factory->CreateSwapChain(device.Get(), &sd, &swapChain);
// 创建渲染目标
ComPtr<ID3D11RenderTargetView> rtv;
ComPtr<ID3D11Texture2D> backBuffer;
swapChain->GetBuffer(0, IID_PPV_ARGS(&backBuffer));
device->CreateRenderTargetView(backBuffer.Get(), nullptr, &rtv);
// 创建深度缓冲D32_FLOAT
ComPtr<ID3D11Texture2D> depthBuffer;
D3D11_TEXTURE2D_DESC depthDesc = {};
depthDesc.Width = Width;
depthDesc.Height = Height;
depthDesc.MipLevels = 1;
depthDesc.ArraySize = 1;
depthDesc.Format = DXGI_FORMAT_D32_FLOAT;
depthDesc.SampleDesc.Count = 1;
depthDesc.Usage = D3D11_USAGE_DEFAULT;
depthDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
device->CreateTexture2D(&depthDesc, nullptr, &depthBuffer);
ComPtr<ID3D11DepthStencilView> dsv;
device->CreateDepthStencilView(depthBuffer.Get(), nullptr, &dsv);
// 创建 staging texture 用于 CPU 读取深度R32_FLOAT
ComPtr<ID3D11Texture2D> depthStaging;
D3D11_TEXTURE2D_DESC stagingDesc = depthDesc;
stagingDesc.Format = DXGI_FORMAT_R32_FLOAT; // 注意DSV 用 D32_FLOATstaging 用 R32_FLOAT
stagingDesc.BindFlags = 0;
stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
stagingDesc.Usage = D3D11_USAGE_STAGING;
device->CreateTexture2D(&stagingDesc, nullptr, &depthStaging);
// 编译并创建着色器
ComPtr<ID3D11VertexShader> vs;
ComPtr<ID3D11PixelShader> ps;
ComPtr<ID3DBlob> vsBlob, psBlob;
D3DCompile(g_VS, strlen(g_VS), nullptr, nullptr, nullptr, "main", "vs_4_0", 0, 0, &vsBlob, nullptr);
D3DCompile(g_PS, strlen(g_PS), nullptr, nullptr, nullptr, "main", "ps_4_0", 0, 0, &psBlob, nullptr);
device->CreateVertexShader(vsBlob->GetBufferPointer(), vsBlob->GetBufferSize(), nullptr, &vs);
device->CreatePixelShader(psBlob->GetBufferPointer(), psBlob->GetBufferSize(), nullptr, &ps);
// 输入布局
D3D11_INPUT_ELEMENT_DESC layout[] = {{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}};
ComPtr<ID3D11InputLayout> inputLayout;
device->CreateInputLayout(layout, 1, vsBlob->GetBufferPointer(), vsBlob->GetBufferSize(), &inputLayout);
// 顶点缓冲
ComPtr<ID3D11Buffer> vertexBuffer;
D3D11_BUFFER_DESC vbDesc = {};
vbDesc.ByteWidth = sizeof(CubeVertices);
vbDesc.Usage = D3D11_USAGE_DEFAULT;
vbDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
D3D11_SUBRESOURCE_DATA vbData = {CubeVertices};
device->CreateBuffer(&vbDesc, &vbData, &vertexBuffer);
// 深度测试启用
ComPtr<ID3D11DepthStencilState> depthState;
D3D11_DEPTH_STENCIL_DESC dsDesc = {};
dsDesc.DepthEnable = TRUE;
dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
dsDesc.DepthFunc = D3D11_COMPARISON_LESS;
device->CreateDepthStencilState(&dsDesc, &depthState);
// 视口
D3D11_VIEWPORT vp = {0, 0, (float) Width, (float) Height, 0, 1};
context->RSSetViewports(1, &vp);
// 打开命名管道(需另一进程已创建)
HANDLE hPipe = CreateFileW(PipeName, GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
if (hPipe == INVALID_HANDLE_VALUE) {
std::cerr << "Failed to open named pipe. Ensure another process created it.\n";
return -1;
}
constexpr size_t depthSize = Width * Height * sizeof(float);
std::vector<BYTE> depthData(depthSize);
// 渲染循环示例只渲染10帧
for (int frame = 0; frame < 10; ++frame) {
// 清屏
float clearColor[] = {0.1f, 0.1f, 0.1f, 1.0f};
context->ClearRenderTargetView(rtv.Get(), clearColor);
context->ClearDepthStencilView(dsv.Get(), D3D11_CLEAR_DEPTH, 1.0f, 0);
// 设置管线
context->OMSetRenderTargets(1, rtv.GetAddressOf(), dsv.Get());
context->OMSetDepthStencilState(depthState.Get(), 1);
context->VSSetShader(vs.Get(), nullptr, 0);
context->PSSetShader(ps.Get(), nullptr, 0);
context->IASetInputLayout(inputLayout.Get());
UINT stride = sizeof(Vertex), offset = 0;
context->IASetVertexBuffers(0, 1, vertexBuffer.GetAddressOf(), &stride, &offset);
context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
// 绘制立方体
context->Draw(6, 0); // 仅前面实际应为36
// 复制深度缓冲到 staging texture
context->CopyResource(depthStaging.Get(), depthBuffer.Get());
// Map 获取数据
D3D11_MAPPED_SUBRESOURCE mapped;
context->Map(depthStaging.Get(), 0, D3D11_MAP_READ, 0, &mapped);
memcpy(depthData.data(), mapped.pData, depthSize);
context->Unmap(depthStaging.Get(), 0);
// 写入命名管道
DWORD written;
if (!WriteFile(hPipe, depthData.data(), static_cast<DWORD>(depthSize), &written, nullptr) || written != depthSize) {
std::cerr << "WriteFile failed or incomplete.\n";
break;
}
// 呈现(可选)
swapChain->Present(0, 0);
}
CloseHandle(hPipe);
CoUninitialize();
return 0;
}
using ::Basalt::Shared::Engine::EngineConfig; using ::Basalt::Shared::Engine::EngineConfig;
using ::Basalt::Shared::Engine::IEngine; using ::Basalt::Shared::Engine::IEngine;
namespace DxUtil = ::Basalt::Shared::DirectX;
class DirectX11Engine : public IEngine { class DirectX11Engine : public IEngine {
public: public:
@@ -213,15 +88,198 @@ public:
virtual ~DirectX11Engine() {} virtual ~DirectX11Engine() {}
private: private:
ComPtr<ID3D11Device> device; ///< 设备 ComPtr<ID3D11Device> device; ///< 设备
ComPtr<ID3D11DeviceContext> context; ///< 上下文 ComPtr<ID3D11DeviceContext> context; ///< 上下文
ComPtr<IDXGISwapChain> swapChain; ///< 交换链 ComPtr<IDXGISwapChain> swap_chain; ///< 交换链
ComPtr<ID3D11RenderTargetView> rtv; ///< 渲染目标视图
ComPtr<ID3D11Texture2D> back_buffer; ///< 后缓冲
ComPtr<ID3D11Texture2D> depth_buffer; ///< 深度缓冲
ComPtr<ID3D11DepthStencilView> dsv; ///< 深度模板视图
ComPtr<ID3D11Texture2D> depth_staging; ///< 用于CPU读取的深度暂存纹理
ComPtr<ID3D11VertexShader> vs; ///< 顶点着色器
ComPtr<ID3D11PixelShader> ps; ///< 像素着色器
ComPtr<ID3DBlob> vs_blob; ///< 顶点着色器字节码
ComPtr<ID3DBlob> ps_blob; ///< 像素着色器字节码
ComPtr<ID3D11InputLayout> input_layout; ///< 输入布局
ComPtr<ID3D11Buffer> vertex_buffer; ///< 顶点缓冲
ComPtr<ID3D11DepthStencilState> depth_state; ///< 深度状态
std::vector<BYTE> depth_data; ///< 深度数据
public: public:
virtual void Startup(EngineConfig&& config) override { IEngine::Startup(std::move(config)); } virtual void Startup(EngineConfig&& config) override {
virtual void Tick() override { IEngine::Tick(); } IEngine::Startup(std::move(config));
virtual void Shutdown() override { IEngine::Shutdown(); }
// 初始化 COM
DXCHK(CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED));
// 创建设备和上下文
DXCHK(D3D11CreateDevice(nullptr,
D3D_DRIVER_TYPE_HARDWARE,
nullptr,
D3D11_CREATE_DEVICE_DEBUG,
nullptr,
0,
D3D11_SDK_VERSION,
&device,
nullptr,
&context));
// 创建交换链(窗口可选,这里仅用于渲染上下文)
DXGI_SWAP_CHAIN_DESC sd = {};
sd.BufferDesc.Width = this->config.width;
sd.BufferDesc.Height = this->config.height;
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
sd.SampleDesc.Count = 1;
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
sd.BufferCount = 1;
sd.OutputWindow = DxUtil::CreateRenderWindow(this->config.width, this->config.height, this->config.title); // 创建窗口
sd.Windowed = TRUE;
ComPtr<IDXGIDevice> dxgi_device;
DXCHK(device.As(&dxgi_device));
ComPtr<IDXGIAdapter> adapter;
DXCHK(dxgi_device->GetAdapter(&adapter));
ComPtr<IDXGIFactory> factory;
DXCHK(adapter->GetParent(IID_PPV_ARGS(&factory)));
DXCHK(factory->CreateSwapChain(device.Get(), &sd, &swap_chain));
// 创建渲染目标
DXCHK(swap_chain->GetBuffer(0, IID_PPV_ARGS(&back_buffer)));
DXCHK(device->CreateRenderTargetView(back_buffer.Get(), nullptr, &rtv));
// 创建深度缓冲D32_FLOAT
D3D11_TEXTURE2D_DESC depth_desc = {};
depth_desc.Width = this->config.width;
depth_desc.Height = this->config.height;
depth_desc.MipLevels = 1;
depth_desc.ArraySize = 1;
depth_desc.Format = DXGI_FORMAT_D32_FLOAT;
depth_desc.SampleDesc.Count = 1;
depth_desc.Usage = D3D11_USAGE_DEFAULT;
depth_desc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
DXCHK(device->CreateTexture2D(&depth_desc, nullptr, &depth_buffer));
DXCHK(device->CreateDepthStencilView(depth_buffer.Get(), nullptr, &dsv));
// 创建 staging texture 用于 CPU 读取深度R32_FLOAT
D3D11_TEXTURE2D_DESC staging_desc = depth_desc;
staging_desc.Format = DXGI_FORMAT_R32_FLOAT; // 注意DSV 用 D32_FLOATstaging 用 R32_FLOAT
staging_desc.BindFlags = 0;
staging_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
staging_desc.Usage = D3D11_USAGE_STAGING;
DXCHK(device->CreateTexture2D(&staging_desc, nullptr, &depth_staging));
// 编译并创建着色器
DXCHK(D3DCompile(g_VS, static_cast<UINT>(strlen(g_VS)), nullptr, nullptr, nullptr, "main", "vs_4_0", 0, 0, &vs_blob, nullptr));
DXCHK(D3DCompile(g_PS, static_cast<UINT>(strlen(g_PS)), nullptr, nullptr, nullptr, "main", "ps_4_0", 0, 0, &ps_blob, nullptr));
DXCHK(device->CreateVertexShader(vs_blob->GetBufferPointer(), vs_blob->GetBufferSize(), nullptr, &vs));
DXCHK(device->CreatePixelShader(ps_blob->GetBufferPointer(), ps_blob->GetBufferSize(), nullptr, &ps));
// 输入布局
D3D11_INPUT_ELEMENT_DESC layout[] = {{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}};
DXCHK(device->CreateInputLayout(layout, 1, vs_blob->GetBufferPointer(), vs_blob->GetBufferSize(), &input_layout));
// 顶点缓冲
D3D11_BUFFER_DESC vb_desc = {};
vb_desc.ByteWidth = sizeof(CubeVertices);
vb_desc.Usage = D3D11_USAGE_DEFAULT;
vb_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
D3D11_SUBRESOURCE_DATA vb_data = {CubeVertices};
DXCHK(device->CreateBuffer(&vb_desc, &vb_data, &vertex_buffer));
// 深度测试启用
D3D11_DEPTH_STENCIL_DESC ds_desc = {};
ds_desc.DepthEnable = TRUE;
ds_desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
ds_desc.DepthFunc = D3D11_COMPARISON_LESS;
DXCHK(device->CreateDepthStencilState(&ds_desc, &depth_state));
// 视口
D3D11_VIEWPORT vp;
ZeroMemory(&vp, sizeof(D3D11_VIEWPORT));
vp.TopLeftX = 0;
vp.TopLeftY = 0;
vp.Width = (float) this->config.width;
vp.Height = (float) this->config.height;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
context->RSSetViewports(1, &vp); // RSSetViewports doesn't return HRESULT, so no need to wrap
//// 打开命名管道(需另一进程已创建)
//constexpr const wchar_t* PipeName = L"\\\\.\\pipe\\54da494c-301a-47a9-9d67-4fbebaeda8cf";
//hPipe = CreateFileW(PipeName, GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
//if (hPipe == INVALID_HANDLE_VALUE) {
// std::cerr << "Failed to open named pipe. Ensure another process created it.\n";
// return;
//}
// 缩放深度数据数组到指定大小
depth_data.resize(this->config.width * this->config.height * sizeof(float));
// 设置管线
context->OMSetRenderTargets(1, rtv.GetAddressOf(), dsv.Get());
context->OMSetDepthStencilState(depth_state.Get(), 1);
context->VSSetShader(vs.Get(), nullptr, 0);
context->PSSetShader(ps.Get(), nullptr, 0);
context->IASetInputLayout(input_layout.Get());
UINT stride = sizeof(Vertex), offset = 0;
context->IASetVertexBuffers(0, 1, vertex_buffer.GetAddressOf(), &stride, &offset);
context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
//frameCount = 0;
}
virtual void Tick() override {
IEngine::Tick();
// 清屏
float clear_color[] = {0.8f, 0.1f, 0.1f, 1.0f};
context->ClearRenderTargetView(rtv.Get(), clear_color);
//context->ClearDepthStencilView(dsv.Get(), D3D11_CLEAR_DEPTH, 1.0f, 0);
//// 设置管线
//context->OMSetRenderTargets(1, rtv.GetAddressOf(), dsv.Get());
//context->OMSetDepthStencilState(depth_state.Get(), 1);
//context->VSSetShader(vs.Get(), nullptr, 0);
//context->PSSetShader(ps.Get(), nullptr, 0);
//context->IASetInputLayout(input_layout.Get());
//UINT stride = sizeof(Vertex), offset = 0;
//context->IASetVertexBuffers(0, 1, vertex_buffer.GetAddressOf(), &stride, &offset);
//context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
// 绘制立方体
context->Draw(sizeof(CubeVertices) / sizeof(Vertex), 0); // 自动计算顶点数
//// 复制深度缓冲到 staging texture
//context->CopyResource(depth_staging.Get(), depth_buffer.Get());
//// Map 获取数据
//D3D11_MAPPED_SUBRESOURCE mapped;
//DXCHK(context->Map(depth_staging.Get(), 0, D3D11_MAP_READ, 0, &mapped));
//memcpy(depth_data.data(), mapped.pData, this->config.width * this->config.height * sizeof(float));
//context->Unmap(depth_staging.Get(), 0);
//// 写入命名管道
//DWORD written;
//if (!WriteFile(hPipe, depth_data.data(), static_cast<DWORD>(this->config.width * this->config.height * sizeof(float)), &written, nullptr) || written != this->config.width * this->config.height * sizeof(float)) {
// std::cerr << "WriteFile failed or incomplete.\n";
//}
// 呈现(可选)
DXCHK(swap_chain->Present(0, 0));
//frameCount++;
}
virtual void Shutdown() override {
IEngine::Shutdown();
//if (hPipe != INVALID_HANDLE_VALUE) {
// CloseHandle(hPipe);
//}
CoUninitialize();
}
}; };
BS_EXPORT void* BSCreateInstance() { BS_EXPORT void* BSCreateInstance() {
@@ -230,4 +288,4 @@ BS_EXPORT void* BSCreateInstance() {
BS_EXPORT void BSDestroyInstance(void* instance) { BS_EXPORT void BSDestroyInstance(void* instance) {
delete reinterpret_cast<DirectX11Engine*>(instance); delete reinterpret_cast<DirectX11Engine*>(instance);
} }

View File

@@ -19,3 +19,6 @@ PRIVATE
BasaltShared BasaltShared
) )
install(TARGETS BasaltPresenter
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)

View File

@@ -1,18 +1,67 @@
#include "dll_loader.hpp" #include "dll_loader.hpp"
#include <basalt_char.hpp>
#include <stdexcept> #include <stdexcept>
#include <filesystem>
#if defined(BASALT_OS_WINDOWS)
#include <windows.h>
#else
#include <unistd.h>
#endif
namespace Basalt::Presenter { namespace Basalt::Presenter {
DllLoader::DllLoader(DllKind kind, const std::basic_string_view<BSCHAR> filename) { static std::filesystem::path get_executable() {
// TODO:
// Add current executable location supports.
// Add sub directories supports.
// Fix file name terminal error.
#if defined(BASALT_OS_WINDOWS) #if defined(BASALT_OS_WINDOWS)
m_Handle = LoadLibraryW(filename.data()); wchar_t buffer[MAX_PATH];
DWORD hr = GetModuleFileNameW(NULL, buffer, MAX_PATH);
if (hr == 0) {
throw std::runtime_error("Failed to get executable path");
} else {
return std::filesystem::path(buffer);
}
#else #else
m_Handle = dlopen(filename.data(), RTLD_LAZY); char buffer[PATH_MAX];
ssize_t len = readlink("/proc/self/exe", buffer, sizeof(buffer) - 1);
if (len != -1) {
buffer[len] = '\0';
return std::filesystem::path(buffer);
} else {
throw std::runtime_error("Failed to get executable path");
}
#endif #endif
}
DllLoader::DllLoader(DllKind kind, const std::basic_string_view<BSCHAR> filename) {
// Build DLL full path
auto dll_path = get_executable().parent_path();
dll_path /= BSTEXT("plugin");
switch (kind) {
case DllKind::Engine:
dll_path /= BSTEXT("engine");
break;
case DllKind::Deliver:
dll_path /= BSTEXT("deliver");
break;
case DllKind::ObjectLoader:
dll_path /= BSTEXT("object_loader");
break;
case DllKind::AnimeLoader:
dll_path /= BSTEXT("anime_loader");
break;
}
dll_path /= filename;
#if defined(BASALT_OS_WINDOWS)
dll_path.replace_extension(BSTEXT(".dll"));
#endif
// Load DLL
#if defined(BASALT_OS_WINDOWS)
m_Handle = LoadLibraryW(dll_path.wstring().c_str());
#else
m_Handle = dlopen(dll_path.string().c_str(), RTLD_LAZY);
#endif
// Check loaded DLL
if (!m_Handle) throw std::runtime_error("Can not load given dynamic library."); if (!m_Handle) throw std::runtime_error("Can not load given dynamic library.");
} }

View File

@@ -39,6 +39,13 @@ namespace Basalt::Presenter {
auto fct = (Fct) GetFunctionPointer(EXPOSE_FUNC_NAME); auto fct = (Fct) GetFunctionPointer(EXPOSE_FUNC_NAME);
return fct(); return fct();
} }
template<typename T>
void DestroyInstance(T* instance) {
using Fct = void (*) (T*);
constexpr char EXPOSE_FUNC_NAME[] = "BSDestroyInstance";
auto fct = (Fct) GetFunctionPointer(EXPOSE_FUNC_NAME);
fct(instance);
}
private: private:
Handle m_Handle; Handle m_Handle;

View File

@@ -1,4 +1,19 @@
#include "dll_loader.hpp"
#include <basalt_char.hpp>
#include <engine.hpp>
namespace Presenter = ::Basalt::Presenter;
namespace Shared = ::Basalt::Shared;
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
return 0; auto engine_dll = Presenter::DllLoader(Presenter::DllKind::Engine, BSTEXT("BasaltDirectX11Engine"));
auto* engine = engine_dll.CreateInstance<Shared::Engine::IEngine>();
Shared::Engine::EngineConfig engine_config{.is_headless = false, .title = BSTEXT("Fuck You"), .width = 800, .height = 600};
engine->Startup(std::move(engine_config));
while (true) {
engine->Tick();
}
engine->Shutdown();
} }

View File

@@ -5,6 +5,7 @@ PRIVATE
pipe_operator.cpp pipe_operator.cpp
engine.cpp engine.cpp
deliver.cpp deliver.cpp
directx_util.cpp
) )
target_sources(BasaltShared target_sources(BasaltShared
PUBLIC PUBLIC
@@ -16,6 +17,7 @@ FILES
pipe_operator.hpp pipe_operator.hpp
engine.hpp engine.hpp
deliver.hpp deliver.hpp
directx_util.hpp
) )
target_include_directories(BasaltShared target_include_directories(BasaltShared
PUBLIC PUBLIC

View File

@@ -0,0 +1,67 @@
#include "directx_util.hpp"
#include <stdexcept>
#include <string>
namespace Basalt::Shared::DirectX {
// Window procedure for the render window
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_CLOSE:
PostQuitMessage(0);
return 0;
default:
break;
}
return DefWindowProcW(hwnd, msg, wParam, lParam);
}
// Create a render window for DirectX
HWND CreateRenderWindow(std::uint32_t width, std::uint32_t height, const std::wstring_view& title) {
static bool g_CLSREG = false;
constexpr wchar_t class_name[] = L"DirectXRenderWindowClass";
std::wstring c_title(title);
if (!g_CLSREG) {
WNDCLASSEXW wc = {0};
wc.cbSize = sizeof(WNDCLASSEXW);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.hInstance = GetModuleHandleW(nullptr);
wc.hCursor = LoadCursorW(nullptr, IDC_ARROW);
wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
wc.lpszClassName = class_name;
if (!RegisterClassExW(&wc)) {
throw std::runtime_error("Failed to register window class");
}
g_CLSREG = true;
}
// Calculate window size including borders
RECT rect = {0, 0, static_cast<LONG>(width), static_cast<LONG>(height)};
AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
HWND hwnd = CreateWindowExW(0,
class_name,
c_title.c_str(),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
rect.right - rect.left,
rect.bottom - rect.top,
nullptr,
nullptr,
GetModuleHandleW(nullptr),
nullptr);
if (!hwnd) {
throw std::runtime_error("Failed to create render window");
}
ShowWindow(hwnd, SW_SHOW);
UpdateWindow(hwnd);
return hwnd;
}
}

View File

@@ -0,0 +1,10 @@
#pragma once
#include <cinttypes>
#include <string_view>
#include <windows.h>
namespace Basalt::Shared::DirectX {
HWND CreateRenderWindow(std::uint32_t width, std::uint32_t height, const std::wstring_view& title);
}

View File

@@ -16,13 +16,13 @@ namespace Basalt::Shared {
// Create Windows pipe name from given name // Create Windows pipe name from given name
auto fullname = std::format(BSTEXT("\\\\.\\pipe\\{}"), name); auto fullname = std::format(BSTEXT("\\\\.\\pipe\\{}"), name);
m_Handle = CreateFileW(fullname.c_str(), // 管道名称 m_Handle = CreateFileW(fullname.c_str(), // 管道名称
GENERIC_READ | GENERIC_WRITE, // 读写权限 GENERIC_READ | GENERIC_WRITE, // 读写权限
0, // 不共享 0, // 不共享
NULL, // 默认安全属性 NULL, // 默认安全属性
OPEN_EXISTING, // 打开已存在的管道 OPEN_EXISTING, // 打开已存在的管道
0, // 默认属性 0, // 默认属性
NULL // 无模板文件 NULL // 无模板文件
); );
if (m_Handle == BAD_PIPE_HANDLE) { if (m_Handle == BAD_PIPE_HANDLE) {
@@ -80,16 +80,16 @@ namespace Basalt::Shared {
void PipeOperator::Read(void *buffer, size_t size) { void PipeOperator::Read(void *buffer, size_t size) {
if (size == 0) { if (size == 0) {
return; // 读取0字节直接返回 return; // 读取0字节直接返回
} }
#if defined(BASALT_OS_WINDOWS) #if defined(BASALT_OS_WINDOWS)
DWORD bytesRead = 0; DWORD bytesRead = 0;
BOOL success = ReadFile(m_Handle, // 管道句柄 BOOL success = ReadFile(m_Handle, // 管道句柄
buffer, // 缓冲区 buffer, // 缓冲区
static_cast<DWORD>(size), // 缓冲区大小 static_cast<DWORD>(size), // 缓冲区大小
&bytesRead, // 实际读取的字节数 &bytesRead, // 实际读取的字节数
NULL // 不使用重叠I/O NULL // 不使用重叠I/O
); );
if (!success) { if (!success) {
@@ -111,7 +111,7 @@ namespace Basalt::Shared {
} }
if (bytesRead == 0) { if (bytesRead == 0) {
// 管道已关闭或到达末尾 // 管道已关闭或到达末尾
throw std::runtime_error("Named pipe closed during read."); throw std::runtime_error("Named pipe closed during read.");
} }
@@ -126,16 +126,16 @@ namespace Basalt::Shared {
void PipeOperator::Write(const void *buffer, size_t size) { void PipeOperator::Write(const void *buffer, size_t size) {
if (size == 0) { if (size == 0) {
return; // 写入0字节直接返回 return; // 写入0字节直接返回
} }
#if defined(BASALT_OS_WINDOWS) #if defined(BASALT_OS_WINDOWS)
DWORD bytesWritten = 0; DWORD bytesWritten = 0;
BOOL success = WriteFile(m_Handle, // 管道句柄 BOOL success = WriteFile(m_Handle, // 管道句柄
buffer, // 数据缓冲区 buffer, // 数据缓冲区
static_cast<DWORD>(size), // 数据大小 static_cast<DWORD>(size), // 数据大小
&bytesWritten, // 实际写入的字节数 &bytesWritten, // 实际写入的字节数
NULL // 不使用重叠I/O NULL // 不使用重叠I/O
); );
if (!success) { if (!success) {