Files
lity3d/Engine/Rendering/graphics_device.c
T
shuiyu1123 0669d102ce 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
2026-07-12 08:21:07 +08:00

190 lines
8.0 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "graphics_device.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
GraphicsDevice* graphics_device_create(void) {
return (GraphicsDevice*)calloc(1, sizeof(GraphicsDevice));
}
void graphics_device_destroy(GraphicsDevice* d) {
if (!d) return;
if (d->depth_stencil) d->depth_stencil->lpVtbl->Release(d->depth_stencil);
if (d->depth_texture) d->depth_texture->lpVtbl->Release(d->depth_texture);
if (d->render_target) d->render_target->lpVtbl->Release(d->render_target);
if (d->swap_chain) d->swap_chain->lpVtbl->Release(d->swap_chain);
if (d->context) d->context->lpVtbl->Release(d->context);
if (d->device) d->device->lpVtbl->Release(d->device);
free(d);
}
static int create_depth_stencil(GraphicsDevice* d, uint32_t w, uint32_t h) {
D3D11_TEXTURE2D_DESC desc = {0};
desc.Width = w; desc.Height = h;
desc.MipLevels = 1; desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
desc.SampleDesc.Count = 1;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
HRESULT hr = d->device->lpVtbl->CreateTexture2D(d->device, &desc, NULL, &d->depth_texture);
if (FAILED(hr)) return 0;
D3D11_DEPTH_STENCIL_VIEW_DESC dsv = {0};
dsv.Format = desc.Format;
dsv.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
hr = d->device->lpVtbl->CreateDepthStencilView(d->device, (ID3D11Resource*)d->depth_texture, &dsv, &d->depth_stencil);
return SUCCEEDED(hr);
}
int graphics_device_init(GraphicsDevice* d, void* hwnd, uint32_t w, uint32_t h, int vsync) {
d->width = w; d->height = h; d->vsync = vsync;
DXGI_SWAP_CHAIN_DESC scd = {0};
scd.BufferCount = 1;
scd.BufferDesc.Width = w;
scd.BufferDesc.Height = h;
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
scd.BufferDesc.RefreshRate.Numerator = 60;
scd.BufferDesc.RefreshRate.Denominator = 1;
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
scd.OutputWindow = (HWND)hwnd;
scd.SampleDesc.Count = 1;
scd.Windowed = TRUE;
scd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
D3D_FEATURE_LEVEL levels[] = {D3D_FEATURE_LEVEL_11_0};
UINT flags = 0;
#ifdef _DEBUG
flags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
HRESULT hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, flags, levels, 1, D3D11_SDK_VERSION, &scd, &d->swap_chain, &d->device, NULL, &d->context);
if (FAILED(hr)) return 0;
ID3D11Texture2D* back_buffer = NULL;
d->swap_chain->lpVtbl->GetBuffer(d->swap_chain, 0, &IID_ID3D11Texture2D, (void**)&back_buffer);
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, d->depth_stencil);
D3D11_VIEWPORT vp = {0};
vp.Width = (float)w; vp.Height = (float)h;
vp.MaxDepth = 1.0f;
d->context->lpVtbl->RSSetViewports(d->context, 1, &vp);
// 设置默认深度状态 (避免 UILayer init 破坏)
D3D11_DEPTH_STENCIL_DESC dsd = {0};
dsd.DepthEnable = TRUE;
dsd.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
dsd.DepthFunc = D3D11_COMPARISON_LESS_EQUAL;
ID3D11DepthStencilState* default_dss = NULL;
d->device->lpVtbl->CreateDepthStencilState(d->device, &dsd, &default_dss);
if (default_dss) {
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;
}
void graphics_device_resize(GraphicsDevice* d, uint32_t w, uint32_t h) {
if (w == 0 || h == 0) return;
d->context->lpVtbl->OMSetRenderTargets(d->context, 0, NULL, NULL);
if (d->render_target) { d->render_target->lpVtbl->Release(d->render_target); d->render_target = NULL; }
if (d->depth_stencil) { d->depth_stencil->lpVtbl->Release(d->depth_stencil); d->depth_stencil = NULL; }
if (d->depth_texture) { d->depth_texture->lpVtbl->Release(d->depth_texture); d->depth_texture = NULL; }
d->swap_chain->lpVtbl->ResizeBuffers(d->swap_chain, 0, w, h, DXGI_FORMAT_UNKNOWN, 0);
ID3D11Texture2D* back_buffer = NULL;
d->swap_chain->lpVtbl->GetBuffer(d->swap_chain, 0, &IID_ID3D11Texture2D, (void**)&back_buffer);
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, d->depth_stencil);
D3D11_VIEWPORT vp = {0};
vp.Width = (float)w; vp.Height = (float)h; vp.MaxDepth = 1.0f;
d->context->lpVtbl->RSSetViewports(d->context, 1, &vp);
d->width = w; d->height = h;
}
void graphics_device_clear(GraphicsDevice* d, float r, float g, float b, float a) {
float color[4] = {r, g, b, a};
d->context->lpVtbl->ClearRenderTargetView(d->context, d->render_target, color);
d->context->lpVtbl->ClearDepthStencilView(d->context, d->depth_stencil, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
}
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;
}