1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
// mcnk_converter.rs - Convert MCNK chunks between different WoW versions
use crate::chunk::*;
use crate::error::Result;
// use crate::mcnk_subchunks::*;
use crate::texture_converter::{convert_area_id, convert_texture_layers};
use crate::version::AdtVersion;
/// Convert a MCNK chunk from one version to another
pub fn convert_mcnk(
source: &McnkChunk,
from_version: AdtVersion,
to_version: AdtVersion,
) -> Result<McnkChunk> {
// If same version, just clone
if from_version == to_version {
return Ok(source.clone());
}
// Create modified copy
let mut result = source.clone();
// Update area ID
result.area_id = convert_area_id(source.area_id, from_version, to_version);
// Convert texture layers
result.texture_layers =
convert_texture_layers(&source.texture_layers, from_version, to_version)?;
// Convert alpha maps
result.alpha_maps = source.alpha_maps.clone();
// Update flags for version changes
update_mcnk_flags(&mut result, from_version, to_version);
// Version-specific conversions
match (from_version, to_version) {
// Vanilla to TBC
(AdtVersion::Vanilla, AdtVersion::TBC) => {
vanilla_to_tbc_mcnk(source, &mut result)?;
}
// TBC to WotLK
(AdtVersion::TBC, AdtVersion::WotLK) => {
tbc_to_wotlk_mcnk(source, &mut result)?;
}
// WotLK to Cataclysm
(AdtVersion::WotLK, AdtVersion::Cataclysm) => {
wotlk_to_cataclysm_mcnk(source, &mut result)?;
}
// Cataclysm to MoP
(AdtVersion::Cataclysm, AdtVersion::MoP) => {
cataclysm_to_mop_mcnk(source, &mut result)?;
}
// Downgrading
(AdtVersion::TBC, AdtVersion::Vanilla) => {
tbc_to_vanilla_mcnk(source, &mut result)?;
}
(AdtVersion::WotLK, AdtVersion::TBC) => {
wotlk_to_tbc_mcnk(source, &mut result)?;
}
(AdtVersion::Cataclysm, AdtVersion::WotLK) => {
cataclysm_to_wotlk_mcnk(source, &mut result)?;
}
(AdtVersion::MoP, AdtVersion::Cataclysm) => {
mop_to_cataclysm_mcnk(source, &mut result)?;
}
// Other conversions - already handled by the basic conversion above
_ => {}
}
Ok(result)
}
/// MCNK flags that changed between versions
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[allow(dead_code)]
pub enum McnkFlags {
/// Has height data (MCVT)
HasMcvt = 0x1,
/// Has normal vectors (MCNR)
HasMcnr = 0x2,
/// Has texture mapping (MCLY)
HasMcly = 0x4,
/// Has doodad references (MCRF)
HasMcrf = 0x8,
/// Has the color map (MCCV)
HasMccv = 0x10,
/// Has the area ID
HasAreaId = 0x20,
/// Has the low detail map
IsLowDetail = 0x40,
/// Has liquid data (MCLQ/MH2O)
HasLiquid = 0x80,
/// Has big alpha (MCAL)
HasBigAlpha = 0x100,
/// Has vertex shading (MCCV)
HasVertexShading = 0x200,
/// 0x400 - unused?
Unused400 = 0x400,
/// TBC+: Has the sound emitter (MCSE)
HasMcse = 0x800,
/// WotLK+: Has the water (MH2O)
HasMh2o = 0x1000,
/// Cataclysm+: Has the cliff texture (MCCR)
HasMccr = 0x2000,
/// MoP+: Has the texture scale (MCWS/MCSS)
HasTextureScale = 0x4000,
/// Legion+: Has the map objects (MCRD)
HasMapObjects = 0x8000,
}
/// Update MCNK flags for version conversion
fn update_mcnk_flags(chunk: &mut McnkChunk, from_version: AdtVersion, to_version: AdtVersion) {
// Clear version-specific flags when downgrading
if from_version > to_version {
// TBC+ flags
if to_version < AdtVersion::TBC {
chunk.flags &= !(McnkFlags::HasMcse as u32);
}
// WotLK+ flags
if to_version < AdtVersion::WotLK {
chunk.flags &= !(McnkFlags::HasMh2o as u32);
}
// Cataclysm+ flags
if to_version < AdtVersion::Cataclysm {
chunk.flags &= !(McnkFlags::HasMccr as u32);
}
// MoP+ flags
if to_version < AdtVersion::MoP {
chunk.flags &= !(McnkFlags::HasTextureScale as u32);
}
// Legion+ flags
if to_version < AdtVersion::Legion {
chunk.flags &= !(McnkFlags::HasMapObjects as u32);
}
}
// Set has_big_alpha flag for WotLK+
if to_version >= AdtVersion::WotLK && from_version < AdtVersion::WotLK {
chunk.flags |= McnkFlags::HasBigAlpha as u32;
} else if to_version < AdtVersion::WotLK && from_version >= AdtVersion::WotLK {
chunk.flags &= !(McnkFlags::HasBigAlpha as u32);
}
// Update liquid flag
if to_version >= AdtVersion::WotLK {
// WotLK+ uses MH2O
if chunk.flags & (McnkFlags::HasLiquid as u32) != 0 {
// Change from MCLQ to MH2O
chunk.flags |= McnkFlags::HasMh2o as u32;
}
} else {
// Pre-WotLK uses MCLQ
chunk.flags &= !(McnkFlags::HasMh2o as u32);
}
}
/// Convert a MCNK chunk from Vanilla to TBC
fn vanilla_to_tbc_mcnk(_source: &McnkChunk, _target: &mut McnkChunk) -> Result<()> {
// TBC added MCSE (sound emitters)
// No direct conversion needed - just update flags
Ok(())
}
/// Convert a MCNK chunk from TBC to WotLK
fn tbc_to_wotlk_mcnk(_source: &McnkChunk, target: &mut McnkChunk) -> Result<()> {
// WotLK changed liquid handling from MCLQ to MH2O
// Actual conversion is done at the ADT level
// Set the big alpha flag
target.flags |= McnkFlags::HasBigAlpha as u32;
// Clear liquid offset/size (handled by MH2O now)
if (target.flags & (McnkFlags::HasLiquid as u32)) != 0 {
target.liquid_offset = 0;
target.liquid_size = 0;
// Set MH2O flag
target.flags |= McnkFlags::HasMh2o as u32;
}
Ok(())
}
/// Convert a MCNK chunk from WotLK to Cataclysm
fn wotlk_to_cataclysm_mcnk(_source: &McnkChunk, _target: &mut McnkChunk) -> Result<()> {
// Cataclysm added cliff textures (MCCR)
// Not all chunks have this - leave flag unset by default
Ok(())
}
/// Convert a MCNK chunk from Cataclysm to MoP
fn cataclysm_to_mop_mcnk(_source: &McnkChunk, _target: &mut McnkChunk) -> Result<()> {
// MoP added texture scaling
// Not all chunks have this - leave flag unset by default
Ok(())
}
/// Convert a MCNK chunk from TBC to Vanilla
fn tbc_to_vanilla_mcnk(_source: &McnkChunk, target: &mut McnkChunk) -> Result<()> {
// Remove TBC-specific features
target.flags &= !(McnkFlags::HasMcse as u32);
Ok(())
}
/// Convert a MCNK chunk from WotLK to TBC
fn wotlk_to_tbc_mcnk(_source: &McnkChunk, target: &mut McnkChunk) -> Result<()> {
// WotLK to TBC - revert liquid handling
// Actual conversion is done at the ADT level
// Clear WotLK-specific flags
target.flags &= !((McnkFlags::HasMh2o as u32) | (McnkFlags::HasBigAlpha as u32));
Ok(())
}
/// Convert a MCNK chunk from Cataclysm to WotLK
fn cataclysm_to_wotlk_mcnk(_source: &McnkChunk, target: &mut McnkChunk) -> Result<()> {
// Remove Cataclysm-specific features
target.flags &= !(McnkFlags::HasMccr as u32);
Ok(())
}
/// Convert a MCNK chunk from MoP to Cataclysm
fn mop_to_cataclysm_mcnk(_source: &McnkChunk, target: &mut McnkChunk) -> Result<()> {
// Remove MoP-specific features
target.flags &= !(McnkFlags::HasTextureScale as u32);
Ok(())
}
/// Convert multiple MCNK chunks
pub fn convert_mcnk_chunks(
chunks: &[McnkChunk],
from_version: AdtVersion,
to_version: AdtVersion,
) -> Result<Vec<McnkChunk>> {
let mut result = Vec::with_capacity(chunks.len());
for chunk in chunks {
let converted = convert_mcnk(chunk, from_version, to_version)?;
result.push(converted);
}
Ok(result)
}