Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -501,9 +501,17 @@ user does.** In rough priority:
### 5.3 Engine features the editor is blocked on

- **Render-mesh-to-texture** (the obvious one): real thumbnails for models
and prefabs. The current render-target API is a per-frame override consumed
at end_frame — unusable mid-frame; needs either an immediate mode or a
dedicated `renderModelToTexture(model, camera, size)` call.
and prefabs. Two editor-side approaches are now DISPROVEN with screenshots
(2026-07-17, details in `src/ui/thumbnails.ts`): mid-frame texture mode
renders nothing (the override is per-frame), and dedicated whole frames
engage the pipeline (GI backend re-selects) but the resulting texture still
draws as nothing in the 2D layer — even a bare magenta clear never shows
through `drawTexturePro`. The engine work is now precisely scoped: a
self-contained `renderModelToTexture(model, camera, size)` pass plus a
golden test that round-trips a rendered texture through `drawTexturePro`
(which today has never sampled an RT texture successfully). The editor
keeps its category-colored cells until then; the dedicated-frame burst
scaffolding is in git history, ready to resurrect.
- **Text-input completeness**: ~~caret movement~~ DONE 2026-07-17 (click
places the caret, Left/Right/Home/End move it, Delete deletes forward,
typing inserts at the caret). Still engine-blocked: clipboard paste,
Expand Down
16 changes: 8 additions & 8 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ import { drawInspector } from './ui/layouts/inspector';
import { drawOutliner } from './ui/layouts/outliner';
import { drawRecentPanel } from './ui/layouts/recent-panel';
import { drawStatusBar } from './ui/layouts/status-bar';
import { pumpThumbnails } from './ui/thumbnails';
import { runThumbnailFrame } from './ui/thumbnails';
import { runSelfTests } from './tests/self-tests';

// ---- self-tests (headless) ---------------------------------------------------
Expand Down Expand Up @@ -151,6 +151,13 @@ let modelsPending = 1;
// ---- main loop -------------------------------------------------------------

while (!windowShouldClose()) {
// Thumbnail render frames are currently a no-op (see ui/thumbnails.ts for
// the two dead ends and the engine work they point to); the hook stays so
// the burst comes back the day the engine can render a model to a texture.
if (modelsPending === 0 && !state.playtesting && runThumbnailFrame(state)) {
continue;
}

const dt = getDeltaTime();

// Auto-save.
Expand Down Expand Up @@ -274,13 +281,6 @@ while (!windowShouldClose()) {
a: 255,
});

// Render missing asset thumbnails, one per frame, once models are in.
// Must run inside the frame but before the main 3D pass (it switches the
// render target and back).
if (modelsPending === 0 && !state.playtesting) {
pumpThumbnails(state, 1);
}

// ---- 3D viewport ---------------------------------------------------------

const cam3D = buildCamera3D(state.camera);
Expand Down
52 changes: 31 additions & 21 deletions src/ui/thumbnails.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,30 @@
// Asset-panel model thumbnails (PLAN §G) — render pass currently DISABLED.
// Asset-panel model thumbnails (PLAN §G) — render pass DISABLED, twice over.
// The asset panel draws category-colored cells instead (visible, clickable,
// labeled); getThumbnail below always returns null and the grid falls back.
//
// The first implementation called beginTextureMode/endTextureMode mid-frame,
// raylib-style. The engine's render targets don't work that way: the override
// set by begin_texture_mode is consumed at END_FRAME ("the next end_frame will
// render to this texture view instead of the surface" — renderer/mod.rs), and
// 2D draws batch for the frame. So the thumbnail textures stayed empty and the
// grid drew invisible images over dark panel — screenshot-verified 2026-07-16.
// What was tried, and what each attempt established (2026-07-16/17):
//
// Rendering a mesh into a texture on this engine needs either (a) a dedicated
// whole frame per thumbnail with the world's scene nodes hidden, or (b) a real
// engine-side render-mesh-to-texture utility. Until one of those exists, the
// asset panel draws colored placeholder cells (visible, clickable, labeled) —
// see asset-panel.ts. The API here stays so the grid lights up the day the
// engine call exists.

import { EditorState } from '../state/editor-state';
// 1. MID-FRAME beginTextureMode/endTextureMode, raylib-style: the engine's
// override is per-frame — begin_texture_mode arms it and only end_frame
// consumes it (renderer/mod.rs), so clearing it mid-frame renders nothing.
// Result: empty textures, invisible cells (screenshot-verified).
//
// 2. DEDICATED FRAMES: hide the world's scene nodes, draw one model, arm the
// override, endDrawing → the whole frame renders into the 128px target
// with no present. The frame pipeline demonstrably ENGAGES (the GI
// backend re-selects during the burst) and the world hide/unhide works —
// but the texture still draws as nothing in the 2D layer: even a bare
// magenta clearBackground never shows up when the texture is drawn via
// drawTexturePro (screenshot-verified). So either the compose pass does
// not write the RT the way begin_texture_mode's docs suggest, or 2D
// sampling of an RT texture is broken (bind group / alpha).
//
// Conclusion: this needs a focused ENGINE session — ideally a purpose-built
// `renderModelToTexture(model, camera, size)` that runs a self-contained
// simple pass, plus a golden test that round-trips a rendered texture
// through drawTexturePro. Editor-side scaffolding (dedicated-frame burst,
// world hide/unhide, framing camera) lives in git history at commit ab43000^
// ..HEAD and can be resurrected the day the engine call exists.

export const THUMB_SIZE = 128;

Expand All @@ -24,14 +34,14 @@ export interface ThumbnailEntry {
height: number;
}

// No-op while the render pass is disabled. Returns 0 = "nothing pending" so
// main.ts never waits on it.
export function pumpThumbnails(_state: EditorState, _maxPerFrame: number): number {
return 0;
import { EditorState } from '../state/editor-state';

// No-op while the render pass is disabled: nothing pending, ever.
export function runThumbnailFrame(_state: EditorState): boolean {
return false;
}

// Always null while the render pass is disabled — the asset panel then draws
// its colored placeholder cell.
// Always null — the asset panel then draws its colored placeholder cell.
export function getThumbnail(_relPath: string): ThumbnailEntry | null {
return null;
}