69051fd486
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.
755 lines
31 KiB
Markdown
755 lines
31 KiB
Markdown
# 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 at `0x00809f0c`)
|
|
- **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**:
|
|
1. `PushFrustumData()` - Save frustum state
|
|
2. `CalculateFrustumCorners(frustumBounds)` - Calculate view frustum
|
|
3. Loop 0x20 (32) times through game object managers:
|
|
- `ProcessActiveGameObjects()` - Update active objects
|
|
- `ProcessInactiveGameObjects()` - Update inactive objects
|
|
- `ValidateGameObject()` - Validate object states
|
|
- **`CullObjectsToRenderList(manager, 1)`** - Cull objects type 1
|
|
- **`CullObjectsToRenderList(manager, 0)`** - Cull objects type 0
|
|
- **`CullObjectsToRenderList(manager, 2)`** - Cull objects type 2
|
|
- `ProcessStaticObjectsCulling()` - Cull static world objects
|
|
4. `PopFrustumStack()` - Restore frustum state
|
|
5. **`CullAndProcessWorldChunks()`** - 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 structure
|
|
- `renderListIndex`: Object type (0, 1, or 2) - likely terrain objects, WMOs, models
|
|
- **Implementation**:
|
|
1. Iterates through object linked list
|
|
2. Copies object bounds via `CopyChunkBounds()`
|
|
3. Tests against frustum with `IsSphereInFrustum()` and `FrustumCullBoundingBox()`
|
|
4. 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**:
|
|
1. Iterates through static objects
|
|
2. Frustum tests with `IsSphereInFrustum()` and `FrustumCullBoundingBox()`
|
|
3. Checks render flags (`g_renderFlags & 0x20`)
|
|
4. 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 `CM2SceneRenderDraw` for 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
|
|
|
|
### 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
|
|
|
|
#### **CM2Scene_DrawModelBatch**
|
|
- **Address**: `0x0070cf70`
|
|
- **Called by**: `RenderBatches` (0x0070b630)
|
|
- **Signature**: `void __fastcall CM2Scene_DrawModelBatch(void *renderContext)`
|
|
- **Role**: Renders a single M2 model batch
|
|
- **Rendering Steps**:
|
|
1. Retrieves batch data from render context (offset 0x3300, 0x3338, 0x3340)
|
|
2. Calculates mesh bounds via `calculateMeshBounds()`
|
|
3. Sets up view frustum clipping planes
|
|
4. Applies bone multiplier and scaling
|
|
5. Calls `CM2Scene_SetupRenderState()`
|
|
6. Sets texture transforms (2 stages)
|
|
7. Executes render via function pointer at renderContext+0x40+0x11c
|
|
8. Clears texture transforms
|
|
9. 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**:
|
|
1. Calculates chunk bounds based on camera position
|
|
2. Clamps to valid ADT tile range (0-63 in each dimension)
|
|
3. Gets active camera via `CGWorldFrame_GetActiveCamera()`
|
|
4. Sets up view/projection matrices
|
|
5. Processes terrain chunks within frustum
|
|
6. 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**: `0x0068db20` region (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+0x11c` that 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) == 0` OR object type != 0
|
|
- **List 2 (Special)**:
|
|
- Head: `PTR_00c7cb54`
|
|
- Offset: `PTR_00c7cb50`
|
|
- Used when: `(g_renderFlags & 0x20) != 0` AND object type == 0
|
|
- **Processing List**: `PTR_00c7cb58`
|
|
- Processed at end of `ProcessStaticObjectsCulling`
|
|
- Objects rendered via `executeRenderCommands()`
|
|
- **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**:
|
|
1. Calls `BeginRender()` to start rendering frame
|
|
2. Sets alpha blending if `g_renderFlags` has high bit set
|
|
3. Iterates through render list at `PTR_00c7cae0`
|
|
4. 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
|
|
6. Calls `EndRender()` to finish rendering
|
|
- **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 `ProcessStaticObjectsCulling` as a loop:
|
|
```c
|
|
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 `RenderObjectsWithLOD` called?
|
|
- **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_ExecuteRenderPass` get called in relation to `ProcessWorldWithFrustum`?
|
|
- **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 `0x00809f0c` or 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:
|
|
|
|
1. **Find and hook terrain renderer** → Render terrain to depth buffer
|
|
2. **Find and hook WMO renderer** → Render WMOs to depth buffer
|
|
3. **Hook `RenderBatches` or `CM2SceneRenderDraw`** → Before model batch rendering:
|
|
- Save depth buffer state
|
|
- Render outline models with custom depth comparison
|
|
- Restore depth buffer
|
|
- Render normal models
|
|
4. **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 `UpdateRenderCallback` usage
|
|
- 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 `CM2SceneRenderDraw` for model batches
|
|
- Implement selective depth testing based on geometry type
|
|
- Test outline visibility through players but not terrain/WMOs
|
|
|
|
## Search Patterns for Further Investigation
|
|
|
|
```typescript
|
|
// 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**
|
|
1. **[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
|
|
|
|
2. **[OK] Terrain Renderer**: `CullAndProcessWorldChunks` (0x00683040)
|
|
- Primary ADT terrain chunk culling and rendering
|
|
- Called AFTER object culling (currently renders terrain depth last)
|
|
|
|
3. **[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
|
|
|
|
4. **[OK] Static Culling**: `ProcessStaticObjectsCulling` (0x00683bf0)
|
|
- Handles WMO groups and static doodads
|
|
- **Contains inline WMO renderer** (`executeRenderCommands` loop at end)
|
|
- Adds to render lists at PTR_00c7cadc/PTR_00c7cb54
|
|
|
|
5. **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
|
|
|
|
6. **[OK] M2 Model Pipeline**: Complete chain from `CM2Scene_ExecuteRenderPass` → `CM2SceneRenderDraw` → `RenderBatches` → `CM2Scene_DrawModelBatch`
|
|
|
|
7. **[OK] Render Lists Mapped**: Documented 7+ global render list structures and their usage
|
|
|
|
### Updated Rendering Flow
|
|
|
|
Based on discoveries, the likely flow is:
|
|
|
|
1. **Culling Phase** (ProcessWorldWithFrustum):
|
|
- Cull objects to render lists (indices 0, 1, 2)
|
|
- Cull static objects (WMOs) to separate lists
|
|
- Cull terrain chunks
|
|
|
|
2. **Rendering Phase** (after ProcessWorldWithFrustum):
|
|
- `RenderObjectsWithLOD()` processes object render lists
|
|
- `ProcessStaticObjectsCulling()` renders WMOs inline
|
|
- `CullAndProcessWorldChunks()` renders terrain
|
|
- (Order still unclear - need to find orchestrator)
|
|
|
|
3. **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**:
|
|
1. **RenderObjectsWithLOD** (0x00684510) - Object rendering
|
|
2. **ProcessStaticObjectsCulling** (0x00683bf0) - WMO/building rendering
|
|
3. **CullAndProcessWorldChunks** (0x00683040) - Terrain rendering
|
|
|
|
**Strategy**: Hook all three to control render order:
|
|
1. Terrain FIRST (write depth)
|
|
2. WMOs/buildings (write depth)
|
|
3. Outline pass (custom depth test to show through players only)
|
|
4. 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+0x11c` in 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+0x11c` for 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_00c7cad0` list 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`:
|
|
```c
|
|
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_00c7cae0` list
|
|
- 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+0x11c` for 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:
|
|
1. Call original (performs all culling)
|
|
2. Manually trigger: Terrain render → WMO render → Outline pass → Object/player render
|
|
|
|
### Option B: Mid-Level (More Control)
|
|
Hook three key functions:
|
|
1. `CullAndProcessWorldChunks` (0x00683040) - Terrain
|
|
2. `ProcessStaticObjectsCulling` (0x00683bf0) - WMOs (inline rendering at end)
|
|
3. `RenderObjectsWithLOD` (0x00684510) - Objects/players
|
|
|
|
### Option C: Low-Level (Maximum Control)
|
|
Hook D3D device:
|
|
1. Hook BeginScene/EndScene
|
|
2. Hook DrawIndexedPrimitive
|
|
3. Track render state to identify terrain/WMO/object draws
|
|
4. Manually control depth buffer between passes
|
|
|
|
### For Selective Occlusion (Recommended: Option A + B)
|
|
1. Hook `ProcessWorldWithFrustum` to control order
|
|
2. Hook `ProcessStaticObjectsCulling` to render WMOs to depth first
|
|
3. Hook `RenderObjectsWithLOD` to inject outline pass before normal objects
|
|
4. 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.
|