feat(v2.1.0): MDL/GPU bridge, TPC fix, walkmesh click, specular/frustum/portal culling, save_are, +185 tests (2748 total)#13
Open
genspark-ai-developer[bot] wants to merge 3 commits into
Conversation
… FBO, LYT parser, render tests
Root cause: _perspective() in viewport_camera.py used OpenGL column-major
convention (proj[2][3]=-1, proj[3][2]=2fn/(n-f)) but was composed with
row-major numpy matrices. This produced w_clip≈0.044 instead of the
correct ≈22, mapping all room geometry to NDC values >400 — completely
outside the clip frustum and therefore invisible.
Fix (viewport_camera.py):
- Swap proj[2][3] and proj[3][2] to match row-major convention:
proj[3][2] = -1 (produces w_clip = -z_eye)
proj[2][3] = 2fn/(n-f) (produces correct z_clip)
- Expanded docstring explaining the convention and .T.tobytes() usage.
Fix (viewport_renderer.py):
- ensure_fbo(): replace simple_framebuffer() (colour-only) with a proper
RGBA8 + D24 framebuffer so DEPTH_TEST actually works during EGL rendering.
Without a depth renderbuffer the depth test is a no-op and all faces
overwrite each other producing a flat uniform colour.
- Remove _HAS_MDL guard from MDL load path (use try/import instead) so
headless scripts that import _EGLRenderer directly can still load MDL files.
- Add _depth_rbo / _color_rbo attributes; release them in release().
Fix (lyt_vis.py LYTParser):
- Handle beginlayout / donelayout block markers (GModular canonical format).
- Support 'room N resref x y z' lines both at top level and inside a
roomcount block, in addition to the classic 'resref x y z' format.
This fixes zero-room LYT parse results when loading mods written by
LYTWriter (which emits the GModular format).
Tests (tests/test_viewport_refactor.py):
- TestProjectionMatrixConvention: 7 tests verifying proj[3][2]==-1,
proj[2][3]==2fn/(n-f), w_clip formula, target-point visibility, and
all room-corner visibility.
- TestEGLRendering: 4 integration tests — mod loads with MDL/MDX,
LYT parser returns 1 room, w_clip≈distance, and full EGL render
produces >1% non-background pixels (72 000 pixels, 15% coverage).
Test data:
- tests/test_data/slem_ar.mod already contains slem_ar.mdl + slem_ar.mdx
(packed in a previous session).
- viewport_render_fixed.png: rendered proof image (800×600, 15% coverage).
Results: 2563 passed, 7 skipped in 8.90s (was 2378 passed before these changes).
genspark-ai-developer
Bot
force-pushed
the
genspark_ai_developer
branch
from
March 20, 2026 07:13
e09b825 to
a20ff6a
Compare
Study report (TEXTBOOK_STUDY_REPORT.md): - Eberly 3D Game Engine Design 2e: three-pass loop, portal rendering, Effect objects, LOD nodes, 16-bone palette validation - Varcholik RT3D Rendering DirectX+HLSL: row-vs-column major validated, DXT textures, TBN normal mapping, shadow mapping, instancing - Ericson Real-Time Collision Detection: AABB tree validated, frustum culling algorithm (Lengyel formula), Möller-Trumbore ray-triangle, cells-and-portals matches KotOR .vis, spatial coherence caching - McKesson Learning Modern 3D Graphics: column-major OpenGL explanation, non-linear depth / reverse-Z, view_dir specular BUG identified, sRGB gamma correction needed, depth precision for outdoor modules - Lengyel Mathematics for 3D Game Programming 3e: normal matrix CPU precompute optimisation, frustum plane extraction formula, TBN tangent space, Cook-Torrance BRDF option - Lengyel Foundations of GED Vol.2 Rendering: UBOs for per-frame data, dual quaternion skinning, danglymesh morph targets, FXAA pass, portal visibility confirmed as correct KotOR architecture - Millington Game Physics Engine Development 2e: physics not priority, AABB update for moved objects, walkmesh BSP for play mode, RK4 for animation splines, damped spring for danglymesh - Millington Preview Ch.18: 2D physics for room assembly overlap check ROADMAP.md updates: - Phase 1: added 1.10 (specular camera_pos fix) and 1.11 (write uniform) - Phase 2: added 2.9 (Möller-Trumbore ray hit) and 2.10 (2D AABB overlap) - Phase 3: added 3.8-3.14 (frustum culling, portal culling, normal matrix precompute, camera_pos, sRGB, shadow mapping, TBN tangent space) - Phase 4: added 4.6-4.8 (RK4 splines, danglymesh spring, DQ skinning) - Phase 5b NEW: Renderer Performance phase (UBOs, instancing, LOD, FXAA, reverse-Z, cull/draw pass split, spatial coherence cache) - Version targets updated to v2.0.13 base, test counts revised upward - Priority order expanded: specular fix and Möller-Trumbore now top items
…um/portal culling, save_are, +185 tests (2748 total) ## v2.0.15 (test_roadmap_pass9.py — 46 tests) - _ray_tri_intersect() edge-case validation (parallel, behind, near-edge, tuple verts) - hit_test_walkmesh() multi-triangle selection (closest-win, empty, degenerate) - set_vis_rooms() portal state management (enable, disable, empty set, None) - _cpu_normal_matrix() correctness (identity, translation, uniform scale) - Frustum helpers: 6-plane extraction, inside/behind culling - LayoutData.from_string() world-coord preservation + .position tuple - VisibilityData API (are_visible, visible_from, case-insensitive) - save_are() / save_ifo() binary validation - GFFStruct.set_field() round-trip ## v2.1.0 (test_roadmap_pass10.py + test_roadmap_pass11.py — 81 tests) ### Core API fixes - gmodular/formats/mdl_parser.py: MeshData.renderable_nodes() alias for visible_mesh_nodes() - gmodular/gui/viewport.py: load_mdl_mesh — correct face-indexed vertex expansion; _upload_textured_mesh called with correct positional args - gmodular/gui/viewport.py: _load_tpc_texture — use TPCReader.from_bytes() + TPCImage.rgba_bytes (replaced broken TPCReader(bytes).to_rgba() call) - gmodular/gui/viewport.py: viewport.py kept under 3,000 lines (trimmed to 2,995) ### Feature wiring - gmodular/gui/viewport.py: walkmesh face selection now interactive — mousePressEvent calls _pick_walkmesh_face(sx,sy) when _walkmesh_edit_mode active; emits walkmesh_face_selected(face_idx, t) Signal - gmodular/gui/main_window.py: VisibilityData.from_string() called after mod load; viewport.set_vis_rooms() receives visible-room set from parsed .vis data ### Test fixtures - tests/test_data/slem_ar.mod: rebuilt with ERFWriter to include slem_ar.mdl + slem_ar.mdx (8 resources total, was 5); test_mod_loads_and_has_mdl now passes ### New test files - tests/test_roadmap_pass10.py: 49 tests (ViewportWidget, MeshNode/MeshData, VisibilityData) - tests/test_roadmap_pass11.py: 32 tests (TPC API, renderable_nodes, slem_ar fixture) ### Previously in this branch (v2.0.14, test_roadmap_pass8.py — 58 tests) - Specular camera_pos fix (view_dir = normalize(camera_pos - v_world_pos)) in all 4 shaders - CPU normal matrix (_cpu_normal_matrix() uniform) - Moller-Trumbore ray-triangle intersection (_ray_tri_intersect + hit_test_walkmesh) - Frustum culling (_extract_frustum_planes + _aabb_inside_frustum + room AABB cache) - Portal/VIS culling (set_vis_rooms, _vis_rooms gate in render loop) - save_are() — complete GFF V3.2 serialiser for .ARE files - GFFStruct.set_field() overload accepting GFFField objects ### Docs - ROADMAP.md: updated to v2.1.0 (2748 tests); session summary tables; Tier 1/2/3 priorities - README.md: v2.1.0 What's New section; features checklist updated - TEXTBOOK_STUDY_REPORT.md: eight-book study report Test result: 2748 passed, 7 skipped, 0 failures
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
GModular v2.1.0 — Full Feature & Fix Session
Test result: 2748 passed, 7 skipped, 0 failures (was 2,492 at v2.0.15 start of session)
v2.0.14 Changes (test_roadmap_pass8.py — 58 tests)
camera_posfix —view_dir = normalize(camera_pos - v_world_pos)in all 4 lit shaderscpu_normal_matuniform via_cpu_normal_matrix()_ray_tri_intersect()+hit_test_walkmesh()_extract_frustum_planes()+_aabb_inside_frustum()+ room AABB cacheset_vis_rooms(),_vis_roomsgate in render loopsave_are()— complete GFF V3.2 serialiser for .ARE filesGFFStruct.set_field()overload — acceptsGFFFieldobjectsv2.0.15 Changes (test_roadmap_pass9.py — 46 tests)
_ray_tri_intersect()edge-case validation (parallel, behind, near-edge, tuple verts, miss outside)hit_test_walkmesh()multi-triangle selection (closest-win, single miss, side-miss, empty, degenerate)set_vis_rooms()portal state management (enable/disable/empty/None/membership)_cpu_normal_matrix()correctness (identity, translation, uniform scale, dtype, shape)LayoutData.from_string()world-coord preservation (single, two rooms, negative coords,.positiontuple)VisibilityDataAPI (are_visible true/false, visible_from, case-insensitive)save_are()/save_ifo()binary validation (ARE/IFO magic bytes, tag-divergence)GFFStruct.set_field()round-trip (GFFField accept, byte value, string, overwrite,inoperator)v2.1.0 Changes (test_roadmap_pass10.py + pass11.py — 81 tests)
Core API fixes
MeshData.renderable_nodes()— canonical alias forvisible_mesh_nodes()added tomdl_parser.pyload_mdl_meshfix — face-indexed vertex expansion corrected;_upload_textured_meshcalled with correct positional args (positions, normals, uvs, uvs2, color)_load_tpc_texturefix — replaced brokenTPCReader(bytes).to_rgba()with correctTPCReader.from_bytes(data)→TPCImage.rgba_bytes; dimensions read fromtpc.width/tpc.heightviewport.py< 3,000 lines — trimmed to 2,995; passesTestViewportLineCountFeature wiring
mousePressEventcalls_pick_walkmesh_face(sx, sy)when_walkmesh_edit_modeactive; emitswalkmesh_face_selected(face_idx, t)VisibilityData.from_string()called after mod open;set_vis_rooms()receives visible-room set from .vis dataTest fixtures
slem_ar.modrebuilt — now containsslem_ar.mdl+slem_ar.mdx(8 resources, was 5);test_mod_loads_and_has_mdlnow passesFiles Changed
gmodular/formats/mdl_parser.pyrenderable_nodes()alias addedgmodular/gui/viewport.pyload_mdl_meshfix,_load_tpc_texturefix, walkmesh click wiring, line count trimmedgmodular/gui/viewport_renderer.pygmodular/gui/main_window.pygmodular/gui/animation_panel.pytests/test_data/slem_ar.modtests/test_roadmap_pass8.pytests/test_roadmap_pass9.pytests/test_roadmap_pass10.pytests/test_roadmap_pass11.pyROADMAP.mdREADME.mdNext Priorities (from ROADMAP.md)
Tier 1 — Critical Path:
RoomPlacement.x/y/zflows torebuild_room_vaosrebuild_room_vaos— wire fixed_load_tpc_textureinto room-VAO buildpassstubs inanimation_panel.pytest_roadmap_pass12.py— cover the above three featuresTier 2 — High Value:
5. Game installation detection (
game_detector.py) — mirror PyKotor strategy6. Module thumbnail generator wired to content browser
7.
module_io.pysilent-swallow audit