- VoxelWorld::setTerrainParam(key, value) exposes the full procgen TerrainSampler (island/continent/ridge/warp/octaves/...) to script, plus an optional sand band for low coastal columns.
- drawVisible now takes graphics::Graphics* (main class) instead of IGraphics3D*: the script binding layer reinterpret-casts interface pointers without secondary-base adjustment, so the IGraphics3D vtable slot for drawVoxelFaceInstances resolved to an unrelated function and voxel draws were silently dropped from the frame.
- Graphics.h: move decal virtual declarations after drawVoxelFaceInstances so the primary vtable slot order matches IGraphics3D for unadjusted script-side dispatch.
- New examples/voxel-terrain scene: first-person fly, 4 terrain presets, streaming chunks, raycast place/break, F12 swapchain screenshot.
- Unit tests for the param API + sand band; docs updated.
- examples/softbody3d: pass explicit Box3D shape arguments (script bindings
do not apply C++ default args) and use math.polarX/polarY instead of
math.sin/cos (EVEngine's math module shadows the standard table)
- ClothGPU: drop unused local in reset() (MSVC /W4 /WX C4189)
- docs: add missing Cloth/Cloth3D API entries to the physics quick reference
AnimSkin can now write CPU-skinning results back to the render mesh so skeletal animation actually plays from scripts:
- capture bind normals at fromModel and skin them per pose (updateSkinnedNormals / getSkinnedNormals, cofactor inverse-transpose + normalize)
- packed getSkinnedPositions() array getter, matching AnimLattice's script pattern
- one-call applyToMesh(gfx, mesh, pose): skin positions+normals then in-place gpu.updateMeshVertices
- Renderable3D.getMesh() script binding so createRenderable meshes are reachable
- Mesh::gpuVertexCount so getVertexCount() is correct for non-morph meshes (both backends)
- tests: packed positions == skinPositionsTo, normals follow pose and stay unit length, applyToMesh render test with in-place updates
- docs: animation/graphics user guides + design spec
avatar/database/dialogue/sceneloader/stylize/virtualgeometry now list
getName(); camera spells getTargetX/Y/Z out in full. These chapters are
gated by scripts/check_bindings.py --strict in CI.
- New user docs: avatar, buildingfx, camera, database, dialogue, grid,
housegen, sceneloader, stylize, virtualgeometry (all written against the
actual addFunc surfaces; API quick-refs included). Wire them into MODULES.md.
- examples/voxel: streaming terrain + place/break demo (procedural atlas,
setTerrain + streamAround, DDA raycast picking, orbit camera). Script logic
verified locally (no script errors; 16 chunks / 3117 rects selected).
- README gallery links in both Readme.md and Readme.en.md.
- Script binding fixes discovered while writing the docs/examples:
* Graphics.setCanvas accepts null (and Canvas instances) so canvas sessions
can be ended from scripts; begin3DFrame/setMesh3DViewProj/setMesh3DView/
setMesh3DCameraPos now exposed for script-driven 3D (voxel etc.).
* SceneLoader.load/host exposed (previously only reload/status were bound).
- Add RGBA-float drawSolidRect/drawTexturedRect overloads so the C++ names
match the script-facing API (script already bound those names).
- Add string-based setTextureSampler(Texture*, filter, mipmap, aniso, lodBias)
overload with strict magic-string validation (unknown filter/mipmap now
throws instead of silently falling back to linear); keep
setTextureSamplerParams as a deprecated alias. Script binding now targets
the overload with an explicit cast.
- Document error contracts: DataModule encode/decode (new[] ownership +
throws), Filesystem setSource/mount/unmount (false on recoverable failure,
no throw), ModelData getMesh vs numeric getters (nullptr vs throw), plus a
two-state error-semantics section in API-CONVENTIONS.md.
- Tests: TextureSampler string validation (valid + deprecated alias + typo
throws), headless test now exercises the RGBA-float overloads.
- Image: expose newImageData(newImageDataFromFile)/newEmptyImageData/isCompressed and a
full ImageData script class (getWidth/Height/Format/Size, pixel get/set, paste, clone,
rotate). ImageData is now registered once by the Image module; drop the duplicate
minimal registrations in Font and Model3D that could overwrite each other.
- Joystick: expose getJoystick/getJoystickFromID/getIndex/addJoystick/removeJoystick and a
Pad class with raw axes/buttons/hats, GameController axis/button names, device info,
and vibration. Pads stay owned by the module (non-owning script handles).
- Mouse: expose setRelativeMode/getRelativeMode plus setVisible/setPosition/setX/setY/
setGrabbed/isGrabbed (SDL backend already implemented them).
- Tests: add image.nut/image_script.cpp and joystick.nut/joystick_script.cpp script tests,
extend mouse.nut with relative-mode/visibility checks, wire into test CMake and the nut
embed template.
- Docs: update image/joystick/mouse user chapters, MODULES.md and the REVIEW log.
* chore(ci): add clang-format gate, CODEOWNERS and agent collaboration rules
* refactor(modules): clear remaining back-edges and split the largest TUs
Three known dependency back-edges are gone (module_depgraph.py KNOWN_BACK_EDGES
is now empty; --check passes with 0 violations, 0 cycles):
- window -> graphics: window queries the new IWindowSurfaceHost capability
(common/WindowSurfaceHost.h) instead of holding a Graphics pointer;
Window::setGraphics was removed and all call sites updated.
- window -> image: Window::setIcon was replaced by setIconRGBA(const uint8_t*,
w, h); the window no longer decodes ImageData.
- scene -> graphics: pickScreenAt / collectFrustumIdsAt implementations moved
to graphics/ScenePicking.cpp (graphics -> scene is a legal downward edge);
scene now depends only on spatial.
TU splits (pure moves, verified identical method sets and brace balance):
- vulkan/Graphics.cpp (5118 lines) -> Graphics.cpp (lifecycle), GraphicsPipeline,
Graphics2D, Graphics3D, GraphicsMesh + shared GraphicsInternal.h.
- scene/Scene.cpp -> Scene.cpp (script layer / host lifecycle / serialization)
+ SceneNodes.cpp + shared SceneInternal.h.
Verified with a real build (MSVC 19.51, prebuilt third-party): full build green;
window.* and Scene.* suites pass, including scene picking/culling and GPU cases.
* refactor(graphics): narrow Graphics interfaces and clear public-header leaks
Step 4 — interface segregation:
- New lean interfaces: IGraphics2D, IGraphics3D, IResourceFactory, IPostFX
(pure virtuals, forward-declared types only; graphics/Color.h extracted from
Canvas.h so modules that only need the color type stop pulling Canvas.h).
- Graphics now implements all four facets; consumers can depend on the narrow
interface they use instead of the 129-method god class.
- Migrated voxel (VoxelWorld::drawVisible -> IGraphics3D*) and model3d
(ModelRenderer::buildRenderable(s) -> IResourceFactory&).
- Graphics.h slims from 24 sub-header includes to a handful of small type
headers + forward declarations; the destructor moved out-of-line so
unique_ptr effect members are destroyed where types are complete.
Step 5 — header leaks (module_depgraph.py '*' marks: 14 -> 7):
- map/TileLayer.h, particles/ParticleEmitter.h, avatar/AvatarInstance.h,
animation/SpineAnim.h, map/TileSystem.h, model3d/ModelData.h,
model3d/ModelRenderer.h, audio/Audio.h + Source.h, image/ImageData.h +
Image.h, dialogue/Dialogue.h, procgen Palette/OutputSpec/TextureRecipe/
PbrMaterial -> forward declarations, includes moved to .cpp.
- voxel/VoxelWorld.h: terrain sampler Pimpl'd (unique_ptr + out-of-line
destructor), removing the procgen header dependency.
- gpgpu/vulkan backend headers stop pulling graphics/vulkan/Graphics.h.
- Remaining '*' marks are deliberate: tiny POD/enum headers (GridConfig,
MapObject, BlendMode, Color), an internal backend header
(GraphicsInternal.h -> filesystem), and lean interface references.
Verified with a full clean build (MSVC) and tests: window/Scene/voxel/
RenderSystem/Quad/shader/TextureSampler/resourceLifetime pass; broad suite
only shows the pre-existing PHYSFS-init filesystem-environment failures.
* feat(resources): revive ResourceManager as unified IAssetReloader-backed cache
* fix(resources): leak ResourceManager singleton to avoid exit-time teardown crashes
Cached CPU resources may own third-party handles (FreeType faces, Assimp
scenes, image decode handlers) whose libraries are torn down at process
exit in an unspecified TU order; destroying cached entries from the
singleton destructor can segfault at exit (seen on CI Windows in
model3d.materialApi.objMtl). Keep the singleton alive until OS reclaim;
explicit unload()/clear() still release entries during the run.
* refactor(devtools): consume business modules through capability interfaces
DevTools / cmdline no longer include business-module headers, so trimming
scene / physics / procgen / particles / audio / ui / graphics no longer
requires disabling devtools, and devtools can be switched off with
-DEVENGINE_MODULE_DEVTOOLS=OFF.
New capability interfaces in common/:
- ISceneQuery (scene) - host/node inspection + mutation + transform sync
- IRenderCapture (graphics) - render status, PNG capture, camera control,
visible-entity snapshot, entity-ID mask, G-buffer PNGs
- IPhysicsQuery (physics) - 2D world lifecycle + ray casts
- IProcgenQuery (procgen) - recipe listing, map/mesh generation
- IParticlesQuery (particles) - emitter status + one-shot emit
- IAudioQuery (audio) - volume / stop-all
- IEditorHost (ui) - declarative editor host (used by cmdline too)
Providers register in their module constructors. DevTools rewires McpServer
(render/scene/procgen/physics/particles/audio/host tools), SceneInspect
(now delegates to ISceneQuery + IRenderCapture) and RenderVision (uses
IRenderCapture::capturePngDataUrl); cmdline/Mcp.cpp uses IEditorHost.
manifest: devtools DEPS graphics scene physics procgen particles audio ui
image event filesystem -> event; cmdline DEPS filesystem ui -> filesystem.
Verified: full build green; devtools.mcp.* tests pass; broad suite shows
only the pre-existing PHYSFS-init filesystem-environment failures.
* style: apply clang-format to changed lines after dev merge
* fix(webgpu): include RenderControl/TextureSampler explicitly after Graphics.h slimming
* fix(webgpu): provide newFont/print stubs to satisfy IGraphics2D/IResourceFactory vtables
* fix(common): make ProcgenQuery.h self-sufficient (cstdint/utility for GCC)
ModelData gains material accessors (base color, metallic/roughness, opacity, two-sided), texture queries by type name (base_color/diffuse/normals/height/...), and embedded texture decode to RGBA8 ImageData. New model3d::buildRenderable(s) helpers assemble Renderable3D from a decoded model (node transform baked, material/PBR/textures applied), bound to Squirrel as Model3D::createRenderable.
Normals for assets missing authored normals now default to smooth generation: CMake applies an idempotent configure-time patch to medialoader switching aiProcess_GenNormals -> aiProcess_GenSmoothNormals.