MiMoEngine ASM: x86-64 MASM汇编+C混合架构游戏引擎
核心热路径(数学/内存/字符串/性能分析)用MASM汇编(SSE/AVX2) 外围系统(窗口/渲染/ECS/音频/UI/脚本)用C语言 含自研编辑器、VisualScript积木编程、中文渲染(glyph_atlas)
This commit is contained in:
commit
2d56cb3bc9
91 files changed
+9988
No files matched your search
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
Reference in new issue
Block a user