aboutsummaryrefslogtreecommitdiff
path: root/engines/glk/level9/bitmap.cpp
blob: 976c8a1a8e3b4f23e2e299f30baefb035a26ce53 (plain)
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
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 */

#include "glk/level9/level9_main.h"
#include "common/file.h"

namespace Glk {
namespace Level9 {

extern Bitmap *bitmap;

void L9Allocate(L9BYTE **ptr, L9UINT32 Size);

L9BOOL bitmap_exists(char *file) {
	return Common::File::exists(file);
}

L9BYTE *bitmap_load(char *file, L9UINT32 *size) {
	L9BYTE *data = NULL;

	Common::File f;
	if (f.open(file)) {
		*size = f.size();
		L9Allocate(&data, *size);
		f.read(data, *size);

		f.close();
	}
	return data;
}

Bitmap *bitmap_alloc(int x, int y) {
	Bitmap *b = NULL;
	L9Allocate((L9BYTE **)&b, sizeof(Bitmap) + (x * y));

	b->width = x;
	b->height = y;
	b->bitmap = ((L9BYTE *)b) + sizeof(Bitmap);
	b->npalette = 0;
	return b;
}

/*
    A PC or ST palette colour is a sixteen bit value in which the low three nybbles
    hold the rgb colour values. The lowest nybble holds the blue value, the
    second nybble the blue value and the third nybble the red value. (The high
    nybble is ignored). Within each nybble, only the low three bits are used
    IE the value can only be 0-7 not the full possible 0-15 and so the MSbit in
    each nybble is always 0.
*/
Colour bitmap_pcst_colour(int big, int small) {
	Colour col;
	L9UINT32 r = big & 0xF;
	L9UINT32 g = (small >> 4) & 0xF;
	L9UINT32 b = small & 0xF;

	r *= 0x49;
	r >>= 1;
	g *= 0x49;
	g >>= 1;
	b *= 0x49;
	b >>= 1;

	col.red = (L9BYTE)(r & 0xFF);
	col.green = (L9BYTE)(g & 0xFF);
	col.blue = (L9BYTE)(b & 0xFF);
	return col;
}

/*
    ST Bitmaps

    On the ST different graphics file formats were used for the early V4
    games (Knight Orc, Gnome Ranger) and the later V4 games (Lancelot,
    Ingrid's Back, Time & Magik and Scapeghost).
*/

/*
    Extracts the number of pixels requested from an eight-byte data block (4 bit-
    planes) passed to it.

    Note:   On entry each one of four pointers is set to point to the start of each
            bit-plane in the block. The function then indexes through each byte in
            each bit plane. and uses shift and mask operations to extract each four
            bit pixel into an L9PIXEL.

            The bit belonging to the pixel in the current byte of the current bit-
            plane is moved to its position in an eight-bit pixel. The byte is then
            masked by a value to select only that bit and added to the final pixel
            value.
*/
L9UINT32 bitmap_st1_decode_pixels(L9BYTE *pic, L9BYTE *data, L9UINT32 count, L9UINT32 pixels) {
	L9UINT32 bitplane_length = count / 4; /* length of each bitplane */
	L9BYTE *bitplane0 = data; /* address of bit0 bitplane */
	L9BYTE *bitplane1 = data + (bitplane_length); /* address of bit1 bitplane */
	L9BYTE *bitplane2 = data + (bitplane_length * 2); /* address of bit2 bitplane */
	L9BYTE *bitplane3 = data + (bitplane_length * 3); /* address of bit3 bitplane */
	L9UINT32 bitplane_index, pixel_index = 0; /* index variables */

	for (bitplane_index = 0; bitplane_index < bitplane_length; bitplane_index++) {
		/* build the eight pixels from the current bitplane bytes, high bit to low */

		/* bit7 byte */
		pic[pixel_index] = ((bitplane3[bitplane_index] >> 4) & 0x08)
		                   + ((bitplane2[bitplane_index] >> 5) & 0x04)
		                   + ((bitplane1[bitplane_index] >> 6) & 0x02)
		                   + ((bitplane0[bitplane_index] >> 7) & 0x01);
		if (pixels == ++pixel_index)
			break;

		/* bit6 byte */
		pic[pixel_index] = ((bitplane3[bitplane_index] >> 3) & 0x08)
		                   + ((bitplane2[bitplane_index] >> 4) & 0x04)
		                   + ((bitplane1[bitplane_index] >> 5) & 0x02)
		                   + ((bitplane0[bitplane_index] >> 6) & 0x01);
		if (pixels == ++pixel_index)
			break;

		/* bit5 byte */
		pic[pixel_index] = ((bitplane3[bitplane_index] >> 2) & 0x08)
		                   + ((bitplane2[bitplane_index] >> 3) & 0x04)
		                   + ((bitplane1[bitplane_index] >> 4) & 0x02)
		                   + ((bitplane0[bitplane_index] >> 5) & 0x01);
		if (pixels == ++pixel_index)
			break;

		/* bit4 byte */
		pic[pixel_index] = ((bitplane3[bitplane_index] >> 1) & 0x08)
		                   + ((bitplane2[bitplane_index] >> 2) & 0x04)
		                   + ((bitplane1[bitplane_index] >> 3) & 0x02)
		                   + ((bitplane0[bitplane_index] >> 4) & 0x01);
		if (pixels == ++pixel_index)
			break;

		/* bit3 byte */
		pic[pixel_index] = ((bitplane3[bitplane_index]) & 0x08)
		                   + ((bitplane2[bitplane_index] >> 1) & 0x04)
		                   + ((bitplane1[bitplane_index] >> 2) & 0x02)
		                   + ((bitplane0[bitplane_index] >> 3) & 0x01);
		if (pixels == ++pixel_index)
			break;

		/* bit2 byte */
		pic[pixel_index] = ((bitplane3[bitplane_index] << 1) & 0x08)
		                   + ((bitplane2[bitplane_index]) & 0x04)
		                   + ((bitplane1[bitplane_index] >> 1) & 0x02)
		                   + ((bitplane0[bitplane_index] >> 2) & 0x01);
		if (pixels == ++pixel_index)
			break;

		/* bit1 byte */
		pic[pixel_index] = ((bitplane3[bitplane_index] << 2) & 0x08)
		                   + ((bitplane2[bitplane_index] << 1) & 0x04)
		                   + ((bitplane1[bitplane_index]) & 0x02)
		                   + ((bitplane0[bitplane_index] >> 1) & 0x01);
		if (pixels == ++pixel_index)
			break;

		/* bit0 byte */
		pic[pixel_index] = ((bitplane3[bitplane_index] << 3) & 0x08)
		                   + ((bitplane2[bitplane_index] << 2) & 0x04)
		                   + ((bitplane1[bitplane_index] << 1) & 0x02)
		                   + ((bitplane0[bitplane_index]) & 0x01);
		if (pixels == ++pixel_index)
			break;
	}

	return pixel_index;
}

/*
    The ST image file has the following format. It consists of a 44 byte header
    followed by the image data.

    The header has the following format:
    Bytes 0-31:     sixteen entry ST palette
    Bytes 32-33:    padding
    Bytes 34-35:    big-endian word holding number of bitplanes needed to make
                up a row of pixels*
    Bytes 36-37:    padding
    Bytes 38-39:    big-endian word holding number of rows in the image*
    Bytes 40-41:    padding**
    Bytes 42-43:    mask for pixels to show in last 16 pixel block. Again, this
                is big endian

    [*]     these are probably big-endian unsigned longs but I have designated
            the upper two bytes as padding because (a) Level 9 does not need
            them as longs and (b) using unsigned shorts reduces byte sex induced
            byte order juggling.
    [**]    not certain what this is for but I suspect that, like bytes 42-43
            it is a mask to indicate which pixels to show, in this case in the
            first 16 pixel block

    The image data is essentially a memory dump of the video RAM representing
    the image in lo-res mode. In lo-res mode each row is 320 pixels wide
    and each pixel can be any one of sixteen colours - needs 4 bits to store.

    In the ST video memory (in lo-res mode which we are dealing with here)
    is organised as follows. The lowest point in memory in the frame buffer
    represents the top-left of the screen, the highest the bottom-right.
    Each row of pixels is stored in sequence.

    Within each pixel row the pixels are stored as follows. Each row is
    divided into groups of 16 pixels. Each sixteen pixel group is stored
    in 8 bytes, logically four groups of two. Each two byte pair
    is a bit-plane for that sixteen pixel group - that is it stores the
    same bit of each pixel in that group. The first two bytes store the
    lowest bit, the second pair the second bit &c.

    The word at bytes 34-35 of the header stores the number of bitplanes
    that make up each pixel row in the image. Multplying this number by
    four gives the number of pixels in the row***. For title and frame
    images that will be 320, for sub-images it will be less.

    [***]   Not always exactly. For GnomeRanger sub-images this value is 60
            - implying there are 240 pixels per row. In fact there are only
            225 pixels in each row. To identify this situation look at the
            big-endian word in bytes 42-43 of the header. This is a mask
            telling you the pixels to use. Each bit represents one pixel in
            the block, with the MSBit representing the first pixel and the
            LSbit the last.

            In this situation, the file does contain the entire sixteen
            pixel block (it has to with the bitplane arrangement) but
            the pixels which are not part of the image are just noise. When
            decoding the image, the L9BITMAP produced has the actual pixel
            dimensions - the surplus pixels are discarded.

            I suspect, though I have not found an instance, that in theory
            the same situation could apply at the start of a pixel row and that
            in this case the big-endian word at bytes 40-41 is the mask.

    Having obtained the pixel dimensions of the image the function uses
    them to allocate memory for the bitmap and then extracts the pixel
    information from the bitmap row by row. For each row eight byte blocks
    are read from the image data and passed to UnpackSTv1Pixels along with
    the number of pixels to extract (usually 16, possibly less for the last
    block in a row.)
*/
L9BOOL bitmap_st1_decode(char *file, int x, int y) {
	L9BYTE *data = NULL;
	int i, xi, yi, max_x, max_y, last_block;
	int bitplanes_row, bitmaps_row, pixel_count, get_pixels;

	L9UINT32 size;
	data = bitmap_load(file, &size);
	if (data == NULL)
		return FALSE;

	bitplanes_row = data[35] + data[34] * 256;
	bitmaps_row = bitplanes_row / 4;
	max_x = bitplanes_row * 4;
	max_y = data[39] + data[38] * 256;
	last_block = data[43] + data[42] * 256;

	/* Check if sub-image with rows shorter than max_x */
	if (last_block != 0xFFFF) {
		/* use last_block to adjust max_x */
		i = 0;
		while ((0x0001 & last_block) == 0) { /* test for ls bit set */
			last_block >>= 1; /* if not, shift right one bit */
			i++;
		}
		max_x = max_x - i;
	}

	if (max_x > MAX_BITMAP_WIDTH || max_y > MAX_BITMAP_HEIGHT) {
		free(data);
		return FALSE;
	}

	if ((x == 0) && (y == 0)) {
		if (bitmap)
			free(bitmap);
		bitmap = bitmap_alloc(max_x, max_y);
	}
	if (bitmap == NULL) {
		free(data);
		return FALSE;
	}

	if (x + max_x > bitmap->width)
		max_x = bitmap->width - x;
	if (y + max_y > bitmap->height)
		max_y = bitmap->height - y;

	for (yi = 0; yi < max_y; yi++) {
		pixel_count = 0;
		for (xi = 0; xi < bitmaps_row; xi++) {
			if ((max_x - pixel_count) < 16)
				get_pixels = max_x - pixel_count;
			else
				get_pixels = 16;

			pixel_count += bitmap_st1_decode_pixels(
			                   bitmap->bitmap + ((y + yi) * bitmap->width) + x + (xi * 16),
			                   data + 44 + (yi * bitplanes_row * 2) + (xi * 8), 8, get_pixels);
		}
	}

	bitmap->npalette = 16;
	for (i = 0; i < 16; i++)
		bitmap->palette[i] = bitmap_pcst_colour(data[(i * 2)], data[1 + (i * 2)]);

	free(data);
	return TRUE;
}

void bitmap_st2_name(int num, char *dir, char *out) {
	/* title picture is #30 */
	if (num == 0)
		num = 30;
	sprintf(out, "%s%d.squ", dir, num);
}

/*
    PC Bitmaps

    On the PC different graphics file formats were used for the early V4
    games (Knight Orc, Gnome Ranger) and the later V4 games (Lancelot,
    Ingrid's Back, Time & Magik and Scapeghost).

    The ST and the PC both use the same image file format for the later
    V4 games (Lancelot, Ingrid's Back, Time & Magik and Scapeghost.)
*/

void bitmap_pc_name(int num, char *dir, char *out) {
	/* title picture is #30 */
	if (num == 0)
		num = 30;
	sprintf(out, "%s%d.pic", dir, num);
}

/*
    The EGA standard for the IBM PCs and compatibles defines 64 colors, any
    16 of which can be mapped to the usable palette at any given time. If
    you display these 64 colors in numerical order, 16 at a time, you get a
    hodgepodge of colors in no logical order. The 64 EGA color numbers are
    assigned in a way that the numbers can easily be converted to a relative
    intensity of each of the three phosphor colors R,G,B. If the number is
    converted to six bit binary, the most significant three bits represent
    the 25% level of R,G,B in that order and the least significant three
    bits represent the 75% level of R,G,B in that order. Take EGA color 53
    for example. In binary, 53 is 110101. Since both R bits are on, R = 1.0.
    Of the G bits only the 25% bit is on so G = 0.25. Of the B bits only the
    75% bit is on so B = 0.75.
*/
Colour bitmap_pc1_colour(int i) {
	Colour col;
	col.red = (((i & 4) >> 1) | ((i & 0x20) >> 5)) * 0x55;
	col.green = ((i & 2) | ((i & 0x10) >> 4)) * 0x55;
	col.blue = (((i & 1) << 1) | ((i & 8) >> 3)) * 0x55;
	return col;
}

/*
    The PC (v1) image file has the following format. It consists of a 22
    byte header organised like this:

    Byte 0:     probably a file type flag
    Byte 1:     the MSB of the file's length as a word
    Bytes 2-3:  little-endian word with picture width in pixels
    Bytes 4-5:  little-endian word with picture height in pixel rows
    Bytes 6-21: the image colour table. One EGA colour in each byte

    The image data is extremely simple. The entire block is packed array
    of 4-bit pixels - IE each byte holds two pixels - the first in the high
    nybble, the second in the low. The pixel value is an index into the
    image colour table. The pixels are organised with the top left first and
    bottom left last, each row in turn.
*/
L9BOOL bitmap_pc1_decode(char *file, int x, int y) {
	L9BYTE *data = NULL;
	int i, xi, yi, max_x, max_y;

	L9UINT32 size;
	data = bitmap_load(file, &size);
	if (data == NULL)
		return FALSE;

	max_x = data[2] + data[3] * 256;
	max_y = data[4] + data[5] * 256;
	if (max_x > MAX_BITMAP_WIDTH || max_y > MAX_BITMAP_HEIGHT) {
		free(data);
		return FALSE;
	}

	if ((x == 0) && (y == 0)) {
		if (bitmap)
			free(bitmap);
		bitmap = bitmap_alloc(max_x, max_y);
	}
	if (bitmap == NULL) {
		free(data);
		return FALSE;
	}

	if (x + max_x > bitmap->width)
		max_x = bitmap->width - x;
	if (y + max_y > bitmap->height)
		max_y = bitmap->height - y;

	for (yi = 0; yi < max_y; yi++) {
		for (xi = 0; xi < max_x; xi++) {
			bitmap->bitmap[(bitmap->width * (y + yi)) + (x + xi)] =
			    (data[23 + ((yi * max_x) / 2) + (xi / 2)] >> ((1 - (xi & 1)) * 4)) & 0x0f;
		}
	}

	bitmap->npalette = 16;
	for (i = 0; i < 16; i++)
		bitmap->palette[i] = bitmap_pc1_colour(data[6 + i]);

	free(data);
	return TRUE;
}

/*
    The PC (v2) image file has the following format. It consists of a 44
    byte header followed by the image data.

    The header has the following format:
    Bytes 0-1: "datalen":   length of file -1 as a big-endian word*
    Bytes 2-3: "flagbyte1 & flagbyte2": unknown, possibly type identifiers.
        Usually 0xFF or 0xFE followed by 0x84, 0x72, 0xFF, 0xFE or
        some other (of a fairly small range of possibles) byte.
    Bytes 4-35: "colour_index[]": sixteen entry palette. Basically an ST
        palette (even if in a PC image file. Each entry is a sixteen
        bit value in which the low three nybbles hold the rgb colour
        values. The lowest nybble holds the blue value, the second
        nybble the blue value and the third nybble the red value. (The
        high nybble is ignored). Within each nybble, only the low
        three bits are used IE the value can only be 0-7 not the full
        possible 0-15 and so the MSbit in each nybble is always 0.**,
    Bytes 36-37: "width": image width in pixels as a big-endian word
    Bytes 38-39: "numrows": image height in pixel rows as a big-endian word
    Byte 40: "seedByte": seed byte to start picture decoding.
    Byte 41: "padByte": unknown. Possibly padding to word align the next
        element?
    Bytes 42-297: "pixelTable": an array of 0x100 bytes used as a lookup table
        for pixel values
    Bytes 298-313: "bitStripTable": an array of 0x10 bytes used as a lookup table
        for the number of bytes to strip from the bit stream for the pixel being
        decoded
    Bytes 314-569:  "indexByteTable": an array of 0x100 bytes used as a lookup
        table to index into bitStripTable and pixelTable****

    The encoded image data then follows ending in a 0x00 at the file length stored
    in the first two bytes of the file. there is then one extra byte holding a
    checksum produced by the addition of all the bytes in the file (except the first
    two and itself)*

    [*] in some PC games the file is padded out beyond this length to the
    nearest 0x80/0x00 boundary with the byte 0x1A. The valid data in the
    file still finishes where this word says with the checkbyte following it.
    [**] I imagine when a game was running on a PC this standard palette
    was algorithimcally changed to suit the graphics mode being used
    (Hercules, MDA, CGA, EGA, MCGA, VGA &c.)
    [***]   Note also, in image 1 of PC Time & Magik I think one palette entry
    is bad as what should be white in the image is actually set to
    a very pale yellow. This is corrected with the display of the next
    sub-picture and I am pretty sure it is note a decoding problem
    here as when run on the PC the same image has the same pale yellow
    cast.
    [****] for detail of how all this works see below

    As this file format is intended for two very different platforms the decoded
    imaged data is in a neutral, intermediate form. Each pixel is extracted as a
    byte with only the low four bits significant. The pixel value is an index into
    the sixteen entry palette.

    The pixel data is compressed, presumably to allow a greater number of images
    to be distributed on the (rather small) default ST & PC floppy disks (in both
    cases about 370 Kbytes.)*****

    Here's how to decode the data. The image data is actually a contiguous bit
    stream with the byte structure on disk having almost no relevance to the
    encoding. We access the bit stream via a two-byte buffer arranged as a word.

    Preparation:

    Initially, move the first byte from the image data into the low byte of
    theBitStreamBuffer and move the second byte of the image data into the
    high byte of theBitStreamBuffer.

    Set a counter (theBufferBitCounter) to 8 which you will use to keep track
    of when it is necesary to refill the buffer.

    Set a L9BYTE variable (theNewPixel) to byte 40 (seedByte) of the header.
    We need to do this because as part of identifying the pixel being
    extracted we need to know the value of the previous pixel extracted. Since
    none exists at this point we must prime this variable with the correct
    value.

    Extraction:

    Set up a loop which you will execute once for each pixel to be extracted
    and within that loop do as follows.

    Copy the low byte of theBitStreamBuffer to an L9BYTE
    (theNewPixelIndexSelector). Examine theNewPixelIndexSelector. If this
    is 0xFF this flags that the index to the new pixel is present as a
    literal in the bit stream; if it is NOT 0xFF then the new pixel index
    value has to be decoded.

    If theNewPixelIndexSelector is NOT 0xFF do as follows:

    Set the variable theNewPixelIndex to the byte in the
    indexByteTable array of the header indexed by
    theNewPixelIndexSelector.

    Set the variable theBufferBitStripCount to the value in the
    bitStripTable array of the header indexed by theNewPixelIndex.

    One-by-one use right bit shift (>>) to remove
    theBufferBitStripCount bits from theBitStreamBuffer. After each
    shift decrement theBufferBitCounter and check whether it has
    reached 0. If it has, get the next byte from the image data and
    insert it in the high byte of theBitStreamBuffer and reset
    theBufferBitCounter to 8. What is happening here is as we remove
    each bit from the bottom of the bit stream buffer we check to see
    if there are any bits left in the high byte of the buffer. As soon
    as we know there are none, we refill it with the next eight bits
    from the image data.

    When this 'bit-stripping' is finished, other than actually identifying
    the new pixel we are nearly done. I will leave that for the moment and
    look at what happens if the low byte of theBitStreamBuffer we put in
    theNewPixelIndexSelector was actually 0xFF:

    In this case, instead of the above routine we begin by removing
    the low eight bits from the theBitStreamBuffer. We use the same
    ono-by-one bit shift right process described above to do this,
    again checking after each shift if it is necesary to refill the
    buffer's high byte.

    When the eight bits have been removed we set theNewPixelIndex to
    the value of the low four bits of theBitStreamBuffer. Having done
    that we again one-by-one strip off those low four bits from the
    theBitStreamBuffer, again checking if we need to refill the buffer
    high byte.

    Irrespective of whether we initially had 0xFF in
    theNewPixelIndexSelector we now have a new value in theNewPixelIndex.
    This value is used as follows to obtain the new pixel value.

    The variable theNewPixel contains either the seedByte or the value of
    the previously extracted pixel. In either case this is a 4-bit value
    in the lower 4 bits. Use the left bit shift operator (or multiply by
    16) to shift those four bits into the high four bits of theNewPixel.

    Add the value in theNewPixelIndex (it is a 4-bit value) to
    theNewPixel. The resulting value is used as an index into the
    pixelTable array of the header to get the actual new pixel value so
    theNewPixel = header.pixelTable[theNewPixel] gets us our new pixel and
    primes theNewPixel for the same process next time around the loop.

    Having got our new pixel it is stored in the next empty space in the
    bitmap and we loop back and start again.

    [*****] I am not sure how the compression was done - someone with a better
    understanding of this area may be able to work out the method from the above.
    I worked out how to decode it by spending many, many hours tracing through the
    code in a debugger - thanks to the now defunct HiSoft for their DevPac ST and
    Gerin Philippe for NoSTalgia <http://users.skynet.be/sky39147/>.
*/
L9BOOL bitmap_pc2_decode(char *file, int x, int y) {
	L9BYTE *data = NULL;
	int i, xi, yi, max_x, max_y;

	L9BYTE theNewPixel, theNewPixelIndex;
	L9BYTE theBufferBitCounter, theNewPixelIndexSelector, theBufferBitStripCount;
	L9UINT16 theBitStreamBuffer, theImageDataIndex;
	L9BYTE *theImageFileData;

	L9UINT32 size;
	data = bitmap_load(file, &size);
	if (data == NULL)
		return FALSE;

	max_x = data[37] + data[36] * 256;
	max_y = data[39] + data[38] * 256;
	if (max_x > MAX_BITMAP_WIDTH || max_y > MAX_BITMAP_HEIGHT) {
		free(data);
		return FALSE;
	}

	if ((x == 0) && (y == 0)) {
		if (bitmap)
			free(bitmap);
		bitmap = bitmap_alloc(max_x, max_y);
	}
	if (bitmap == NULL) {
		free(data);
		return FALSE;
	}

	if (x + max_x > bitmap->width)
		max_x = bitmap->width - x;
	if (y + max_y > bitmap->height)
		max_y = bitmap->height - y;

	/* prime the new pixel variable with the seed byte */
	theNewPixel = data[40];
	/* initialise the index to the image data */
	theImageDataIndex = 0;
	/* prime the bit stream buffer */
	theImageFileData = data + 570;
	theBitStreamBuffer = theImageFileData[theImageDataIndex++];
	theBitStreamBuffer = theBitStreamBuffer +
	                     (0x100 * theImageFileData[theImageDataIndex++]);
	/* initialise the bit stream buffer bit counter */
	theBufferBitCounter = 8;

	for (yi = 0; yi < max_y; yi++) {
		for (xi = 0; xi < max_x; xi++) {
			theNewPixelIndexSelector = (theBitStreamBuffer & 0x00FF);
			if (theNewPixelIndexSelector != 0xFF) {
				/* get index for new pixel and bit strip count */
				theNewPixelIndex = (data + 314)[theNewPixelIndexSelector];
				/* get the bit strip count */
				theBufferBitStripCount = (data + 298)[theNewPixelIndex];
				/* strip theBufferBitStripCount bits from theBitStreamBuffer */
				while (theBufferBitStripCount > 0) {
					theBitStreamBuffer = theBitStreamBuffer >> 1;
					theBufferBitStripCount--;
					theBufferBitCounter--;
					if (theBufferBitCounter == 0) {
						/* need to refill the theBitStreamBuffer high byte */
						theBitStreamBuffer = theBitStreamBuffer +
						                     (0x100 * theImageFileData[theImageDataIndex++]);
						/* re-initialise the bit stream buffer bit counter */
						theBufferBitCounter = 8;
					}
				}
			} else {
				/* strip the 8 bits holding 0xFF from theBitStreamBuffer */
				theBufferBitStripCount = 8;
				while (theBufferBitStripCount > 0) {
					theBitStreamBuffer = theBitStreamBuffer >> 1;
					theBufferBitStripCount--;
					theBufferBitCounter--;
					if (theBufferBitCounter == 0) {
						/* need to refill the theBitStreamBuffer high byte */
						theBitStreamBuffer = theBitStreamBuffer +
						                     (0x100 * theImageFileData[theImageDataIndex++]);
						/* re-initialise the bit stream buffer bit counter */
						theBufferBitCounter = 8;
					}
				}
				/* get the literal pixel index value from the bit stream */
				theNewPixelIndex = (0x000F & theBitStreamBuffer);
				theBufferBitStripCount = 4;
				/* strip 4 bits from theBitStreamBuffer */
				while (theBufferBitStripCount > 0) {
					theBitStreamBuffer = theBitStreamBuffer >> 1;
					theBufferBitStripCount--;
					theBufferBitCounter--;
					if (theBufferBitCounter == 0) {
						/* need to refill the theBitStreamBuffer high byte */
						theBitStreamBuffer = theBitStreamBuffer +
						                     (0x100 * theImageFileData[theImageDataIndex++]);
						/* re-initialise the bit stream buffer bit counter */
						theBufferBitCounter = 8;
					}
				}
			}

			/* shift the previous pixel into the high four bits of theNewPixel */
			theNewPixel = (0xF0 & (theNewPixel << 4));
			/* add the index to the new pixel to theNewPixel */
			theNewPixel = theNewPixel + theNewPixelIndex;
			/* extract the nex pixel from the table */
			theNewPixel = (data + 42)[theNewPixel];
			/* store new pixel in the bitmap */
			bitmap->bitmap[(bitmap->width * (y + yi)) + (x + xi)] = theNewPixel;
		}
	}

	bitmap->npalette = 16;
	for (i = 0; i < 16; i++)
		bitmap->palette[i] = bitmap_pcst_colour(data[4 + (i * 2)], data[5 + (i * 2)]);

	free(data);
	return TRUE;
}

BitmapType bitmap_pc_type(char *file) {
	BitmapType type = PC2_BITMAPS;

	Common::File f;
	if (f.open(file)) {
		L9BYTE data[6];
		int x, y;

		if (f.read(data, sizeof(data)) != sizeof(data) && !f.eos())
			return NO_BITMAPS;
		f.close();

		x = data[2] + data[3] * 256;
		y = data[4] + data[5] * 256;

		if ((x == 0x0140) && (y == 0x0087))
			type = PC1_BITMAPS;
		if ((x == 0x00E0) && (y == 0x0074))
			type = PC1_BITMAPS;
		if ((x == 0x0140) && (y == 0x0087))
			type = PC1_BITMAPS;
		if ((x == 0x00E1) && (y == 0x0076))
			type = PC1_BITMAPS;
	}

	return type;
}

/*
    Amiga Bitmaps
*/

void bitmap_noext_name(int num, char *dir, char *out) {
	if (num == 0) {
		sprintf(out, "%stitle", dir);
		if (Common::File::exists(out))
			return;

		num = 30;
	}

	sprintf(out, "%s%d", dir, num);
}

int bitmap_amiga_intensity(int col) {
	return (int)(pow((double)col / 15, 1.0 / 0.8) * 0xff);
}

/*
    Amiga palette colours are word length structures with the red, green and blue
    values stored in the second, third and lowest nybles respectively. The high
    nybble is always zero.
*/
Colour bitmap_amiga_colour(int i1, int i2) {
	Colour col;
	col.red = bitmap_amiga_intensity(i1 & 0xf);
	col.green = bitmap_amiga_intensity(i2 >> 4);
	col.blue = bitmap_amiga_intensity(i2 & 0xf);
	return col;
}

/*
    The Amiga image file has the following format. It consists of a 44 byte
    header followed by the image data.

    The header has the following format:
    Bytes 0-63:  thirty-two entry Amiga palette
    Bytes 64-65: padding
    Bytes 66-67: big-endian word holding picture width in pixels*
    Bytes 68-69: padding
    Bytes 70-71: big-endian word holding number of pixel rows in the image*

    [*] these are probably big-endian unsigned longs but I have designated
    the upper two bytes as padding because (a) Level 9 does not need
    them as longs and (b) using unsigned shorts reduces byte sex induced
    byte order juggling.

    The images are designed for an Amiga low-res mode screen - that is they
    assume a 320*256 (or 320 * 200 if NSTC display) screen with a palette of
    32 colours from the possible 4096.

    The image data is organised the same way that Amiga video memory is. The
    entire data block is divided into five equal length bit planes with the
    first bit plane holding the low bit of each 5-bit pixel, the second bitplane
    the second bit of the pixel and so on up to the fifth bit plane holding the
    high bit of the f5-bit pixel.
*/
L9BOOL bitmap_amiga_decode(char *file, int x, int y) {
	L9BYTE *data = NULL;
	int i, xi, yi, max_x, max_y, p, b;

	L9UINT32 size;
	data = bitmap_load(file, &size);
	if (data == NULL)
		return FALSE;

	max_x = (((((data[64] << 8) | data[65]) << 8) | data[66]) << 8) | data[67];
	max_y = (((((data[68] << 8) | data[69]) << 8) | data[70]) << 8) | data[71];
	if (max_x > MAX_BITMAP_WIDTH || max_y > MAX_BITMAP_HEIGHT) {
		free(data);
		return FALSE;
	}

	if ((x == 0) && (y == 0)) {
		if (bitmap)
			free(bitmap);
		bitmap = bitmap_alloc(max_x, max_y);
	}
	if (bitmap == NULL) {
		free(data);
		return FALSE;
	}

	if (x + max_x > bitmap->width)
		max_x = bitmap->width - x;
	if (y + max_y > bitmap->height)
		max_y = bitmap->height - y;

	for (yi = 0; yi < max_y; yi++) {
		for (xi = 0; xi < max_x; xi++) {
			p = 0;
			for (b = 0; b < 5; b++)
				p |= ((data[72 + (max_x / 8) * (max_y * b + yi) + xi / 8] >> (7 - (xi % 8))) & 1) << b;
			bitmap->bitmap[(bitmap->width * (y + yi)) + (x + xi)] = p;
		}
	}

	bitmap->npalette = 32;
	for (i = 0; i < 32; i++)
		bitmap->palette[i] = bitmap_amiga_colour(data[i * 2], data[i * 2 + 1]);

	free(data);
	return TRUE;
}

BitmapType bitmap_noext_type(char *file) {
	Common::File f;
	if (f.open(file)) {
		L9BYTE data[72];
		int x, y;

		if (f.read(data, sizeof(data)) != sizeof(data) && !f.eos())
			return NO_BITMAPS;
		f.close();

		x = data[67] + data[66] * 256;
		y = data[71] + data[70] * 256;

		if ((x == 0x0140) && (y == 0x0088))
			return AMIGA_BITMAPS;
		if ((x == 0x0140) && (y == 0x0087))
			return AMIGA_BITMAPS;
		if ((x == 0x00E0) && (y == 0x0075))
			return AMIGA_BITMAPS;
		if ((x == 0x00E4) && (y == 0x0075))
			return AMIGA_BITMAPS;
		if ((x == 0x00E0) && (y == 0x0076))
			return AMIGA_BITMAPS;
		if ((x == 0x00DB) && (y == 0x0076))
			return AMIGA_BITMAPS;

		x = data[3] + data[2] * 256;
		y = data[7] + data[6] * 256;

		if ((x == 0x0200) && (y == 0x00D8))
			return MAC_BITMAPS;
		if ((x == 0x0168) && (y == 0x00BA))
			return MAC_BITMAPS;
		if ((x == 0x0168) && (y == 0x00BC))
			return MAC_BITMAPS;
		if ((x == 0x0200) && (y == 0x00DA))
			return MAC_BITMAPS;
		if ((x == 0x0168) && (y == 0x00DA))
			return MAC_BITMAPS;

		x = data[35] + data[34] * 256;
		y = data[39] + data[38] * 256;

		if ((x == 0x0050) && (y == 0x0087))
			return ST1_BITMAPS;
		if ((x == 0x0038) && (y == 0x0074))
			return ST1_BITMAPS;
	}

	return NO_BITMAPS;
}

/*
    Macintosh Bitmaps
*/

/*
    The Mac image file format is very simple. The header is ten bytes
    with the width of the image in pixels in the first long and the
    height (in pixel rows) in the second long - both are big-endian.
    (In both cases I treat these as unsigned shorts to minimise byte
    twiddling when working around byte sex issues). There follow two
    unidentified bytes - possibly image type identifiers or maybe
    valid pixel masks for the beginning and end of pixel rows in
    sub-images.

    The image data is extremely simple. The entire block is a packed array
    of 1-bit pixels - I.E. each byte holds eight pixels - with 1 representing
    white and 0 representing black. The pixels are organised with the top
    left first and bottom left last, each row in turn.

    The image sizes are 512 * 216 pixels for main images and 360 * 186 pixels
    for sub-images.
*/
L9BOOL bitmap_mac_decode(char *file, int x, int y) {
	L9BYTE *data = NULL;
	int xi, yi, max_x, max_y;

	L9UINT32 size;
	data = bitmap_load(file, &size);
	if (data == NULL)
		return FALSE;

	max_x = data[3] + data[2] * 256;
	max_y = data[7] + data[6] * 256;
	if (max_x > MAX_BITMAP_WIDTH || max_y > MAX_BITMAP_HEIGHT) {
		free(data);
		return FALSE;
	}

	if (x > 0)  /* Mac bug, apparently */
		x = 78;

	if ((x == 0) && (y == 0)) {
		if (bitmap)
			free(bitmap);
		bitmap = bitmap_alloc(max_x, max_y);
	}
	if (bitmap == NULL) {
		free(data);
		return FALSE;
	}

	if (x + max_x > bitmap->width)
		max_x = bitmap->width - x;
	if (y + max_y > bitmap->height)
		max_y = bitmap->height - y;

	for (yi = 0; yi < max_y; yi++) {
		for (xi = 0; xi < max_x; xi++) {
			bitmap->bitmap[(bitmap->width * (y + yi)) + (x + xi)] =
			    (data[10 + (max_x / 8) * yi + xi / 8] >> (7 - (xi % 8))) & 1;
		}
	}

	bitmap->npalette = 2;
	bitmap->palette[0].red = 0;
	bitmap->palette[0].green = 0;
	bitmap->palette[0].blue = 0;
	bitmap->palette[1].red = 0xff;
	bitmap->palette[1].green = 0xff;
	bitmap->palette[1].blue = 0xff;

	free(data);
	return TRUE;
}

/*
    C64 Bitmaps, also related formats (BBC B, Amstrad CPC and Spectrum +3)
*/

/* Commodore 64 palette from Vice */
const Colour bitmap_c64_colours[] = {
	{0x00, 0x00, 0x00 },
	{0xff, 0xff, 0xff },
	{0x89, 0x40, 0x36 },
	{0x7a, 0xbf, 0xc7 },
	{0x8a, 0x46, 0xae },
	{0x68, 0xa9, 0x41 },
	{0x3e, 0x31, 0xa2 },
	{0xd0, 0xdc, 0x71 },
	{0x90, 0x5f, 0x25 },
	{0x5c, 0x47, 0x00 },
	{0xbb, 0x77, 0x6d },
	{0x55, 0x55, 0x55 },
	{0x80, 0x80, 0x80 },
	{0xac, 0xea, 0x88 },
	{0x7c, 0x70, 0xda },
	{0xab, 0xab, 0xab }
};

const Colour bitmap_bbc_colours[] = {
	{0x00, 0x00, 0x00 },
	{0xff, 0x00, 0x00 },
	{0x00, 0xff, 0x00 },
	{0xff, 0xff, 0x00 },
	{0x00, 0x00, 0xff },
	{0xff, 0x00, 0xff },
	{0x00, 0xff, 0xff },
	{0xff, 0xff, 0xff }
};

void bitmap_c64_name(int num, char *dir, char *out) {
	if (num == 0)
		sprintf(out, "%stitle mpic", dir);
	else
		sprintf(out, "%spic%d", dir, num);
}

void bitmap_bbc_name(int num, char *dir, char *out) {
	if (num == 0) {
		sprintf(out, "%sP.Title", dir);
		if (Common::File::exists(out))
			return;

		sprintf(out, "%stitle", dir);
	} else {
		sprintf(out, "%sP.Pic%d", dir, num);
		if (Common::File::exists(out))
			return;

		sprintf(out, "%spic%d", dir, num);
	}
}

void bitmap_cpc_name(int num, char *dir, char *out) {
	if (num == 0)
		sprintf(out, "%stitle.pic", dir);
	else if (num == 1)
		sprintf(out, "%s1.pic", dir);
	else
		sprintf(out, "%sallpics.pic", dir);
}

BitmapType bitmap_c64_type(char *file) {
	BitmapType type = C64_BITMAPS;

	Common::File f;
	if (f.open(file)) {
		L9UINT32 size = f.size();
		f.close();

		if (size == 10048)
			type = BBC_BITMAPS;
		if (size == 6494)
			type = BBC_BITMAPS;
	}

	return type;
}

/*
    The C64 graphics file format is (loosely) based on the layout of
    C64 graphics memory. There are in fact two formats (i) the
    standard game images and (ii) title pictures. For both formats
    the file begins within the 2-byte pair 0x00 and 0x20.

    The images are "multi-color bitmap mode" images which means they
    have rows of 160 double width pixels and can be up to 200 rows
    long. (The title images are 200 lines long, the game images are
    136 lines long.) Unlike Amiga, Mac, ST and PC graphics there are
    no "main" and "sub" images. All game graphics have the same
    dimensions and each completely replaces its predecessor.

    The graphics files used on the Amstrad CPC and Spectrum +3 are also
    virtually identical to C64 graphics files. This choice was presumably
    made because although the CPC screen was more capable than the c64 it
    was (in low resolution) the same size (160*200) and presumably
    algorothmic conversion conversion of the colours was trivial for
    the interpreter. In addition (a) the artwork already existed so no
    extra expense would be incurred and (b) by accepting the C64's
    limitation of only four colours in each 4*8 pixel block (but still
    with sixteen colours on screen) they got a compressed file format
    allowing more pictures on each disk.

    The file organisation is rather different though. Only picture
    one and the title picture are separate files. All the other
    pictures (2-29) are stored in one large file "allpics.pic".

    On these platforms the picture 1 file and title picture file have
    an AMSDOS header (a 128 byte block of metadata) which contains a
    checksum of the first 66 bytes of the header in a little-endian
    word at bytes 67 & 68. On the original C64 platform there was a
    simple two byte header. Following the header the data is organised
    exactly as in the C64 game and title image files. The
    'allpics.pic" file has no header and consists of 0x139E blocks
    each forming a picture, in the C64 game file format (minus the two
    byte header).
*/
L9BOOL bitmap_c64_decode(char *file, BitmapType type, int num) {
	L9BYTE *data = NULL;
	int i = 0, xi, yi, max_x = 0, max_y = 0, cx, cy, px, py, p;
	int off = 0, off_scr = 0, off_col = 0, off_bg = 0, col_comp = 0;

	L9UINT32 size;
	data = bitmap_load(file, &size);
	if (data == NULL)
		return FALSE;

	if (type == C64_BITMAPS) {
		if (size == 10018) { /* C64 title picture */
			max_x = 320;
			max_y = 200;
			off = 2;
			off_scr = 8002;
			off_bg = 9003;
			off_col = 9018;
			col_comp = 0;
		} else if (size == 6464) { /* C64 picture */
			max_x = 320;
			max_y = 136;
			off = 2;
			off_scr = 5442;
			off_col = 6122;
			off_bg = 6463;
			col_comp = 1;
		} else
			return FALSE;
	} else if (type == BBC_BITMAPS) {
		if (size == 10058) { /* BBC title picture */
			max_x = 320;
			max_y = 200;
			off = 10;
			off_scr = 8010;
			off_bg = 9011;
			off_col = 9026;
			col_comp = 0;
		} else if (size == 10048) { /* BBC title picture */
			max_x = 320;
			max_y = 200;
			off = 0;
			off_scr = 8000;
			off_bg = 9001;
			off_col = 9016;
			col_comp = 0;
		} else if (size == 6504) { /* BBC picture */
			max_x = 320;
			max_y = 136;
			off = 10;
			off_scr = 5450;
			off_col = 6130;
			off_bg = 6471;
			col_comp = 1;
		} else if (size == 6494) { /* BBC picture */
			max_x = 320;
			max_y = 136;
			off = 0;
			off_scr = 5440;
			off_col = 6120;
			off_bg = 6461;
			col_comp = 1;
		} else
			return FALSE;
	} else if (type == CPC_BITMAPS) {
		if (num == 0) { /* CPC/+3 title picture */
			max_x = 320;
			max_y = 200;
			off = 128;
			off_scr = 8128;
			off_bg = 9128;
			off_col = 9144;
			col_comp = 0;
		} else if (num == 1) { /* First CPC/+3 picture */
			max_x = 320;
			max_y = 136;
			off = 128;
			off_scr = 5568;
			off_col = 6248;
			off_bg = 6588;
			col_comp = 1;
		} else if (num >= 2 && num <= 29) { /* Subsequent CPC/+3 pictures */
			max_x = 320;
			max_y = 136;
			off = ((num - 2) * 6462);
			off_scr = 5440 + ((num - 2) * 6462);
			off_col = 6120 + ((num - 2) * 6462);
			off_bg = 6460 + ((num - 2) * 6462);
			col_comp = 1;
		} else
			return FALSE;
	}

	if (bitmap)
		free(bitmap);
	bitmap = bitmap_alloc(max_x, max_y);
	if (bitmap == NULL) {
		free(data);
		return FALSE;
	}

	for (yi = 0; yi < max_y; yi++) {
		for (xi = 0; xi < max_x / 2; xi++) {
			cx = xi / 4;
			px = xi % 4;
			cy = yi / 8;
			py = yi % 8;

			p = data[off + (cy * 40 + cx) * 8 + py];
			p = (p >> ((3 - px) * 2)) & 3;

			switch (p) {
			case 0:
				i = data[off_bg] & 0x0f;
				break;
			case 1:
				i = data[off_scr + cy * 40 + cx] >> 4;
				break;
			case 2:
				i = data[off_scr + cy * 40 + cx] & 0x0f;
				break;
			case 3:
				if (col_comp)
					i = (data[off_col + (cy * 40 + cx) / 2] >> ((1 - (cx % 2)) * 4)) & 0x0f;
				else
					i = data[off_col + (cy * 40 + cx)] & 0x0f;
				break;
			}

			bitmap->bitmap[(bitmap->width * yi) + (xi * 2)] = i;
			bitmap->bitmap[(bitmap->width * yi) + (xi * 2) + 1] = i;
		}
	}

	bitmap->npalette = 16;
	for (i = 0; i < 16; i++)
		bitmap->palette[i] = bitmap_c64_colours[i];

	free(data);
	return TRUE;
}

/*
    The graphics files used by the BBC B are virtually identical
    to C64 graphics files. I assume that (as with the CPC and
    Spectrum+3) this choice was made because the BBC mode 2 screen,
    was nearly the same size (160*256) and had roughly the same capability
    as the C64 screen (displays 16 colours, although eight of those ar
    just the first eight flashing).

    In addition (a) the artwork already existed so no extra expense would
    be incurred and (b) by accepting the C64's limitation of only four
    colours in each 4*8 pixel block (but still with sixteen colours on
    screen) they got a compressed file format allowing more pictures
    on each disk.

    The file organisation is very close to the C64. The naming system
    can be the same eg "PIC12", but another form is also used :
    "P.Pic12". Unlike the C64 the BBC has well defined title images,
    called "TITLE" or P.Title. All pictures are in separate files.

    The only difference seems to be:

    * There is either *no* header before the image data or a simple
    10 byte header which I think *may* be a file system header
    left in place by the extractor system.

    * There is an extra 32 bytes following the data at the end of
    each file. These bytes encode a table to convert between the 16
    C64 colours and 16, four-pixel pix-patterns used to let the BBC
    (with only 8 colours) represent the sixteen possible C64 colours.

    A pix-pattern looks like this:

             |   Even |   Odd   |
             | Column | Column  |
        -----------------------------
        Even Row |Pixel 1 | Pixel 2 |
        ---------|--------|---------|
        Odd Row  |Pixel 3 | Pixel 4 |
        -----------------------------

    Each of the four pixel *can* be any of the eight BBC Mode 2
    steady colours. In practice they seem either to be all the
    same or a simple check of two colours - the pixels in the
    odd row being in the reverse order to those in the even row.

    When converting a C64 pixel to a BBC pixel the game uses the
    value of the C64 pixel as an index into the array of sixteen
    BBC pix-patterns. The game looks at the selected pattern and
    chooses the BBC pixel colour thus: if the pixel is in an even
    numbered row and an even numbered column, it uses Pixel 1 from
    the pattern, if in an even row but an odd column, it uses Pixel 3
    and so on.

    The pix-pattern data is encoded thus: the first sixteen bytes
    encode the even row pixels for the patterns, one byte per
    pattern, and in the same way the second sixteen bytes encode
    the odd row pixels for each pattern. For example for the
    pattern representing C64 colour 0 the even row pixels are encoded
    in the first byte and the odd row pixels in the sixteenth byte.

    Within each byte the pixels are encoded in this way:

    Bit     7   6   5   4   3   2   1   0
    -------------------------------------
            0   0   1   0   0   1   1   1
            |   |   |   |   |   |   |   |
            +---|---+---|---+---|---+---|----- Even Pixel 0101 (5)
                |       |       |       |
                +-------+-------+-------+----- Odd Pixel 0011 (3)

    This function calls the C64 decoding routines to do the actual
    loading. See the comments to that function for details of how the
    image is encoded and stored.
*/
L9BOOL bitmap_bbc_decode(char *file, BitmapType type, int num) {
	unsigned char   patRowData[32];
	unsigned char patArray[16][2][2];
	int i, j, k, isOddColumn, isOddRow;
	L9BYTE pixel;

	if (bitmap_c64_decode(file, type, num) == FALSE)
		return FALSE;

	Common::File f;
	if (!f.open(file))
		return FALSE;

	/* Seek to the offset of the pixPat data and read in the data */
	f.seek(f.size() - 32, SEEK_SET);
	if (f.read(patRowData, 32) != 32 && !f.eos())
		return FALSE;
	f.close();

	/* Extract the patterns */
	i = 0;
	for (k = 0; k < 2; k++) {
		for (j = 0; j < 16; j++) {
			/* Extract the even col pixel for this pattern row */
			patArray[j][k][0] =
			    ((patRowData[i] >> 4) & 0x8) + ((patRowData[i] >> 3) & 0x4) +
			    ((patRowData[i] >> 2) & 0x2) + ((patRowData[i] >> 1) & 0x1);
			/* Extract the odd col pixel for this pattern row */
			patArray[j][k][1] =
			    ((patRowData[i] >> 3) & 0x8) + ((patRowData[i] >> 2) & 0x4) +
			    ((patRowData[i] >> 1) & 0x2) + (patRowData[i] & 0x1);
			i++;
		}
	}

	/* Convert the image. Each BBC pixel is represented by two pixels here */
	i = 0;
	isOddRow = 0;
	for (j = 0; j < bitmap->height; j++) {
		isOddColumn = 0;
		for (k = 0; k < bitmap->width / 2; k++) {
			pixel = bitmap->bitmap[i];
			bitmap->bitmap[i] = patArray[pixel][isOddColumn][isOddRow];
			bitmap->bitmap[i + 1] = patArray[pixel][isOddColumn][isOddRow];
			isOddColumn ^= 1;
			i += 2;
		}
		isOddRow ^= 1;
	}

	bitmap->npalette = 8;
	for (i = 0; i < 8; i++)
		bitmap->palette[i] = bitmap_bbc_colours[i];

	return TRUE;
}

BitmapType DetectBitmaps(char *dir) {
	char file[MAX_PATH];

	bitmap_noext_name(2, dir, file);
	if (bitmap_exists(file))
		return bitmap_noext_type(file);

	bitmap_pc_name(2, dir, file);
	if (bitmap_exists(file))
		return bitmap_pc_type(file);

	bitmap_c64_name(2, dir, file);
	if (bitmap_exists(file))
		return bitmap_c64_type(file);

	bitmap_bbc_name(2, dir, file);
	if (bitmap_exists(file))
		return BBC_BITMAPS;

	bitmap_cpc_name(2, dir, file);
	if (bitmap_exists(file))
		return CPC_BITMAPS;

	bitmap_st2_name(2, dir, file);
	if (bitmap_exists(file))
		return ST2_BITMAPS;

	return NO_BITMAPS;
}

Bitmap *DecodeBitmap(char *dir, BitmapType type, int num, int x, int y) {
	char file[MAX_PATH];

	switch (type) {
	case PC1_BITMAPS:
		bitmap_pc_name(num, dir, file);
		if (bitmap_pc1_decode(file, x, y))
			return bitmap;
		break;

	case PC2_BITMAPS:
		bitmap_pc_name(num, dir, file);
		if (bitmap_pc2_decode(file, x, y))
			return bitmap;
		break;

	case AMIGA_BITMAPS:
		bitmap_noext_name(num, dir, file);
		if (bitmap_amiga_decode(file, x, y))
			return bitmap;
		break;

	case C64_BITMAPS:
		bitmap_c64_name(num, dir, file);
		if (bitmap_c64_decode(file, type, num))
			return bitmap;
		break;

	case BBC_BITMAPS:
		bitmap_bbc_name(num, dir, file);
		if (bitmap_bbc_decode(file, type, num))
			return bitmap;
		break;

	case CPC_BITMAPS:
		bitmap_cpc_name(num, dir, file);
		if (bitmap_c64_decode(file, type, num)) /* Nearly identical to C64 */
			return bitmap;
		break;

	case MAC_BITMAPS:
		bitmap_noext_name(num, dir, file);
		if (bitmap_mac_decode(file, x, y))
			return bitmap;
		break;

	case ST1_BITMAPS:
		bitmap_noext_name(num, dir, file);
		if (bitmap_st1_decode(file, x, y))
			return bitmap;
		break;

	case ST2_BITMAPS:
		bitmap_st2_name(num, dir, file);
		if (bitmap_pc2_decode(file, x, y))
			return bitmap;
		break;

	default:
		break;
	}

	return NULL;
}

} // End of namespace Level9
} // End of namespace Glk