Unicode support for fonts.

git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@1546 8092fc87-c524-0410-9efc-e669fe64eaf9
This commit is contained in:
meep-eep
2005-02-19 01:11:37 +00:00
parent e7eabd46b9
commit 285208a1c4
3 changed files with 257 additions and 129 deletions
+16 -3
View File
@@ -324,8 +324,21 @@ _text_blt (PRECT pClipRect, PRIMITIVEPTR PrimPtr)
static inline FRAME_DESC * static inline FRAME_DESC *
getCharFrame (FONT_DESC *fontPtr, wchar_t ch) { getCharFrame (FONT_DESC *fontPtr, wchar_t ch) {
if (ch > MAX_CHARS) wchar_t pageStart = ch & 0xff00;
return NULL;
return &fontPtr->CharDesc[ch - FIRST_CHAR]; FONT_PAGE *page = fontPtr->fontPages;
for (;;)
{
if (page == NULL)
return NULL;
if (page->pageStart == pageStart)
break;
page = page->next;
}
return &page->charDesc[ch - page->firstChar];
} }
+26 -6
View File
@@ -19,19 +19,39 @@
#ifndef _FONT_H #ifndef _FONT_H
#define _FONT_H #define _FONT_H
#define FIRST_CHAR (UNICODE)' '
// keep MAX_CHARS under 256 for now
#define MAX_CHARS 255
// MAX_CHARS gets cast to UNICODE in a few places and is used in math
// UNICODE is defined to BYTE, all strings attached
#define MAX_DELTAS 100 #define MAX_DELTAS 100
typedef struct FontPage
{
struct FontPage *next;
wchar_t pageStart;
wchar_t firstChar;
size_t numChars;
FRAME_DESC *charDesc;
} FONT_PAGE;
typedef FONT_PAGE *PFONT_PAGE;
static inline FONT_PAGE *
AllocFontPage (int numChars)
{
FONT_PAGE *result = HMalloc (sizeof (FONT_PAGE));
result->charDesc = HCalloc (numChars * sizeof *result->charDesc);
return result;
}
static inline void
FreeFontPage (FONT_PAGE *page)
{
HFree (page->charDesc);
HFree (page);
}
typedef struct typedef struct
{ {
FONT_REF FontRef; FONT_REF FontRef;
BYTE Leading; BYTE Leading;
FRAME_DESC CharDesc[MAX_CHARS]; FONT_PAGE *fontPages;
} FONT_DESC; } FONT_DESC;
typedef FONT_DESC *PFONT_DESC; typedef FONT_DESC *PFONT_DESC;
+210 -115
View File
@@ -29,6 +29,7 @@
#include "sdluio.h" #include "sdluio.h"
#include "libs/file.h" #include "libs/file.h"
#include "libs/reslib.h" #include "libs/reslib.h"
#include "../font.h"
#include "primitives.h" #include "primitives.h"
@@ -105,9 +106,8 @@ process_image (FRAMEPTR FramePtr, SDL_Surface *img[], AniData *ani, int cel_ct)
} }
static void static void
process_font (FRAMEPTR FramePtr, SDL_Surface *img[], int cel_ct) processFontChar (FRAMEPTR FramePtr, SDL_Surface *surf, int charInd)
{ {
int hx, hy;
int x,y; int x,y;
Uint8 r,g,b,a; Uint8 r,g,b,a;
Uint32 p; Uint32 p;
@@ -117,26 +117,25 @@ process_font (FRAMEPTR FramePtr, SDL_Surface *img[], int cel_ct)
PutPixelFn putpix; PutPixelFn putpix;
TYPE_SET (FramePtr->TypeIndexAndFlags, WANT_PIXMAP << FTYPE_SHIFT); TYPE_SET (FramePtr->TypeIndexAndFlags, WANT_PIXMAP << FTYPE_SHIFT);
INDEX_SET (FramePtr->TypeIndexAndFlags, cel_ct); INDEX_SET (FramePtr->TypeIndexAndFlags, charInd);
// XXX: Is this still relevant?
hx = hy = 0; SDL_LockSurface (surf);
SDL_LockSurface (img[cel_ct]);
// convert 32-bit png font to indexed // convert 32-bit png font to indexed
new_surf = SDL_CreateRGBSurface (SDL_SWSURFACE, img[cel_ct]->w, img[cel_ct]->h, new_surf = SDL_CreateRGBSurface (SDL_SWSURFACE, surf->w, surf->h,
8, 0, 0, 0, 0); 8, 0, 0, 0, 0);
getpix = getpixel_for (img[cel_ct]); getpix = getpixel_for (surf);
putpix = putpixel_for (new_surf); putpix = putpixel_for (new_surf);
for (y = 0; y < img[cel_ct]->h; ++y) for (y = 0; y < surf->h; ++y)
{ {
for (x = 0; x < img[cel_ct]->w; ++x) for (x = 0; x < surf->w; ++x)
{ {
p = getpix (img[cel_ct], x, y); p = getpix (surf, x, y);
SDL_GetRGBA (p, img[cel_ct]->format, &r, &g, &b, &a); SDL_GetRGBA (p, surf->format, &r, &g, &b, &a);
if (r == 0 && g == 0 && b == 0) if (r == 0 && g == 0 && b == 0)
putpix (new_surf, x, y, 0); putpix (new_surf, x, y, 0);
@@ -145,7 +144,9 @@ process_font (FRAMEPTR FramePtr, SDL_Surface *img[], int cel_ct)
} }
} }
colors[0].r = colors[0].g = colors[0].b = 0; colors[0].r = 0;
colors[0].g = 0;
colors[0].b = 0;
for (x = 1; x < 256; ++x) for (x = 1; x < 256; ++x)
{ {
colors[x].r = 255; colors[x].r = 255;
@@ -156,20 +157,38 @@ process_font (FRAMEPTR FramePtr, SDL_Surface *img[], int cel_ct)
SDL_SetColors (new_surf, colors, 0, 256); SDL_SetColors (new_surf, colors, 0, 256);
SDL_SetColorKey (new_surf, SDL_SRCCOLORKEY, 0); SDL_SetColorKey (new_surf, SDL_SRCCOLORKEY, 0);
SDL_UnlockSurface (img[cel_ct]); SDL_UnlockSurface (surf);
SDL_FreeSurface (img[cel_ct]); SDL_FreeSurface (surf);
img[cel_ct] = new_surf; FramePtr->image = TFB_DrawImage_New (new_surf);
surf = FramePtr->image->NormalImg;
FramePtr->image = TFB_DrawImage_New (img[cel_ct]); SetFrameBounds (FramePtr, surf->w + 1, surf->h + 1);
img[cel_ct] = FramePtr->image->NormalImg; // 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.
FramePtr->HotSpot = MAKE_HOT_SPOT (hx, hy); {
SetFrameBounds (FramePtr, img[cel_ct]->w, img[cel_ct]->h); // This tunes the font positioning to be about what it should
// TODO: prolly needs a little tweaking still
int tune_amount = 0;
if (surf->h == 8)
tune_amount = -1;
else if (surf->h == 9)
tune_amount = -2;
else if (surf->h > 9)
tune_amount = -3;
FramePtr->HotSpot = MAKE_HOT_SPOT (0, surf->h + tune_amount);
}
} }
//stretch_frame // stretch_frame
// create a new frame of size neww x newh, and blit a scaled version FramePtr into it // create a new frame of size neww x newh, and blit a scaled version FramePtr
// into it.
// destroy the old frame if 'destroy' is 1 // destroy the old frame if 'destroy' is 1
FRAMEPTR stretch_frame (FRAMEPTR FramePtr, int neww, int newh, int destroy) FRAMEPTR stretch_frame (FRAMEPTR FramePtr, int neww, int newh, int destroy)
{ {
@@ -181,8 +200,7 @@ FRAMEPTR stretch_frame (FRAMEPTR FramePtr, int neww, int newh, int destroy)
type = (UBYTE)TYPE_GET (GetFrameParentDrawable (FramePtr) type = (UBYTE)TYPE_GET (GetFrameParentDrawable (FramePtr)
->FlagsAndIndex) >> FTYPE_SHIFT; ->FlagsAndIndex) >> FTYPE_SHIFT;
NewFrame = CaptureDrawable ( NewFrame = CaptureDrawable (
CreateDrawable (type, (SIZE)neww, (SIZE)newh, 1) CreateDrawable (type, (SIZE)neww, (SIZE)newh, 1));
);
tfbImg = FramePtr->image; tfbImg = FramePtr->image;
LockMutex (tfbImg->mutex); LockMutex (tfbImg->mutex);
src = tfbImg->NormalImg; src = tfbImg->NormalImg;
@@ -222,7 +240,8 @@ void process_rgb_bmp (FRAMEPTR FramePtr, Uint32 *rgba, int maxx, int maxy)
UnlockMutex (tfbImg->mutex); UnlockMutex (tfbImg->mutex);
} }
void fill_frame_rgb (FRAMEPTR FramePtr, Uint32 color, int x0, int y0, int x, int y) void fill_frame_rgb (FRAMEPTR FramePtr, Uint32 color, int x0, int y0,
int x, int y)
{ {
SDL_Surface *img; SDL_Surface *img;
TFB_Image *tfbImg; TFB_Image *tfbImg;
@@ -570,143 +589,219 @@ _ReleaseCelData (MEM_HANDLE handle)
return (TRUE); return (TRUE);
} }
typedef struct BuildCharDesc {
SDL_Surface *surface;
wchar_t index;
} BuildCharDesc;
int
compareBCDIndex(const BuildCharDesc *bcd1, const BuildCharDesc *bcd2) {
return (int) bcd1->index - (int) bcd2->index;
}
MEM_HANDLE MEM_HANDLE
_GetFontData (uio_Stream *fp, DWORD length) _GetFontData (uio_Stream *fp, DWORD length)
{ {
DWORD cel_ct; COUNT numDirEntries;
COUNT num_entries; FONT_REF fontRef = 0;
FONT_REF FontRef; DIRENTRY fontDir = 0;
DIRENTRY FontDir; BuildCharDesc *bcds = NULL;
BOOLEAN found_chars; size_t numBCDs = 0;
#define MAX_CELS 256 int dirEntryI;
SDL_Surface *img[MAX_CELS] = { 0 }; uio_DirHandle *fontDirHandle = NULL;
char pattern[PATH_MAX]; FONTPTR fontPtr;
if (_cur_resfile_name == 0) if (_cur_resfile_name == 0)
return (0); goto err;
found_chars = FALSE; fontDir = CaptureDirEntryTable (LoadDirEntryTable (contentDir,
FontDir = CaptureDirEntryTable (LoadDirEntryTable (contentDir, _cur_resfile_name, ".", match_MATCH_SUBSTRING, &numDirEntries));
_cur_resfile_name, ".", match_MATCH_SUBSTRING, if (fontDir == 0)
&num_entries)); goto err;
while (num_entries--)
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; char *char_name;
unsigned int charIndex;
SDL_Surface *surface;
char_name = GetDirEntryAddress (SetAbsDirEntryTableIndex (FontDir, num_entries)); char_name = GetDirEntryAddress (SetAbsDirEntryTableIndex (
if (sscanf (char_name, "%u.", (unsigned int*) &cel_ct) == 1 fontDir, dirEntryI));
&& cel_ct >= FIRST_CHAR if (sscanf (char_name, "%u.", &charIndex) != 1)
&& img[cel_ct -= FIRST_CHAR] == 0 continue;
&& sprintf (pattern, "%s/%s", _cur_resfile_name, char_name)
&& (img[cel_ct] = sdluio_loadImage (contentDir, pattern))) if (charIndex > 0xffff)
{ continue;
if (img[cel_ct]->w > 0
&& img[cel_ct]->h > 0 surface = sdluio_loadImage (fontDirHandle, char_name);
&& img[cel_ct]->format->BitsPerPixel >= 8) if (surface == NULL)
found_chars = TRUE; continue;
else
{ if (surface->w == 0 || surface->h == 0 ||
SDL_FreeSurface (img[cel_ct]); surface->format->BitsPerPixel < 8) {
img[cel_ct] = 0; SDL_FreeSurface (surface);
} continue;
} }
bcds[numBCDs].surface = surface;
bcds[numBCDs].index = charIndex;
numBCDs++;
} }
DestroyDirEntryTable (ReleaseDirEntryTable (FontDir)); uio_closeDir (fontDirHandle);
DestroyDirEntryTable (ReleaseDirEntryTable (fontDir));
#if 0
if (numBCDs == 0)
goto err;
#endif
// sort on the character index
qsort (bcds, numBCDs, sizeof (BuildCharDesc),
(int (*)(const void *, const void *)) compareBCDIndex);
fontRef = AllocFont (0);
if (fontRef == 0)
goto err;
fontPtr = LockFont (fontRef);
if (fontPtr == NULL)
goto err;
fontPtr->FontRef = fontRef;
fontPtr->Leading = 0;
FontRef = 0;
if (found_chars && (FontRef = AllocFont (0)))
{ {
FONTPTR FontPtr; size_t startBCD = 0;
int pageStart;
cel_ct = MAX_CELS; // MAX_CHARS; FONT_PAGE **pageEndPtr = &fontPtr->fontPages;
if ((FontPtr = LockFont (FontRef)) == 0) while (startBCD < numBCDs)
{ {
while (cel_ct--) // Process one character page.
{ size_t endBCD;
if (img[cel_ct]) pageStart = bcds[startBCD].index & 0xff00;
SDL_FreeSurface (img[cel_ct]);
}
mem_release (FontRef); endBCD = startBCD;
FontRef = 0; while (endBCD < numBCDs &&
} (bcds[endBCD].index & 0xff00) == pageStart)
else endBCD++;
{
FRAMEPTR FramePtr;
FontPtr->FontRef = FontRef;
FontPtr->Leading = 0;
FramePtr = &FontPtr->CharDesc[cel_ct];
while (--FramePtr, cel_ct--)
{ {
if (img[cel_ct]) 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_font (FramePtr, img, cel_ct); // Process one character.
SetFrameBounds (FramePtr, GetFrameWidth (FramePtr) + 1, GetFrameHeight (FramePtr) + 1); BuildCharDesc *bcd = &bcds[bcdI];
FRAME_DESC *destFrame =
&page->charDesc[bcd->index - page->firstChar];
if (img[0]) if (destFrame->image != NULL)
{ {
// This tunes the font positioning to be about what it should // There's already an image for this character.
// TODO: prolly needs a little tweaking still #ifdef DEBUG
fprintf (stderr, "Duplicate image for characted %d "
int tune_amount = 0; "for font %s.\n", (int) bcd->index,
_cur_resfile_name);
if (img[0]->h == 8) #endif
tune_amount = -1; SDL_FreeSurface (bcd->surface);
else if (img[0]->h == 9) continue;
tune_amount = -2;
else if (img[0]->h > 9)
tune_amount = -3;
FramePtr->HotSpot = MAKE_HOT_SPOT (0, img[0]->h + tune_amount);
} }
if (GetFrameHeight (FramePtr) > FontPtr->Leading) processFontChar (destFrame, bcd->surface,
FontPtr->Leading = GetFrameHeight (FramePtr); bcd->index - page->firstChar);
// bcd->surface is handed over to destFrame.
// Don't access it through bcd->surface any more.
// It may be freed from within ProcessFontChar().
if (GetFrameHeight (destFrame) > fontPtr->Leading)
fontPtr->Leading = GetFrameHeight (destFrame);
} }
} }
++FontPtr->Leading;
UnlockFont (FontRef); startBCD = endBCD;
} }
*pageEndPtr = NULL;
} }
fontPtr->Leading++;
UnlockFont (fontRef);
HFree (bcds);
(void) fp; /* Satisfying compiler (unused parameter) */ (void) fp; /* Satisfying compiler (unused parameter) */
(void) length; /* Satisfying compiler (unused parameter) */ (void) length; /* Satisfying compiler (unused parameter) */
return (FontRef); return fontRef;
err:
if (fontRef != 0)
mem_release (fontRef);
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));
return 0;
} }
BOOLEAN BOOLEAN
_ReleaseFontData (MEM_HANDLE handle) _ReleaseFontData (MEM_HANDLE handle)
{ {
FONTPTR FontPtr; FONTPTR font = LockFont (handle);
if (font == NULL)
if ((FontPtr = LockFont (handle)) == 0) return FALSE;
return (FALSE);
{ {
int cel_ct; FONT_PAGE *page;
FRAMEPTR FramePtr; FONT_PAGE *nextPage;
cel_ct = MAX_CHARS; for (page = font->fontPages; page != NULL; page = nextPage)
FramePtr = &FontPtr->CharDesc[cel_ct];
while (--FramePtr, cel_ct--)
{ {
TFB_Image *img = FramePtr->image; size_t charI;
if (img) for (charI = 0; charI < page->numChars; charI++)
{ {
FramePtr->image = NULL; FRAME_DESC *frame = &page->charDesc[charI];
TFB_DrawScreen_DeleteImage (img); if (frame->image == NULL)
continue;
TFB_DrawScreen_DeleteImage (frame->image);
} }
nextPage = page->next;
FreeFontPage (page);
} }
} }
UnlockFont (handle); UnlockFont (handle);
mem_release (handle); mem_release (handle);
return (TRUE); return TRUE;
} }
// _request_drawable was in libs/graphics/drawable.c before modularization // _request_drawable was in libs/graphics/drawable.c before modularization