A scene link keeps an external object in step with the node it hangs off. The
kinds were a closed enum with a switch in TransformSystem, so scene had to
include graphics, physics and audio to do the casts, and no other module could
ever attach to the tree without editing SceneHost.h -- particles, voxel,
spritestack, avatar and weather all had to stay outside it.
Kinds are registered now (scene/SceneLink.h). The module owning the target type
supplies pushWorld / pullWorld / alive, keeps the casts on its own side where
the type is complete, and scene never learns what a Renderable3D is. Dispatch is
a function-pointer table rather than virtual calls, since link sync runs for
every dirty node every frame.
The six typed helpers (linkRenderable2D and friends) stay as conveniences and
now resolve their kind by name, so they return false rather than crash when the
module that registers it was trimmed out. The script API already named kinds
with strings, which is exactly the registry key, so it is unchanged.
Direction is now the right way round: graphics, physics and audio depend on
scene rather than scene on them, and scene drops from L5 to L1. What remains is
scene -> graphics from pickScreenAt / collectFrustumIdsAt, which take a Camera3D
and read its projection; that is recorded in the back-edge whitelist as the next
thing to move.
Each provider lives in a SceneLinks.cpp, sharing the basename so the three come
out of the build together when scene is disabled.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
The SDL pump did the translation itself, so it had to know about keyboard,
joystick, touch, window, graphics, audio and ui: eight upward dependencies from
one of the engine's lowest modules, and the source of every remaining
dependency cycle.
Each module now registers an IPlatformEventSink for the events it owns and the
pump only dispatches. Key and text events move to keyboard/sdl, joystick and
game-controller events (including the hotplug device table) to joystick/sdl,
finger events to touch/sdl, resize and the mobile background/foreground surface
watch to window/sdl, the ImGui observer to ui, and Audio::pump to an
end-of-pump hook in audio. The pump keeps only quit and window-close, which are
about the event loop rather than any one module.
Sinks run in priority order -- observer, then surface, then input -- so ImGui
still sees events first and the window is resized before anything reads its
size. The mobile surface teardown keeps using SDL_AddEventWatch rather than the
poll path, since by the time SDL_PollEvent returns the native surface is gone;
the watch is now installed by the window module on its first pump.
Also removes exceptionIfInRenderPass, whose body has been commented out since
it was written and whose only remaining effect was a graphics include.
The engine dependency graph now has zero cycles, down from 26, and the back-edge
whitelist is down to 2 (window -> graphics, window -> image). Layering is also
right way up: event sits at L0 with the input modules above it at L1/L2.
Verified: unit tests for event/input/ui/audio/thread pass, and the example
smoke suite gives the same 19 pass / 9 fail as the pre-change baseline (those 9
fail on main too, from script API drift in the examples themselves).
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
HotReload knew what lived at every watched path: it included graphics to
refresh textures, particles to reload emitter configs and map to reload tile
layers. That made the engine's lowest-level module depend on three of its
highest, and it was the only reason filesystem sat in a dependency cycle.
Each module now registers an eve::caps::IAssetReloader for the assets it owns
and HotReload only routes paths. Behaviour is unchanged: automatic dispatch
still matches by extension, an explicit bind() still targets one kind and
ignores the extension, and the texture reloader runs at kTexture priority so
the GPU upload happens before emitters and tile layers re-bind to it.
The reloadable set now follows the linked module set, so a build without
particles simply has no particle reloader rather than a dangling reference.
Reload kinds also become extensible: a module or plugin can add one without
touching filesystem.
Back-edge whitelist 14 -> 11; the dependency graph is now acyclic apart from
the event pump.
(map.render.tilesContributeDepthY fails when run after the hotreload cases both
before and after this change -- pre-existing test-order state, not from here.)
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Introduces eve::cap in common/Capability.h: a name-keyed registry where the
consumer owns the interface, the provider registers an implementation, and
neither includes the other. It generalises what common/RenderTrace.h already
does for the render tracer, and supports both a single provider (provide/query)
and many ordered ones (addListener/forEach), keyed by string so a provider
compiled into a plugin lands in the same slot as the host.
Two upward dependencies go away:
system -> graphics IGpuInfo. The Vulkan physical-device fields move into
graphics/vulkan/GpuInfoProvider.cpp, with a WebGPU
counterpart, so System.cpp loses both the graphics
include and its EVENGINE_WEBGPU branches.
thread -> event IMainThreadPost. postMain and submitPost now enqueue
through the capability. The interface makes explicit
what was previously only a comment in submitPost: the
submitting thread calls prepare() so the worker never
reaches the module registry.
Both now report an error when no provider is linked, rather than lazily
creating a module the build may not contain.
Step S3 of docs/dev/模块编排与裁剪架构.md; back-edge whitelist 16 -> 14.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Analyse how the 53 modules currently collaborate and why none of them can be
trimmed outside the hardcoded WASM axis, then lay out a target architecture and
a six-step route to per-module build options.
Adds scripts/module_depgraph.py, which produces the dependency graph, the
7-layer topological ordering and the cycle list the document cites. Its --check
mode fails on any back-edge outside the 16 known ones, so it doubles as the CI
guardrail for step S1.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Water used newMeshShader (runtime glslc compile), which is unsupported on
Windows (compileGlslWithGlslc throws there), failing graphics.water.* tests in
the Windows CI job. Extract the water fragment to shaders/water.frag, compile
it to water_frag_spv.inc, and create the shader via newMeshShaderFromSpv so it
works on every platform. Add compile_graphics_water_shaders.py.
Move the user-maintained VKBuilder from the third-party aggregate into external/ (git submodule), and relocate the third-party DungeonTemplateLibrary and Box3D from external/ into the third-party aggregate (previously pushed to EVEngine/third-party). Update .gitmodules, include paths, DTL/box3d build wiring, and docs.
- Renamed rendering functions to follow a consistent naming convention (e.g., `update` to `eve_update`, `draw` to `eve_render`).
- Set background colors for bush, tree, skyscraper, and other procedural generators to enhance visual consistency.
- Adjusted parameters in `gfx.drawSolidRect` and `gfx.drawTexturedRect` to use floating-point values for improved precision.
Add a screen-space reflection (SSR) fullscreen pass and hook it into the Water
shader as an optional, off-by-default reflection overlay.
- ScreenSpaceReflection: ray-marches the reflected ray over the lit scene color
+ hardware depth, reconstructing the world normal from depth (mirrors the
SSGI pass). Outputs reflected color with A = hit validity into a canvas.
Graphics::newScreenSpaceReflection() + script binding; quality knobs
(strength/steps/stepLen/thickness/distance) and enabled toggle.
- Water::setScreenSpaceReflection(enabled, strength) + setViewport: the water
shader samples the reflection texture (bound via the height slot, binding 6)
at screen UV and blends it over the env-cubemap reflection. Off by default.
- New ssr.frag + compile script; vulkan SPIR-V regenerated.
Note: SSR reflects only geometry that is on-screen. For a horizontal water plane
viewed from above the reflected geometry sits in the void below the plane (no
depth there), so SSR finds no hits there; it works for on-screen-reflective
surfaces (glossy floors/walls, grazing water). Env-cubemap reflection remains
the default; SSR is additive when enabled.
Show only the part of a marked character that is hidden behind a building,
as a filled highlight silhouette (Overwatch-style). Visible parts render
normally.
- Shader: xray_mesh.frag samples G-buffer hardware depth (binding 7) and
compares it against its own fragment depth: occluded (behind) pixels emit
the highlight, visible pixels discard. Drawn as a second pass over the
scene with depth test/write off + alpha blend.
- RenderSystem3D: MeshRenderer gains xrayShader + xrayHighlight. X-ray
targets are skipped in the G-buffer (their pixels record occluder depth),
then redrawn with the X-ray shader; scene depth is bound via
Graphics::setMesh3DSceneDepth.
- Graphics: new setMesh3DSceneDepth + Shader::setXray. Vulkan adds binding 7
to the mesh3d set layout and a dedicated X-ray pipeline variant.
- WebGPU: new newMeshShaderFromWgsl (WGSL custom mesh shaders), scene-depth
binding 9, X-ray pipeline variant, xray params packed into the Frame UBO,
and the G-buffer hardware depth is exposed/sampleable (getHwDepthTexture).
AO (SPIR-V) is skipped on WebGPU via supportsGBufferPost.
- stylize: 'xray' style registered (createMeshShader dispatches SPIR-V on
Vulkan / WGSL on WebGPU) with push-constant params.
- Tests: test/Xray.cpp (shader/flags + occluded-silhouette render smoke).
Add a t3ssel8r-style screen-space outline computed from the G-buffer
hardware depth and world-normal buffers. For each pixel the shader
samples an 8-neighbourhood at a configurable width and flags depth
(silhouette/occlusion) and normal (crease) discontinuities, emitting
vec4(outlineColor, edgeMask) that is SrcAlpha-blended over the scene.
- new graphics::Outline class (mirrors AmbientOcclusion) with color,
width, depth/normal thresholds, softness and clip knobs
- new outline_post.frag + compiled SPIR-V include + compile script
- RenderControl "outline" feature (implies gbuffer, default off) applied
by RenderSystem3D after the forward/hair passes
- Graphics.newOutline + Squirrel binding + test/Outline.cpp (params,
feature toggle, and an interactive cube preview)
Sample terrain meshes with Poisson-disk or Halton blue noise, expand
root-pivoted billboard quads, and shade them with a 4-frame sway atlas.
Instance ids desync the animation, the CSM shadow map picks between
light and dark green, and a second sparse pass adds always-dark tufts.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
- Added support for the WebGPU backend in the CMake configuration, enabling builds for Emscripten and native Dawn.
- Implemented conditional compilation for WebGPU-specific features, including shader management and file system handling.
- Updated the build process to exclude unnecessary modules and dependencies for WebGPU, optimizing the engine for browser environments.
- Enhanced the installation script to include WebGPU-related files and directories in the output.
- Refactored existing modules to accommodate WebGPU, ensuring compatibility and performance improvements across the engine.
- Introduced new compile options and configurations tailored for WebGPU builds, including handling of third-party libraries and assets.
- Introduced a new mechanism for registering C++ entity view functions, allowing Squirrel scripts to access and manipulate C++ entities directly.
- Implemented a `cppCollect` function to traverse class hierarchies and collect C++ entities based on registered views, enhancing script interaction with C++ components.
- Updated the ECS API to expose new functions for registering C++ entity views and collecting entities in scripts.
- Enhanced existing tests to validate the new functionality and ensure proper integration between C++ and Squirrel scripts.
- Introduced a new toon shader for enhanced visual effects in 3D rendering.
- Updated vertex shaders across multiple files to use the inverse-transpose of the model matrix for normal calculations, ensuring correct normal transformations for non-uniform scaling.
- Added the mesh3d_toon.vert shader to the shader compilation script.
- Updated SPIR-V binaries for affected shaders to reflect the changes in normal matrix calculations.
- Enhanced test cases to validate the new toon shader functionality and its integration with existing graphics features.
- Added a new 3D rendering pipeline section in the documentation, detailing initialization, VKBuilder, and asynchronous frame handling.
- Updated the Ambient Occlusion module to support depth-based sampling, allowing for improved visual fidelity in 3D scenes.
- Introduced new shader functionalities for ambient occlusion and global illumination, enhancing the overall rendering quality.
- Updated GBuffer to include hardware depth texture for more accurate depth sampling in 3D rendering.
- Enhanced the RenderControl to manage new features for ambient occlusion and global illumination, ensuring they are enabled by default.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
Introduce a compilable render feature control (shadow/gbuffer/forward/hair),
package shading into Material+ModelPart attachable to Renderable3D, and fill
sampleable linear-depth/normal (optional albedo) G-buffer targets while
keeping forward HW z-testing and CSM shadows.
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Introduce mesh3d_hair GLSL shaders with alpha-blended Vulkan pipeline
(no back-face cull, depth write disabled). Expose gfx.newHairShader(),
Renderable3D.setHair() for a back-to-front transparent pass in
RenderSystem3D, plus HairShader helpers and unit tests.
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
* feat(image): ImageData::rotate with inverse-map nearest/linear
Add CPU pixel rotation on ImageData using destination-to-source inverse
mapping (Geometric Tools / standard image processing). Supports nearest
and bilinear filters, optional canvas expand to fit the rotated AABB,
and matches Math::rotate2* angle convention. Includes unit tests, Font
script binding, and docs.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
* test(image): assert exact 90° rotate pixel positions
Pin nearest+expand 90° mapping of corner markers to (1,2) and (0,0).
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
* feat(image): implement RotSprite pixel-art rotation filter
Add Xenowhirl RotSprite as ImageData::rotate filter "rotsprite":
Scale2x×3 with color similarity, best 8×8 sampling offset search,
nearest-neighbor rotate+downscale, and single-pixel detail restore.
Quarter turns use an exact remapping fast path. Tests cover 90°
palette preservation and 45° no-new-colors.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
* fix(ci): M_PI on MSVC and GitHub API 403 for asset downloads
Windows unit tests failed because test/image.cpp used M_PI without the
MSVC fallback used by other test files. macOS build failed when
download_skinned_character.sh hit GitHub API 403 during PRE_BUILD; add
User-Agent + optional GITHUB_TOKEN auth to asset fetch scripts and pass
GITHUB_TOKEN in CI build steps.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
* Add extensible building placement module for strategy/ETS games
Introduce eve.Building with data-driven definitions, grid occupancy worlds,
ghost previews, and pluggable validate/snap/change hooks. Includes design docs,
user module guide, unit tests, and a gitignore fix so build*/ no longer ignores
src/modules/building/.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
* fix(building): preserve free-snap world pose on placeAtWorld
placeAtWorld now keeps the snap rule's worldX/worldY on the placed
instance instead of always rewriting to the cell origin, so free and
custom snap modes stay accurate for ETS-style soft placement.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
* Add examples/building town placement sandbox demo
Interactive demo covering grid snap ghost preview, terrain (dock on water),
road adjacency (stall), L-mask barn, rotate/remove, and resource costs.
Also adds make building shortcut, docs links, and a unit test locking the
demo building definitions.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
* fix(ci): vendor CesiumMan test assets to avoid flaky Linux SSL download
Linux CI failed linking unit_test when PRE_BUILD curl hit a self-signed
certificate fetching CesiumMan from api.github.com. Commit the ~464 KiB
glTF fixture, skip download when files are present, and add curl retries
with explicit CA bundle for refresh runs.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
* feat(animation): CPU skinning + CesiumMan download test
Add AnimSkin linear-blend skinning, ModelData bone/weight APIs, and a
network download script for Khronos CesiumMan used by animation.skinned
integration tests during unit_test builds.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
* fix(test): mount CesiumMan via physfs for skinned animation tests
Model3D loads through the VFS; use allowMountingForPath + mount like
ClassicScenes so CesiumMan.gltf resolves with its .bin sidecar.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
* feat(graphics): texture cell bombing to break tiling
Add UV-space cell bombing on the default mesh3d / clustered PBR paths:
per-cell random offset and rotation blended across a 2x2 neighborhood
(with textureGrad for stable mips). Opt-in via Renderable3D::setTexCellBomb
(strength 0 keeps prior behavior). Includes GLSL helper, SPIR-V embeds,
CPU reference header, docs, and smoke tests.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
* fix(graphics): rotate UVs in cell bombing; harden GPU test
Rotate UVs about each cell center (not just translate) so periodic
textures actually break tiling. Use the known-good UV cube + repeating
motif in the pixel smoke test.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Add a voxel module that remeshes 32³ chunks into six face-direction
buffers of 32-bit packed rectangles (xyz+wh+tex), culls by frustum,
view range, and camera-facing normals, then draws via a new Vulkan
instanced unit-quad path (Graphics::drawVoxelFaceInstances).
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
* feat(tests): classic scene flythroughs with render config switching
Add Cornell Box (committed), procedural metal/roughness chart, and
downloadable Sponza/DamagedHelmet tests that fly the camera while
cycling ambient, directional, shadows, point lights, and IBL.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
* fix(tests): bake Assimp node transforms and light classic scenes
Apply scene-graph world matrices when spawning meshes, fix Cornell face
winding for inward normals, keep Sponza dielectric under missing MR
texture sampling, and link sndio when OpenAL builds that backend.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
* docs(tests): note ClassicScenes coverage
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
* feat(stylize): add NPR stylized rendering module
Add eve.Stylize with cartoon, watercolor, ink, and pixel post-process
shaders, mesh variants for cartoon/ink, CPU processImage helpers, and
StylePass integration over graphics Shader/Canvas.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
* fix(stylize): fix unit test Color/unique_ptr assertions
Use global Color typedef and compare unique_ptr via get() so zeroerr
decomposition does not try to copy unique_ptr.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
* feat(stylize): cylinder style gallery PNGs for docs
Add Graphics::newMeshCylinder and a gallery test that renders a lit
cylinder in cartoon/ink/watercolor/pixel styles, writing PNGs into
docs/images/stylize for the design doc. Fix pixel toon banding so dark
bands are not crushed to black.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
* fix(stylize): close gap vs research NPR looks in gallery
Stabilize lighting (no blown whites), use silhouette-only outlines so
stripe albedo no longer blacks out the form, composite watercolor/ink
onto paper, and retune cel/wash/pixel passes toward UTS / Bousseau /
Sumi-e / pixel-pipeline cues. Refresh cylinder gallery PNGs.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
* feat(stylize): stabilize extension APIs for future NPR work
Add StyleChain, newPassFromShader, applyTo, supports()/param
introspection, and document reserved gbuffer/multi-pass hooks.
Effects stay as first-pass approximations; the public surface is
what subsequent depth-outline and separable passes should plug into.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
* docs(procgen): add procedural generation module design
Capture confirmed product direction (runtime map-first, textures
second, pixel/low-poly RPG) plus API sketch, algorithm registry,
configurable outputs, and Phase A checklist.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
* docs(procgen): list procgen in module summary table
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
* feat(procgen): Phase A runtime map generation with DTL
Add eve.Procgen module: semantic Grid2D, algorithm registry, palettes,
and TileLayer/JSON outputs. Built-ins use Dungeon Template Library
(BSP, cellular cave, maze, perlin terrain) plus local drunkard walk.
Includes tests and examples/procgen demo.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
* feat(procgen): Phase B runtime pixel texture recipes
Add seamless value-noise texture generation with banded color ramps
for soil/stone/marble/water/sky_cloud, ImageData/Texture/normal outputs,
and script bindings for gfx.newTexture / drawTexturedRect.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
* fix(test): qualify eve::image::ImageData in procgen tests
Bare image:: failed to resolve under `using namespace eve::procgen`,
breaking unit_test builds on Linux/Windows/macOS CI.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
* fix(procgen): link EVProcgen in tests and fix Apple Clang DTL build
unit_test was missing EVProcgen, causing undefined references on Linux/Windows.
Avoid the DTL umbrella header (broken Voronoi CRTP on Apple Clang) and provide
DrawJagged* compat shims that define the missing drawOperatorArray.
Verified locally: linux-debug build, unit_test link, and all 13 procgen ctests.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>