From 7f6002caba3f0a6749820c2772161caf55b8d267 Mon Sep 17 00:00:00 2001 From: neonloop Date: Fri, 7 May 2021 20:00:12 +0000 Subject: Initial commit (uqm-0.8.0) --- src/libs/graphics/gfxload.c | 597 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 597 insertions(+) create mode 100644 src/libs/graphics/gfxload.c (limited to 'src/libs/graphics/gfxload.c') diff --git a/src/libs/graphics/gfxload.c b/src/libs/graphics/gfxload.c new file mode 100644 index 0000000..969a910 --- /dev/null +++ b/src/libs/graphics/gfxload.c @@ -0,0 +1,597 @@ +//Copyright Paul Reiche, Fred Ford. 1992-2002 + +/* + * This program 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include + +#include "options.h" +#include "port.h" +#include "libs/uio.h" +#include "libs/reslib.h" + // for _cur_resfile_name +#include "libs/log.h" +#include "libs/memlib.h" +#include "libs/graphics/tfb_draw.h" +#include "libs/graphics/drawable.h" +#include "libs/graphics/font.h" + + +typedef struct anidata +{ + int transparent_color; + int colormap_index; + int hotspot_x; + int hotspot_y; +} AniData; + +extern uio_Repository *repository; +static uio_AutoMount *autoMount[] = { NULL }; + +static void +process_image (FRAME FramePtr, TFB_Canvas img[], AniData *ani, int cel_ct) +{ + TFB_Image *tfbimg; + int hx, hy; + + FramePtr->Type = ROM_DRAWABLE; + FramePtr->Index = cel_ct; + + // handle transparency cases + if (TFB_DrawCanvas_IsPaletted (img[cel_ct])) + { // indexed color image + if (ani[cel_ct].transparent_color >= 0) + { + TFB_DrawCanvas_SetTransparentIndex (img[cel_ct], + ani[cel_ct].transparent_color, FALSE); + } + } + else + { // special transparency cases for truecolor images + if (ani[cel_ct].transparent_color == 0) + { // make RGB=0,0,0 transparent + Color color = {0, 0, 0, 0}; + TFB_DrawCanvas_SetTransparentColor (img[cel_ct], color, FALSE); + } + } + if (ani[cel_ct].transparent_color == -1) + { // enforce -1 to mean 'no transparency' + TFB_DrawCanvas_SetTransparentIndex (img[cel_ct], -1, FALSE); + // set transparent_color == -2 to use PNG tRNS transparency + } + + hx = ani[cel_ct].hotspot_x; + hy = ani[cel_ct].hotspot_y; + + FramePtr->image = TFB_DrawImage_New (img[cel_ct]); + + tfbimg = FramePtr->image; + tfbimg->colormap_index = ani[cel_ct].colormap_index; + img[cel_ct] = tfbimg->NormalImg; + + FramePtr->HotSpot = MAKE_HOT_SPOT (hx, hy); + SetFrameBounds (FramePtr, tfbimg->extent.width, tfbimg->extent.height); + +#ifdef CLIPDEBUG + { + /* for debugging clipping: + draws white (or most matching color from palette) pixels to + every corner of the image + */ + Color color = {0xff, 0xff, 0xff, 0xff}; + RECT r = {{0, 0}, {1, 1}}; + if (tfbimg->extent.width > 2 && tfbimg->extent.height > 2) + { + TFB_DrawImage_Rect (&r, color, tfbimg); + r.corner.x = tfbimg->extent.width - 1; + TFB_DrawImage_Rect (&r, color, tfbimg); + r.corner.y = tfbimg->extent.height - 1; + TFB_DrawImage_Rect (&r, color, tfbimg); + r.corner.x = 0; + TFB_DrawImage_Rect (&r, color, tfbimg); + } + } +#endif +} + +static void +processFontChar (TFB_Char* CharPtr, TFB_Canvas canvas) +{ + BYTE* newdata; + size_t dpitch; + + TFB_DrawCanvas_GetExtent (canvas, &CharPtr->extent); + + // Currently, each font char has its own separate data + // but that can change to common mem area + dpitch = CharPtr->extent.width; + newdata = HMalloc (dpitch * CharPtr->extent.height * sizeof (BYTE)); + TFB_DrawCanvas_GetFontCharData (canvas, newdata, dpitch); + + CharPtr->data = newdata; + CharPtr->pitch = dpitch; + CharPtr->disp.width = CharPtr->extent.width + 1; + CharPtr->disp.height = CharPtr->extent.height + 1; + // XXX: why the +1? + // I brought it into this function from the only calling + // function, but I don't know why it was there in the first + // place. + // XXX: the +1 appears to be for character and line spacing + // text_blt just adds the frame width to move to the next char + + { + // This tunes the font positioning to be about what it should + // TODO: prolly needs a little tweaking still + + int tune_amount = 0; + + if (CharPtr->extent.height == 8) + tune_amount = -1; + else if (CharPtr->extent.height == 9) + tune_amount = -2; + else if (CharPtr->extent.height > 9) + tune_amount = -3; + + CharPtr->HotSpot = MAKE_HOT_SPOT (0, + CharPtr->extent.height + tune_amount); + } +} + +void * +_GetCelData (uio_Stream *fp, DWORD length) +{ + int cel_total, cel_index, n; + DWORD opos; + char CurrentLine[1024], filename[PATH_MAX]; + TFB_Canvas *img; + AniData *ani; + DRAWABLE Drawable; + uio_MountHandle *aniMount = 0; + uio_DirHandle *aniDir = 0; + uio_Stream *aniFile = 0; + + opos = uio_ftell (fp); + + { + char *s1, *s2; + char aniDirName[PATH_MAX]; + const char *aniFileName; + uint8 buf[4] = { 0, 0, 0, 0 }; + uint32 header; + + if (_cur_resfile_name == 0 + || (((s2 = 0), (s1 = strrchr (_cur_resfile_name, '/')) == 0) + && (s2 = strrchr (_cur_resfile_name, '\\')) == 0)) + { + n = 0; + } + else + { + if (s2 > s1) + s1 = s2; + n = s1 - _cur_resfile_name + 1; + } + + uio_fread(buf, 4, 1, fp); + header = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); + if (_cur_resfile_name && header == 0x04034b50) + { + // zipped ani file + if (n) + { + strncpy (aniDirName, _cur_resfile_name, n - 1); + aniDirName[n - 1] = 0; + aniFileName = _cur_resfile_name + n; + } + else + { + strcpy(aniDirName, "."); + aniFileName = _cur_resfile_name; + } + aniDir = uio_openDir (repository, aniDirName, 0); + aniMount = uio_mountDir (repository, aniDirName, uio_FSTYPE_ZIP, + aniDir, aniFileName, "/", autoMount, + uio_MOUNT_RDONLY | uio_MOUNT_TOP, + NULL); + aniFile = uio_fopen (aniDir, aniFileName, "r"); + opos = 0; + n = 0; + } + else + { + // unpacked ani file + strncpy (filename, _cur_resfile_name, n); + aniFile = fp; + aniDir = contentDir; + } + } + + cel_total = 0; + uio_fseek (aniFile, opos, SEEK_SET); + while (uio_fgets (CurrentLine, sizeof (CurrentLine), aniFile)) + { + ++cel_total; + } + + img = HMalloc (sizeof (TFB_Canvas) * cel_total); + ani = HMalloc (sizeof (AniData) * cel_total); + if (!img || !ani) + { + log_add (log_Warning, "Couldn't allocate space for '%s'", _cur_resfile_name); + if (aniMount) + { + uio_fclose(aniFile); + uio_closeDir(aniDir); + uio_unmountDir(aniMount); + } + HFree (img); + HFree (ani); + return NULL; + } + + cel_index = 0; + uio_fseek (aniFile, opos, SEEK_SET); + while (uio_fgets (CurrentLine, sizeof (CurrentLine), aniFile) && cel_index < cel_total) + { + sscanf (CurrentLine, "%s %d %d %d %d", &filename[n], + &ani[cel_index].transparent_color, &ani[cel_index].colormap_index, + &ani[cel_index].hotspot_x, &ani[cel_index].hotspot_y); + + img[cel_index] = TFB_DrawCanvas_LoadFromFile (aniDir, filename); + if (img[cel_index] == NULL) + { + const char *err; + + err = TFB_DrawCanvas_GetError (); + log_add (log_Warning, "_GetCelData: Unable to load image!"); + if (err != NULL) + log_add (log_Warning, "Gfx Driver reports: %s", err); + } + else + { + ++cel_index; + } + + if ((int)uio_ftell (aniFile) - (int)opos >= (int)length) + break; + } + + Drawable = NULL; + if (cel_index && (Drawable = AllocDrawable (cel_index))) + { + if (!Drawable) + { + while (cel_index--) + TFB_DrawCanvas_Delete (img[cel_index]); + + HFree (Drawable); + Drawable = NULL; + } + else + { + FRAME FramePtr; + + Drawable->Flags = WANT_PIXMAP; + Drawable->MaxIndex = cel_index - 1; + + FramePtr = &Drawable->Frame[cel_index]; + while (--FramePtr, cel_index--) + process_image (FramePtr, img, ani, cel_index); + } + } + + if (Drawable == NULL) + log_add (log_Warning, "Couldn't get cel data for '%s'", + _cur_resfile_name); + + if (aniMount) + { + uio_fclose(aniFile); + uio_closeDir(aniDir); + uio_unmountDir(aniMount); + } + + HFree (img); + HFree (ani); + return Drawable; +} + +BOOLEAN +_ReleaseCelData (void *handle) +{ + DRAWABLE DrawablePtr; + int cel_ct; + FRAME FramePtr = NULL; + + if ((DrawablePtr = handle) == 0) + return (FALSE); + + cel_ct = DrawablePtr->MaxIndex + 1; + FramePtr = DrawablePtr->Frame; + + HFree (handle); + if (FramePtr) + { + int i; + for (i = 0; i < cel_ct; i++) + { + TFB_Image *img = FramePtr[i].image; + if (img) + { + FramePtr[i].image = NULL; + TFB_DrawScreen_DeleteImage (img); + } + } + HFree (FramePtr); + } + + return (TRUE); +} + +typedef struct BuildCharDesc +{ + TFB_Canvas canvas; + UniChar index; +} BuildCharDesc; + +static int +compareBCDIndex (const void *arg1, const void *arg2) +{ + const BuildCharDesc *bcd1 = (const BuildCharDesc *) arg1; + const BuildCharDesc *bcd2 = (const BuildCharDesc *) arg2; + + return (int) bcd1->index - (int) bcd2->index; +} + +void * +_GetFontData (uio_Stream *fp, DWORD length) +{ + COUNT numDirEntries; + DIRENTRY fontDir = NULL; + BuildCharDesc *bcds = NULL; + size_t numBCDs = 0; + int dirEntryI; + uio_DirHandle *fontDirHandle = NULL; + uio_MountHandle *fontMount = NULL; + FONT fontPtr = NULL; + + if (_cur_resfile_name == 0) + goto err; + + if (fp != (uio_Stream*)~0) + { + // font is zipped instead of being in a directory + + char *s1, *s2; + int n; + const char *fontZipName; + char fontDirName[PATH_MAX]; + + if ((((s2 = 0), (s1 = strrchr (_cur_resfile_name, '/')) == 0) + && (s2 = strrchr (_cur_resfile_name, '\\')) == 0)) + { + strcpy(fontDirName, "."); + fontZipName = _cur_resfile_name; + } + else + { + if (s2 > s1) + s1 = s2; + n = s1 - _cur_resfile_name + 1; + strncpy (fontDirName, _cur_resfile_name, n - 1); + fontDirName[n - 1] = 0; + fontZipName = _cur_resfile_name + n; + } + + fontDirHandle = uio_openDir (repository, fontDirName, 0); + fontMount = uio_mountDir (repository, _cur_resfile_name, uio_FSTYPE_ZIP, + fontDirHandle, fontZipName, "/", autoMount, + uio_MOUNT_RDONLY | uio_MOUNT_TOP, + NULL); + uio_closeDir (fontDirHandle); + } + + fontDir = CaptureDirEntryTable (LoadDirEntryTable (contentDir, + _cur_resfile_name, ".", match_MATCH_SUBSTRING)); + if (fontDir == 0) + goto err; + numDirEntries = GetDirEntryTableCount (fontDir); + + fontDirHandle = uio_openDirRelative (contentDir, _cur_resfile_name, 0); + if (fontDirHandle == NULL) + goto err; + + bcds = HMalloc (numDirEntries * sizeof (BuildCharDesc)); + if (bcds == NULL) + goto err; + + // Load the surfaces for all dir Entries + for (dirEntryI = 0; dirEntryI < numDirEntries; dirEntryI++) + { + char *char_name; + unsigned int charIndex; + TFB_Canvas canvas; + EXTENT size; + + char_name = GetDirEntryAddress (SetAbsDirEntryTableIndex ( + fontDir, dirEntryI)); + if (sscanf (char_name, "%x.", &charIndex) != 1) + continue; + + if (charIndex > 0xffff) + continue; + + canvas = TFB_DrawCanvas_LoadFromFile (fontDirHandle, char_name); + if (canvas == NULL) + continue; + + TFB_DrawCanvas_GetExtent (canvas, &size); + if (size.width == 0 || size.height == 0) + { + TFB_DrawCanvas_Delete (canvas); + continue; + } + + bcds[numBCDs].canvas = canvas; + bcds[numBCDs].index = charIndex; + numBCDs++; + } + uio_closeDir (fontDirHandle); + DestroyDirEntryTable (ReleaseDirEntryTable (fontDir)); + if (fontMount != 0) + uio_unmountDir(fontMount); + +#if 0 + if (numBCDs == 0) + goto err; +#endif + + // sort on the character index + qsort (bcds, numBCDs, sizeof (BuildCharDesc), compareBCDIndex); + + fontPtr = AllocFont (0); + if (fontPtr == NULL) + goto err; + + fontPtr->Leading = 0; + fontPtr->LeadingWidth = 0; + + { + size_t startBCD = 0; + UniChar pageStart; + FONT_PAGE **pageEndPtr = &fontPtr->fontPages; + while (startBCD < numBCDs) + { + // Process one character page. + size_t endBCD; + pageStart = bcds[startBCD].index & CHARACTER_PAGE_MASK; + + endBCD = startBCD; + while (endBCD < numBCDs && + (bcds[endBCD].index & CHARACTER_PAGE_MASK) == pageStart) + endBCD++; + + { + size_t bcdI; + int numChars = bcds[endBCD - 1].index + 1 + - bcds[startBCD].index; + FONT_PAGE *page = AllocFontPage (numChars); + page->pageStart = pageStart; + page->firstChar = bcds[startBCD].index; + page->numChars = numChars; + *pageEndPtr = page; + pageEndPtr = &page->next; + + for (bcdI = startBCD; bcdI < endBCD; bcdI++) + { + // Process one character. + BuildCharDesc *bcd = &bcds[bcdI]; + TFB_Char *destChar = + &page->charDesc[bcd->index - page->firstChar]; + + if (destChar->data != NULL) + { + // There's already an image for this character. + log_add (log_Debug, "Duplicate image for character %d " + "for font %s.", (int) bcd->index, + _cur_resfile_name); + TFB_DrawCanvas_Delete (bcd->canvas); + continue; + } + + processFontChar (destChar, bcd->canvas); + TFB_DrawCanvas_Delete (bcd->canvas); + + if (destChar->disp.height > fontPtr->Leading) + fontPtr->Leading = destChar->disp.height; + if (destChar->disp.width > fontPtr->LeadingWidth) + fontPtr->LeadingWidth = destChar->disp.width; + } + } + + startBCD = endBCD; + } + *pageEndPtr = NULL; + } + + fontPtr->Leading++; + + HFree (bcds); + + (void) fp; /* Satisfying compiler (unused parameter) */ + (void) length; /* Satisfying compiler (unused parameter) */ + return fontPtr; + +err: + if (fontPtr != 0) + HFree (fontPtr); + + if (bcds != NULL) + { + size_t bcdI; + for (bcdI = 0; bcdI < numBCDs; bcdI++) + TFB_DrawCanvas_Delete (bcds[bcdI].canvas); + HFree (bcds); + } + + if (fontDirHandle != NULL) + uio_closeDir (fontDirHandle); + + if (fontDir != 0) + DestroyDirEntryTable (ReleaseDirEntryTable (fontDir)); + + if (fontMount != 0) + uio_unmountDir(fontMount); + + return 0; +} + +BOOLEAN +_ReleaseFontData (void *handle) +{ + FONT font = (FONT) handle; + if (font == NULL) + return FALSE; + + { + FONT_PAGE *page; + FONT_PAGE *nextPage; + + for (page = font->fontPages; page != NULL; page = nextPage) + { + size_t charI; + for (charI = 0; charI < page->numChars; charI++) + { + TFB_Char *c = &page->charDesc[charI]; + + if (c->data == NULL) + continue; + + // XXX: fix this if fonts get per-page data + // rather than per-char + TFB_DrawScreen_DeleteData (c->data); + } + + nextPage = page->next; + FreeFontPage (page); + } + } + + HFree (font); + + return TRUE; +} -- cgit v1.2.3