From 586792b774cceb5a9bb832fe76e8400be80874e0 Mon Sep 17 00:00:00 2001 From: tolelom <98kimsungmin@naver.com> Date: Wed, 25 Mar 2026 15:26:34 +0900 Subject: [PATCH] docs: add Phase 8-4 editor UI status, spec, and deferred items Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/DEFERRED.md | 10 + docs/STATUS.md | 19 +- .../specs/2026-03-25-phase8-4-editor.md | 215 ++++++++++++++++++ 3 files changed, 240 insertions(+), 4 deletions(-) create mode 100644 docs/superpowers/specs/2026-03-25-phase8-4-editor.md diff --git a/docs/DEFERRED.md b/docs/DEFERRED.md index 5548f6d..dbc1df0 100644 --- a/docs/DEFERRED.md +++ b/docs/DEFERRED.md @@ -62,6 +62,16 @@ - **raycast_all (다중 hit)** — 가장 가까운 hit만 반환. - **BVH 조기 종료 최적화** — 모든 리프 검사 후 최소 t 선택. front-to-back 순회 미구현. +## Phase 8-4 + +- **씬 뷰포트** — 3D 렌더러 임베드 미구현. +- **엔티티 인스펙터** — ECS 컴포넌트 편집 미구현. +- **에셋 브라우저** — 파일 시스템 탐색 미구현. +- **텍스트 입력** — 키보드 → 문자열 입력 미구현. +- **스크롤, 드래그앤드롭** — 미구현. +- **도킹, 탭, 윈도우 드래그** — 미구현. +- **TTF 폰트** — 비트맵 고정폭만. 가변 크기 미지원. + ## Phase 8-3 - **핫 리로드** — 파일 변경 감지 + Lua state 재로드 미구현. diff --git a/docs/STATUS.md b/docs/STATUS.md index da23c30..7dbae82 100644 --- a/docs/STATUS.md +++ b/docs/STATUS.md @@ -125,6 +125,14 @@ - voltex_ai: A* pathfinding on triangle graph (center-point path) - voltex_ai: Steering behaviors (seek, flee, arrive, wander, follow_path) +### Phase 8-4: Immediate Mode UI (Editor Foundation) +- voltex_editor: FontAtlas (8x12 비트맵 ASCII, 코드 생성) +- voltex_editor: DrawList (정점/인덱스/커맨드), DrawVertex (Unorm8x4 color) +- voltex_editor: UiContext (IMGUI 상태, hot/active, 커서 레이아웃) +- voltex_editor: Widgets (text, button, slider, checkbox, panel) +- voltex_editor: UiRenderer (wgpu 2D pipeline, alpha blending, orthographic) +- examples/editor_demo (IMGUI 위젯 데모) + ### Phase 8-3: Lua Scripting - voltex_script: Lua 5.4 내장 빌드 (cc crate) - voltex_script: Lua C API FFI 바인딩 @@ -151,10 +159,11 @@ crates/ ├── voltex_audio — AudioClip, WAV parser, mixing, WASAPI backend, AudioSystem, MixGroup, spatial ├── voltex_ai — NavMesh, A* pathfinding, steering behaviors ├── voltex_net — UDP packets, NetServer, NetClient -└── voltex_script — Lua 5.4 FFI, LuaState, scripting bindings +├── voltex_script — Lua 5.4 FFI, LuaState, scripting bindings +└── voltex_editor — IMGUI framework, UiRenderer, widgets ``` -## 테스트: 245개 전부 통과 +## 테스트: 255개 전부 통과 - voltex_asset: 14 - voltex_audio: 35 (audio_clip 2 + wav 5 + mixing 11 + audio_system 2 + spatial 8 + mix_group 7) @@ -165,9 +174,10 @@ crates/ - voltex_ai: 15 (navmesh 4 + pathfinding 5 + steering 6) - voltex_net: 8 (packet 7 + integration 1) - voltex_script: 9 (state 8 + bindings 1) +- voltex_editor: 10 (font 2 + draw_list 3 + widgets 3 + layout 1 + renderer 1) - voltex_renderer: 33 (20 + SSGI 3 + RT 3 + bloom 3 + tonemap 4) -## Examples (11개) +## Examples (12개) - triangle — Phase 1 삼각형 - model_viewer — OBJ 큐브 + Blinn-Phong @@ -180,8 +190,9 @@ crates/ - ibl_demo — Normal map + IBL - audio_demo — 사인파 오디오 재생 - deferred_demo — 디퍼드 렌더링 + 다중 포인트 라이트 +- editor_demo — IMGUI 위젯 데모 -## 다음: Phase 8-4 (에디터) — Stretch Goal +## 전체 완료! 스펙 참조: `docs/superpowers/specs/2026-03-24-voltex-engine-design.md` diff --git a/docs/superpowers/specs/2026-03-25-phase8-4-editor.md b/docs/superpowers/specs/2026-03-25-phase8-4-editor.md new file mode 100644 index 0000000..f8d9123 --- /dev/null +++ b/docs/superpowers/specs/2026-03-25-phase8-4-editor.md @@ -0,0 +1,215 @@ +# Phase 8-4: Immediate Mode UI — Design Spec + +## Overview + +`voltex_editor` crate를 신규 생성한다. Immediate Mode UI 프레임워크를 구현하여 에디터의 기반을 마련한다. + +## Scope + +- 비트맵 폰트 아틀라스 (8x12 고정폭 ASCII, 코드 생성) +- DrawList (정점/인덱스/커맨드 버퍼) +- UiContext (IMGUI 상태, hot/active 위젯) +- 위젯: text, button, slider, checkbox, begin_panel/end_panel +- 커서 기반 자동 레이아웃 +- wgpu UI 렌더 파이프라인 (2D, alpha blending) +- editor_demo 예제 + +## Out of Scope + +- 씬 뷰포트 (3D 임베드) +- 엔티티 인스펙터 / 에셋 브라우저 +- 텍스트 입력 (키보드 → 문자열) +- 스크롤, 드래그앤드롭 +- TTF 파싱 / 가변 크기 폰트 +- 도킹, 탭, 윈도우 드래그 + +## Module Structure + +``` +crates/voltex_editor/ +├── Cargo.toml +└── src/ + ├── lib.rs + ├── font.rs — FontAtlas (비트맵 생성 + GPU 텍스처) + ├── draw_list.rs — DrawVertex, DrawCommand, DrawList + ├── ui_context.rs — UiContext (IMGUI 상태) + ├── widgets.rs — text, button, slider, checkbox, panel + ├── layout.rs — 커서 기반 레이아웃 + └── renderer.rs — UI 렌더 파이프라인 (wgpu 셰이더) +``` + +## Dependencies + +- `voltex_math` — Vec2 +- `wgpu`, `bytemuck` — GPU 렌더링 + +## Types + +### FontAtlas + +```rust +pub struct FontAtlas { + pub width: u32, // 아틀라스 텍스처 너비 + pub height: u32, + pub glyph_width: u32, // 8 + pub glyph_height: u32, // 12 + pub pixels: Vec, // R8 grayscale +} +``` + +- `generate() -> Self` — 하드코딩된 8x12 비트맵 데이터로 ASCII 32~126 생성 +- `glyph_uv(ch: char) -> (f32, f32, f32, f32)` — (u0, v0, u1, v1) UV 좌표 + +아틀라스 레이아웃: 16열 x 6행 = 96 글리프. 텍스처 크기: 128x72 (16*8 x 6*12). + +### DrawVertex + +```rust +#[repr(C)] +#[derive(Copy, Clone, Pod, Zeroable)] +pub struct DrawVertex { + pub position: [f32; 2], + pub uv: [f32; 2], + pub color: [u8; 4], // RGBA +} +``` + +### DrawCommand + +```rust +pub struct DrawCommand { + pub index_offset: u32, + pub index_count: u32, + pub clip_rect: [f32; 4], // x, y, w, h (미사용, 추후) +} +``` + +### DrawList + +```rust +pub struct DrawList { + pub vertices: Vec, + pub indices: Vec, + pub commands: Vec, +} +``` + +- `clear()` — 매 프레임 리셋 +- `add_rect(x, y, w, h, color)` — 색상 사각형 +- `add_rect_uv(x, y, w, h, u0, v0, u1, v1, color)` — 텍스처 사각형 +- `add_text(font, text, x, y, color)` — 문자열 (글리프별 쿼드) + +### UiContext + +```rust +pub struct UiContext { + // Widget state + pub hot: Option, + pub active: Option, + + // Draw output + pub draw_list: DrawList, + + // Layout cursor + pub cursor_x: f32, + pub cursor_y: f32, + pub indent: f32, + pub line_height: f32, + + // Input (매 프레임 외부에서 설정) + pub mouse_x: f32, + pub mouse_y: f32, + pub mouse_down: bool, + pub mouse_clicked: bool, + pub mouse_released: bool, + + // Screen + pub screen_width: f32, + pub screen_height: f32, + + // Font + pub font: FontAtlas, + + // Internal + id_counter: u64, +} +``` + +- `new(screen_w, screen_h) -> Self` +- `begin_frame(mouse_x, mouse_y, mouse_down)` — 프레임 시작, draw_list 클리어 +- `end_frame()` — draw_list 확정 +- `gen_id() -> u64` — 위젯별 고유 ID (호출 순서 기반) + +### Widget Functions (UiContext methods) + +```rust +impl UiContext { + pub fn text(&mut self, text: &str) + pub fn button(&mut self, label: &str) -> bool + pub fn slider(&mut self, label: &str, value: f32, min: f32, max: f32) -> f32 + pub fn checkbox(&mut self, label: &str, checked: bool) -> bool + pub fn begin_panel(&mut self, title: &str, x: f32, y: f32, w: f32, h: f32) + pub fn end_panel(&mut self) +} +``` + +**button 로직:** +1. ID 생성 +2. 사각형 그리기 (배경색 = hot이면 밝게, active면 더 밝게) +3. 텍스트 그리기 +4. 마우스가 사각형 안이면 hot 설정 +5. hot + mouse_clicked이면 active 설정 +6. active + mouse_released이면 → true 반환 (클릭됨) + +**slider 로직:** +1. 배경 바 그리기 +2. 현재 값 위치에 핸들 그리기 +3. active이면 마우스 X로 값 업데이트 +4. 변경된 값 반환 + +### UI Render Pipeline + +```wgsl +// ui_shader.wgsl +struct UiUniform { + projection: mat4x4, // orthographic screen projection +}; + +@group(0) @binding(0) var ui: UiUniform; +@group(0) @binding(1) var t_atlas: texture_2d; +@group(0) @binding(2) var s_atlas: sampler; + +@vertex +fn vs_main(@location(0) pos: vec2, @location(1) uv: vec2, @location(2) color: vec4) -> ... { + // Transform by orthographic projection + // Pass UV and color +} + +@fragment +fn fs_main(...) -> @location(0) vec4 { + let tex = textureSample(t_atlas, s_atlas, uv); + return vec4(color.rgb * tex.r, color.a * tex.r); // font alpha from texture +} +``` + +프로젝션: `orthographic(0, screen_w, screen_h, 0, -1, 1)` — 좌상단 원점. + +비텍스처 사각형(배경, 버튼)은 UV=(0,0) 영역(아틀라스의 화이트 픽셀)을 사용하거나, 셰이더에서 UV=(0,0)일 때 색상만 사용. + +## Test Plan + +### font.rs +- generate(): 아틀라스 크기 확인 (128x72) +- glyph_uv('A'): UV 범위 확인 + +### draw_list.rs +- add_rect: 정점 4개 + 인덱스 6개 추가 +- add_text: 글자 수 * 4 정점 +- clear: 비어있음 + +### ui_context.rs +- button: mouse over → hot, click → returns true +- slider: value 변경 확인 + +### 통합 +- editor_demo 예제: 텍스트, 버튼, 슬라이더가 화면에 표시