1 module pixelatrix.bpp4;
2 
3 import pixelatrix.common;
4 import siryul;
5 
6 deprecated ubyte[8][8] toPixelMatrix(ubyte[] data) @safe pure in {
7 	assert(data.length == 8*4, "Data length mismatch");
8 } out(result) {
9 	foreach (row; result) {
10 		foreach (pixel; row) {
11 			assert(pixel < 16, "Pixel colour out of range");
12 		}
13 	}
14 } do {
15 	return Intertwined4BPP(data[0 .. 8 * 4]).pixelMatrix;
16 }
17 /++
18 + 4 bit per pixel tile format with palette. Each row has its bitplanes stored
19 + adjacent to one another. Commonly used by the SNES and PC Engine.
20 +/
21 align(1) struct Intertwined4BPP {
22 	align(1):
23 	ubyte[32] raw;
24 	@SerializationMethod
25 	string toBase64() const @safe {
26 		import std.base64 : Base64;
27 		return Base64.encode(raw[]);
28 	}
29 	ubyte[8][8] pixelMatrix() const @safe pure
30 		out(result; result.isValidBitmap!4)
31 	{
32 		ubyte[8][8] output;
33 		foreach (x; 0..8) {
34 			foreach (y; 0..8) {
35 				output[x][7-y] = cast(ubyte)
36 					(((raw[x*2]&(1<<y))>>y) +
37 					(((raw[x*2+1]&(1<<y))>>y)<<1) +
38 					(((raw[16 + x*2]&(1<<y))>>y)<<2) +
39 					(((raw[16 + x*2 + 1]&(1<<y))>>y)<<3));
40 			}
41 		}
42 		return output;
43 	}
44 }
45 ///
46 @safe pure unittest {
47 	import std.string : representation;
48 	const data = Intertwined4BPP(import("bpp4-sample1.bin").representation[0 .. 8 * 4]);
49 	const ubyte[8][8] finaldata = [
50 		[0x0, 0xF, 0x2, 0xE, 0xE, 0xE, 0xF, 0xA],
51 		[0x0, 0x0, 0xF, 0x6, 0xE, 0xE, 0xE, 0xE],
52 		[0x0, 0x0, 0xF, 0xF, 0xF, 0x8, 0xF, 0xF],
53 		[0x0, 0xF, 0xF, 0xF, 0x8, 0x8, 0x8, 0xF],
54 		[0x0, 0xF, 0x8, 0xF, 0x7, 0x7, 0xF, 0x7],
55 		[0x0, 0xF, 0x8, 0x7, 0x7, 0x7, 0xF, 0x7],
56 		[0x0, 0x0, 0xF, 0x8, 0x9, 0x9, 0x7, 0x7],
57 		[0x0, 0x0, 0x0, 0xF, 0x9, 0x9, 0xF, 0xA]
58 	];
59 	assert(data.pixelMatrix() == finaldata);
60 }
61 
62 /++
63 + 4 bit per pixel tile format with palette. Each pixel is stored in linear order.
64 + Commonly used by the GBA.
65 +/
66 align(1) struct GBA4BPP {
67 	align(1):
68 	ubyte[32] raw;
69 	@SerializationMethod
70 	string toBase64() const @safe {
71 		import std.base64 : Base64;
72 		return Base64.encode(raw[]);
73 	}
74 	ubyte[8][8] pixelMatrix() const @safe pure
75 		out(result; result.isValidBitmap!4)
76 	{
77 		ubyte[8][8] output;
78 		foreach (i, b; raw) {
79 			output[i / 4][(i % 4) * 2] = b&0xF;
80 			output[i / 4][(i % 4) * 2 + 1] = (b&0xF0) >> 4;
81 		}
82 		return output;
83 	}
84 }
85 ///
86 @safe pure unittest {
87 	import std.string : representation;
88 	const data = GBA4BPP(import("bpp4-sample2.bin").representation[0 .. 8 * 4]);
89 	const ubyte[8][8] finaldata = [
90 		[0x0, 0x0, 0x3, 0xC, 0x5, 0xC, 0x5, 0x0],
91 		[0xE, 0xC, 0xD, 0xE, 0x6, 0x6, 0x6, 0x6],
92 		[0xC, 0xC, 0xD, 0x0, 0x0, 0x0, 0xB, 0x0],
93 		[0x3, 0x0, 0x3, 0x7, 0x0, 0x0, 0x3, 0x8],
94 		[0x0, 0x0, 0xC, 0x0, 0x0, 0x0, 0xD, 0x0],
95 		[0x0, 0x0, 0x8, 0x0, 0x1, 0x1, 0xF, 0x1],
96 		[0x8, 0x8, 0x9, 0x8, 0x0, 0x0, 0xE, 0x0],
97 		[0xC, 0xD, 0xC, 0xC, 0xE, 0x6, 0x6, 0xE]
98 	];
99 	assert(data.pixelMatrix() == finaldata);
100 }