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
);
11 DE_DECLARE_MODULE(de_module_stos_pp1
);
12 DE_DECLARE_MODULE(de_module_stos_pp2
);
13 DE_DECLARE_MODULE(de_module_stos_pp3
);
14 DE_DECLARE_MODULE(de_module_stos_daj
);
16 #define BANKID_PKSCREEN 0x06071963U
17 #define BANKID_SPRITE 0x19861987U
19 #define PKPIC_IMGTYPE_UNKNOWN 99
20 #define PKPIC_IMGTYPE_LOW 100
21 #define PKPIC_IMGTYPE_MED 101
22 #define PKPIC_IMGTYPE_HIGH 102
23 #define PKPIC_IMGTYPE_PP1 110
24 #define PKPIC_IMGTYPE_PP3 112
25 #define PKPIC_IMGTYPE_M4P 120
27 static const u8
*g_lion_sig
= (const u8
*)"Lionpoubnk";
31 UI imgtype
; // PKPIC_IMGTYPE_*
35 i64 pseudowidth
, pseudoheight
;
37 i64 picdata_rel
, picdata_abs
;
38 i64 rledata_rel
, rledata_abs
;
39 i64 pointdata_rel
, pointdata_abs
;
43 typedef struct localctx_struct
{
45 UI imgtype_of_res0
; // PKPIC_IMGTYPE_*
54 static const char* sprite_res_name
[3] = { "low", "med", "high" };
55 static const u8 sprite_res_bpp
[3] = { 4, 2, 1 };
58 static void do_sprite_param_block(deark
*c
, lctx
*d
, i64 res
,
59 i64 sprite_index
, i64 param_blk_pos
, i64 pos
)
61 i64 sprite_data_offs_raw
;
62 i64 width_raw
; // = width_in_pixels/16
67 struct atari_img_decode_data
*adata_fg
= NULL
;
68 struct atari_img_decode_data
*adata_mask
= NULL
;
70 u32 mask_pal
[2] = { DE_STOCKCOLOR_WHITE
, DE_STOCKCOLOR_BLACK
};
72 de_dbg(c
, "%s-res sprite #%d param block at %d", sprite_res_name
[res
],
73 (int)sprite_index
, (int)pos
);
75 adata_fg
= de_malloc(c
, sizeof(struct atari_img_decode_data
));
76 adata_mask
= de_malloc(c
, sizeof(struct atari_img_decode_data
));
78 adata_fg
->bpp
= (i64
)sprite_res_bpp
[res
];
79 adata_fg
->ncolors
= ((i64
)1)<<adata_fg
->bpp
;
81 adata_mask
->ncolors
= 2;
83 sprite_data_offs_raw
= de_getu32be(pos
);
85 //de_dbg(c, "sprite data offset: %d (->%d)", (int)sprite_data_offs_raw, (int)mask_offs);
86 width_raw
= (i64
)de_getbyte(pos
+4);
87 adata_fg
->w
= width_raw
*16;
88 adata_fg
->h
= (i64
)de_getbyte(pos
+5);
89 de_dbg_dimensions(c
, adata_fg
->w
, adata_fg
->h
);
90 if(!de_good_image_dimensions(c
, adata_fg
->w
, adata_fg
->h
)) goto done
;
92 adata_mask
->w
= adata_fg
->w
;
93 adata_mask
->h
= adata_fg
->h
;
94 mask_offs
= param_blk_pos
+ sprite_data_offs_raw
;
95 mask_size
= (width_raw
* 2 * 1) * adata_mask
->h
;
96 de_dbg(c
, "mask image at %d, len=%d", (int)mask_offs
, (int)mask_size
);
97 if(mask_offs
>=c
->infile
->len
) goto done
;
99 fg_offs
= mask_offs
+ mask_size
;
100 fg_size
= (width_raw
* 2 * adata_fg
->bpp
) * adata_fg
->h
;
101 de_dbg(c
, "foreground image at %d, len=%d", (int)fg_offs
, (int)fg_size
);
103 adata_mask
->unc_pixels
= dbuf_open_input_subfile(c
->infile
, mask_offs
, mask_size
);
104 adata_fg
->unc_pixels
= dbuf_open_input_subfile(c
->infile
, fg_offs
, fg_size
);
106 adata_mask
->pal
= mask_pal
;
107 adata_fg
->pal
= d
->pal
;
109 adata_mask
->img
= de_bitmap_create(c
, adata_fg
->w
, adata_fg
->h
, 1);
110 adata_fg
->img
= de_bitmap_create(c
, adata_fg
->w
, adata_fg
->h
, 4);
112 fmtutil_atari_decode_image(c
, adata_mask
);
113 fmtutil_atari_decode_image(c
, adata_fg
);
114 de_bitmap_apply_mask(adata_fg
->img
, adata_mask
->img
, 0);
115 fi
= de_finfo_create(c
);
116 fmtutil_atari_set_standard_density(c
, adata_fg
, fi
);
117 de_bitmap_write_to_file_finfo(adata_fg
->img
, fi
, 0);
121 dbuf_close(adata_fg
->unc_pixels
);
122 de_bitmap_destroy(adata_fg
->img
);
123 de_free(c
, adata_fg
);
126 dbuf_close(adata_mask
->unc_pixels
);
127 de_bitmap_destroy(adata_mask
->img
);
128 de_free(c
, adata_mask
);
130 de_finfo_destroy(c
, fi
);
131 de_dbg_indent(c
, -1);
134 // A block of sprites for a particular resolution
135 static void do_sprite_param_blocks(deark
*c
, lctx
*d
, i64 res
,
136 i64 nsprites
, i64 pos
)
139 de_dbg(c
, "%s-res sprite param blocks at %d", sprite_res_name
[res
],
143 for(k
=0; k
<nsprites
; k
++) {
144 do_sprite_param_block(c
, d
, res
, k
, pos
, pos
+ 8*k
);
146 de_dbg_indent(c
, -1);
149 static void read_sprite_palette(deark
*c
, lctx
*d
, i64 pos
)
153 if(pos
>=c
->infile
->len
) return;
155 n
= de_getu32be(pos
);
157 de_warn(c
, "Sprite palette not found (expected at %d)", (int)pos
);
158 d
->pal
[0] = DE_STOCKCOLOR_WHITE
;
161 de_dbg(c
, "sprite palette at %d", (int)pos
);
163 fmtutil_read_atari_palette(c
, c
->infile
, pos
+4, d
->pal
, 16, 16, 0);
164 de_dbg_indent(c
, -1);
167 static void do_sprite_bank(deark
*c
, lctx
*d
, i64 pos
)
170 i64 paramoffs_raw
[3]; // One for each resolution: low, med, hi
173 i64 nsprites_total
= 0;
176 for(res
=0; res
<3; res
++) {
177 paramoffs_raw
[res
] = de_getu32be(pos
+4+4*res
);
178 // paramoffs is relative to the first position after the ID.
179 paramoffs
[res
] = pos
+ 4 + paramoffs_raw
[res
];
180 nsprites
[res
] = de_getu16be(pos
+16+2*res
);
181 de_dbg(c
, "%s-res sprites: %d, param blk offset: %d ("DE_CHAR_RIGHTARROW
" %d)", sprite_res_name
[res
],
182 (int)nsprites
[res
], (int)paramoffs_raw
[res
], (int)paramoffs
[res
]);
183 nsprites_total
+= nsprites
[res
];
186 // TODO: What's the right way to calculate the position of the palette?
187 pal_pos
= pos
+ 22 + (nsprites_total
)*8;
188 read_sprite_palette(c
, d
, pal_pos
);
190 for(res
=0; res
<3; res
++) {
191 if(nsprites
[res
]<1) continue;
192 if(paramoffs
[res
]>(c
->infile
->len
-8)) continue;
193 do_sprite_param_blocks(c
, d
, res
, nsprites
[res
], paramoffs
[res
]);
197 static void do_icon(deark
*c
, lctx
*d
, i64 idx
, i64 pos
)
199 de_bitmap
*fgimg
= NULL
;
200 de_bitmap
*maskimg
= NULL
;
208 de_dbg(c
, "icon #%d, at %d", (int)idx
, (int)pos
);
211 format_flag
= de_getu16be(pos
+4);
212 de_dbg(c
, "format flag: 0x%04x", (unsigned int)format_flag
);
213 bgcol
= de_getu16be(pos
+6);
214 fgcol
= de_getu16be(pos
+8);
215 de_dbg(c
, "bgcol: 0x%04x, fgcol: 0x%04x", (unsigned int)bgcol
, (unsigned int)fgcol
);
217 // TODO: I don't know how to figure out what colors to use.
218 if(fgcol
==0 && bgcol
!=0) {
222 cvtflags
|= DE_CVTF_WHITEISZERO
;
228 fgimg
= de_bitmap_create(c
, w
, h
, 2);
229 maskimg
= de_bitmap_create(c
, w
, h
, 1);
231 bitsstart
= pos
+ 10;
233 de_convert_image_bilevel(c
->infile
, bitsstart
, rowspan
, maskimg
, 0);
234 de_convert_image_bilevel(c
->infile
, bitsstart
+2, rowspan
, fgimg
, cvtflags
);
235 de_bitmap_apply_mask(fgimg
, maskimg
, 0);
237 de_bitmap_write_to_file(fgimg
, NULL
, DE_CREATEFLAG_OPT_IMAGE
);
238 de_bitmap_destroy(fgimg
);
239 de_bitmap_destroy(maskimg
);
240 de_dbg_indent(c
, -1);
243 struct pictbank_params
{
256 static void do_icon_bank(deark
*c
, lctx
*d
, i64 pos
)
261 num_icons
= de_getu16be(pos
+4);
262 de_dbg(c
, "number of icons: %d", (int)num_icons
);
263 for(k
=0; k
<num_icons
; k
++) {
264 do_icon(c
, d
, k
, pos
+6+84*k
);
268 static void render_stos_pp3(deark
*c
, struct pictbank_params
*pb
, i64 width_in_words
)
273 planesize
= pb
->width_in_bytes
* pb
->pseudoheight
;
275 for(lump
=0; lump
<pb
->height_in_lumps
; lump
++) {
277 i64 lump_start_srcpos_in_plane
;
280 lump_start_srcpos_in_plane
= pb
->width_in_bytes
* pb
->lines_per_lump
* lump
;
281 lump_start_ypos
= pb
->lines_per_lump
* lump
* 2;
283 // col_idx=0 = the first 32 pixels of the even numbered rows
284 // col_idx=width_in_words = the first 32 pixels of the odd numbered rows
285 // (TODO: What happens if width_in_words is odd?)
286 for(col_idx
=0; col_idx
<pb
->width_in_bytes
; col_idx
++) {
287 i64 col_start_srcpos_in_plane
;
292 continue; // We process 2 columns at a time
295 if(col_idx
>= width_in_words
) {
302 col_start_srcpos_in_plane
= lump_start_srcpos_in_plane
+ col_idx
*pb
->lines_per_lump
;
304 for(ypos_in_lump
=0; ypos_in_lump
<pb
->lines_per_lump
; ypos_in_lump
++) {
309 ypos
= lump_start_ypos
+ ypos_in_lump
*2 + rowparity
;
312 xpos
= (col_idx
% width_in_words
)*16;
318 // n=0: the first 8 pixels of every 32 plane 0 lump+0
319 // n=1: the second 8 pixels of every 32 plane 0 lump+1
320 // n=2: the third 8 pixels of every 32 plane 1 lump+0
321 // n=3: the fourth 8 pixels of every 32 plane 1 lump+1
325 v
= dbuf_getbyte(pb
->unc_pixels
, planesize
*(n
>>1) +
326 col_start_srcpos_in_plane
+ pb
->lines_per_lump
*(n
&1) + ypos_in_lump
);
331 palent
= (v
>>(7-i
)) & 1;
332 de_bitmap_setpixel_rgb(pb
->img
, xpos
, ypos
, pb
->pal
[palent
]);
341 static void render_stos_pp1(deark
*c
, struct pictbank_params
*pb
)
346 UI bits_per_pixel
= 4;
349 planesize
= pb
->width_in_bytes
* pb
->pseudoheight
;
351 for(lump
=0; lump
<pb
->height_in_lumps
; lump
++) {
353 i64 lump_start_srcpos_in_plane
;
355 i64 num_skipped_cols
= 0;
357 lump_start_srcpos_in_plane
= pb
->width_in_bytes
* pb
->lines_per_lump
* lump
;
358 lump_start_ypos
= pb
->lines_per_lump
* lump
;
360 for(col_idx
=0; col_idx
<pb
->width_in_bytes
; col_idx
++) {
361 i64 col_start_srcpos_in_plane
;
364 // Skip the last 2 of every group of 4 columns. They contain bits
365 // associated with the first 2 columns.
371 col_start_srcpos_in_plane
= lump_start_srcpos_in_plane
+
372 pb
->lines_per_lump
*col_idx
;
374 for(ypos_in_lump
=0; ypos_in_lump
<pb
->lines_per_lump
; ypos_in_lump
++) {
379 ypos
= lump_start_ypos
+ ypos_in_lump
;
381 for(pn
=0; pn
<num_planes
; pn
++) {
382 xbuf
[pn
] = dbuf_getbyte(pb
->unc_pixels
, planesize
*pn
+
383 col_start_srcpos_in_plane
+ ypos_in_lump
);
384 xbuf
[pn
+2] = dbuf_getbyte(pb
->unc_pixels
, planesize
*pn
+
385 col_start_srcpos_in_plane
+ 2*pb
->lines_per_lump
+ ypos_in_lump
);
392 for(pn
=0; pn
<bits_per_pixel
; pn
++) {
393 if(xbuf
[pn
] & (1<<(7-i
))) {
398 xpos
= (col_idx
-num_skipped_cols
)*8 + i
;
399 de_bitmap_setpixel_rgb(pb
->img
, xpos
, ypos
, pb
->pal
[palent
]);
406 static void render_stos_med4plane(deark
*c
, struct pictbank_params
*pb
)
411 UI bits_per_pixel
= 2;
414 //width_in_bytes = pb->width_in_words*2;
415 planesize
= pb
->width_in_bytes
* pb
->pseudoheight
;
417 for(lump
=0; lump
<pb
->height_in_lumps
; lump
++) {
419 i64 lump_start_srcpos_in_plane
;
422 lump_start_srcpos_in_plane
= pb
->width_in_bytes
* pb
->lines_per_lump
* lump
;
423 lump_start_ypos
= pb
->lines_per_lump
* lump
;
425 for(col_idx
=0; col_idx
<pb
->width_in_bytes
; col_idx
++) {
426 i64 col_start_srcpos_in_plane
;
429 // Each column that we process sets 16 pixels:
430 // 8 pixels are set, then 8 pixels skipped, then 8 pixels set.
432 col_start_srcpos_in_plane
= lump_start_srcpos_in_plane
+
433 pb
->lines_per_lump
*col_idx
;
435 for(ypos_in_lump
=0; ypos_in_lump
<pb
->lines_per_lump
; ypos_in_lump
++) {
440 ypos
= lump_start_ypos
+ ypos_in_lump
;
442 // xbuf[0..1] are for the first set of 8 pixels.
443 // xbuf[2..3] are for the second set.
444 for(pn
=0; pn
<num_planes
; pn
++) {
445 xbuf
[pn
] = dbuf_getbyte(pb
->unc_pixels
, planesize
*pn
+
446 col_start_srcpos_in_plane
+ ypos_in_lump
);
450 if(col_idx
%2) xpos1
-= 8;
457 for(pixset
=0; pixset
<2; pixset
++) {
459 for(pn
=0; pn
<bits_per_pixel
; pn
++) {
460 if(xbuf
[pixset
*2+pn
] & (1<<(7-i
))) {
464 xpos
= xpos1
+ pixset
*16 + i
;
465 de_bitmap_setpixel_rgb(pb
->img
, xpos
, ypos
, pb
->pal
[palent
]);
473 // TODO: Consolidate this with the similar function in abk.c.
474 static void render_stos_pictbank_std(deark
*c
, struct pictbank_params
*pb
)
480 if((size_t)pb
->num_planes
> sizeof(xbuf
)) goto done
;
481 if(pb
->bits_per_pixel
!= pb
->num_planes
) goto done
;
482 de_zeromem(xbuf
, sizeof(xbuf
));
483 planesize
= pb
->width_in_bytes
* pb
->pseudoheight
;
485 for(lump
=0; lump
<pb
->height_in_lumps
; lump
++) {
487 i64 lump_start_srcpos_in_plane
;
490 lump_start_srcpos_in_plane
= pb
->width_in_bytes
* pb
->lines_per_lump
* lump
;
491 lump_start_ypos
= pb
->lines_per_lump
* lump
;
493 for(col_idx
=0; col_idx
<pb
->width_in_bytes
; col_idx
++) {
494 i64 col_start_srcpos_in_plane
;
497 col_start_srcpos_in_plane
= lump_start_srcpos_in_plane
+
498 pb
->lines_per_lump
*col_idx
;
500 for(ypos_in_lump
=0; ypos_in_lump
<pb
->lines_per_lump
; ypos_in_lump
++) {
505 ypos
= lump_start_ypos
+ ypos_in_lump
;
507 for(pn
=0; pn
<pb
->num_planes
; pn
++) {
508 xbuf
[pn
] = dbuf_getbyte(pb
->unc_pixels
, planesize
*pn
+
509 col_start_srcpos_in_plane
+ ypos_in_lump
);
516 for(pn
=0; pn
<pb
->bits_per_pixel
; pn
++) {
517 if(xbuf
[pn
] & (1<<(7-i
))) {
522 xpos
= col_idx
*8 + i
;
523 de_bitmap_setpixel_rgb(pb
->img
, xpos
, ypos
, pb
->pal
[palent
]);
535 static void render_stos_pictbank1(deark
*c
, lctx
*d
, struct pkpic_ctx
*pp
,
536 dbuf
*unc_pixels
, de_bitmap
*img
, UI num_planes
)
538 struct pictbank_params
*pb
;
540 pb
= de_malloc(c
, sizeof(struct pictbank_params
));
541 pb
->num_planes
= num_planes
;
542 pb
->bits_per_pixel
= pb
->num_planes
;
543 pb
->width_in_bytes
= pp
->width_in_words
* 2;
544 pb
->height_in_lumps
= pp
->height_in_lumps
;
545 pb
->lines_per_lump
= pp
->lines_per_lump
;
546 pb
->pseudoheight
= pp
->pseudoheight
;
547 pb
->unc_pixels
= unc_pixels
;
551 if(pp
->imgtype
==PKPIC_IMGTYPE_PP1
) {
552 render_stos_pp1(c
, pb
);
554 else if(pp
->imgtype
==PKPIC_IMGTYPE_PP3
) {
555 render_stos_pp3(c
, pb
, pp
->width_in_words
);
557 else if(pp
->imgtype
==PKPIC_IMGTYPE_M4P
) {
558 render_stos_med4plane(c
, pb
);
561 render_stos_pictbank_std(c
, pb
);
567 static void do_pkscreen_bank(deark
*c
, lctx
*d
, i64 pos1
)
569 struct pkpic_ctx
*pp
= NULL
;
570 dbuf
*unc_pixels
= NULL
;
571 de_bitmap
*img
= NULL
;
572 struct atari_img_decode_data
*adata
= NULL
;
574 const char *tname
= NULL
;
578 int saved_indent_level
;
580 de_dbg_indent_save(c
, &saved_indent_level
);
581 pp
= de_malloc(c
, sizeof(struct pkpic_ctx
));
582 de_zeromem(d
->pal
, sizeof(d
->pal
));
585 pp
->res_code
= (UI
)de_getu16be_p(&pos
);
586 de_dbg(c
, "res: %u", pp
->res_code
);
588 switch(pp
->res_code
) {
590 if(d
->imgtype_of_res0
==PKPIC_IMGTYPE_UNKNOWN
) {
591 pp
->imgtype
= PKPIC_IMGTYPE_LOW
;
594 pp
->imgtype
= d
->imgtype_of_res0
;
598 if(d
->imgtype_of_res1
==PKPIC_IMGTYPE_UNKNOWN
) {
601 if(d
->is_container_fmt
) {
602 pp
->imgtype
= PKPIC_IMGTYPE_MED
;
606 // Unfortunately, a file with res=1 (that couldn't be identified by
607 // its extension) seems to be more likely to be the oddball PP1
608 // format than the nice standard STOS medium-resolution format.
609 pp
->imgtype
= PKPIC_IMGTYPE_PP1
;
612 de_warn(c
, "Ambiguous image. If it looks wrong, try \"-opt stos:res1=<%s>\".", tmps
);
615 pp
->imgtype
= d
->imgtype_of_res1
;
618 case 2: pp
->imgtype
= PKPIC_IMGTYPE_HIGH
; break;
619 default: pp
->imgtype
= PKPIC_IMGTYPE_UNKNOWN
; break;
622 switch(pp
->imgtype
) {
623 case PKPIC_IMGTYPE_LOW
:
626 tname
= "4-plane low res";
628 case PKPIC_IMGTYPE_M4P
:
631 tname
= "DAJ 4-plane med res";
633 case PKPIC_IMGTYPE_MED
:
636 tname
= "2-plane med res";
638 case PKPIC_IMGTYPE_HIGH
:
641 tname
= "1-plane high res";
643 case PKPIC_IMGTYPE_PP1
:
646 tname
= "PP1 2-plane low res";
648 case PKPIC_IMGTYPE_PP3
:
651 tname
= "PP3 2-plane high res";
654 de_err(c
, "Unsupported picture resolution: %u", pp
->res_code
);
658 de_dbg(c
, "interpreted image type: %s", tname
);
662 pp
->width_in_words
= de_getu16be_p(&pos
);
663 pp
->pseudowidth
= pp
->width_in_words
* 16;
664 if(pp
->imgtype
==PKPIC_IMGTYPE_PP1
) {
665 pp
->w
= pp
->width_in_words
* 8;
667 else if(pp
->imgtype
==PKPIC_IMGTYPE_M4P
) {
668 pp
->w
= pp
->width_in_words
* 32;
671 pp
->w
= pp
->pseudowidth
;
673 de_dbg(c
, "width in words: %"I64_FMT
, pp
->width_in_words
);
674 pp
->height_in_lumps
= de_getu16be_p(&pos
);
675 de_dbg(c
, "height in lumps: %"I64_FMT
, pp
->height_in_lumps
);
677 pp
->lines_per_lump
= de_getu16be_p(&pos
);
678 de_dbg(c
, "lines per lump: %"I64_FMT
, pp
->lines_per_lump
);
679 pp
->pseudoheight
= pp
->height_in_lumps
* pp
->lines_per_lump
;
680 if(pp
->imgtype
==PKPIC_IMGTYPE_PP3
) {
681 pp
->h
= pp
->pseudoheight
* 2;
684 pp
->h
= pp
->pseudoheight
;
686 de_dbg_dimensions(c
, pp
->w
, pp
->h
);
688 pp
->picdata_rel
= 70;
689 pp
->rledata_rel
= de_getu32be_p(&pos
);
690 pp
->pointdata_rel
= de_getu32be_p(&pos
);
691 pp
->picdata_abs
= pos1
+ pp
->picdata_rel
;
692 pp
->rledata_abs
= pos1
+ pp
->rledata_rel
;
693 pp
->pointdata_abs
= pos1
+ pp
->pointdata_rel
;
694 de_dbg(c
, "picdata: %"I64_FMT
, pp
->picdata_abs
);
695 de_dbg(c
, "rledata: %"I64_FMT
, pp
->rledata_abs
);
696 de_dbg(c
, "pointdata: %"I64_FMT
, pp
->pointdata_abs
);
699 de_dbg(c
, "palette at %"I64_FMT
, pos
);
701 fmtutil_read_atari_palette(c
, c
->infile
, pos
, d
->pal
, 16, 16, 0);
702 de_dbg_indent(c
, -1);
704 if(bits_per_pixel
==1) {
705 if((d
->pal
[0] & 0xffffff)==0) {
706 d
->pal
[0] = DE_STOCKCOLOR_BLACK
;
707 d
->pal
[1] = DE_STOCKCOLOR_WHITE
;
710 d
->pal
[0] = DE_STOCKCOLOR_WHITE
;
711 d
->pal
[1] = DE_STOCKCOLOR_BLACK
;
715 pp
->unc_image_size
= pp
->width_in_words
*2 * (i64
)num_planes
* pp
->h
;
717 unc_pixels
= dbuf_create_membuf(c
, 0, 0);
719 fmtutil_decompress_stos_pictbank(c
, c
->infile
, pp
->picdata_abs
, pp
->rledata_abs
,
720 pp
->pointdata_abs
, unc_pixels
, pp
->unc_image_size
);
722 img
= de_bitmap_create(c
, pp
->w
, pp
->h
, ((bits_per_pixel
==1)?1:3));
723 render_stos_pictbank1(c
, d
, pp
, unc_pixels
, img
, num_planes
);
725 fi
= de_finfo_create(c
);
726 adata
= de_malloc(c
, sizeof(struct atari_img_decode_data
));
727 adata
->bpp
= (i64
)bits_per_pixel
;
728 fmtutil_atari_set_standard_density(c
, adata
, fi
);
729 de_bitmap_write_to_file_finfo(img
, fi
, DE_CREATEFLAG_OPT_IMAGE
);
732 de_bitmap_destroy(img
);
733 dbuf_close(unc_pixels
);
738 de_finfo_destroy(c
, fi
);
739 de_dbg_indent_restore(c
, saved_indent_level
);
742 static void do_mbk_data_bank(deark
*c
, lctx
*d
, i64 pos
)
744 const char *bn
= "?";
746 de_dbg(c
, "STOS data bank at %d", (int)pos
);
748 d
->data_bank_id
= (u32
)de_getu32be(pos
);
750 switch(d
->data_bank_id
) {
751 case BANKID_PKSCREEN
: bn
= "packed screen"; break;
752 case 0x13490157U
: bn
= "music bank"; break;
753 case 0x28091960U
: bn
= "icon bank"; break;
754 case BANKID_SPRITE
: bn
= "sprite bank"; break;
755 case 0x4d414553U
: bn
= "Maestro!"; break;
758 de_dbg(c
, "data bank id: 0x%08x (%s)", (unsigned int)d
->data_bank_id
, bn
);
760 switch(d
->data_bank_id
) {
762 do_sprite_bank(c
, d
, pos
);
765 do_icon_bank(c
, d
, pos
);
767 case BANKID_PKSCREEN
:
768 do_pkscreen_bank(c
, d
, pos
);
771 de_dbg_indent(c
, -1);
774 static void do_mbk(deark
*c
, lctx
*d
)
777 const char *bt
= "?";
779 de_dbg(c
, "MBK header at %d", (int)pos
);
782 de_dbg(c
, "bank number: %d", (int)d
->banknum
);
784 d
->banksize
= de_getu32be(14);
785 d
->banktype
= (u8
)(d
->banksize
>>24);
786 d
->banksize
&= (i64
)0x00ffffff;
788 switch(d
->banktype
) {
789 case 0x01: bt
= "work"; break;
790 case 0x02: bt
= "screen"; break;
791 case 0x81: bt
= "data"; break;
792 case 0x82: bt
= "datascreen"; break;
793 case 0x84: bt
= "set"; break;
794 case 0x85: bt
= "packed files"; break;
797 de_dbg(c
, "bank type: 0x%02x (%s)", (unsigned int)d
->banktype
, bt
);
798 de_dbg(c
, "bank size: %d", (int)d
->banksize
);
800 de_dbg_indent(c
, -1);
804 if(d
->banktype
==0x81) {
805 do_mbk_data_bank(c
, d
, pos
);
809 static void do_mbs(deark
*c
, lctx
*d
)
812 de_dbg(c
, "MBS header at %d", (int)pos
);
815 static void run_mbk_mbs_internal(deark
*c
, de_module_params
*mparams
, UI mode
)
820 char opt_res0_c
= '\0';
821 char opt_res1_c
= '\0';
824 d
= de_malloc(c
, sizeof(lctx
));
826 d
->imgtype_of_res1
= PKPIC_IMGTYPE_UNKNOWN
;
827 d
->imgtype_of_res0
= PKPIC_IMGTYPE_UNKNOWN
;
829 if(mode
==1) { // .pp1 extension
830 d
->imgtype_of_res1
= PKPIC_IMGTYPE_PP1
;
833 d
->imgtype_of_res1
= PKPIC_IMGTYPE_MED
;
836 d
->imgtype_of_res1
= PKPIC_IMGTYPE_PP3
;
838 else if(mode
==4) { // .daj extension
839 d
->imgtype_of_res0
= PKPIC_IMGTYPE_M4P
;
840 d
->imgtype_of_res1
= PKPIC_IMGTYPE_MED
;
843 s
= de_get_ext_option(c
, "stos:res0");
844 if(s
) opt_res0_c
= s
[0];
845 s
= de_get_ext_option(c
, "stos:res1");
846 if(s
) opt_res1_c
= s
[0];
848 if(opt_res1_c
=='l') {
849 d
->imgtype_of_res1
= PKPIC_IMGTYPE_PP1
;
851 else if(opt_res1_c
=='m') {
852 d
->imgtype_of_res1
= PKPIC_IMGTYPE_MED
;
854 else if(opt_res1_c
=='h') {
855 d
->imgtype_of_res1
= PKPIC_IMGTYPE_PP3
;
858 if(opt_res0_c
=='l') {
859 d
->imgtype_of_res0
= PKPIC_IMGTYPE_LOW
;
861 else if(opt_res0_c
=='m') {
862 d
->imgtype_of_res0
= PKPIC_IMGTYPE_M4P
;
865 de_read(buf
, 0, sizeof(buf
));
866 if(!de_memcmp(buf
, g_lion_sig
, 10)) {
867 d
->is_container_fmt
= 1;
868 d
->banknum
= de_getu32be(10);
870 de_declare_fmt(c
, "STOS MBS");
874 de_declare_fmt(c
, "STOS MBK");
879 id
= (u32
)de_getu32be_direct(buf
);
881 if(id
==BANKID_SPRITE
) {
882 de_declare_fmt(c
, "STOS Sprite Bank");
883 do_sprite_bank(c
, d
, 0);
885 else if(id
==BANKID_PKSCREEN
) {
886 de_declare_fmt(c
, "STOS Packed Screen / Picture Packer");
887 do_pkscreen_bank(c
, d
, 0);
890 de_err(c
, "Not a (supported) STOS/MBK format");
897 static void de_run_mbk_mbs(deark
*c
, de_module_params
*mparams
)
899 run_mbk_mbs_internal(c
, mparams
, 0);
902 // Detects raw packed screen, and MBK containing packed screen.
903 // Returns the resolution in *res.
904 static int is_stos_packedscreen(deark
*c
, UI
*res
)
912 de_read(buf
, 0, sizeof(buf
));
914 if(!de_memcmp(buf
, g_lion_sig
, 10)) is_mbk
= 1;
916 if((UI
)de_getu32be_direct(&buf
[10]) == 0) return 0; // screen out MBS
917 if(buf
[14] != 0x81) return 0; // must be type 'data'
921 id
= (UI
)de_getu32be_direct(&buf
[bpos
]);
922 if(id
!=BANKID_PKSCREEN
) return 0;
923 *res
= (UI
)de_getu16be_direct(&buf
[bpos
+4]);
927 // Note: Returned values must be kept consistent with other stos modules.
928 static int de_identify_mbk(deark
*c
)
933 de_read(buf
, 0, sizeof(buf
));
934 if(!de_memcmp(buf
, g_lion_sig
, 10))
936 id
= (UI
)de_getu32be_direct(buf
);
937 if(id
==BANKID_SPRITE
) {
940 else if(id
==BANKID_PKSCREEN
) {
946 static void de_help_mbk(deark
*c
)
948 fmtutil_atari_help_palbits(c
);
949 de_msg(c
, "-opt stos:res0=<l|m> : Assume res 0 pics are low/med res");
950 de_msg(c
, "-opt stos:res1=<l|m|h> : Assume res 1 pics are low/med/high res");
953 void de_module_mbk(deark
*c
, struct deark_module_info
*mi
)
956 mi
->desc
= "STOS Memory Bank (.MBK)";
957 mi
->run_fn
= de_run_mbk_mbs
;
958 mi
->identify_fn
= de_identify_mbk
;
959 mi
->help_fn
= de_help_mbk
;
960 mi
->id_alias
[0] = "mbk";
963 // Note: Returned values must be kept consistent with other stos modules.
964 static int de_identify_stos_pp1(deark
*c
)
970 has_ext
= de_input_file_has_ext(c
, "pp1");
971 if(!has_ext
) return 0;
972 is_pkscr
= is_stos_packedscreen(c
, &res
);
973 if(is_pkscr
&& res
==1) return 100;
977 static void de_run_stos_pp1(deark
*c
, de_module_params
*mparams
)
979 run_mbk_mbs_internal(c
, mparams
, 1);
982 void de_module_stos_pp1(deark
*c
, struct deark_module_info
*mi
)
985 mi
->desc
= "Picture Packer low res";
986 mi
->run_fn
= de_run_stos_pp1
;
987 mi
->identify_fn
= de_identify_stos_pp1
;
988 mi
->help_fn
= de_help_mbk
;
991 static void de_run_stos_pp2(deark
*c
, de_module_params
*mparams
)
993 run_mbk_mbs_internal(c
, mparams
, 2);
996 // Note: Returned values must be kept consistent with other stos modules.
997 static int de_identify_stos_pp2(deark
*c
)
1003 has_ext
= de_input_file_has_ext(c
, "pp2");
1004 if(!has_ext
) return 0;
1005 is_pkscr
= is_stos_packedscreen(c
, &res
);
1006 if(is_pkscr
&& res
==1) return 100;
1010 void de_module_stos_pp2(deark
*c
, struct deark_module_info
*mi
)
1012 mi
->id
= "stos_pp2";
1013 mi
->desc
= "Picture Packer med res";
1014 mi
->run_fn
= de_run_stos_pp2
;
1015 mi
->identify_fn
= de_identify_stos_pp2
;
1016 mi
->help_fn
= de_help_mbk
;
1019 static void de_run_stos_pp3(deark
*c
, de_module_params
*mparams
)
1021 run_mbk_mbs_internal(c
, mparams
, 3);
1024 // Note: Returned values must be kept consistent with other stos modules.
1025 static int de_identify_stos_pp3(deark
*c
)
1031 has_ext
= de_input_file_has_ext(c
, "pp3");
1032 if(!has_ext
) return 0;
1033 is_pkscr
= is_stos_packedscreen(c
, &res
);
1034 if(is_pkscr
&& res
==1) return 100;
1038 void de_module_stos_pp3(deark
*c
, struct deark_module_info
*mi
)
1040 mi
->id
= "stos_pp3";
1041 mi
->desc
= "Picture Packer high res";
1042 mi
->run_fn
= de_run_stos_pp3
;
1043 mi
->identify_fn
= de_identify_stos_pp3
;
1044 mi
->help_fn
= de_help_mbk
;
1047 static void de_run_stos_daj(deark
*c
, de_module_params
*mparams
)
1049 run_mbk_mbs_internal(c
, mparams
, 4);
1052 // Note: Returned values must be kept consistent with other stos modules.
1053 static int de_identify_stos_daj(deark
*c
)
1059 has_ext
= de_input_file_has_ext(c
, "daj");
1060 if(!has_ext
) return 0;
1061 is_pkscr
= is_stos_packedscreen(c
, &res
);
1062 if(is_pkscr
&& (res
==0 || res
==1)) return 100;
1066 // .DAJ, a 4-plane medium res format, seems to be used only by a presentation-like
1067 // viewer used by the ST+ (ST Plus) Atari diskmagazine.
1068 void de_module_stos_daj(deark
*c
, struct deark_module_info
*mi
)
1070 mi
->id
= "stos_daj";
1071 mi
->desc
= "Picture Packer DAJ";
1072 mi
->run_fn
= de_run_stos_daj
;
1073 mi
->identify_fn
= de_identify_stos_daj
;
1074 mi
->help_fn
= de_help_mbk
;