feat: major engine overhaul - scene demo with lighting, sphere, ground
- Scene Demo: cube + sphere + ground plane with proper lighting - Audio: XAudio2 dynamic loading + WAV playback - Physics: expanded collision system - Renderer: improved pipeline with materials - UI: extended widget system - VisualScript: enhanced serializer + block interactions - ASM: optimized math/memory/profiling routines - Window: mouse input + scroll support
This commit is contained in:
1 parent
2653926d85
commit
0669d102ce
35 files changed
+1844
-314
No files matched your search
@@ -1,6 +1,7 @@
|
||||
#include "graphics_device.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
GraphicsDevice* graphics_device_create(void) {
|
||||
return (GraphicsDevice*)calloc(1, sizeof(GraphicsDevice));
|
||||
@@ -60,7 +61,7 @@ int graphics_device_init(GraphicsDevice* d, void* hwnd, uint32_t w, uint32_t h,
|
||||
d->device->lpVtbl->CreateRenderTargetView(d->device, (ID3D11Resource*)back_buffer, NULL, &d->render_target);
|
||||
if (back_buffer) back_buffer->lpVtbl->Release(back_buffer);
|
||||
create_depth_stencil(d, w, h);
|
||||
d->context->lpVtbl->OMSetRenderTargets(d->context, 1, &d->render_target, NULL);
|
||||
d->context->lpVtbl->OMSetRenderTargets(d->context, 1, &d->render_target, d->depth_stencil);
|
||||
D3D11_VIEWPORT vp = {0};
|
||||
vp.Width = (float)w; vp.Height = (float)h;
|
||||
vp.MaxDepth = 1.0f;
|
||||
@@ -77,6 +78,19 @@ int graphics_device_init(GraphicsDevice* d, void* hwnd, uint32_t w, uint32_t h,
|
||||
d->context->lpVtbl->OMSetDepthStencilState(d->context, default_dss, 0);
|
||||
default_dss->lpVtbl->Release(default_dss);
|
||||
}
|
||||
|
||||
// 设置默认光栅化状态:背面剔除 + 实体填充
|
||||
D3D11_RASTERIZER_DESC rd = {0};
|
||||
rd.FillMode = D3D11_FILL_SOLID;
|
||||
rd.CullMode = D3D11_CULL_BACK;
|
||||
rd.FrontCounterClockwise = FALSE;
|
||||
rd.DepthClipEnable = TRUE;
|
||||
ID3D11RasterizerState* default_rs = NULL;
|
||||
d->device->lpVtbl->CreateRasterizerState(d->device, &rd, &default_rs);
|
||||
if (default_rs) {
|
||||
d->context->lpVtbl->RSSetState(d->context, default_rs);
|
||||
default_rs->lpVtbl->Release(default_rs);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -108,3 +122,68 @@ void graphics_device_clear(GraphicsDevice* d, float r, float g, float b, float a
|
||||
void graphics_device_present(GraphicsDevice* d) {
|
||||
d->swap_chain->lpVtbl->Present(d->swap_chain, d->vsync ? 1 : 0, 0);
|
||||
}
|
||||
|
||||
int graphics_device_save_screenshot(GraphicsDevice* d, const char* path) {
|
||||
if (!d || !d->swap_chain || !d->device || !d->context) return 0;
|
||||
|
||||
ID3D11Texture2D* back = NULL;
|
||||
HRESULT hr = d->swap_chain->lpVtbl->GetBuffer(d->swap_chain, 0, &IID_ID3D11Texture2D, (void**)&back);
|
||||
if (FAILED(hr) || !back) return 0;
|
||||
|
||||
D3D11_TEXTURE2D_DESC desc = {0};
|
||||
back->lpVtbl->GetDesc(back, &desc);
|
||||
|
||||
D3D11_TEXTURE2D_DESC sd = desc;
|
||||
sd.BindFlags = 0;
|
||||
sd.Usage = D3D11_USAGE_STAGING;
|
||||
sd.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||
sd.MiscFlags = 0;
|
||||
|
||||
ID3D11Texture2D* staging = NULL;
|
||||
hr = d->device->lpVtbl->CreateTexture2D(d->device, &sd, NULL, &staging);
|
||||
if (FAILED(hr) || !staging) { back->lpVtbl->Release(back); return 0; }
|
||||
|
||||
d->context->lpVtbl->CopyResource(d->context, (ID3D11Resource*)staging, (ID3D11Resource*)back);
|
||||
|
||||
D3D11_MAPPED_SUBRESOURCE map = {0};
|
||||
hr = d->context->lpVtbl->Map(d->context, (ID3D11Resource*)staging, 0, D3D11_MAP_READ, 0, &map);
|
||||
if (FAILED(hr)) { staging->lpVtbl->Release(staging); back->lpVtbl->Release(back); return 0; }
|
||||
|
||||
FILE* f = fopen(path, "wb");
|
||||
if (!f) { d->context->lpVtbl->Unmap(d->context, (ID3D11Resource*)staging, 0); staging->lpVtbl->Release(staging); back->lpVtbl->Release(back); return 0; }
|
||||
|
||||
int w = (int)desc.Width;
|
||||
int h = (int)desc.Height;
|
||||
int row_size = ((w * 3 + 3) / 4) * 4;
|
||||
int file_size = 54 + row_size * h;
|
||||
|
||||
unsigned char header[54] = {0};
|
||||
header[0] = 'B'; header[1] = 'M';
|
||||
memcpy(header + 2, &file_size, 4);
|
||||
header[10] = 54;
|
||||
header[14] = 40;
|
||||
memcpy(header + 18, &w, 4);
|
||||
memcpy(header + 22, &h, 4);
|
||||
header[26] = 1;
|
||||
header[28] = 24;
|
||||
fwrite(header, 1, 54, f);
|
||||
|
||||
unsigned char* row = (unsigned char*)malloc(row_size);
|
||||
for (int y = 0; y < h; y++) {
|
||||
uint8_t* src = (uint8_t*)map.pData + (h - 1 - y) * map.RowPitch;
|
||||
for (int x = 0; x < w; x++) {
|
||||
// 后台缓冲区为 RGBA,BMP 24-bit 需要 BGR
|
||||
row[x * 3 + 0] = src[x * 4 + 2];
|
||||
row[x * 3 + 1] = src[x * 4 + 1];
|
||||
row[x * 3 + 2] = src[x * 4 + 0];
|
||||
}
|
||||
fwrite(row, 1, row_size, f);
|
||||
}
|
||||
free(row);
|
||||
fclose(f);
|
||||
|
||||
d->context->lpVtbl->Unmap(d->context, (ID3D11Resource*)staging, 0);
|
||||
staging->lpVtbl->Release(staging);
|
||||
back->lpVtbl->Release(back);
|
||||
return 1;
|
||||
}
|
||||
@@ -3,7 +3,8 @@
|
||||
#include <dxgi.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
typedef struct GraphicsDevice GraphicsDevice;
|
||||
struct GraphicsDevice {
|
||||
ID3D11Device* device;
|
||||
ID3D11DeviceContext* context;
|
||||
IDXGISwapChain* swap_chain;
|
||||
@@ -13,7 +14,7 @@ typedef struct {
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
int vsync;
|
||||
} GraphicsDevice;
|
||||
};
|
||||
|
||||
GraphicsDevice* graphics_device_create(void);
|
||||
void graphics_device_destroy(GraphicsDevice* d);
|
||||
@@ -21,3 +22,4 @@ int graphics_device_init(GraphicsDevice* d, void* hwnd, uint32_t w, uint32_t h,
|
||||
void graphics_device_resize(GraphicsDevice* d, uint32_t w, uint32_t h);
|
||||
void graphics_device_clear(GraphicsDevice* d, float r, float g, float b, float a);
|
||||
void graphics_device_present(GraphicsDevice* d);
|
||||
int graphics_device_save_screenshot(GraphicsDevice* d, const char* path);
|
||||
@@ -1,5 +1,18 @@
|
||||
#include "renderer.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static void fill_constant_buffer(float* cb, const Mat4* world, const Mat4* wvp,
|
||||
Vec3 light_dir, Vec4 light_color, Vec4 ambient_color,
|
||||
int use_texture, Vec4 diffuse_color) {
|
||||
memcpy(cb + 0, world->m, sizeof(float) * 16);
|
||||
memcpy(cb + 16, wvp->m, sizeof(float) * 16);
|
||||
cb[32] = light_dir.x; cb[33] = light_dir.y; cb[34] = light_dir.z; cb[35] = 0.0f;
|
||||
cb[36] = light_color.x; cb[37] = light_color.y; cb[38] = light_color.z; cb[39] = light_color.w;
|
||||
cb[40] = ambient_color.x; cb[41] = ambient_color.y; cb[42] = ambient_color.z; cb[43] = ambient_color.w;
|
||||
cb[44] = use_texture ? 1.0f : 0.0f; cb[45] = 0.0f; cb[46] = 0.0f; cb[47] = 0.0f;
|
||||
cb[48] = diffuse_color.x; cb[49] = diffuse_color.y; cb[50] = diffuse_color.z; cb[51] = diffuse_color.w;
|
||||
}
|
||||
|
||||
Renderer* renderer_create(GraphicsDevice* device) {
|
||||
Renderer* r = (Renderer*)calloc(1, sizeof(Renderer));
|
||||
@@ -15,7 +28,14 @@ Renderer* renderer_create(GraphicsDevice* device) {
|
||||
void renderer_destroy(Renderer* r) { free(r); }
|
||||
|
||||
void renderer_begin_frame(Renderer* r) {
|
||||
ID3D11DeviceContext* ctx = r->device->context;
|
||||
graphics_device_clear(r->device, 0.1f, 0.1f, 0.15f, 1.0f);
|
||||
D3D11_VIEWPORT vp = {0};
|
||||
vp.Width = (float)r->device->width;
|
||||
vp.Height = (float)r->device->height;
|
||||
vp.MaxDepth = 1.0f;
|
||||
ctx->lpVtbl->RSSetViewports(ctx, 1, &vp);
|
||||
ctx->lpVtbl->IASetPrimitiveTopology(ctx, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
}
|
||||
|
||||
void renderer_end_frame(Renderer* r) {
|
||||
@@ -37,9 +57,41 @@ void renderer_draw_mesh(Renderer* r, Mesh* m) {
|
||||
}
|
||||
|
||||
void renderer_draw_mesh_with_shader(Renderer* r, Mesh* m, Shader* s, const Mat4* world, Texture* t) {
|
||||
if (!m || !s) return;
|
||||
if (!m || !s || !r) return;
|
||||
ID3D11DeviceContext* ctx = r->device->context;
|
||||
shader_bind(s, ctx);
|
||||
|
||||
Mat4 wvp;
|
||||
mat4_multiply(world, &r->view, &wvp);
|
||||
mat4_multiply(&wvp, &r->projection, &wvp);
|
||||
|
||||
float cb[64];
|
||||
memset(cb, 0, sizeof(cb));
|
||||
fill_constant_buffer(cb, world, &wvp, r->light_dir, r->light_color, r->ambient_color, t ? 1 : 0, (Vec4){1,1,1,1});
|
||||
|
||||
shader_set_matrix(s, ctx, cb);
|
||||
if (t) texture_bind(t, ctx, 0);
|
||||
|
||||
renderer_draw_mesh(r, m);
|
||||
}
|
||||
|
||||
void renderer_draw_mesh_with_material(Renderer* r, Mesh* m, Material* mat, const Mat4* world) {
|
||||
if (!m || !mat || !mat->shader || !r) return;
|
||||
ID3D11DeviceContext* ctx = r->device->context;
|
||||
shader_bind(mat->shader, ctx);
|
||||
|
||||
Mat4 wvp;
|
||||
mat4_multiply(world, &r->view, &wvp);
|
||||
mat4_multiply(&wvp, &r->projection, &wvp);
|
||||
|
||||
float cb[64];
|
||||
memset(cb, 0, sizeof(cb));
|
||||
fill_constant_buffer(cb, world, &wvp, r->light_dir, r->light_color, r->ambient_color,
|
||||
mat->use_texture, mat->color);
|
||||
|
||||
shader_set_matrix(mat->shader, ctx, cb);
|
||||
if (mat->use_texture && mat->texture) texture_bind(mat->texture, ctx, 0);
|
||||
|
||||
renderer_draw_mesh(r, m);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,10 +4,12 @@
|
||||
#include "mesh.h"
|
||||
#include "texture.h"
|
||||
#include "camera.h"
|
||||
#include "material.h"
|
||||
#include "../include/engine_api.h"
|
||||
#include "../ASM/math_c_fallback.h"
|
||||
|
||||
typedef struct {
|
||||
typedef struct Renderer Renderer;
|
||||
struct Renderer {
|
||||
GraphicsDevice* device;
|
||||
Shader* current_shader;
|
||||
Mat4 view;
|
||||
@@ -15,7 +17,7 @@ typedef struct {
|
||||
Vec3 light_dir;
|
||||
Vec4 light_color;
|
||||
Vec4 ambient_color;
|
||||
} Renderer;
|
||||
};
|
||||
|
||||
Renderer* renderer_create(GraphicsDevice* device);
|
||||
void renderer_destroy(Renderer* renderer);
|
||||
@@ -23,6 +25,7 @@ void renderer_begin_frame(Renderer* renderer);
|
||||
void renderer_end_frame(Renderer* renderer);
|
||||
void renderer_draw_mesh(Renderer* renderer, Mesh* mesh);
|
||||
void renderer_draw_mesh_with_shader(Renderer* renderer, Mesh* mesh, Shader* shader, const Mat4* world, Texture* tex);
|
||||
void renderer_draw_mesh_with_material(Renderer* renderer, Mesh* mesh, Material* material, const Mat4* world);
|
||||
void renderer_set_view(Renderer* renderer, const Mat4* view);
|
||||
void renderer_set_projection(Renderer* renderer, const Mat4* projection);
|
||||
void renderer_set_light(Renderer* renderer, Vec3 dir, Vec4 color, Vec4 ambient);
|
||||
|
||||
@@ -1,22 +1,30 @@
|
||||
#include "shader.h"
|
||||
#include "../Core/logger.h"
|
||||
#include <d3dcompiler.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static const char* default_vs =
|
||||
"struct VS_IN{float3 pos:POSITION;float3 n:NORMAL;float2 uv:TEXCOORD;float4 col:COLOR;};"
|
||||
"struct PS_IN{float4 pos:SV_POSITION;float4 col:COLOR;};"
|
||||
"cbuffer CB:register(b0){float4x4 WVP;};"
|
||||
"PS_IN main(VS_IN i){PS_IN o;o.pos=mul(float4(i.pos,1),WVP);o.col=i.col;return o;}";
|
||||
"struct PS_IN{float4 pos:SV_POSITION;float3 world_n:NORMAL;float2 uv:TEXCOORD;float4 col:COLOR;};"
|
||||
"cbuffer CB:register(b0){float4x4 World;float4x4 WVP;float4 LightDir;float4 LightColor;float4 AmbientColor;float4 UseTexture;float4 DiffuseColor;};"
|
||||
"PS_IN main(VS_IN i){PS_IN o;o.pos=mul(float4(i.pos,1),WVP);o.world_n=normalize(mul(float4(i.n,0),World).xyz);o.uv=i.uv;o.col=i.col*DiffuseColor;return o;}";
|
||||
|
||||
static const char* default_ps =
|
||||
"struct PS_IN{float4 pos:SV_POSITION;float4 col:COLOR;};"
|
||||
"float4 main(PS_IN i):SV_TARGET{return i.col;}";
|
||||
"struct PS_IN{float4 pos:SV_POSITION;float3 world_n:NORMAL;float2 uv:TEXCOORD;float4 col:COLOR;};"
|
||||
"cbuffer CB:register(b0){float4x4 World;float4x4 WVP;float4 LightDir;float4 LightColor;float4 AmbientColor;float4 UseTexture;float4 DiffuseColor;};"
|
||||
"Texture2D tex:register(t0);SamplerState samp:register(s0);"
|
||||
"float4 main(PS_IN i):SV_TARGET{float3 ld=normalize(LightDir.xyz);float diff=saturate(dot(i.world_n,ld));float4 light=AmbientColor+LightColor*diff;float4 albedo=i.col;if(UseTexture.x>0.5)albedo=albedo*tex.Sample(samp,i.uv);return albedo*light;}";
|
||||
|
||||
static ID3DBlob* compile_shader(const char* code, uint32_t len, const char* target) {
|
||||
ID3DBlob *blob = NULL, *err = NULL;
|
||||
D3DCompile(code, len, NULL, NULL, NULL, "main", target, D3DCOMPILE_OPTIMIZATION_LEVEL3, 0, &blob, &err);
|
||||
if (err) err->lpVtbl->Release(err);
|
||||
UINT flags = D3DCOMPILE_OPTIMIZATION_LEVEL3 | D3DCOMPILE_PACK_MATRIX_ROW_MAJOR;
|
||||
D3DCompile(code, len, NULL, NULL, NULL, "main", target, flags, 0, &blob, &err);
|
||||
if (err) {
|
||||
const char* msg = (const char*)err->lpVtbl->GetBufferPointer(err);
|
||||
LOG_ERROR("Shader compile error (%s): %s", target, msg);
|
||||
err->lpVtbl->Release(err);
|
||||
}
|
||||
return blob;
|
||||
}
|
||||
|
||||
@@ -41,6 +49,7 @@ int shader_compile(Shader* s, ID3D11Device* dev, const char* vs_code, const char
|
||||
ID3DBlob* vs_blob = compile_shader(vs_code, vs_len, "vs_5_0");
|
||||
ID3DBlob* ps_blob = compile_shader(ps_code, ps_len, "ps_5_0");
|
||||
if (!vs_blob || !ps_blob) {
|
||||
LOG_ERROR("Failed to compile default shader (vs=%p ps=%p)", (void*)vs_blob, (void*)ps_blob);
|
||||
if (vs_blob) vs_blob->lpVtbl->Release(vs_blob);
|
||||
if (ps_blob) ps_blob->lpVtbl->Release(ps_blob);
|
||||
return 0;
|
||||
@@ -67,6 +76,7 @@ void shader_bind(Shader* s, ID3D11DeviceContext* ctx) {
|
||||
ctx->lpVtbl->PSSetShader(ctx, s->ps, NULL, 0);
|
||||
ctx->lpVtbl->IASetInputLayout(ctx, s->layout);
|
||||
ctx->lpVtbl->VSSetConstantBuffers(ctx, 0, 1, &s->cb);
|
||||
ctx->lpVtbl->PSSetConstantBuffers(ctx, 0, 1, &s->cb);
|
||||
}
|
||||
|
||||
void shader_set_matrix(Shader* s, ID3D11DeviceContext* ctx, const float* data) {
|
||||
|
||||
@@ -6,6 +6,32 @@
|
||||
|
||||
#pragma comment(lib, "windowscodecs.lib")
|
||||
|
||||
// 为 MinGW 提供 COM 助手宏(MSVC 已内联提供)
|
||||
#ifndef _MSC_VER
|
||||
#define ID3D11ShaderResourceView_Release(p) (p)->lpVtbl->Release(p)
|
||||
#define ID3D11Texture2D_Release(p) (p)->lpVtbl->Release(p)
|
||||
#define ID3D11Device_CreateTexture2D(p,a,b,c) (p)->lpVtbl->CreateTexture2D(p,a,b,c)
|
||||
#define ID3D11Device_CreateShaderResourceView(p,a,b,c) (p)->lpVtbl->CreateShaderResourceView(p,a,b,c)
|
||||
#define ID3D11DeviceContext_GetDevice(p,a) (p)->lpVtbl->GetDevice(p,a)
|
||||
#define ID3D11DeviceContext_PSSetShaderResources(p,a,b,c) (p)->lpVtbl->PSSetShaderResources(p,a,b,c)
|
||||
#define ID3D11DeviceContext_PSSetSamplers(p,a,b,c) (p)->lpVtbl->PSSetSamplers(p,a,b,c)
|
||||
#define ID3D11Device_CreateSamplerState(p,a,b) (p)->lpVtbl->CreateSamplerState(p,a,b)
|
||||
|
||||
#define IWICBitmapDecoder_GetFrame(p,a,b) (p)->lpVtbl->GetFrame(p,a,b)
|
||||
#define IWICBitmapFrameDecode_GetSize(p,a,b) (p)->lpVtbl->GetSize(p,a,b)
|
||||
#define IWICImagingFactory_CreateFormatConverter(p,a) (p)->lpVtbl->CreateFormatConverter(p,a)
|
||||
#define IWICFormatConverter_Initialize(p,a,b,c,d,e,f) (p)->lpVtbl->Initialize(p,a,b,c,d,e,f)
|
||||
#define IWICFormatConverter_CopyPixels(p,a,b,c,d) (p)->lpVtbl->CopyPixels(p,a,b,c,d)
|
||||
#define IWICFormatConverter_Release(p) (p)->lpVtbl->Release(p)
|
||||
#define IWICBitmapFrameDecode_Release(p) (p)->lpVtbl->Release(p)
|
||||
#define IWICImagingFactory_CreateDecoderFromFilename(p,a,b,c,d,e) (p)->lpVtbl->CreateDecoderFromFilename(p,a,b,c,d,e)
|
||||
#define IWICBitmapDecoder_Release(p) (p)->lpVtbl->Release(p)
|
||||
#define IWICImagingFactory_CreateStream(p,a) (p)->lpVtbl->CreateStream(p,a)
|
||||
#define IWICStream_InitializeFromMemory(p,a,b) (p)->lpVtbl->InitializeFromMemory(p,a,b)
|
||||
#define IWICImagingFactory_CreateDecoderFromStream(p,a,b,c,d) (p)->lpVtbl->CreateDecoderFromStream(p,a,b,c,d)
|
||||
#define IWICStream_Release(p) (p)->lpVtbl->Release(p)
|
||||
#endif
|
||||
|
||||
static IWICImagingFactory* wic_factory = NULL;
|
||||
|
||||
static HRESULT ensure_wic(void) {
|
||||
@@ -183,6 +209,23 @@ Texture* texture_create_checkerboard(ID3D11Device* device, uint32_t size, uint32
|
||||
|
||||
void texture_bind(Texture* texture, ID3D11DeviceContext* ctx, uint32_t slot) {
|
||||
if (!texture || !texture->srv) return;
|
||||
ID3D11DeviceContext_PSSetShaderResources(ctx, slot, 1, &texture->srv);
|
||||
ID3D11DeviceContext_PSSetSamplers(ctx, slot, 1, &(ID3D11SamplerState*){NULL});
|
||||
static ID3D11SamplerState* default_sampler = NULL;
|
||||
if (!default_sampler) {
|
||||
ID3D11Device* device = NULL;
|
||||
ctx->lpVtbl->GetDevice(ctx, &device);
|
||||
if (device) {
|
||||
D3D11_SAMPLER_DESC sd = {0};
|
||||
sd.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
|
||||
sd.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||
sd.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||
sd.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||
sd.ComparisonFunc = D3D11_COMPARISON_NEVER;
|
||||
sd.MinLOD = 0;
|
||||
sd.MaxLOD = D3D11_FLOAT32_MAX;
|
||||
device->lpVtbl->CreateSamplerState(device, &sd, &default_sampler);
|
||||
device->lpVtbl->Release(device);
|
||||
}
|
||||
}
|
||||
ctx->lpVtbl->PSSetShaderResources(ctx, slot, 1, &texture->srv);
|
||||
ctx->lpVtbl->PSSetSamplers(ctx, slot, 1, &default_sampler);
|
||||
}
|
||||
Reference in new issue
Block a user