Files
wagic/JGE/src/JGBKFont.cpp

648 lines
11 KiB
C++

//-------------------------------------------------------------------------------------
//
// JGE++ is a hardware accelerated 2D game SDK for PSP/Windows.
//
// Licensed under the BSD license, see LICENSE in JGE root for details.
//
// Copyright (c) 2007 James Hui (a.k.a. Dr.Watson) <jhkhui@gmail.com>
// Copyright (c) 2007 Sijiu Duan (a.k.a. Chi80) <sijiu49@gmail.com>
//
//-------------------------------------------------------------------------------------
#include <stdio.h>
#include "../include/JGBKFont.h"
#include "../include/JFileSystem.h"
JRenderer* JGBKFont::mRenderer = NULL;
JGBKFont::JGBKFont()
{
mRenderer = JRenderer::GetInstance();
mChnFont = NULL;
mEngFont = NULL;
mCurr = 0;
mColor = ARGB(255,255,255,255);
mBgColor = ARGB(0,0,0,0);
mScale = 1.0f;
mRotation = 0.0f;
mCount = 0;
mTexture = NULL;
mSprites = NULL;
mGBCode = NULL;
mCharBuffer = NULL;
}
JGBKFont::~JGBKFont()
{
SAFE_DELETE_ARRAY(mEngFont);
SAFE_DELETE_ARRAY(mChnFont);
SAFE_DELETE(mTexture);
if (mSprites)
{
for (int i=0;i<mCacheSize;i++)
{
if (mSprites[i])
delete mSprites[i];
}
delete [] mSprites;
}
if (mGBCode)
delete [] mGBCode;
if (mCharBuffer)
delete[] mCharBuffer;
}
bool JGBKFont::Init(const char* engFileName, const char* chnFileName, int fontsize, bool smallEnglishFont)
{
mSmallEnglishFont = smallEnglishFont;
mFontSize = fontsize;
mCacheImageWidth = 256;
mCacheImageHeight = 256;
mBytesPerRow = (mFontSize+7)/8;
mBytesPerChar = mBytesPerRow*mFontSize;
mCol = mCacheImageWidth/mFontSize;
mRow = mCacheImageHeight/mFontSize;
mCacheSize = mCol*mRow;
mSprites = new JQuad*[mCacheSize];
mGBCode = new int[mCacheSize];
#if defined (WIN32) || defined (LINUX)
mCharBuffer = new DWORD[mFontSize*mFontSize];
#endif
mTexture = mRenderer->CreateTexture(mCacheImageWidth, mCacheImageHeight, true);
int index = 0;
for (int y=0;y<mRow;y++)
{
for (int x=0;x<mCol;x++)
{
mGBCode[index] = -1;
mSprites[index] = new JQuad(mTexture, x*mFontSize, y*mFontSize, mFontSize, mFontSize);
mSprites[index]->SetHotSpot(mFontSize/2, mFontSize/2);
index++;
}
}
int size;
JFileSystem *fileSys = JFileSystem::GetInstance();
if (!fileSys->OpenFile(engFileName))
return false;
size = fileSys->GetFileSize();
mEngFont = new BYTE[size];
fileSys->ReadFile(mEngFont, size);
fileSys->CloseFile();
if (!fileSys->OpenFile(chnFileName))
return false;
size = fileSys->GetFileSize();
mChnFont = new BYTE[size];
fileSys->ReadFile(mChnFont, size);
fileSys->CloseFile();
return true;
}
#if defined (WIN32) || defined (LINUX)
#else
void SwizzlePlot(u8* out, PIXEL_TYPE color, int i, int j, unsigned int width)
{
unsigned int rowblocks = (width >> 4);
unsigned int blockx = (i >> 4);
unsigned int blocky = (j >> 3);
unsigned int x = (i - (blockx<<4));
unsigned int y = (j - (blocky<<3));
unsigned int block_index = blockx + ((blocky) * rowblocks);
unsigned int block_address = block_index << 7;
u8* p = out + (block_address + x + (y << 4));
PIXEL_TYPE* dest = (PIXEL_TYPE *)p;
*dest = color;
}
#endif
int JGBKFont::PreCacheChar(const BYTE *ch)
{
int code;
BOOL isChinese = true;
if (*ch > 0x80)
{
// get offset to the proper character bits (GBK encoding)
code = (((DWORD)(*ch - 0x81)) * 0xBF + ((DWORD)(*(ch + 1) - 0x40)));
}
else
{
code = ((DWORD)*ch)|0x10000;
isChinese = false;
}
if (mGBCode[mCurr] != -1)
{
for (int i=0;i<mCacheSize;i++)
{
if (mGBCode[i] == code)
return i;
}
}
mCount++;
int index = mCurr++;
if (mCurr >= mCacheSize)
mCurr = 0;
#if defined (WIN32) || defined (LINUX) || defined (IOS)
int x = 0;
int y = 0;
memset(mCharBuffer, 0, sizeof(DWORD)*mFontSize*mFontSize);
#else
u8* pTexture = (u8*) mTexture->mBits;
int x;
int y = (int)mSprites[index]->mY;
#endif
BYTE* src;
BYTE bits;
int bitCount;
if (isChinese)
{
src = mChnFont + code * mBytesPerChar;
for (int i=0;i<mBytesPerChar;)
{
bitCount = mFontSize;
#if defined (WIN32) || defined (LINUX)
x = 0;
#else
x = (int)mSprites[index]->mX;
#endif
for (int j=0;j<mBytesPerRow;j++)
{
bits = src[i++];
BYTE bitMask = 0x80;
for (int z=0;z<8&&bitCount;z++)
{
#if defined (WIN32) || defined (LINUX) || defined (IOS)
if ((bits & bitMask) != 0)
mCharBuffer[y*mFontSize+x] = ARGB(255,255,255,255);
else
mCharBuffer[y*mFontSize+x] = ARGB(0,0,0,0);
#else
if ((bits & bitMask) != 0)
SwizzlePlot(pTexture, ARGB(255,255,255,255), x*PIXEL_SIZE, y, mTexture->mTexWidth*PIXEL_SIZE);
else
SwizzlePlot(pTexture, ARGB(0,0,0,0), x*PIXEL_SIZE, y, mTexture->mTexWidth*PIXEL_SIZE);
#endif
bitMask >>= 1;
x++;
bitCount--;
}
}
y++;
}
}
else
{
int size = (mFontSize <= 16)?mFontSize:mFontSize*2;
src = mEngFont + (code-0x10000) * size;
int n;
for (int i=0;i<size;)
{
#if defined (WIN32) || defined (LINUX) || defined (IOS)
x = 0;
#else
x = (int)mSprites[index]->mX;
#endif
// width of the English fonts is only half of the Chinese ones
// put char in the middle
if (mFontSize <= 16)
{
for (n=0;n<(mFontSize-8)/2;n++)
{
#if defined (WIN32) || defined (LINUX) || defined (IOS)
mCharBuffer[y*mFontSize+x] = ARGB(0,0,0,0);
#else
SwizzlePlot(pTexture, ARGB(0,0,0,0), x*PIXEL_SIZE, y, mTexture->mTexWidth*PIXEL_SIZE);
#endif
x++;
}
}
int count = (mFontSize <= 16)?1:2;
bitCount = mFontSize;
for (int k=0;k<count;k++)
{
bits = src[i++];
BYTE bitMask = 0x80;
for (int z=0;z<8&&bitCount;z++)
{
#if defined (WIN32) || defined (LINUX) || defined (IOS)
if ((bits & bitMask) != 0)
mCharBuffer[y*mFontSize+x] = ARGB(255,255,255,255);
else
mCharBuffer[y*mFontSize+x] = ARGB(0,0,0,0);
#else
if ((bits & bitMask) != 0)
SwizzlePlot(pTexture, ARGB(255,255,255,255), x*PIXEL_SIZE, y, mTexture->mTexWidth*PIXEL_SIZE);
else
SwizzlePlot(pTexture, ARGB(0,0,0,0), x*PIXEL_SIZE, y, mTexture->mTexWidth*PIXEL_SIZE);
#endif
x++;
bitMask >>= 1;
bitCount--;
}
}
if (mFontSize <= 16)
{
for (n=0;n<(mFontSize-8)/2;n++)
{
#if defined (WIN32) || defined (LINUX) || defined (IOS)
mCharBuffer[y*mFontSize+x] = ARGB(0,0,0,0);
#else
SwizzlePlot(pTexture, ARGB(0,0,0,0), x*PIXEL_SIZE, y, mTexture->mTexWidth*PIXEL_SIZE);
#endif
x++;
}
}
y++;
}
}
mGBCode[index] = code;
#if defined (WIN32) || defined (LINUX) || defined (IOS)
x = (int)mSprites[index]->mX;
y = (int)mSprites[index]->mY;
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, mFontSize, mFontSize, GL_RGBA, GL_UNSIGNED_BYTE, mCharBuffer);
#else
sceKernelDcacheWritebackAll();
//sceKernelDcacheWritebackInvalidateAll();
#endif
return index;
}
int JGBKFont::PrepareString(BYTE* str, int* dest)
{
mRenderer->BindTexture(mTexture);
BYTE* src = str;
int count = 0;
while (*src != 0)
{
if (*src > 0x80)
{
dest[count++] = PreCacheChar(src);
src += 2;
}
else if (*src >= ' ')
{
dest[count++] = PreCacheChar(src);
src += 1;
}
else // control characters
{
dest[count++] = 0x80000 | *src;
src += 1;
}
}
return count;
}
void JGBKFont::RenderEncodedString(const int* text, int count, float x, float y)
{
int n = 0;
float xx = x;
float yy = y;
bool isChinese;
for (int i=0;i<count;i++)
{
if (text[n] == 0x8000a)
{
xx = x;
yy += (mFontSize*mScale);
}
else if (text[n] == 0x8000d)
{
}
else
{
isChinese = ((text[n] & 0x10000) == 0x10000);
mSprites[text[n]]->SetColor(mColor);
mRenderer->RenderQuad(mSprites[text[n]], xx, yy, mRotation, mScale, mScale);
if (mSmallEnglishFont && !isChinese)
xx += (mFontSize*mScale)/2;
else
xx += (mFontSize*mScale);
if (xx >= 480)
{
xx = x;
yy += (mFontSize*mScale);
}
}
n++;
}
}
int JGBKFont::GetStringWidth( BYTE* str )
{
int w=0;
int h=0;
GetStringArea(str, &w, &h);
return w;
}
int JGBKFont::GetStringHeight( BYTE* str )
{
int w=0;
int h=0;
GetStringArea(str, &w, &h);
return h;
}
void JGBKFont::GetStringArea( BYTE* str, int *w, int *h)
{
BYTE* src = str;
float len= 0;
float xx = 0;
float yy = mFontSize*mScale;
bool isChinese=true;
while (*src != 0)
{
if (yy + mFontSize < 0.0f) // don't render when outside viewport
{
if (*src < ' ') // control characters
{
if (*src == 0x0a) // NEWLINE
{
if(xx>len)
len=xx;
xx = 0;
yy += (mFontSize*mScale);
}
src += 1;
}
else
{
if (*src > 0x80)
{
src += 2;
}
else if (*src >= ' ')
{
src += 1;
}
xx += (mFontSize*mScale);
if (xx >= 480)
{
if(xx>len)
len=xx;
xx = 0;
yy += (mFontSize*mScale);
}
}
}
else if (yy > SCREEN_HEIGHT_F)
{
break;
}
else
{
if (*src < ' ') // control characters
{
if (*src == 0x0a) // NEWLINE
{
if(xx>len)
len=xx;
xx = 0;
yy += (mFontSize*mScale);
}
src += 1;
}
else
{
if (*src > 0x80)
{
//index = PreCacheChar(src);
src += 2;
if (isChinese==false)
xx+=5*(mFontSize*mScale)/16;
isChinese = true;
}
else if (*src >= ' ')
{
src += 1;
if(isChinese==true)
xx-=3*(mFontSize*mScale)/16;
isChinese = false;
}
if (mSmallEnglishFont && !isChinese)
xx += (mFontSize*mScale)/2;
else
xx += (mFontSize*mScale);
if (xx >= 480)
{
if(xx>len)
len=xx;
xx = 0;
yy += (mFontSize*mScale);
}
}
}
}
if (xx>len)
{
len=xx;
}
*w=(int)len;
*h=(int)yy;
}
void JGBKFont::RenderString(BYTE* str, float x, float y, int alignment)
{
int w=0;
int h=0;
switch(alignment)
{
case JGETEXT_RIGHT:
GetStringArea(str,&w,&h);
x-=w;
break;
case JGETEXT_CENTER:
GetStringArea(str,&w,&h);
x-=w/2;
break;
case JGETEXT_LEFT:
default:
break;
}
mRenderer->BindTexture(mTexture);
BYTE* src = str;
float xx = x;
float yy = y;
int index;
bool isChinese=true;
while (*src != 0)
{
if (yy + mFontSize < 0.0f) // don't render when outside viewport
{
if (*src < ' ') // control characters
{
if (*src == 0x0a) // NEWLINE
{
xx = x;
yy += (mFontSize*mScale);
}
src += 1;
}
else
{
if (*src > 0x80)
{
src += 2;
}
else if (*src >= ' ')
{
src += 1;
}
xx += (mFontSize*mScale);
if (xx >= 480)
{
xx = x;
yy += (mFontSize*mScale);
}
}
}
else if (yy > SCREEN_HEIGHT_F)
{
return;
}
else
{
if (*src < ' ') // control characters
{
if (*src == 0x0a) // NEWLINE
{
xx = x;
yy += (mFontSize*mScale);
}
src += 1;
}
else
{
if (*src > 0x80)
{
index = PreCacheChar(src);
src += 2;
if (isChinese==false)
xx+=5*(mFontSize*mScale)/16;
isChinese = true;
}
else if (*src >= ' ')
{
index = PreCacheChar(src);
src += 1;
if(isChinese==true)
xx-=3*(mFontSize*mScale)/16;
isChinese = false;
}
mSprites[index]->SetColor(mColor);
mRenderer->RenderQuad(mSprites[index], xx, yy, mRotation, mScale, mScale);
if (mSmallEnglishFont && !isChinese)
xx += (mFontSize*mScale)/2;
else
xx += (mFontSize*mScale);
if (xx >= 480)
{
xx = x;
yy += (mFontSize*mScale);
}
}
}
}
}
void JGBKFont::SetScale(float scale) { mScale = scale; }
void JGBKFont::SetRotation(float rot) { mRotation = rot; }
void JGBKFont::SetColor(PIXEL_TYPE color) { mColor = color; }
void JGBKFont::SetBgColor(PIXEL_TYPE color) { mBgColor = color; }