u7shp.c

Go to the documentation of this file.
00001 /* 
00002  * SHP loading file filter for The GIMP version 1.2.x and 1.3.11+
00003  *
00004  * (C) 2000-2001 Tristan Tarrant
00005  * (C) 2001-2004 Willem Jan Palenstijn
00006  *
00007  * You can find the most recent version of this file in the Exult sources,
00008  * available from http://exult.sf.net/
00009  */
00010 
00011 #ifdef HAVE_CONFIG_H
00012 #include "config.h"
00013 #endif
00014 
00015 #include <stdio.h>
00016 #include <stdlib.h>
00017 #include <string.h>
00018 #include <ctype.h>
00019 
00020 #include <gtk/gtk.h>
00021 
00022 #include <libgimp/gimp.h>
00023 #include <libgimp/gimpui.h>
00024 
00025 #ifdef HAVE_GIMP_1_2
00026 #define GIMP20_CONST
00027 #else
00028 #define GIMP20_CONST const
00029 #endif
00030 
00031 
00032 /* Declare some local functions.
00033  */
00034 static void   query      (void);
00035 static void   run        (GIMP20_CONST gchar   *name,
00036                           gint     nparams,
00037                           GIMP20_CONST GimpParam  *param,
00038                           gint    *nreturn_vals,
00039                           GimpParam **return_vals);
00040 static void   load_palette(gchar *filename);
00041 static void   choose_palette (void);
00042 static gint32 load_image (gchar   *filename);
00043 static gint32 save_image (gchar  *filename,
00044       gint32  image_ID,
00045       gint32  drawable_ID,
00046       gint32  orig_image_ID);
00047 #ifdef HAVE_GIMP_1_2
00048 static GimpRunModeType run_mode;
00049 #else
00050 static GimpRunMode run_mode;
00051 #endif
00052 
00053 static guchar   gimp_cmap[768] = {
00054 0x00, 0x00, 0x00, 0xF8, 0xF0, 0xCC, 0xF4, 0xE4, 0xA4, 0xF0, 0xDC, 0x78, 
00055 0xEC, 0xD0, 0x50, 0xEC, 0xC8, 0x28, 0xD8, 0xAC, 0x20, 0xC4, 0x94, 0x18, 
00056 0xB0, 0x80, 0x10, 0x9C, 0x68, 0x0C, 0x88, 0x54, 0x08, 0x74, 0x44, 0x04, 
00057 0x60, 0x30, 0x00, 0x4C, 0x24, 0x00, 0x38, 0x14, 0x00, 0xF8, 0xFC, 0xFC, 
00058 0xFC, 0xD8, 0xD8, 0xFC, 0xB8, 0xB8, 0xFC, 0x98, 0x9C, 0xFC, 0x78, 0x80, 
00059 0xFC, 0x58, 0x64, 0xFC, 0x38, 0x4C, 0xFC, 0x1C, 0x34, 0xDC, 0x14, 0x28, 
00060 0xC0, 0x0C, 0x1C, 0xA4, 0x08, 0x14, 0x88, 0x04, 0x0C, 0x6C, 0x00, 0x04, 
00061 0x50, 0x00, 0x00, 0x34, 0x00, 0x00, 0x18, 0x00, 0x00, 0xFC, 0xEC, 0xD8, 
00062 0xFC, 0xDC, 0xB8, 0xFC, 0xCC, 0x98, 0xFC, 0xBC, 0x7C, 0xFC, 0xAC, 0x5C, 
00063 0xFC, 0x9C, 0x3C, 0xFC, 0x8C, 0x1C, 0xFC, 0x7C, 0x00, 0xE0, 0x6C, 0x00, 
00064 0xC0, 0x60, 0x00, 0xA4, 0x50, 0x00, 0x88, 0x44, 0x00, 0x6C, 0x34, 0x00, 
00065 0x50, 0x24, 0x00, 0x34, 0x18, 0x00, 0x18, 0x08, 0x00, 0xFC, 0xFC, 0xD8, 
00066 0xF4, 0xF4, 0x9C, 0xEC, 0xEC, 0x60, 0xE4, 0xE4, 0x2C, 0xDC, 0xDC, 0x00, 
00067 0xC0, 0xC0, 0x00, 0xA4, 0xA4, 0x00, 0x88, 0x88, 0x00, 0x6C, 0x6C, 0x00, 
00068 0x50, 0x50, 0x00, 0x34, 0x34, 0x00, 0x18, 0x18, 0x00, 0xD8, 0xFC, 0xD8, 
00069 0xB0, 0xFC, 0xAC, 0x8C, 0xFC, 0x80, 0x6C, 0xFC, 0x54, 0x50, 0xFC, 0x28, 
00070 0x38, 0xFC, 0x00, 0x28, 0xDC, 0x00, 0x1C, 0xC0, 0x00, 0x14, 0xA4, 0x00, 
00071 0x0C, 0x88, 0x00, 0x04, 0x6C, 0x00, 0x00, 0x50, 0x00, 0x00, 0x34, 0x00, 
00072 0x00, 0x18, 0x00, 0xD4, 0xD8, 0xFC, 0xB8, 0xB8, 0xFC, 0x98, 0x98, 0xFC, 
00073 0x7C, 0x7C, 0xFC, 0x5C, 0x5C, 0xFC, 0x3C, 0x3C, 0xFC, 0x00, 0x00, 0xFC, 
00074 0x00, 0x00, 0xE0, 0x00, 0x00, 0xC0, 0x00, 0x00, 0xA4, 0x00, 0x00, 0x88, 
00075 0x00, 0x00, 0x6C, 0x00, 0x00, 0x50, 0x00, 0x00, 0x34, 0x00, 0x00, 0x18, 
00076 0xE8, 0xC8, 0xE8, 0xD4, 0x98, 0xD4, 0xC4, 0x6C, 0xC4, 0xB0, 0x48, 0xB0, 
00077 0xA0, 0x28, 0xA0, 0x8C, 0x10, 0x8C, 0x7C, 0x00, 0x7C, 0x6C, 0x00, 0x6C, 
00078 0x60, 0x00, 0x60, 0x50, 0x00, 0x50, 0x44, 0x00, 0x44, 0x34, 0x00, 0x34, 
00079 0x24, 0x00, 0x24, 0x18, 0x00, 0x18, 0xF4, 0xE8, 0xE4, 0xEC, 0xDC, 0xD4, 
00080 0xE4, 0xCC, 0xC0, 0xE0, 0xC0, 0xB0, 0xD8, 0xB0, 0xA0, 0xD0, 0xA4, 0x90, 
00081 0xC8, 0x98, 0x80, 0xC4, 0x8C, 0x74, 0xAC, 0x7C, 0x64, 0x98, 0x6C, 0x58, 
00082 0x80, 0x5C, 0x4C, 0x6C, 0x4C, 0x3C, 0x54, 0x3C, 0x30, 0x3C, 0x2C, 0x24, 
00083 0x28, 0x1C, 0x14, 0x10, 0x0C, 0x08, 0xEC, 0xEC, 0xEC, 0xDC, 0xDC, 0xDC, 
00084 0xCC, 0xCC, 0xCC, 0xBC, 0xBC, 0xBC, 0xAC, 0xAC, 0xAC, 0x9C, 0x9C, 0x9C, 
00085 0x8C, 0x8C, 0x8C, 0x7C, 0x7C, 0x7C, 0x6C, 0x6C, 0x6C, 0x60, 0x60, 0x60, 
00086 0x50, 0x50, 0x50, 0x44, 0x44, 0x44, 0x34, 0x34, 0x34, 0x24, 0x24, 0x24, 
00087 0x18, 0x18, 0x18, 0x08, 0x08, 0x08, 0xE8, 0xE0, 0xD4, 0xD8, 0xC8, 0xB0, 
00088 0xC8, 0xB0, 0x90, 0xB8, 0x98, 0x70, 0xA8, 0x84, 0x58, 0x98, 0x70, 0x40, 
00089 0x88, 0x5C, 0x2C, 0x7C, 0x4C, 0x18, 0x6C, 0x3C, 0x0C, 0x5C, 0x34, 0x0C, 
00090 0x4C, 0x2C, 0x0C, 0x3C, 0x24, 0x0C, 0x2C, 0x1C, 0x08, 0x20, 0x14, 0x08, 
00091 0xEC, 0xE8, 0xE4, 0xDC, 0xD4, 0xD0, 0xCC, 0xC4, 0xBC, 0xBC, 0xB0, 0xAC, 
00092 0xAC, 0xA0, 0x98, 0x9C, 0x90, 0x88, 0x8C, 0x80, 0x78, 0x7C, 0x70, 0x68, 
00093 0x6C, 0x60, 0x5C, 0x60, 0x54, 0x50, 0x50, 0x48, 0x44, 0x44, 0x3C, 0x38, 
00094 0x34, 0x30, 0x2C, 0x24, 0x20, 0x20, 0x18, 0x14, 0x14, 0xE0, 0xE8, 0xD4, 
00095 0xC8, 0xD4, 0xB4, 0xB4, 0xC0, 0x98, 0x9C, 0xAC, 0x7C, 0x88, 0x98, 0x60, 
00096 0x70, 0x84, 0x4C, 0x5C, 0x70, 0x38, 0x4C, 0x5C, 0x28, 0x40, 0x50, 0x20, 
00097 0x38, 0x44, 0x1C, 0x30, 0x3C, 0x18, 0x28, 0x30, 0x14, 0x20, 0x24, 0x10, 
00098 0x18, 0x1C, 0x08, 0x0C, 0x10, 0x04, 0xEC, 0xD8, 0xCC, 0xDC, 0xB8, 0xA0, 
00099 0xCC, 0x98, 0x7C, 0xBC, 0x80, 0x5C, 0xAC, 0x64, 0x3C, 0x9C, 0x50, 0x24, 
00100 0x8C, 0x3C, 0x0C, 0x7C, 0x2C, 0x00, 0x6C, 0x24, 0x00, 0x60, 0x20, 0x00, 
00101 0x50, 0x1C, 0x00, 0x44, 0x14, 0x00, 0x34, 0x10, 0x00, 0x24, 0x0C, 0x00, 
00102 0xF0, 0xF0, 0xFC, 0xE4, 0xE4, 0xFC, 0xD8, 0xD8, 0xFC, 0xCC, 0xCC, 0xFC, 
00103 0xC0, 0xC0, 0xFC, 0xB4, 0xB4, 0xFC, 0xA8, 0xA8, 0xFC, 0x9C, 0x9C, 0xFC, 
00104 0x84, 0xD0, 0x00, 0x84, 0xB0, 0x00, 0x7C, 0x94, 0x00, 0x68, 0x78, 0x00, 
00105 0x50, 0x58, 0x00, 0x3C, 0x40, 0x00, 0x2C, 0x24, 0x00, 0x1C, 0x08, 0x00, 
00106 0x20, 0x00, 0x00, 0xEC, 0xD8, 0xC4, 0xDC, 0xC0, 0xB4, 0xCC, 0xB4, 0xA0, 
00107 0xBC, 0x9C, 0x94, 0xAC, 0x90, 0x80, 0x9C, 0x84, 0x74, 0x8C, 0x74, 0x64, 
00108 0x7C, 0x64, 0x58, 0x6C, 0x54, 0x4C, 0x60, 0x48, 0x44, 0x50, 0x40, 0x38, 
00109 0x44, 0x34, 0x2C, 0x34, 0x2C, 0x24, 0x24, 0x18, 0x18, 0x18, 0x10, 0x10, 
00110 0xFC, 0xF8, 0xFC, 0xAC, 0xD4, 0xF0, 0x70, 0xAC, 0xE4, 0x34, 0x8C, 0xD8, 
00111 0x00, 0x6C, 0xD0, 0x30, 0x8C, 0xD8, 0x6C, 0xB0, 0xE4, 0xB0, 0xD4, 0xF0, 
00112 0xFC, 0xFC, 0xF8, 0xFC, 0xEC, 0x40, 0xFC, 0xC0, 0x28, 0xFC, 0x8C, 0x10, 
00113 0xFC, 0x50, 0x00, 0xC8, 0x38, 0x00, 0x98, 0x28, 0x00, 0x68, 0x18, 0x00, 
00114 0x7C, 0xDC, 0x7C, 0x44, 0xB4, 0x44, 0x18, 0x90, 0x18, 0x00, 0x6C, 0x00, 
00115 0xF8, 0xB8, 0xFC, 0xFC, 0x64, 0xEC, 0xFC, 0x00, 0xB4, 0xCC, 0x00, 0x70, 
00116 0xFC, 0xFC, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0x00, 
00117 0xFC, 0xFC, 0xFC, 0x61, 0x61, 0x61, 0xC0, 0xC0, 0xC0, 0xFC, 0x00, 0xF1 };
00118 
00119 GimpPlugInInfo PLUG_IN_INFO =
00120 {
00121   NULL,  /* init_proc  */
00122   NULL,  /* quit_proc  */
00123   query, /* query_proc */
00124   run,   /* run_proc   */
00125 };
00126 
00127 struct u7frame {
00128   gint16 leftX;
00129   gint16 leftY;
00130   gint16 rightX;
00131   gint16 rightY;
00132   gint16 width;
00133   gint16 height;
00134         gint32 datalen;
00135   guchar *pixels;
00136 };
00137 
00138 struct u7shape {
00139   int num_frames;
00140   struct u7frame *frames;
00141 };
00142 
00143 
00144 MAIN ()
00145 
00146 static void
00147 query (void)
00148 {
00149   static GimpParamDef load_args[] = {
00150     { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
00151     { GIMP_PDB_STRING, "filename", "The name of the file to load" },
00152     { GIMP_PDB_STRING, "raw_filename", "The name entered" }
00153   };
00154   static GimpParamDef load_return_vals[] = {
00155     { GIMP_PDB_IMAGE, "image", "Output image" }
00156   };
00157   static gint nload_args = sizeof (load_args) / sizeof (load_args[0]);
00158   static gint nload_return_vals = (sizeof (load_return_vals) /
00159     sizeof (load_return_vals[0]));
00160 
00161   static GimpParamDef save_args[] = {
00162     { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
00163     { GIMP_PDB_IMAGE,    "image",           "Image to save" },
00164     { GIMP_PDB_DRAWABLE, "drawable",        "Drawable to save" },
00165     { GIMP_PDB_STRING, "filename", "The name of the file to save" },
00166     { GIMP_PDB_STRING, "raw_filename", "The name entered" }
00167   };
00168   static gint nsave_args = sizeof (save_args) / sizeof (save_args[0]);
00169 
00170   gimp_install_procedure ("file_shp_load",
00171     "loads files in Ultima 7 SHP format",
00172     "FIXME: write help for shp_load",
00173     "Tristan Tarrant",
00174     "Tristan Tarrant",
00175     "2000",
00176     "<Load>/SHP",
00177     NULL,
00178     GIMP_PLUGIN,
00179     nload_args, nload_return_vals,
00180     load_args, load_return_vals);
00181 
00182   gimp_register_magic_load_handler ("file_shp_load",
00183     "shp",
00184     "",
00185     "");
00186 
00187   gimp_install_procedure ("file_shp_save",
00188     "Save files in Ultima 7 SHP format",
00189     "FIXME: write help for shp_save",
00190     "Tristan Tarrant",
00191     "Tristan Tarrant",
00192     "2000",
00193     "<Save>/SHP",
00194     "INDEXEDA",
00195     GIMP_PLUGIN,
00196     nsave_args, 0,
00197     save_args, NULL);
00198 
00199   gimp_register_save_handler ("file_shp_save",
00200     "shp",
00201     "");
00202 }
00203 
00204 static void
00205 run (GIMP20_CONST gchar   *name,
00206      gint     nparams,
00207      GIMP20_CONST GimpParam  *param,
00208      gint    *nreturn_vals,
00209      GimpParam **return_vals)
00210 {
00211   static GimpParam values[2];
00212   GimpPDBStatusType   status = GIMP_PDB_SUCCESS;
00213   gint32        image_ID;
00214   gint32        drawable_ID;
00215   gint32        orig_image_ID;
00216 
00217   run_mode = param[0].data.d_int32;
00218 
00219   *nreturn_vals = 1;
00220   *return_vals  = values;
00221   values[0].type          = GIMP_PDB_STATUS;
00222   values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
00223 
00224   if (strcmp (name, "file_shp_load") == 0) {
00225     gimp_ui_init ("u7shp", FALSE);
00226     choose_palette();
00227     image_ID = load_image (param[1].data.d_string);
00228 
00229     if (image_ID != -1) {
00230       *nreturn_vals = 2;
00231       values[1].type         = GIMP_PDB_IMAGE;
00232       values[1].data.d_image = image_ID;
00233     } else {
00234       status = GIMP_PDB_EXECUTION_ERROR;
00235     }
00236   } else if (strcmp (name, "file_shp_save") == 0) {
00237     image_ID    = orig_image_ID = param[1].data.d_int32;
00238     drawable_ID = param[2].data.d_int32;
00239     save_image (param[3].data.d_string,
00240       image_ID,
00241       drawable_ID,
00242       orig_image_ID);
00243   } else{
00244     status = GIMP_PDB_CALLING_ERROR;
00245   }
00246   values[0].data.d_status = status;
00247 }
00248 
00249 unsigned int read1(FILE *f)
00250 {
00251   unsigned char b0;
00252   b0 = fgetc(f);
00253   return b0;
00254 }
00255 
00256 unsigned int read2(FILE *f)
00257 {
00258   unsigned char b0, b1;
00259   b0 = fgetc(f);
00260   b1 = fgetc(f);
00261   return (b0 + (b1<<8));
00262 }
00263 
00264 /* Flauschepelz */
00265 signed int read2signed(FILE *f)
00266 {
00267         unsigned char b0, b1;
00268         signed int i0;
00269         b0 = fgetc(f);
00270         b1 = fgetc(f);
00271         i0 = b0 + (b1<<8);
00272         if (i0 >= 32768) { i0 = i0 - 65536; }
00273         return (i0);
00274 }
00275 
00276 unsigned int read4(FILE *f)
00277 {
00278   unsigned char b0, b1, b2, b3;
00279   b0 = fgetc(f);
00280   b1 = fgetc(f);
00281   b2 = fgetc(f);
00282   b3 = fgetc(f);
00283   return (b0 + (b1<<8) + (b2<<16) + (b3<<24));
00284 }
00285 
00286 void write1(FILE *f, unsigned char b)
00287 {
00288   fputc(b, f);
00289 }
00290 
00291 void write2(FILE *f, unsigned int b)
00292 {
00293   fputc(b & 0xFF, f);
00294   fputc((b >> 8) & 0xFF, f);
00295 }
00296 
00297 void write4(FILE *f, unsigned int b)
00298 {
00299   fputc(b & 0xFF, f);
00300   fputc((b >> 8) & 0xFF, f);
00301   fputc((b >> 16) & 0xFF, f);
00302   fputc((b >> 24) & 0xFF, f);
00303 }
00304 
00305 unsigned char *out1(unsigned char *p, unsigned char b)
00306 {
00307     *p++ = b;
00308     return p;
00309 }
00310 
00311 unsigned char *out2(unsigned char *p, unsigned int b)
00312 {
00313     *p++ = b & 0xFF;
00314     *p++ = (b >> 8) & 0xFF;
00315     return p;
00316 }
00317 
00318 unsigned char *out4(unsigned char *p, unsigned int b)
00319 {
00320     *p++ = b & 0xFF;
00321     *p++ = (b >> 8) & 0xFF;
00322     *p++ = (b >> 16) & 0xFF;
00323     *p++ = (b >> 24) & 0xFF;
00324     return p;
00325 }
00326 
00327 static void load_palette (gchar *filename)
00328 {
00329   FILE *fp;
00330   long len;
00331   int i;
00332   
00333   fp = fopen (filename, "rb");
00334   if (!fp) {
00335     return;
00336   }
00337   fseek(fp, 0, SEEK_END);
00338   len = ftell(fp);
00339   fseek(fp, 0, SEEK_SET);
00340   if(len==768) {
00341     for(i=0;i<256;i++) {
00342       gimp_cmap[i*3]=read1(fp) << 2;
00343       gimp_cmap[i*3+1]=read1(fp) << 2;
00344       gimp_cmap[i*3+2]=read1(fp) << 2;
00345     }
00346   } else if(len==1536) {
00347     for(i=0;i<256;i++) {
00348       gimp_cmap[i*3]=read1(fp) << 2;
00349       read1(fp);
00350       gimp_cmap[i*3+1]=read1(fp) << 2;
00351       read1(fp);
00352       gimp_cmap[i*3+2]=read1(fp) << 2;
00353       read1(fp);
00354     }
00355   }
00356   fclose(fp);
00357 }
00358 
00359 static void file_sel_delete( GtkWidget *widget, GtkWidget **file_sel )
00360 {
00361   gtk_widget_destroy( *file_sel );
00362   *file_sel = NULL;
00363 }
00364 
00365 static void file_selected( GtkWidget *widget, gboolean *selected )
00366 {
00367   *selected = TRUE;
00368 }
00369 
00370 gchar* file_select( gchar *title )
00371 {
00372   GtkWidget *file_sel;
00373   gchar *filename;
00374   gboolean selected = FALSE;
00375 
00376   file_sel = gtk_file_selection_new( title );
00377   gtk_window_set_modal( GTK_WINDOW( file_sel ), TRUE );
00378 
00379   gtk_signal_connect( GTK_OBJECT( file_sel ), "destroy", 
00380                             GTK_SIGNAL_FUNC( file_sel_delete ), &file_sel );
00381   
00382         gtk_signal_connect( GTK_OBJECT( GTK_FILE_SELECTION( file_sel )->cancel_button ), "clicked", GTK_SIGNAL_FUNC( file_sel_delete ), &file_sel );
00383         
00384         gtk_signal_connect( GTK_OBJECT( GTK_FILE_SELECTION( file_sel )->ok_button ), "clicked", GTK_SIGNAL_FUNC( file_selected ), &selected );
00385 
00386         gtk_widget_show( file_sel );
00387 
00388   while( ( ! selected ) && ( file_sel ) )
00389     gtk_main_iteration();
00390 
00391   /* canceled or window was closed */
00392   if( ! selected )
00393     return NULL;
00394 
00395   /* ok */
00396   filename = g_strdup( gtk_file_selection_get_filename( GTK_FILE_SELECTION( file_sel ) ) );
00397   gtk_widget_destroy( file_sel );
00398   return filename;
00399 }
00400 
00401 
00402 
00403 static void choose_palette()
00404 {
00405   load_palette(file_select("Choose palette"));
00406 }
00407 
00408 
00409 static gint32 load_image (gchar *filename)
00410 {
00411   FILE *fp;
00412   gint32 file_size;
00413   gint32 shape_size;
00414   gint32 hdr_size;
00415   guchar *pixptr, *eod;
00416   gint32 frame_offset;
00417   gint16  slice;
00418   gint32 image_ID = -1;
00419   gint32 layer_ID = -1;
00420   gint16 slice_type;
00421   gint16 slice_length;
00422   gint16 block_type;
00423   gint16 block_length;
00424   /*  gint32 max_width;
00425     gint32 max_height;*/
00426   gint16 max_leftX = -1, max_rightX = -1;
00427   gint16 max_leftY = -1, max_rightY = -1;
00428   signed int offsetX;
00429   signed int offsetY;
00430   gchar *framename;
00431   guchar block;
00432   guchar pix;
00433   GimpDrawable *drawable;
00434   GimpPixelRgn pixel_rgn;
00435   GimpImageType image_type;
00436   int i;
00437   int j;
00438 
00439         /* Flauschepelz */
00440         signed int temp_int;
00441 
00442   struct u7shape shape;
00443   struct u7frame *frame;
00444   
00445   fp = fopen (filename, "rb");
00446   if (!fp) {
00447     g_message ("SHP: can't open \"%s\"\n", filename);
00448     return -1;
00449   }
00450   fseek(fp, 0, SEEK_END);
00451   file_size = ftell(fp);
00452   fseek(fp, 0, SEEK_SET);
00453   
00454   shape_size = read4(fp);
00455   
00456   if(file_size!=shape_size) { /* 8x8 tile */
00457     image_type = GIMP_INDEXED_IMAGE;
00458     shape.num_frames = file_size/64;
00459     fseek(fp, 0, SEEK_SET);   /* Return to start of file */
00460 #ifdef DEBUG
00461     printf("num_frames = %d\n", shape.num_frames);
00462 #endif
00463     shape.frames = g_new(struct u7frame, shape.num_frames);
00464     max_leftX = 0; max_leftY = 0; max_rightX = 7; max_rightY = 7;
00465     /*    max_width = 8;
00466         max_height = 8;*/
00467     for(i=0; i<shape.num_frames; i++) {
00468       frame = &shape.frames[i];
00469       frame->width = 8;
00470       frame->height = 8;
00471       frame->leftX = 0;
00472       frame->leftY = 0;
00473       frame->pixels = (char *)g_malloc(64);
00474       fread(frame->pixels, 1, 64, fp);
00475     }
00476   } else {
00477     image_type = GIMP_INDEXEDA_IMAGE;
00478     hdr_size = read4(fp);
00479     shape.num_frames = (hdr_size-4)/4;
00480     /*    max_width = -1;
00481         max_height = -1;*/
00482 #ifdef DEBUG
00483     printf("num_frames = %d\n", shape.num_frames);
00484 #endif
00485     shape.frames = g_new(struct u7frame, shape.num_frames);
00486   
00487     for(i=0; i<shape.num_frames; i++) {
00488       frame = &shape.frames[i];
00489       // Go to where frame offset is stored
00490       fseek(fp, (i+1)*4, SEEK_SET);
00491       frame_offset = read4(fp);
00492       fseek(fp, frame_offset, SEEK_SET);
00493       frame->rightX = read2(fp);
00494       frame->leftX = read2(fp);
00495       frame->leftY = read2(fp);
00496       frame->rightY = read2(fp);
00497 
00498       if (frame->leftX > max_leftX)
00499         max_leftX = frame->leftX;
00500       if (frame->rightX > max_rightX)
00501         max_rightX = frame->rightX;
00502       if (frame->leftY > max_leftY)
00503         max_leftY = frame->leftY;
00504       if (frame->rightY > max_rightY)
00505         max_rightY = frame->rightY;
00506 
00507       frame->width = frame->leftX+frame->rightX+1;
00508       /*      if(frame->width>max_width)
00509             max_width = frame->width;*/
00510       frame->height = frame->leftY+frame->rightY+1;
00511       /*      if(frame->height>max_height)
00512             max_height = frame->height;*/
00513       pixptr = frame->pixels = g_new0(char, frame->width*frame->height*2);
00514       eod = frame->pixels+frame->width*frame->height*2;
00515       while((slice=read2(fp))!=0) {
00516         slice_type = slice & 0x1;
00517         slice_length = slice >> 1;
00518 
00519                                 /* Flauschepelz */
00520         offsetX = read2signed(fp);
00521         offsetY = read2signed(fp);
00522 
00523                                 temp_int = (frame->leftY + offsetY)*frame->width*2 +
00524                                            (frame->leftX + offsetX)*2;
00525 
00526                                 pixptr = frame->pixels;
00527                                 pixptr = pixptr + temp_int;
00528 
00529                                 /*
00530         pixptr = frame->pixels+(offsetY*frame->width+offsetX)*2;
00531                                 */
00532 
00533         if(pixptr<frame->pixels)
00534           pixptr = frame->pixels;
00535         if(slice_type) {  // Compressed
00536           while(slice_length>0) {
00537             block = read1(fp);
00538             block_type = block & 0x1;
00539             block_length = block >> 1;
00540             if(block_type) {
00541               pix = read1(fp);
00542               for(j=0;j<block_length;j++) {
00543                 *pixptr++ = pix;
00544                 *pixptr++ = 255;
00545               }
00546             } else {
00547               for(j=0;j<block_length;j++) {
00548                 pix = read1(fp);
00549                 *pixptr++ = pix;
00550                 *pixptr++ = 255;
00551               }
00552             }
00553             slice_length -= block_length;
00554           }
00555         } else {    // Uncompressed
00556           // Just read the pixels
00557           for(j=0;j<slice_length;j++) {
00558             pix = read1(fp);
00559             *pixptr++ = pix;
00560             *pixptr++ = 255;
00561           }
00562         }
00563       }
00564     }
00565   }
00566   image_ID = gimp_image_new (max_leftX+max_rightX+1, 
00567            max_leftY+max_rightY+1, GIMP_INDEXED);
00568   gimp_image_set_filename (image_ID, filename);
00569   gimp_image_set_cmap (image_ID, gimp_cmap, 256);
00570   for(i=0; i<shape.num_frames; i++) {
00571     framename = g_strdup_printf ("Frame %d", i);
00572     frame = &shape.frames[i];
00573     layer_ID = gimp_layer_new (image_ID, framename,
00574       frame->width, frame->height,
00575       image_type, 100, GIMP_NORMAL_MODE);
00576     g_free (framename);
00577     gimp_image_add_layer (image_ID, layer_ID, 0);
00578     gimp_layer_translate (layer_ID, (gint)(max_leftX-frame->leftX),
00579               (gint)(max_leftY-frame->leftY));
00580 
00581     drawable = gimp_drawable_get (layer_ID);
00582     
00583     gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, drawable->width, drawable->height, TRUE, FALSE);
00584     gimp_pixel_rgn_set_rect (&pixel_rgn, frame->pixels, 0, 0, drawable->width, drawable->height);
00585 
00586     gimp_drawable_flush (drawable);
00587     gimp_drawable_detach (drawable);
00588   }
00589 
00590   fclose(fp);
00591   
00592   for(i=0; i<shape.num_frames; i++) {
00593     g_free(shape.frames[i].pixels);
00594   }
00595 
00596   g_free(shape.frames);
00597 
00598   gimp_image_add_hguide(image_ID, max_leftY);
00599 #ifdef DEBUG
00600   printf("Added hguide=%d\n", max_leftY);
00601 #endif
00602   gimp_image_add_vguide(image_ID, max_leftX);
00603 #ifdef DEBUG
00604   printf("Added vguide=%d\n", max_leftX);
00605 #endif
00606   
00607   return image_ID;
00608 }
00609 
00610 static int find_runs(short *runs, unsigned char *pixptr, int x, int w)
00611 {
00612     int runcnt = 0;
00613     while (x < w && pixptr[1] != 0) { // Stop at first transparent pixel.
00614   int run = 0;    // Look for repeat.
00615   while (x < w - 1 && pixptr[0] == pixptr[2] && pixptr[3]!=0) {
00616 #ifdef DEBUG
00617       if(pixptr[3]==0)
00618       printf("Warning: found pixel pair, but second is transparent\n");
00619 #endif
00620       x++;
00621       pixptr+=2;
00622       run++;
00623   }
00624   if (run) {    // Repeated?  Count 1st, shift, flag.
00625       run = ((run + 1)<<1)|1;
00626       x++;    // Also pass the last one.
00627       pixptr+=2;
00628   } else {
00629     do {      /* Pass non-repeated run of */
00630         x++;
00631         pixptr+=2;
00632         run += 2; // So we don't have to shift.
00633     } while (x < w && pixptr[1] != 0 &&
00634      (x == w - 1 || pixptr[0] != pixptr[2]));
00635   }
00636   // Store run length.
00637   runs[runcnt++] = run;
00638     }
00639     runs[runcnt] = 0;   /* 0-delimit list. */
00640     return x;
00641 }
00642 
00643 static int skip_transparent(unsigned char **pixptr, int x, int w)
00644 {
00645     unsigned char *pixel = *pixptr;
00646     while (x < w && pixel[1] == 0) {  /* Pixel is transparent if alpha is 0 */
00647   x++;
00648   pixel+=2;
00649     }
00650     *pixptr = pixel;
00651     return x;
00652 }
00653 
00654 static gint32 save_image (gchar  *filename,
00655       gint32  image_ID,
00656       gint32  drawable_ID,
00657       gint32  orig_image_ID)
00658 {
00659   FILE *fp;
00660   gint32 shape_size;
00661   gint32 hdr_size;
00662   gint32 max_width;
00663   gint32 max_height;
00664   gint offsetX;
00665   gint offsetY;
00666   gchar *name_buf;
00667   GimpDrawable *drawable;
00668   GimpPixelRgn pixel_rgn;
00669   guchar *pixptr;
00670   guchar *pix;
00671   guchar *out;
00672   guchar *outptr;
00673   int i;
00674   int j;
00675   int k;
00676   int newx;
00677   int x;
00678   int y;
00679   int hotx;
00680   int hoty;
00681   gint32 guide_ID;
00682   gint32 *layers;   
00683   int nlayers;
00684   int pos;
00685 
00686   struct u7shape shape;
00687   struct u7frame *frame;
00688   
00689   if (run_mode != GIMP_RUN_NONINTERACTIVE) {
00690     name_buf = g_strdup_printf ("Saving %s:", filename);
00691     gimp_progress_init (name_buf);
00692     g_free (name_buf);
00693   }
00694   
00695   /* Find the guides... */
00696   guide_ID = gimp_image_find_next_guide(image_ID, 0);
00697   hotx = -1;
00698   hoty = -1;
00699   while(guide_ID>0) {
00700     int orientation;
00701 #ifdef DEBUG
00702     printf("Found guide %d:", guide_ID);
00703 #endif
00704     orientation = gimp_image_get_guide_orientation(image_ID, guide_ID);
00705     switch(orientation) {
00706 #ifdef HAVE_GIMP_1_2
00707     case GIMP_HORIZONTAL:
00708 #else
00709     case GIMP_ORIENTATION_HORIZONTAL:
00710 #endif
00711       if(hoty<0) {
00712         hoty = gimp_image_get_guide_position(image_ID, guide_ID);
00713 #ifdef DEBUG
00714         printf(", horizontal=%d\n", hoty);
00715 #endif
00716       }
00717       break;
00718 #ifdef HAVE_GIMP_1_2
00719     case GIMP_VERTICAL:
00720 #else
00721     case GIMP_ORIENTATION_VERTICAL:
00722 #endif
00723       if(hotx<0) {
00724         hotx = gimp_image_get_guide_position(image_ID, guide_ID);
00725 #ifdef DEBUG
00726         printf(", vertical=%d\n", hotx);
00727 #endif
00728       }
00729       break;
00730     default:
00731       break;
00732     }
00733     guide_ID = gimp_image_find_next_guide(image_ID, guide_ID);
00734   }
00735   
00736   /* get a list of layers for this image_ID */
00737   layers = gimp_image_get_layers (image_ID, &nlayers);
00738 
00739   if (nlayers > 0 && !gimp_drawable_is_indexed(layers[0])) {
00740     g_message ("SHP: You can only save indexed images!");
00741     return -1;    
00742   }
00743 
00744   max_width = gimp_image_width (image_ID);
00745   max_height = gimp_image_height (image_ID);
00746 
00747   shape.num_frames = nlayers;
00748   hdr_size = (nlayers+1)*4;
00749   shape.frames = (struct u7frame *)malloc(sizeof(struct u7frame)*shape.num_frames);
00750 
00751   for (k=0;k<nlayers;k++) {
00752     frame = &shape.frames[k];
00753     drawable = gimp_drawable_get (layers[k]);
00754     gimp_drawable_offsets (layers[k], &offsetX, &offsetY);
00755     frame->width = drawable->width;
00756     frame->height = drawable->height;
00757     frame->leftX = hotx - offsetX;
00758     frame->leftY = hoty - offsetY;
00759     frame->rightX = frame->width-frame->leftX-1;
00760     frame->rightY = frame->height-frame->leftY-1;
00761     pix = (gchar *)malloc(frame->width*frame->height*2);
00762     pixptr = pix;
00763     out = (gchar *)malloc(frame->width*frame->height*8);
00764     outptr = out;
00765     gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0,
00766              drawable->width, drawable->height, FALSE, FALSE);
00767     gimp_pixel_rgn_get_rect (&pixel_rgn, pixptr, 0, 0,
00768            drawable->width, drawable->height);
00769 
00770     newx = 0;
00771     for (y = 0; y < frame->height; y++) {
00772         for (x = 0; (x = skip_transparent(&pixptr, x, frame->width)) < frame->width; x = newx) {
00773       short runs[100];
00774       newx = find_runs(runs, pixptr, x, frame->width);
00775       if (!runs[1] && !(runs[0]&1)) {
00776           int len = runs[0] >> 1;
00777           outptr = out2(outptr, runs[0]);
00778           outptr = out2(outptr, x - frame->leftX);
00779           outptr = out2(outptr, y - frame->leftY);
00780           for(i=0; i<len; i++) {
00781         *outptr++ = *pixptr;
00782         pixptr +=2;
00783           }
00784       } else {
00785           outptr = out2(outptr, ((newx - x)<<1)|1);
00786           outptr = out2(outptr, x - frame->leftX);
00787           outptr = out2(outptr, y - frame->leftY);
00788           for (i = 0; runs[i]; i++) {
00789         int len = runs[i]>>1;
00790         if (runs[i]&1) {
00791             while (len) {
00792           int c = len > 127 ? 127 : len;
00793           *outptr++ = (c<<1)|1;
00794           *outptr++ = *pixptr;
00795           pixptr += (c*2);
00796           len -= c;
00797             }
00798         } else while (len > 0) {
00799             int c;
00800             c = len > 127 ? 127 : len;
00801             *outptr++ = c<<1;
00802             for(j=0; j<c; j++) {
00803           *outptr++ = *pixptr;
00804           pixptr +=2;
00805             }
00806             len -= c;
00807         }
00808           }
00809       }
00810         }
00811     }
00812     outptr = out2(outptr, 0);     // End with 0 length.
00813     frame->datalen = outptr - out;
00814     frame->pixels = (gchar *) malloc(frame->datalen);
00815     memcpy(frame->pixels, out, frame->datalen);
00816     free(out);
00817     free(pix);
00818     gimp_drawable_detach(drawable);
00819   }
00820 
00821   fp = fopen (filename, "wb");
00822   if (!fp) {
00823     g_message ("SHP: can't create \"%s\"\n", filename);
00824     return -1;
00825   }
00826 
00827   shape_size = 0;
00828   write4(fp, shape_size); // Fill in later
00829   for(i=0; i<shape.num_frames; i++) 
00830       write4(fp, 0);  // Fill in later
00831   for(i=0; i<shape.num_frames; i++) {
00832       frame = &shape.frames[shape.num_frames-i-1];
00833       pos = ftell(fp);  // Get the frame offset
00834       fseek(fp, (i+1)*4, SEEK_SET);
00835       write4(fp, pos);  // Write it in the right place
00836       fseek(fp, pos, SEEK_SET);
00837       write2(fp, frame->rightX);
00838       write2(fp, frame->leftX);
00839       write2(fp, frame->leftY);
00840       write2(fp, frame->rightY);
00841       fwrite(frame->pixels, 1, frame->datalen, fp);
00842   }
00843 
00844   pos = ftell(fp);  // Get the file size
00845   fseek(fp, 0, SEEK_SET);
00846   write4(fp, pos);  // Write it in the right place
00847 
00848   fclose(fp);
00849   
00850   for(i=0; i<shape.num_frames; i++) {
00851       free(shape.frames[i].pixels);
00852   }
00853   free(shape.frames);
00854 
00855   return 0;
00856 }

Generated on Mon Jul 9 14:42:48 2007 for ExultEngine by  doxygen 1.5.1