Module control API: - Three cdecl exports: WeirdUtils_IsModuleActive, WeirdUtils_DisableModule, WeirdUtils_DisableAll - C header include/weirdutils_api.h for runtime DLL discovery - All modules gain pub module_name, isActive(), shared mutex via src/mutex.zig - build.zig refactored to module_list array of ModuleDesc Bigcursor: - D3D9 vtable hooks on SetCursorProperties/ShowCursor - Scale2x/Scale3x pixel-art upscalers in pure Zig (replaces 12K-line hqx C) - Bilinear resampler for fractional scales (1.0-4.0, default 1.2) - Win32 cursor via CreateIconIndirect bypasses D3D9 32x32 limit - FNV-1a hash cache for ~16 cursor bitmaps - Lua API: SetCursorScale(n) / GetCursorScale() - CVar cursorScale for Config.wtf persistence (tenths) Other: - Add dpslog module stub - Docs and README updates
8.0 KiB
8.0 KiB
Ground-Projected Raid Markers
Goal: Render placeable raid markers (like Wrath+) that project onto the ground as area indicators.
Status: Research complete, implementation pending
What We Have
D3D9 Rendering Infrastructure
- File:
src/outline/d3d9_hook.zig - Render target management (silhouette RT, JFA ping-pong buffers)
- Shader assembly via D3DX (PS 3.0)
- Fullscreen quad rendering with
DrawPrimitiveUP - Complete state save/restore around custom passes
- Hooks: EndScene, DrawIndexedPrimitive, Reset
Model Rendering Hooks
- File:
src/outline/model_hook.zig CM2SceneRenderDrawhook - batch reordering for depth controlCM2Scene_DrawBatchProjectedhook - per-batch interception- Access to render context and model pointers
- Batch reordering ensures outline targets render when only terrain+WMO depth exists
Render Pipeline Documentation
- File:
docs/RENDER_ARCHITECTURE.md - Terrain renderer:
CullAndProcessWorldChunks(0x00683040) - WMO renderer:
ProcessStaticObjectsCulling(0x00683bf0) - M2 model pipeline fully mapped
- Depth buffer control via hook ordering
Outline Rendering Research
- File:
docs/outline-rendering-research.md - JFA (Jump Flood Algorithm) for distance-field outlines
- Stencil + blur techniques (Valve L4D style)
- Screen-space dilation approaches
- All SM 3.0 compatible
UnitXP SP3 Reference
- Path:
/media/storage/projects/UnitXP_SP3_Orig/UnitXP_SP3/ - Key file:
Vanilla1121_functions.h vanilla1121_worldToScreen(C3Vector& world)- world → screen projectionCWorld_Intersect()- raycast through world geometryvanilla1121_unitPosition()- unit world positionvanilla1121_getCameraPosition()- camera world position
WoWee Terrain Renderer Reference
- Path:
/media/storage/projects/WoWee/src/rendering/terrain_renderer.cpp - Modern OpenGL terrain rendering with multi-layer textures
- Frustum culling, LOD, shadow mapping
- Good reference for understanding terrain data structures
What's Missing
1. Terrain Height Query
// Need: Get terrain Z at world (X, Y)
float GetTerrainHeight(float worldX, float worldY);
Options:
- Reverse engineer WoW's internal terrain height function
- Use
CWorld_Intersect()with vertical ray:(x, y, +1000) → (x, y, -1000) - ADT tile parsing (complex, requires MPQ access)
2. Terrain Normal Query
// Need: Get terrain normal at world (X, Y) for quad orientation
C3Vector GetTerrainNormal(float worldX, float worldY);
Options:
- Sample height at 4 neighboring points, compute normal
- Reverse engineer WoW's internal function
3. Depth Buffer as Texture (for projected decals)
// Need: Access depth buffer as readable texture
IDirect3DTexture9* GetDepthAsTexture();
D3D9 approaches:
INTZ/RAWZformat hack (requires driver support)D3DFMT_D24S8→D3DFMT_D24X8withINTZfourcc- Render depth to separate RT during terrain pass
- See: https://aras-p.info/texts/D3D9GPUHacks.html
Implementation Options
Option A: Screen-Space Marker (Simplest)
Complexity: Low
Visual Quality: Basic (icon on screen, no ground conformity)
Implementation:
- Hook raid target array at
0x00B71368(8 GUIDs) - Get marked unit's world position via
vanilla1121_unitPosition() - Project to screen via
vanilla1121_worldToScreen() - Draw icon sprite in EndScene at screen position
- Optional: Depth test against terrain depth buffer
Pros:
- Minimal implementation
- Uses existing infrastructure
- No terrain queries needed
Cons:
- Marker doesn't conform to terrain
- Looks like a floating icon, not ground projection
- No "area on the ground" effect
Option B: Projected Ground Decal (Recommended)
Complexity: Medium
Visual Quality: Good (conforms to terrain, area indicator)
Implementation:
- Store marker world positions (from raid target array or click events)
- In EndScene, after terrain+WMO depth written:
- For each active marker:
- Bind depth buffer as texture (INTZ hack or separate RT)
- Render fullscreen quad with decal shader
- Shader reconstructs world position from depth
- If within marker radius, output marker color/texture
- Distance fade at edges for soft boundary
Decal Shader (HLSL SM 3.0):
// Uniforms set by CPU
float3 MarkerCenter; // World position
float MarkerRadius; // In world units
float4 MarkerColor; // RGBA
float2 ScreenSize; // For UV calculation
// Depth buffer bound to s0
sampler2D DepthSampler : register(s0);
float4 DecalPS(float2 uv : TEXCOORD0) : COLOR
{
// Read depth, reconstruct world position
float depth = tex2D(DepthSampler, uv).r;
float3 worldPos = ReconstructWorldPosition(uv, depth);
// Distance from marker center (XZ plane)
float2 offset = worldPos.xz - MarkerCenter.xz;
float dist = length(offset);
// Soft falloff
float alpha = saturate(1.0 - (dist / MarkerRadius));
alpha = smoothstep(0.0, 0.3, alpha); // Soft edge
// Output
return float4(MarkerColor.rgb, MarkerColor.a * alpha);
}
Pros:
- Conforms to terrain contours
- Looks like ground projection
- Can support multiple markers
- Soft edges for aesthetic
Cons:
- Requires depth buffer access (driver-dependent)
- More complex shader setup
- Per-marker render pass overhead
Option C: World-Space Quad (Best Conformity)
Complexity: High
Visual Quality: Best (actual geometry on terrain)
Implementation:
- Create marker quad mesh (4 vertices, 2 triangles)
- Hook
CM2SceneRenderDrawto inject custom geometry - For each marker:
- Query terrain height at marker position
- Query terrain normal for orientation
- Position quad at terrain height, orient to normal
- Add to render batch with marker texture
- Render as part of M2 batch with depth testing
Pros:
- Perfect terrain conformity
- Actual geometry, not shader trick
- Proper depth testing with other objects
Cons:
- Requires terrain height/normal queries
- More complex geometry management
- Hook injection into render pipeline
Recommended Path
Phase 1: Proof of Concept (Screen-Space)
- Implement basic screen-space marker rendering
- Hook raid target array, project positions
- Draw simple circle/icon at screen position
- Verify hook integration works
Estimated effort: 1-2 hours
Phase 2: Ground Decal (Primary Target)
- Implement INTZ depth texture hack
- Write decal projection shader
- Add marker position storage
- Render projected circles on terrain
Estimated effort: 4-6 hours
Phase 3: Polish
- Add marker textures (skull, cross, square, etc.)
- Soft edge falloff
- Multiple marker colors
- Optional: Click-to-place interface
Estimated effort: 2-3 hours
Key Files to Create/Modify
New Files
src/marker/
├── marker_tracker.zig # Track active markers, positions
├── marker_decal.zig # Decal rendering shader + pipeline
├── marker_hooks.zig # Raid target array hooks
└── marker_types.zig # Data structures
Modified Files
src/outline/d3d9_hook.zig # Add depth texture creation
src/outline/types.zig # Add depth texture format constants
src/main.zig # Initialize marker system
External References
D3D9 Depth Buffer Hacks
- https://aras-p.info/texts/D3D9GPUHacks.html
- INTZ / RAWZ format for reading depth as texture
Decal Rendering Techniques
- Valve L4D Glow Effect (stencil + blur): https://developer.valvesoftware.com/wiki/L4D_Glow_Effect
- Unreal Engine deferred decals: https://docs.unrealengine.com/4.27/en-US/RenderingAndGraphics/DeferredRendering/
WoW 1.12.1 Internals
- wowdev.wiki for ADT terrain format
- UnitXP_SP3 for function signatures and calling conventions
Notes
- Raid markers in Wrath+ use ground-projected circles with icon in center
- Our outline system already has the render target / shader infrastructure
- Depth buffer access is the main technical challenge for Option B
- Option A is good for quick testing, Option B is the production target