diff --git a/project/msvc/grafx2-win32.vcxproj b/project/msvc/grafx2-win32.vcxproj index fa2d05e5..697a798e 100644 --- a/project/msvc/grafx2-win32.vcxproj +++ b/project/msvc/grafx2-win32.vcxproj @@ -82,6 +82,7 @@ + CPU_6502_STATIC;CPU_6502_USE_LOCAL_HEADER;CPU_6502_DEPENDENCIES_H="6502types.h";%(PreprocessorDefinitions) CPU_6502_STATIC;CPU_6502_USE_LOCAL_HEADER;CPU_6502_DEPENDENCIES_H="6502types.h";%(PreprocessorDefinitions) diff --git a/project/msvc/grafx2-win32.vcxproj.filters b/project/msvc/grafx2-win32.vcxproj.filters index 5c2886ae..1c1da724 100644 --- a/project/msvc/grafx2-win32.vcxproj.filters +++ b/project/msvc/grafx2-win32.vcxproj.filters @@ -234,6 +234,9 @@ Fichiers sources + + Fichiers sources + diff --git a/src/2gsformats.c b/src/2gsformats.c new file mode 100644 index 00000000..6c195ea8 --- /dev/null +++ b/src/2gsformats.c @@ -0,0 +1,302 @@ +/* vim:expandtab:ts=2 sw=2: +*/ +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright owned by various GrafX2 authors, see COPYRIGHT.txt for details. + + Grafx2 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; version 2 + of the License. + + Grafx2 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 Grafx2; if not, see +*/ + +///@file 2gsformats.c +/// Formats for the Apple II GS + +#include +#include +#include +#include "global.h" +#include "fileformats.h" +#include "loadsavefuncs.h" +#include "io.h" +#include "gfx2mem.h" +#include "gfx2log.h" + +/** + * Test for an Apple 2 GS picture file + */ +void Test_2GS(T_IO_Context * context, FILE * file) +{ + unsigned long file_size; + dword chunksize; + byte header[5]; + + (void)context; + File_error = 1; + file_size = File_length_file(file); + if (!Read_dword_le(file, &chunksize)) + return; + if (!Read_bytes(file, header, sizeof(header))) + return; + if (0 != memcmp(header, "\x04MAIN", 5)) + return; + if (file_size < chunksize) + return; + File_error = 0; +} + +/** + * Load a 16 entry Apple II GS palette from file + */ +static int Load_2GS_Palette(T_Components * palette, FILE * file) +{ + unsigned int i; + for (i = 0; i < 16; i++) + { + word palentry; + if (!Read_word_le(file, &palentry)) + return 0; + palette[i].R = ((palentry >> 8) & 0x0f) * 0x11; + palette[i].G = ((palentry >> 4) & 0x0f) * 0x11; + palette[i].B = (palentry & 0x0f) * 0x11; + } + return 1; +} + +#define COMPONENTS(x) linepal[x].R, linepal[x].G, linepal[x].B + +/** + * set the (2 or 4) pixels for the byte. + */ +#define WRITE2GS_PIXELS \ +if (multipalcount > 0) \ +{ \ + if (linemode & 0x80) \ + { \ + Set_pixel_24b(context, x++, y, COMPONENTS(8 + (pixel >> 6))); \ + Set_pixel_24b(context, x++, y, COMPONENTS(12 + ((pixel >> 4) & 3))); \ + Set_pixel_24b(context, x++, y, COMPONENTS((pixel >> 2) & 3)); \ + Set_pixel_24b(context, x++, y, COMPONENTS(4 + (pixel & 3))); \ + } \ + else \ + { \ + Set_pixel_24b(context, x++, y, COMPONENTS(pixel >> 4)); \ + Set_pixel_24b(context, x++, y, COMPONENTS(pixel & 15)); \ + } \ +} \ +else \ +{ \ + if (linemode & 0x80) \ + { \ + Set_pixel(context, x++, y, (linemode << 4) | 8 | (pixel >> 6)); \ + Set_pixel(context, x++, y, (linemode << 4) | 12 | ((pixel >> 4) & 3)); \ + Set_pixel(context, x++, y, (linemode << 4) | ((pixel >> 2) & 3)); \ + Set_pixel(context, x++, y, (linemode << 4) | 4 | (pixel & 3)); \ + } \ + else \ + { \ + Set_pixel(context, x++, y, (linemode << 4) | (pixel >> 4)); \ + Set_pixel(context, x++, y, (linemode << 4) | (pixel & 15)); \ + } \ +} + +void Load_2GS(T_IO_Context * context) +{ + FILE * file; + unsigned long file_size; + dword chunksize; + byte header[5]; + word mode; + word width; + word height; + word palcount; + word palindex; + long lineoffset; + long dataoffset; + word y; + byte bpp = 2; + word multipalcount = 0; + long multipaloffset = -1; + long offset; + + File_error = 1; + file = Open_file_read(context); + if (file == NULL) + return; + file_size = File_length_file(file); + if (!Read_dword_le(file, &chunksize)) + return; + if (!Read_bytes(file, header, sizeof(header))) + goto error; + if (0 != memcmp(header, "\x04MAIN", 5)) + goto error; + if (!Read_word_le(file, &mode) || !Read_word_le(file, &width) || !Read_word_le(file, &palcount)) + goto error; + + if (Config.Clear_palette) + memset(context->Palette, 0, sizeof(T_Palette)); + for (palindex = 0; palindex < palcount; palindex++) + { + if (!Load_2GS_Palette(context->Palette + (palindex * 16), file)) + goto error; + } + if (!Read_word_le(file, &height)) + goto error; + lineoffset = ftell(file); + dataoffset = lineoffset + 4 * (long)height; + GFX2_Log(GFX2_DEBUG, " mode %02x %ux%u %u palettes\n", mode, (unsigned)width, (unsigned)height, (unsigned)palcount); + + // read other chunks before decoding the picture + GFX2_Log(GFX2_DEBUG, "file_size : %06lx, chunksize : %06lx, current offset : %06lx\n", file_size, chunksize, dataoffset); + offset = chunksize; + while (offset < (long)file_size) + { + char * p; + byte c; + fseek(file, offset, SEEK_SET); + if (!Read_dword_le(file, &chunksize) || !Read_byte(file, &c)) + goto error; + p = GFX2_malloc(c + 1); + if (p) + { + fread(p, 1, c, file); + p[c] = '\0'; + GFX2_Log(GFX2_DEBUG, "%06lx: %04x %s\n", offset, chunksize, p); + if (c == 4 && 0 == memcmp(p, "NOTE", 4)) + { + word len; + if (Read_word_le(file, &len)) + { + free(p); + p = GFX2_malloc(len + 1); + if (p) + { + fread(p, 1, len, file); + p[len] = '\0'; + GFX2_Log(GFX2_DEBUG, "%s\n", p); + } + } + } + else if (c == 12 && 0 == memcmp(p, "SuperConvert", 12)) + { + dword len = chunksize - 4 - 13; + free(p); + p = GFX2_malloc(len); + if (p) + { + fread(p, 1, len, file); + GFX2_LogHexDump(GFX2_DEBUG, "", p, 0 /*offset + 4 + 13*/, (long)len); + } + } + else if (c == 8 && 0 == memcmp(p, "MULTIPAL", 8)) + { + if (Read_word_le(file, &multipalcount)) + { + // all palettes are there... + multipaloffset = ftell(file); + } + } + free(p); + } + offset += chunksize; + } + + if (multipalcount > 0) + { + bpp = 12; + } + else + { + while ((1 << bpp) < ((mode & 0x80) ? 4 : 16) * palcount) + bpp++; + } + File_error = 0; + Pre_load(context, width, height, file_size, FORMAT_2GS, (mode & 0x80) ? PIXEL_TALL : PIXEL_SIMPLE, bpp); + if (File_error) + goto error; + for (y = 0; y < height; y++) + { + word linebytes; + byte linemode; + word x; + T_Components linepal[16]; + if (multipalcount > y) + { + fseek(file, multipaloffset + 32 * y, SEEK_SET); + if (!Load_2GS_Palette(linepal, file)) + goto error; + } + fseek(file, lineoffset, SEEK_SET); + if (!Read_word_le(file, &linebytes) || !Read_byte(file, &linemode)) + goto error; + //GFX2_Log(GFX2_DEBUG, "Line #%03u mode/pal=%02x %u bytes\n", (unsigned)y, linemode, (unsigned)linebytes); + lineoffset += 4; + fseek(file, dataoffset, SEEK_SET); + if (multipalcount > 0) + { + linemode = 0; + } + for (x = 0; x < width; ) + { + byte code, pixel; + unsigned count; + if (!Read_byte(file, &code)) + goto error; + count = (code & 0x3f) + 1; + switch (code >> 6) + { + case 0: // unpacked + while (count-- > 0) + { + if (!Read_byte(file, &pixel)) + goto error; + WRITE2GS_PIXELS + } + break; + case 3: // byte packed x 4 + count <<= 2; + case 1: // byte packed + if (!Read_byte(file, &pixel)) + goto error; + while (count-- > 0) + { + WRITE2GS_PIXELS + } + break; + case 2: // dword packed + { + byte pixels[4]; + if (!Read_bytes(file, pixels, 4)) + goto error; + while (count-- > 0) + { + int i; + for (i = 0; i < 4; i++) + { + pixel = pixels[i]; + WRITE2GS_PIXELS + } + } + } + break; + } + } + dataoffset += linebytes; + } + + fclose(file); + return; + +error: + File_error = 1; + fclose(file); +} \ No newline at end of file diff --git a/src/Makefile b/src/Makefile index e3299f2b..c108d275 100644 --- a/src/Makefile +++ b/src/Makefile @@ -819,6 +819,7 @@ OBJS = main.o init.o graph.o $(APIOBJ) misc.o osdep.o special.o \ loadsave.o loadsavefuncs.o \ pngformat.o motoformats.o stformats.o c64formats.o cpcformats.o \ ifformat.o msxformats.o packbits.o giformat.o \ + 2gsformats.o \ fileformats.o miscfileformats.o libraw2crtc.o \ brush_ops.o buttons_effects.o layers.o \ oldies.o tiles.o colorred.o unicode.o gfx2surface.o \ diff --git a/src/const.h b/src/const.h index b865b1a4..3afc0b81 100644 --- a/src/const.h +++ b/src/const.h @@ -136,6 +136,7 @@ enum FILE_FORMATS FORMAT_FLI, ///< Autodesk Animator FLI/FLC FORMAT_MOTO, ///< Thomson MO/TO computers pictures FORMAT_HGR, ///< Apple II HGR and DHGR + FORMAT_2GS, ///< Apple II GS format FORMAT_TIFF, ///< Tagged Image File Format FORMAT_GRB, ///< HP-48 Grob FORMAT_MSX, ///< MSX formats diff --git a/src/fileformats.h b/src/fileformats.h index 7ca44330..c6ff08a6 100644 --- a/src/fileformats.h +++ b/src/fileformats.h @@ -207,5 +207,10 @@ void Test_MSX(T_IO_Context *, FILE *); void Load_MSX(T_IO_Context *); void Save_MSX(T_IO_Context *); +// -- Apple II GS ----------------------------------------------------------- +void Test_2GS(T_IO_Context *, FILE *); +void Load_2GS(T_IO_Context *); +void Save_2GS(T_IO_Context *); + /// @} #endif diff --git a/src/loadsave.c b/src/loadsave.c index ae0000b0..5aee3b65 100644 --- a/src/loadsave.c +++ b/src/loadsave.c @@ -114,6 +114,7 @@ const T_Format File_formats[] = { "gpx;" "cpc;scr;win;pph;cm5;go1;sgx;" "hgr;dhgr;" + "shr;gs;iigs;32k;" "grb;grob;" "sc2;" "tga;pnm;xpm;xcf;jpg;jpeg;tif;tiff;ico;ic2;cur;info;flc;bin;map"}, @@ -156,6 +157,7 @@ const T_Format File_formats[] = { {FORMAT_MOTO," moto",Test_MOTO,Load_MOTO,Save_MOTO,0, 1, 0, "bin", "bin;map"}, {FORMAT_MSX, " msx", Test_MSX, Load_MSX, Save_MSX, 0, 0, 0, "sc2", "sc2"}, {FORMAT_HGR, " hgr", Test_HGR, Load_HGR, Save_HGR, 0, 0, 1, "hgr", "hgr;dhgr;bin"}, + {FORMAT_2GS, " 2gs", Test_2GS, Load_2GS, NULL, 0, 0, 0, "shr", "shr;gs;iigs;32k"}, #ifndef __no_tifflib__ {FORMAT_TIFF," tiff",Test_TIFF,Load_TIFF,Save_TIFF,0, 1, 1, "tif", "tif;tiff"}, #endif