- Texture eyedropper: pickTextureAt() samples dominant texture at world
position by reading chunk alpha maps. Alt+Click in paint mode or
click the Eyedropper button to activate
- loadADT now checks custom_zones/ and output/ for WOT/WHM open format
files first, falling back to ADT binary only if not found
- Fix unused variable warning in scatterPatches
- Document Alt+Click in help panel
- River/road tool now shows translucent blue path preview ribbon with
edge lines between start and end points before applying
- Preview follows cursor when waiting for end point, locks when set
- Undo support for all remaining operations: rotateTerrain90, mirrorX,
mirrorY, scaleHeights, offsetHeights, invertHeights, smoothBeaches
- Every terrain-modifying operation in the editor is now undoable
- All terrain generators now undoable: crater, mesa, hill, voronoi,
dunes, detail noise, thermal erosion, canyon, island, ridge, road,
river, perlin noise — all wrapped with recordGeneratorUndo/commit
- Unsaved changes warning on quit: Save & Quit / Quit / Cancel dialog
- createNewTerrain clears quest editor and path capture state
- recordGeneratorUndo/commitGeneratorUndo helper methods snapshot all
256 chunks before/after any generator operation
- River/Road tool now uses click-capture mode instead of button-based
cursor position — click terrain directly to set start and end points
- 3-step flow: Click Start → Click End → Apply Path (with preview text)
- Cancel button available at each step
- Path state tracked on EditorUI with setPathPoint()/clearPath()
- Intercepts terrain clicks before mode-specific handling when active
- Extend undo/redo to snapshot alpha maps and texture layers alongside
heights — texture painting operations are now fully undoable
- Bracket paint mode with beginStroke/endStroke like sculpt mode
- Fix stale static char buffer in quest objective loop (showed wrong
objective's description when editing multiple objectives)
- Zero-initialize all quest UI text buffers for null termination safety
- Fix unused variable warnings in terrain_editor.cpp
- Quest editor: add loadFromFile() with nlohmann/json, chain validation
with circular reference detection, wire into ADT load and save pipeline
- Project: replace naive substring JSON parsing with nlohmann/json for
both save() and load(), fix shell injection in gitCommit()
- Content pack: replace manual JSON with nlohmann/json, validate binary
format magic numbers (WHM1/WOM1/WOB1), add WOB to openFormatScore
(now scores 0-6), mark invalid files with (!) in summary
- Wire WOB buildings into WMO render pipeline (loads→converts→renders)
- Implement JSON DBC loading in DBCFile::loadJSON() with nlohmann/json
- Wire JSON DBC override into AssetManager (custom_zones/output scan)
- Add WMO→WOB conversion with full geometry (fromWMO)
- Replace placeholder WOB export with real WMO→WOB conversion in editor
- Add --convert-wmo CLI flag for batch WMO→WOB conversion
- Store discovered custom zones on Renderer with getCustomZones() accessor
- Add isCustomZone_ member to TerrainManager
All 6 Blizzard format replacements now fully load in the client:
ADT→WOT/WHM, WDT→zone.json, BLP→PNG, DBC→JSON, M2→WOM, WMO→WOB
- Exports 129x129 grayscale PNG showing terrain elevation
- Auto-normalizes to 0-255 based on actual height range
- Useful for zone documentation, thumbnails, and previews
- Auto-exported alongside WOT/WHM/normals on every save
- Zone export now creates WOB placeholder files for all placed WMO
buildings in output/MapName/buildings/
- Full WMO→WOB conversion (with geometry) requires group file loading
which is complex — placeholders reserve the path structure for now
- All 6 format conversions now auto-run on every zone export:
ADT→WOT/WHM, BLP→PNG, DBC→JSON, M2→WOM, WMO→WOB, WDT→zone.json
- Zone export now converts all placed M2 models to WOM open format
- Deduplicates: each unique M2 path converted only once
- WOM files saved to output/MapName/models/ with original path structure
- Uses WoweeModelLoader::fromM2() for M2→WOM conversion
- Combined with PNG texture export, zones can now be fully distributed
without any Blizzard proprietary files
Full open format export pipeline:
Terrain: ADT→WOT/WHM | Textures: BLP→PNG | Data: DBC→JSON
Models: M2→WOM | Buildings: WMO→WOB (manual) | Map: WDT→zone.json
- TextureExporter: converts Blizzard BLP textures to standard PNG
for fully open redistribution of custom zones
- collectUsedTextures(): finds all texture paths referenced by terrain
- exportTexturesAsPng(): loads BLP via asset manager, writes RGBA PNG
using stb_image_write to output/MapName/textures/
- Zone export now automatically converts all used textures to PNG
- Client's PNG override system already loads these automatically
(checks for .png alongside .blp before loading)
Format replacement progress:
- DONE: ADT→WOT/WHM (terrain)
- DONE: WDT→zone.json (map definition)
- DONE: BLP→PNG (textures — auto-exported on zone save)
- TODO: DBC→JSON, M2→open model, WMO→open building
- File > Export Open Format (.wot/.whm) menu item for standalone export
- Every zone export (Ctrl+S, Export Zone) now also writes .wot/.whm
alongside the ADT/WDT — dual format output
- Export package now contains: ADT + WDT + WOT + WHM + JSON files
- Both Blizzard-compatible (for existing servers) and open format
(for wowee-native loading and redistribution)
- File > Export Content Pack (.wcp) saves zone + packs into WCP archive
- Auto-saves zone first, then bundles into the novel WCP format
- WCP is a custom format unique to wowee (not MPQ, not CASC)
- Output: output/MapName.wcp ready for distribution
- Toast notification on success/failure
- Ctrl+Shift+Z redo now works globally (was only in Sculpt mode)
- Ctrl+Z undo works in all modes with toast confirmation
- centerOnTerrain() uses actual mesh chunk positions instead of formula
- Toast shows "Undo" / "Redo" / "Undo placement" for user feedback
- Camera now positions at the center of actual loaded terrain chunks
instead of using formula-based coordinates that can be wrong for
instanced maps
- Falls back to formula if no valid chunks loaded
- Fixes camera starting far from terrain on some maps
- ADT doodad/WMO positions now converted from ADT space to render coords
via core::coords::adtToWorld() — fixes objects appearing at wrong positions
when loading existing WoW maps
- Selecting a map in the Load dialog now auto-finds the first valid tile
(no more clicking "Find Tile" manually — it's automatic)
- Better error messages with toast for failed terrain loads
- Validates mesh has valid chunks before attempting GPU upload
Root cause of ADT loading failures: instanced maps (dungeons, raids)
have arbitrary internal coord values (e.g. tile 62,0 for a file named
_28_27.adt). The terrain mesh generator uses these coords to compute
world positions, resulting in chunks placed thousands of units away
from the camera → "Failed to upload terrain to GPU".
Fix: override terrain_.coord with the tileX/tileY from the filename
before mesh generation. This ensures chunks are positioned correctly
regardless of what the ADT file's internal header says.
- File > Generate Complete Zone: runs the full procedural pipeline
in one click: noise → smooth (3 passes) → recalc normals →
height-based auto-paint (sand/grass/rock/snow) → slope-based
cliff paint (rock on steep faces)
- Creates a fully textured, natural-looking zone from flat terrain
- Removed stale quickGenerate checkbox from New Terrain dialog
- NPC placement now only updates cheap marker geometry (no M2 reload)
- Full M2 rebuild only triggers when PLACED OBJECT count changes
(not NPC count — NPCs use markers, not M2 instances for now)
- Split lastObjectCount_ into lastObjCount_ + lastNpcCount_ to track
objects and NPCs independently
- Prevents the destructive clear+reload cycle that caused GPU crashes
when rapidly placing multiple NPCs
Root cause of GPU crashes (VK_ERROR_DEVICE_LOST): every NPC placement
triggered a full clear+reload of ALL M2 models. After several cycles
the GPU state corrupted, causing vertex explosions and device lost.
Fixes:
- NPC placement now only updates cheap marker geometry (no M2 reload)
- Full M2 rebuild only happens when object COUNT changes (not every click)
- clearAllObjects() properly resets viewport, placer, spawner, markers,
and history in one call with vkDeviceWaitIdle fence
- New Terrain uses clearAllObjects() for consistent reset
- Clear All menu item calls clearAllObjects()
- M2 vertex validation: rejects models with NaN/infinite/extreme
vertex positions before GPU upload (prevents vertex explosions)
- NPC marker building extracted to updateNpcMarkers() method
(can be called independently without M2 rebuild)
- Middle mouse drag orbits camera around the terrain point under cursor
(or 100 units ahead if no terrain hit)
- Maintains distance from pivot while rotating yaw/pitch
- Much more intuitive for inspecting terrain features, placed objects,
and NPC positions from different angles
- Works alongside right-drag (free look) and WASD (fly)
- New Quest mode (key 6) with full quest creation panel:
- Title, description, required level
- Quest giver / turn-in NPC ID linkage
- Up to 4 objectives: Kill, Collect, Talk, Explore, Escort, Use Object
- Rewards: XP and gold
- Quest chain support via nextQuestId linking
- Quest list showing all created quests with level and objective count
- Save quests to JSON (included in Export Zone package)
- Foundation for campaign system: create quest chains across NPCs,
link objectives to placed creatures, build storylines
- "Center on Terrain" (Home key or View menu): resets camera to center
of loaded tile at 300 units altitude with 45-degree downward pitch.
Essential for recovering when camera gets lost in empty space.
- Toast confirmation on center action
- Scroll wheel now zooms camera (moves along look direction) instead
of adjusting speed. Much more intuitive for terrain editing.
- Shift+scroll adjusts camera speed (old behavior preserved)
- Click on minimap to teleport camera to that location on the terrain
- Zoom speed scales with current camera speed for consistent feel
- Loading an existing ADT now imports its MDDF (doodad) and MODF (WMO)
placements into the object placer with correct position/rotation/scale
- Allows editing zones that already have objects placed in them
- Mutable getObjects() accessor for bulk import operations
- Log shows imported doodad + WMO count on load