# wolf_3d_flutter Flutter integration package for the shared Wolfenstein 3D runtime. ## What This Package Provides `wolf_3d_flutter` layers Flutter-specific host concerns on top of `wolf_3d_dart`: - high-level engine facade (`Wolf3dFlutterEngine`), - Flutter input adapter, - platform audio integration, - renderer host widgets and runtime mode helpers, - app/session managers and persistence adapters, - shader-enabled rendering support. Primary entrypoint: `lib/wolf_3d_flutter.dart` ## Prerequisites - Flutter SDK - Dart SDK `^3.11.1` - Workspace dependency on `wolf_3d_dart` ## Setup From this directory: ```bash flutter pub get ``` ## Usage Typical host initialization pattern: ```dart final Wolf3dFlutterEngine engine = await Wolf3dFlutterEngine( debug: kDebugMode, ).init(); ``` `init()` handles platform setup, audio init, configured external discovery, and optional seeded game injection. To load packaged game data from `wolf_3d_assets`, use `Wolf3dFlutterEngine.loadGameDataFromAssets(...)` and pass the result via `seededGames`: ```dart final retail = await Wolf3dFlutterEngine.loadGameDataFromAssets( version: GameVersion.retail, packageName: 'wolf_3d_assets', assetDirectory: 'assets/retail', ); final shareware = await Wolf3dFlutterEngine.loadGameDataFromAssets( version: GameVersion.shareware, packageName: 'wolf_3d_assets', assetDirectory: 'assets/shareware', ); final Wolf3dFlutterEngine engine = await Wolf3dFlutterEngine( debug: kDebugMode, ).init(seededGames: [retail, shareware]); ``` The facade itself lives in `lib/engine/wolf3d_flutter_engine.dart` and is re-exported through the package barrel at `lib/wolf_3d_flutter.dart`. External consumers should keep importing the barrel unless they have a specific reason to target the engine library directly. The same pattern applies to the Flutter input adapter and the desktop persistence adapters: they now live in focused subdirectories and are re-exported through `lib/wolf_3d_flutter.dart`. For full host wiring examples, see: - `apps/wolf_3d_gui/lib/main.dart` ## Package Structure - `lib/wolf_3d_flutter.dart` — barrel export for the public Flutter package surface. - `lib/engine/wolf3d_flutter_engine.dart` — high-level engine facade and discovery bootstrap. - `lib/input/` — Flutter-specific input adapters. - `lib/persistence/` — desktop persistence adapters for saves and renderer settings. - `lib/renderer/` — renderer host widgets. - `lib/managers/` — runtime/session/display/persistence managers. - `lib/audio/` — platform-aware audio backends. - `shaders/wolf_world.frag` — base fragment shader included in package configuration. - `shaders/wolf_world_bloom.frag` — bloom-enabled fragment shader variant. ## Integration Notes - Keep UI/platform concerns in this package or app hosts, not in `wolf_3d_dart`. - Use exported APIs from `lib/wolf_3d_flutter.dart` rather than importing private internals from `lib/src` in dependencies. - Shader paths are declared in this package `pubspec.yaml` and must stay synchronized with renderer usage. ## Shader Architecture And Performance Notes This package ships two shader variants: - `shaders/wolf_world.frag` (base pass, no bloom taps) - `shaders/wolf_world_bloom.frag` (bloom-enabled variant) The renderer selects one variant in Dart based on runtime settings. This is a performance decision: when bloom is disabled, we do not run bloom sampling code at all. ### No-Branch Shader Policy For package-owned shader sources, do not use `if` statements. Use branchless selection patterns (`mix`, `step`, `smoothstep`, mask algebra) instead. Static check: ```bash rg "\bif\s*\(" packages/wolf_3d_flutter/shaders ``` Expected result: no matches in source shader files. ### Why This Is Different From Dart If you are primarily a Dart developer, this is the key mindset shift: - Dart code runs on CPU cores with branch prediction and comparatively cheap control flow. - Fragment shaders run across many pixels in parallel on GPU SIMD/SIMT lanes. - If neighboring pixels take different branches, the GPU can serialize branch paths (divergence), reducing throughput. - Texture reads are usually more expensive than scalar ALU math. Removing bloom work entirely when disabled is often better than trying to gate it inside one shader. In short: in Dart, `if` can be good structure. In fragment shaders, branchless math and pass selection are often better for frame time. ### Dart-Style Thinking vs Shader-Style Thinking CPU/Dart style: ```dart if (effectsEnabled) { uv = warp(uv); } if (outsideScreen(uv)) { return bezelColor; } ``` Shader style used here: ```glsl vec2 effectiveUv = mix(uv, warpedUv, effectsMask); float bezelMask = (1.0 - insideMask) * effectsMask; vec3 outColor = mix(screenColor, bezelColor, bezelMask); ``` Both produce feature-equivalent behavior, but the second keeps execution paths uniform across fragments. ### Shader Block Guide (What / Why) 1. UV normalization: Convert fragment coordinates to 0..1 UV so all sampling math is resolution agnostic. 2. Barrel warp: Simulates curved CRT glass by pushing UVs outward as radius increases. 3. Inside/outside mask: Computes whether warped UV remains on the emissive screen rectangle. This replaces branch-based bezel routing. 4. Edge-aware AA: Computes local luma span from N/S/E/W neighbors and blends toward neighborhood average only where contrast indicates potential aliasing. 5. CRT modulation: Applies scanlines, moving sweep, center lift, and vignette to mimic phosphor and lens behavior. 6. Bezel shading: Uses overflow distance and edge bleed sampling to build depth, inner lip, and scene-tinted glow on bezel regions. 7. Bloom variant only: Adds three-ring cross taps, brightness gating, and tone mapping. This code is in a separate shader so bloom-off mode avoids paying this cost. ### Constant Tuning Reference - Warp factor: `0.045` Higher = stronger curvature. - AA blend ceiling: `0.45` Higher = softer edges, more blur risk. - Scanline band: `0.88 + 0.12 * sin(...)` Lower floor or higher amplitude increases CRT stripe intensity. - Sweep speed: `uTime * 0.08` Higher = faster sweep line travel. - Bloom ring radii: `3`, `7`, `13` texels Larger radii spread glow farther but increase halo size. - Bloom gain: `0.42` Higher = brighter bloom before tone map. - Tone map: `color / (color + 0.75) * 1.75` Controls highlight rolloff and midtone lift. ### Glossary - UV: normalized texture coordinates in [0, 1]. - Luma: perceived brightness estimate from RGB. - Mask: scalar 0..1 value used to blend between alternatives. - Vignette: edge darkening effect. - Tone map: compresses highlights into displayable range. - Tap: one texture sample read. - Divergence: parallel shader lanes taking different branches. ### Profiling Expectations - Bloom disabled: base shader variant runs, no bloom taps. - Bloom enabled: bloom shader variant runs, additional texture sampling cost. - Effects disabled: both shaders still remain branchless; effect contribution is blended out by mask values. ## Troubleshooting - **No discovered game data**: confirm configured/persisted data directory paths are valid. - **Desktop behavior mismatch**: verify desktop windowing and audio dependencies are available on the target OS. - **Render issues after shader changes**: confirm shader path and package config are still aligned. ## Related Modules - Core runtime package: [`../wolf_3d_dart/README.md`](../wolf_3d_dart/README.md) - GUI host app: [`../../apps/wolf_3d_gui/README.md`](../../apps/wolf_3d_gui/README.md) - Shared assets package: [`../wolf_3d_assets/README.md`](../wolf_3d_assets/README.md) - Workspace overview: [`../../README.md`](../../README.md)