feat(rts-egui): pipeline 3D wgpu (scene pass) + fixes de codegen (gcell) + net nonblocking#1979
Conversation
…lex/…) A user 'class Transform' collided with the always-embedded node:stream Transform (Readable→Duplex→Transform→PassThrough): merge_programs appended prelude+user funcs without dedup, so BOTH __rtsn_ctor_Transform existed. Prune kept the prelude's (name matched the referenced class) but dropped its unused Duplex super, leaving the prelude ctor compiling a call to a pruned function (unknown function __rtsn_ctor_Duplex). Any name in an embedded shim chain (Transform/Duplex/Readable/Writable/PassThrough/…) was effectively reserved. Fix: in merge_programs drop every prelude func the user redefines, so the user's definition wins cleanly and prune reaches the real dependency set. Privacy gate (prelude_fns) now computed over SURVIVING prelude funcs — a user-shadowed name is not granted engine.* privacy. Suite: 724/731 files (2444/2452 tests) — at/above the documented 723/8 baseline; the 5 stream/fs failures pass individually (pre-existing full-suite flakiness). Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01BTUfYgP96N1MvfwtmWERMQ
…cell promotion) A top-level 'const NEAR = 0.05' (literal init) read inside a plain top-level 'function' bailed: 'closure captures NEAR which is not a simple local in scope'. Module-level bindings lower as locals of __rtsn_main; a sibling function has no closure env, so the by-value capture path (which only serves arrows) could not resolve them. module_globals gated literal-init reads out of gcell promotion (only non-literal 'runtime_init' reads promoted). Drop that gate: promote any top-level let/const READ free from a function. This is also JS-correct (closures observe later mutations via the shared cell), and a never-written literal const lands in immutable_gcells (read once at fn entry), so the cost is amortized. Top-level-only consts (never read from a function) stay off the path — plain user consts unaffected. Suite: 723/731 (2443/2452) = documented baseline; function_global's name=undefined is a pre-existing new-Function bug (fails identically on the pre-fix build), not a regression here. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01BTUfYgP96N1MvfwtmWERMQ
…h*/drawMesh Render 3D acelerado por GPU no backend wgpu, seguindo egui-ui-crate-design 1b (scene pass Clear+geometria ANTES do egui overlay Load, 1 encoder, 1 present — padrao custom3d_wgpu): - frame/scene3d.rs: Scene3D (pipeline WGSL vs/fs difuso, depth texture, uniform camera+luz, registry de meshes, instance buffer por frame). view_proj/model construidas em Rust casando a convencao da camera fly (yaw/pitch). Sem bytemuck/ wgpu-util (bytes via from_raw_parts + mapped_at_creation). - scene_api.rs: extern C do namespace egui — meshUpload/meshFree/setCamera/ setLight/drawMesh, tied ao handle da janela (NAO na trait neutra rts-render). - frame/gpu.rs: RenderState.scene: Option<Scene3D>; present_wgpu roda o scene pass antes do egui e o egui usa LoadOp::Load quando a cena limpou. - frame/mod.rs: CentralPanel vira transparente quando ha cena 3D (senao tapava o scene pass). glow: sem 3D (no-op), como manda o plano. - lib.rs: 5 membros no namespace egui. Resultado: solar system (18 obj) a 60fps (vsync), era ~35 no raster software. Culling desligado por ora (depth resolve; winding a acertar depois). Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01BTUfYgP96N1MvfwtmWERMQ
…s 3D Backface culling e da ENGINE (config do pipeline, nao do dev). O winding das meshes (CCW pra fora, geradas em gpu3d.ts) casa com a projecao left-handed — as faces de tras sao descartadas (metade do trabalho de fragmento a menos). O 'nada visivel' anterior era o CentralPanel opaco (ja corrigido), nao o culling. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01BTUfYgP96N1MvfwtmWERMQ
…cies) - Cam uniform ganha cam_pos (vec4); scene3d/scene_api passam a posicao da camera. - Fragment shader: alem do difuso, termo specular Blinn-Phong (half-vector, shininess 32, intensidade 0.35) -> brilho especular nas esferas/superficies. - Uniform 80 -> 96 bytes; VOut carrega a posicao de mundo p/ o view dir. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01BTUfYgP96N1MvfwtmWERMQ
…rais) - Pipeline de sky (triangulo fullscreen, sem depth write -> fica no fundo) desenhado antes das meshes no mesmo pass. - Fragment reconstroi o RAIO DE MUNDO por pixel (base da camera right/up/fwd + tangentes do FOV, passadas no uniform) -> gradiente por ray.y + estrelas via hash da direcao quantizada (esparsas, giram com a camera). - Cam uniform cresce p/ 144 bytes (add cam_right/up/fwd); view_proj retorna Cam3D com a base. Solar system agora num ceu estrelado a 60fps. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01BTUfYgP96N1MvfwtmWERMQ
- Luz vira PONTUAL: cam.light.xyz = POSICAO da luz (nao mais direcao); set_light guarda a posicao (sem normalizar). Fragment: lightDir = normalize(lightPos-world) -> lados dia/noite corretos (fases da lua etc). - Emissivo por objeto: instance ganha iparams (stride 80->96, @location 7); se emissive>0.5 a cor sai cheia sem sombreamento (ex.: o Sol brilha). - drawMesh ganha o arg emissive (i64); scene_api/lib.rs propagam. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01BTUfYgP96N1MvfwtmWERMQ
…hader 3D SOMBRAS: shadow pass depth-only renderiza a cena vista da luz numa depth texture 2048² (light_view_proj ortográfica); o fs amostra com comparison sampler + PCF 3×3 -> objetos projetam sombra uns nos outros e no chão. Uniform da câmera cresce pra 208 bytes (ganha light_vp mat4). group(1) = shadow_tex + sampler_comparison. Novo egui.setShadow(dir, center, radius) — radius<=0 desliga. TEXTURA: iparams.y por objeto (drawMesh ganha arg tex); fs aplica xadrez procedural em espaço de mundo quando tex>0 (chão quadriculado). Instance stride segue 96 (emissive=x, tex=y). Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01BTUfYgP96N1MvfwtmWERMQ
Lê window.inner_size()/scale_factor do UiCtx e devolve o tamanho LÓGICO (points) atual — segue o resize. Permite UI responsiva no lado TS (o motor não expunha o tamanho da janela a nenhum namespace até agora). Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01BTUfYgP96N1MvfwtmWERMQ
Base para servidores/harness que não podem travar no recv: marca listener/stream não-bloqueante; tcp_accept devolve 0 sem cliente e tcp_recv devolve -2 (distinto de 0=fechado, -1=erro) quando não há dados prontos — o loop pode renderizar entre polls. std::net por baixo (try_clone compartilha o socket, flag propaga). Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01BTUfYgP96N1MvfwtmWERMQ
Lajes finas, beiral de telhado e escala não-uniforme não 'vazam' mais ao serem vistos por trás — antes a face de trás era descartada e parecia transparente. Custo desprezível pros primitivos convexos; comportamento certo pra um editor. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01BTUfYgP96N1MvfwtmWERMQ
…ll global Bug: no top-level do main, um let/const cujo nome está no conjunto de globais promovidos NÃO criava Variable local — escrevia direto na célula global. Um let/const ANINHADO (em loop/if/bloco) que colidisse de nome com um top-level promovido era desviado pra MESMA gcell em vez de shadowar → um 'const x' no corpo de um while corrompia um 'x' global (vazava o valor da última iteração pra fora, e funções liam o valor errado). Fix: rastreia block_depth (lower_block incrementa; body do fn = depth 1, aninhado ≥2). O desvio pra gcell no is_main só vale em depth 1 (a declaração top-level real); aninhados viram locais frescos que shadowam (semântica JS correta). Repro validado: 'const x' num while já não corrompe o 'x' global (readX 300→7). Suíte TS: 723/731 arquivos, 2443/2452 testes — IDÊNTICO ao baseline (as 8 falhas são pré-existentes: Function.name, node shims). Zero regressão. Gate ok. NOTA: isto é um bug real e SEPARADO do heisenbug de render do editor (esse é uma corrupção de codegen sensível a layout no __rtsn_main gigante, contornado pelo function-wrap no rts-game — não resolvido por esta mudança). Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01BTUfYgP96N1MvfwtmWERMQ
…nostico removido) Investigacao do bug de render de .obj carregado terminou no lado TS (gpu3d). O scene3d/scene_api voltam ao estado commitado (prints de debug removidos).
…e-editor # Conflicts: # crates/rts-egui/src/frame/gpu.rs # crates/rts-egui/src/frame/mod.rs
Merge com origin/main feito — conflitos resolvidos, zero regressão medidaIntegrei os 36 commits do 2 conflitos, ambos em O codegen ( Regressão: nenhuma. Build completo compila (exit 0). Suíte TS local: 2443/2452 testes. As 8 falhas foram auditadas contra o baseline
|
…look-at NaN-safe, clearColor, near/far Ao conciliar os dois scene passes 3D paralelos (merge), a base é o nosso (shadow PCF/luz pontual/skybox/specular/emissivo/textura), mas as partes boas do gpu3d deles foram enxertadas no nosso, adaptadas à base left-handed: - egui.setCameraLookAt(eye,target,fov,aspect,near,far): câmera look-at NaN-safe (up alternativo ao olhar reto pra cima/baixo, em vez de gimbal-lock/NaN) — melhor pro "frame selected" do editor. near/far explícitos. - egui.setClearColor(r,g,b) + setSkybox(on): fundo CHAPADO desligando o skybox procedural — gap real (o viewport do editor quer fundo neutro, não starfield). - perspective_lh() compartilhado entre a câmera fly e a look-at. - 4 testes unitários do math 3D (projeção clip, base ortonormal, reto-pra-baixo sem NaN, translação pura) — validados via check rustc isolado (o harness de teste do crate não linka standalone: dep de símbolos do runtime, pré-existente). Suíte TS: 2444/2452 (724/731 arquivos) — zero regressão nova; os 7 restantes já falham idênticos no origin/main (cluster node/crypto pré-existente).
…gui.* após a conciliação do merge
Enxerto do bom do gpu3d (não descartei tudo do outro lado)Revisitei o
O doc Suíte TS: 2444/2452, zero regressão nova. |
Cross-runtime parity (RTS vs Bun vs Node)
Divergences detected
|
Root cause do badge 0% (23/07): o passo de instalar libasound2t64 flakeou no runner; sem libasound.so.2 (linkada por cpal) o binário rts nao carrega e TODOS os 679 fixtures viram __RUNTIME_ERROR__ → badge 0%. Nao era regressao do #1979: o binario Linux e byte-identico e passa 57/60 num ubuntu:24.04 limpo. - apt-get update/install com retry (3x) para tolerar hiccup de mirror. - Passo-guarda que roda o binario num smoke antes de medir; se lib faltar ou o rts nao iniciar, ABORTA o job (sem publicar badge 0% falso — o badge bom fica). Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01ToH9kabtTfwwS33bwqvsTa
O que tem aqui (13 commits)
Trabalho feito localmente enquanto eu construía o editor de jogos (rts-game) em cima do motor. Abro como branch/PR porque o
origin/maindivergiu (36 commits novos, incl. um scene3d paralelo) e um merge no main precisa de conciliação humana — ver aviso de conflito abaixo.rts-egui — pipeline 3D wgpu (scene pass)
351e9ec2pipeline 3D wgpu completo + 5 primitivos (egui.meshUpload/drawMesh/setCamera/setLight)5a7fb635specular Blinn-Phong6d360e50skybox procedural (gradiente + estrelas)4c324d21luz pontual + flag emissivo por objetof0eb61c6shadow map direcional (PCF) + textura procedural701a25a9egui.winWidth/winHeight(tamanho lógico vivo)ee259c82scene pass sem backface culling (cull_mode None) — necessário p/ meshes.objde winding inconsistentecodegen — 2 fixes reais de bug (com repro no editor)
41990a4anomes de classe/fn de usuário (Transform/Duplex/…) sombreiam shims do prelude (dedup em merge_programs)7b3727f7const/let de módulo lido dentro de função resolve (promoção a gcell)af57caaelet/const aninhado no__rtsn_mainnão aliasa mais a gcell global (fixblock_depth; zero regressão na suíte TS)net
287befe9tcp_set_nonblocking+ sentinela -2 (WouldBlock) notcp_recv— usado pelo controle WebSocket non-blocking do editorO
origin/mainjá tem um scene3d próprio no rts-egui (src/scene3d/math3d.rs,render_backend.rs) feito em paralelo. Esta branch temsrc/frame/scene3d.rs. Os dois precisam ser conciliados à mão antes de mergear. Overlap também emlower.rs(meu fix de gcell vs codegen deles),frame/gpu.rs,frame/mod.rs,lib.rs.Os fixes de codegen (gcell/prelude-shadow) e o
netnonblocking são independentes e provavelmente aplicam limpo — dá pra cherry-pickar separado se o scene3d for descartado em favor do de vocês.🤖 Generated with Claude Code