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
This commit is contained in:
avolkov
2009-12-25 04:18:45 +00:00
parent 09c52874a4
commit 98b3cc75c5
6 changed files with 702 additions and 619 deletions
+1 -1
View File
@@ -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"
+603
View File
@@ -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 <string.h>
#include <stdio.h>
#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;
}
+2 -615
View File
@@ -18,172 +18,13 @@
#ifdef GFXMODULE_SDL
#ifdef WIN32
#include <io.h>
#endif
#include <fcntl.h>
#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
+87 -3
View File
@@ -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;
}
+5
View File
@@ -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