home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (C) 1996 by Raphael Quinet. All rights reserved.
- *
- * Permission to use, copy, modify, and distribute this software and
- * its documentation for any purpose and without fee is hereby
- * granted, provided that the above copyright notice appear in all
- * copies and that both that copyright notice and this permission
- * notice appear in supporting documentation. If more than a few
- * lines of this code are used in a program which displays a copyright
- * notice or credit notice, the following acknowledgment must also be
- * displayed on the same screen: "This product includes software
- * developed by Raphael Quinet for use in the Quake Editing Utilities
- * project." THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR
- * IMPLIED WARRANTY.
- *
- * More information about the QEU project can be found on the WWW:
- * "http://www.montefiore.ulg.ac.be/~quinet/games/editing.html" or by
- * mail: Raphael Quinet, 9 rue des Martyrs, B-4550 Nandrin, Belgium.
- */
-
- /*
- * F_SPRITE.C - Read and write Quake sprite files.
- */
-
- /*
- * NOTE: There are still some parts of the sprite format which are a
- * bit strange for me. I could be wrong for the multi-image
- * stuff, even if it works rather well. The test version of
- * Quake doesn't contain enough "special" sprites like the
- * torches (s_torch*.spr) and the shots (shots.spr), so I'm
- * not sure if my guesses are correct.
- * This piece of code is probably more complex than it should
- * be, but at least it works. More or less.
- */
-
- #include "qeu.h"
- #include "q_misc.h"
- #include "q_files.h"
- #include "f_sprite.h"
- /*! #include <math.h> */
-
- /*
- * Create a new, empty sprite.
- */
- SpritePtr NewSprite()
- {
- SpritePtr sprite;
-
- sprite = (SpritePtr)QMalloc((UInt32)sizeof(struct SpriteInfo));
- sprite->unknown1 = 0L;
- sprite->unknown2 = 0L;
- sprite->radius = 0.0;
- sprite->maxwidth = 0;
- sprite->maxheight = 0;
- sprite->numframes = 0;
- sprite->frames = NULL;
- sprite->unknown4 = 0L;
- sprite->unknown5 = 0L;
- return sprite;
- }
-
-
- /*
- * Discard a sprite and free memory.
- */
- void FreeSprite(SpritePtr sprite)
- {
- UInt16 i, j;
-
- if (sprite->numframes > 0)
- for (i = 0; i < sprite->numframes; i++)
- if (sprite->frames[i].images != NULL)
- {
- if (sprite->frames[i].numimages == 0)
- {
- if (sprite->frames[i].images[0].bitmap.data != NULL)
- QFree(sprite->frames[i].images[0].bitmap.data);
- }
- else
- {
- for (j = 0; j < sprite->frames[i].numimages; j++)
- if (sprite->frames[i].images[j].bitmap.data != NULL)
- QFree(sprite->frames[i].images[j].bitmap.data);
- }
- }
- QFree(sprite);
- }
-
-
- /*
- * Add an image to a sprite. The bitmap data is copied and can be
- * freed after having called this function. If "framenum" is negative
- * and "multi" is FALSE, a new frame is created, containing a single
- * image. If "framenum" is negative and "multi" is TRUE, a new
- * multi-image frame is created, using the value of "unknown" for the
- * first image. If "framenum" is greater or equal to zero and "multi"
- * is TRUE, the image is added to an existing multi-image frame.
- * Returns the number of the frame that was added or modified.
- */
- UInt16 AddSpriteImage(SpritePtr sprite, Int16 framenum, Bool multi,
- Float32 unknown, Int16 xoffset, Int16 yoffset,
- BitMap *bmptr)
- {
- UInt16 n, i;
-
- n = sprite->numframes;
- if (framenum < 0)
- {
- if (n == 0)
- sprite->frames = (SpriteFrame *)QMalloc((UInt32)sizeof(SpriteFrame));
- else
- sprite->frames = (SpriteFrame *)QRealloc(sprite->frames,
- (UInt32)(n + 1) * (UInt32)sizeof(SpriteFrame));
- if (multi == TRUE)
- {
- sprite->frames[n].numimages = 1;
- sprite->frames[n].unknown = (Float32 *)QMalloc(
- (UInt32)sizeof(Float32));
- }
- else
- sprite->frames[n].numimages = 0;
- sprite->frames[n].images = (SpriteImage *)QMalloc(
- (UInt32)sizeof(SpriteImage));
- sprite->numframes = n + 1;
- i = 0;
- }
- else
- {
- if (n == 0 || framenum >= n)
- ProgError("BUG: cannot add an image to a non-existing frame (%d, %d)",
- n, framenum);
- n = framenum;
- i = sprite->frames[n].numimages;
- if (i == 0)
- {
- sprite->frames[n].unknown = (Float32 *)QMalloc(
- (UInt32)sizeof(Float32));
- sprite->frames[n].images = (SpriteImage *)QMalloc(
- (UInt32)sizeof(SpriteImage));
- }
- else
- {
- sprite->frames[n].unknown = (Float32 *)QRealloc(
- sprite->frames[n].unknown, (UInt32)(i + 1)
- * (UInt32)sizeof(Float32));
- sprite->frames[n].images = (SpriteImage *)QRealloc(
- sprite->frames[n].images, (UInt32)(i + 1)
- * (UInt32)sizeof(SpriteImage));
- }
- sprite->frames[n].unknown[i] = unknown;
- sprite->frames[n].numimages = i + 1;
- }
- sprite->frames[n].images[i].xoffset = xoffset;
- sprite->frames[n].images[i].yoffset = yoffset;
- sprite->frames[n].images[i].bitmap.width = bmptr->width;
- sprite->frames[n].images[i].bitmap.height = bmptr->height;
- sprite->frames[n].images[i].bitmap.data = QMemDup(bmptr->data,
- (UInt32)(bmptr->width) * (UInt32)(bmptr->height));
- return n;
- }
-
-
- /*
- * Read a sprite into memory. The optional offset to the start of the
- * sprite data is given in "offset" (so that one can read the sprite
- * data from an individual file as well as from within a WAD2 or PACK
- * file).
- */
- SpritePtr ReadSprite(FILE *file, UInt32 offset)
- {
- SpritePtr sprite;
- UInt32 numframes;
- UInt16 n, i, f = 0;
- UInt32 u, w, h;
- Int32 x, y;
- BitMap *bmptr;
- Float32 *unknown;
-
- if (file == NULL)
- return NULL;
- if ((fseek(file, offset, SEEK_SET) < 0)
- || (ReadMagic(file) != FTYPE_SPRITE))
- return NULL;
- sprite = NewSprite();
- if ((ReadInt32(file, &(sprite->unknown1)) == FALSE)
- || (ReadInt32(file, &(sprite->unknown2)) == FALSE)
- || (ReadFloat32(file, &(sprite->radius)) == FALSE)
- || (ReadInt32(file, &w) == FALSE)
- || (w > 65535L)
- || (ReadInt32(file, &h) == FALSE)
- || (h > 65535L)
- || (ReadInt32(file, &numframes) == FALSE)
- || (numframes > 65535L)
- || (ReadInt32(file, &(sprite->unknown4)) == FALSE)
- || (ReadInt32(file, &(sprite->unknown5)) == FALSE))
- {
- FreeSprite(sprite);
- return NULL;
- }
- sprite->maxwidth = (UInt16)w;
- sprite->maxheight = (UInt16)h;
- if (numframes == 0L)
- return sprite;
- bmptr = NewBitMap();
- bmptr->data = (UInt8 huge *)QMalloc(w * h);
- for (n = 0; n < (UInt16)numframes; n++)
- {
- if (ReadInt32(file, &u) == FALSE)
- {
- FreeBitMap(bmptr);
- FreeSprite(sprite);
- return NULL;
- }
- if (u != 0)
- {
- printf("(Frame %d) u = 0x%lx\n", n, u);
- if (ReadInt32(file, &u) == FALSE)
- {
- FreeBitMap(bmptr);
- FreeSprite(sprite);
- return NULL;
- }
- unknown = (Float32 *)QMalloc(u * (UInt32)sizeof(Float32));
- for (i = 0; i < (UInt16)u; i++)
- if (ReadFloat32(file, &(unknown[i])) == FALSE)
- {
- QFree(unknown);
- FreeBitMap(bmptr);
- FreeSprite(sprite);
- return NULL;
- }
- for (i = 0; i < (UInt16)u; i++)
- {
- if ((ReadInt32(file, &x) == FALSE)
- || (x > 32767L)
- || (x < -32768L)
- || (ReadInt32(file, &y) == FALSE)
- || (y > 32767L)
- || (y < -32768L)
- || (ReadInt32(file, &w) == FALSE)
- || (w == 0)
- || (w > (UInt32)(sprite->maxwidth))
- || (ReadInt32(file, &h) == FALSE)
- || (h == 0)
- || (h > (UInt32)(sprite->maxheight))
- || (ReadBytes(file, bmptr->data, w * h) == FALSE))
- {
- QFree(unknown);
- FreeBitMap(bmptr);
- FreeSprite(sprite);
- return NULL;
- }
- bmptr->width = (UInt16)w;
- bmptr->height = (UInt16)h;
- if (i == 0)
- f = AddSpriteImage(sprite, -1, TRUE, unknown[i],
- (Int16)x, (Int16)y, bmptr);
- else
- f = AddSpriteImage(sprite, f, TRUE, unknown[i],
- (Int16)x, (Int16)y, bmptr);
- }
- QFree(unknown);
- }
- else
- {
- if ((ReadInt32(file, &x) == FALSE)
- || (x > 32767L)
- || (x < -32768L)
- || (ReadInt32(file, &y) == FALSE)
- || (y > 32767L)
- || (y < -32768L)
- || (ReadInt32(file, &w) == FALSE)
- || (w == 0)
- || (w > (UInt32)(sprite->maxwidth))
- || (ReadInt32(file, &h) == FALSE)
- || (h == 0)
- || (h > (UInt32)(sprite->maxheight))
- || (ReadBytes(file, bmptr->data, w * h) == FALSE))
- {
- FreeBitMap(bmptr);
- FreeSprite(sprite);
- return NULL;
- }
- bmptr->width = (UInt16)w;
- bmptr->height = (UInt16)h;
- AddSpriteImage(sprite, -1, FALSE, 0.0, (Int16)x, (Int16)y, bmptr);
- }
- }
- FreeBitMap(bmptr);
- return sprite;
- }
-
-
- /*
- * Print the structure of a sprite in "outf".
- */
- void DumpSprite(FILE *outf, SpritePtr sprite)
- {
- UInt16 n, i;
-
- if (outf == NULL || sprite == NULL)
- return;
- fprintf(outf, "Unknown1 = 0x%lx\n", sprite->unknown1);
- fprintf(outf, "Unknown2 = 0x%lx\n", sprite->unknown2);
- fprintf(outf, "Radius = %f\n", sprite->radius);
- fprintf(outf, "MaxWidth = %u\n", sprite->maxwidth);
- fprintf(outf, "MaxHeight = %u\n", sprite->maxheight);
- fprintf(outf, "NumFrames = %u\n", sprite->numframes);
- fprintf(outf, "Unknown4 = 0x%lx\n", sprite->unknown4);
- fprintf(outf, "Unknown5 = 0x%lx\n", sprite->unknown5);
- for (n = 0; n < sprite->numframes; n++)
- {
- printf("Frame %d:\n", n);
- if (sprite->frames[n].numimages == 0)
- {
- fprintf(outf, " x offset = %d\n",
- sprite->frames[n].images[0].xoffset);
- fprintf(outf, " y offset = %d\n",
- sprite->frames[n].images[0].yoffset);
- fprintf(outf, " width = %u\n",
- sprite->frames[n].images[0].bitmap.width);
- fprintf(outf, " height = %u\n",
- sprite->frames[n].images[0].bitmap.height);
- }
- else
- for (i = 0; i < sprite->frames[n].numimages; i++)
- {
- printf(" Image %d:\n", i);
- fprintf(outf, " unknown = %f\n",
- sprite->frames[n].unknown[i]);
- fprintf(outf, " x offset = %d\n",
- sprite->frames[n].images[i].xoffset);
- fprintf(outf, " y offset = %d\n",
- sprite->frames[n].images[i].yoffset);
- fprintf(outf, " width = %u\n",
- sprite->frames[n].images[i].bitmap.width);
- fprintf(outf, " height = %u\n",
- sprite->frames[n].images[i].bitmap.height);
- }
- }
- fprintf(outf, "End.\n");
- }
-
-
- /*
- * Adjust the sprite information according to the width and height
- * of the frames. This should be called before saving a sprite.
- */
- void AdjustSpriteInfo(SpritePtr sprite)
- {
- UInt16 n, i;
- Float32 w, h;
- Bool modified = FALSE;
-
- for (n = 0; n < sprite->numframes; n++)
- if (sprite->frames[n].numimages == 0)
- {
- if (sprite->frames[n].images[0].bitmap.width > sprite->maxwidth)
- {
- sprite->maxwidth = sprite->frames[n].images[0].bitmap.width;
- modified = TRUE;
- }
- if (sprite->frames[n].images[0].bitmap.height > sprite->maxheight)
- {
- sprite->maxheight = sprite->frames[n].images[0].bitmap.height;
- modified = TRUE;
- }
- }
- else
- for (i = 0; i < sprite->frames[n].numimages; i++)
- {
- if (sprite->frames[n].images[i].bitmap.width > sprite->maxwidth)
- {
- sprite->maxwidth = sprite->frames[n].images[i].bitmap.width;
- modified = TRUE;
- }
- if (sprite->frames[n].images[i].bitmap.height > sprite->maxheight)
- {
- sprite->maxheight = sprite->frames[n].images[i].bitmap.height;
- modified = TRUE;
- }
- }
- if (modified == TRUE)
- {
- w = (Float32)(sprite->maxwidth / 2);
- h = (Float32)(sprite->maxheight / 2);
- /*!
- sprite->radius = sqrt(w * w + h * h);
- */
- }
- /*! I don't know how to adjust the other fields (unknown{1,2,4,5}) */
- }
-
-
- /*
- * Save sprite to a file (all frames).
- * The number of bytes written is returned (0 if an error occured).
- */
- UInt32 SaveSprite(FILE *file, SpritePtr sprite)
- {
- UInt16 n, i;
- Int32 x, y;
- UInt32 u, w, h;
- UInt32 size;
-
- if (sprite == NULL)
- return 0L;
- w = (UInt32)(sprite->maxwidth);
- h = (UInt32)(sprite->maxheight);
- u = (UInt32)(sprite->numframes);
- if ((WriteBytes(file, "IDSP", 4) == FALSE)
- || (WriteInt32(file, &(sprite->unknown1)) == FALSE)
- || (WriteInt32(file, &(sprite->unknown2)) == FALSE)
- || (WriteFloat32(file, &(sprite->radius)) == FALSE)
- || (WriteInt32(file, &w) == FALSE)
- || (WriteInt32(file, &h) == FALSE)
- || (WriteInt32(file, &u) == FALSE)
- || (WriteInt32(file, &(sprite->unknown4)) == FALSE)
- || (WriteInt32(file, &(sprite->unknown5)) == FALSE))
- return 0L;
- size = 36L;
- for (n = 0; n < sprite->numframes; n++)
- {
- if (sprite->frames[n].numimages == 0)
- {
- u = 0;
- x = (Int32)(sprite->frames[n].images[0].xoffset);
- y = (Int32)(sprite->frames[n].images[0].yoffset);
- if ((WriteInt32(file, &u) == FALSE)
- || (WriteInt32(file, &x) == FALSE)
- || (WriteInt32(file, &y) == FALSE))
- return 0L;
- u = SaveBitMap(file, &(sprite->frames[n].images[0].bitmap));
- if (u == 0L)
- return 0L;
- size += 12L + u;
- }
- else
- {
- /* hack... */
- if ((sprite->frames[n].numimages >= 2)
- && (sprite->frames[n].unknown[1] > 0.1))
- u = 0x1000000;
- else
- u = 0x0000001;
- if (WriteInt32(file, &u) == FALSE)
- return 0L;
- u = (UInt32)(sprite->frames[n].numimages);
- if (WriteInt32(file, &u) == FALSE)
- return 0L;
- size += 8L;
- for (i = 0; i < sprite->frames[n].numimages; i++)
- if (WriteFloat32(file, &(sprite->frames[n].unknown[i])) == FALSE)
- return 0L;
- for (i = 0; i < sprite->frames[n].numimages; i++)
- {
- x = (Int32)(sprite->frames[n].images[i].xoffset);
- y = (Int32)(sprite->frames[n].images[i].yoffset);
- if ((WriteInt32(file, &x) == FALSE)
- || (WriteInt32(file, &y) == FALSE))
- return 0L;
- u = SaveBitMap(file, &(sprite->frames[n].images[i].bitmap));
- if (u == 0L)
- return 0L;
- size += 12 + u;
- }
- }
- }
- return size;
- }
-
- /* end of file */
-