Loading of atari ST TNY files

This commit is contained in:
Thomas Bernard 2019-12-07 19:24:08 +01:00
parent be68b498ac
commit 5e78ad6282
No known key found for this signature in database
GPG Key ID: 0FF11B67A5C0863C
5 changed files with 235 additions and 1 deletions

View File

@ -140,6 +140,7 @@ enum FILE_FORMATS
FORMAT_PC1, ///< Atari ST Degas Elite
FORMAT_CEL, ///< Atari ST Cyber Paint Cell
FORMAT_NEO, ///< Atari ST NeoChrome
FORMAT_TNY, ///< Atari ST Tiny Stuff
FORMAT_C64, ///< Several C64 formats : Koala, FLI, BML, etc.
FORMAT_PRG, ///< C64 autoload picture
FORMAT_GPX, ///< pixcen C64 format : .gpx

View File

@ -101,6 +101,11 @@ void Test_PC1(T_IO_Context *, FILE *);
void Load_PC1(T_IO_Context *);
void Save_PC1(T_IO_Context *);
// -- Tiny Stuff ------------------------------------------------------------
void Test_TNY(T_IO_Context *, FILE *);
void Load_TNY(T_IO_Context *);
void Save_TNY(T_IO_Context *);
// -- NEO -------------------------------------------------------------------
void Test_NEO(T_IO_Context *, FILE *);
void Load_NEO(T_IO_Context *);

View File

@ -543,6 +543,7 @@ static const T_Help_table helptable_credits[] =
HELP_TEXT (" SCx : Colorix (?)")
HELP_TEXT (" SCR : Advanced OCP Art Studio + iMPdraw")
HELP_TEXT (" TIFF : Aldus (now Adobe)")
HELP_TEXT (" TNY : David Mumper")
HELP_TEXT (" XPM : C.Nahaboo and D.Dardailler / Bull")
HELP_TEXT ("")
HELP_TEXT ("")

View File

@ -115,7 +115,7 @@ static void Save_ClipBoard_Image(T_IO_Context *);
const T_Format File_formats[] = {
{FORMAT_ALL_IMAGES, "(all)", NULL, NULL, NULL, 0, 0, 0, "",
"gif;png;bmp;2bp;pcx;pkm;iff;lbm;ilbm;sham;ham;ham6;ham8;acbm;pic;anim;img;sci;scq;scf;scn;sco;cel;"
"pi1;pc1;pi2;pc2;pi3;pc3;neo;"
"pi1;pc1;pi2;pc2;pi3;pc3;neo;tny;tn1;tn2;tn3;tn4;"
"c64;p64;a64;pi;rp;aas;art;dd;iph;ipt;hpc;ocp;koa;koala;fli;bml;cdu;prg;pmg;rpm;"
"gpx;"
"cpc;scr;win;pph,cm5;go1;"
@ -138,6 +138,7 @@ const T_Format File_formats[] = {
{FORMAT_SCx, " sc?", Test_SCx, Load_SCx, Save_SCx, 0, 0, 0, "sc?", "sci;scq;scf;scn;sco"},
{FORMAT_PI1, " pi1", Test_PI1, Load_PI1, Save_PI1, 0, 0, 0, "pi1", "pi1;pi2;pi3"},
{FORMAT_PC1, " pc1", Test_PC1, Load_PC1, Save_PC1, 0, 0, 0, "pc1", "pc1;pc2;pc3"},
{FORMAT_TNY, " tny", Test_TNY, Load_TNY, NULL, 0, 0, 0, "tny", "tny;tn1;tn2;tn3;tn4"},
{FORMAT_CEL, " cel", Test_CEL, Load_CEL, Save_CEL, 0, 0, 0, "cel", "cel"},
{FORMAT_NEO, " neo", Test_NEO, Load_NEO, Save_NEO, 0, 0, 0, "neo", "neo"},
{FORMAT_KCF, " kcf", Test_KCF, Load_KCF, Save_KCF, 1, 0, 0, "kcf", "kcf"},

View File

@ -50,6 +50,7 @@
* - PI1 : Degas
* - PC1 : Degas elite compressed
* - NEO : Neochrome
* - TNY : Tiny Stuff / Tiny View
*
* @{
*/
@ -1164,4 +1165,229 @@ error:
Remove_file(context);
}
void Test_TNY(T_IO_Context * context, FILE * file)
{
unsigned long file_size;
unsigned long theorical_size;
byte res; // 0 = Low, 1 = midres, 2 = hires. +3 for color cycling
word control_bytes;
word data_words;
(void)context;
File_error = 1;
file_size = File_length_file(file);
if (file_size > 32044)
return;
if (!Read_byte(file, &res))
return;
if (res >= 6)
return;
if (res >= 3)
{
if (fseek(file, 4, SEEK_CUR) < 0) // skip color cycling info
return;
theorical_size = 41;
}
else
theorical_size = 37;
if (fseek(file, 16*2, SEEK_CUR) < 0) // skip palette
return;
if (!Read_word_be(file, &control_bytes) || !Read_word_be(file, &data_words))
return;
theorical_size += control_bytes + data_words * 2;
if (theorical_size <= file_size && file_size < theorical_size + 512)
{
GFX2_Log(GFX2_DEBUG, "TNY res=%d %hu control bytes, %hu data words\n",
(int)res, control_bytes, data_words);
File_error = 0;
}
}
void Load_TNY(T_IO_Context * context)
{
FILE * file;
byte res; // 0 = Low, 1 = midres, 2 = hires. +3 for color cycling
word control_bytes;
byte * control;
word data_words;
byte * data;
byte buffer[32000 + 2];
File_error = 1;
file = Open_file_read(context);
if (file == NULL)
return;
if (Read_byte(file, &res) && (res < 6))
{
enum PIXEL_RATIO ratio = PIXEL_SIMPLE;
word width = 640, height = 200;
byte bpp;
byte cycling_range = 0;
byte cycling_speed = 0;
word duration = 0;
switch (res)
{
case 0:
case 3:
width = 320;
bpp = 4;
break;
case 1:
case 4:
bpp = 2;
ratio = PIXEL_TALL;
break;
case 2:
case 5:
bpp = 1;
height = 400;
break;
}
if (res >= 3)
{
if( !Read_byte(file, &cycling_range)
|| !Read_byte(file, &cycling_speed)
|| !Read_word_be(file, &duration))
{
fclose(file);
return;
}
GFX2_Log(GFX2_DEBUG, "TNY Color Cycling : %02x speed=%02x duration=%d\n",
cycling_range, cycling_speed, duration);
}
// Read palette
if ( !Read_bytes(file, buffer, 32)
|| !Read_word_be(file, &control_bytes)
|| !Read_word_be(file, &data_words))
{
fclose(file);
return;
}
control = GFX2_malloc(control_bytes);
data = GFX2_malloc(data_words * 2);
if (control == NULL || data == NULL)
{
fclose(file);
return;
}
if ( Read_bytes(file, control, control_bytes)
&& Read_bytes(file, data, data_words * 2))
{
byte cb;
word cc, count;
int src, dst;
int line;
File_error = 0;
Pre_load(context, width, height, File_length_file(file), FORMAT_TNY, ratio, bpp);
// Set palette
if (Config.Clear_palette)
memset(context->Palette, 0, sizeof(T_Palette));
PI1_decode_palette(buffer, context->Palette);
if (res >= 3)
{
context->Cycle_range[context->Color_cycles].Start = (cycling_range & 0xf0) >> 4;
context->Cycle_range[context->Color_cycles].End = (cycling_range & 0x0f);
if (cycling_speed & 0x80)
{
context->Cycle_range[context->Color_cycles].Inverse = 1;
cycling_speed = 256 - cycling_speed;
}
else
context->Cycle_range[context->Color_cycles].Inverse = 0;
context->Cycle_range[context->Color_cycles].Speed = 175 / cycling_speed;
context->Color_cycles++;
}
for (cc = 0, src = 0, dst = 0; cc < control_bytes && dst < 32000; )
{
cb = control[cc++];
if (cb & 0x80)
{
// copy
do {
buffer[dst++] = data[src++];
buffer[dst++] = data[src++];
} while(++cb != 0);
}
else switch(cb)
{
case 0: // repeat (word count)
count = control[cc++] << 8;
count += control[cc++];
while (count-- > 0)
{
buffer[dst++] = data[src];
buffer[dst++] = data[src+1];
}
src += 2;
break;
case 1: // copy (word count)
count = control[cc++] << 8;
count += control[cc++];
memcpy(buffer+dst, data+src, count * 2);
dst += count * 2;
src += count * 2;
break;
default: // repeat next data word
while(cb-- > 0)
{
buffer[dst++] = data[src];
buffer[dst++] = data[src+1];
}
src += 2;
}
}
GFX2_Log(GFX2_DEBUG, " %d %d ; %d %d ; %d\n", cc, control_bytes, src, data_words * 2, dst);
/**
* Tiny stuff packs the ST RAM in 4 planes of 8000 bytes
* Data is organized by column in each plane
* Warning : this is the same organization for all 3 ST Video modes
*/
for (line = 0; line < 200; line++)
{
int col;
for (col = 0; col < 20; col++)
{
byte planar[8];
byte pixels[16];
src = (line + col * 200) * 2;
for (dst = 0; dst < 8;)
{
planar[dst++] = buffer[src];
planar[dst++] = buffer[src+1];
src += 8000;
}
switch(res)
{
case 0:
case 3:
PI1_8b_to_16p(planar, pixels);
for (dst = 0 ; dst < 16; dst++)
Set_pixel(context, col * 16 + dst, line, pixels[dst]);
break;
case 1:
case 4:
PI2_8b_to_16p(planar, pixels);
for (dst = 0 ; dst < 16; dst++)
Set_pixel(context, col * 32 + dst, line, pixels[dst]);
PI2_8b_to_16p(planar + 4, pixels);
for (dst = 0 ; dst < 16; dst++)
Set_pixel(context, col * 32 + 16 + dst, line, pixels[dst]);
break;
case 2:
case 5:
for (dst = 0 ; dst < 64; dst++)
Set_pixel(context, (col % 10) * 64 + dst, line * 2 + (col / 10),
(planar[(dst >> 3)] >> (7 - (dst & 7))) & 1);
}
}
}
}
free(control);
free(data);
}
fclose(file);
}
/* @} */