wow_wmo/wmo_types.rs
1use std::collections::HashMap;
2
3use crate::types::{BoundingBox, Color, Vec3};
4use crate::version::WmoVersion;
5use crate::wmo_group_types::WmoGroupFlags;
6use bitflags::bitflags;
7
8/// Represents a WMO root file
9#[derive(Debug)]
10pub struct WmoRoot {
11 /// WMO version
12 pub version: WmoVersion,
13
14 /// List of materials
15 pub materials: Vec<WmoMaterial>,
16
17 /// List of groups
18 pub groups: Vec<WmoGroupInfo>,
19
20 /// List of portals
21 pub portals: Vec<WmoPortal>,
22
23 /// List of portal references
24 pub portal_references: Vec<WmoPortalReference>,
25
26 /// List of visible block lists
27 pub visible_block_lists: Vec<Vec<u16>>,
28
29 /// List of lights
30 pub lights: Vec<WmoLight>,
31
32 /// List of doodad definitions
33 pub doodad_defs: Vec<WmoDoodadDef>,
34
35 /// List of doodad sets
36 pub doodad_sets: Vec<WmoDoodadSet>,
37
38 /// Global bounding box
39 pub bounding_box: BoundingBox,
40
41 /// List of textures
42 pub textures: Vec<String>,
43
44 /// Map of texture offsets to indices in the textures vector
45 pub texture_offset_index_map: HashMap<u32, u32>,
46
47 /// Model header info
48 pub header: WmoHeader,
49
50 /// Skybox model path, if any
51 pub skybox: Option<String>,
52
53 /// Convex volume planes (Cataclysm+, transport WMOs)
54 /// Contains collision geometry for advanced physics interactions
55 pub convex_volume_planes: Option<WmoConvexVolumePlanes>,
56}
57
58/// WMO header information
59#[derive(Debug, Clone)]
60pub struct WmoHeader {
61 /// Number of materials
62 pub n_materials: u32,
63
64 /// Number of groups
65 pub n_groups: u32,
66
67 /// Number of portals
68 pub n_portals: u32,
69
70 /// Number of lights
71 pub n_lights: u32,
72
73 /// Number of doodad names
74 pub n_doodad_names: u32,
75
76 /// Number of doodad defs
77 pub n_doodad_defs: u32,
78
79 /// Number of doodad sets
80 pub n_doodad_sets: u32,
81
82 /// Global WMO flags
83 pub flags: WmoFlags,
84
85 /// Ambient color
86 pub ambient_color: Color,
87}
88
89bitflags! {
90 /// Global WMO flags
91 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
92 pub struct WmoFlags: u32 {
93 /// Contains vertex colors
94 const HAS_VERTEX_COLORS = 0x01;
95 /// Outdoor
96 const OUTDOOR = 0x02;
97 /// Does not cast shadows on terrain
98 const NO_TERRAIN_SHADOWS = 0x04;
99 /// Contains groups with liquids
100 const HAS_LIQUIDS = 0x08;
101 /// Indoor map
102 const INDOOR_MAP = 0x10;
103 /// Contains skybox (introduced in WotLK)
104 const HAS_SKYBOX = 0x20;
105 /// Needs rendering during a special pass
106 const SPECIAL_PASS = 0x40;
107 /// Uses scene graph for rendering
108 const USE_SCENE_GRAPH = 0x80;
109 /// Shows minimap in outdoor
110 const SHOW_MINIMAP_OUTDOOR = 0x100;
111 /// Mount allowed inside this WMO
112 const MOUNT_ALLOWED = 0x200;
113 }
114}
115
116/// Represents a WMO material
117#[derive(Debug, Clone)]
118pub struct WmoMaterial {
119 /// Material flags
120 pub flags: WmoMaterialFlags,
121
122 /// Texture 1 index in MOTX chunk
123 pub shader: u32,
124
125 /// Blend mode
126 pub blend_mode: u32,
127
128 /// Texture 1 offset in MOTX chunk
129 pub texture1: u32,
130
131 /// Emissive color
132 pub emissive_color: Color,
133
134 /// Sidn color
135 pub sidn_color: Color,
136
137 /// Framebuffer blend
138 pub framebuffer_blend: Color,
139
140 /// Texture 2 offset in MOTX chunk
141 pub texture2: u32,
142
143 /// Diffuse color
144 pub diffuse_color: Color,
145
146 /// Ground type
147 pub ground_type: u32,
148}
149
150bitflags! {
151 /// WMO material flags
152 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
153 pub struct WmoMaterialFlags: u32 {
154 /// Unlit
155 const UNLIT = 0x01;
156 /// Unfogged
157 const UNFOGGED = 0x02;
158 /// Two-sided
159 const TWO_SIDED = 0x04;
160 /// Exterior light
161 const EXTERIOR_LIGHT = 0x08;
162 /// Window light
163 const WINDOW_LIGHT = 0x10;
164 /// Use clamp s addressing
165 const CLAMP_S = 0x20;
166 /// Use clamp t addressing
167 const CLAMP_T = 0x40;
168 /// Unused 1
169 const UNUSED1 = 0x80;
170 /// Shadow batch 1
171 const SHADOW_BATCH_1 = 0x100;
172 /// Shadow batch 2
173 const SHADOW_BATCH_2 = 0x200;
174 /// Unused 2
175 const UNUSED2 = 0x400;
176 /// Unused 3
177 const UNUSED3 = 0x800;
178 }
179}
180
181impl WmoMaterial {
182 pub fn get_texture1_index(&self, texture_offset_index_map: &HashMap<u32, u32>) -> u32 {
183 texture_offset_index_map
184 .get(&self.texture1)
185 .copied()
186 .unwrap()
187 }
188
189 pub fn get_texture2_index(&self, texture_offset_index_map: &HashMap<u32, u32>) -> u32 {
190 texture_offset_index_map
191 .get(&self.texture2)
192 .copied()
193 .unwrap()
194 }
195}
196
197/// Represents information about a WMO group
198#[derive(Debug, Clone)]
199pub struct WmoGroupInfo {
200 /// Group flags
201 pub flags: WmoGroupFlags,
202
203 /// Bounding box
204 pub bounding_box: BoundingBox,
205
206 /// Group name (often contains a numeric index)
207 pub name: String,
208}
209
210/// Represents a WMO portal
211#[derive(Debug, Clone)]
212pub struct WmoPortal {
213 /// Portal vertices
214 pub vertices: Vec<Vec3>,
215
216 /// Normal vector
217 pub normal: Vec3,
218}
219
220/// Represents a WMO portal reference
221#[derive(Debug, Clone)]
222pub struct WmoPortalReference {
223 /// Portal index
224 pub portal_index: u16,
225
226 /// Group index
227 pub group_index: u16,
228
229 /// Side (0 or 1)
230 pub side: u16,
231}
232
233/// Represents a WMO light
234#[derive(Debug, Clone)]
235pub struct WmoLight {
236 /// Light type
237 pub light_type: WmoLightType,
238
239 /// Light position
240 pub position: Vec3,
241
242 /// Light color
243 pub color: Color,
244
245 /// Light intensity
246 pub intensity: f32,
247
248 /// Rotation quaternion (x, y, z, w) from on-disk C4Quaternion at +0x18.
249 /// Used by spot and directional lights for orientation.
250 pub rotation: [f32; 4],
251
252 /// Attenuation start distance (at +0x28 on disk)
253 pub attenuation_start: f32,
254
255 /// Attenuation end distance (at +0x2C on disk)
256 pub attenuation_end: f32,
257
258 /// Use attenuation
259 pub use_attenuation: bool,
260
261 /// Additional properties based on light type
262 pub properties: WmoLightProperties,
263}
264
265/// Type of WMO light
266#[derive(Debug, Clone, Copy, PartialEq, Eq)]
267pub enum WmoLightType {
268 /// Omnidirectional point light
269 Omni = 0,
270
271 /// Spotlight
272 Spot = 1,
273
274 /// Directional light
275 Directional = 2,
276
277 /// Ambient light
278 Ambient = 3,
279}
280
281impl WmoLightType {
282 /// Convert a raw value to a WmoLightType
283 pub fn from_raw(raw: u8) -> Option<Self> {
284 match raw {
285 0 => Some(Self::Omni),
286 1 => Some(Self::Spot),
287 2 => Some(Self::Directional),
288 3 => Some(Self::Ambient),
289 // Unknown light types default to Omni
290 _ => {
291 // Log warning but continue with default
292 tracing::warn!("Unknown light type {}, defaulting to Omni", raw);
293 Some(Self::Omni)
294 }
295 }
296 }
297}
298
299/// Additional light properties depending on light type
300#[derive(Debug, Clone)]
301pub enum WmoLightProperties {
302 /// Omni light properties (none)
303 Omni,
304
305 /// Spotlight properties
306 Spot {
307 /// Direction
308 direction: Vec3,
309
310 /// Hotspot angle (inner cone)
311 hotspot: f32,
312
313 /// Falloff angle (outer cone)
314 falloff: f32,
315 },
316
317 /// Directional light properties
318 Directional {
319 /// Direction
320 direction: Vec3,
321 },
322
323 /// Ambient light properties (none)
324 Ambient,
325}
326
327/// Represents a WMO doodad definition
328#[derive(Debug, Clone)]
329pub struct WmoDoodadDef {
330 /// Doodad name offset in MODN chunk
331 pub name_offset: u32,
332
333 /// Doodad position
334 pub position: Vec3,
335
336 /// Doodad orientation as quaternion
337 pub orientation: [f32; 4],
338
339 /// Doodad scale factor
340 pub scale: f32,
341
342 /// Doodad color
343 pub color: Color,
344
345 /// Doodad set index
346 pub set_index: u16,
347}
348
349/// Represents a WMO doodad set
350#[derive(Debug, Clone)]
351pub struct WmoDoodadSet {
352 /// Set name
353 pub name: String,
354
355 /// Start doodad index
356 pub start_doodad: u32,
357
358 /// Number of doodads in this set
359 pub n_doodads: u32,
360}
361
362/// Represents a convex volume plane (MCVP chunk)
363/// Added in Cataclysm for transport WMOs and world objects requiring collision
364/// Based on empirical analysis: typically 496 bytes in transport WMOs
365#[derive(Debug, Clone)]
366pub struct WmoConvexVolumePlane {
367 /// Plane normal vector
368 pub normal: Vec3,
369
370 /// Distance from origin along the normal
371 pub distance: f32,
372
373 /// Plane flags (usage unknown)
374 pub flags: u32,
375}
376
377/// Container for MCVP chunk data
378/// Found in Cataclysm+ WMOs, particularly transport objects like ships
379#[derive(Debug, Clone)]
380pub struct WmoConvexVolumePlanes {
381 /// List of convex volume planes
382 /// Each plane defines a clipping boundary for the WMO collision system
383 pub planes: Vec<WmoConvexVolumePlane>,
384}