Files
wagic/projects/mtg/src/WFont.cpp
T
omegablast2002@yahoo.com 777098f763 fixed a bug where CHANGELING was not giving all creature subtypes. Changelings now set creature types in MTGCardInstance::initMTGCI
moved removed it from the setType function of cardprimitive.
Issue: 501
2010-10-31 16:55:05 +00:00

612 lines
16 KiB
C++

#include "PrecompiledHeader.h"
#include "WFont.h"
#include "WResourceManager.h"
#include "JFileSystem.h"
#define ISGBK(c) ((c) > 0x80 || (c) < 0x30 || (c) == '-' || (c) == '/')
static PIXEL_TYPE gencolor(int id, PIXEL_TYPE color)
{
unsigned int a, r, g, b, r0, g0, b0;
#if defined (WIN32) || defined (LINUX)
a = (color >> 24) & 0xFF;
r = (color >> 16) & 0xFF;
g = (color >> 8) & 0xFF;
b = (color >> 0) & 0xFF;
#else // PSP
# if defined (ABGR8888)
a = (color >> 24) & 0xFF;
b = (color >> 16) & 0xFF;
g = (color >> 8) & 0xFF;
r = (color >> 0) & 0xFF;
# elif defined (ABGR5551)
a = ((color >> 15) & 0x01) << 7;
b = ((color >> 10) & 0x1F) << 3;
g = ((color >> 5) & 0x1F) << 3;
r = ((color >> 0) & 0x1F) << 3;
# elif defined (ABGR4444)
a = ((color >> 12) & 0x0F) << 4;
b = ((color >> 8) & 0x0F) << 4;
g = ((color >> 4) & 0x0F) << 4;
r = ((color >> 0) & 0x0F) << 4;
# endif
#endif
r0 = g0 = b0 = 255;
switch (id) {
case Fonts::MAIN_FONT: // simon 245, 228, 156
r0 = 245; g0 = 228; b0 = 156;
break;
case Fonts::MENU_FONT: // f3 255, 252, 175
r0 = 255; g0 = 252; b0 = 175;
break;
case Fonts::MAGIC_FONT: // magic 219, 255, 151
r0 = 219; g0 = 255; b0 = 151;
break;
case Fonts::SMALLFACE_FONT: // smallface 255, 255, 255
r0 = 255; g0 = 255; b0 = 255;
break;
default:
;
}
r = r * r0 / 255;
g = g * g0 / 255;
b = b * b0 / 255;
return ARGB(a,r,g,b);
}
//
JRenderer * WFBFont::mRenderer = NULL;
WLBFont::WLBFont(int inFontID, const char *fontname, int lineheight, bool useVideoRAM)
: WFont(inFontID)
{
string path(fontname);
if (path.size() > 4 ) path = path.substr(0, path.size() - 4); //some stupid manipulation because of the way Font works in JGE
it = NEW JLBFont(path.c_str(), lineheight, useVideoRAM);
}
WFBFont::WFBFont(int inFontID, const char *fontname, int lineheight, bool useVideoRAM)
: WFont(inFontID)
{
mRenderer = JRenderer::GetInstance();
mCharBuffer = NULL;
mSprites = NULL;
mGBCode = NULL;
mCurr = 0;
char tmpFileName[32], engFileName[32];
strcpy(tmpFileName, fontname);
char * ep = strrchr(tmpFileName, '.');
*ep = '\0';
sprintf(engFileName, "%s.asc", tmpFileName);
JFileSystem *fileSys = JFileSystem::GetInstance();
int size = 0;
if (!fileSys->OpenFile(fontname))
return;
size = fileSys->GetFileSize();
mChnFont = NEW u8[size];
fileSys->ReadFile(mChnFont, size);
fileSys->CloseFile();
if (!fileSys->OpenFile(engFileName))
return;
size = fileSys->GetFileSize();
mEngFont = NEW u8[size];
fileSys->ReadFile(mEngFont, size);
fileSys->CloseFile();
mColor0 = ARGB(255, 255, 255, 255);
mColor = mColor0;
mFontSize = lineheight;
mScale = 1.0f;
// using 4-bit(half-byte) to store 1 pixel
mBytesPerRow = static_cast<unsigned int>(mFontSize / 2);
mBytesPerChar = static_cast<unsigned int>(mBytesPerRow*mFontSize);
mCacheImageWidth = 256;
mCacheImageHeight = 256;
mCol = mCacheImageWidth / mFontSize;
mRow = mCacheImageHeight / mFontSize;
mCacheSize = mCol * mRow;
mSprites = NEW JQuad*[mCacheSize];
mGBCode = NEW int[mCacheSize];
#if defined (WIN32) || defined (LINUX)
mCharBuffer = NEW u32[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,
static_cast<float>(x*mFontSize),
static_cast<float>(y*mFontSize),
static_cast<float>(mFontSize),
static_cast<float>(mFontSize));
mSprites[index]->SetHotSpot(static_cast<float>(mFontSize / 2), static_cast<float>(mFontSize / 2));
index++;
}
}
}
WFBFont::~WFBFont()
{
SAFE_DELETE(mEngFont);
SAFE_DELETE(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;
}
#if defined (WIN32) || defined (LINUX)
#else
static 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 WFBFont::PreCacheChar(const u8 *ch)
{
int code;
bool dualByteFont = true;
u8 * src;
unsigned int size, offset;
u8 gray;
#if 0
if (*ch > 0xA0 && *(ch + 1) > 0xA0)
// get offset to the proper character bits (GB2312 encoding)
code = (((u32)(*ch - 0xA1)) * 0x5E + ((u32)(*(ch + 1) - 0xA1)));
else if (*ch > 0x80) {
// get offset to the character space's bits (GBK encoding)
code = 0;
}
else {
code = ((u32)*ch)|0x10000;
dualByteFont = false;
}
#else
code = this->GetCode(ch, &dualByteFont);
#endif
if (mGBCode[mCurr] != -1) {
for (int i = 0; i < mCacheSize; i++) {
if (mGBCode[i] == code)
return i;
}
}
int index = mCurr++;
if (mCurr >= mCacheSize)
mCurr = 0;
#if defined (WIN32) || defined (LINUX)
int x = 0;
int y = 0;
memset(mCharBuffer, 0, sizeof(u32) * mFontSize * mFontSize);
#else
u8* pTexture = (u8*) mTexture->mBits;
int x;
int y = (int)mSprites[index]->mY;
#endif
if (dualByteFont) {
size = mFontSize;
src = mChnFont + code * mBytesPerChar;
offset = 0;
}
else {
size = mFontSize / 2;
src = mEngFont + (code - 0x10000) * (mFontSize * size / 2);
offset = 0;
}
// set up the font texture buffer
for (unsigned int i = 0; i < mFontSize; i++) {
#if defined (WIN32) || defined (LINUX)
x = 0;
#else
x = (int)mSprites[index]->mX;
#endif
unsigned int j = 0;
#if 1
for (; j < offset; j++) {
#if defined (WIN32) || defined (LINUX)
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++;
}
#endif
for (; j < offset + size; j++) {
// as 4-bit(half-byte) stores 1 pixel
// get out the proper data according to the even or odd quality of the counter
gray = src[(i * size + j - offset) / 2];
gray = ((j - offset) & 1) ? (gray & 0xF0) : ((gray & 0x0F) << 4);
if (gray) gray |= 0x0F;
#if defined (WIN32) || defined (LINUX)
mCharBuffer[y * mFontSize + x] = ARGB(gray, 255, 255, 255);
#else
SwizzlePlot(pTexture, ARGB(gray, 255, 255, 255), x * PIXEL_SIZE, y, mTexture->mTexWidth * PIXEL_SIZE);
#endif
x++;
}
for (; j < mFontSize; j++) {
#if defined (WIN32) || defined (LINUX)
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)
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();
#endif
return index;
}
void WFBFont::DrawString(const char *s, float x, float y, int align, float leftOffset, float width)
{
unsigned char c = *(unsigned short *)s & 0xFF;
if (ISGBK(c) || (s[1] == ':' && s[2] == ' ')) {}
else {
// tricky: the single byte font is always mFontID + kSingleByteFontOffset!
// See WResourceManager::InitFonts()
WFont * mFont = resources.GetWFont(mFontID + Fonts::kSingleByteFontOffset);
mFont->SetScale(GetScale());
mFont->SetColor(GetColor());
mFont->DrawString(s, x, y, align, leftOffset, width);
return;
}
u8 * str = (u8 *)s;
// (0, 0) refers to the center of the word, so fix it to the upper-left corner
x += (mFontSize * mScale) / 2;
y += (mFontSize * mScale) / 2;
switch (align) {
case JGETEXT_RIGHT:
x -= GetStringWidth(s);
break;
case JGETEXT_CENTER:
x -= GetStringWidth(s) / 2;
break;
case JGETEXT_LEFT:
default:
break;
}
mRenderer->BindTexture(mTexture);
u8 * src = str;
float xx = x;
float yy = y;
int index = 0;
bool dualByteFont=true;
while (*src != 0) {
if (yy > SCREEN_HEIGHT_F) // don't render or count outside the buttom of viewport
return;
else if (yy + mFontSize < 0.0f) { // don't render when outside the top of viewport, but counted
if (*src < 0x20) { // control characters
if (*src == 0x0a) { // NEWLINE
xx = x;
yy += (mFontSize*mScale);
}
src += 1;
}
else {
if (*src > 0x80) // Chinese (GBK) and Japanese (SJIS) characters
src += 2;
else
src += 1;
xx += (mFontSize*mScale);
if (xx >= 480) {
xx = x;
yy += (mFontSize*mScale);
}
}
}
else {
if (*src < 0x20) { // control characters
if (*src == 0x0a) { // NEWLINE
xx = x;
yy += (mFontSize * mScale);
}
src += 1;
}
else {
int mana = -1;
if (*src > 0x80) { // Chinese (GBK) and Japanese (SJIS) characters
mana = this->GetMana(src);
index = PreCacheChar(src);
src += 2;
dualByteFont = true;
}
else {
index = PreCacheChar(src);
src += 1;
dualByteFont = false;
}
// fix for leftoffset and witdth's setting
float xPos, yPos, charWidth, charHeight;
mSprites[index]->GetTextureRect(&xPos, &yPos, &charWidth, &charHeight);
float xPos0 = xPos;
float charWidth0 = charWidth;
float delta = (dualByteFont) ? (charWidth * mScale) : (charWidth * mScale / 2);
if (leftOffset) {
if (leftOffset < 0) {
xx -= leftOffset;
leftOffset = 0;
}
else if (leftOffset - delta > 0) {
leftOffset -= delta;
continue;
}
else {
xPos += leftOffset / mScale;
delta -= leftOffset;
leftOffset = 0;
charWidth = delta / mScale;
}
}
else if (width) {
if (xx > x + width)
return;
if (xx + delta > x + width) {
delta = x + width - xx;
charWidth = delta / mScale;
}
}
if (mana >= 0) {
int mana2 = -1;
if (*src == '/' && (mana2 = this->GetMana(src+1)) >= 0) { // hybrid mana cost
src += 3;
unsigned char t = (JGE::GetInstance()->GetTime() / 3) & 0xFF;
unsigned char v = t + 127;
float scale = 0.05f * cosf(2*M_PI*((float)t)/256.0f);
if (scale < 0) {
mRenderer->RenderQuad(manaIcons[mana], xx + 3 * sinf(2*M_PI*((float)t)/256.0f), yy + 3 * cosf(2*M_PI*((float)(t-35))/256.0f), 0, 0.5f * mScale, 0.5f * mScale);
mRenderer->RenderQuad(manaIcons[mana2], xx + 3 * sinf(2*M_PI*((float)v)/256.0f), yy + 3 * cosf(2*M_PI*((float)(v-35))/256.0f), 0, 0.5f * mScale, 0.5f * mScale);
}
else {
mRenderer->RenderQuad(manaIcons[mana2], xx + 3 * sinf(2*M_PI*((float)v)/256.0f), yy + 3 * cosf(2*M_PI*((float)(v-35))/256.0f), 0, 0.5f * mScale, 0.5f * mScale);
mRenderer->RenderQuad(manaIcons[mana], xx + 3 * sinf(2*M_PI*((float)t)/256.0f), yy + 3 * cosf(2*M_PI*((float)(t-35))/256.0f), 0, 0.5f * mScale, 0.5f * mScale);
}
mana = Constants::MTG_NB_COLORS + 1; // donot draw colorless cost in hybrid mana cost
}
else
mRenderer->RenderQuad(manaIcons[mana], xx, yy, 0, 0.5f * mScale, 0.5f * mScale);
mRenderer->BindTexture(mTexture); // manaIcons use different texture, so we need to rebind it.
}
if (mana <= 0) {
mSprites[index]->SetTextureRect(xPos, yPos, charWidth, charHeight);
mSprites[index]->SetColor(mColor);
mRenderer->RenderQuad(mSprites[index], xx, yy, 0, mScale, mScale);
mSprites[index]->SetTextureRect(xPos0, yPos, charWidth0, charHeight);
}
xx += delta;
if (xx >= 480) {
xx = x;
yy += (mFontSize * mScale);
}
}
}
}
}
void WFBFont::DrawString(std::string s, float x, float y, int align, float leftOffset, float width)
{
DrawString(s.c_str(),x,y,align,leftOffset,width);
}
void WFBFont::SetColor(PIXEL_TYPE color)
{
mColor0 = color;
mColor = gencolor(mFontID, color);
}
float WFBFont::GetStringWidth(const char *s) const
{
unsigned char c = *(unsigned short *)s & 0xFF;
if (ISGBK(c)) {
u8 * src = (u8 *)s;
float xx = 0;
bool dualByteFont = true;
while (*src != 0) {
if (*src > 0x80) { // Chinese and Japanese
src += 2;
dualByteFont = true;
}
else { // Latin 1
src += 1;
dualByteFont = false;
}
if (dualByteFont)
xx += (mFontSize * mScale);
else
xx += (mFontSize * mScale) / 2;
}
return xx;
}
else {
WFont * mFont = resources.GetWFont(mFontID + Fonts::kSingleByteFontOffset);
mFont->SetScale(GetScale());
return mFont->GetStringWidth(s);
}
}
void WFBFont::SetScale(float scale)
{
mScale = scale;
}
float WFBFont::GetScale() const {return mScale;}
float WFBFont::GetHeight() const {return (mFontSize * mScale);}
int WGBKFont::GetCode(const u8 *ch, bool *dualByteFont) const
{
int code = 0;
*dualByteFont = true;
if (*ch > 0xA0 && *(ch + 1) > 0xA0) {
// get offset to the proper character bits (GB2312 encoding)
code = (((u32)(*ch - 0xA1)) * 0x5E + ((u32)(*(ch + 1) - 0xA1)));
}
else if (*ch > 0x80) {
// get offset to the character space's bits (GBK encoding)
code = 0;
}
else {
code = ((u32)*ch)|0x10000;
*dualByteFont = false;
}
return code;
}
int WGBKFont::GetMana(const u8 *ch) const
{
int mana = -1;
if (*ch != 0xa3) return mana;
switch (*(ch+1)) {
case 0xC7:
mana = Constants::MTG_COLOR_GREEN;
break;
case 0xD5:
mana = Constants::MTG_COLOR_BLUE;
break;
case 0xD2:
mana = Constants::MTG_COLOR_RED;
break;
case 0xC2:
mana = Constants::MTG_COLOR_BLACK;
break;
case 0xD7:
mana = Constants::MTG_COLOR_WHITE;
break;
case 0xD4: // T
case 0xD8: // X
case 0xD9: // Y
mana = Constants::MTG_UNCOLORED;
break;
default:
if (*(ch+1) >= 0xB0 && *(ch+1) <= 0xB9)
mana = Constants::MTG_UNCOLORED;
}
return mana;
}
int WSJISFont::GetCode(const u8 *ch, bool *dualByteFont) const
{
int code = 0;
*dualByteFont = true;
if (*ch > 0xDF && *(ch + 1) > 0x3F) {
// get offset to the proper character bits (ShiftJIS encoding 2nd part)
code = (((u32)(*ch - 0xE0 + 0x1F)) * 0xBD + ((u32)(*(ch + 1) - 0x40)));
}
else if (*ch > 0x80 && *(ch + 1) > 0x3F) {
// get offset to the proper character bits (ShiftJIS encoding 1st part)
code = (((u32)(*ch - 0x81)) * 0xBD + ((u32)(*(ch + 1) - 0x40)));
}
else if (*ch > 0x80) {
// get offset to the character space's bits (ShiftJIS encoding)
code = 0;
}
else {
code = ((u32)*ch)|0x10000;
*dualByteFont = false;
}
return code;
}
int WSJISFont::GetMana(const u8 *ch) const
{
int mana = -1;
if (*ch != 0x82) return mana;
switch (*(ch+1)) {
case 0x66:
mana = Constants::MTG_COLOR_GREEN;
break;
case 0x74:
mana = Constants::MTG_COLOR_BLUE;
break;
case 0x71:
mana = Constants::MTG_COLOR_RED;
break;
case 0x61:
mana = Constants::MTG_COLOR_BLACK;
break;
case 0x76:
mana = Constants::MTG_COLOR_WHITE;
break;
case 0x73: // T
case 0x77: // X
case 0x78: // Y
mana = Constants::MTG_UNCOLORED;
break;
default:
if (*(ch+1) >= 0x4F && *(ch+1) <= 0x58)
mana = Constants::MTG_UNCOLORED;
}
return mana;
}