From 98b3cc75c58c12164adb7655cb1db2ae0d0d7264 Mon Sep 17 00:00:00 2001 From: avolkov Date: Fri, 25 Dec 2009 04:18:45 +0000 Subject: [PATCH] Gfxlib cleanup: move ani and font loading functions out of SDL domain; SDL-specific bits split off into TFB_Canvas functions git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@3469 8092fc87-c524-0410-9efc-e669fe64eaf9 --- sc2/build/msvc6/UrQuanMasters.dsp | 4 + sc2/src/libs/graphics/Makeinfo | 2 +- sc2/src/libs/graphics/gfxload.c | 603 +++++++++++++++++++++++ sc2/src/libs/graphics/sdl/3do_getbody.c | 617 +----------------------- sc2/src/libs/graphics/sdl/canvas.c | 90 +++- sc2/src/libs/graphics/tfb_draw.h | 5 + 6 files changed, 702 insertions(+), 619 deletions(-) create mode 100644 sc2/src/libs/graphics/gfxload.c diff --git a/sc2/build/msvc6/UrQuanMasters.dsp b/sc2/build/msvc6/UrQuanMasters.dsp index 83677d690..21180cee0 100644 --- a/sc2/build/msvc6/UrQuanMasters.dsp +++ b/sc2/build/msvc6/UrQuanMasters.dsp @@ -471,6 +471,10 @@ SOURCE=..\..\src\libs\graphics\gfxintrn.h # End Source File # Begin Source File +SOURCE=..\..\src\libs\graphics\gfxload.c +# End Source File +# Begin Source File + SOURCE=..\..\src\libs\graphics\intersec.c # End Source File # Begin Source File diff --git a/sc2/src/libs/graphics/Makeinfo b/sc2/src/libs/graphics/Makeinfo index 6854e34ee..f654bb9c1 100644 --- a/sc2/src/libs/graphics/Makeinfo +++ b/sc2/src/libs/graphics/Makeinfo @@ -1,5 +1,5 @@ uqm_SUBDIRS="sdl" uqm_CFILES="boxint.c clipline.c cmap.c context.c drawable.c filegfx.c - bbox.c dcqueue.c + bbox.c dcqueue.c gfxload.c font.c frame.c gfx_common.c intersec.c loaddisp.c pixmap.c resgfx.c tfb_draw.c tfb_prim.c widgets.c" diff --git a/sc2/src/libs/graphics/gfxload.c b/sc2/src/libs/graphics/gfxload.c new file mode 100644 index 000000000..226f67952 --- /dev/null +++ b/sc2/src/libs/graphics/gfxload.c @@ -0,0 +1,603 @@ +//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; + + if (DrawablePtr->Frame) + { + FramePtr = DrawablePtr->Frame; + if (FramePtr->Type == SCREEN_DRAWABLE) + { + FramePtr = NULL; + } + } + + 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; + +int +compareBCDIndex (const BuildCharDesc *bcd1, const BuildCharDesc *bcd2) +{ + 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), + (int (*)(const void *, const void *)) 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; +} diff --git a/sc2/src/libs/graphics/sdl/3do_getbody.c b/sc2/src/libs/graphics/sdl/3do_getbody.c index 886188386..0a144f713 100644 --- a/sc2/src/libs/graphics/sdl/3do_getbody.c +++ b/sc2/src/libs/graphics/sdl/3do_getbody.c @@ -18,172 +18,13 @@ #ifdef GFXMODULE_SDL -#ifdef WIN32 -#include -#endif -#include - -#include "options.h" #include "port.h" +#include "libs/gfxlib.h" +#include "libs/graphics/tfb_draw.h" #include "sdl_common.h" -#include "sdluio.h" -#include "libs/file.h" -#include "libs/reslib.h" -#include "libs/log.h" -#include "libs/memlib.h" -#include "../font.h" #include "primitives.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, SDL_Surface *img[], AniData *ani, int cel_ct) -{ - TFB_Image *tfbimg; - int hx, hy; - - FramePtr->Type = ROM_DRAWABLE; - FramePtr->Index = cel_ct; - - // handle transparency cases - if (img[cel_ct]->format->palette) - { // indexed color image - if (ani[cel_ct].transparent_color >= 0) - SDL_SetColorKey (img[cel_ct], SDL_SRCCOLORKEY, - ani[cel_ct].transparent_color); - } - else if (img[cel_ct]->format->BitsPerPixel > 8) - { // special transparency cases for truecolor images - if (ani[cel_ct].transparent_color == 0) - // make RGB=0,0,0 transparent - SDL_SetColorKey (img[cel_ct], SDL_SRCCOLORKEY, - SDL_MapRGBA (img[cel_ct]->format, 0, 0, 0, 0)); - } - if (ani[cel_ct].transparent_color == -1) - { // enforce -1 to mean 'no transparency' - SDL_SetColorKey (img[cel_ct], 0, 0); - // 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] = (SDL_Surface *)tfbimg->NormalImg; - - FramePtr->HotSpot = MAKE_HOT_SPOT (hx, hy); - SetFrameBounds (FramePtr, img[cel_ct]->w, img[cel_ct]->h); - -#ifdef CLIPDEBUG - { - /* for debugging clipping: - draws white (or most matching color from palette) pixels to - every corner of the image - */ - Uint32 color = SDL_MapRGB (img[cel_ct]->format, 255, 255, 255); - SDL_Rect r = {0, 0, 1, 1}; - if (img[cel_ct]->w > 2 && img[cel_ct]->h > 2) - { - SDL_FillRect (img[cel_ct], &r, color); - r.x = img[cel_ct]->w - 1; - SDL_FillRect (img[cel_ct], &r, color); - r.y = img[cel_ct]->h - 1; - SDL_FillRect (img[cel_ct], &r, color); - r.x = 0; - SDL_FillRect (img[cel_ct], &r, color); - } - } -#endif -} - -static void -processFontChar (TFB_Char* CharPtr, SDL_Surface *surf) -{ - int x,y; - Uint8 r,g,b,a; - Uint32 p; - SDL_PixelFormat* srcfmt = surf->format; - GetPixelFn getpix; - BYTE* newdata; - Uint32 dpitch; - - // Currently, each font char has its own separate data - // but that can change to common mem area - newdata = HMalloc (surf->w * surf->h * sizeof(BYTE)); - dpitch = surf->w; - - SDL_LockSurface (surf); - - getpix = getpixel_for (surf); - - // produce an alpha-only image in internal BYTE[] format - // from the SDL surface - for (y = 0; y < surf->h; ++y) - { - BYTE* dst = newdata + dpitch * y; - - for (x = 0; x < surf->w; ++x, ++dst) - { - p = getpix (surf, x, y); - SDL_GetRGBA (p, srcfmt, &r, &g, &b, &a); - - if (!srcfmt->Amask) - { // produce alpha from intensity (Y component) - // using a fast approximation - // contributions to Y are: R=2, G=4, B=1 - a = (((int)r << 1) + ((int)g << 2) + b) / 7; - } - - *dst = a; - } - } - - SDL_UnlockSurface (surf); - - CharPtr->data = newdata; - CharPtr->pitch = dpitch; - CharPtr->extent.width = surf->w; - CharPtr->extent.height = surf->h; - CharPtr->disp.width = surf->w + 1; - CharPtr->disp.height = surf->h + 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); - } -} - // stretch_frame // create a new frame of size neww x newh, and blit a scaled version FramePtr // into it. @@ -373,458 +214,4 @@ Uint32 frame_mapRGBA (FRAME FramePtr,Uint8 r, Uint8 g, Uint8 b, Uint8 a) return (SDL_MapRGBA (img->format, r, g, b, a)); } -void * -_GetCelData (uio_Stream *fp, DWORD length) -{ - int cel_total, cel_index, n; - DWORD opos; - char CurrentLine[1024], filename[PATH_MAX]; - SDL_Surface **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 (SDL_Surface *) * 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] = sdluio_loadImage (aniDir, filename); - if (img[cel_index] == NULL) - { - const char *err; - - err = SDL_GetError(); - log_add (log_Warning, "_GetCelData: Unable to load image!"); - if (err != NULL) - log_add (log_Warning, "SDL reports: %s", err); - SDL_FreeSurface (img[cel_index]); - } - else if (img[cel_index]->w < 0 || img[cel_index]->h < 0 || - img[cel_index]->format->BitsPerPixel < 8) - { - log_add (log_Warning, "_GetCelData: Bad file!"); - SDL_FreeSurface (img[cel_index]); - } - 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--) - SDL_FreeSurface (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; - - if (DrawablePtr->Frame) - { - FramePtr = DrawablePtr->Frame; - if (FramePtr->Type == SCREEN_DRAWABLE) - { - FramePtr = NULL; - } - } - - 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 { - SDL_Surface *surface; - UniChar index; -} BuildCharDesc; - -int -compareBCDIndex(const BuildCharDesc *bcd1, const BuildCharDesc *bcd2) { - 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; - SDL_Surface *surface; - - char_name = GetDirEntryAddress (SetAbsDirEntryTableIndex ( - fontDir, dirEntryI)); - if (sscanf (char_name, "%x.", &charIndex) != 1) - continue; - - if (charIndex > 0xffff) - continue; - - surface = sdluio_loadImage (fontDirHandle, char_name); - if (surface == NULL) - continue; - - if (surface->w == 0 || surface->h == 0 || - surface->format->BitsPerPixel < 8) { - SDL_FreeSurface (surface); - continue; - } - - bcds[numBCDs].surface = surface; - 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), - (int (*)(const void *, const void *)) 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); - SDL_FreeSurface (bcd->surface); - continue; - } - - processFontChar (destChar, bcd->surface); - SDL_FreeSurface (bcd->surface); - - 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++) - SDL_FreeSurface (bcds[bcdI].surface); - 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; -} - #endif diff --git a/sc2/src/libs/graphics/sdl/canvas.c b/sc2/src/libs/graphics/sdl/canvas.c index f81407e1d..c5428a9e8 100644 --- a/sc2/src/libs/graphics/sdl/canvas.c +++ b/sc2/src/libs/graphics/sdl/canvas.c @@ -24,6 +24,7 @@ #include "libs/memlib.h" #include "primitives.h" #include "palette.h" +#include "sdluio.h" #include "rotozoom.h" #include "options.h" #include "types.h" @@ -43,6 +44,15 @@ TFB_DrawCanvas_Initialize (void) // need error correction here } +const char * +TFB_DrawCanvas_GetError (void) +{ + const char *err = SDL_GetError (); + // TODO: Should we call SDL_ClearError() here so that it is not + // returned again later? + return err; +} + void TFB_DrawCanvas_Line (int x1, int y1, int x2, int y2, Color color, TFB_Canvas target) @@ -590,6 +600,23 @@ TFB_DrawCanvas_New_RotationTarget (TFB_Canvas src_canvas, int angle) return newsurf; } +TFB_Canvas +TFB_DrawCanvas_LoadFromFile (void *dir, const char *fileName) +{ + SDL_Surface *surf = sdluio_loadImage (dir, fileName); + if (!surf) + return NULL; + + if (surf->format->BitsPerPixel < 8) + { + SDL_SetError ("unsupported image format (min 8bpp)"); + SDL_FreeSurface (surf); + surf = NULL; + } + + return surf; +} + void TFB_DrawCanvas_Delete (TFB_Canvas canvas) { @@ -603,7 +630,51 @@ TFB_DrawCanvas_Delete (TFB_Canvas canvas) { SDL_FreeSurface (canvas); } +} +BOOLEAN +TFB_DrawCanvas_GetFontCharData (TFB_Canvas canvas, BYTE *outData, + unsigned dataPitch) +{ + SDL_Surface *surf = canvas; + int x, y; + Uint8 r, g, b, a; + Uint32 p; + SDL_PixelFormat *fmt = surf->format; + GetPixelFn getpix; + + if (!surf || !outData) + return FALSE; + + SDL_LockSurface (surf); + + getpix = getpixel_for (surf); + + // produce an alpha-only image in internal BYTE[] format + // from the SDL surface + for (y = 0; y < surf->h; ++y) + { + BYTE *dst = outData + dataPitch * y; + + for (x = 0; x < surf->w; ++x, ++dst) + { + p = getpix (surf, x, y); + SDL_GetRGBA (p, fmt, &r, &g, &b, &a); + + if (!fmt->Amask) + { // produce alpha from intensity (Y component) + // using a fast approximation + // contributions to Y are: R=2, G=4, B=1 + a = ((r * 2) + (g * 4) + b) / 7; + } + + *dst = a; + } + } + + SDL_UnlockSurface (surf); + + return TRUE; } Color * @@ -1617,10 +1688,14 @@ TFB_DrawCanvas_GetPixel (TFB_Canvas canvas, int x, int y) return c; } + SDL_LockSurface (surf); + getpixel = getpixel_for(surf); pixel = (*getpixel)(surf, x, y); SDL_GetRGBA (pixel, surf->format, &c.r, &c.g, &c.b, &c.a); + SDL_UnlockSurface (surf); + return c; } @@ -1726,6 +1801,7 @@ BOOLEAN TFB_DrawCanvas_Intersect (TFB_Canvas canvas1, POINT c1org, TFB_Canvas canvas2, POINT c2org, const RECT *interRect) { + BOOLEAN ret = FALSE; SDL_Surface *surf1 = canvas1; SDL_Surface *surf2 = canvas2; int x, y; @@ -1733,6 +1809,9 @@ TFB_DrawCanvas_Intersect (TFB_Canvas canvas1, POINT c1org, Uint32 s1mask, s2mask; GetPixelFn getpixel1, getpixel2; + SDL_LockSurface (surf1); + SDL_LockSurface (surf2); + getpixel1 = getpixel_for (surf1); getpixel2 = getpixel_for (surf2); @@ -1774,10 +1853,15 @@ TFB_DrawCanvas_Intersect (TFB_Canvas canvas1, POINT c1org, Uint32 p2 = getpixel2 (surf2, x + c2org.x, y + c2org.y) & s2mask; if (p1 != s1key && p2 != s2key) - return TRUE; // pixel collision + { // pixel collision + ret = TRUE; + break; + } } } - // no pixel collision - return FALSE; + SDL_UnlockSurface (surf2); + SDL_UnlockSurface (surf1); + + return ret; } diff --git a/sc2/src/libs/graphics/tfb_draw.h b/sc2/src/libs/graphics/tfb_draw.h index 5921ff51d..1b0114511 100644 --- a/sc2/src/libs/graphics/tfb_draw.h +++ b/sc2/src/libs/graphics/tfb_draw.h @@ -118,6 +118,7 @@ void TFB_DrawImage_FilledImage (TFB_Image *img, int x, int y, int scale, void TFB_DrawImage_FontChar (TFB_Char *, TFB_Image *backing, int x, int y, TFB_Image *target); +TFB_Canvas TFB_DrawCanvas_LoadFromFile (void *dir, const char *fileName); TFB_Canvas TFB_DrawCanvas_New_TrueColor (int w, int h, BOOLEAN hasalpha); TFB_Canvas TFB_DrawCanvas_New_ForScreen (int w, int h, BOOLEAN withalpha); TFB_Canvas TFB_DrawCanvas_New_Paletted (int w, int h, Color palette[256], @@ -157,6 +158,8 @@ void TFB_DrawCanvas_FontChar (TFB_Char *, TFB_Image *backing, int x, int y, void TFB_DrawCanvas_CopyRect (TFB_Canvas source, const RECT *srcRect, TFB_Canvas target, POINT dstPt); +BOOLEAN TFB_DrawCanvas_GetFontCharData (TFB_Canvas canvas, BYTE *outData, + unsigned dataPitch); Color *TFB_DrawCanvas_ExtractPalette (TFB_Canvas canvas); void TFB_DrawCanvas_SetPalette (TFB_Canvas target, Color palette[256]); int TFB_DrawCanvas_GetTransparentIndex (TFB_Canvas canvas); @@ -177,6 +180,8 @@ Color TFB_DrawCanvas_GetPixel (TFB_Canvas canvas, int x, int y); BOOLEAN TFB_DrawCanvas_Intersect (TFB_Canvas canvas1, POINT c1org, TFB_Canvas canvas2, POINT c2org, const RECT *interRect); +const char *TFB_DrawCanvas_GetError (void); + TFB_Canvas TFB_GetScreenCanvas (SCREEN screen); #endif