See: https://moddingwiki.shikadi.net/wiki/Carmack_compression
(compressed_data: &[u8])
| 470 | |
| 471 | /// See: https://moddingwiki.shikadi.net/wiki/Carmack_compression |
| 472 | fn carmack_decompress(compressed_data: &[u8]) -> Vec<u8> { |
| 473 | const NEAR_POINTER: u8 = 0xA7; |
| 474 | const FAR_POINTER: u8 = 0xA8; |
| 475 | let mut output = Vec::new(); |
| 476 | let mut word_i = 0; |
| 477 | let mut n_shifts = 0; |
| 478 | let mut offset = 0; |
| 479 | |
| 480 | while offset < compressed_data.len() - 2 { |
| 481 | match &compressed_data[offset..(offset + 2)] { |
| 482 | [0x00, NEAR_POINTER] | [0x00, FAR_POINTER] => { |
| 483 | // ignore 0x00 and invert the following word |
| 484 | output.push(compressed_data[offset + 2]); |
| 485 | output.push(compressed_data[offset + 1]); |
| 486 | n_shifts += 1; |
| 487 | } |
| 488 | [count, NEAR_POINTER] => { |
| 489 | let distance = usize::from(compressed_data[offset + 2]); |
| 490 | let segment_start = output.len() - distance * 2; |
| 491 | let segment_end = segment_start + usize::from(*count) * 2; |
| 492 | let segment_to_repeat = output[segment_start..segment_end].to_vec(); |
| 493 | output.extend_from_slice(&segment_to_repeat); |
| 494 | n_shifts += 1; |
| 495 | } |
| 496 | [count, FAR_POINTER] => { |
| 497 | let distance = u16::from_le_bytes( |
| 498 | compressed_data[(offset + 2)..(offset + 4)] |
| 499 | .try_into() |
| 500 | .unwrap(), |
| 501 | ); |
| 502 | let segment_start = (usize::from(distance) + 1) * 2; |
| 503 | let segment_end = segment_start + usize::from(*count) * 2; |
| 504 | let segment_to_repeat = output[segment_start..segment_end].to_vec(); |
| 505 | output.extend_from_slice(&segment_to_repeat); |
| 506 | word_i += 1; |
| 507 | } |
| 508 | word_bytes => { |
| 509 | output.extend_from_slice(word_bytes); |
| 510 | } |
| 511 | } |
| 512 | |
| 513 | word_i += 1; |
| 514 | offset = word_i * 2 + n_shifts; |
| 515 | } |
| 516 | |
| 517 | if offset < compressed_data.len() { |
| 518 | let remainder = &compressed_data[offset..]; |
| 519 | output.extend_from_slice(remainder); |
| 520 | } |
| 521 | |
| 522 | output |
| 523 | } |
| 524 | |
| 525 | fn get_plane(data: &[u8], offset: i32, length: u16, magic_rlew_word: &[u8; 2]) -> [[u16; 64]; 64] { |
| 526 | let plane_start = offset as usize; |