1 // This file is part of Deark.
2 // Copyright (C) 2016 Jason Summers
3 // See the file COPYING for terms of use.
5 // STOS Memory Bank (MBK)
7 #include <deark-config.h>
8 #include <deark-private.h>
9 #include <deark-fmtutil.h>
10 DE_DECLARE_MODULE(de_module_mbk
);
12 typedef struct localctx_struct
{
20 static const char* sprite_res_name
[3] = { "low", "med", "high" };
21 static const u8 sprite_res_bpp
[3] = { 4, 2, 1 };
24 static void do_sprite_param_block(deark
*c
, lctx
*d
, i64 res
,
25 i64 sprite_index
, i64 param_blk_pos
, i64 pos
)
27 i64 sprite_data_offs_raw
;
28 i64 width_raw
; // = width_in_pixels/16
33 struct atari_img_decode_data
*adata_fg
= NULL
;
34 struct atari_img_decode_data
*adata_mask
= NULL
;
36 u32 mask_pal
[2] = { DE_STOCKCOLOR_WHITE
, DE_STOCKCOLOR_BLACK
};
38 de_dbg(c
, "%s-res sprite #%d param block at %d", sprite_res_name
[res
],
39 (int)sprite_index
, (int)pos
);
41 adata_fg
= de_malloc(c
, sizeof(struct atari_img_decode_data
));
42 adata_mask
= de_malloc(c
, sizeof(struct atari_img_decode_data
));
44 adata_fg
->bpp
= (i64
)sprite_res_bpp
[res
];
45 adata_fg
->ncolors
= ((i64
)1)<<adata_fg
->bpp
;
47 adata_mask
->ncolors
= 2;
49 sprite_data_offs_raw
= de_getu32be(pos
);
51 //de_dbg(c, "sprite data offset: %d (->%d)", (int)sprite_data_offs_raw, (int)mask_offs);
52 width_raw
= (i64
)de_getbyte(pos
+4);
53 adata_fg
->w
= width_raw
*16;
54 adata_fg
->h
= (i64
)de_getbyte(pos
+5);
55 de_dbg_dimensions(c
, adata_fg
->w
, adata_fg
->h
);
56 if(!de_good_image_dimensions(c
, adata_fg
->w
, adata_fg
->h
)) goto done
;
58 adata_mask
->w
= adata_fg
->w
;
59 adata_mask
->h
= adata_fg
->h
;
60 mask_offs
= param_blk_pos
+ sprite_data_offs_raw
;
61 mask_size
= (width_raw
* 2 * 1) * adata_mask
->h
;
62 de_dbg(c
, "mask image at %d, len=%d", (int)mask_offs
, (int)mask_size
);
63 if(mask_offs
>=c
->infile
->len
) goto done
;
65 fg_offs
= mask_offs
+ mask_size
;
66 fg_size
= (width_raw
* 2 * adata_fg
->bpp
) * adata_fg
->h
;
67 de_dbg(c
, "foreground image at %d, len=%d", (int)fg_offs
, (int)fg_size
);
69 adata_mask
->unc_pixels
= dbuf_open_input_subfile(c
->infile
, mask_offs
, mask_size
);
70 adata_fg
->unc_pixels
= dbuf_open_input_subfile(c
->infile
, fg_offs
, fg_size
);
72 adata_mask
->pal
= mask_pal
;
73 adata_fg
->pal
= d
->pal
;
75 adata_mask
->img
= de_bitmap_create(c
, adata_fg
->w
, adata_fg
->h
, 1);
76 adata_fg
->img
= de_bitmap_create(c
, adata_fg
->w
, adata_fg
->h
, 4);
78 fmtutil_atari_decode_image(c
, adata_mask
);
79 fmtutil_atari_decode_image(c
, adata_fg
);
80 de_bitmap_apply_mask(adata_fg
->img
, adata_mask
->img
, 0);
81 fi
= de_finfo_create(c
);
82 fmtutil_atari_set_standard_density(c
, adata_fg
, fi
);
83 de_bitmap_write_to_file_finfo(adata_fg
->img
, fi
, 0);
87 dbuf_close(adata_fg
->unc_pixels
);
88 de_bitmap_destroy(adata_fg
->img
);
92 dbuf_close(adata_mask
->unc_pixels
);
93 de_bitmap_destroy(adata_mask
->img
);
94 de_free(c
, adata_mask
);
96 de_finfo_destroy(c
, fi
);
100 // A block of sprites for a particular resolution
101 static void do_sprite_param_blocks(deark
*c
, lctx
*d
, i64 res
,
102 i64 nsprites
, i64 pos
)
105 de_dbg(c
, "%s-res sprite param blocks at %d", sprite_res_name
[res
],
109 for(k
=0; k
<nsprites
; k
++) {
110 do_sprite_param_block(c
, d
, res
, k
, pos
, pos
+ 8*k
);
112 de_dbg_indent(c
, -1);
115 static void read_sprite_palette(deark
*c
, lctx
*d
, i64 pos
)
119 if(pos
>=c
->infile
->len
) return;
121 n
= de_getu32be(pos
);
123 de_warn(c
, "Sprite palette not found (expected at %d)", (int)pos
);
124 d
->pal
[0] = DE_STOCKCOLOR_WHITE
;
127 de_dbg(c
, "sprite palette at %d", (int)pos
);
129 fmtutil_read_atari_palette(c
, c
->infile
, pos
+4, d
->pal
, 16, 16, 0);
130 de_dbg_indent(c
, -1);
133 static void do_sprite_bank(deark
*c
, lctx
*d
, i64 pos
)
136 i64 paramoffs_raw
[3]; // One for each resolution: low, med, hi
139 i64 nsprites_total
= 0;
142 for(res
=0; res
<3; res
++) {
143 paramoffs_raw
[res
] = de_getu32be(pos
+4+4*res
);
144 // paramoffs is relative to the first position after the ID.
145 paramoffs
[res
] = pos
+ 4 + paramoffs_raw
[res
];
146 nsprites
[res
] = de_getu16be(pos
+16+2*res
);
147 de_dbg(c
, "%s-res sprites: %d, param blk offset: %d ("DE_CHAR_RIGHTARROW
" %d)", sprite_res_name
[res
],
148 (int)nsprites
[res
], (int)paramoffs_raw
[res
], (int)paramoffs
[res
]);
149 nsprites_total
+= nsprites
[res
];
152 // TODO: What's the right way to calculate the position of the palette?
153 pal_pos
= pos
+ 22 + (nsprites_total
)*8;
154 read_sprite_palette(c
, d
, pal_pos
);
156 for(res
=0; res
<3; res
++) {
157 if(nsprites
[res
]<1) continue;
158 if(paramoffs
[res
]>(c
->infile
->len
-8)) continue;
159 do_sprite_param_blocks(c
, d
, res
, nsprites
[res
], paramoffs
[res
]);
163 static void do_icon(deark
*c
, lctx
*d
, i64 idx
, i64 pos
)
165 de_bitmap
*img
= NULL
;
175 de_dbg(c
, "icon #%d, at %d", (int)idx
, (int)pos
);
178 format_flag
= de_getu16be(pos
+4);
179 de_dbg(c
, "format flag: 0x%04x", (unsigned int)format_flag
);
180 bgcol
= de_getu16be(pos
+6);
181 fgcol
= de_getu16be(pos
+8);
182 de_dbg(c
, "bgcol: 0x%04x, fgcol: 0x%04x", (unsigned int)bgcol
, (unsigned int)fgcol
);
184 // TODO: I don't know how to figure out what colors to use.
185 if(fgcol
==0 && bgcol
!=0) {
186 d
->pal
[0] = DE_STOCKCOLOR_BLACK
;
187 d
->pal
[1] = DE_STOCKCOLOR_WHITE
;
190 d
->pal
[0] = DE_STOCKCOLOR_WHITE
;
191 d
->pal
[1] = DE_STOCKCOLOR_BLACK
;
197 img
= de_bitmap_create(c
, w
, h
, 2);
199 bitsstart
= pos
+ 10;
202 mskbit
= de_get_bits_symbol(c
->infile
, 1, bitsstart
+ j
*rowspan
, i
);
203 fgbit
= de_get_bits_symbol(c
->infile
, 1, bitsstart
+ j
*rowspan
+ 2, i
);
204 clr
= d
->pal
[(unsigned int)fgbit
];
206 clr
= DE_SET_ALPHA(clr
, 0);
208 de_bitmap_setpixel_rgba(img
, i
, j
, clr
);
212 de_bitmap_write_to_file(img
, NULL
, 0);
213 de_bitmap_destroy(img
);
214 de_dbg_indent(c
, -1);
217 static void do_icon_bank(deark
*c
, lctx
*d
, i64 pos
)
222 num_icons
= de_getu16be(pos
+4);
223 de_dbg(c
, "number of icons: %d", (int)num_icons
);
224 for(k
=0; k
<num_icons
; k
++) {
225 do_icon(c
, d
, k
, pos
+6+84*k
);
229 static void do_mbk_data_bank(deark
*c
, lctx
*d
, i64 pos
)
231 const char *bn
= "?";
233 de_dbg(c
, "STOS data bank at %d", (int)pos
);
235 d
->data_bank_id
= (u32
)de_getu32be(pos
);
237 switch(d
->data_bank_id
) {
238 case 0x06071963U
: bn
= "packed screen"; break;
239 case 0x13490157U
: bn
= "music bank"; break;
240 case 0x28091960U
: bn
= "icon bank"; break;
241 case 0x19861987U
: bn
= "sprite bank"; break;
242 case 0x4d414553U
: bn
= "Maestro!"; break;
245 de_dbg(c
, "data bank id: 0x%08x (%s)", (unsigned int)d
->data_bank_id
, bn
);
247 switch(d
->data_bank_id
) {
249 do_sprite_bank(c
, d
, pos
);
252 do_icon_bank(c
, d
, pos
);
255 de_dbg_indent(c
, -1);
258 static void do_mbk(deark
*c
, lctx
*d
)
261 const char *bt
= "?";
263 de_dbg(c
, "MBK header at %d", (int)pos
);
266 de_dbg(c
, "bank number: %d", (int)d
->banknum
);
268 d
->banksize
= de_getu32be(14);
269 d
->banktype
= (u8
)(d
->banksize
>>24);
270 d
->banksize
&= (i64
)0x00ffffff;
272 switch(d
->banktype
) {
273 case 0x01: bt
= "work"; break;
274 case 0x02: bt
= "screen"; break;
275 case 0x81: bt
= "data"; break;
276 case 0x82: bt
= "datascreen"; break;
277 case 0x84: bt
= "set"; break;
278 case 0x85: bt
= "packed files"; break;
281 de_dbg(c
, "bank type: 0x%02x (%s)", (unsigned int)d
->banktype
, bt
);
282 de_dbg(c
, "bank size: %d", (int)d
->banksize
);
284 de_dbg_indent(c
, -1);
288 if(d
->banktype
==0x81) {
289 do_mbk_data_bank(c
, d
, pos
);
293 static void do_mbs(deark
*c
, lctx
*d
)
296 de_dbg(c
, "MBS header at %d", (int)pos
);
299 static void de_run_mbk_mbs(deark
*c
, de_module_params
*mparams
)
305 d
= de_malloc(c
, sizeof(lctx
));
307 de_read(buf
, 0, sizeof(buf
));
308 if(!de_memcmp(buf
, "Lionpoubnk", 10)) {
309 d
->banknum
= de_getu32be(10);
311 de_declare_fmt(c
, "STOS MBS");
315 de_declare_fmt(c
, "STOS MBK");
320 id
= (u32
)de_getu32be_direct(buf
);
322 if(id
==0x19861987U
) {
323 de_declare_fmt(c
, "STOS Sprite Bank");
324 do_sprite_bank(c
, d
, 0);
327 de_err(c
, "Not a (supported) STOS/MBK format");
334 static int de_identify_mbk(deark
*c
)
338 de_read(buf
, 0, sizeof(buf
));
339 if(!de_memcmp(buf
, "Lionpoubnk", 10))
341 if(!de_memcmp(buf
, "\x19\x86\x19\x87", 4)) { // Sprite bank
347 static void de_help_mbk(deark
*c
)
349 fmtutil_atari_help_palbits(c
);
352 void de_module_mbk(deark
*c
, struct deark_module_info
*mi
)
355 mi
->desc
= "STOS Memory Bank (.MBK)";
356 mi
->run_fn
= de_run_mbk_mbs
;
357 mi
->identify_fn
= de_identify_mbk
;
358 mi
->help_fn
= de_help_mbk
;