Files
lity3d/Engine/Editor/uilayer.c
T
shuiyu1123 2d56cb3bc9 MiMoEngine ASM: x86-64 MASM汇编+C混合架构游戏引擎
核心热路径(数学/内存/字符串/性能分析)用MASM汇编(SSE/AVX2)
外围系统(窗口/渲染/ECS/音频/UI/脚本)用C语言
含自研编辑器、VisualScript积木编程、中文渲染(glyph_atlas)
2026-07-10 19:20:40 +08:00

253 lines
11 KiB
C

#include "uilayer.h"
#include <stdlib.h>
#include <string.h>
#include "../Core/logger.h"
#define UI_MAX_VERTS (UI_MAX_QUADS * 4)
#define UI_MAX_IDXS (UI_MAX_QUADS * 6)
typedef struct { float p[3], n[3], uv[2], c[4]; } UIVert;
static UIVert g_verts[UI_MAX_VERTS];
static uint32_t g_indices[UI_MAX_IDXS];
static int g_vi = 0;
static int g_ii = 0;
static UIVert g_text_verts[UI_MAX_VERTS];
static uint32_t g_text_indices[UI_MAX_IDXS];
static int g_tvi = 0;
static int g_tii = 0;
static ID3D11ShaderResourceView* g_text_srv = NULL;
static void screen_to_world(float sx, float sy, float sw, float sh, float z, float* wx, float* wy) {
*wx = sx - sw * 0.5f;
*wy = -(sy - sh * 0.5f);
}
int uilayer_init(UILayer* u, ID3D11Device* dev, float screen_w, float screen_h) {
memset(u, 0, sizeof(*u));
u->screen_w = screen_w;
u->screen_h = screen_h;
u->z_plane = 0.0f;
u->camera = camera_orthographic(screen_w, screen_h, 0.1f, 200.0f);
u->camera.position = (Vec3){0, 0, 100};
u->camera.target = (Vec3){0, 0, 0};
u->camera.dirty = 1;
camera_update(&u->camera);
u->shader = shader_create();
if (!shader_compile(u->shader, dev, NULL, NULL, 0, 0)) {
LOG_ERROR("UILayer: shader compile failed");
return 0;
}
D3D11_BUFFER_DESC bd = {0};
D3D11_SUBRESOURCE_DATA sd = {0};
UIVert* empty = (UIVert*)calloc(UI_MAX_VERTS, sizeof(UIVert));
bd.ByteWidth = UI_MAX_VERTS * sizeof(UIVert);
bd.Usage = D3D11_USAGE_DEFAULT;
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
sd.pSysMem = empty;
dev->lpVtbl->CreateBuffer(dev, &bd, &sd, &u->vb);
free(empty);
uint32_t* eidx = (uint32_t*)calloc(UI_MAX_IDXS, sizeof(uint32_t));
bd.ByteWidth = UI_MAX_IDXS * sizeof(uint32_t);
bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
sd.pSysMem = eidx;
dev->lpVtbl->CreateBuffer(dev, &bd, &sd, &u->ib);
free(eidx);
UIVert* empty2 = (UIVert*)calloc(UI_MAX_VERTS, sizeof(UIVert));
bd.ByteWidth = UI_MAX_VERTS * sizeof(UIVert);
bd.Usage = D3D11_USAGE_DEFAULT;
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
sd.pSysMem = empty2;
dev->lpVtbl->CreateBuffer(dev, &bd, &sd, &u->text_vb);
free(empty2);
uint32_t* eidx2 = (uint32_t*)calloc(UI_MAX_IDXS, sizeof(uint32_t));
bd.ByteWidth = UI_MAX_IDXS * sizeof(uint32_t);
bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
sd.pSysMem = eidx2;
dev->lpVtbl->CreateBuffer(dev, &bd, &sd, &u->text_ib);
free(eidx2);
D3D11_RASTERIZER_DESC rdesc = {0};
rdesc.FillMode = D3D11_FILL_SOLID;
rdesc.CullMode = D3D11_CULL_NONE;
dev->lpVtbl->CreateRasterizerState(dev, &rdesc, &u->rstate);
D3D11_DEPTH_STENCIL_DESC dsdesc = {0};
dsdesc.DepthEnable = FALSE;
dsdesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
dev->lpVtbl->CreateDepthStencilState(dev, &dsdesc, &u->ds_state);
D3D11_BLEND_DESC bdesc = {0};
bdesc.RenderTarget[0].BlendEnable = TRUE;
bdesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
bdesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
bdesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
bdesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
bdesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
bdesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
dev->lpVtbl->CreateBlendState(dev, &bdesc, &u->text_blend);
D3D11_SAMPLER_DESC sdesc = {0};
sdesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
sdesc.AddressU = sdesc.AddressV = sdesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
dev->lpVtbl->CreateSamplerState(dev, &sdesc, &u->text_sampler);
const char* text_vs_src =
"cbuffer CB:register(b0){float4x4 WVP;};"
"struct VS_IN{float4 pos:POSITION;float3 n:NORMAL;float2 uv:TEXCOORD;float4 col:COLOR;};"
"struct PS_IN{float4 pos:SV_POSITION;float2 uv:TEXCOORD;float4 col:COLOR;};"
"PS_IN main(VS_IN i){PS_IN o;o.pos=mul(i.pos,WVP);o.uv=i.uv;o.col=i.col;return o;}";
const char* text_ps_src =
"Texture2D tex:register(t0);SamplerState smp:register(s0);"
"struct PS_IN{float4 pos:SV_POSITION;float2 uv:TEXCOORD;float4 col:COLOR;};"
"float4 main(PS_IN i):SV_TARGET{float a=tex.Sample(smp,i.uv).a;return float4(i.col.rgb,i.col.a*a);}";
ID3DBlob *vsb = NULL, *psb = NULL;
D3DCompile(text_vs_src, (UINT)strlen(text_vs_src), NULL, NULL, NULL, "main", "vs_5_0", 0, 0, &vsb, NULL);
D3DCompile(text_ps_src, (UINT)strlen(text_ps_src), NULL, NULL, NULL, "main", "ps_5_0", 0, 0, &psb, NULL);
if (vsb && psb) {
dev->lpVtbl->CreateVertexShader(dev, vsb->lpVtbl->GetBufferPointer(vsb), vsb->lpVtbl->GetBufferSize(vsb), NULL, &u->text_vs);
dev->lpVtbl->CreatePixelShader(dev, psb->lpVtbl->GetBufferPointer(psb), psb->lpVtbl->GetBufferSize(psb), NULL, &u->text_ps);
D3D11_INPUT_ELEMENT_DESC layout[] = {
{"POSITION",0,DXGI_FORMAT_R32G32B32_FLOAT,0,0,D3D11_INPUT_PER_VERTEX_DATA,0},
{"NORMAL",0,DXGI_FORMAT_R32G32B32_FLOAT,0,12,D3D11_INPUT_PER_VERTEX_DATA,0},
{"TEXCOORD",0,DXGI_FORMAT_R32G32_FLOAT,0,24,D3D11_INPUT_PER_VERTEX_DATA,0},
{"COLOR",0,DXGI_FORMAT_R32G32B32A32_FLOAT,0,32,D3D11_INPUT_PER_VERTEX_DATA,0},
};
dev->lpVtbl->CreateInputLayout(dev, layout, 4, vsb->lpVtbl->GetBufferPointer(vsb), vsb->lpVtbl->GetBufferSize(vsb), &u->text_layout);
vsb->lpVtbl->Release(vsb);
psb->lpVtbl->Release(psb);
}
LOG_INFO("UILayer: initialized (%.0fx%.0f)", screen_w, screen_h);
return 1;
}
void uilayer_destroy(UILayer* u) {
if (!u) return;
if (u->text_sampler) u->text_sampler->lpVtbl->Release(u->text_sampler);
if (u->text_blend) u->text_blend->lpVtbl->Release(u->text_blend);
if (u->text_layout) u->text_layout->lpVtbl->Release(u->text_layout);
if (u->text_ps) u->text_ps->lpVtbl->Release(u->text_ps);
if (u->text_vs) u->text_vs->lpVtbl->Release(u->text_vs);
if (u->text_ib) u->text_ib->lpVtbl->Release(u->text_ib);
if (u->text_vb) u->text_vb->lpVtbl->Release(u->text_vb);
if (u->ds_state) u->ds_state->lpVtbl->Release(u->ds_state);
if (u->rstate) u->rstate->lpVtbl->Release(u->rstate);
if (u->ib) u->ib->lpVtbl->Release(u->ib);
if (u->vb) u->vb->lpVtbl->Release(u->vb);
if (u->shader) shader_destroy(u->shader);
memset(u, 0, sizeof(*u));
}
void uilayer_begin(UILayer* u) {
(void)u;
g_vi = 0; g_ii = 0;
g_tvi = 0; g_tii = 0;
g_text_srv = NULL;
}
void uilayer_rect(UILayer* u, float x, float y, float w, float h,
float r, float g, float b, float a) {
if (g_vi + 4 > UI_MAX_VERTS) return;
float x0, y0, x1, y1;
screen_to_world(x, y, u->screen_w, u->screen_h, u->z_plane, &x0, &y0);
screen_to_world(x + w, y + h, u->screen_w, u->screen_h, u->z_plane, &x1, &y1);
float z = u->z_plane;
uint32_t base = (uint32_t)g_vi;
g_verts[g_vi] = (UIVert){{x0,y0,z},{0,0,1},{0,0},{r,g,b,a}}; g_vi++;
g_verts[g_vi] = (UIVert){{x1,y0,z},{0,0,1},{1,0},{r,g,b,a}}; g_vi++;
g_verts[g_vi] = (UIVert){{x1,y1,z},{0,0,1},{1,1},{r,g,b,a}}; g_vi++;
g_verts[g_vi] = (UIVert){{x0,y1,z},{0,0,1},{0,1},{r,g,b,a}}; g_vi++;
g_indices[g_ii++] = base; g_indices[g_ii++] = base+1; g_indices[g_ii++] = base+2;
g_indices[g_ii++] = base; g_indices[g_ii++] = base+2; g_indices[g_ii++] = base+3;
}
void uilayer_textured_rect(UILayer* u, ID3D11DeviceContext* ctx,
ID3D11ShaderResourceView* srv,
float x, float y, float w, float h,
float u0, float v0, float u1, float v1,
float r, float g, float b, float a) {
(void)ctx;
if (!srv || g_tvi + 4 > UI_MAX_VERTS) return;
float x0, y0, x1, y1;
screen_to_world(x, y, u->screen_w, u->screen_h, u->z_plane, &x0, &y0);
screen_to_world(x + w, y + h, u->screen_w, u->screen_h, u->z_plane, &x1, &y1);
float z = u->z_plane;
uint32_t base = (uint32_t)g_tvi;
g_text_verts[g_tvi] = (UIVert){{x0,y0,z},{0,0,1},{u0,v0},{r,g,b,a}}; g_tvi++;
g_text_verts[g_tvi] = (UIVert){{x1,y0,z},{0,0,1},{u1,v0},{r,g,b,a}}; g_tvi++;
g_text_verts[g_tvi] = (UIVert){{x1,y1,z},{0,0,1},{u1,v1},{r,g,b,a}}; g_tvi++;
g_text_verts[g_tvi] = (UIVert){{x0,y1,z},{0,0,1},{u0,v1},{r,g,b,a}}; g_tvi++;
g_text_indices[g_tii++] = base; g_text_indices[g_tii++] = base+1; g_text_indices[g_tii++] = base+2;
g_text_indices[g_tii++] = base; g_text_indices[g_tii++] = base+2; g_text_indices[g_tii++] = base+3;
g_text_srv = srv;
}
static void flush_batch(ID3D11DeviceContext* ctx, UIVert* verts, uint32_t* indices,
int num_idx, ID3D11Buffer* vb, ID3D11Buffer* ib) {
if (num_idx == 0) return;
ctx->lpVtbl->UpdateSubresource(ctx, (ID3D11Resource*)vb, 0, NULL, verts, 0, 0);
ctx->lpVtbl->UpdateSubresource(ctx, (ID3D11Resource*)ib, 0, NULL, indices, 0, 0);
UINT stride = sizeof(UIVert), offset = 0;
ctx->lpVtbl->IASetVertexBuffers(ctx, 0, 1, &vb, &stride, &offset);
ctx->lpVtbl->IASetIndexBuffer(ctx, ib, DXGI_FORMAT_R32_UINT, 0);
ctx->lpVtbl->DrawIndexed(ctx, (UINT)num_idx, 0, 0);
}
void uilayer_flush(UILayer* u, ID3D11DeviceContext* ctx) {
if (g_ii == 0) return;
Mat4 view = u->camera.view;
Mat4 proj = u->camera.projection;
Mat4 vp, vp_t;
mat4_multiply(&view, &proj, &vp);
mat4_transpose(&vp, &vp_t);
D3D11_VIEWPORT vport = {0};
vport.Width = u->screen_w; vport.Height = u->screen_h; vport.MaxDepth = 1.0f;
ctx->lpVtbl->RSSetViewports(ctx, 1, &vport);
ctx->lpVtbl->RSSetState(ctx, u->rstate);
ctx->lpVtbl->OMSetDepthStencilState(ctx, u->ds_state, 0);
ctx->lpVtbl->IASetPrimitiveTopology(ctx, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
shader_bind(u->shader, ctx);
shader_set_matrix(u->shader, ctx, (float*)&vp_t);
flush_batch(ctx, g_verts, g_indices, g_ii, u->vb, u->ib);
}
void uilayer_flush_text(UILayer* u, ID3D11DeviceContext* ctx) {
if (g_tii == 0 || !g_text_srv || !u->text_vs || !u->text_ps) return;
Mat4 view = u->camera.view;
Mat4 proj = u->camera.projection;
Mat4 vp, vp_t;
mat4_multiply(&view, &proj, &vp);
mat4_transpose(&vp, &vp_t);
D3D11_VIEWPORT vport = {0};
vport.Width = u->screen_w; vport.Height = u->screen_h; vport.MaxDepth = 1.0f;
ctx->lpVtbl->RSSetViewports(ctx, 1, &vport);
ctx->lpVtbl->RSSetState(ctx, u->rstate);
ctx->lpVtbl->OMSetDepthStencilState(ctx, u->ds_state, 0);
ctx->lpVtbl->IASetPrimitiveTopology(ctx, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
ctx->lpVtbl->VSSetShader(ctx, u->text_vs, NULL, 0);
ctx->lpVtbl->PSSetShader(ctx, u->text_ps, NULL, 0);
ctx->lpVtbl->IASetInputLayout(ctx, u->text_layout);
ctx->lpVtbl->UpdateSubresource(ctx, (ID3D11Resource*)u->shader->cb, 0, NULL, &vp_t, 0, 0);
ctx->lpVtbl->VSSetConstantBuffers(ctx, 0, 1, &u->shader->cb);
float bf[4] = {0};
ctx->lpVtbl->OMSetBlendState(ctx, u->text_blend, bf, 0xFFFFFFFF);
ctx->lpVtbl->PSSetShaderResources(ctx, 0, 1, &g_text_srv);
ctx->lpVtbl->PSSetSamplers(ctx, 0, 1, &u->text_sampler);
flush_batch(ctx, g_text_verts, g_text_indices, g_tii, u->text_vb, u->text_ib);
}