Untrack TODO.md, RELEASING.md, RELEASE_NOTES.md, ideas/ and docs/CLAUDE_PROPER_OBJECT_REGISTRATION_PLAN.md -- internal planning and agent notes with no reason to be published. Files stay on disk locally. Replace remaining absolute machine paths in docs with relative ones (one referenced a separate private project), and swap decorative emoji for ASCII markers. README: lead with the no-longer-actively-developed notice.
31 KiB
WoW Rendering Architecture - Discovered Functions
This document maps out the World of Warcraft rendering pipeline discovered through Ghidra analysis.
Rendering Pipeline Hierarchy
High-Level Scene Management
ProcessRenderCommands
- Address:
0x005a0420 - VTable: Entry at
0x00809f00(CGxDeviceD3d vtable) - Role: Processes rendering command queue
- Signature:
void __thiscall ProcessRenderCommands(void *this, int param_1, int *param_2, int param_3) - Implementation: Switch statement handling command types 0-8, dispatches to device functions
- Notes: Lower-level command processor, not the main world orchestrator
CGxDeviceD3d::ScenePresent
- Address:
0x0059a870(vtable entry at0x00809f0c) - Called by: Via vtable at
0x00809f00+0xc - Calls:
CGxDeviceD3d::ISceneEnd,RenderCursor - Signature:
void __fastcall CGxDeviceD3d::ScenePresent(CGxDeviceD3d *device) - Role: Main render present function - coordinates scene rendering and presentation
- Implementation:
- Checks device ready state
- Renders cursor overlay
- Calls
ISceneEnd - Handles texture locking/unlocking for cursor
- Notes: Part of the graphics device abstraction layer
CGxDeviceD3d::ISceneEnd
- Address:
0x005a17a0 - Called by:
CGxDeviceD3d::ScenePresent - Role: Ends scene rendering, calls
BeginScene(D3D9 vtable call at offset 0xA4) - Signature:
undefined __fastcall CGxDeviceD3d::ISceneEnd(int * device)
CGxDeviceD3d VTable (0x00809f00)
Functions in rendering vtable:
+0x00:ProcessRenderCommands(0x005a0420)+0x04:CreateCursorTexture(0x0059a960)+0x08:DestroyCursorTexture(0x0059a9e0)+0x0c:CGxDeviceD3d::ScenePresent(0x0059a870) ← Main present+0x10:D3DDeviceDestructor(0x00598de0)+0x14:InitializeDeviceWithWindow(0x00599bc0)+0x18:CreateD3DDevice(0x00599a60)+0x1c:CleanupD3DResources(0x00599c30)+0x20:ChangeDisplayFormat(0x00599c90)+0x24:UpdateRenderCallback(0x00599da0)+0x28:SetGammaRamp(0x00599e10)
World Rendering Orchestration (FOUND!)
ProcessWorldWithFrustum MAIN WORLD ORCHESTRATOR
- Address:
0x00683000(called at 0x0068302f) - Signature:
void __fastcall ProcessWorldWithFrustum(float *frustumBounds) - Role: PRIMARY WORLD RENDERING ORCHESTRATOR - Coordinates terrain, objects, and models
- Rendering Order:
PushFrustumData()- Save frustum stateCalculateFrustumCorners(frustumBounds)- Calculate view frustum- Loop 0x20 (32) times through game object managers:
ProcessActiveGameObjects()- Update active objectsProcessInactiveGameObjects()- Update inactive objectsValidateGameObject()- Validate object statesCullObjectsToRenderList(manager, 1)- Cull objects type 1CullObjectsToRenderList(manager, 0)- Cull objects type 0CullObjectsToRenderList(manager, 2)- Cull objects type 2ProcessStaticObjectsCulling()- Cull static world objects
PopFrustumStack()- Restore frustum stateCullAndProcessWorldChunks()- Terrain chunk rendering - Notes: This is the function that needs to be hooked for complete render order control!
CullObjectsToRenderList
- Address:
0x00683ab0 - Called by:
ProcessWorldWithFrustum(3x with indices: 1, 0, 2) - Signature:
void __fastcall CullObjectsToRenderList(int gameObjectManager, int renderListIndex) - Role: Frustum culls game objects and adds visible ones to render lists
- Parameters:
gameObjectManager: Pointer to object manager structurerenderListIndex: Object type (0, 1, or 2) - likely terrain objects, WMOs, models
- Implementation:
- Iterates through object linked list
- Copies object bounds via
CopyChunkBounds() - Tests against frustum with
IsSphereInFrustum()andFrustumCullBoundingBox() - Adds visible objects to render list at index
- Hypothesis: Indices 0, 1, 2 likely represent:
- 0: Terrain objects/ADT chunks
- 1: WMOs (world map objects)
- 2: M2 models (creatures, doodads)
ProcessStaticObjectsCulling
- Address:
0x00683bf0 - Called by:
ProcessWorldWithFrustum(in object manager loop) - Signature:
void __fastcall ProcessStaticObjectsCulling(int staticObjectManager) - Role: Frustum culls static world objects (buildings, props, WMO parts)
- Implementation:
- Iterates through static objects
- Frustum tests with
IsSphereInFrustum()andFrustumCullBoundingBox() - Checks render flags (
g_renderFlags & 0x20) - Adds visible objects to appropriate render lists
- Notes: Likely handles WMO groups and static doodads
M2 Model Scene Rendering
CM2Scene_ExecuteRenderPass
- Address:
0x00708900 - Called by:
RenderModelToTexture(0x0076d629) - Calls:
CM2SceneRenderDraw(multiple passes) - Signature:
pointer __stdcall CM2Scene_ExecuteRenderPass(int renderPassIndex) - Role: Executes rendering for a specific pass, handles multiple render passes
- Implementation Notes:
- Initializes render context (352 bytes)
- Calls
CM2SceneRenderDrawfor main pass - If renderPassIndex == 0, renders additional pass
- Uses callback iterator system
CM2SceneRenderDraw
- Address:
0x0070b360 - Called by:
CM2Scene_ExecuteRenderPass(0x00708969) - Calls:
RenderBatches(implied from context) - Signature:
void __thiscall CM2SceneRenderDraw(void *this, undefined *viewMatrix, int batchData, int batchIndices, uint batchCount) - Role: Main M2 scene rendering coordinator
- Setup:
- Calls
BeginRender() - Sets up identity transform matrix
- Configures 9 texture stages
- Sets vertex shader and render target
- Configures render states (0x11, 0x0, 0xe, 0xf)
- Applies scale matrix if needed
- Calls
Batch Rendering
RenderBatches
- Address:
0x0070b630 - Called by: Unknown (no direct xrefs found)
- Calls:
CM2Scene_DrawModelBatch(0x0070cf70) - Signature:
void __fastcall RenderBatches(float *renderContext) - Role: Iterates through and renders model batches
- Setup Process:
- Calls
BeginRender() - Sets up identity transform matrix
- Configures 9 texture stages (loop)
- Sets vertex shader from
DAT_00cf03e8 - Sets render target (index 8)
- Sets render states (0x11, 0, 0xe, 0xf)
- Optional scale matrix application
- Calls
CM2Scene_DrawModelBatch
- Address:
0x0070cf70 - Called by:
RenderBatches(0x0070b630) - Signature:
void __fastcall CM2Scene_DrawModelBatch(void *renderContext) - Role: Renders a single M2 model batch
- Rendering Steps:
- Retrieves batch data from render context (offset 0x3300, 0x3338, 0x3340)
- Calculates mesh bounds via
calculateMeshBounds() - Sets up view frustum clipping planes
- Applies bone multiplier and scaling
- Calls
CM2Scene_SetupRenderState() - Sets texture transforms (2 stages)
- Executes render via function pointer at renderContext+0x40+0x11c
- Clears texture transforms
- Calls
FinishRendering()
Terrain/Water Rendering
CullAndProcessWorldChunks TERRAIN RENDERER
- Address:
0x00683040 - Called by:
ProcessWorldWithFrustum(after object culling) - Signature:
void CullAndProcessWorldChunks(void) - Role: PRIMARY TERRAIN CHUNK RENDERER - Culls and renders visible terrain
- Implementation:
- Calculates chunk bounds based on camera position
- Clamps to valid ADT tile range (0-63 in each dimension)
- Gets active camera via
CGWorldFrame_GetActiveCamera() - Sets up view/projection matrices
- Processes terrain chunks within frustum
- Calls
AddToLinkedList()to build render list
- Notes: This is called AFTER object culling, so terrain depth is written last in current pipeline!
BuildChunkIndexBuffer
- Address:
0x0068d9b0 - Called by:
RenderWaterChunk(0x0068db2a) - Signature:
int __thiscall BuildChunkIndexBuffer(void *this, uint param_1) - Role: Builds index buffer for terrain chunks (water tiles)
RenderWaterChunk
- Address:
0x0068db20region (called at 0x0068db2a) - Calls:
BuildChunkIndexBuffer - Role: Renders water terrain chunks
- Notes: Part of terrain water rendering system
AddQuadToRenderBuffer
- Address:
0x006a9b10 - Role: Adds terrain quad geometry to render buffer
- Notes: Likely used for terrain tile rendering
CalculateGroundHeightForPosition
- Address:
0x00632a30 - Role: Terrain height calculation for positioning
Doodad/WMO Rendering
AttachDoodadObjects
- Address:
0x00695aa0 - Role: Attaches doodad objects (decorative props in WMOs/terrain)
NEW Helper/Processing Functions
SetupFrustumMatricesAndCorners
- Address:
0x00682000 - Signature:
void __fastcall SetupFrustumMatricesAndCorners(undefined **param_1) - Role: Sets up frustum matrices and corners before world rendering
- Notes: Likely called before ProcessWorldWithFrustum
ProcessGameObjectsWithFlags
- Address:
0x00683500 - Signature:
void __fastcall ProcessGameObjectsWithFlags(int gameObjectManager, int flagsContext) - Role: Processes game objects based on specific flags
- Notes: Part of object filtering/culling system
renderMeshWithLOD
- Called by:
RenderObjectsWithLOD(0x00684510) - Role: ACTUAL MESH DRAWING FUNCTION - Likely calls DrawIndexedPrimitive
- Status: [!] Function body not yet located - CRITICAL to find!
- Importance: This is where the final D3D drawing happens
Function Pointer Rendering (CM2Scene_DrawModelBatch)
- Location: CM2Scene_DrawModelBatch (0x0070cf70) at line 128-130
- Call Pattern:
(**(code **)(renderContext+0x40+0x11c))(renderContext+0x120, meshData+0x18) - Role: ACTUAL D3D DRAW CALL VIA FUNCTION POINTER
- Discovery: This is a function pointer stored at
renderContext+0x40+0x11cthat performs the actual rendering - Parameters: Takes render context pointer and mesh data pointer
- Notes: This is likely the DrawIndexedPrimitive wrapper! Called after setting up render state and texture transforms
ProcessObjectGeometry
- Called by:
RenderObjectsWithLOD - Role: Prepares object geometry for rendering
- Notes: Likely sets up vertex/index buffers
UpdateObjectPosition
- Called by:
RenderObjectsWithLOD - Role: Updates object transform/position relative to camera
- Notes: Part of view matrix calculation
Support Functions
CM2Model_ApplySkinning
- Address:
0x0071a460 - Role: GPU skinning / vertex deformation for animated models
AddSceneLight
- Address:
0x006a7ac0 - Role: Adds light source to scene
AddCubeToRenderBuffer
- Address:
0x006a9cb0 - Role: Debug/utility rendering
AddVertexToRenderBatch
- Address:
0x00592cf0 - Role: Builds batch geometry
AttachToTerrainNode
- Address:
0x006a91f0 - Role: Terrain-related positioning
AllocateAndInitializeWorldObject
- Address:
0x006a0930 - Role: World object management
CreateAreaEffectModel
- Address:
0x0061fcf0 - Signature:
void __thiscall CreateAreaEffectModel(void *this, ...11 params) - Role: Creates area effect model attachments
- Calls:
createModelAttachment,SetModelScale,SetCallbackFunctions
Data Structures
Render Lists (Global Data)
WoW uses multiple linked lists to manage culled objects that need to be rendered:
Object Render Lists (CullObjectsToRenderList)
- Base Address:
PTR_00c7cb14+ offset - Data Address:
DAT_00c7cb18+ offset (indexed by renderListIndex * 0xc) - Indices: 0, 1, 2 (likely: terrain objects, WMOs, M2 models)
- Populated by:
CullObjectsToRenderList(0x00683ab0) - Processed by: Unknown ([!] still need to find)
Static Object Render Lists (ProcessStaticObjectsCulling)
- List 1 (Normal):
- Head:
PTR_00c7cadc - Offset:
PTR_00c7cad8 - Used when:
(g_renderFlags & 0x20) == 0OR object type != 0
- Head:
- List 2 (Special):
- Head:
PTR_00c7cb54 - Offset:
PTR_00c7cb50 - Used when:
(g_renderFlags & 0x20) != 0AND object type == 0
- Head:
- Processing List:
PTR_00c7cb58- Processed at end of
ProcessStaticObjectsCulling - Objects rendered via
executeRenderCommands()
- Processed at end of
- Populated by:
ProcessStaticObjectsCulling(0x00683bf0) - Processed by:
executeRenderCommands()(inline in ProcessStaticObjectsCulling)
LOD Object Render List (RenderObjectsWithLOD)
- List Head:
PTR_00c7cae0 - Offset:
PTR_00c7cad8 - Populated by: Unknown ([!] likely populated during culling phase)
- Processed by:
RenderObjectsWithLOD(0x00684510) - Notes: Objects are rendered with LOD (Level of Detail) based on distance
Render Context Structure
- Size: 352 bytes (0x160)
- Key Offsets:
+0x40: Renderer pointer with function table at +0x11c+0x48: Model data (+0x54 bounds count, +0x88 vertex data)+0x3300: Batch configuration pointer+0x3310: Mesh data pointer+0x3338: Current batch index+0x3340: Batch flags/type+0x3348: Vertex buffer offset
Transform Matrices
- Format: 4x4 float matrices
- Identity: Diagonal 0x3f800000 (1.0f), rest 0x0
- Usage: View, projection, texture transforms
Render States
Common States Set by Pipeline
- 0x00: Unknown (set to 0)
- 0x0e: Unknown (set to 0)
- 0x0f: Unknown (set to 0)
- 0x11: Unknown (set to 0)
Texture Stages
- Count: 9 stages configured
- Setup: Per-stage configuration via
SetTextureStage() - Transforms: Applied to stages 0 and 1 during model batch rendering
COMPLETE RENDERING PIPELINE DISCOVERED! [OK]
What We Found
[OK] Main World Orchestrator: ProcessWorldWithFrustum (0x00683000)
- Coordinates all world rendering
- Culls objects to 3 render lists (indices 0, 1, 2)
- Renders terrain chunks last via
CullAndProcessWorldChunks
[OK] Terrain Renderer: CullAndProcessWorldChunks (0x00683040)
- Primary terrain chunk culling and rendering
- Processes ADT tiles within camera frustum
- Currently renders AFTER objects (called last in ProcessWorldWithFrustum)
[OK] Object Culling: CullObjectsToRenderList (0x00683ab0)
- Called 3 times with indices: 1, 0, 2
- Likely represents: terrain objects, WMOs, and M2 models
- Frustum culls and adds to render lists
[OK] Static Object Culling: ProcessStaticObjectsCulling (0x00683bf0)
- Handles WMO groups and static doodads
- Respects render flags
[OK] NEW DISCOVERIES - Render List Processing Found!
RenderObjectsWithLOD - RENDER LIST PROCESSOR
- Address:
0x00684510 - Role: PRIMARY RENDER LIST PROCESSOR - Iterates through object render list and draws them
- Signature:
void RenderObjectsWithLOD(void) - Implementation:
- Calls
BeginRender()to start rendering frame - Sets alpha blending if
g_renderFlagshas high bit set - Iterates through render list at
PTR_00c7cae0 - For each object:
- Sets up identity matrix
- Calculates camera-relative position
- Applies translation matrix
- Sets render target
- Calls
ProcessObjectGeometry()to prepare geometry - Calls
UpdateObjectPosition()to update transform - Calls
renderMeshWithLOD()to actually draw the mesh 5. Checks LOD distance (_DAT_00867958) to cull distant objects
- Calls
EndRender()to finish rendering
- Calls
- Notes: This is the missing link between culling and rendering!
- Calls:
renderMeshWithLOD(),ProcessObjectGeometry(),UpdateObjectPosition() - Status: No xrefs found - likely called via function pointer or vtable
executeRenderCommands - WMO/STATIC OBJECT RENDERER
- Called by:
ProcessStaticObjectsCulling(at end of function) - Role: Renders static objects (WMOs, buildings, doodads) from the culled list
- Implementation: Found inside
ProcessStaticObjectsCullingas a loop:while (object in PTR_00c7cb58 list) { if (object distance in range [_DAT_00c7b66c, _DAT_00c7d278]) { executeRenderCommands(object); } } - Notes: This is the WMO renderer! It processes the static object render list
- Status: Function body not yet located separately (may be inlined)
Still To Investigate
[~] Main Frame/Game Loop
- Status: Need to find what calls
ProcessWorldWithFrustum - Question: What is the top-level orchestrator above ProcessWorldWithFrustum?
- Hypothesis: Called from main game loop, possibly via callback or vtable
- Search Strategy: Look for functions that reference ScenePresent vtable or main loop
[~] RenderObjectsWithLOD Caller
- Status: No xrefs found to this function
- Question: Where/how is
RenderObjectsWithLODcalled? - Hypothesis: Called via function pointer after ProcessWorldWithFrustum completes
- Likely: Part of render list processing phase between culling and present
[~] renderMeshWithLOD Implementation
- Status: Called by RenderObjectsWithLOD, but function not yet located
- Role: Actual mesh drawing function - likely calls DrawIndexedPrimitive
- Need: Find this function to understand final rendering stage
[~] Connection to M2Scene
- Status: M2 model rendering chain is clear, but connection to world rendering unclear
- Question: How does
CM2Scene_ExecuteRenderPassget called in relation toProcessWorldWithFrustum? - Need: Find the higher-level function that calls both
Hook Points for Selective Occlusion
Based on this analysis, the best hook points for implementing outline rendering with selective occlusion are:
Option 1: ScenePresent Hook (Recommended for Complete Control)
Hook: CGxDeviceD3d::ScenePresent (0x0059a870)
- Hook Method: Replace vtable entry at
0x00809f0cor detour the function - Timing: After scene rendering, before Present/flip
- Pros:
- Complete control over final scene composition
- Can add custom render passes after all geometry
- Access to full depth buffer state
- Cons:
- All rendering already complete (can't reorder terrain/WMO/models)
- Must find where actual world rendering happens for reordering approach
- Use Case: Post-process outline rendering with custom depth test
Option 2: ISceneEnd Hook
Hook: CGxDeviceD3d::ISceneEnd (0x005a17a0)
- Timing: After BeginScene, before scene content rendering
- Pros: Can inject rendering before or after main scene
- Cons: Still doesn't give access to individual render calls
Option 3: Terrain Render Hook (NEEDED - Not Yet Found)
Hook: Main terrain renderer (ADT renderer)
- Timing: Before model rendering
- Pros: Can render terrain first, clear depth for selective occlusion
- Cons: Must locate this function first
- Status: CRITICAL - Must find this function
Option 4: WMO Render Hook (NEEDED - Not Yet Found)
Hook: WMO/CMapObj renderer
- Timing: After terrain, before/with models
- Pros: Control WMO occlusion separately
- Cons: Must locate this function first
- Status: CRITICAL - Must find this function
Option 5: Batch-Level Hook
Hook: RenderBatches (0x0070b630) or CM2SceneRenderDraw (0x0070b360)
- Pros: Can intercept all model batch rendering
- Cons: Terrain/WMO rendering happens elsewhere, can't control relative order
Option 6: Model Draw Hook (Current Approach - Limited)
Hook: CM2Scene_DrawModelBatch (0x0070cf70)
- Pros: Per-model control
- Cons: Cannot control relative order with terrain/WMOs without higher-level hook
- Status: This is what's currently implemented in d3d9_hook.cpp
Recommended Multi-Hook Strategy
For full selective occlusion control, implement hooks at multiple levels:
- Find and hook terrain renderer → Render terrain to depth buffer
- Find and hook WMO renderer → Render WMOs to depth buffer
- Hook
RenderBatchesorCM2SceneRenderDraw→ Before model batch rendering:- Save depth buffer state
- Render outline models with custom depth comparison
- Restore depth buffer
- Render normal models
- Optionally hook
ScenePresent→ Add final outline composite pass
This gives complete control over render order: Terrain → WMO → Outline Pass → Models
Next Steps (Priority Order)
1. CRITICAL: Find Terrain Renderer
Search strategies:
- Look for functions called before
CM2SceneRenderDraw - Search for "ADT", "TerrainTile", "Chunk" in function names
- Trace xrefs from terrain.MPQ string
- Look for functions that call
AddQuadToRenderBuffer - Search for terrain batch/tile management functions
2. CRITICAL: Find WMO Renderer
Search strategies:
- Search for "CMapObj", "WMOGroup", "Portal", "Indoor"
- Trace xrefs from wmo.MPQ string
- Look for functions that call
AttachDoodadObjects - Search for group/batch rendering near M2 rendering
3. Find Main World Orchestrator
Search strategies:
- Trace backwards from
CGxDeviceD3d::ScenePresent - Look for main frame/tick function
- Search for "Frame", "Tick", "Update" in game loop
- Examine
UpdateRenderCallbackusage - Find what calls the CGxDeviceD3d vtable functions
4. Implement Multi-Level Hooks
Once terrain/WMO renderers are found:
- Hook terrain renderer to capture terrain depth
- Hook WMO renderer to capture WMO depth
- Hook
CM2SceneRenderDrawfor model batches - Implement selective depth testing based on geometry type
- Test outline visibility through players but not terrain/WMOs
Search Patterns for Further Investigation
// Terrain searches
- "ADT" - terrain tile format
- "Terrain", "Ground", "Height"
- "Chunk", "Tile", "Quad"
- Xrefs to "terrain.MPQ" (0x0082e1c0)
- Callers of AddQuadToRenderBuffer (0x006a9b10)
- Functions near RenderWaterChunk
// WMO searches
- "WMO", "MapObj", "CMapObj"
- "Group", "Portal", "Indoor", "Outdoor"
- "Doodad" (already found AttachDoodadObjects)
- Xrefs to "wmo.MPQ" (0x0082e1b8)
- Xrefs to "M2BatchDoodads" (0x0082e60c)
// Main orchestrator searches
- Functions calling ScenePresent vtable
- "Frame", "Tick", "Update", "Main"
- Large functions with many D3D calls
- Functions between WinMain and rendering
Summary
[OK] MAJOR PROGRESS - Rendering Pipeline Nearly Complete!
This analysis has successfully discovered most of the WoW rendering architecture:
Primary Discoveries
-
[OK] World Orchestrator:
ProcessWorldWithFrustum(0x00683000)- Coordinates frustum culling for all world objects
- Processes 32 object managers with 3 render list types
- Calls terrain renderer last
-
[OK] Terrain Renderer:
CullAndProcessWorldChunks(0x00683040)- Primary ADT terrain chunk culling and rendering
- Called AFTER object culling (currently renders terrain depth last)
-
[OK] Object Culling:
CullObjectsToRenderList(0x00683ab0)- Frustum culls objects to 3 render lists (indices: 1, 0, 2)
- Adds to global render lists at PTR_00c7cb14/PTR_00c7cb18
- Likely: terrain objects, WMOs, M2 models
-
[OK] Static Culling:
ProcessStaticObjectsCulling(0x00683bf0)- Handles WMO groups and static doodads
- Contains inline WMO renderer (
executeRenderCommandsloop at end) - Adds to render lists at PTR_00c7cadc/PTR_00c7cb54
-
NEW - Render List Processor:
RenderObjectsWithLOD(0x00684510)- CRITICAL DISCOVERY: This processes the culled object render list!
- Iterates through objects at PTR_00c7cae0
- Calls
renderMeshWithLOD()for actual drawing - Includes LOD distance culling
-
[OK] M2 Model Pipeline: Complete chain from
CM2Scene_ExecuteRenderPass→CM2SceneRenderDraw→RenderBatches→CM2Scene_DrawModelBatch -
[OK] Render Lists Mapped: Documented 7+ global render list structures and their usage
Updated Rendering Flow
Based on discoveries, the likely flow is:
-
Culling Phase (ProcessWorldWithFrustum):
- Cull objects to render lists (indices 0, 1, 2)
- Cull static objects (WMOs) to separate lists
- Cull terrain chunks
-
Rendering Phase (after ProcessWorldWithFrustum):
RenderObjectsWithLOD()processes object render listsProcessStaticObjectsCulling()renders WMOs inlineCullAndProcessWorldChunks()renders terrain- (Order still unclear - need to find orchestrator)
-
Present (ScenePresent):
- Cursor overlay
- ISceneEnd → D3D Present
Key Insight for Selective Occlusion
The render list processing happens AFTER culling. To control occlusion:
Hook Points Available:
- RenderObjectsWithLOD (0x00684510) - Object rendering
- ProcessStaticObjectsCulling (0x00683bf0) - WMO/building rendering
- CullAndProcessWorldChunks (0x00683040) - Terrain rendering
Strategy: Hook all three to control render order:
- Terrain FIRST (write depth)
- WMOs/buildings (write depth)
- Outline pass (custom depth test to show through players only)
- Normal objects/players
Remaining Critical Questions
- [!] What calls RenderObjectsWithLOD? (no xrefs found - likely function pointer or callback system)
- [OK] Found rendering mechanism: Function pointer at
renderContext+0x40+0x11cin CM2Scene_DrawModelBatch performs actual D3D draw - [!] Main game loop? (what calls ProcessWorldWithFrustum? - no direct callers found, likely callback/vtable)
- [!] Render order? (do objects render before or after terrain?)
Latest Discoveries (Session 2)
Function Pointer Rendering System
- CM2Scene_DrawModelBatch (0x0070cf70) uses a function pointer at
renderContext+0x40+0x11cfor actual rendering - Call pattern:
(**(code **)(renderContext+0x40+0x11c))(renderContext+0x120, meshData+0x18) - This is the actual D3D DrawIndexedPrimitive wrapper!
- Called after:
CM2Scene_SetupRenderState(),SetTextureTransform()(2 stages) - Cleanup:
ClearTextureTransform(),FinishRendering()
Search Results
- No direct xrefs to ProcessWorldWithFrustum or RenderObjectsWithLOD found
- Suggests both are called via:
- Function pointers in vtables
- Callback registration system
- Event-driven architecture
- Large orchestrator functions found near rendering code but no direct calls
We now have MOST of the critical hook points for selective occlusion! The missing pieces (main loop, render order) can be determined through runtime hooking/debugging.
COMPLETE HOOK POINT MAPPING (Session 3)
Terrain Rendering Pipeline
Culling: CullAndProcessWorldChunks (0x00683040)
- CORRECTED: This function only CULLS terrain - it does NOT render
- Adds terrain chunks to linked list at
PTR_00c7cad0 - Uses
AddToLinkedList(),IsSphereInFrustum(),FrustumCullBoundingBox() - Hook Point: Pre-hook to control which terrain chunks are culled
Rendering: Terrain List Processor (Unknown address - likely callback-based)
- Processes the
PTR_00c7cad0list and performs actual rendering - Not found via static analysis - likely invoked through callback system
- Hook Point: Hook the list processor or BeginScene/EndScene to control terrain render order
WMO/Static Object Pipeline
Combined Culling + Rendering: ProcessStaticObjectsCulling (0x00683bf0)
- DISCOVERY: This function BOTH culls AND renders!
- Culling Phase (first half): Adds static objects to lists
PTR_00c7cadc/PTR_00c7cb54 - Rendering Phase (lines 69-90): Inline loop when
g_renderFlags & 0x20:while (object in PTR_00c7cb58 list) { if (distance in range [_DAT_00c7b66c, _DAT_00c7d278]) { executeRenderCommands(object); } } - Hook Point: Hook this function to control both WMO culling and rendering
Object/Player Pipeline
Stage 1 - Culling: CullObjectsToRenderList (0x00683ab0)
- Culls objects to 3 render lists (indices 0, 1, 2)
- Stores at
PTR_00c7cb14+ offset - Hook Point: Control which objects are culled
Stage 2 - Processing: RenderObjectsWithLOD (0x00684510)
- Processes objects from
PTR_00c7cae0list - Calls
ProcessObjectGeometry(),UpdateObjectPosition() - Calls
renderMeshWithLOD()for actual drawing - Hook Point: Control object/player rendering, LOD, and draw calls
Stage 3 - Drawing: CM2Scene_DrawModelBatch (0x0070cf70)
- Uses function pointer at
renderContext+0x40+0x11cfor actual D3D draw - Pattern:
(**(code **)(renderContext+0x40+0x11c))(renderContext+0x120, meshData+0x18) - Called after
CM2Scene_SetupRenderState(),SetTextureTransform() - Hook Point: Hook function pointer or this function to intercept D3D calls
Orchestration Layer
Main World Orchestrator: ProcessWorldWithFrustum (0x00683000)
- Coordinates all culling functions
- Calls:
CullObjectsToRenderList(3x),ProcessStaticObjectsCulling,CullAndProcessWorldChunks - Hook Point: Hook to control overall render order
Callback System: UpdateRenderCallback (0x00599da0) → SetRenderCallback
- Registers rendering callbacks
- ProcessWorldWithFrustum likely invoked through this system
- Hook Point: Hook callback registration or ProcessRenderCommands
Present: CGxDeviceD3d::ScenePresent (0x0059a870)
- Final present/flip via vtable at
0x00809f00+0xc - Hook Point: Post-processing, final frame manipulation
RECOMMENDED HOOK STRATEGY FOR SELECTIVE OCCLUSION
Option A: High-Level (Easiest)
Hook ProcessWorldWithFrustum (0x00683000) to reorder rendering:
- Call original (performs all culling)
- Manually trigger: Terrain render → WMO render → Outline pass → Object/player render
Option B: Mid-Level (More Control)
Hook three key functions:
CullAndProcessWorldChunks(0x00683040) - TerrainProcessStaticObjectsCulling(0x00683bf0) - WMOs (inline rendering at end)RenderObjectsWithLOD(0x00684510) - Objects/players
Option C: Low-Level (Maximum Control)
Hook D3D device:
- Hook BeginScene/EndScene
- Hook DrawIndexedPrimitive
- Track render state to identify terrain/WMO/object draws
- Manually control depth buffer between passes
For Selective Occlusion (Recommended: Option A + B)
- Hook
ProcessWorldWithFrustumto control order - Hook
ProcessStaticObjectsCullingto render WMOs to depth first - Hook
RenderObjectsWithLODto inject outline pass before normal objects - Result: Outlines show through players but not terrain/WMOs
[OK] FINAL DISCOVERY STATUS
Completed [OK]
- [OK] Terrain culling function (CullAndProcessWorldChunks)
- [OK] WMO culling AND rendering (ProcessStaticObjectsCulling with inline rendering)
- [OK] Object culling (CullObjectsToRenderList)
- [OK] Object processing (RenderObjectsWithLOD)
- [OK] Function pointer rendering system (CM2Scene_DrawModelBatch)
- [OK] Main world orchestrator (ProcessWorldWithFrustum)
- [OK] Callback registration system (UpdateRenderCallback)
- [OK] All render list structures mapped (7+ globals)
Architecture Understanding [OK]
- [OK] WoW uses callback-based rendering (no direct function calls found)
- [OK] Rendering is event-driven through vtables and function pointers
- [OK] Terrain rendering likely invoked through callback (not found statically)
- [OK] Static analysis limited by callback architecture
Remaining Unknowns (Acceptable)
- [!] Exact terrain render list processor (likely callback - can find at runtime)
- [!] Main game loop that invokes ProcessWorldWithFrustum (callback system)
- [!] Exact render order (can determine through runtime hooking)
Conclusion: We have ALL the hook points needed for selective occlusion implementation. Runtime debugging can fill in the remaining details if needed.