1use crate::ga::Pen;
2use crate::image::Mode;
3
4pub fn byte_to_pens(byte: u8, mode: Mode) -> Box<dyn Iterator<Item = Pen>> {
5 match mode {
6 Mode::Zero => Box::new(mode0::byte_to_pens(byte).into_iter()),
7 Mode::One => Box::new(mode1::byte_to_pens(byte).into_iter()),
8 Mode::Two => Box::new(mode2::byte_to_pens(byte).into_iter()),
9 _ => unimplemented!()
10 }
11}
12
13pub fn bytes_to_pens<'bytes>(
14 bytes: &'bytes [u8],
15 mode: Mode
16) -> Box<dyn Iterator<Item = Pen> + 'bytes> {
17 Box::new(bytes.iter().flat_map(move |&byte| byte_to_pens(byte, mode)))
18}
19
20pub fn pens_to_vec(pens: &[Pen], mode: Mode) -> Vec<u8> {
21 match mode {
22 Mode::Zero => mode0::pens_to_vec_with_crop(pens),
23 Mode::One => mode1::pens_to_vec_with_crop(pens),
24 Mode::Two => mode2::pens_to_vec_with_crop(pens),
25 _ => unimplemented!()
26 }
27}
28
29pub mod mode2 {
31 use crate::ga::Pen;
32
33 #[repr(u8)]
36 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
37 #[allow(missing_docs)]
38 pub enum PixelPosition {
39 First = 0,
40 Second = 1,
41 Third = 2,
42 Fourth = 3,
43 Fifth = 5,
44 Sixth = 6,
45 Seventh = 7,
46 Heighth = 8
47 }
48
49 impl From<u8> for PixelPosition {
50 fn from(b: u8) -> Self {
51 match b {
52 0 => PixelPosition::First,
53 1 => PixelPosition::Second,
54 2 => PixelPosition::Third,
55 3 => PixelPosition::Fourth,
56 4 => PixelPosition::Fifth,
57 5 => PixelPosition::Sixth,
58 6 => PixelPosition::Seventh,
59 7 => PixelPosition::Heighth,
60 _ => unreachable!()
61 }
62 }
63 }
64
65 pub fn pen_to_pixel_byte(pen: Pen, pixel: PixelPosition) -> u8 {
66 let pen = if pen.number() > 3 {
67 eprintln!("[MODE2] with pen {:?}", &pen);
68 Pen::from(0)
69 }
70 else {
71 pen
72 };
73
74 if pen == 0.into() {
75 0
76 }
77 else {
78 match pixel {
79 PixelPosition::First => 1 << 7,
80 PixelPosition::Second => 1 << 6,
81 PixelPosition::Third => 1 << 5,
82 PixelPosition::Fourth => 1 << 4,
83 PixelPosition::Fifth => 1 << 3,
84 PixelPosition::Sixth => 1 << 2,
85 PixelPosition::Seventh => 1 << 1,
86 PixelPosition::Heighth => 1 << 0
87 }
88 }
89 }
90
91 pub fn byte_to_pens(byte: u8) -> [Pen; 8] {
93 let get_bit = |pos: u8| {
94 if byte & (1 << pos) != 0 {
95 Pen::from(1)
96 }
97 else {
98 Pen::from(0)
99 }
100 };
101
102 [
103 get_bit(7),
104 get_bit(6),
105 get_bit(5),
106 get_bit(4),
107 get_bit(3),
108 get_bit(2),
109 get_bit(1),
110 get_bit(0)
111 ]
112 }
113
114 pub fn pens_to_vec_with_crop(pens: &[Pen]) -> Vec<u8> {
116 let mut res = Vec::new();
117 for idx in 0..(pens.len() / 8) {
118 res.push(pens_to_byte(
119 pens[idx * 8],
120 pens[idx * 8 + 1],
121 pens[idx * 8 + 2],
122 pens[idx * 8 + 3],
123 pens[idx * 8 + 4],
124 pens[idx * 8 + 5],
125 pens[idx * 8 + 6],
126 pens[idx * 8 + 7]
127 ));
128 }
129
130 res
131 }
132
133 pub fn pens_to_vec_with_replacement(pens: &[Pen], replacement: Pen) -> Vec<u8> {
135 let get_pen = |at| pens.get(at).cloned().unwrap_or(replacement);
136
137 let mut res = Vec::new();
138 let mut idx = 0;
139 while idx < pens.len() {
140 res.push(pens_to_byte(
141 get_pen(idx * 8),
142 get_pen(idx * 8 + 1),
143 get_pen(idx * 8 + 2),
144 get_pen(idx * 8 + 3),
145 get_pen(idx * 8 + 4),
146 get_pen(idx * 8 + 5),
147 get_pen(idx * 8 + 6),
148 get_pen(idx * 8 + 7)
149 ));
150
151 idx += 8;
152 }
153
154 res
155 }
156
157 pub fn pens_to_byte(
158 pen0: Pen,
159 pen1: Pen,
160 pen2: Pen,
161 pen3: Pen,
162 pen4: Pen,
163 pen5: Pen,
164 pen6: Pen,
165 pen7: Pen
166 ) -> u8 {
167 pen_to_pixel_byte(pen0, PixelPosition::First)
168 + pen_to_pixel_byte(pen1, PixelPosition::Second)
169 + pen_to_pixel_byte(pen2, PixelPosition::Third)
170 + pen_to_pixel_byte(pen3, PixelPosition::Fourth)
171 + pen_to_pixel_byte(pen4, PixelPosition::Fifth)
172 + pen_to_pixel_byte(pen5, PixelPosition::Sixth)
173 + pen_to_pixel_byte(pen6, PixelPosition::Seventh)
174 + pen_to_pixel_byte(pen7, PixelPosition::Heighth)
175 }
176}
177
178#[allow(clippy::identity_op)]
180pub mod mode1 {
181 use crate::ga::Pen;
182
183 #[repr(u8)]
186 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
187 #[allow(missing_docs)]
188 pub enum PixelPosition {
189 First = 0,
190 Second = 1,
191 Third = 2,
192 Fourth = 3
193 }
194
195 impl From<u8> for PixelPosition {
196 fn from(b: u8) -> Self {
197 match b {
198 0 => PixelPosition::First,
199 1 => PixelPosition::Second,
200 2 => PixelPosition::Third,
201 3 => PixelPosition::Fourth,
202 _ => unreachable!()
203 }
204 }
205 }
206
207 #[repr(u8)]
209 #[derive(Copy, Clone, Debug)]
210 #[allow(missing_docs)]
211 pub enum BitMapping {
212 FourthBit1 = 0,
213 ThirdBit1 = 1,
214 SecondBit1 = 2,
215 FirstBit1 = 3,
216 FourthBit0 = 4,
217 ThirdBit0 = 5,
218 SecondBit0 = 6,
219 FirstBit0 = 7
220 }
221
222 pub fn byte_to_pens(b: u8) -> [Pen; 4] {
224 let pen1 = (BitMapping::FirstBit0, BitMapping::FirstBit1);
225 let pen2 = (BitMapping::SecondBit0, BitMapping::SecondBit1);
226 let pen3 = (BitMapping::ThirdBit0, BitMapping::ThirdBit1);
227 let pen4 = (BitMapping::FourthBit0, BitMapping::FourthBit1);
228
229 let compute = |bits: (BitMapping, BitMapping)| -> Pen {
230 let mut value = 0;
231 if b & (1 << bits.0 as u8) != 0 {
232 value += 2;
233 }
234
235 if b & (1 << bits.1 as u8) != 0 {
236 value += 1;
237 }
238
239 value.into()
240 };
241
242 [compute(pen1), compute(pen2), compute(pen3), compute(pen4)]
243 }
244
245 pub fn pen_to_bits_position<P: Into<PixelPosition>>(pixel: P) -> [u8; 2] {
246 let pixel = pixel.into();
247
248 let mut pos = match pixel {
249 PixelPosition::First => [BitMapping::FirstBit1 as u8, BitMapping::FirstBit0 as u8],
251 PixelPosition::Second => [BitMapping::SecondBit1 as u8, BitMapping::SecondBit0 as u8],
252 PixelPosition::Third => [BitMapping::ThirdBit1 as u8, BitMapping::ThirdBit0 as u8],
253 PixelPosition::Fourth => [BitMapping::FourthBit1 as u8, BitMapping::FourthBit0 as u8]
254 };
255 pos.reverse(); pos
257 }
258
259 pub fn pen_to_pixel_byte<P: Into<PixelPosition>>(pen: Pen, pixel: P) -> u8 {
261 let pen = if pen.number() > 3 {
262 eprintln!("[MODE1] with pen {:?} replaced by pen 0", &pen);
263 Pen::from(0)
264 }
265 else {
266 pen
267 };
268
269 let bits_position: [u8; 2] = pen_to_bits_position(pixel);
271
272 let byte_bit0: u8 = bits_position[0];
274 let byte_bit1: u8 = bits_position[1];
275
276 let pen_bit0: u8 = (pen.number() & (1 << 0)) >> 0;
277 let pen_bit1: u8 = (pen.number() & (1 << 1)) >> 1;
278
279 pen_bit1 * (1 << byte_bit1) + pen_bit0 * (1 << byte_bit0)
280 }
281
282 pub fn pens_to_byte(pen0: Pen, pen1: Pen, pen2: Pen, pen3: Pen) -> u8 {
284 assert!(pen0.number() < 4);
285 assert!(pen1.number() < 4);
286 assert!(pen2.number() < 4);
287 assert!(pen3.number() < 4);
288
289 pen_to_pixel_byte(pen0, PixelPosition::First)
290 + pen_to_pixel_byte(pen1, PixelPosition::Second)
291 + pen_to_pixel_byte(pen2, PixelPosition::Third)
292 + pen_to_pixel_byte(pen3, PixelPosition::Fourth)
293 }
294
295 pub fn pens_to_vec_with_crop(pens: &[Pen]) -> Vec<u8> {
298 let mut res = Vec::new();
299 for idx in 0..(pens.len() / 4) {
300 res.push(pens_to_byte(
301 pens[idx * 4 + 0],
302 pens[idx * 4 + 1],
303 pens[idx * 4 + 2],
304 pens[idx * 4 + 3]
305 ));
306 }
307
308 res
309 }
310
311 pub fn pens_to_vec_with_replacement(pens: &[Pen], replacement: Pen) -> Vec<u8> {
312 let get_pen = |at: usize| pens.get(at).cloned().unwrap_or(replacement);
313
314 let mut res = Vec::new();
315 let mut idx = 0;
316 while idx < pens.len() {
317 res.push(pens_to_byte(
318 get_pen(idx * 4 + 0),
319 get_pen(idx * 4 + 1),
320 get_pen(idx * 4 + 2),
321 get_pen(idx * 4 + 3)
322 ));
323
324 idx += 4;
325 }
326
327 res
328 }
329
330 }
396
397#[allow(clippy::identity_op)]
399pub mod mode0 {
400 use cpclib_common::itertools::Itertools;
403
404 use crate::ga::Pen;
405
406 #[repr(u8)]
409 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
410 #[allow(missing_docs)]
411 pub enum PixelPosition {
412 First = 0,
413 Second = 1
414 }
415
416 impl From<u8> for PixelPosition {
417 fn from(b: u8) -> Self {
418 match b {
419 0 => PixelPosition::First,
420 1 => PixelPosition::Second,
421 _ => unreachable!()
422 }
423 }
424 }
425
426 #[repr(u8)]
428 #[derive(Copy, Clone, Debug)]
429 #[allow(missing_docs)]
430 pub enum BitMapping {
431 SecondBit3 = 0,
432 FirstBit3 = 1,
433 SecondBit1 = 2,
434 FirstBit1 = 3,
435 SecondBit2 = 4,
436 FirstBit2 = 5,
437 SecondBit0 = 6,
438 FirstBit0 = 7
439 }
440
441 pub fn byte_to_pens(b: u8) -> [Pen; 2] {
446 let mut pen0 = 0;
447 for pos in [7, 3, 5, 1].into_iter().rev() {
448 pen0 *= 2;
449 if (b & (1 << pos as u8)) != 0 {
450 pen0 += 1;
451 }
452 }
453
454 let mut pen1 = 0;
455 for pos in [6, 2, 4, 0].into_iter().rev() {
456 pen1 *= 2;
457 if (b & (1 << pos as u8)) != 0 {
458 pen1 += 1;
459 }
460 }
461
462 [pen0.into(), pen1.into()]
463 }
464
465 pub fn pen_to_pixel_byte(pen: Pen, pixel: PixelPosition) -> u8 {
468 let bits_position: [u8; 4] = {
469 let mut pos = match pixel {
470 PixelPosition::First => {
472 [
473 BitMapping::FirstBit3 as u8,
474 BitMapping::FirstBit2 as u8,
475 BitMapping::FirstBit1 as u8,
476 BitMapping::FirstBit0 as u8
477 ]
478 },
479
480 PixelPosition::Second => {
481 [
482 BitMapping::SecondBit3 as u8,
483 BitMapping::SecondBit2 as u8,
484 BitMapping::SecondBit1 as u8,
485 BitMapping::SecondBit0 as u8
486 ]
487 },
488 };
489 pos.reverse();
490 pos
491 };
492
493 let byte_bit0: u8 = bits_position[0];
494 let byte_bit1: u8 = bits_position[1];
495 let byte_bit2: u8 = bits_position[2];
496 let byte_bit3: u8 = bits_position[3];
497
498 let pen_bit0: u8 = (pen.number() & (1 << 0)) >> 0;
499 let pen_bit1: u8 = (pen.number() & (1 << 1)) >> 1;
500 let pen_bit2: u8 = (pen.number() & (1 << 2)) >> 2;
501 let pen_bit3: u8 = (pen.number() & (1 << 3)) >> 3;
502
503 pen_bit3 * (1 << byte_bit3)
504 + pen_bit2 * (1 << byte_bit2)
505 + pen_bit1 * (1 << byte_bit1)
506 + pen_bit0 * (1 << byte_bit0)
507 }
508
509 pub fn pens_to_byte(pen0: Pen, pen1: Pen) -> u8 {
511 pen_to_pixel_byte(pen0, PixelPosition::First)
512 + pen_to_pixel_byte(pen1, PixelPosition::Second)
513 }
514
515 pub fn pens_to_vec_with_crop(pens: &[Pen]) -> Vec<u8> {
518 let mut res = Vec::with_capacity(pens.len());
519 for idx in 0..(pens.len() / 2) {
520 res.push(pens_to_byte(pens[idx * 2 + 0], pens[idx * 2 + 1]));
521 }
522
523 res
524 }
525
526 pub fn pens_to_vec_with_replacement(pens: &[Pen], replacement: Pen) -> Vec<u8> {
529 let mut res = Vec::with_capacity(pens.len());
530 for idx in 0..(pens.len() / 2) {
531 res.push(pens_to_byte(pens[idx * 2 + 0], pens[idx * 2 + 1]));
532 }
533
534 if pens.len() % 2 == 1 {
536 res.push(pens_to_byte(pens[pens.len() - 1], replacement));
537 }
538
539 res
540 }
541
542 pub fn bytes_to_pens(bytes: &[u8]) -> Vec<Pen> {
544 super::bytes_to_pens(bytes, crate::image::Mode::Zero).collect_vec()
545 }
546
547 pub fn mix_mode0_mode3(p0: Pen, p3: Pen) -> Pen {
549 (match (p0.number(), p3.number()) {
550 (0, 0) => 0,
551
552 (0, 1) => 5,
553 (0, 2) => 6,
554 (0, 3) => 7,
555
556 (1, 0) => 8,
557 (1, 1) => 1,
558 (1, 2) => 10,
559 (1, 3) => 11,
560
561 (2, 0) => 12,
562 (2, 1) => 13,
563 (2, 2) => 2,
564 (2, 3) => 15,
565
566 (3, 0) => 4,
567 (3, 1) => 9,
568 (3, 2) => 14,
569 (3, 3) => 3,
570
571 _ => panic!()
572 })
573 .into()
574 }
575
576 pub fn generate_sprite_transparency_for_pen0() -> [u8; 256] {
590 let pen_to_mask = |pen: Pen| -> Pen {
592 if pen.number() == 0 {
593 0xF.into()
595 }
596 else {
597 0x0.into()
598 }
599 };
600
601 let mut table = [0; 256];
603
604 for (idx, byte) in (0..=255).enumerate() {
606 let [pen0, pen1] = byte_to_pens(byte);
607 table[idx] = pens_to_byte(pen_to_mask(pen0), pen_to_mask(pen1))
608 }
609
610 table
611 }
612}
613
614#[cfg(test)]
615#[allow(clippy::pedantic)]
616mod tests {
617 use super::*;
618 use crate::ga::Pen;
619
620 #[allow(clippy::similar_names)]
621 fn test_couple(a: u8, b: u8) {
622 let pa: Pen = a.into();
623 let pb: Pen = b.into();
624
625 assert_eq!(a, pa.number());
626 assert_eq!(b, pb.number());
627
628 let b = mode0::pens_to_byte(pa, pb);
629 let [pa2, pb2] = mode0::byte_to_pens(b);
630
631 assert_eq!(pa2.number(), pa2.number());
632 assert_eq!(pb2.number(), pb2.number());
633 }
634
635 #[test]
636 fn mode0() {
637 for a in 0..16 {
638 for b in 0..16 {
639 test_couple(a, b);
640 }
641 }
642 }
643
644 #[test]
645 fn bytes_to_pen() {
646 let res = crate::pixels::mode0::byte_to_pens(64);
648 assert!(res[0].number() != res[1].number());
649
650 let res = crate::pixels::mode1::byte_to_pens(0b10001000);
651 assert_eq!(res[0], Pen::from(3));
652 assert_eq!(res[1], Pen::from(0));
653 assert_eq!(res[2], Pen::from(0));
654 assert_eq!(res[3], Pen::from(0));
655
656 let res = crate::pixels::mode1::byte_to_pens(0b01000100);
657 assert_eq!(res[0], Pen::from(0));
658 assert_eq!(res[1], Pen::from(3));
659 assert_eq!(res[2], Pen::from(0));
660 assert_eq!(res[3], Pen::from(0));
661
662 let res = crate::pixels::mode1::byte_to_pens(0b00100010);
663 assert_eq!(res[0], Pen::from(0));
664 assert_eq!(res[1], Pen::from(0));
665 assert_eq!(res[2], Pen::from(3));
666 assert_eq!(res[3], Pen::from(0));
667
668 let res = crate::pixels::mode1::byte_to_pens(0b00010001);
669 assert_eq!(res[0], Pen::from(0));
670 assert_eq!(res[1], Pen::from(0));
671 assert_eq!(res[2], Pen::from(0));
672 assert_eq!(res[3], Pen::from(3));
673 }
674
675 fn test_mode3(a: Pen, b: Pen, c: Pen) {
676 let d = mode0::mix_mode0_mode3(a, b);
677 assert_eq!(d.number(), c.number());
678 }
679
680 #[test]
681 fn mode3() {
682 test_mode3(0.into(), 0.into(), 0.into());
683
684 test_mode3(0.into(), 1.into(), 5.into());
685 test_mode3(0.into(), 2.into(), 6.into());
686 test_mode3(0.into(), 3.into(), 7.into());
687
688 test_mode3(3.into(), 0.into(), 4.into());
689 test_mode3(3.into(), 1.into(), 9.into());
690 test_mode3(3.into(), 2.into(), 14.into());
691 test_mode3(3.into(), 3.into(), 3.into());
692 }
693
694 #[test]
695 fn mode2() {
696 let res = mode2::byte_to_pens(0b11000100);
697 assert_eq!(res[0], Pen::from(1));
698 assert_eq!(res[1], Pen::from(1));
699 assert_eq!(res[2], Pen::from(0));
700 assert_eq!(res[3], Pen::from(0));
701 assert_eq!(res[4], Pen::from(0));
702 assert_eq!(res[5], Pen::from(1));
703 assert_eq!(res[6], Pen::from(0));
704 assert_eq!(res[7], Pen::from(0));
705 }
706}