1use std::collections::HashMap;
35
36const FILE_HEADER: u32 = 0x0044_3355;
41const PRIORITY_UPDATE: u32 = 0xFFFF_FF15;
42const MODIFIER_CHAIN: u32 = 0xFFFF_FF14;
43const MODEL_NODE: u32 = 0xFFFF_FF22;
44const CLOD_MESH_DECLARATION: u32 = 0xFFFF_FF31;
45const CLOD_BASE_MESH_CONTINUATION: u32 = 0xFFFF_FF3B;
46const LINE_SET_DECLARATION: u32 = 0xFFFF_FF37;
47const LINE_SET_CONTINUATION: u32 = 0xFFFF_FF3F;
48const SHADING_MODIFIER: u32 = 0xFFFF_FF45;
49const LIT_TEXTURE_SHADER: u32 = 0xFFFF_FF53;
50const MATERIAL_RESOURCE: u32 = 0xFFFF_FF54;
51
52const CHAIN_NODE: u32 = 0;
54const CHAIN_MODEL_RESOURCE: u32 = 1;
55
56const UTF8: u32 = 106;
58
59const STATIC_FULL: u32 = 0x400;
67const MAX_RANGE: u32 = STATIC_FULL + 0x3FFF;
70const CONTEXT_8: u32 = 0;
72
73const CTX_BASE_SHADING_ID: u32 = 1;
74const CTX_NUM_NEW_FACES: u32 = 1;
75const CTX_LINE_SHADING_ID: u32 = 1;
76const CTX_POSITION_DIFF_SIGNS: u32 = 20;
77const CTX_POSITION_DIFF_MAG_X: u32 = 21;
78const CTX_POSITION_DIFF_MAG_Y: u32 = 22;
79const CTX_POSITION_DIFF_MAG_Z: u32 = 23;
80const CTX_NUM_LOCAL_NORMALS: u32 = 40;
81const CTX_NORMAL_DIFF_SIGNS: u32 = 41;
82const CTX_NORMAL_DIFF_MAG_X: u32 = 42;
83const CTX_NORMAL_DIFF_MAG_Y: u32 = 43;
84const CTX_NORMAL_DIFF_MAG_Z: u32 = 44;
85const CTX_NORMAL_LOCAL_INDEX: u32 = 45;
86
87fn static_range(count: u32) -> u32 {
89 STATIC_FULL + count
90}
91
92const ELEPHANT: u32 = 0x1FFF;
95const MAX_SYMBOL_IN_HISTOGRAM: u32 = 0xFFFF;
97
98#[derive(Debug, Clone, PartialEq)]
104pub struct Material {
105 pub name: String,
106 pub ambient: [f32; 3],
107 pub diffuse: [f32; 3],
108 pub specular: [f32; 3],
109 pub emissive: [f32; 3],
110 pub reflectivity: f32,
111 pub opacity: f32,
112}
113
114#[derive(Debug, Clone, Default, PartialEq)]
117pub struct Mesh {
118 pub positions: Vec<[f32; 3]>,
119 pub normals: Vec<[f32; 3]>,
120 pub triangles: Vec<([u32; 3], u32)>,
121}
122
123#[derive(Debug, Clone, Default, PartialEq)]
125pub struct Lines {
126 pub positions: Vec<[f32; 3]>,
127 pub segments: Vec<([u32; 2], u32)>,
128}
129
130#[derive(Debug, Clone, PartialEq)]
131pub enum Geometry {
132 Mesh(Mesh),
133 Lines(Lines),
134}
135
136#[derive(Debug, Clone, PartialEq)]
139pub struct Model {
140 pub name: String,
141 pub geometry: Geometry,
142 pub shaders: Vec<usize>,
144 pub two_sided: bool,
147}
148
149#[derive(Debug, Clone, Default, PartialEq)]
150pub struct Scene {
151 pub materials: Vec<Material>,
152 pub models: Vec<Model>,
153}
154
155pub fn validate(scene: &Scene) -> Result<(), String> {
157 let mut names = std::collections::HashSet::new();
158 for model in &scene.models {
159 if model.name.is_empty() || model.name.len() > 0xFFFF {
160 return Err(format!("model name '{}' is empty or too long", model.name));
161 }
162 if !names.insert(model.name.as_str()) {
163 return Err(format!("two models are named '{}'", model.name));
164 }
165 if model.shaders.is_empty() {
166 return Err(format!("model '{}' has no shader", model.name));
167 }
168 if let Some(bad) = model.shaders.iter().find(|index| **index >= scene.materials.len()) {
169 return Err(format!("model '{}' names material {bad}, which does not exist", model.name));
170 }
171 let shading = model.shaders.len() as u32;
172 match &model.geometry {
173 Geometry::Mesh(mesh) => {
174 if mesh.positions.is_empty() || mesh.triangles.is_empty() {
175 return Err(format!("mesh '{}' is empty", model.name));
176 }
177 if mesh.normals.len() != mesh.positions.len() {
178 return Err(format!("mesh '{}' has a normal count unlike its position count", model.name));
179 }
180 let n = mesh.positions.len() as u32;
181 if mesh.triangles.iter().any(|(t, s)| t.iter().any(|i| *i >= n) || *s >= shading) {
182 return Err(format!("mesh '{}' indexes past its arrays", model.name));
183 }
184 }
185 Geometry::Lines(lines) => {
186 if lines.positions.is_empty() || lines.segments.is_empty() {
187 return Err(format!("line set '{}' is empty", model.name));
188 }
189 let n = lines.positions.len() as u32;
190 if lines.segments.iter().any(|(s, m)| s.iter().any(|i| *i >= n) || s[0] == s[1] || *m >= shading) {
191 return Err(format!("line set '{}' has a degenerate or out-of-range segment", model.name));
192 }
193 }
194 }
195 }
196 for material in &scene.materials {
197 if material.name.is_empty() || material.name.len() > 0xFFFF {
198 return Err(format!("material name '{}' is empty or too long", material.name));
199 }
200 }
201 Ok(())
202}
203
204pub fn write(scene: &Scene) -> Result<Vec<u8>, String> {
206 validate(scene)?;
207 let mut blocks: Vec<u8> = Vec::new();
208
209 push_block(&mut blocks, PRIORITY_UPDATE, &uncompressed(|w| w.write_u32(0)));
210 for model in &scene.models {
211 let node = block_bytes(MODEL_NODE, &model_node(model));
212 let shading = block_bytes(SHADING_MODIFIER, &shading_modifier(model, scene));
213 push_block(&mut blocks, MODIFIER_CHAIN, &modifier_chain(&model.name, CHAIN_NODE, &[node, shading]));
214 }
215 for model in &scene.models {
216 let resource = resource_name(model);
217 let members = match &model.geometry {
218 Geometry::Mesh(mesh) => vec![block_bytes(CLOD_MESH_DECLARATION, &mesh_declaration(&resource, mesh, model))],
219 Geometry::Lines(lines) => {
220 let quant = line_quantisation(lines);
221 vec![
222 block_bytes(LINE_SET_DECLARATION, &line_declaration(&resource, lines, model, &quant)),
223 block_bytes(LINE_SET_CONTINUATION, &line_continuation(&resource, lines, &quant)),
224 ]
225 }
226 };
227 push_block(&mut blocks, MODIFIER_CHAIN, &modifier_chain(&resource, CHAIN_MODEL_RESOURCE, &members));
228 }
229 for material in &scene.materials {
230 push_block(&mut blocks, LIT_TEXTURE_SHADER, &lit_texture_shader(material));
231 }
232 for material in &scene.materials {
233 push_block(&mut blocks, MATERIAL_RESOURCE, &material_resource(material));
234 }
235 push_block(&mut blocks, PRIORITY_UPDATE, &uncompressed(|w| w.write_u32(0x100)));
236 for model in &scene.models {
237 if let Geometry::Mesh(mesh) = &model.geometry {
238 push_block(&mut blocks, CLOD_BASE_MESH_CONTINUATION, &base_mesh(&resource_name(model), mesh));
239 }
240 }
241
242 const HEADER_BLOCK: u64 = 12 + 24;
245 let file_size = HEADER_BLOCK + blocks.len() as u64;
246 let header = uncompressed(|w| {
247 w.write_u16(0); w.write_u16(0); w.write_u32(0); w.write_u32(HEADER_BLOCK as u32);
251 w.write_u64(file_size);
252 w.write_u32(UTF8);
253 });
254 let mut out = Vec::with_capacity(file_size as usize);
255 push_block(&mut out, FILE_HEADER, &header);
256 out.extend_from_slice(&blocks);
257 Ok(out)
258}
259
260fn resource_name(model: &Model) -> String {
261 format!("{}.res", model.name)
262}
263
264fn push_block(out: &mut Vec<u8>, block_type: u32, data: &[u8]) {
267 out.extend_from_slice(&block_type.to_le_bytes());
268 out.extend_from_slice(&(data.len() as u32).to_le_bytes());
269 out.extend_from_slice(&0u32.to_le_bytes());
270 out.extend_from_slice(data);
271 out.resize(out.len() + (4 - data.len() % 4) % 4, 0);
272}
273
274fn block_bytes(block_type: u32, data: &[u8]) -> Vec<u8> {
275 let mut out = Vec::new();
276 push_block(&mut out, block_type, data);
277 out
278}
279
280fn uncompressed(body: impl FnOnce(&mut BitWriter)) -> Vec<u8> {
281 let mut w = BitWriter::default();
282 body(&mut w);
283 w.finish()
284}
285
286fn modifier_chain(name: &str, chain_type: u32, members: &[Vec<u8>]) -> Vec<u8> {
289 let mut head = uncompressed(|w| {
290 w.write_string(name);
291 w.write_u32(chain_type);
292 w.write_u32(0); });
294 head.resize(head.len() + (4 - head.len() % 4) % 4, 0);
295 head.extend_from_slice(&(members.len() as u32).to_le_bytes());
296 for member in members {
297 head.extend_from_slice(member);
298 }
299 head
300}
301
302const IDENTITY: [f32; 16] = [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0];
303
304fn model_node(model: &Model) -> Vec<u8> {
305 uncompressed(|w| {
306 w.write_string(&model.name);
307 w.write_u32(1); w.write_string("");
309 for value in IDENTITY {
310 w.write_f32(value);
311 }
312 w.write_string(&resource_name(model));
313 w.write_u32(if model.two_sided { 3 } else { 1 });
315 })
316}
317
318fn shading_modifier(model: &Model, scene: &Scene) -> Vec<u8> {
319 uncompressed(|w| {
320 w.write_string(&model.name);
321 w.write_u32(1); w.write_u32(0x0F); w.write_u32(model.shaders.len() as u32);
324 for material in &model.shaders {
325 w.write_u32(1); w.write_string(&scene.materials[*material].name);
327 }
328 })
329}
330
331fn write_shading_descriptions(w: &mut BitWriter, count: usize) {
334 w.write_u32(count as u32);
335 for index in 0..count {
336 w.write_u32(0); w.write_u32(0); w.write_u32(index as u32); }
340}
341
342fn mesh_declaration(resource: &str, mesh: &Mesh, model: &Model) -> Vec<u8> {
343 uncompressed(|w| {
344 w.write_string(resource);
345 w.write_u32(0); w.write_u32(0); w.write_u32(mesh.triangles.len() as u32);
348 w.write_u32(mesh.positions.len() as u32);
349 w.write_u32(mesh.normals.len() as u32);
350 w.write_u32(0); w.write_u32(0); w.write_u32(0); write_shading_descriptions(w, model.shaders.len());
354 w.write_u32(mesh.positions.len() as u32);
356 w.write_u32(mesh.positions.len() as u32);
357 for _ in 0..3 {
360 w.write_u32(1000);
361 }
362 for _ in 0..5 {
363 w.write_f32(1.0);
364 }
365 w.write_f32(-1.0);
367 w.write_f32(0.0);
368 w.write_f32(0.0);
369 w.write_u32(0); })
371}
372
373fn base_mesh(resource: &str, mesh: &Mesh) -> Vec<u8> {
374 let mut w = BitWriter::default();
375 w.write_string(resource);
376 w.write_u32(0); w.write_u32(mesh.triangles.len() as u32);
378 w.write_u32(mesh.positions.len() as u32);
379 w.write_u32(mesh.normals.len() as u32);
380 w.write_u32(0);
381 w.write_u32(0);
382 w.write_u32(0);
383 for p in &mesh.positions {
384 for c in p {
385 w.write_f32(*c);
386 }
387 }
388 for n in &mesh.normals {
389 for c in n {
390 w.write_f32(*c);
391 }
392 }
393 let positions = static_range(mesh.positions.len() as u32);
394 let normals = static_range(mesh.normals.len() as u32);
395 for (corners, shading) in &mesh.triangles {
396 w.write_compressed_u32(CTX_BASE_SHADING_ID, *shading);
397 for corner in corners {
398 w.write_compressed_u32(positions, *corner);
399 w.write_compressed_u32(normals, *corner);
400 }
401 }
402 w.finish()
403}
404
405struct LineQuant {
409 position: f32,
410 normal: f32,
411}
412
413fn line_quantisation(lines: &Lines) -> LineQuant {
414 let mut min = lines.positions[0];
415 let mut max = lines.positions[0];
416 for p in &lines.positions {
417 for axis in 0..3 {
418 min[axis] = min[axis].min(p[axis]);
419 max[axis] = max[axis].max(p[axis]);
420 }
421 }
422 let centre = [(min[0] + max[0]) * 0.5, (min[1] + max[1]) * 0.5, (min[2] + max[2]) * 0.5];
423 let radius_squared = lines
424 .positions
425 .iter()
426 .map(|p| (p[0] - centre[0]).powi(2) + (p[1] - centre[1]).powi(2) + (p[2] - centre[2]).powi(2))
427 .fold(0.0f32, f32::max);
428 let mut position = 262_144.0f32;
429 if radius_squared > 0.0 {
430 position /= radius_squared.sqrt();
431 }
432 let largest = min.iter().chain(max.iter()).map(|c| c.abs()).fold(0.0f32, f32::max);
433 if largest > 0.0 {
434 position = position.min(0xFFFF_FE00u32 as f32 / largest);
435 }
436 LineQuant { position, normal: 16_384.0 }
437}
438
439fn line_declaration(resource: &str, lines: &Lines, model: &Model, quant: &LineQuant) -> Vec<u8> {
440 uncompressed(|w| {
441 w.write_string(resource);
442 w.write_u32(0); w.write_u32(0); w.write_u32(lines.segments.len() as u32);
445 w.write_u32(lines.positions.len() as u32);
446 w.write_u32(1); w.write_u32(0);
448 w.write_u32(0);
449 w.write_u32(0);
450 write_shading_descriptions(w, model.shaders.len());
451 for _ in 0..3 {
452 w.write_u32(0); }
454 w.write_f32(1.0 / quant.position);
455 w.write_f32(1.0 / quant.normal);
456 w.write_f32(1.0 / 16_384.0); w.write_f32(1.0 / 16_384.0); w.write_f32(1.0 / 16_384.0); for _ in 0..3 {
460 w.write_u32(0); }
462 w.write_u32(0); })
464}
465
466const LINE_NORMAL: [f32; 3] = [0.0, 0.0, 1.0];
469
470fn quantise(v: [f32; 3], factor: f32) -> (u8, [u32; 3]) {
472 let signs = (v[0] < 0.0) as u8 | ((v[1] < 0.0) as u8) << 1 | ((v[2] < 0.0) as u8) << 2;
473 let mag = |c: f32| (0.5f32 + factor * c.abs()) as u32;
474 (signs, [mag(v[0]), mag(v[1]), mag(v[2])])
475}
476
477fn reconstruct(predicted: [f32; 3], signs: u8, mag: [u32; 3], inverse: f32) -> [f32; 3] {
478 let mut out = predicted;
479 for axis in 0..3 {
480 let step = inverse * mag[axis] as f32;
481 out[axis] = if signs & (1 << axis) != 0 { predicted[axis] - step } else { predicted[axis] + step };
482 }
483 out
484}
485
486fn line_continuation(resource: &str, lines: &Lines, quant: &LineQuant) -> Vec<u8> {
495 let count = lines.positions.len() as u32;
496 let mut by_later: Vec<Vec<(u32, u32)>> = vec![Vec::new(); lines.positions.len()];
499 for ([a, b], shading) in &lines.segments {
500 let (early, late) = if a < b { (*a, *b) } else { (*b, *a) };
501 by_later[late as usize].push((early, *shading));
502 }
503 let mut has_line = vec![false; lines.positions.len()];
506
507 let mut w = BitWriter::default();
508 w.write_string(resource);
509 w.write_u32(0); w.write_u32(0); w.write_u32(count); let inverse = 1.0 / quant.position;
513 let mut previous = [0.0f32; 3];
514 for current in 0..count {
515 let position = lines.positions[current as usize];
516 let (split_range, split, predicted) = if current == 0 {
517 (static_range(1), 0, [0.0f32; 3])
518 } else {
519 (static_range(current), current - 1, previous)
520 };
521 w.write_compressed_u32(split_range, split);
522 let diff = [position[0] - predicted[0], position[1] - predicted[1], position[2] - predicted[2]];
523 let (signs, mag) = quantise(diff, quant.position);
524 w.write_compressed_u8(CTX_POSITION_DIFF_SIGNS, signs);
525 w.write_compressed_u32(CTX_POSITION_DIFF_MAG_X, mag[0]);
526 w.write_compressed_u32(CTX_POSITION_DIFF_MAG_Y, mag[1]);
527 w.write_compressed_u32(CTX_POSITION_DIFF_MAG_Z, mag[2]);
528 previous = reconstruct(predicted, signs, mag, inverse);
529 if current == 0 {
530 w.write_compressed_u32(CTX_NUM_LOCAL_NORMALS, 0);
531 w.write_compressed_u32(CTX_NUM_NEW_FACES, 0);
532 continue;
533 }
534 let new_lines = &by_later[current as usize];
535 let predicted_normal = if has_line[split as usize] { LINE_NORMAL } else { [0.0; 3] };
536 w.write_compressed_u32(CTX_NUM_LOCAL_NORMALS, 2 * new_lines.len() as u32);
537 let normal_diff = [
538 LINE_NORMAL[0] - predicted_normal[0],
539 LINE_NORMAL[1] - predicted_normal[1],
540 LINE_NORMAL[2] - predicted_normal[2],
541 ];
542 let (normal_signs, normal_mag) = quantise(normal_diff, quant.normal);
543 for _ in 0..new_lines.len() * 2 {
544 w.write_compressed_u8(CTX_NORMAL_DIFF_SIGNS, normal_signs);
545 w.write_compressed_u32(CTX_NORMAL_DIFF_MAG_X, normal_mag[0]);
546 w.write_compressed_u32(CTX_NORMAL_DIFF_MAG_Y, normal_mag[1]);
547 w.write_compressed_u32(CTX_NORMAL_DIFF_MAG_Z, normal_mag[2]);
548 }
549 w.write_compressed_u32(CTX_NUM_NEW_FACES, new_lines.len() as u32);
550 for (index, (early, shading)) in new_lines.iter().enumerate() {
551 w.write_compressed_u32(CTX_LINE_SHADING_ID, *shading);
552 w.write_compressed_u32(static_range(current), *early);
553 for end in 0..2 {
554 w.write_compressed_u32(CTX_NORMAL_LOCAL_INDEX, 2 * index as u32 + end);
555 }
556 has_line[*early as usize] = true;
557 }
558 if !new_lines.is_empty() {
559 has_line[current as usize] = true;
560 }
561 }
562 w.finish()
563}
564
565fn lit_texture_shader(material: &Material) -> Vec<u8> {
566 uncompressed(|w| {
567 w.write_string(&material.name);
568 w.write_u32(1); w.write_f32(0.0); w.write_u32(0x617); w.write_u32(0x606); w.write_u32(1); w.write_u32(0); w.write_u32(0); w.write_string(&material.name);
576 })
577}
578
579fn material_resource(material: &Material) -> Vec<u8> {
580 uncompressed(|w| {
581 w.write_string(&material.name);
582 w.write_u32(0x3F); for colour in [material.ambient, material.diffuse, material.specular, material.emissive] {
584 for c in colour {
585 w.write_f32(c);
586 }
587 }
588 w.write_f32(material.reflectivity);
589 w.write_f32(material.opacity);
590 })
591}
592
593#[derive(Debug, Clone)]
602struct Histogram {
603 counts: Vec<u32>,
604 tree: Vec<u32>,
605 total: u32,
606}
607
608impl Histogram {
609 fn new() -> Self {
610 let mut h = Histogram { counts: vec![0; 128], tree: vec![0; 129], total: 0 };
611 h.bump(0, 1);
612 h
613 }
614
615 fn bump(&mut self, symbol: usize, by: u32) {
616 if symbol >= self.counts.len() {
617 let mut size = self.counts.len();
618 while size <= symbol {
619 size *= 2;
620 }
621 let counts = std::mem::take(&mut self.counts);
622 self.counts = vec![0; size];
623 self.tree = vec![0; size + 1];
624 self.total = 0;
625 for (s, c) in counts.into_iter().enumerate() {
626 if c > 0 {
627 self.bump(s, c);
628 }
629 }
630 }
631 self.counts[symbol] += by;
632 self.total += by;
633 let mut i = symbol + 1;
634 while i < self.tree.len() {
635 self.tree[i] += by;
636 i += i & i.wrapping_neg();
637 }
638 }
639
640 fn freq(&self, symbol: u32) -> u32 {
641 self.counts.get(symbol as usize).copied().unwrap_or(0)
642 }
643
644 fn cum(&self, symbol: u32) -> u32 {
646 let mut i = (symbol as usize).min(self.counts.len());
647 let mut sum = 0;
648 while i > 0 {
649 sum += self.tree[i];
650 i -= i & i.wrapping_neg();
651 }
652 sum
653 }
654
655 fn symbol_at(&self, target: u32) -> u32 {
657 let mut position = 0usize;
659 let mut remaining = target;
660 let mut step = self.tree.len().next_power_of_two() / 2;
661 while step > 0 {
662 let next = position + step;
663 if next < self.tree.len() && self.tree[next] <= remaining {
664 position = next;
665 remaining -= self.tree[next];
666 }
667 step /= 2;
668 }
669 position as u32
670 }
671
672 fn add(&mut self, symbol: u32) {
673 if symbol > MAX_SYMBOL_IN_HISTOGRAM {
674 return;
675 }
676 if self.total >= ELEPHANT {
677 let halved: Vec<u32> = self.counts.iter().map(|c| c >> 1).collect();
678 self.tree.iter_mut().for_each(|t| *t = 0);
679 self.counts.iter_mut().for_each(|c| *c = 0);
680 self.total = 0;
681 for (s, c) in halved.into_iter().enumerate() {
682 if c > 0 {
683 self.bump(s, c);
684 }
685 }
686 self.bump(0, 1);
687 }
688 self.bump(symbol as usize, 1);
689 }
690}
691
692const HALF: u32 = 0x8000;
693const QUARTER: u32 = 0x4000;
694
695#[derive(Debug, Clone)]
697struct BitWriter {
698 bytes: Vec<u8>,
699 bit: usize,
700 high: u32,
701 low: u32,
702 underflow: u32,
703 compressed: bool,
704 contexts: HashMap<u32, Histogram>,
705}
706
707impl Default for BitWriter {
708 fn default() -> Self {
709 BitWriter {
710 bytes: Vec::new(),
711 bit: 0,
712 high: 0xFFFF,
713 low: 0,
714 underflow: 0,
715 compressed: false,
716 contexts: HashMap::new(),
717 }
718 }
719}
720
721fn swap8(value: u32) -> u32 {
723 (value as u8).reverse_bits() as u32
724}
725
726impl BitWriter {
727 fn write_bit(&mut self, value: u32) {
728 let byte = self.bit / 8;
729 if byte == self.bytes.len() {
730 self.bytes.push(0);
731 }
732 if value & 1 != 0 {
733 self.bytes[byte] |= 1 << (self.bit % 8);
734 }
735 self.bit += 1;
736 }
737
738 fn initial(&self) -> bool {
739 self.high == 0xFFFF && self.low == 0 && self.underflow == 0
740 }
741
742 fn write_u8(&mut self, value: u8) {
743 let symbol = swap8(value as u32);
744 if self.initial() {
745 for i in 0..8 {
746 self.write_bit((value as u32) >> i);
747 }
748 } else {
749 self.write_static(STATIC_FULL + 256, symbol + 1);
750 }
751 }
752
753 fn write_u16(&mut self, value: u16) {
754 self.write_u8(value as u8);
755 self.write_u8((value >> 8) as u8);
756 }
757
758 fn write_u32(&mut self, value: u32) {
759 self.write_u16(value as u16);
760 self.write_u16((value >> 16) as u16);
761 }
762
763 fn write_u64(&mut self, value: u64) {
764 self.write_u32(value as u32);
765 self.write_u32((value >> 32) as u32);
766 }
767
768 fn write_f32(&mut self, value: f32) {
769 self.write_u32(value.to_bits());
770 }
771
772 fn write_string(&mut self, text: &str) {
773 self.write_u16(text.len() as u16);
774 for byte in text.bytes() {
775 self.write_u8(byte);
776 }
777 }
778
779 fn encode(&mut self, cum: u32, freq: u32, total: u32) {
782 let range = self.high + 1 - self.low;
783 self.high = self.low.wrapping_sub(1).wrapping_add(range * (cum + freq) / total);
786 self.low += range * cum / total;
787 let mut bit = self.low >> 15;
788 while (self.high & HALF) == (self.low & HALF) {
789 self.high &= !HALF;
790 self.high += self.high + 1;
791 self.write_bit(bit);
792 while self.underflow > 0 {
793 self.underflow -= 1;
794 self.write_bit(!bit & 1);
795 }
796 self.low &= !HALF;
797 self.low += self.low;
798 bit = self.low >> 15;
799 }
800 while (self.high & QUARTER) == 0 && (self.low & QUARTER) == QUARTER {
801 self.high &= !HALF;
802 self.high <<= 1;
803 self.low <<= 1;
804 self.high |= HALF;
805 self.high |= 1;
806 self.low &= !HALF;
807 self.underflow += 1;
808 }
809 }
810
811 fn write_static(&mut self, context: u32, symbol: u32) {
813 let total = context - STATIC_FULL;
814 debug_assert!(symbol >= 1 && symbol <= total);
815 self.encode(symbol - 1, 1, total);
816 }
817
818 fn write_dynamic(&mut self, context: u32, symbol: u32) -> bool {
821 let histogram = self.contexts.entry(context).or_insert_with(Histogram::new);
822 let (mut symbol, total) = (symbol, histogram.total);
823 let mut freq = histogram.freq(symbol);
824 if freq == 0 {
825 symbol = 0;
826 freq = histogram.freq(0);
827 }
828 let cum = histogram.cum(symbol);
829 histogram.add(symbol);
830 self.encode(cum, freq, total);
831 symbol == 0
832 }
833
834 fn write_compressed(&mut self, context: u32, value: u32, raw: impl Fn(&mut Self, u32)) {
835 self.compressed = true;
836 if context != CONTEXT_8 && context < MAX_RANGE {
837 let escaped = if context > STATIC_FULL {
838 self.write_static(context, value + 1);
839 false
840 } else {
841 self.write_dynamic(context, value + 1)
842 };
843 if escaped {
844 raw(self, value);
845 if let Some(histogram) = self.contexts.get_mut(&context) {
846 histogram.add(value + 1);
847 }
848 }
849 } else {
850 raw(self, value);
851 }
852 }
853
854 fn write_compressed_u32(&mut self, context: u32, value: u32) {
855 self.write_compressed(context, value, |w, v| w.write_u32(v));
856 }
857
858 fn write_compressed_u8(&mut self, context: u32, value: u8) {
859 self.write_compressed(context, value as u32, |w, v| w.write_u8(v as u8));
860 }
861
862 fn finish(mut self) -> Vec<u8> {
865 if self.compressed {
866 self.write_u32(0);
867 }
868 self.bytes.truncate(self.bit.div_ceil(8));
869 self.bytes
870 }
871}
872
873
874