Loading of atari ST TNY files
This commit is contained in:
parent
be68b498ac
commit
5e78ad6282
@ -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
|
||||
|
||||
@ -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 *);
|
||||
|
||||
@ -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 ("")
|
||||
|
||||
@ -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"},
|
||||
|
||||
226
src/stformats.c
226
src/stformats.c
@ -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);
|
||||
}
|
||||
|
||||
/* @} */
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user