Feature: Map Geometry (.mapgeo) Parser and Builder
Summary
Implement a Rust parser and builder for Map Geometry environment files (.mapgeo), which contain 3D geometry data for League of Legends maps.
Reference Implementation
C# LeagueToolkit: https://github.com/LeagueToolkit/LeagueToolkit/blob/main/src/LeagueToolkit/Core/Environment/EnvironmentAsset.cs
Related types in the same repository:
EnvironmentAssetMesh.cs - Mesh data
EnvironmentAssetShaderTextureOverride.cs - Shader overrides
BucketedGeometry.cs - Spatial scene graph
GeometryBucket.cs - Individual bucket cells
PlanarReflector.cs - Reflection planes
Format Overview
- Magic:
OEGM
- Versions: 5, 6, 7, 9, 11, 12, 13, 14, 15, 17
- Contents: Vertex/index buffers, meshes, spatial bucketing, planar reflectors
Understanding Bucketed Geometry
The mapgeo format contains two separate geometry systems:
1. Environment Meshes - Renderable Geometry
- Full vertex data (positions, normals, UVs, colors, tangents)
- Material references and textures
- Used for actual GPU rendering
- Each mesh has its own bounding box/sphere for frustum culling
2. Bucketed Geometry - Spatial Query Geometry
- Simplified vertices (positions only) and indices
- No materials or vertex attributes
- Used for spatial queries, not rendering
How Bucketing Works
The map is divided into a uniform 2D grid on the XZ plane (top-down). Each cell (bucket) contains:
┌─────┬─────┬─────┬─────┐
│ 0,3 │ 1,3 │ 2,3 │ 3,3 │ ← Top-down view of map
├─────┼─────┼─────┼─────┤
│ 0,2 │ 1,2 │ 2,2 │ 3,2 │
├─────┼─────┼─────┼─────┤
│ 0,1 │ 1,1 │ 2,1 │ 3,1 │ Each cell is a "bucket"
├─────┼─────┼─────┼─────┤
│ 0,0 │ 1,0 │ 2,0 │ 3,0 │
└─────┴─────┴─────┴─────┘
Each GeometryBucket stores:
StartIndex / BaseVertex - Range into shared vertex/index buffers
InsideFaceCount - Triangles fully contained in bucket
StickingOutFaceCount - Triangles extending beyond bucket bounds
MaxStickOutX/Z - How far geometry extends (expands culling bounds)
Purpose of Bucketed Geometry
The bucketed data serves as a low-detail spatial acceleration structure for:
- CPU-side occlusion culling - Simplified proxy geometry for visibility queries
- Collision / Raycasting - Fast spatial queries without full mesh detail
- Visibility layer control - Per-face
EnvironmentVisibility flags for fog of war or layer-based visibility
Relationship Between Systems
Notably, there are no explicit references from buckets to meshes in the file format. The systems are independent:
- Meshes self-cull using their bounding volumes against the camera frustum
- Buckets provide acceleration for collision, occlusion, and visibility queries
- The game engine likely builds mesh↔bucket associations at runtime based on spatial overlap
The VisibilityControllerPathHash in BucketedGeometry suggests integration with a visibility controller system for fog of war or area-based effects.
Existing Infrastructure
The codebase already has building blocks to leverage:
ltk_file - Recognizes MapGeometry kind and OEGM magic
ltk_mesh::mem - VertexBuffer, IndexBuffer, VertexBufferDescription types
ltk_primitives - AABB, Sphere, Color
Rust-Specific Improvements
Consider the following improvements over the C# implementation:
Data Representation
- Zero-copy buffer access - Use memory-mapped views or
Cow<[u8]> for vertex/index data to avoid unnecessary allocations when only reading
- Typed vertex accessors - Provide strongly-typed iterators over vertex attributes (positions, normals, UVs) instead of raw byte access
- Arena-based mesh references - Use indices or handles to reference shared buffers rather than
Rc/Arc to keep data cache-friendly
Ergonomics
- Builder pattern - Provide
EnvironmentAssetBuilder with validation at construction time
- Mesh iteration - Implement
IntoIterator for convenient mesh traversal
- Submesh slicing - Allow extracting submesh geometry as standalone views
Integration
- glTF export - Consider optional conversion to glTF for interoperability with 3D tools
- Spatial queries - Expose bucketed geometry for efficient ray-casting or frustum culling
- Mesh merging - Utility to merge meshes sharing materials for rendering optimization
Performance
- Parallel reading - Vertex/index buffers can be read in parallel after parsing headers
- Lazy buffer loading - Defer buffer reads until accessed (useful for large maps)
- SIMD vertex processing - Use
glam SIMD types for batch vertex transformations
Bucketed Geometry API
- Bucket lookup -
get_bucket(world_x, world_z) -> &GeometryBucket
- Range queries -
buckets_in_region(aabb) -> impl Iterator<Item = &GeometryBucket>
- Raycast support -
raycast(origin, direction) -> Option<RayHit> using bucket acceleration
Tasks
Notes
- Essential for map modding/visualization tools
- File uses little-endian byte order
- Index buffers use
u16 indices
- Scene graphs use spatial bucketing for efficient culling
- Bucketed geometry is separate from renderable meshes (no direct references)
Feature: Map Geometry (
.mapgeo) Parser and BuilderSummary
Implement a Rust parser and builder for Map Geometry environment files (
.mapgeo), which contain 3D geometry data for League of Legends maps.Reference Implementation
C# LeagueToolkit: https://github.com/LeagueToolkit/LeagueToolkit/blob/main/src/LeagueToolkit/Core/Environment/EnvironmentAsset.cs
Related types in the same repository:
EnvironmentAssetMesh.cs- Mesh dataEnvironmentAssetShaderTextureOverride.cs- Shader overridesBucketedGeometry.cs- Spatial scene graphGeometryBucket.cs- Individual bucket cellsPlanarReflector.cs- Reflection planesFormat Overview
OEGMUnderstanding Bucketed Geometry
The mapgeo format contains two separate geometry systems:
1. Environment Meshes - Renderable Geometry
2. Bucketed Geometry - Spatial Query Geometry
How Bucketing Works
The map is divided into a uniform 2D grid on the XZ plane (top-down). Each cell (bucket) contains:
Each
GeometryBucketstores:StartIndex/BaseVertex- Range into shared vertex/index buffersInsideFaceCount- Triangles fully contained in bucketStickingOutFaceCount- Triangles extending beyond bucket boundsMaxStickOutX/Z- How far geometry extends (expands culling bounds)Purpose of Bucketed Geometry
The bucketed data serves as a low-detail spatial acceleration structure for:
EnvironmentVisibilityflags for fog of war or layer-based visibilityRelationship Between Systems
Notably, there are no explicit references from buckets to meshes in the file format. The systems are independent:
The
VisibilityControllerPathHashinBucketedGeometrysuggests integration with a visibility controller system for fog of war or area-based effects.Existing Infrastructure
The codebase already has building blocks to leverage:
ltk_file- RecognizesMapGeometrykind and OEGM magicltk_mesh::mem-VertexBuffer,IndexBuffer,VertexBufferDescriptiontypesltk_primitives-AABB,Sphere,ColorRust-Specific Improvements
Consider the following improvements over the C# implementation:
Data Representation
Cow<[u8]>for vertex/index data to avoid unnecessary allocations when only readingRc/Arcto keep data cache-friendlyErgonomics
EnvironmentAssetBuilderwith validation at construction timeIntoIteratorfor convenient mesh traversalIntegration
Performance
glamSIMD types for batch vertex transformationsBucketed Geometry API
get_bucket(world_x, world_z) -> &GeometryBucketbuckets_in_region(aabb) -> impl Iterator<Item = &GeometryBucket>raycast(origin, direction) -> Option<RayHit>using bucket accelerationTasks
.mapgeofilesNotes
u16indices