From 7a0533d21acf48b3722ded6be96e527a574e20cf Mon Sep 17 00:00:00 2001 From: shuiyu1123 Date: Sun, 12 Jul 2026 12:13:50 +0800 Subject: [PATCH] sync: user's Lity3D_source.zip changes - Engine core: improved initialization and lifecycle - Renderer: camera and rendering pipeline updates - Editor: updated editor code - Window: improved window handling - Demo/main.c: scene demo with AssetManager + scene loading - build.bat: updated build script - 11 files modified from user's manual edits --- Demo/editor_main.c | 983 +++++++++++++++++++++++------------- Demo/main.c | 2 +- Engine/Core/engine.c | 6 +- Engine/Core/engine.h | 2 +- Engine/Core/logger.c | 4 +- Engine/Editor/editor.c | 2 +- Engine/Rendering/camera.c | 2 +- Engine/Rendering/renderer.c | 27 +- Engine/Rendering/renderer.h | 3 + Engine/Window/window.c | 8 +- build.bat | 46 +- 11 files changed, 707 insertions(+), 378 deletions(-) diff --git a/Demo/editor_main.c b/Demo/editor_main.c index 98895c8..b7d1b6d 100644 --- a/Demo/editor_main.c +++ b/Demo/editor_main.c @@ -1,391 +1,682 @@ #include "../Engine/Core/engine.h" #include "../Engine/Core/logger.h" -#include "../Engine/Core/timer.h" -#include "../Engine/Window/window.h" +#include "../Engine/Core/asset_manager.h" #include "../Engine/Rendering/graphics_device.h" +#include "../Engine/Rendering/renderer.h" +#include "../Engine/Rendering/shader.h" +#include "../Engine/Rendering/material.h" +#include "../Engine/Rendering/mesh.h" +#include "../Engine/Rendering/camera.h" +#include "../Engine/Scene/scene_graph.h" +#include "../Engine/Scene/scene_render.h" +#include "../Engine/Scene/scene_serialize.h" +#include "../Engine/Editor/glyph_atlas.h" #include "../Engine/include/engine_api.h" #include "../Engine/ASM/math_c_fallback.h" -#include "../Engine/Editor/glyph_atlas.h" #include #include #include #include +#include -static GraphicsDevice* g_dev = NULL; -static GlyphAtlas g_atlas; +/* -------------------------------------------------------------------------- */ +/* Editor state */ +/* -------------------------------------------------------------------------- */ +static Engine* g_engine = NULL; +static GraphicsDevice* g_gdev = NULL; +static Renderer* g_renderer = NULL; +static AssetManager* g_assets = NULL; +static Asset* g_shader_asset = NULL; +static Scene* g_scene = NULL; +static Camera g_camera; -static ID3D11DepthStencilState* g_no_depth = NULL; -static ID3D11RasterizerState* g_no_cull = NULL; -static ID3D11BlendState* g_alpha_blend = NULL; -static ID3D11SamplerState* g_sampler = NULL; -static ID3D11Buffer* g_cb = NULL; +static GlyphAtlas g_atlas; +static int g_atlas_ok = 0; -static ID3D11VertexShader* g_vs = NULL; -static ID3D11PixelShader* g_ps = NULL; -static ID3D11InputLayout* g_layout = NULL; -static ID3D11VertexShader* g_tex_vs = NULL; -static ID3D11PixelShader* g_tex_ps = NULL; -static ID3D11InputLayout* g_tex_layout = NULL; +static SceneNode* g_selected = NULL; +static int g_mouse_x = 0; +static int g_mouse_y = 0; +static int g_mouse_down[3] = {0}; +static int g_mouse_last_x = 0; +static int g_mouse_last_y = 0; +static int g_camera_drag = 0; -typedef struct { float p[3], n[3], uv[2], c[4]; } V; +static char g_console[16][256]; +static int g_console_count = 0; +static char g_status[256] = ""; -static void draw_quad(ID3D11DeviceContext* ctx, float x, float y, float w, float h, - float r, float g, float b, float a) { - V v[4] = { - {{x,y,0},{0,0,-1},{0,0},{r,g,b,a}}, - {{x+w,y,0},{0,0,-1},{1,0},{r,g,b,a}}, - {{x+w,y+h,0},{0,0,-1},{1,1},{r,g,b,a}}, - {{x,y+h,0},{0,0,-1},{0,1},{r,g,b,a}}, - }; - uint32_t idx[6] = {0,1,2, 0,2,3}; - ID3D11Buffer *vb = NULL, *ib = NULL; - D3D11_BUFFER_DESC bd = {0}; D3D11_SUBRESOURCE_DATA sd = {0}; - bd.ByteWidth = sizeof(V)*4; bd.Usage = D3D11_USAGE_DEFAULT; bd.BindFlags = D3D11_BIND_VERTEX_BUFFER; - sd.pSysMem = v; g_dev->device->lpVtbl->CreateBuffer(g_dev->device, &bd, &sd, &vb); - bd.ByteWidth = sizeof(uint32_t)*6; bd.BindFlags = D3D11_BIND_INDEX_BUFFER; - sd.pSysMem = idx; g_dev->device->lpVtbl->CreateBuffer(g_dev->device, &bd, &sd, &ib); - UINT stride = sizeof(V), 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, 6, 0, 0); - ib->lpVtbl->Release(ib); vb->lpVtbl->Release(vb); -} +/* UI metrics */ +#define ED_MENU_H 30 +#define ED_TOOLBAR_H 30 +#define ED_LEFT_W 240 +#define ED_RIGHT_W 260 +#define ED_BOTTOM_H 180 +#define ED_SPLITTER 1 -static void draw_text(ID3D11DeviceContext* ctx, const wchar_t* text, - int x, int y, float r, float g, float b, float a) { - typedef struct { float p[3], n[3], uv[2], c[4]; } TV; - ctx->lpVtbl->VSSetShader(ctx, g_tex_vs, NULL, 0); - ctx->lpVtbl->PSSetShader(ctx, g_tex_ps, NULL, 0); - ctx->lpVtbl->IASetInputLayout(ctx, g_tex_layout); - ctx->lpVtbl->VSSetConstantBuffers(ctx, 0, 1, &g_cb); - ctx->lpVtbl->PSSetShaderResources(ctx, 0, 1, &g_atlas.srv); - ctx->lpVtbl->PSSetSamplers(ctx, 0, 1, &g_sampler); - ctx->lpVtbl->OMSetBlendState(ctx, g_alpha_blend, NULL, 0xFFFFFFFF); - for (const wchar_t* p = text; *p; p++) { - float u0, v0, u1, v1, adv_x, adv_y; - if (!glyph_atlas_get_or_create(&g_atlas, g_dev->device, ctx, *p, &u0, &v0, &u1, &v1, &adv_x, &adv_y)) continue; - TV tv[4] = { - {{(float)x,(float)y,0},{0,0,1},{u0,v0},{r,g,b,a}}, - {{(float)x+adv_x,(float)y,0},{0,0,1},{u1,v0},{r,g,b,a}}, - {{(float)x+adv_x,(float)y+adv_y,0},{0,0,1},{u1,v1},{r,g,b,a}}, - {{(float)x,(float)y+adv_y,0},{0,0,1},{u0,v1},{r,g,b,a}}, - }; - uint32_t ti[6] = {0,1,2, 0,2,3}; - ID3D11Buffer *tvb = NULL, *tib = NULL; - D3D11_BUFFER_DESC bd = {0}; D3D11_SUBRESOURCE_DATA sd = {0}; - bd.ByteWidth = sizeof(TV)*4; bd.Usage = D3D11_USAGE_DEFAULT; bd.BindFlags = D3D11_BIND_VERTEX_BUFFER; - sd.pSysMem = tv; g_dev->device->lpVtbl->CreateBuffer(g_dev->device, &bd, &sd, &tvb); - bd.ByteWidth = sizeof(uint32_t)*6; bd.BindFlags = D3D11_BIND_INDEX_BUFFER; - sd.pSysMem = ti; g_dev->device->lpVtbl->CreateBuffer(g_dev->device, &bd, &sd, &tib); - UINT stride2 = sizeof(TV), offset2 = 0; - ctx->lpVtbl->IASetVertexBuffers(ctx, 0, 1, &tvb, &stride2, &offset2); - ctx->lpVtbl->IASetIndexBuffer(ctx, tib, DXGI_FORMAT_R32_UINT, 0); - ctx->lpVtbl->DrawIndexed(ctx, 6, 0, 0); - tib->lpVtbl->Release(tib); tvb->lpVtbl->Release(tvb); - x += (int)adv_x + 1; - } -} +/* UI D3D resources */ +static ID3D11DepthStencilState* g_ui_depth = NULL; +static ID3D11RasterizerState* g_ui_raster = NULL; +static ID3D11BlendState* g_ui_blend = NULL; +static ID3D11SamplerState* g_ui_sampler = NULL; +static ID3D11Buffer* g_ui_cb = NULL; +static ID3D11VertexShader* g_ui_vs = NULL; +static ID3D11PixelShader* g_ui_ps = NULL; +static ID3D11InputLayout* g_ui_layout = NULL; +static ID3D11VertexShader* g_text_vs = NULL; +static ID3D11PixelShader* g_text_ps = NULL; +static ID3D11InputLayout* g_text_layout = NULL; -static void setup_solid(ID3D11DeviceContext* ctx) { - ctx->lpVtbl->VSSetShader(ctx, g_vs, NULL, 0); - ctx->lpVtbl->PSSetShader(ctx, g_ps, NULL, 0); - ctx->lpVtbl->IASetInputLayout(ctx, g_layout); - ctx->lpVtbl->VSSetConstantBuffers(ctx, 0, 1, &g_cb); - ctx->lpVtbl->OMSetBlendState(ctx, NULL, NULL, 0xFFFFFFFF); -} - -static void setup_2d(ID3D11DeviceContext* ctx, float sw, float sh) { - float proj[16] = {0}; - proj[0] = 2.0f / sw; proj[5] = -2.0f / sh; - proj[10] = 1.0f; proj[12] = -1.0f; proj[13] = 1.0f; proj[15] = 1.0f; - Mat4 proj_m, proj_t; - memcpy(&proj_m, proj, sizeof(Mat4)); - mat4_transpose(&proj_m, &proj_t); - ctx->lpVtbl->UpdateSubresource(ctx, (ID3D11Resource*)g_cb, 0, NULL, &proj_t, 0, 0); - D3D11_VIEWPORT vp = {0}; - vp.Width = sw; vp.Height = sh; vp.MaxDepth = 1.0f; - ctx->lpVtbl->RSSetViewports(ctx, 1, &vp); - ctx->lpVtbl->RSSetState(ctx, g_no_cull); - ctx->lpVtbl->OMSetDepthStencilState(ctx, g_no_depth, 0); - ctx->lpVtbl->IASetPrimitiveTopology(ctx, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - setup_solid(ctx); -} - -typedef struct { - char name[64]; - float x, y, z, rx, ry, rz, sx, sy, sz; - int visible; -} SceneEntity; - -#define MAX_ENTITIES 64 -static SceneEntity g_entities[MAX_ENTITIES]; -static int g_entity_count = 0; -static int g_selected = 2; -static char g_console_lines[32][256]; -static int g_console_count = 0; -static char g_file_path[512] = "untitled.ly"; -static int g_mouse_x = 0, g_mouse_y = 0; -static int g_mouse_click = 0; -static int g_mouse_click_x = 0, g_mouse_click_y = 0; +typedef struct { float p[3], n[3], uv[2], c[4]; } UIVertex; +/* -------------------------------------------------------------------------- */ +/* Console */ +/* -------------------------------------------------------------------------- */ static void console_add(const char* msg) { - if (g_console_count >= 32) { - for (int i = 0; i < 31; i++) strcpy(g_console_lines[i], g_console_lines[i+1]); - g_console_count = 31; + if (g_console_count >= 16) { + for (int i = 0; i < 15; i++) strcpy(g_console[i], g_console[i+1]); + g_console_count = 15; } - strncpy(g_console_lines[g_console_count], msg, 255); - g_console_lines[g_console_count][255] = 0; + strncpy(g_console[g_console_count], msg, 255); + g_console[g_console_count][255] = 0; g_console_count++; } -static void on_mouse_move(int x, int y) { - g_mouse_x = x; g_mouse_y = y; +/* -------------------------------------------------------------------------- */ +/* Shader helpers */ +/* -------------------------------------------------------------------------- */ +static ID3DBlob* compile_blob(const char* code, const char* target) { + ID3DBlob *blob = NULL, *err = NULL; + D3DCompile(code, strlen(code), NULL, NULL, NULL, "main", target, + D3DCOMPILE_OPTIMIZATION_LEVEL3 | D3DCOMPILE_PACK_MATRIX_ROW_MAJOR, 0, &blob, &err); + if (err) { + LOG_ERROR("Editor shader compile (%s): %s", target, (char*)err->lpVtbl->GetBufferPointer(err)); + err->lpVtbl->Release(err); + } + return blob; } -static void on_mouse_button(int button, int pressed) { - if (button == 0 && pressed) { - if (g_mouse_click == 0) { - g_mouse_click = 1; - g_mouse_click_x = g_mouse_x; - g_mouse_click_y = g_mouse_y; - } - } -} +static int compile_ui_shaders(ID3D11Device* dev) { + const char* vs = + "cbuffer CB:register(b0){float4x4 WVP;};" + "struct I{float4 p:POSITION;float3 n:NORMAL;float2 u:TEXCOORD;float4 c:COLOR;};" + "struct O{float4 p:SV_POSITION;float2 u:TEXCOORD;float4 c:COLOR;};" + "O main(I i){O o;o.p=mul(i.p,WVP);o.u=i.u;o.c=i.c;return o;}"; + const char* ps = + "struct O{float4 p:SV_POSITION;float2 u:TEXCOORD;float4 c:COLOR;};" + "float4 main(O i):SV_TARGET{return i.c;}"; + const char* tps = + "Texture2D t:register(t0);SamplerState s:register(s0);" + "struct O{float4 p:SV_POSITION;float2 u:TEXCOORD;float4 c:COLOR;};" + "float4 main(O i):SV_TARGET{float a=t.Sample(s,i.u).a;return float4(i.c.rgb,i.c.a*a);}"; -static void process_click(void) { - if (!g_mouse_click) return; - g_mouse_click = 0; - int cx = g_mouse_click_x, cy = g_mouse_click_y; - float pw = 220, mh = 28, th = 28, sh2 = 22, ch = 180; - if (cx >= 0 && cx <= (int)pw && cy >= (int)(mh + th)) { - for (int i = 0; i < g_entity_count; i++) { - float ey = 60 + i * 22; - if (cy >= (int)ey - 4 && cy <= (int)ey + 18) { - g_selected = i; - char buf[128]; snprintf(buf, sizeof(buf), "Selected: %s", g_entities[i].name); - console_add(buf); - return; - } - } - } -} + ID3DBlob *b1 = compile_blob(vs, "vs_5_0"), *b2 = compile_blob(ps, "ps_5_0"), *b3 = compile_blob(tps, "ps_5_0"); + if (!b1 || !b2 || !b3) return 0; -static void save_ly(const char* path) { - FILE* f = fopen(path, "w"); - if (!f) { console_add("ERROR: save failed"); return; } - fprintf(f, "# lity3d scene\n# format: .ly\n\n"); - for (int i = 0; i < g_entity_count; i++) { - SceneEntity* e = &g_entities[i]; - fprintf(f, "[Entity]\nname = %s\n", e->name); - fprintf(f, "position = %.2f, %.2f, %.2f\n", e->x, e->y, e->z); - fprintf(f, "rotation = %.2f, %.2f, %.2f\n", e->rx, e->ry, e->rz); - fprintf(f, "scale = %.2f, %.2f, %.2f\n", e->sx, e->sy, e->sz); - fprintf(f, "visible = %d\n\n", e->visible); - } - fclose(f); - char buf[128]; snprintf(buf, sizeof(buf), "Saved %d entities -> %s", g_entity_count, path); - console_add(buf); -} + dev->lpVtbl->CreateVertexShader(dev, b1->lpVtbl->GetBufferPointer(b1), b1->lpVtbl->GetBufferSize(b1), NULL, &g_ui_vs); + dev->lpVtbl->CreatePixelShader(dev, b2->lpVtbl->GetBufferPointer(b2), b2->lpVtbl->GetBufferSize(b2), NULL, &g_ui_ps); + dev->lpVtbl->CreatePixelShader(dev, b3->lpVtbl->GetBufferPointer(b3), b3->lpVtbl->GetBufferSize(b3), NULL, &g_text_ps); -static void load_ly(const char* path) { - FILE* f = fopen(path, "r"); - if (!f) { console_add("ERROR: open failed"); return; } - g_entity_count = 0; g_selected = -1; - char line[256]; SceneEntity tmp = {0}; int in_e = 0; - while (fgets(line, sizeof(line), f)) { - if (line[0] == '#' || line[0] == '\n') continue; - if (strstr(line, "[Entity]")) { - if (in_e && g_entity_count < MAX_ENTITIES) g_entities[g_entity_count++] = tmp; - memset(&tmp, 0, sizeof(tmp)); tmp.visible = 1; tmp.sx = tmp.sy = tmp.sz = 1.0f; in_e = 1; continue; - } - if (!in_e) continue; - char* eq = strchr(line, '='); if (!eq) continue; - *eq = 0; eq++; char* key = line; while (*key == ' ') key++; - char* nl = strchr(eq, '\n'); if (nl) *nl = 0; while (*eq == ' ') eq++; - if (strstr(key, "name")) strncpy(tmp.name, eq, 63); - else if (strstr(key, "position")) sscanf(eq, "%f, %f, %f", &tmp.x, &tmp.y, &tmp.z); - else if (strstr(key, "rotation")) sscanf(eq, "%f, %f, %f", &tmp.rx, &tmp.ry, &tmp.rz); - else if (strstr(key, "scale")) sscanf(eq, "%f, %f, %f", &tmp.sx, &tmp.sy, &tmp.sz); - else if (strstr(key, "visible")) tmp.visible = atoi(eq); - } - if (in_e && g_entity_count < MAX_ENTITIES) g_entities[g_entity_count++] = tmp; - fclose(f); char buf[128]; - snprintf(buf, sizeof(buf), "Loaded %d entities <- %s", g_entity_count, path); - console_add(buf); strncpy(g_file_path, path, 511); -} - -static void init_default_scene(void) { - g_entity_count = 0; - const char* n[] = {"Camera","DirectionalLight","Player","Ground","Tree","Rock","Water","Skybox"}; - for (int i = 0; i < 8; i++) { - strncpy(g_entities[i].name, n[i], 63); g_entities[i].visible = 1; - g_entities[i].sx = g_entities[i].sy = g_entities[i].sz = 1.0f; - } - g_entity_count = 8; g_selected = 2; -} - -static void on_render(Engine* engine) { - if (!g_dev) return; - process_click(); - ID3D11DeviceContext* ctx = g_dev->context; - float sw = (float)g_dev->width, sh = (float)g_dev->height; - - graphics_device_clear(g_dev, 0.18f, 0.18f, 0.22f, 1.0f); - setup_2d(ctx, sw, sh); - - float mh = 30, th = 30, ch = 180, pw = 240, sbh = 24; - - draw_quad(ctx, 0, 0, sw, mh, 0.15f, 0.15f, 0.22f, 1.0f); - draw_quad(ctx, 0, mh, sw, 1, 0.35f, 0.45f, 0.75f, 1.0f); - - draw_quad(ctx, 0, mh+1, sw, th, 0.22f, 0.22f, 0.30f, 1.0f); - draw_quad(ctx, 0, mh+th+1, sw, 1, 0.30f, 0.30f, 0.40f, 1.0f); - - float body_h = sh - mh - th - ch - sbh - 2; - draw_quad(ctx, 0, mh+th+2, pw, body_h, 0.22f, 0.22f, 0.28f, 1.0f); - draw_quad(ctx, pw, mh+th+2, 1, body_h, 0.35f, 0.45f, 0.75f, 1.0f); - - draw_quad(ctx, pw+1, mh+th+2, sw-pw*2-2, body_h, 0.16f, 0.16f, 0.20f, 1.0f); - draw_quad(ctx, sw-pw-1, mh+th+2, 1, body_h, 0.35f, 0.45f, 0.75f, 1.0f); - - draw_quad(ctx, sw-pw, mh+th+2, pw, body_h, 0.22f, 0.22f, 0.28f, 1.0f); - - draw_quad(ctx, 0, sh-ch-sbh, sw, 1, 0.35f, 0.45f, 0.75f, 1.0f); - draw_quad(ctx, 0, sh-ch-sbh+1, sw, ch, 0.19f, 0.19f, 0.25f, 1.0f); - - draw_quad(ctx, 0, sh-sbh, sw, 1, 0.35f, 0.45f, 0.75f, 1.0f); - draw_quad(ctx, 0, sh-sbh+1, sw, sbh, 0.20f, 0.22f, 0.32f, 1.0f); - - draw_text(ctx, L"lity3d Editor", 12, 7, 0.6f, 0.8f, 1.0f, 1.0f); - const wchar_t* menus[] = {L"\u6587\u4ef6", L"\u7f16\u8f91", L"\u89c6\u56fe", L"\u6784\u5efa", L"\u5e2e\u52a9"}; - int mx = 130; - for (int i = 0; i < 5; i++) { draw_text(ctx, menus[i], mx, 8, 0.9f, 0.9f, 0.92f, 1.0f); mx += 80; } - - draw_text(ctx, L"\u573a\u666f", 12, (int)(mh+th+8), 0.5f, 0.7f, 1.0f, 1.0f); - draw_text(ctx, L"\u89c6\u53e3", (int)(pw+16), (int)(mh+th+8), 0.5f, 0.7f, 1.0f, 1.0f); - draw_text(ctx, L"\u5c5e\u6027", (int)(sw-pw+12), (int)(mh+th+8), 0.5f, 0.7f, 1.0f, 1.0f); - draw_text(ctx, L"\u63a7\u5236\u53f0", 12, (int)(sh-ch-sbh+8), 0.5f, 0.7f, 1.0f, 1.0f); - - for (int i = 0; i < g_entity_count; i++) { - float ey = mh + th + 30 + i * 24; - if (i == g_selected) - draw_quad(ctx, 4, ey - 2, pw - 8, 22, 0.25f, 0.35f, 0.60f, 1.0f); - wchar_t wn[64]; int len = (int)strlen(g_entities[i].name); - for (int j = 0; j < len && j < 63; j++) wn[j] = (wchar_t)g_entities[i].name[j]; wn[len] = 0; - draw_text(ctx, wn, 16, (int)ey, (i == g_selected) ? 1.0f : 0.85f, (i == g_selected) ? 1.0f : 0.85f, (i == g_selected) ? 1.0f : 0.88f, 1.0f); - } - - if (g_selected >= 0 && g_selected < g_entity_count) { - SceneEntity* e = &g_entities[g_selected]; int ix = (int)(sw-pw+12), iy = (int)(mh+th+32); - draw_text(ctx, L"\u540d\u79f0:", ix, iy, 0.5f, 0.7f, 1.0f, 1.0f); - wchar_t wn[64]; int len = (int)strlen(e->name); - for (int j = 0; j < len && j < 63; j++) wn[j] = (wchar_t)e->name[j]; wn[len] = 0; - draw_text(ctx, wn, ix + 48, iy, 1.0f, 1.0f, 1.0f, 1.0f); - iy += 26; - draw_text(ctx, L"\u53ef\u89c1: \u2611", ix, iy, 0.85f, 0.85f, 0.88f, 1.0f); - } - - int cy = (int)(sh - ch - sbh + 28); - for (int i = g_console_count - 1; i >= 0 && i >= g_console_count - 6; i--) { - wchar_t wl[256]; int len = (int)strlen(g_console_lines[i]); - for (int j = 0; j < len && j < 255; j++) wl[j] = (wchar_t)g_console_lines[i][j]; - wl[len] = 0; draw_text(ctx, wl, 12, cy, 0.7f, 0.7f, 0.75f, 1.0f); cy += 20; - } - - char status[256]; - snprintf(status, sizeof(status), "%s | %d entities | Ctrl+S save | Ctrl+O load | Esc quit", g_file_path, g_entity_count); - wchar_t ws[256]; int sl = (int)strlen(status); - for (int j = 0; j < sl && j < 255; j++) ws[j] = (wchar_t)status[j]; ws[sl] = 0; - draw_text(ctx, ws, 12, (int)(sh - 20), 0.6f, 0.6f, 0.65f, 1.0f); - - graphics_device_present(g_dev); -} - -static void on_key(Engine* engine, int key) { - if (key == VK_ESCAPE) engine_request_quit(engine); - if (key == 'S' && GetAsyncKeyState(VK_CONTROL) & 0x8000) save_ly(g_file_path); - if (key == 'O' && GetAsyncKeyState(VK_CONTROL) & 0x8000) load_ly(g_file_path); -} - -static int compile_shader(ID3D11Device* dev, const char* vs, const char* ps, - ID3D11VertexShader** out_vs, ID3D11PixelShader** out_ps, - ID3D11InputLayout** out_layout) { - ID3DBlob *b1=NULL,*b2=NULL,*e=NULL; - D3DCompile(vs,(UINT)strlen(vs),NULL,NULL,NULL,"main","vs_5_0",0,0,&b1,&e); if(e){e->lpVtbl->Release(e);e=NULL;} - D3DCompile(ps,(UINT)strlen(ps),NULL,NULL,NULL,"main","ps_5_0",0,0,&b2,&e); if(e){e->lpVtbl->Release(e);e=NULL;} - if(!b1||!b2) return 0; - dev->lpVtbl->CreateVertexShader(dev,b1->lpVtbl->GetBufferPointer(b1),b1->lpVtbl->GetBufferSize(b1),NULL,out_vs); - dev->lpVtbl->CreatePixelShader(dev,b2->lpVtbl->GetBufferPointer(b2),b2->lpVtbl->GetBufferSize(b2),NULL,out_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,b1->lpVtbl->GetBufferPointer(b1),b1->lpVtbl->GetBufferSize(b1),out_layout); - b1->lpVtbl->Release(b1); b2->lpVtbl->Release(b2); - return 1; + dev->lpVtbl->CreateInputLayout(dev, layout, 4, b1->lpVtbl->GetBufferPointer(b1), b1->lpVtbl->GetBufferSize(b1), &g_ui_layout); + g_text_layout = g_ui_layout; + g_text_vs = g_ui_vs; + + b1->lpVtbl->Release(b1); b2->lpVtbl->Release(b2); b3->lpVtbl->Release(b3); + return g_ui_vs && g_ui_ps && g_text_ps && g_ui_layout; } -int WINAPI WinMain(HINSTANCE hI, HINSTANCE hP, LPSTR cmd, int nS) { - (void)hI;(void)hP;(void)nS; - LOG_INFO("=== lity3d Editor ==="); - EngineConfig cfg = engine_default_config(); - cfg.app_name = "lity3d Editor"; - cfg.vsync = 1; cfg.window_width = 1440; cfg.window_height = 900; - Engine* engine = engine_create(); - if (!engine_init(engine, &cfg)) return -1; - g_dev = graphics_device_create(); - if (!graphics_device_init(g_dev, window_get_handle(engine->window), cfg.window_width, cfg.window_height, 1)) return -1; - glyph_atlas_init(&g_atlas, g_dev->device); +static void create_ui_states(ID3D11Device* dev) { + D3D11_DEPTH_STENCIL_DESC dsd = {0}; + dsd.DepthEnable = FALSE; dsd.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; + dev->lpVtbl->CreateDepthStencilState(dev, &dsd, &g_ui_depth); - D3D11_DEPTH_STENCIL_DESC dsd = {0}; dsd.DepthEnable = FALSE; dsd.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; - g_dev->device->lpVtbl->CreateDepthStencilState(g_dev->device, &dsd, &g_no_depth); - D3D11_RASTERIZER_DESC rd = {0}; rd.FillMode = D3D11_FILL_SOLID; rd.CullMode = D3D11_CULL_NONE; - g_dev->device->lpVtbl->CreateRasterizerState(g_dev->device, &rd, &g_no_cull); - D3D11_BLEND_DESC bd = {0}; bd.RenderTarget[0].BlendEnable = TRUE; - bd.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; bd.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; - bd.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; bd.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; - bd.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; bd.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; + D3D11_RASTERIZER_DESC rd = {0}; + rd.FillMode = D3D11_FILL_SOLID; rd.CullMode = D3D11_CULL_NONE; + dev->lpVtbl->CreateRasterizerState(dev, &rd, &g_ui_raster); + + D3D11_BLEND_DESC bd = {0}; + bd.RenderTarget[0].BlendEnable = TRUE; + bd.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; + bd.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; + bd.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; + bd.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; + bd.RenderTarget[0].BlendOp = bd.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; bd.RenderTarget[0].RenderTargetWriteMask = 0x0F; - g_dev->device->lpVtbl->CreateBlendState(g_dev->device, &bd, &g_alpha_blend); - D3D11_SAMPLER_DESC sd = {0}; sd.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; + dev->lpVtbl->CreateBlendState(dev, &bd, &g_ui_blend); + + D3D11_SAMPLER_DESC sd = {0}; + sd.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; sd.AddressU = sd.AddressV = sd.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; - g_dev->device->lpVtbl->CreateSamplerState(g_dev->device, &sd, &g_sampler); - D3D11_BUFFER_DESC cbd = {0}; cbd.ByteWidth = 256; cbd.Usage = D3D11_USAGE_DEFAULT; cbd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; - g_dev->device->lpVtbl->CreateBuffer(g_dev->device, &cbd, NULL, &g_cb); + dev->lpVtbl->CreateSamplerState(dev, &sd, &g_ui_sampler); - const char* solid_vs = "cbuffer CB:register(b0){float4x4 WVP;};struct I{float4 p:POSITION;float3 n:NORMAL;float2 u:TEXCOORD;float4 c:COLOR;};struct O{float4 p:SV_POSITION;float2 u:TEXCOORD;float4 c:COLOR;};O main(I i){O o;o.p=mul(i.p,WVP);o.u=i.u;o.c=i.c;return o;}"; - const char* solid_ps = "struct O{float4 p:SV_POSITION;float2 u:TEXCOORD;float4 c:COLOR;};float4 main(O i):SV_TARGET{return i.c;}"; - compile_shader(g_dev->device, solid_vs, solid_ps, &g_vs, &g_ps, &g_layout); + D3D11_BUFFER_DESC cbd = {0}; + cbd.ByteWidth = 256; cbd.Usage = D3D11_USAGE_DEFAULT; cbd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + dev->lpVtbl->CreateBuffer(dev, &cbd, NULL, &g_ui_cb); +} - const char* tex_vs = "cbuffer CB:register(b0){float4x4 WVP;};struct I{float4 p:POSITION;float3 n:NORMAL;float2 u:TEXCOORD;float4 c:COLOR;};struct O{float4 p:SV_POSITION;float2 u:TEXCOORD;float4 c:COLOR;};O main(I i){O o;o.p=mul(i.p,WVP);o.u=i.u;o.c=i.c;return o;}"; - const char* tex_ps = "Texture2D t:register(t0);SamplerState s:register(s0);struct O{float4 p:SV_POSITION;float2 u:TEXCOORD;float4 c:COLOR;};float4 main(O i):SV_TARGET{float a=t.Sample(s,i.u).a;return float4(i.c.rgb,i.c.a*a);}"; - compile_shader(g_dev->device, tex_vs, tex_ps, &g_tex_vs, &g_tex_ps, &g_tex_layout); +/* -------------------------------------------------------------------------- */ +/* UI rendering */ +/* -------------------------------------------------------------------------- */ +static void ui_set_projection(ID3D11DeviceContext* ctx, float sw, float sh) { + float proj[16] = {0}; + proj[0] = 2.0f / sw; proj[5] = -2.0f / sh; + proj[10] = 1.0f; proj[12] = -1.0f; proj[13] = 1.0f; proj[15] = 1.0f; + ctx->lpVtbl->UpdateSubresource(ctx, (ID3D11Resource*)g_ui_cb, 0, NULL, proj, 0, 0); +} - if (cmd && cmd[0]) { load_ly(cmd); } - else { init_default_scene(); } - console_add("lity3d Editor ready"); - console_add("Ctrl+S save .ly | Ctrl+O load .ly | Esc quit"); +static void ui_setup_solid(ID3D11DeviceContext* ctx) { + ctx->lpVtbl->VSSetShader(ctx, g_ui_vs, NULL, 0); + ctx->lpVtbl->PSSetShader(ctx, g_ui_ps, NULL, 0); + ctx->lpVtbl->IASetInputLayout(ctx, g_ui_layout); + ctx->lpVtbl->VSSetConstantBuffers(ctx, 0, 1, &g_ui_cb); + ctx->lpVtbl->OMSetBlendState(ctx, NULL, NULL, 0xFFFFFFFF); +} - engine_set_render_callback(engine, on_render); - engine_set_key_callback(engine, on_key); - window_set_mouse_move_callback(engine->window, on_mouse_move); - window_set_mouse_button_callback(engine->window, on_mouse_button); - engine_run(engine); +static void ui_setup_text(ID3D11DeviceContext* ctx) { + ctx->lpVtbl->VSSetShader(ctx, g_text_vs, NULL, 0); + ctx->lpVtbl->PSSetShader(ctx, g_text_ps, NULL, 0); + ctx->lpVtbl->IASetInputLayout(ctx, g_text_layout); + ctx->lpVtbl->VSSetConstantBuffers(ctx, 0, 1, &g_ui_cb); + ctx->lpVtbl->PSSetShaderResources(ctx, 0, 1, &g_atlas.srv); + ctx->lpVtbl->PSSetSamplers(ctx, 0, 1, &g_ui_sampler); + ctx->lpVtbl->OMSetBlendState(ctx, g_ui_blend, NULL, 0xFFFFFFFF); +} - if(g_tex_layout)g_tex_layout->lpVtbl->Release(g_tex_layout); - if(g_tex_ps)g_tex_ps->lpVtbl->Release(g_tex_ps); - if(g_tex_vs)g_tex_vs->lpVtbl->Release(g_tex_vs); - if(g_layout)g_layout->lpVtbl->Release(g_layout); - if(g_ps)g_ps->lpVtbl->Release(g_ps); - if(g_vs)g_vs->lpVtbl->Release(g_vs); - if(g_cb)g_cb->lpVtbl->Release(g_cb); - if(g_sampler)g_sampler->lpVtbl->Release(g_sampler); - if(g_alpha_blend)g_alpha_blend->lpVtbl->Release(g_alpha_blend); - if(g_no_cull)g_no_cull->lpVtbl->Release(g_no_cull); - if(g_no_depth)g_no_depth->lpVtbl->Release(g_no_depth); - glyph_atlas_destroy(&g_atlas); - graphics_device_destroy(g_dev); engine_shutdown(engine); +static void ui_begin(ID3D11DeviceContext* ctx, float sw, float sh) { + D3D11_VIEWPORT vp = {0}; + vp.Width = sw; vp.Height = sh; vp.MaxDepth = 1.0f; + ctx->lpVtbl->RSSetViewports(ctx, 1, &vp); + ctx->lpVtbl->RSSetState(ctx, g_ui_raster); + ctx->lpVtbl->OMSetDepthStencilState(ctx, g_ui_depth, 0); + ctx->lpVtbl->IASetPrimitiveTopology(ctx, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + ui_set_projection(ctx, sw, sh); + ui_setup_solid(ctx); +} + +static void draw_quad(ID3D11DeviceContext* ctx, float x, float y, float w, float h, + float r, float g, float b, float a) { + UIVertex v[4] = { + {{x, y, 0},{0,0,-1},{0,0},{r,g,b,a}}, + {{x+w, y, 0},{0,0,-1},{1,0},{r,g,b,a}}, + {{x+w, y+h, 0},{0,0,-1},{1,1},{r,g,b,a}}, + {{x, y+h, 0},{0,0,-1},{0,1},{r,g,b,a}}, + }; + uint32_t idx[6] = {0,1,2, 0,2,3}; + ID3D11Buffer *vb = NULL, *ib = NULL; + D3D11_BUFFER_DESC bd = {0}; D3D11_SUBRESOURCE_DATA sd = {0}; + bd.ByteWidth = sizeof(UIVertex)*4; bd.Usage = D3D11_USAGE_DEFAULT; bd.BindFlags = D3D11_BIND_VERTEX_BUFFER; + sd.pSysMem = v; g_gdev->device->lpVtbl->CreateBuffer(g_gdev->device, &bd, &sd, &vb); + bd.ByteWidth = sizeof(uint32_t)*6; bd.BindFlags = D3D11_BIND_INDEX_BUFFER; + sd.pSysMem = idx; g_gdev->device->lpVtbl->CreateBuffer(g_gdev->device, &bd, &sd, &ib); + UINT stride = sizeof(UIVertex), 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, 6, 0, 0); + if (ib) ib->lpVtbl->Release(ib); + if (vb) vb->lpVtbl->Release(vb); +} + +static void draw_text(ID3D11DeviceContext* ctx, const wchar_t* text, int x, int y, + float r, float g, float b, float a) { + if (!g_atlas_ok) return; + ui_setup_text(ctx); + for (const wchar_t* p = text; *p; p++) { + float u0, v0, u1, v1, ax, ay; + if (!glyph_atlas_get_or_create(&g_atlas, g_gdev->device, ctx, *p, &u0, &v0, &u1, &v1, &ax, &ay)) continue; + UIVertex tv[4] = { + {{(float)x, (float)y, 0},{0,0,1},{u0,v0},{r,g,b,a}}, + {{(float)x + ax, (float)y, 0},{0,0,1},{u1,v0},{r,g,b,a}}, + {{(float)x + ax, (float)y + ay, 0},{0,0,1},{u1,v1},{r,g,b,a}}, + {{(float)x, (float)y + ay, 0},{0,0,1},{u0,v1},{r,g,b,a}}, + }; + uint32_t ti[6] = {0,1,2, 0,2,3}; + ID3D11Buffer *tvb = NULL, *tib = NULL; + D3D11_BUFFER_DESC bd = {0}; D3D11_SUBRESOURCE_DATA sd = {0}; + bd.ByteWidth = sizeof(UIVertex)*4; bd.Usage = D3D11_USAGE_DEFAULT; bd.BindFlags = D3D11_BIND_VERTEX_BUFFER; + sd.pSysMem = tv; g_gdev->device->lpVtbl->CreateBuffer(g_gdev->device, &bd, &sd, &tvb); + bd.ByteWidth = sizeof(uint32_t)*6; bd.BindFlags = D3D11_BIND_INDEX_BUFFER; + sd.pSysMem = ti; g_gdev->device->lpVtbl->CreateBuffer(g_gdev->device, &bd, &sd, &tib); + UINT stride = sizeof(UIVertex), offset = 0; + ctx->lpVtbl->IASetVertexBuffers(ctx, 0, 1, &tvb, &stride, &offset); + ctx->lpVtbl->IASetIndexBuffer(ctx, tib, DXGI_FORMAT_R32_UINT, 0); + ctx->lpVtbl->DrawIndexed(ctx, 6, 0, 0); + if (tib) tib->lpVtbl->Release(tib); + if (tvb) tvb->lpVtbl->Release(tvb); + x += (int)ax + 1; + } + ui_setup_solid(ctx); +} + +static void draw_text_a(ID3D11DeviceContext* ctx, const char* text, int x, int y, + float r, float g, float b, float a) { + wchar_t buf[256]; + int n = (int)strlen(text); if (n > 255) n = 255; + for (int i = 0; i < n; i++) buf[i] = (wchar_t)text[i]; + buf[n] = 0; + draw_text(ctx, buf, x, y, r, g, b, a); +} + +/* -------------------------------------------------------------------------- */ +/* Scene helpers */ +/* -------------------------------------------------------------------------- */ +static SceneNode* create_primitive(Scene* scene, SceneNode* parent, AssetManager* am, + ID3D11Device* dev, const char* name, MeshType type, + Vec3 pos, Vec3 rot, Vec3 scale, Material* mat) { + SceneNode* node = scene_create_node(scene, name); + if (!node) return NULL; + if (parent) scene_set_parent(node, parent); + node->position = pos; + node->scale = scale; + quat_from_euler(rot.x, rot.y, rot.z, &node->rotation); + + Asset* mesh_asset = asset_manager_load_mesh(am, dev, name); + if (!mesh_asset) { + const char* builtin = NULL; + if (type == MESH_CUBE) builtin = "cube"; + else if (type == MESH_SPHERE) builtin = "sphere"; + else if (type == MESH_PLANE) builtin = "plane"; + if (builtin) mesh_asset = asset_manager_load_mesh(am, dev, builtin); + } + if (mesh_asset && mat) { + MeshRenderer* mr = mesh_renderer_create(type, (Mesh*)asset_data(mesh_asset), mat); + scene_node_set_mesh_renderer(node, mr); + } + return node; +} + +static Scene* create_default_editor_scene(AssetManager* am, ID3D11Device* dev, Shader* shader) { + Scene* scene = (Scene*)malloc(sizeof(Scene)); + if (!scene) return NULL; + scene_init(scene); + strncpy(scene->root->name, "root", sizeof(scene->root->name) - 1); + + Material* mat_red = material_create(shader, NULL); + mat_red->color = (Vec4){1.0f, 0.3f, 0.2f, 1.0f}; + Material* mat_blue = material_create(shader, NULL); + mat_blue->color = (Vec4){0.2f, 0.5f, 1.0f, 1.0f}; + Material* mat_ground = material_create(shader, NULL); + mat_ground->color = (Vec4){0.3f, 0.3f, 0.35f, 1.0f}; + + create_primitive(scene, scene->root, am, dev, "cube", MESH_CUBE, + (Vec3){0,0,0}, (Vec3){0,0,0}, (Vec3){1,1,1}, mat_red); + create_primitive(scene, scene->root, am, dev, "sphere", MESH_SPHERE, + (Vec3){2.0f,0,0}, (Vec3){0,0,0}, (Vec3){0.8f,0.8f,0.8f}, mat_blue); + create_primitive(scene, scene->root, am, dev, "ground", MESH_PLANE, + (Vec3){0,-1.0f,0}, (Vec3){0,0,0}, (Vec3){1,1,1}, mat_ground); + + scene_update(scene); + return scene; +} + +/* -------------------------------------------------------------------------- */ +/* Editor UI */ +/* -------------------------------------------------------------------------- */ +static void draw_panel_bg(ID3D11DeviceContext* ctx, float sw, float sh) { + float body_h = sh - ED_MENU_H - ED_TOOLBAR_H - ED_BOTTOM_H; + + /* menu bar */ + draw_quad(ctx, 0, 0, sw, ED_MENU_H, 0.14f, 0.14f, 0.18f, 1.0f); + /* toolbar */ + draw_quad(ctx, 0, ED_MENU_H, sw, ED_TOOLBAR_H, 0.20f, 0.20f, 0.26f, 1.0f); + /* separators */ + draw_quad(ctx, 0, ED_MENU_H, sw, 1, 0.30f, 0.45f, 0.75f, 1.0f); + draw_quad(ctx, 0, ED_MENU_H + ED_TOOLBAR_H, sw, 1, 0.30f, 0.45f, 0.75f, 1.0f); + /* left panel */ + draw_quad(ctx, 0, ED_MENU_H + ED_TOOLBAR_H + 1, ED_LEFT_W, body_h, 0.18f, 0.18f, 0.23f, 1.0f); + draw_quad(ctx, ED_LEFT_W, ED_MENU_H + ED_TOOLBAR_H + 1, ED_SPLITTER, body_h, 0.30f, 0.45f, 0.75f, 1.0f); + /* right panel */ + draw_quad(ctx, sw - ED_RIGHT_W, ED_MENU_H + ED_TOOLBAR_H + 1, ED_RIGHT_W, body_h, 0.18f, 0.18f, 0.23f, 1.0f); + draw_quad(ctx, sw - ED_RIGHT_W - ED_SPLITTER, ED_MENU_H + ED_TOOLBAR_H + 1, ED_SPLITTER, body_h, 0.30f, 0.45f, 0.75f, 1.0f); + /* bottom console */ + draw_quad(ctx, 0, sh - ED_BOTTOM_H - ED_SPLITTER, sw, ED_SPLITTER, 0.30f, 0.45f, 0.75f, 1.0f); + draw_quad(ctx, 0, sh - ED_BOTTOM_H, sw, ED_BOTTOM_H, 0.16f, 0.16f, 0.21f, 1.0f); + /* status bar */ + draw_quad(ctx, 0, sh - 22, sw, 22, 0.20f, 0.22f, 0.32f, 1.0f); +} + +static void draw_hierarchy(ID3D11DeviceContext* ctx, float sh) { + (void)sh; + int y = ED_MENU_H + ED_TOOLBAR_H + 28; + draw_text(ctx, L"\u573a\u666f\u5c42\u7ea7", 12, y - 20, 0.5f, 0.75f, 1.0f, 1.0f); + if (!g_scene) return; + + for (int i = 1; i < g_scene->node_count; i++) { + SceneNode* node = &g_scene->nodes[i]; + if (node->id < 0) continue; + + int row_y = y + (i - 1) * 22; + if (node == g_selected) + draw_quad(ctx, 4, (float)row_y - 2, ED_LEFT_W - 8, 22, 0.25f, 0.38f, 0.65f, 1.0f); + + wchar_t wn[64]; + int len = (int)strlen(node->name); if (len > 63) len = 63; + for (int j = 0; j < len; j++) wn[j] = (wchar_t)node->name[j]; + wn[len] = 0; + draw_text(ctx, wn, 16, row_y, 1.0f, 1.0f, 1.0f, 1.0f); + } +} + +static void draw_inspector(ID3D11DeviceContext* ctx, float sw, float sh) { + (void)sh; + int x = (int)(sw - ED_RIGHT_W + 12); + int y = ED_MENU_H + ED_TOOLBAR_H + 28; + draw_text(ctx, L"\u5c5e\u6027", x, y - 20, 0.5f, 0.75f, 1.0f, 1.0f); + if (!g_selected) { + draw_text_a(ctx, "未选择对象", x, y, 0.7f, 0.7f, 0.75f, 1.0f); + return; + } + + char buf[128]; + int iy = y; + snprintf(buf, sizeof(buf), "名称: %s", g_selected->name); draw_text_a(ctx, buf, x, iy, 1.0f, 1.0f, 1.0f, 1.0f); iy += 24; + + float rx, ry, rz; + quat_to_euler(&g_selected->rotation, &rx, &ry, &rz); + snprintf(buf, sizeof(buf), "位置: %.2f %.2f %.2f", g_selected->position.x, g_selected->position.y, g_selected->position.z); + draw_text_a(ctx, buf, x, iy, 0.85f, 0.85f, 0.88f, 1.0f); iy += 22; + snprintf(buf, sizeof(buf), "旋转: %.1f %.1f %.1f", rx * 57.2958f, ry * 57.2958f, rz * 57.2958f); + draw_text_a(ctx, buf, x, iy, 0.85f, 0.85f, 0.88f, 1.0f); iy += 22; + snprintf(buf, sizeof(buf), "缩放: %.2f %.2f %.2f", g_selected->scale.x, g_selected->scale.y, g_selected->scale.z); + draw_text_a(ctx, buf, x, iy, 0.85f, 0.85f, 0.88f, 1.0f); iy += 30; + + draw_text_a(ctx, "WASD 平移 | QE 升降", x, iy, 0.6f, 0.7f, 0.85f, 1.0f); iy += 20; + draw_text_a(ctx, "方向键 旋转 | +/- 缩放", x, iy, 0.6f, 0.7f, 0.85f, 1.0f); +} + +static void draw_console(ID3D11DeviceContext* ctx, float sh) { + int y = (int)(sh - ED_BOTTOM_H + 24); + draw_text(ctx, L"\u63a7\u5236\u53f0", 12, y - 18, 0.5f, 0.75f, 1.0f, 1.0f); + int cy = y; + for (int i = g_console_count - 1; i >= 0 && i >= g_console_count - 6; i--) { + wchar_t wl[256]; + int len = (int)strlen(g_console[i]); if (len > 255) len = 255; + for (int j = 0; j < len; j++) wl[j] = (wchar_t)g_console[i][j]; + wl[len] = 0; + draw_text(ctx, wl, 12, cy, 0.75f, 0.75f, 0.80f, 1.0f); + cy += 20; + } +} + +static void draw_ui(ID3D11DeviceContext* ctx, float sw, float sh) { + ui_begin(ctx, sw, sh); + draw_quad(ctx, 0, 0, sw, sh, 0.5f, 0, 0, 0.3f); /* debug overlay */ + draw_panel_bg(ctx, sw, sh); + + /* title / menus */ + draw_text(ctx, L"Lity3D Engine Editor", 12, 7, 0.6f, 0.8f, 1.0f, 1.0f); + const wchar_t* menus[] = {L"\u6587\u4ef6", L"\u7f16\u8f91", L"\u89c6\u56fe", L"\u6784\u5efa", L"\u5e2e\u52a9"}; + int mx = 160; + for (int i = 0; i < 5; i++) { draw_text(ctx, menus[i], mx, 8, 0.9f, 0.9f, 0.92f, 1.0f); mx += 70; } + + draw_hierarchy(ctx, sh); + draw_inspector(ctx, sw, sh); + draw_console(ctx, sh); + + draw_text_a(ctx, g_status, 12, (int)(sh - 18), 0.65f, 0.65f, 0.70f, 1.0f); +} + +/* -------------------------------------------------------------------------- */ +/* Input / interaction */ +/* -------------------------------------------------------------------------- */ +static void update_status(void) { + if (g_selected) { + snprintf(g_status, sizeof(g_status), + "%s | pos(%.2f,%.2f,%.2f) | FOV %.0f | Esc quit | Ctrl+S save", + g_selected->name, + g_selected->position.x, g_selected->position.y, g_selected->position.z, + g_camera.fov_y * 57.2958f); + } else { + snprintf(g_status, sizeof(g_status), "无选中对象 | FOV %.0f | Esc quit | Ctrl+S save", g_camera.fov_y * 57.2958f); + } +} + +static void process_hierarchy_click(int mx, int my) { + float body_top = ED_MENU_H + ED_TOOLBAR_H + 1; + float body_h = (float)g_gdev->height - ED_MENU_H - ED_TOOLBAR_H - ED_BOTTOM_H; + if (mx < 0 || mx > ED_LEFT_W || my < body_top || my > body_top + body_h) return; + + int list_y = ED_MENU_H + ED_TOOLBAR_H + 28; + int idx = (my - list_y + 2) / 22 + 1; + if (idx >= 1 && idx < g_scene->node_count) { + SceneNode* node = &g_scene->nodes[idx]; + if (node->id >= 0) { + g_selected = node; + char buf[128]; snprintf(buf, sizeof(buf), "选中: %s", node->name); + console_add(buf); + update_status(); + } + } +} + +static void on_mouse_move(Engine* engine, int x, int y) { + (void)engine; + g_mouse_x = x; g_mouse_y = y; + + if (g_camera_drag && g_mouse_down[1]) { + float dx = (float)(x - g_mouse_last_x); + float dy = (float)(y - g_mouse_last_y); + camera_rotate_yaw(&g_camera, dx * 0.005f); + camera_rotate_pitch(&g_camera, dy * 0.005f); + g_mouse_last_x = x; g_mouse_last_y = y; + } else if (g_mouse_down[1]) { + g_camera_drag = 1; + g_mouse_last_x = x; g_mouse_last_y = y; + } else { + g_camera_drag = 0; + } +} + +static void on_mouse_button(Engine* engine, int button, int pressed) { + (void)engine; + if (button >= 0 && button < 3) g_mouse_down[button] = pressed; + + if (button == 0 && pressed) { + process_hierarchy_click(g_mouse_x, g_mouse_y); + } +} + +static void on_key(Engine* engine, int key) { + if (key == VK_ESCAPE) { engine_request_quit(engine); return; } + + if (GetAsyncKeyState(VK_CONTROL) & 0x8000) { + if (key == 'S' || key == 's') { + if (scene_save(g_scene, "scene.txt")) { + console_add("已保存 scene.txt"); + } else { + console_add("保存 scene.txt 失败"); + } + return; + } + if (key == 'O' || key == 'o') { + Scene* new_scene = scene_load("scene.txt", g_gdev->device, (Shader*)asset_data(g_shader_asset)); + if (new_scene) { + scene_destroy_renderers(g_scene); + scene_destroy(g_scene); + free(g_scene); + g_scene = new_scene; + g_selected = NULL; + console_add("已加载 scene.txt"); + } else { + console_add("加载 scene.txt 失败"); + } + return; + } + } + + if (!g_selected) return; + + float speed = 0.1f; + if (GetAsyncKeyState(VK_SHIFT) & 0x8000) speed = 0.5f; + + Vec3 pos = g_selected->position; + switch (key) { + case 'W': case 'w': pos.z += speed; break; + case 'S': case 's': pos.z -= speed; break; + case 'A': case 'a': pos.x -= speed; break; + case 'D': case 'd': pos.x += speed; break; + case 'Q': case 'q': pos.y += speed; break; + case 'E': case 'e': pos.y -= speed; break; + default: break; + } + if (pos.x != g_selected->position.x || pos.y != g_selected->position.y || pos.z != g_selected->position.z) { + scene_set_position(g_selected, pos.x, pos.y, pos.z); + } + + float rx, ry, rz; + quat_to_euler(&g_selected->rotation, &rx, &ry, &rz); + int rot_changed = 0; + switch (key) { + case VK_LEFT: ry -= 0.05f; rot_changed = 1; break; + case VK_RIGHT: ry += 0.05f; rot_changed = 1; break; + case VK_UP: rx -= 0.05f; rot_changed = 1; break; + case VK_DOWN: rx += 0.05f; rot_changed = 1; break; + case VK_PRIOR: rz += 0.05f; rot_changed = 1; break; /* PageUp */ + case VK_NEXT: rz -= 0.05f; rot_changed = 1; break; /* PageDown */ + default: break; + } + if (rot_changed) scene_set_rotation_euler(g_selected, rx, ry, rz); + + Vec3 scale = g_selected->scale; + int scale_changed = 0; + switch (key) { + case VK_ADD: scale.x += 0.1f; scale.y += 0.1f; scale.z += 0.1f; scale_changed = 1; break; + case VK_SUBTRACT: scale.x -= 0.1f; scale.y -= 0.1f; scale.z -= 0.1f; scale_changed = 1; break; + default: break; + } + if (scale_changed) scene_set_scale(g_selected, scale.x, scale.y, scale.z); + + update_status(); +} + +static void on_resize(Engine* engine, int width, int height) { + (void)engine; + if (width > 0 && height > 0) { + renderer_resize(g_renderer, width, height); + g_camera.aspect = (float)width / (float)height; + g_camera.dirty = 1; + } +} + +/* -------------------------------------------------------------------------- */ +/* Render callback */ +/* -------------------------------------------------------------------------- */ +static void on_render(Engine* engine) { + (void)engine; + if (!g_renderer || !g_gdev) return; + + renderer_set_view(g_renderer, camera_get_view(&g_camera)); + renderer_set_projection(g_renderer, camera_get_projection(&g_camera)); + + renderer_begin_frame(g_renderer); + if (g_scene) { + scene_update(g_scene); + scene_render(g_scene, g_renderer); + } + + draw_ui(g_gdev->context, (float)g_gdev->width, (float)g_gdev->height); + + renderer_end_frame(g_renderer); + + if (engine->frame_count == 60) { + graphics_device_save_screenshot(g_gdev, "editor_screenshot.bmp"); + console_add("已保存 editor_screenshot.bmp"); + } +} + +static void on_update(Engine* engine, double dt) { + (void)engine; (void)dt; +} + +/* -------------------------------------------------------------------------- */ +/* Main */ +/* -------------------------------------------------------------------------- */ +int WINAPI WinMain(HINSTANCE hI, HINSTANCE hP, LPSTR cmd, int nS) { + (void)hI; (void)hP; (void)nS; + logger_init("engine.log"); + LOG_INFO("=== Lity3D Engine Editor ==="); + + EngineConfig cfg = engine_default_config(); + cfg.app_name = "Lity3D Engine Editor"; + cfg.window_width = 1440; + cfg.window_height = 900; + cfg.vsync = 1; + + g_engine = engine_create(); + if (!engine_init(g_engine, &cfg)) { + LOG_FATAL("Engine init failed"); + return -1; + } + + g_gdev = engine_get_graphics_device(g_engine); + g_renderer = engine_get_renderer(g_engine); + + g_assets = asset_manager_create(); + g_shader_asset = asset_manager_load_shader(g_assets, g_gdev->device, NULL, NULL); + if (!g_shader_asset) { + LOG_FATAL("Shader load failed"); + return -1; + } + Shader* default_shader = (Shader*)asset_data(g_shader_asset); + + g_scene = scene_load("scene.txt", g_gdev->device, default_shader); + if (!g_scene) { + LOG_INFO("Creating default editor scene"); + g_scene = create_default_editor_scene(g_assets, g_gdev->device, default_shader); + scene_save(g_scene, "scene.txt"); + } + + float aspect = (float)cfg.window_width / cfg.window_height; + g_camera = camera_perspective(1.0472f, aspect, 0.1f, 100.0f); + g_camera.position = (Vec3){0, 1.5f, -5.0f}; + g_camera.target = (Vec3){0, 0, 0}; + g_camera.dirty = 1; + + g_atlas_ok = glyph_atlas_init(&g_atlas, g_gdev->device); + if (!g_atlas_ok) LOG_WARN("GlyphAtlas init failed"); + + create_ui_states(g_gdev->device); + if (!compile_ui_shaders(g_gdev->device)) { + LOG_FATAL("UI shader compile failed"); + return -1; + } + + console_add("Lity3D Engine Editor ready"); + console_add("Ctrl+S 保存 | Ctrl+O 加载 | Esc 退出"); + console_add("左键点选层级,右键拖拽旋转视角"); + update_status(); + + engine_set_update_callback(g_engine, on_update); + engine_set_render_callback(g_engine, on_render); + engine_set_key_callback(g_engine, on_key); + engine_set_resize_callback(g_engine, on_resize); + engine_set_mouse_move_callback(g_engine, on_mouse_move); + engine_set_mouse_button_callback(g_engine, on_mouse_button); + + engine_run(g_engine); + + if (g_scene) { + scene_destroy_renderers(g_scene); + scene_destroy(g_scene); + free(g_scene); + } + asset_manager_destroy(g_assets); + + if (g_ui_sampler) g_ui_sampler->lpVtbl->Release(g_ui_sampler); + if (g_ui_blend) g_ui_blend->lpVtbl->Release(g_ui_blend); + if (g_ui_raster) g_ui_raster->lpVtbl->Release(g_ui_raster); + if (g_ui_depth) g_ui_depth->lpVtbl->Release(g_ui_depth); + if (g_ui_cb) g_ui_cb->lpVtbl->Release(g_ui_cb); + if (g_ui_ps) g_ui_ps->lpVtbl->Release(g_ui_ps); + if (g_ui_vs) g_ui_vs->lpVtbl->Release(g_ui_vs); + if (g_ui_layout) g_ui_layout->lpVtbl->Release(g_ui_layout); + if (g_atlas_ok) glyph_atlas_destroy(&g_atlas); + + engine_shutdown(g_engine); + logger_shutdown(); return 0; } diff --git a/Demo/main.c b/Demo/main.c index 5a4d9a2..992f01d 100644 --- a/Demo/main.c +++ b/Demo/main.c @@ -163,7 +163,7 @@ int main(int argc, char* argv[]) { (void)argc; (void)argv; EngineConfig config = engine_default_config(); - config.app_name = "MiMo Engine - Scene Demo"; + config.app_name = "Lity3D - Scene Demo"; config.vsync = 0; config.window_width = 1280; config.window_height = 720; diff --git a/Engine/Core/engine.c b/Engine/Core/engine.c index 23b998c..2a08bbb 100644 --- a/Engine/Core/engine.c +++ b/Engine/Core/engine.c @@ -68,7 +68,7 @@ int engine_init(Engine* engine, const EngineConfig* config) { // 初始化日志 logger_init("engine.log"); - LOG_INFO("Initializing MiMo Engine ASM..."); + LOG_INFO("Initializing Lity3D Engine..."); // 初始化计时器 timer_init(); @@ -124,7 +124,7 @@ int engine_init(Engine* engine, const EngineConfig* config) { engine->running = 1; engine->frame_count = 0; - LOG_INFO("MiMo Engine ASM initialized successfully."); + LOG_INFO("Lity3D Engine initialized successfully."); return 1; } @@ -184,7 +184,7 @@ void engine_run(Engine* engine) { void engine_shutdown(Engine* engine) { if (!engine->initialized) return; - LOG_INFO("Shutting down MiMo Engine ASM..."); + LOG_INFO("Shutting down Lity3D Engine..."); if (engine->renderer) { renderer_destroy(engine->renderer); diff --git a/Engine/Core/engine.h b/Engine/Core/engine.h index 2773158..5196776 100644 --- a/Engine/Core/engine.h +++ b/Engine/Core/engine.h @@ -37,7 +37,7 @@ typedef struct { // 初始化默认配置 static inline EngineConfig engine_default_config(void) { EngineConfig config; - config.app_name = "MiMo Engine ASM"; + config.app_name = "Lity3D Engine"; config.window_width = 1280; config.window_height = 720; config.fullscreen = 0; diff --git a/Engine/Core/logger.c b/Engine/Core/logger.c index ff3857e..f89f7a3 100644 --- a/Engine/Core/logger.c +++ b/Engine/Core/logger.c @@ -19,11 +19,11 @@ void logger_init(const char* log_file) { if (log_file) { g_log_file = fopen(log_file, "w"); if (g_log_file) { - fprintf(g_log_file, "=== MiMo Engine ASM Log ===\n"); + fprintf(g_log_file, "=== Lity3D Engine Log ===\n"); fflush(g_log_file); } } - printf("=== MiMo Engine ASM Log ===\n"); + printf("=== Lity3D Engine Log ===\n"); } void logger_shutdown(void) { diff --git a/Engine/Editor/editor.c b/Engine/Editor/editor.c index 8bf12e9..3811221 100644 --- a/Engine/Editor/editor.c +++ b/Engine/Editor/editor.c @@ -59,7 +59,7 @@ void editor_render(Editor* ed) { uilayer_flush(&ed->ui, ctx); float sw2 = sw, sh2 = sh; - bitmap_font_draw(&ed->font, ctx, "MiMo Engine Editor", 10, 6, + bitmap_font_draw(&ed->font, ctx, "Lity3D Engine Editor", 10, 6, 0.4f, 0.75f, 1.0f, 1.0f, sw2, sh2); const char* menu[] = {"File", "Edit", "View", "Build", "Help"}; diff --git a/Engine/Rendering/camera.c b/Engine/Rendering/camera.c index 42213b2..285cfcd 100644 --- a/Engine/Rendering/camera.c +++ b/Engine/Rendering/camera.c @@ -72,7 +72,7 @@ void camera_move_right(Camera* camera, float distance) { Vec3 forward, right; vec3_sub(&camera->target, &camera->position, &forward); vec3_normalize(&forward, &forward); - vec3_cross(&forward, &camera->up, &right); + vec3_cross(&camera->up, &forward, &right); vec3_normalize(&right, &right); Vec3 move; vec3_scale(&right, distance, &move); diff --git a/Engine/Rendering/renderer.c b/Engine/Rendering/renderer.c index 34ce8cf..9504ab2 100644 --- a/Engine/Rendering/renderer.c +++ b/Engine/Rendering/renderer.c @@ -1,4 +1,5 @@ #include "renderer.h" +#include "../Core/logger.h" #include #include @@ -22,6 +23,8 @@ Renderer* renderer_create(GraphicsDevice* device) { r->light_dir = (Vec3){0.5f, -1.0f, 0.3f}; r->light_color = (Vec4){1,1,1,1}; r->ambient_color = (Vec4){0.2f,0.2f,0.3f,1}; + r->clear_color[0] = 0.1f; r->clear_color[1] = 0.1f; + r->clear_color[2] = 0.15f; r->clear_color[3] = 1.0f; return r; } @@ -29,7 +32,7 @@ void renderer_destroy(Renderer* r) { free(r); } void renderer_begin_frame(Renderer* r) { ID3D11DeviceContext* ctx = r->device->context; - graphics_device_clear(r->device, 0.1f, 0.1f, 0.15f, 1.0f); + graphics_device_clear(r->device, r->clear_color[0], r->clear_color[1], r->clear_color[2], r->clear_color[3]); D3D11_VIEWPORT vp = {0}; vp.Width = (float)r->device->width; vp.Height = (float)r->device->height; @@ -43,17 +46,15 @@ void renderer_end_frame(Renderer* r) { } void renderer_draw_mesh(Renderer* r, Mesh* m) { - if (!m) return; + if (!r || !m || m->icount == 0) return; + if (!m->vb) { LOG_ERROR("renderer_draw_mesh: null vertex buffer"); return; } + if (!m->ib) { LOG_ERROR("renderer_draw_mesh: null index buffer"); return; } ID3D11DeviceContext* ctx = r->device->context; UINT stride = sizeof(Vertex); UINT offset = 0; ctx->lpVtbl->IASetVertexBuffers(ctx, 0, 1, &m->vb, &stride, &offset); - if (m->ib) { - ctx->lpVtbl->IASetIndexBuffer(ctx, m->ib, DXGI_FORMAT_R32_UINT, 0); - ctx->lpVtbl->DrawIndexed(ctx, m->icount, 0, 0); - } else { - ctx->lpVtbl->Draw(ctx, m->vcount, 0); - } + ctx->lpVtbl->IASetIndexBuffer(ctx, m->ib, DXGI_FORMAT_R32_UINT, 0); + ctx->lpVtbl->DrawIndexed(ctx, m->icount, 0, 0); } void renderer_draw_mesh_with_shader(Renderer* r, Mesh* m, Shader* s, const Mat4* world, Texture* t) { @@ -98,8 +99,18 @@ void renderer_draw_mesh_with_material(Renderer* r, Mesh* m, Material* mat, const void renderer_set_view(Renderer* r, const Mat4* v) { r->view = *v; } void renderer_set_projection(Renderer* r, const Mat4* p) { r->projection = *p; } void renderer_set_light(Renderer* r, Vec3 d, Vec4 c, Vec4 a) { r->light_dir=d; r->light_color=c; r->ambient_color=a; } +void renderer_set_clear_color(Renderer* r, float rc, float g, float b, float a) { + if (!r) return; + r->clear_color[0] = rc; r->clear_color[1] = g; + r->clear_color[2] = b; r->clear_color[3] = a; +} GraphicsDevice* renderer_get_device(Renderer* r) { return r ? r->device : NULL; } +void renderer_get_view_projection(const Renderer* r, Mat4* out) { + if (!r || !out) return; + mat4_multiply(&r->view, &r->projection, out); +} + void renderer_resize(Renderer* r, int width, int height) { if (r && r->device && width > 0 && height > 0) { graphics_device_resize(r->device, width, height); diff --git a/Engine/Rendering/renderer.h b/Engine/Rendering/renderer.h index 4435218..37fad16 100644 --- a/Engine/Rendering/renderer.h +++ b/Engine/Rendering/renderer.h @@ -17,6 +17,7 @@ struct Renderer { Vec3 light_dir; Vec4 light_color; Vec4 ambient_color; + float clear_color[4]; }; Renderer* renderer_create(GraphicsDevice* device); @@ -29,5 +30,7 @@ void renderer_draw_mesh_with_material(Renderer* renderer, Mesh* mesh, Material* void renderer_set_view(Renderer* renderer, const Mat4* view); void renderer_set_projection(Renderer* renderer, const Mat4* projection); void renderer_set_light(Renderer* renderer, Vec3 dir, Vec4 color, Vec4 ambient); +void renderer_set_clear_color(Renderer* renderer, float r, float g, float b, float a); GraphicsDevice* renderer_get_device(Renderer* renderer); void renderer_resize(Renderer* renderer, int width, int height); +void renderer_get_view_projection(const Renderer* renderer, Mat4* out); diff --git a/Engine/Window/window.c b/Engine/Window/window.c index e2e4444..4cdfc94 100644 --- a/Engine/Window/window.c +++ b/Engine/Window/window.c @@ -8,7 +8,7 @@ #include // 窗口类名 -static const wchar_t* WINDOW_CLASS = L"MiMoEngineWindow"; +static const wchar_t* WINDOW_CLASS = L"Lity3DEngineWindow"; // 全局回调 static WindowKeyCallback g_key_callback = NULL; @@ -58,22 +58,28 @@ static LRESULT CALLBACK window_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM l return 0; case WM_LBUTTONDOWN: + SetCapture(hwnd); if (g_mouse_button_callback) g_mouse_button_callback(0, 1); return 0; case WM_RBUTTONDOWN: + SetCapture(hwnd); if (g_mouse_button_callback) g_mouse_button_callback(1, 1); return 0; case WM_MBUTTONDOWN: + SetCapture(hwnd); if (g_mouse_button_callback) g_mouse_button_callback(2, 1); return 0; case WM_LBUTTONUP: + if (GetCapture() == hwnd) ReleaseCapture(); if (g_mouse_button_callback) g_mouse_button_callback(0, 0); return 0; case WM_RBUTTONUP: + if (GetCapture() == hwnd) ReleaseCapture(); if (g_mouse_button_callback) g_mouse_button_callback(1, 0); return 0; case WM_MBUTTONUP: + if (GetCapture() == hwnd) ReleaseCapture(); if (g_mouse_button_callback) g_mouse_button_callback(2, 0); return 0; diff --git a/build.bat b/build.bat index 49b44ef..0085ee1 100644 --- a/build.bat +++ b/build.bat @@ -9,12 +9,12 @@ set GXX=%MINGW%\g++.exe set ENGINE_DIR=Engine set DEMO_DIR=Demo -set OUTPUT=MiMoEngine_ASM.exe +set OUTPUT=Lity3D.exe set CFLAGS=-O2 -Wall -Wextra -DWIN32_LEAN_AND_MEAN -D_CRT_SECURE_NO_WARNINGS -DMATH_ASM_AVAILABLE=0 -I%ENGINE_DIR% -I%ENGINE_DIR%\include set LDFLAGS=-ld3d11 -ldxgi -ld3dcompiler -lole32 -loleaut32 -luuid -lgdi32 -luser32 -lkernel32 -lwinmm -lxinput1_4 -lwindowscodecs -static -echo === MiMoEngine ASM Build === +echo === Lity3DEngine ASM Build === echo Compiler: %GCC% REM 创建输出目录并清理旧对象 @@ -30,11 +30,15 @@ echo [1/3] Compiling Engine sources... %GCC% %CFLAGS% -c %ENGINE_DIR%\Window\window.c -o build\window.o %GCC% %CFLAGS% -c %ENGINE_DIR%\Rendering\graphics_device.c -o build\graphics_device.o %GCC% %CFLAGS% -c %ENGINE_DIR%\Rendering\renderer.c -o build\renderer.o +%GCC% %CFLAGS% -c %ENGINE_DIR%\Rendering\frustum.c -o build\frustum.o %GCC% %CFLAGS% -c %ENGINE_DIR%\Rendering\shader.c -o build\shader.o %GCC% %CFLAGS% -c %ENGINE_DIR%\Rendering\mesh.c -o build\mesh.o %GCC% %CFLAGS% -c %ENGINE_DIR%\Rendering\texture.c -o build\texture.o %GCC% %CFLAGS% -c %ENGINE_DIR%\Rendering\material.c -o build\material.o %GCC% %CFLAGS% -c %ENGINE_DIR%\Rendering\camera.c -o build\camera.o +%GCC% %CFLAGS% -c %ENGINE_DIR%\Rendering\camera_controller.c -o build\camera_controller.o +%GCC% %CFLAGS% -c %ENGINE_DIR%\Terrain\terrain.c -o build\terrain.o +%GCC% %CFLAGS% -c %ENGINE_DIR%\Terrain\terrain_manager.c -o build\terrain_manager.o %GCC% %CFLAGS% -c %ENGINE_DIR%\ECS\world.c -o build\world.o %GCC% %CFLAGS% -c %ENGINE_DIR%\Input\input.c -o build\input.o %GCC% %CFLAGS% -c %ENGINE_DIR%\Physics\physics.c -o build\physics.o @@ -57,35 +61,49 @@ echo [2/4] Compiling VisualScript... %GCC% %CFLAGS% -c %ENGINE_DIR%\VisualScript\block_serializer.c -o build\block_serializer.o %GCC% %CFLAGS% -c %ENGINE_DIR%\VisualScript\block_editor.c -o build\block_editor.o -REM 编译 Editor 模块 -echo [3/4] Compiling Editor... -%GCC% %CFLAGS% -c %ENGINE_DIR%\Editor\glyph_atlas.c -o build\glyph_atlas.o - REM 编译 Demo -echo [4/4] Compiling Demo... +echo [3/3] Compiling Demo... %GCC% %CFLAGS% -c %DEMO_DIR%\main.c -o build\main.o %GCC% %CFLAGS% -c %DEMO_DIR%\audio_demo.c -o build\audio_demo.o -%GCC% %CFLAGS% -c %DEMO_DIR%\editor_main.c -o build\editor_main.o +%GCC% %CFLAGS% -c %DEMO_DIR%\open_world_demo.c -o build\open_world_demo.o REM 链接主程序 echo Linking main... -%GXX% build\engine.o build\logger.o build\timer.o build\asset_manager.o build\window.o build\graphics_device.o build\renderer.o build\shader.o build\mesh.o build\texture.o build\material.o build\camera.o build\world.o build\input.o build\physics.o build\audio.o build\ui.o build\lua_engine.o build\scene_graph.o build\scene_render.o build\scene_serialize.o build\block_core.o build\block_types.o build\block_workspace.o build\block_interaction.o build\block_renderer.o build\block_palette.o build\block_executor.o build\block_serializer.o build\block_editor.o build\glyph_atlas.o build\main.o -o build\%OUTPUT% %LDFLAGS% +%GXX% build\engine.o build\logger.o build\timer.o build\asset_manager.o build\window.o build\graphics_device.o build\renderer.o build\frustum.o build\shader.o build\mesh.o build\texture.o build\material.o build\camera.o build\camera_controller.o build\terrain.o build\terrain_manager.o build\world.o build\input.o build\physics.o build\audio.o build\ui.o build\lua_engine.o build\scene_graph.o build\scene_render.o build\scene_serialize.o build\block_core.o build\block_types.o build\block_workspace.o build\block_interaction.o build\block_renderer.o build\block_palette.o build\block_executor.o build\block_serializer.o build\block_editor.o build\main.o -o build\%OUTPUT% %LDFLAGS% REM 链接音频演示 echo Linking audio_demo... -%GXX% build\engine.o build\logger.o build\timer.o build\asset_manager.o build\window.o build\graphics_device.o build\renderer.o build\shader.o build\mesh.o build\texture.o build\material.o build\camera.o build\world.o build\input.o build\physics.o build\audio.o build\ui.o build\lua_engine.o build\scene_graph.o build\scene_render.o build\scene_serialize.o build\block_core.o build\block_types.o build\block_workspace.o build\block_interaction.o build\block_renderer.o build\block_palette.o build\block_executor.o build\block_serializer.o build\block_editor.o build\glyph_atlas.o build\audio_demo.o -o build\audio_demo.exe %LDFLAGS% +%GXX% build\engine.o build\logger.o build\timer.o build\asset_manager.o build\window.o build\graphics_device.o build\renderer.o build\frustum.o build\shader.o build\mesh.o build\texture.o build\material.o build\camera.o build\camera_controller.o build\terrain.o build\terrain_manager.o build\world.o build\input.o build\physics.o build\audio.o build\ui.o build\lua_engine.o build\scene_graph.o build\scene_render.o build\scene_serialize.o build\block_core.o build\block_types.o build\block_workspace.o build\block_interaction.o build\block_renderer.o build\block_palette.o build\block_executor.o build\block_serializer.o build\block_editor.o build\audio_demo.o -o build\audio_demo.exe %LDFLAGS% -REM 链接编辑器 -echo Linking editor... -%GXX% build\engine.o build\logger.o build\timer.o build\asset_manager.o build\window.o build\graphics_device.o build\renderer.o build\shader.o build\mesh.o build\texture.o build\material.o build\camera.o build\world.o build\input.o build\physics.o build\audio.o build\ui.o build\lua_engine.o build\scene_graph.o build\scene_render.o build\scene_serialize.o build\block_core.o build\block_types.o build\block_workspace.o build\block_interaction.o build\block_renderer.o build\block_palette.o build\block_executor.o build\block_serializer.o build\block_editor.o build\glyph_atlas.o build\editor_main.o -o build\editor.exe %LDFLAGS% -mwindows +REM 链接开放世界演示 +echo Linking open_world_demo... +%GXX% build\engine.o build\logger.o build\timer.o build\asset_manager.o build\window.o build\graphics_device.o build\renderer.o build\frustum.o build\shader.o build\mesh.o build\texture.o build\material.o build\camera.o build\camera_controller.o build\terrain.o build\terrain_manager.o build\world.o build\input.o build\physics.o build\audio.o build\ui.o build\lua_engine.o build\scene_graph.o build\scene_render.o build\scene_serialize.o build\block_core.o build\block_types.o build\block_workspace.o build\block_interaction.o build\block_renderer.o build\block_palette.o build\block_executor.o build\block_serializer.o build\block_editor.o build\open_world_demo.o -o build\open_world_demo.exe %LDFLAGS% + +REM 编译 C# 编辑器 +echo Building C# editor... +dotnet build EditorCS\Lity3DEditor.csproj -c Release -o build if %ERRORLEVEL% EQU 0 ( echo. echo === Build succeeded! === echo Output: build\%OUTPUT% echo Audio Demo: build\audio_demo.exe + echo Open World Demo: build\open_world_demo.exe + echo Editor: build\editor.exe echo. - echo Run with: build\%OUTPUT% or build\audio_demo.exe + echo Run with: build\%OUTPUT%, build\audio_demo.exe, build\open_world_demo.exe, or build\editor.exe + + REM 清理中间文件,保留可分发产物 + del /Q build\*.o 2>nul + del /Q build\libEngine.a 2>nul + del /Q build\engine.log 2>nul + del /Q build\screenshot*.bmp 2>nul + rmdir /S /Q build\CMakeFiles 2>nul + del /Q build\CMakeCache.txt 2>nul + del /Q build\Makefile 2>nul + del /Q build\cmake_install.cmake 2>nul + del /Q build\scene.txt 2>nul + del /Q build\scene_log.txt 2>nul ) else ( echo. echo === Build FAILED! ===