MiMoEngine ASM: x86-64 MASM汇编+C混合架构游戏引擎

核心热路径(数学/内存/字符串/性能分析)用MASM汇编(SSE/AVX2)
外围系统(窗口/渲染/ECS/音频/UI/脚本)用C语言
含自研编辑器、VisualScript积木编程、中文渲染(glyph_atlas)
This commit is contained in:
shuiyu1123 committed 2026-07-10 19:20:40 +08:00
commit 2d56cb3bc9
91 files changed
+9988

No files matched your search

+303
View File
@@ -0,0 +1,303 @@
#include "bitmap_font.h"
#include <stdlib.h>
#include <string.h>
#include "../Core/logger.h"
static const uint8_t FONT_DATA[FONT_NUM_CHARS][FONT_CHAR_H] = {
{0},{0x00,0x00,0x18,0x3C,0x3C,0x3C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00},
{0x00,0x66,0x66,0x66,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x6C,0x6C,0xFE,0x6C,0x6C,0xFE,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00},
{0x18,0x18,0x7C,0xC6,0xC2,0xC0,0x7C,0x06,0x06,0x86,0xC6,0x7C,0x18,0x18,0x00,0x00},
{0x00,0x00,0x00,0x00,0xC2,0xC6,0x0C,0x18,0x30,0x60,0xC6,0x86,0x00,0x00,0x00,0x00},
{0x00,0x00,0x38,0x6C,0x6C,0x38,0x76,0xDC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00},
{0x00,0x30,0x30,0x30,0x70,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x0C,0x18,0x30,0x30,0x30,0x30,0x30,0x30,0x18,0x0C,0x00,0x00,0x00,0x00},
{0x00,0x00,0x30,0x18,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x18,0x30,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x02,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x00,0x00,0x00,0x00},
{0x00,0x00,0x7C,0xC6,0xC6,0xCE,0xDE,0xF6,0xE6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
{0x00,0x00,0x18,0x38,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x00,0x00,0x00,0x00},
{0x00,0x00,0x7C,0xC6,0x06,0x0C,0x18,0x30,0x60,0xC0,0xC6,0xFE,0x00,0x00,0x00,0x00},
{0x00,0x00,0x7C,0xC6,0x06,0x06,0x3C,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00},
{0x00,0x00,0x0C,0x1C,0x3C,0x6C,0xCC,0xFE,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00},
{0x00,0x00,0xFE,0xC0,0xC0,0xC0,0xFC,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00},
{0x00,0x00,0x38,0x60,0xC0,0xC0,0xFC,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
{0x00,0x00,0xFE,0xC6,0x06,0x06,0x0C,0x18,0x30,0x30,0x30,0x30,0x00,0x00,0x00,0x00},
{0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7C,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
{0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7E,0x06,0x06,0x06,0x0C,0x78,0x00,0x00,0x00,0x00},
{0},{0},{0},
{0x00,0x00,0x00,0x0C,0x18,0x30,0x60,0xC0,0x60,0x30,0x18,0x0C,0x00,0x00,0x00,0x00},
{0},{0},
{0x00,0x00,0x7C,0xC6,0xC6,0x0C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00},
{0},{0},{0},{0},{0},{0},{0},{0},{0},
{0x00,0x00,0x7C,0xC6,0xC6,0xCE,0xDE,0xF6,0xE6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
{0x00,0x00,0x18,0x38,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x00,0x00,0x00,0x00},
{0x00,0x00,0x7C,0xC6,0x06,0x0C,0x18,0x30,0x60,0xC0,0xC6,0xFE,0x00,0x00,0x00,0x00},
{0x00,0x00,0x7C,0xC6,0x06,0x06,0x3C,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00},
{0x00,0x00,0x0C,0x1C,0x3C,0x6C,0xCC,0xFE,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00},
{0x00,0x00,0xFE,0xC0,0xC0,0xC0,0xFC,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00},
{0x00,0x00,0x38,0x60,0xC0,0xC0,0xFC,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
{0x00,0x00,0xFE,0xC6,0x06,0x06,0x0C,0x18,0x30,0x30,0x30,0x30,0x00,0x00,0x00,0x00},
{0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7C,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
{0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7E,0x06,0x06,0x06,0x0C,0x78,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x30,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x0C,0x18,0x30,0x60,0xC0,0x60,0x30,0x18,0x0C,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x60,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x60,0x00,0x00,0x00,0x00},
{0x00,0x00,0x7C,0xC6,0xC6,0x0C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x7C,0xC6,0xC6,0xDE,0xDE,0xDE,0xDC,0xC0,0x7C,0x00,0x00,0x00,0x00},
{0x00,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00},
{0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x66,0x66,0x66,0x66,0xFC,0x00,0x00,0x00,0x00},
{0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xC0,0xC0,0xC2,0x66,0x3C,0x00,0x00,0x00,0x00},
{0x00,0x00,0xF8,0x6C,0x66,0x66,0x66,0x66,0x66,0x66,0x6C,0xF8,0x00,0x00,0x00,0x00},
{0x00,0x00,0xFE,0x66,0x62,0x68,0x78,0x68,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00},
{0x00,0x00,0xFE,0x66,0x62,0x68,0x78,0x68,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00},
{0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xDE,0xC6,0xC6,0x66,0x3A,0x00,0x00,0x00,0x00},
{0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00},
{0x00,0x00,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00},
{0x00,0x00,0x1E,0x0C,0x0C,0x0C,0x0C,0x0C,0xCC,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00},
{0x00,0x00,0xE6,0x66,0x66,0x6C,0x78,0x78,0x6C,0x66,0x66,0xE6,0x00,0x00,0x00,0x00},
{0x00,0x00,0xF0,0x60,0x60,0x60,0x60,0x60,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00},
{0x00,0x00,0xC6,0xEE,0xFE,0xFE,0xD6,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00},
{0x00,0x00,0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00},
{0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
{0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00},
{0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xD6,0xDE,0x7C,0x0C,0x0E,0x00,0x00},
{0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x6C,0x66,0x66,0x66,0xE6,0x00,0x00,0x00,0x00},
{0x00,0x00,0x7C,0xC6,0xC6,0x60,0x38,0x0C,0x06,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
{0x00,0x00,0xFF,0xDB,0x99,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00},
{0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
{0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x6C,0x38,0x10,0x00,0x00,0x00,0x00},
{0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xD6,0xD6,0xD6,0xFE,0xEE,0x6C,0x00,0x00,0x00,0x00},
{0x00,0x00,0xC6,0xC6,0x6C,0x7C,0x38,0x38,0x7C,0x6C,0xC6,0xC6,0x00,0x00,0x00,0x00},
{0x00,0x00,0xC6,0xC6,0xC6,0x6C,0x38,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00},
{0x00,0x00,0xFE,0xC6,0x86,0x0C,0x18,0x30,0x60,0xC2,0xC6,0xFE,0x00,0x00,0x00,0x00},
{0x00,0x00,0x3C,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3C,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x80,0xC0,0xE0,0x70,0x38,0x1C,0x0E,0x06,0x02,0x00,0x00,0x00,0x00},
{0x00,0x00,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00,0x00,0x00,0x00},
{0x10,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00},
};
static Shader* g_font_shader = NULL;
static ID3D11Buffer* g_font_vb = NULL;
static ID3D11Buffer* g_font_ib = NULL;
static FontVert g_font_verts[FONT_MAX_QUADS * 4];
static uint32_t g_font_indices[FONT_MAX_QUADS * 6];
static int g_font_vi = 0;
static int g_font_ii = 0;
static void make_ortho(float* m, float sw, float sh) {
memset(m, 0, 64);
m[0] = 2.0f / sw;
m[5] = -2.0f / sh;
m[10] = 1.0f;
m[12] = -1.0f;
m[13] = 1.0f;
m[15] = 1.0f;
}
static void make_atlas(uint8_t* pixels, int w, int h) {
memset(pixels, 0, (size_t)w * h * 4);
int cols = w / FONT_CHAR_W;
for (int i = 0; i < FONT_NUM_CHARS; i++) {
int cx = (i % cols) * FONT_CHAR_W;
int cy = (i / cols) * FONT_CHAR_H;
for (int row = 0; row < FONT_CHAR_H; row++) {
uint8_t bits = FONT_DATA[i][row];
for (int col = 0; col < 8; col++) {
if (bits & (0x80 >> col)) {
int px = cx + col, py = cy + row;
int idx = (py * w + px) * 4;
pixels[idx] = 255; pixels[idx+1] = 255; pixels[idx+2] = 255; pixels[idx+3] = 255;
}
}
}
}
}
int bitmap_font_init(BitmapFont* f, ID3D11Device* dev) {
memset(f, 0, sizeof(*f));
int cols = 16;
f->atlas_w = cols * FONT_CHAR_W;
f->atlas_h = ((FONT_NUM_CHARS + cols - 1) / cols) * FONT_CHAR_H;
uint8_t* pixels = (uint8_t*)malloc((size_t)f->atlas_w * f->atlas_h * 4);
make_atlas(pixels, f->atlas_w, f->atlas_h);
D3D11_TEXTURE2D_DESC td = {0};
td.Width = (UINT)f->atlas_w; td.Height = (UINT)f->atlas_h;
td.MipLevels = 1; td.ArraySize = 1;
td.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
td.SampleDesc.Count = 1;
td.Usage = D3D11_USAGE_DEFAULT;
td.BindFlags = D3D11_BIND_SHADER_RESOURCE;
D3D11_SUBRESOURCE_DATA sd = {0};
sd.pSysMem = pixels; sd.SysMemPitch = (UINT)(f->atlas_w * 4);
HRESULT hr = dev->lpVtbl->CreateTexture2D(dev, &td, &sd, &f->texture);
free(pixels);
if (FAILED(hr)) return 0;
dev->lpVtbl->CreateShaderResourceView(dev, (ID3D11Resource*)f->texture, NULL, &f->srv);
f->shader = shader_create();
if (!shader_compile(f->shader, dev, NULL, NULL, 0, 0)) return 0;
g_font_shader = f->shader;
D3D11_BUFFER_DESC bd = {0};
bd.ByteWidth = FONT_MAX_QUADS * 4 * sizeof(FontVert);
bd.Usage = D3D11_USAGE_DEFAULT;
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
memset(g_font_verts, 0, sizeof(g_font_verts));
sd.pSysMem = g_font_verts;
dev->lpVtbl->CreateBuffer(dev, &bd, &sd, &g_font_vb);
bd.ByteWidth = FONT_MAX_QUADS * 6 * sizeof(uint32_t);
bd.Usage = D3D11_USAGE_DEFAULT;
bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
memset(g_font_indices, 0, sizeof(g_font_indices));
sd.pSysMem = g_font_indices;
dev->lpVtbl->CreateBuffer(dev, &bd, &sd, &g_font_ib);
bd.ByteWidth = 256; bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
dev->lpVtbl->CreateBuffer(dev, &bd, NULL, &f->cb);
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, &f->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, &f->sampler);
D3D11_DEPTH_STENCIL_DESC dsdesc = {0};
dsdesc.DepthEnable = FALSE;
dsdesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
dev->lpVtbl->CreateDepthStencilState(dev, &dsdesc, &f->ds_no_depth);
LOG_INFO("bitmap_font: initialized (%dx%d atlas)", f->atlas_w, f->atlas_h);
return 1;
}
void bitmap_font_destroy(BitmapFont* f) {
if (!f) return;
if (f->ds_no_depth) f->ds_no_depth->lpVtbl->Release(f->ds_no_depth);
if (f->sampler) f->sampler->lpVtbl->Release(f->sampler);
if (f->blend) f->blend->lpVtbl->Release(f->blend);
if (f->cb) f->cb->lpVtbl->Release(f->cb);
if (g_font_ib) { g_font_ib->lpVtbl->Release(g_font_ib); g_font_ib = NULL; }
if (g_font_vb) { g_font_vb->lpVtbl->Release(g_font_vb); g_font_vb = NULL; }
if (f->shader) { shader_destroy(f->shader); g_font_shader = NULL; }
if (f->srv) f->srv->lpVtbl->Release(f->srv);
if (f->texture) f->texture->lpVtbl->Release(f->texture);
memset(f, 0, sizeof(*f));
}
static void font_flush(ID3D11DeviceContext* ctx,
float screen_w, float screen_h, int num_idx) {
if (num_idx == 0) return;
float wvp[64];
make_ortho(wvp, screen_w, screen_h);
ID3D11Device* dev = NULL;
ctx->lpVtbl->GetDevice(ctx, &dev);
D3D11_RASTERIZER_DESC rdesc = {0};
rdesc.FillMode = D3D11_FILL_SOLID;
rdesc.CullMode = D3D11_CULL_NONE;
rdesc.ScissorEnable = FALSE;
ID3D11RasterizerState* rstate = NULL;
HRESULT hr = dev->lpVtbl->CreateRasterizerState(dev, &rdesc, &rstate);
if (rstate) {
ctx->lpVtbl->RSSetState(ctx, rstate);
rstate->lpVtbl->Release(rstate);
}
dev->lpVtbl->Release(dev);
shader_bind(g_font_shader, ctx);
shader_set_matrix(g_font_shader, ctx, wvp);
UINT stride = sizeof(FontVert), offset = 0;
ctx->lpVtbl->IASetVertexBuffers(ctx, 0, 1, &g_font_vb, &stride, &offset);
ctx->lpVtbl->IASetIndexBuffer(ctx, g_font_ib, DXGI_FORMAT_R32_UINT, 0);
ctx->lpVtbl->IASetPrimitiveTopology(ctx, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
ctx->lpVtbl->DrawIndexed(ctx, (UINT)num_idx, 0, 0);
}
static void font_begin(void) { g_font_vi = 0; g_font_ii = 0; }
static void font_add_quad(BitmapFont* f, float x, float y, float w, float h,
float r, float g, float b, float a) {
if (g_font_vi + 4 > FONT_MAX_QUADS * 4) return;
float u0 = 0.19f, v0 = 0.01f, u1 = 0.24f, v1 = 0.15f;
int vi = g_font_vi;
g_font_verts[vi] = (FontVert){{x, y, 0},{0,0,-1},{u0,v0},{r,g,b,a}};
g_font_verts[vi+1] = (FontVert){{x+w, y, 0},{0,0,-1},{u1,v0},{r,g,b,a}};
g_font_verts[vi+2] = (FontVert){{x+w, y+h, 0},{0,0,-1},{u1,v1},{r,g,b,a}};
g_font_verts[vi+3] = (FontVert){{x, y+h, 0},{0,0,-1},{u0,v1},{r,g,b,a}};
uint32_t base = (uint32_t)vi;
g_font_indices[g_font_ii++] = base; g_font_indices[g_font_ii++] = base+1; g_font_indices[g_font_ii++] = base+2;
g_font_indices[g_font_ii++] = base; g_font_indices[g_font_ii++] = base+2; g_font_indices[g_font_ii++] = base+3;
g_font_vi += 4;
}
void bitmap_font_draw(BitmapFont* f, ID3D11DeviceContext* ctx,
const char* text, int x, int y,
float r, float g, float b, float a,
float screen_w, float screen_h) {
if (!text || !*text || !f->shader) return;
int len = (int)strlen(text);
if (len > FONT_MAX_QUADS) len = FONT_MAX_QUADS;
int cols = f->atlas_w / FONT_CHAR_W;
font_begin();
int cx = x;
for (int i = 0; i < len; i++) {
int ch = (unsigned char)text[i] - FONT_FIRST_CHAR;
if (ch < 0 || ch >= FONT_NUM_CHARS) ch = 0;
int col_idx = ch % cols;
int row_idx = ch / cols;
float u0 = (float)(col_idx * FONT_CHAR_W) / (float)f->atlas_w;
float v0 = (float)(row_idx * FONT_CHAR_H) / (float)f->atlas_h;
float u1 = (float)((col_idx + 1) * FONT_CHAR_W) / (float)f->atlas_w;
float v1 = (float)((row_idx + 1) * FONT_CHAR_H) / (float)f->atlas_h;
int vi = g_font_vi;
g_font_verts[vi] = (FontVert){{(float)cx,(float)y,0},{0,0,-1},{u0,v0},{r,g,b,a}};
g_font_verts[vi+1] = (FontVert){{(float)cx+FONT_CHAR_W,(float)y,0},{0,0,-1},{u1,v0},{r,g,b,a}};
g_font_verts[vi+2] = (FontVert){{(float)cx+FONT_CHAR_W,(float)y+FONT_CHAR_H,0},{0,0,-1},{u1,v1},{r,g,b,a}};
g_font_verts[vi+3] = (FontVert){{(float)cx,(float)y+FONT_CHAR_H,0},{0,0,-1},{u0,v1},{r,g,b,a}};
uint32_t base = (uint32_t)vi;
g_font_indices[g_font_ii++] = base; g_font_indices[g_font_ii++] = base+1; g_font_indices[g_font_ii++] = base+2;
g_font_indices[g_font_ii++] = base; g_font_indices[g_font_ii++] = base+2; g_font_indices[g_font_ii++] = base+3;
g_font_vi += 4;
cx += FONT_CHAR_W;
}
ctx->lpVtbl->UpdateSubresource(ctx, (ID3D11Resource*)g_font_vb, 0, NULL, g_font_verts, 0, 0);
ctx->lpVtbl->UpdateSubresource(ctx, (ID3D11Resource*)g_font_ib, 0, NULL, g_font_indices, 0, 0);
font_flush(ctx, screen_w, screen_h, g_font_ii);
}
void bitmap_font_rect(BitmapFont* f, ID3D11DeviceContext* ctx,
float x, float y, float w, float h,
float r, float g, float b, float a,
float screen_w, float screen_h) {
if (!f->shader) return;
font_begin();
font_add_quad(f, x, y, w, h, r, g, b, a);
ctx->lpVtbl->UpdateSubresource(ctx, (ID3D11Resource*)g_font_vb, 0, NULL, g_font_verts, 0, 0);
ctx->lpVtbl->UpdateSubresource(ctx, (ID3D11Resource*)g_font_ib, 0, NULL, g_font_indices, 0, 0);
font_flush(ctx, screen_w, screen_h, g_font_ii);
}
+40
View File
@@ -0,0 +1,40 @@
#pragma once
#include <d3d11.h>
#include <stdint.h>
#include "../Rendering/shader.h"
#define FONT_CHAR_W 8
#define FONT_CHAR_H 16
#define FONT_FIRST_CHAR 32
#define FONT_NUM_CHARS 96
#define FONT_MAX_QUADS 4096
typedef struct {
float pos[3];
float norm[3];
float uv[2];
float color[4];
} FontVert;
typedef struct {
ID3D11Texture2D* texture;
ID3D11ShaderResourceView* srv;
ID3D11Buffer* cb;
Shader* shader;
ID3D11BlendState* blend;
ID3D11SamplerState* sampler;
ID3D11DepthStencilState* ds_no_depth;
int atlas_w;
int atlas_h;
} BitmapFont;
int bitmap_font_init(BitmapFont* f, ID3D11Device* dev);
void bitmap_font_destroy(BitmapFont* f);
void bitmap_font_draw(BitmapFont* f, ID3D11DeviceContext* ctx,
const char* text, int x, int y,
float r, float g, float b, float a,
float screen_w, float screen_h);
void bitmap_font_rect(BitmapFont* f, ID3D11DeviceContext* ctx,
float x, float y, float w, float h,
float r, float g, float b, float a,
float screen_w, float screen_h);
+122
View File
@@ -0,0 +1,122 @@
#include "editor.h"
#include "../Core/logger.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
static const float BG_DARK[] = {0.12f, 0.12f, 0.14f};
static const float BG_PANEL[] = {0.16f, 0.16f, 0.18f};
static const float BG_TITLE[] = {0.20f, 0.20f, 0.24f};
static const float BG_INPUT[] = {0.10f, 0.10f, 0.12f};
int editor_init(Editor* ed, GraphicsDevice* dev) {
memset(ed, 0, sizeof(*ed));
ed->device = dev;
if (!uilayer_init(&ed->ui, dev->device, (float)dev->width, (float)dev->height)) return 0;
int sw = dev->width, sh = dev->height;
int menu_h = 28;
ed->panels[0] = (EditorPanel){PANEL_VIEWPORT, "Viewport", 220, menu_h, sw-440, sh-menu_h-200, 1, 0, 0};
ed->panels[1] = (EditorPanel){PANEL_SCENE, "Scene", 0, menu_h, 220, sh-menu_h-200, 1, 0, 0};
ed->panels[2] = (EditorPanel){PANEL_INSPECTOR, "Inspector", sw-220, menu_h, 220, sh-menu_h-200, 1, 0, 0};
ed->panels[3] = (EditorPanel){PANEL_CONSOLE, "Console", 0, sh-200, sw, 200, 1, 0, 0};
ed->panel_count = 4;
ed->scene_entities_count = 8;
strcpy(ed->selected_entity, "Cube");
LOG_INFO("Editor initialized");
return 1;
}
void editor_shutdown(Editor* ed) {
uilayer_destroy(&ed->ui);
}
void editor_update(Editor* ed, float dt) {
ed->time += dt;
ed->viewport_rotation += dt * 0.5f;
}
void editor_render(Editor* ed) {
ID3D11DeviceContext* ctx = ed->device->context;
float sw = (float)ed->device->width;
float sh = (float)ed->device->height;
graphics_device_clear(ed->device, BG_DARK[0], BG_DARK[1], BG_DARK[2], 1.0f);
uilayer_begin(&ed->ui);
uilayer_rect(&ed->ui, 0, 0, sw, 28, 1.0f, 0.0f, 0.0f, 1.0f);
uilayer_rect(&ed->ui, 0, 28, sw, 28, 0.0f, 1.0f, 0.0f, 1.0f);
uilayer_rect(&ed->ui, 0, 56, sw/3, sh-256, 0.0f, 0.0f, 1.0f, 1.0f);
uilayer_rect(&ed->ui, sw/3, 56, sw/3, sh-256, 1.0f, 1.0f, 0.0f, 1.0f);
uilayer_rect(&ed->ui, 2*sw/3, 56, sw/3, sh-256, 1.0f, 0.0f, 1.0f, 1.0f);
uilayer_rect(&ed->ui, 0, sh-200, sw, 200, 0.0f, 1.0f, 1.0f, 1.0f);
uilayer_rect(&ed->ui, 0, sh-22, sw, 22, 1.0f, 0.5f, 0.0f, 1.0f);
uilayer_flush(&ed->ui, ctx);
float sw2 = sw, sh2 = sh;
bitmap_font_draw(&ed->font, ctx, "MiMo Engine Editor", 10, 6,
0.4f, 0.75f, 1.0f, 1.0f, sw2, sh2);
const char* menu[] = {"File", "Edit", "View", "Build", "Help"};
int mx = 180;
for (int i = 0; i < 5; i++) {
bitmap_font_draw(&ed->font, ctx, menu[i], mx + 8, 6,
0.9f, 0.9f, 0.92f, 1.0f, sw2, sh2);
mx += (int)strlen(menu[i]) * 8 + 16;
}
const char* tools[] = {"Select", "Move", "Rotate", "Scale"};
int tx = 6;
for (int i = 0; i < 4; i++) {
bitmap_font_draw(&ed->font, ctx, tools[i], tx + 4, 34,
0.9f, 0.9f, 0.92f, 1.0f, sw2, sh2);
tx += (int)strlen(tools[i]) * 8 + 16;
}
for (int i = 0; i < ed->panel_count; i++) {
EditorPanel* p = &ed->panels[i];
if (!p->visible) continue;
bitmap_font_draw(&ed->font, ctx, p->title, p->x + 6, p->y + 6,
0.9f, 0.9f, 0.92f, 1.0f, sw2, sh2);
}
bitmap_font_draw(&ed->font, ctx, ed->selected_entity, 226, 56,
0.4f, 0.75f, 1.0f, 1.0f, sw2, sh2);
const char* entities[] = {"Light", "Camera", "Cube", "Plane", "Sphere", "Particles", "Audio", "Skybox"};
for (int i = 0; i < 8; i++) {
bitmap_font_draw(&ed->font, ctx, entities[i], 226, 78 + i * 22,
0.9f, 0.9f, 0.92f, 1.0f, sw2, sh2);
}
const char* sections[] = {"Transform", "Mesh Filter", "Material", "Collider"};
int sy = 56;
for (int s = 0; s < 4; s++) {
bitmap_font_draw(&ed->font, ctx, sections[s], (int)sw - 214, sy,
0.9f, 0.9f, 0.92f, 1.0f, sw2, sh2);
sy += 26;
}
char status[128];
snprintf(status, sizeof(status), "Entities: %d | Time: %.1fs", ed->scene_entities_count, ed->time);
bitmap_font_draw(&ed->font, ctx, status, 10, (int)sh - 18,
0.55f, 0.55f, 0.6f, 1.0f, sw2, sh2);
}
void editor_handle_input(Editor* ed, int msg, int wp, int lp) {
(void)lp;
switch (msg) {
case 0x0200: ed->input.mouse_x = wp & 0xFFFF; ed->input.mouse_y = (wp >> 16) & 0x7FFF; break;
case 0x0201: ed->input.mouse_lbtn = 1; break;
case 0x0202: ed->input.mouse_lbtn = 0; break;
case 0x0204: ed->input.mouse_rbtn = 1; break;
case 0x0205: ed->input.mouse_rbtn = 0; break;
case 0x0100: if (wp < 256) ed->input.key_down[wp] = 1; break;
case 0x0101: if (wp < 256) ed->input.key_down[wp] = 0; break;
}
}
+55
View File
@@ -0,0 +1,55 @@
#pragma once
#include "uilayer.h"
#include "bitmap_font.h"
#include "../Rendering/graphics_device.h"
#include <stdint.h>
#define EDITOR_MAX_PANELS 16
typedef enum {
PANEL_SCENE,
PANEL_INSPECTOR,
PANEL_CONSOLE,
PANEL_ASSETS,
PANEL_VIEWPORT,
} PanelType;
typedef struct {
PanelType type;
const char* title;
int x, y, w, h;
int visible;
int collapsed;
int active_tab;
} EditorPanel;
typedef struct {
int mouse_x, mouse_y;
int mouse_lbtn;
int mouse_rbtn;
int key_down[256];
char text_input[256];
int text_len;
} EditorInput;
typedef struct {
GraphicsDevice* device;
UILayer ui;
BitmapFont font;
EditorPanel panels[EDITOR_MAX_PANELS];
int panel_count;
EditorInput input;
float time;
char console_lines[32][256];
int console_count;
int console_scroll;
char selected_entity[128];
int scene_entities_count;
float viewport_rotation;
} Editor;
int editor_init(Editor* ed, GraphicsDevice* dev);
void editor_shutdown(Editor* ed);
void editor_update(Editor* ed, float dt);
void editor_render(Editor* ed);
void editor_handle_input(Editor* ed, int msg, int wp, int lp);
+124
View File
@@ -0,0 +1,124 @@
#include "editor_2d.h"
#include <stdlib.h>
#include <string.h>
int editor2d_init(Editor2D* e, ID3D11Device* dev) {
memset(e, 0, sizeof(*e));
e->shader = shader_create();
if (!shader_compile(e->shader, dev, NULL, NULL, 0, 0)) return 0;
D3D11_BUFFER_DESC bd = {0};
bd.ByteWidth = ED2D_MAX_QUADS * 4 * sizeof(Ed2DVert);
bd.Usage = D3D11_USAGE_DYNAMIC;
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
if (FAILED(dev->lpVtbl->CreateBuffer(dev, &bd, NULL, &e->vb))) return 0;
bd.ByteWidth = ED2D_MAX_QUADS * 6 * sizeof(uint32_t);
bd.Usage = D3D11_USAGE_DEFAULT;
bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
bd.CPUAccessFlags = 0;
uint32_t* idx = (uint32_t*)malloc(ED2D_MAX_QUADS * 6 * sizeof(uint32_t));
for (int i = 0; i < ED2D_MAX_QUADS; i++) {
uint32_t b2 = i * 4;
idx[i*6]=b2; idx[i*6+1]=b2+1; idx[i*6+2]=b2+2;
idx[i*6+3]=b2; idx[i*6+4]=b2+2; idx[i*6+5]=b2+3;
}
D3D11_SUBRESOURCE_DATA sd = {0}; sd.pSysMem = idx;
dev->lpVtbl->CreateBuffer(dev, &bd, &sd, &e->ib);
free(idx);
e->verts = (Ed2DVert*)malloc(ED2D_MAX_QUADS * 4 * sizeof(Ed2DVert));
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, &e->blend);
D3D11_DEPTH_STENCIL_DESC dsdesc = {0};
dsdesc.DepthEnable = FALSE;
dsdesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
dev->lpVtbl->CreateDepthStencilState(dev, &dsdesc, &e->ds_no_depth);
return 1;
}
void editor2d_destroy(Editor2D* e) {
if (!e) return;
if (e->ds_no_depth) e->ds_no_depth->lpVtbl->Release(e->ds_no_depth);
if (e->blend) e->blend->lpVtbl->Release(e->blend);
if (e->ib) e->ib->lpVtbl->Release(e->ib);
if (e->vb) e->vb->lpVtbl->Release(e->vb);
shader_destroy(e->shader);
free(e->verts);
memset(e, 0, sizeof(*e));
}
void editor2d_begin(Editor2D* e, float sw, float sh) {
e->quad_count = 0;
e->screen_w = sw;
e->screen_h = sh;
memset(e->wvp, 0, sizeof(e->wvp));
e->wvp[0] = 2.0f / sw;
e->wvp[5] = -2.0f / sh;
e->wvp[12] = -1.0f;
e->wvp[13] = 1.0f;
e->wvp[15] = 1.0f;
}
void editor2d_rect(Editor2D* e, float x, float y, float w, float h, float r, float g, float b, float a) {
if (e->quad_count >= ED2D_MAX_QUADS) return;
int vi = e->quad_count * 4;
e->verts[vi+0] = (Ed2DVert){x, y, 0, 0,0,-1, 0,1, r,g,b,a};
e->verts[vi+1] = (Ed2DVert){x+w, y, 0, 0,0,-1, 1,1, r,g,b,a};
e->verts[vi+2] = (Ed2DVert){x+w, y+h, 0, 0,0,-1, 1,0, r,g,b,a};
e->verts[vi+3] = (Ed2DVert){x, y+h, 0, 0,0,-1, 0,0, r,g,b,a};
e->quad_count++;
}
void editor2d_rect_border(Editor2D* e, float x, float y, float w, float h, float r, float g, float b, float a, float t) {
editor2d_rect(e, x, y, w, t, r, g, b, a);
editor2d_rect(e, x, y+h-t, w, t, r, g, b, a);
editor2d_rect(e, x, y, t, h, r, g, b, a);
editor2d_rect(e, x+w-t, y, t, h, r, g, b, a);
}
void editor2d_end(Editor2D* e, ID3D11DeviceContext* ctx) {
if (e->quad_count == 0) return;
D3D11_MAPPED_SUBRESOURCE mapped;
if (FAILED(ctx->lpVtbl->Map(ctx, (ID3D11Resource*)e->vb, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped))) return;
memcpy(mapped.pData, e->verts, (size_t)e->quad_count * 4 * sizeof(Ed2DVert));
ctx->lpVtbl->Unmap(ctx, (ID3D11Resource*)e->vb, 0);
if (e->rtv) {
ctx->lpVtbl->OMSetRenderTargets(ctx, 1, &e->rtv, NULL);
}
D3D11_VIEWPORT vp = {0};
vp.Width = e->screen_w;
vp.Height = e->screen_h;
vp.MaxDepth = 1.0f;
ctx->lpVtbl->RSSetViewports(ctx, 1, &vp);
shader_bind(e->shader, ctx);
shader_set_matrix(e->shader, ctx, e->wvp);
UINT stride = sizeof(Ed2DVert), offset = 0;
ctx->lpVtbl->IASetVertexBuffers(ctx, 0, 1, &e->vb, &stride, &offset);
ctx->lpVtbl->IASetIndexBuffer(ctx, e->ib, DXGI_FORMAT_R32_UINT, 0);
ctx->lpVtbl->IASetPrimitiveTopology(ctx, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
float bf[4] = {0};
ctx->lpVtbl->OMSetBlendState(ctx, e->blend, bf, 0xFFFFFFFF);
ctx->lpVtbl->OMSetDepthStencilState(ctx, e->ds_no_depth, 0);
ctx->lpVtbl->DrawIndexed(ctx, (UINT)(e->quad_count * 6), 0, 0);
}
+35
View File
@@ -0,0 +1,35 @@
#pragma once
#include <d3d11.h>
#include <stdint.h>
#include "../Rendering/shader.h"
#include "../Rendering/mesh.h"
#define ED2D_MAX_QUADS 8192
typedef struct {
float x, y, z;
float nx, ny, nz;
float u, v;
float r, g, b, a;
} Ed2DVert;
typedef struct {
Shader* shader;
ID3D11Buffer* vb;
ID3D11Buffer* ib;
ID3D11BlendState* blend;
ID3D11DepthStencilState* ds_no_depth;
ID3D11RenderTargetView* rtv;
Ed2DVert* verts;
int quad_count;
float screen_w;
float screen_h;
float wvp[16];
} Editor2D;
int editor2d_init(Editor2D* e, ID3D11Device* dev);
void editor2d_destroy(Editor2D* e);
void editor2d_begin(Editor2D* e, float sw, float sh);
void editor2d_rect(Editor2D* e, float x, float y, float w, float h, float r, float g, float b, float a);
void editor2d_rect_border(Editor2D* e, float x, float y, float w, float h, float r, float g, float b, float a, float thickness);
void editor2d_end(Editor2D* e, ID3D11DeviceContext* ctx);
+171
View File
@@ -0,0 +1,171 @@
#include "glyph_atlas.h"
#include <stdlib.h>
#include <string.h>
#include <d3d11.h>
#include <Windows.h>
#include "../Core/logger.h"
typedef struct {
wchar_t ch;
int x, y;
int w, h;
float u0, v0, u1, v1;
float advance_x;
} GlyphEntry;
#define MAX_GLYPHS 1024
static GlyphEntry g_entries[MAX_GLYPHS];
static int g_entry_count = 0;
int glyph_atlas_init(GlyphAtlas* ga, ID3D11Device* dev) {
memset(ga, 0, sizeof(*ga));
ga->cell_w = GLYPH_CELL_W;
ga->cell_h = GLYPH_CELL_H;
ga->atlas_w = GLYPH_ATLAS_SIZE;
ga->atlas_h = GLYPH_ATLAS_SIZE;
ga->next_x = 0;
ga->next_y = 0;
ga->u_scale = 1.0f / (float)ga->atlas_w;
ga->v_scale = 1.0f / (float)ga->atlas_h;
uint8_t* pixels = (uint8_t*)calloc(ga->atlas_w * ga->atlas_h * 4, 1);
D3D11_TEXTURE2D_DESC td = {0};
td.Width = ga->atlas_w;
td.Height = ga->atlas_h;
td.MipLevels = 1;
td.ArraySize = 1;
td.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
td.SampleDesc.Count = 1;
td.Usage = D3D11_USAGE_DEFAULT;
td.BindFlags = D3D11_BIND_SHADER_RESOURCE;
D3D11_SUBRESOURCE_DATA sd = {0};
sd.pSysMem = pixels;
sd.SysMemPitch = ga->atlas_w * 4;
HRESULT hr = dev->lpVtbl->CreateTexture2D(dev, &td, &sd, &ga->texture);
free(pixels);
if (FAILED(hr)) return 0;
dev->lpVtbl->CreateShaderResourceView(dev, (ID3D11Resource*)ga->texture, NULL, &ga->srv);
LOG_INFO("GlyphAtlas: initialized (%dx%d, max %d glyphs)", ga->atlas_w, ga->atlas_h, MAX_GLYPHS);
return 1;
}
void glyph_atlas_destroy(GlyphAtlas* ga) {
if (!ga) return;
if (ga->srv) ga->srv->lpVtbl->Release(ga->srv);
if (ga->texture) ga->texture->lpVtbl->Release(ga->texture);
memset(ga, 0, sizeof(*ga));
g_entry_count = 0;
}
static int find_glyph(wchar_t ch) {
for (int i = 0; i < g_entry_count; i++) {
if (g_entries[i].ch == ch) return i;
}
return -1;
}
int glyph_atlas_get_or_create(GlyphAtlas* ga, ID3D11Device* dev, ID3D11DeviceContext* ctx, wchar_t ch,
float* u0, float* v0, float* u1, float* v1,
float* advance_x, float* advance_y) {
int idx = find_glyph(ch);
if (idx >= 0) {
*u0 = g_entries[idx].u0;
*v0 = g_entries[idx].v0;
*u1 = g_entries[idx].u1;
*v1 = g_entries[idx].v1;
*advance_x = g_entries[idx].advance_x;
*advance_y = (float)g_entries[idx].h;
return 1;
}
if (g_entry_count >= MAX_GLYPHS) return 0;
if (ga->next_x + ga->cell_w > ga->atlas_w) {
ga->next_x = 0;
ga->next_y += ga->cell_h;
}
if (ga->next_y + ga->cell_h > ga->atlas_h) return 0;
HDC hdc = GetDC(NULL);
HFONT hfont = CreateFontW(
ga->cell_h - 4, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
CLEARTYPE_QUALITY, FIXED_PITCH | FF_DONTCARE, L"Microsoft YaHei"
);
HFONT old = (HFONT)SelectObject(hdc, hfont);
GLYPHMETRICS gm = {0};
MAT2 mat = {{0,0},{0,0},{0,0},{0,0}};
mat.eM11.value = 1; mat.eM22.value = 1;
DWORD size = GetGlyphOutlineW(hdc, ch, GGO_GRAY8_BITMAP, &gm, 0, NULL, &mat);
int gw = gm.gmBlackBoxX;
int gh = gm.gmBlackBoxY;
int gx = ga->next_x;
int gy = ga->next_y;
if (size > 0 && gw > 0 && gh > 0) {
uint8_t* buf = (uint8_t*)malloc(size);
GetGlyphOutlineW(hdc, ch, GGO_GRAY8_BITMAP, &gm, size, buf, &mat);
uint8_t* pixels = (uint8_t*)calloc(gw * gh * 4, 1);
int row_bytes = ((gw + 3) / 4) * 4;
for (int row = 0; row < gh; row++) {
for (int col = 0; col < gw; col++) {
int src_idx = row * row_bytes + col;
if (src_idx < (int)size) {
uint8_t gray = buf[src_idx];
uint8_t alpha = (gray > 200) ? 255 : (gray > 100) ? 200 : (gray > 30) ? 128 : 0;
int idx = (row * gw + col) * 4;
pixels[idx] = 255;
pixels[idx + 1] = 255;
pixels[idx + 2] = 255;
pixels[idx + 3] = alpha;
}
}
}
D3D11_BOX box = {0};
box.left = gx;
box.top = gy;
box.front = 0;
box.right = gx + gw;
box.bottom = gy + gh;
box.back = 1;
ctx->lpVtbl->UpdateSubresource(ctx, (ID3D11Resource*)ga->texture, 0, &box, pixels, gw * 4, 0);
free(buf);
free(pixels);
}
SelectObject(hdc, old);
DeleteObject(hfont);
ReleaseDC(NULL, hdc);
GlyphEntry* e = &g_entries[g_entry_count++];
e->ch = ch;
e->x = gx;
e->y = gy;
e->w = gw > 0 ? gw : ga->cell_w / 2;
e->h = gh > 0 ? gh : ga->cell_h;
e->u0 = (float)gx * ga->u_scale;
e->v0 = (float)gy * ga->v_scale;
e->u1 = (float)(gx + e->w) * ga->u_scale;
e->v1 = (float)(gy + e->h) * ga->v_scale;
e->advance_x = (float)(gm.gmCellIncX > 0 ? gm.gmCellIncX : ga->cell_w / 2);
ga->next_x += ga->cell_w;
*u0 = e->u0;
*v0 = e->v0;
*u1 = e->u1;
*v1 = e->v1;
*advance_x = e->advance_x;
*advance_y = (float)e->h;
return 1;
}
+28
View File
@@ -0,0 +1,28 @@
#pragma once
#include <d3d11.h>
#include <stdint.h>
#define GLYPH_CELL_W 32
#define GLYPH_CELL_H 32
#define GLYPH_ATLAS_COLS 16
#define GLYPH_ATLAS_ROWS 16
#define GLYPH_ATLAS_SIZE (GLYPH_ATLAS_COLS * GLYPH_CELL_W)
typedef struct {
ID3D11Texture2D* texture;
ID3D11ShaderResourceView* srv;
int atlas_w;
int atlas_h;
int next_x;
int next_y;
int cell_w;
int cell_h;
float u_scale;
float v_scale;
} GlyphAtlas;
int glyph_atlas_init(GlyphAtlas* ga, ID3D11Device* dev);
void glyph_atlas_destroy(GlyphAtlas* ga);
int glyph_atlas_get_or_create(GlyphAtlas* ga, ID3D11Device* dev, ID3D11DeviceContext* ctx, wchar_t ch,
float* u0, float* v0, float* u1, float* v1,
float* advance_x, float* advance_y);
+10
View File
@@ -0,0 +1,10 @@
#pragma once
#include "uilayer.h"
#include "bitmap_font.h"
int textlayer_init(TextLayer* t, ID3D11Device* dev, BitmapFont* font, UILayer* ui);
void textlayer_destroy(TextLayer* t);
void textlayer_draw(TextLayer* t, ID3D11DeviceContext* ctx,
const char* text, int x, int y,
float r, float g, float b, float a,
float screen_w, float screen_h);
+252
View File
@@ -0,0 +1,252 @@
#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);
}
+41
View File
@@ -0,0 +1,41 @@
#pragma once
#include "../Rendering/camera.h"
#include "../Rendering/shader.h"
#include "../Rendering/mesh.h"
#include "../Rendering/graphics_device.h"
#include "../ASM/math_c_fallback.h"
#define UI_MAX_QUADS 8192
typedef struct {
Camera camera;
Shader* shader;
ID3D11Buffer* vb;
ID3D11Buffer* ib;
ID3D11Buffer* text_vb;
ID3D11Buffer* text_ib;
ID3D11RasterizerState* rstate;
ID3D11DepthStencilState* ds_state;
ID3D11VertexShader* text_vs;
ID3D11PixelShader* text_ps;
ID3D11InputLayout* text_layout;
ID3D11BlendState* text_blend;
ID3D11SamplerState* text_sampler;
float screen_w;
float screen_h;
float z_plane;
} UILayer;
int uilayer_init(UILayer* u, ID3D11Device* dev, float screen_w, float screen_h);
void uilayer_destroy(UILayer* u);
void uilayer_begin(UILayer* u);
void uilayer_rect(UILayer* u,
float x, float y, float w, float h,
float r, float g, float b, float a);
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 uilayer_flush(UILayer* u, ID3D11DeviceContext* ctx);
void uilayer_flush_text(UILayer* u, ID3D11DeviceContext* ctx);