From ba0362d817130f68cfdc33f9558ece78a4347a53 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Fri, 22 Feb 2013 20:05:07 +0100 Subject: [PATCH] PGF font support. Mostly an adaptation and cleanup of JPCSP's font system. --- Common/LogManager.cpp | 2 +- Core/CMakeLists.txt | 1 + Core/Core.vcxproj | 3 +- Core/Core.vcxproj.filters | 14 +- Core/Font/PGF.cpp | 531 ++++++++++++++++++ Core/Font/PGF.h | 289 ++++++++++ Core/HLE/FunctionWrappers.h | 12 +- Core/HLE/HLE.h | 1 + Core/HLE/sceFont.cpp | 1005 ++++++++++++++++++++++++---------- Core/HLE/sceFont.h | 1 + Core/HLE/sceIo.cpp | 17 +- Core/HLE/sceKernel.cpp | 2 + Core/Util/BlockAllocator.cpp | 17 + Core/Util/BlockAllocator.h | 19 +- Core/Util/Pool.h | 25 - android/jni/Android.mk | 1 + 16 files changed, 1603 insertions(+), 337 deletions(-) create mode 100644 Core/Font/PGF.cpp create mode 100644 Core/Font/PGF.h delete mode 100644 Core/Util/Pool.h diff --git a/Common/LogManager.cpp b/Common/LogManager.cpp index 69d0b3ce01..f475219173 100644 --- a/Common/LogManager.cpp +++ b/Common/LogManager.cpp @@ -28,7 +28,7 @@ // Unfortunately this is quite slow. // #define LOG_MSC_OUTPUTDEBUG true -#define LOG_MSC_OUTPUTDEBUG false +#define LOG_MSC_OUTPUTDEBUG true void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char *file, int line, const char* fmt, ...) diff --git a/Core/CMakeLists.txt b/Core/CMakeLists.txt index 3706931498..3bbd94a384 100644 --- a/Core/CMakeLists.txt +++ b/Core/CMakeLists.txt @@ -21,6 +21,7 @@ set(SRCS ELF/ElfReader.cpp ELF/ParamSFO.cpp ELF/PrxDecrypter.cpp + Font/PGF.cpp HLE/HLE.cpp HLE/HLETables.cpp HLE/sceAtrac.cpp diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index 50c55c3a01..c744df54b3 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -144,6 +144,7 @@ + @@ -312,6 +313,7 @@ + @@ -412,7 +414,6 @@ - diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index aeafbe3ada..04d25d780a 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -49,6 +49,9 @@ {0b77054f-7fc7-4c33-ada3-762aecde69e5} + + {1c79e88d-1c48-450b-8af6-f22ce7d40c66} + @@ -375,6 +378,10 @@ MIPS\ARM + + + Font + @@ -533,9 +540,6 @@ Util - - Util - Debugger @@ -695,6 +699,10 @@ MIPS\ARM + + + Font + diff --git a/Core/Font/PGF.cpp b/Core/Font/PGF.cpp new file mode 100644 index 0000000000..2fd2c4140b --- /dev/null +++ b/Core/Font/PGF.cpp @@ -0,0 +1,531 @@ +// Copyright (c) 2012- PPSSPP Project. + +// 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, version 2.0 or later versions. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +// ============== NOTE!!!! + +// Thanks to the JPCSP project! This sceFont implementation is basically a C++ take on JPCSP's font code. +// Some parts, especially in this file, were simply copied, so I guess this really makes this file GPL3. + +#include "Common/CommonTypes.h" +#include "Core/MemMap.h" +#include "Core/Font/PGF.h" + +// These fonts, created by ttf2pgf, don't have complete glyph info and need to be identified. +static bool isJPCSPFont(const char *fontName) { + return !strcmp(fontName, "Liberation") || !strcmp(fontName, "Sazanami") || !strcmp(fontName, "UnDotum"); +} + +// Gets a number of bits from an offset. +// TODO: Make more efficient. +static int getBits(int numBits, const u8 *buf, size_t pos) { + int v = 0; + for (int i = 0; i < numBits; i++) { + v = v | (((buf[pos >> 3] >> (pos & 7)) & 1) << i); + pos++; + } + return v; +} + +static std::vector getTable(const u8 *buf, int bpe, int length) { + std::vector vec; + vec.resize(length); + for (int i = 0; i < length; i++) { + vec[i] = getBits(bpe, buf, bpe * i); + } + return vec; +} + +PGF::PGF() + : fontData(0), charMap(0), shadowCharMap(0), charPointerTable(0) { + +} + +PGF::~PGF() { + delete [] fontData; + delete [] charMap; + delete [] shadowCharMap; + delete [] charPointerTable; +} + +void PGF::DoState(PointerWrap &p) { + // TODO! +} + +void PGF::ReadPtr(const u8 *ptr, size_t dataSize) { + const u8 *const startPtr = ptr; + + INFO_LOG(HLE, "Reading %i bytes of PGF header", sizeof(header)); + memcpy(&header, ptr, sizeof(header)); + ptr += sizeof(header); + + if (header.revision == 3) { + memcpy(&rev3extra, ptr, sizeof(rev3extra)); + rev3extra.compCharMapLength1 &= 0xFFFF; + rev3extra.compCharMapLength2 &= 0xFFFF; + ptr += sizeof(rev3extra); + } + + const u32 *wptr = (const u32 *)ptr; + dimensionTable[0].resize(header.dimTableLength); + dimensionTable[1].resize(header.dimTableLength); + for (int i = 0; i < header.dimTableLength; i++) { + dimensionTable[0][i] = *wptr++; + dimensionTable[1][i] = *wptr++; + } + + xAdjustTable[0].resize(header.xAdjustTableLength); + xAdjustTable[1].resize(header.xAdjustTableLength); + for (int i = 0; i < header.xAdjustTableLength; i++) { + xAdjustTable[0][i] = *wptr++; + xAdjustTable[1][i] = *wptr++; + } + + yAdjustTable[0].resize(header.yAdjustTableLength); + yAdjustTable[1].resize(header.yAdjustTableLength); + for (int i = 0; i < header.yAdjustTableLength; i++) { + yAdjustTable[0][i] = *wptr++; + yAdjustTable[1][i] = *wptr++; + } + + advanceTable[0].resize(header.advanceTableLength); + advanceTable[1].resize(header.advanceTableLength); + for (int i = 0; i < header.advanceTableLength; i++) { + advanceTable[0][i] = *wptr++; + advanceTable[1][i] = *wptr++; + } + + const u8 *uptr = (const u8 *)wptr; + + int shadowCharMapSize = ((header.shadowMapLength * header.shadowMapBpe + 31) & ~31) / 8; + shadowCharMap = new u8[shadowCharMapSize]; + for (int i = 0; i < shadowCharMapSize; i++) { + shadowCharMap[i] = *uptr++; + } + + const u16 *sptr = (const u16 *)uptr; + if (header.revision == 3) { + charmapCompressionTable1[0].resize(rev3extra.compCharMapLength1); + charmapCompressionTable1[1].resize(rev3extra.compCharMapLength1); + for (int i = 0; i < rev3extra.compCharMapLength1; i++) { + charmapCompressionTable1[0][i] = *sptr++; + charmapCompressionTable1[1][i] = *sptr++; + } + + charmapCompressionTable2[0].resize(rev3extra.compCharMapLength2); + charmapCompressionTable2[1].resize(rev3extra.compCharMapLength2); + for (int i = 0; i < rev3extra.compCharMapLength2; i++) { + charmapCompressionTable2[0][i] = *sptr++; + charmapCompressionTable2[1][i] = *sptr++; + } + } + + uptr = (const u8 *)sptr; + + int charMapSize = ((header.charMapLength * header.charMapBpe + 31) & ~31) / 8; + + charMap = new u8[charMapSize]; + for (int i = 0; i < charMapSize; i++) { + charMap[i] = *uptr++; + } + + int charPointerSize = (((header.charPointerLength * header.charPointerBpe + 31) & ~31) / 8); + charPointerTable = new u8[charPointerSize]; + for (int i = 0; i < charPointerSize; i++) { + charPointerTable[i] = *uptr++; + } + + // PGF Fontdata. + u32 fontDataOffset = uptr - startPtr; + + fontDataSize = dataSize - fontDataOffset; + fontData = new u8[fontDataSize]; + memcpy(fontData, uptr, fontDataSize); + + // charmap.resize(); + charmap.resize(header.charMapLength); + int charmap_compr_len = header.revision == 3 ? 7 : 1; + charmap_compr.resize(charmap_compr_len * 4); + glyphs.resize(header.charPointerLength); + shadowGlyphs.resize(header.shadowMapLength); + firstGlyph = header.firstGlyph; + + // Parse out the char map (array where each entry is an irregular number of bits) + // BPE = bits per entry, I think. + for (int i = 0; i < header.charMapLength; i++) { + charmap[i] = getBits(header.charMapBpe, charMap, i * header.charMapBpe); + // This check seems a little odd. + if ((size_t)charmap[i] >= glyphs.size()) + charmap[i] = 65535; + } + + std::vector charPointers = getTable(charPointerTable, header.charPointerBpe, glyphs.size()); + std::vector shadowMap = getTable(shadowCharMap, header.shadowMapBpe, shadowGlyphs.size()); + + // Pregenerate glyphs. + for (size_t i = 0; i < glyphs.size(); i++) { + GetGlyph(fontData, charPointers[i] * 4 * 8 /* ??? */, FONT_PGF_CHARGLYPH, glyphs[i]); + } + + // And shadow glyphs. + for (size_t i = 0; i < shadowGlyphs.size(); i++) { + size_t shadowId = glyphs[i].shadowID; + if (shadowId >= 0 && shadowId < shadowMap.size()) { + size_t charId = shadowMap[shadowId]; + if (charId >= 0 && charId < glyphs.size()) { + // TODO: check for pre existing shadow glyph + GetGlyph(fontData, charPointers[charId] * 4 * 8 /* ??? */, FONT_PGF_SHADOWGLYPH, shadowGlyphs[i]); + } + } + } +} + +int PGF::GetCharIndex(int charCode, const std::vector &charmapCompressed) { + int charIndex = 0; + for (size_t i = 0; i < charmapCompressed.size(); i += 2) { + if (charCode >= charmapCompressed[i] && charCode < charmapCompressed[i] + charmapCompressed[i + 1]) { + charIndex += charCode - charmapCompressed[i]; + return charIndex; + } + charIndex += charmapCompressed[i + 1]; + } + return -1; +} + +bool PGF::GetCharInfo(int charCode, PGFCharInfo *charInfo) { + Glyph glyph; + if (!GetCharGlyph(charCode, FONT_PGF_CHARGLYPH, glyph)) { + // Character not in font, return zeroed charInfo as on real PSP. + return false; + } + memset(charInfo, 0, sizeof(charInfo)); + + charInfo->bitmapWidth = glyph.w; + charInfo->bitmapHeight = glyph.h; + charInfo->bitmapLeft = glyph.left; + charInfo->bitmapTop = glyph.top; + charInfo->sfp26Width = glyph.dimensionWidth; + charInfo->sfp26Height = glyph.dimensionHeight; + charInfo->sfp26Ascender = glyph.top << 6; + charInfo->sfp26Descender = (glyph.h - glyph.top) << 6; + charInfo->sfp26BearingHX = glyph.xAdjustH; + charInfo->sfp26BearingHY = glyph.yAdjustH; + charInfo->sfp26BearingVX = glyph.xAdjustV; + charInfo->sfp26BearingVY = glyph.yAdjustV; + charInfo->sfp26AdvanceH = glyph.advanceH; + charInfo->sfp26AdvanceV = glyph.advanceV; + return true; +} + +void PGF::GetFontInfo(PGFFontInfo *fi) { + fi->maxGlyphWidthI = header.maxSize[0]; + fi->maxGlyphHeightI = header.maxSize[1]; + fi->maxGlyphAscenderI = header.maxAscender; + fi->maxGlyphDescenderI = header.maxDescender; + fi->maxGlyphLeftXI = header.maxLeftXAdjust; + fi->maxGlyphBaseYI = header.maxBaseYAdjust; + fi->minGlyphCenterXI = header.minCenterXAdjust; + fi->maxGlyphTopYI = header.maxTopYAdjust; + fi->maxGlyphAdvanceXI = header.maxAdvance[0]; + fi->maxGlyphAdvanceYI = header.maxAdvance[1]; + fi->maxGlyphWidthF = header.maxSize[0] / 64.0f; + fi->maxGlyphHeightF = header.maxSize[1] / 64.0f; + fi->maxGlyphAscenderF = header.maxAscender / 64.0f; + fi->maxGlyphDescenderF = header.maxDescender / 64.0f; + fi->maxGlyphLeftXF = header.maxLeftXAdjust / 64.0f; + fi->maxGlyphBaseYF = header.maxBaseYAdjust / 64.0f; + fi->minGlyphCenterXF = header.minCenterXAdjust / 64.0f; + fi->maxGlyphTopYF = header.maxTopYAdjust / 64.0f; + fi->maxGlyphAdvanceXF = header.maxAdvance[0] / 64.0f; + fi->maxGlyphAdvanceYF = header.maxAdvance[1] / 64.0f; + + fi->maxGlyphWidth = header.maxGlyphWidth; + fi->maxGlyphHeight = header.maxGlyphHeight; + fi->charMapLength = header.charMapLength; + fi->shadowMapLength = 0; // header.shadowMapLength; TODO + + fi->BPP = header.bpp; +} + +bool PGF::GetGlyph(const u8 *fontdata, size_t charPtr, int glyphType, Glyph &glyph) { + if (glyphType == FONT_PGF_SHADOWGLYPH) { + if (charPtr + 96 > fontDataSize * 8) + return false; + charPtr += getBits(14, fontdata, charPtr) * 8; + if (charPtr + 96 > fontDataSize * 8) + return false; + } + charPtr += 14; + + glyph.w = getBits(7, fontdata, charPtr); + charPtr += 7; + + glyph.h = getBits(7, fontdata, charPtr); + charPtr += 7; + + glyph.left = getBits(7, fontdata, charPtr); + charPtr += 7; + if (glyph.left >= 64) { + glyph.left -= 128; + } + + glyph.top = getBits(7, fontdata, charPtr); + charPtr += 7; + if (glyph.top >= 64) { + glyph.top -= 128; + } + + glyph.flags = getBits(6, fontdata, charPtr); + charPtr += 6; + + if (glyph.flags & FONT_PGF_CHARGLYPH) { + // Skip magic number + charPtr += 7; + + glyph.shadowID = getBits(9, fontdata, charPtr); + charPtr += 9; + + int dimensionIndex = getBits(8, fontdata, charPtr); + charPtr += 8; + + int xAdjustIndex = getBits(8, fontdata, charPtr); + charPtr += 8; + + int yAdjustIndex = getBits(8, fontdata, charPtr); + charPtr += 8; + + charPtr += + ((glyph.flags & FONT_PGF_METRIC_FLAG1) ? 0 : 56) + + ((glyph.flags & FONT_PGF_METRIC_FLAG2) ? 0 : 56) + + ((glyph.flags & FONT_PGF_METRIC_FLAG3) ? 0 : 56); + + int advanceIndex = getBits(8, fontdata, charPtr); + charPtr += 8; + + if (dimensionIndex < header.dimTableLength) { + glyph.dimensionWidth = dimensionTable[0][dimensionIndex]; + glyph.dimensionHeight = dimensionTable[1][dimensionIndex]; + } + + if (xAdjustIndex < header.xAdjustTableLength) { + glyph.xAdjustH = xAdjustTable[0][xAdjustIndex]; + glyph.xAdjustV = xAdjustTable[1][xAdjustIndex]; + } + + if (yAdjustIndex < header.xAdjustTableLength) { + glyph.yAdjustH = yAdjustTable[0][yAdjustIndex]; + glyph.yAdjustV = yAdjustTable[1][yAdjustIndex]; + } + + if (dimensionIndex == 0 && xAdjustIndex == 0 && yAdjustIndex == 0 && isJPCSPFont(fileName.c_str())) { + // Fonts created by ttf2pgf do not contain complete Glyph information. + // Provide default values. + glyph.dimensionWidth = glyph.w << 6; + glyph.dimensionHeight = glyph.h << 6; + // This stuff doesn't exactly look right. + glyph.xAdjustH = glyph.left << 6; + glyph.xAdjustV = glyph.left << 6; + glyph.yAdjustH = glyph.top << 6; + glyph.yAdjustV = glyph.top << 6; + } + + if (advanceIndex < header.advanceTableLength) { + glyph.advanceH = advanceTable[0][advanceIndex]; + glyph.advanceV = advanceTable[1][advanceIndex]; + } + } else { + glyph.shadowID = 65535; + glyph.advanceH = 0; + } + + glyph.ptr = (u32)(charPtr / 8); + return true; +} + +bool PGF::GetCharGlyph(int charCode, int glyphType, Glyph &glyph) { + if (charCode < firstGlyph) + return false; + charCode -= firstGlyph; + if (charCode < (int)charmap.size()) { + charCode = charmap[charCode]; + } + if (glyphType == FONT_PGF_CHARGLYPH) { + if (charCode >= (int)glyphs.size()) + return false; + glyph = glyphs[charCode]; + } else { + if (charCode >= (int)shadowGlyphs.size()) + return false; + glyph = shadowGlyphs[charCode]; + } + return true; +} + +void PGF::DrawCharacter(u32 base, int bpl, int bufWidth, int bufHeight, int x, int y, int clipX, int clipY, int clipWidth, int clipHeight, int pixelformat, int charCode, int altCharCode, int glyphType) { + Glyph glyph; + if (!GetCharGlyph(charCode, glyphType, glyph)) { + // No Glyph available for this charCode, try to use the alternate char. + charCode = altCharCode; + if (!GetCharGlyph(charCode, glyphType, glyph)) { + return; + } + } + + if (glyph.w <= 0 || glyph.h <= 0) { + return; + } + + if (((glyph.flags & FONT_PGF_BMP_OVERLAY) != FONT_PGF_BMP_H_ROWS) && + ((glyph.flags & FONT_PGF_BMP_OVERLAY) != FONT_PGF_BMP_V_ROWS)) { + return; + } + + u32 bitPtr = glyph.ptr * 8; + int numberPixels = glyph.w * glyph.h; + int pixelIndex = 0; + + while (pixelIndex < numberPixels && bitPtr + 8 < fontDataSize * 8) { + // This is some kind of nibble based RLE compression. + int nibble = getBits(4, fontData, bitPtr); + bitPtr += 4; + + int count; + int value; + if (nibble < 8) { + value = getBits(4, fontData, bitPtr); + bitPtr += 4; + count = nibble + 1; + } else { + count = 16 - nibble; + } + + for (int i = 0; i < count && pixelIndex < numberPixels; i++) { + if (nibble >= 8) { + value = getBits(4, fontData, bitPtr); + bitPtr += 4; + } + + int xx, yy; + if ((glyph.flags & FONT_PGF_BMP_OVERLAY) == FONT_PGF_BMP_H_ROWS) { + xx = pixelIndex % glyph.w; + yy = pixelIndex / glyph.w; + } else { + xx = pixelIndex / glyph.h; + yy = pixelIndex % glyph.h; + } + + int pixelX = x + xx; + int pixelY = y + yy; + if (pixelX >= clipX && pixelX < clipX + clipWidth && pixelY >= clipY && pixelY < clipY + clipHeight) { + // 4-bit color value + int pixelColor = value; + switch (pixelformat) { + case PSP_FONT_PIXELFORMAT_8: + // 8-bit color value + pixelColor |= pixelColor << 4; + break; + case PSP_FONT_PIXELFORMAT_24: + // 24-bit color value + pixelColor |= pixelColor << 4; + pixelColor |= pixelColor << 8; + pixelColor |= pixelColor << 8; + break; + case PSP_FONT_PIXELFORMAT_32: + // 32-bit color value + pixelColor |= pixelColor << 4; + pixelColor |= pixelColor << 8; + pixelColor |= pixelColor << 16; + break; + } + + SetFontPixel(base, bpl, bufWidth, bufHeight, pixelX, pixelY, pixelColor, pixelformat); + } + + pixelIndex++; + } + } +} + +void PGF::SetFontPixel(u32 base, int bpl, int bufWidth, int bufHeight, int x, int y, int pixelColor, int pixelformat) { + if (x < 0 || x >= bufWidth || y < 0 || y >= bufHeight) { + return; + } + + static const u8 fontPixelSizeInBytes[] = { 0, 0, 1, 3, 4 }; // 0 means 2 pixels per byte + int pixelBytes = fontPixelSizeInBytes[pixelformat]; + int bufMaxWidth = (pixelBytes == 0 ? bpl * 2 : bpl / pixelBytes); + if (x >= bufMaxWidth) { + return; + } + + int framebufferAddr = base + (y * bpl) + (pixelBytes == 0 ? x / 2 : x * pixelBytes); + + switch (pixelformat) { + case PSP_FONT_PIXELFORMAT_4: + case PSP_FONT_PIXELFORMAT_4_REV: + { + int oldColor = Memory::Read_U8(framebufferAddr); + int newColor; + if ((x & 1) != pixelformat) { + newColor = (pixelColor << 4) | (oldColor & 0xF); + } else { + newColor = (oldColor & 0xF0) | pixelColor; + } + Memory::Write_U8(newColor, framebufferAddr); + break; + } + case PSP_FONT_PIXELFORMAT_8: + { + Memory::Write_U8((u8)pixelColor, framebufferAddr); + break; + } + case PSP_FONT_PIXELFORMAT_24: + { + Memory::Write_U8(pixelColor & 0xFF, framebufferAddr + 0); + Memory::Write_U8(pixelColor >> 8, framebufferAddr + 1); + Memory::Write_U8(pixelColor >> 16, framebufferAddr + 2); + break; + } + case PSP_FONT_PIXELFORMAT_32: + { + Memory::Write_U32(pixelColor, framebufferAddr); + break; + } + } +} + +u32 GetFontPixelColor(int color, int pixelformat) { + switch (pixelformat) { + case PSP_FONT_PIXELFORMAT_4: + case PSP_FONT_PIXELFORMAT_4_REV: + // Use only 4-bit alpha + color = (color >> 28) & 0xF; + break; + case PSP_FONT_PIXELFORMAT_8: + // Use only 8-bit alpha + color = (color >> 24) & 0xFF; + break; + case PSP_FONT_PIXELFORMAT_24: + // Use RGB with 8-bit values + color = color & 0x00FFFFFF; + break; + case PSP_FONT_PIXELFORMAT_32: + // Use RGBA with 8-bit values + break; + } + + return color; +} \ No newline at end of file diff --git a/Core/Font/PGF.h b/Core/Font/PGF.h new file mode 100644 index 0000000000..bba9f29d3d --- /dev/null +++ b/Core/Font/PGF.h @@ -0,0 +1,289 @@ +// Copyright (c) 2012- PPSSPP Project. + +// 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, version 2.0 or later versions. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +// Thanks to the JPCSP project! This sceFont implementation is basically a C++ take on JPCSP's font code. + +#pragma once + +#include +#include + +#include "Common/Log.h" +#include "Common/ChunkFile.h" +#include "Common/CommonTypes.h" + +enum { + FONT_FILETYPE_PGF = 0x00, + FONT_FILETYPE_BWFON = 0x01, +}; + +enum { + FONT_PGF_BMP_H_ROWS = 0x01, + FONT_PGF_BMP_V_ROWS = 0x02, + FONT_PGF_BMP_OVERLAY = 0x03, + FONT_PGF_METRIC_FLAG1 = 0x04, + FONT_PGF_METRIC_FLAG2 = 0x08, + FONT_PGF_METRIC_FLAG3 = 0x10, + FONT_PGF_CHARGLYPH = 0x20, + FONT_PGF_SHADOWGLYPH = 0x40, +}; + +enum Family { + FONT_FAMILY_SANS_SERIF = 1, + FONT_FAMILY_SERIF = 2, +}; + +enum Style { + FONT_STYLE_REGULAR = 1, + FONT_STYLE_ITALIC = 2, + FONT_STYLE_BOLD = 5, + FONT_STYLE_BOLD_ITALIC = 6, + FONT_STYLE_DB = 103, // Demi-Bold / semi-bold +}; + +enum Language { + FONT_LANGUAGE_JAPANESE = 1, + FONT_LANGUAGE_LATIN = 2, + FONT_LANGUAGE_KOREAN = 3, + FONT_LANGUAGE_CHINESE = 4, +}; + +enum FontPixelFormat { + PSP_FONT_PIXELFORMAT_4 = 0, // 2 pixels packed in 1 byte (natural order) + PSP_FONT_PIXELFORMAT_4_REV = 1, // 2 pixels packed in 1 byte (reversed order) + PSP_FONT_PIXELFORMAT_8 = 2, // 1 pixel in 1 byte + PSP_FONT_PIXELFORMAT_24 = 3, // 1 pixel in 3 bytes (RGB) + PSP_FONT_PIXELFORMAT_32 = 4, // 1 pixel in 4 bytes (RGBA) +}; + + +struct PGFFontStyle { + float fontH; + float fontV; + float fontHRes; + float fontVRes; + float fontWeight; + u16 fontFamily; + u16 fontStyle; + // Check. + u16 fontStyleSub; + u16 fontLanguage; + u16 fontRegion; + u16 fontCountry; + char fontName[64]; + char fontFileName[64]; + u32 fontAttributes; + u32 fontExpire; +}; + + +class Glyph { +public: + int x; + int y; + int w; + int h; + int left; + int top; + int flags; + int shadowID; + int advanceH; + int advanceV; + int dimensionWidth, dimensionHeight; + int xAdjustH, xAdjustV; + int yAdjustH, yAdjustV; + u32 ptr; +}; + +#pragma pack(push,1) +struct PGFHeader +{ + u16 headerOffset; + u16 headerSize; + + char PGFMagic[4]; + int revision; + int version; + + int charMapLength; + int charPointerLength; + int charMapBpe; + int charPointerBpe; + + u8 pad1[2]; + u8 bpp; + u8 pad2[1]; + + int hSize; + int vSize; + int hResolution; + int vResolution; + + u8 pad3[1]; + char fontName[64]; + char fontType[64]; + u8 pad4[1]; + + u16 firstGlyph; + u16 lastGlyph; + + u8 pad5[26]; + + int maxAscender; + int maxDescender; + int maxLeftXAdjust; + int maxBaseYAdjust; + int minCenterXAdjust; + int maxTopYAdjust; + + int maxAdvance[2]; + int maxSize[2]; + u16 maxGlyphWidth; + u16 maxGlyphHeight; + u8 pad6[2]; + + u8 dimTableLength; + u8 xAdjustTableLength; + u8 yAdjustTableLength; + u8 advanceTableLength; + u8 pad7[102]; + + int shadowMapLength; + int shadowMapBpe; + float unknown1; + int shadowScale[2]; + u8 pad8[8]; +}; + +struct PGFHeaderRev3Extra { + int compCharMapBpe1; + int compCharMapLength1; + int compCharMapBpe2; + int compCharMapLength2; + u32 unknown; +}; + +struct PGFCharInfo { + u32 bitmapWidth; + u32 bitmapHeight; + u32 bitmapLeft; + u32 bitmapTop; + // Glyph metrics (in 26.6 signed fixed-point). + u32 sfp26Width; + u32 sfp26Height; + s32 sfp26Ascender; + s32 sfp26Descender; + s32 sfp26BearingHX; + s32 sfp26BearingHY; + s32 sfp26BearingVX; + s32 sfp26BearingVY; + s32 sfp26AdvanceH; + s32 sfp26AdvanceV; + u8 pad[4]; +}; + +struct PGFFontInfo { + // Glyph metrics (in 26.6 signed fixed-point). + int maxGlyphWidthI; + int maxGlyphHeightI; + int maxGlyphAscenderI; + int maxGlyphDescenderI; + int maxGlyphLeftXI; + int maxGlyphBaseYI; + int minGlyphCenterXI; + int maxGlyphTopYI; + int maxGlyphAdvanceXI; + int maxGlyphAdvanceYI; + + // Glyph metrics (replicated as float). + float maxGlyphWidthF; + float maxGlyphHeightF; + float maxGlyphAscenderF; + float maxGlyphDescenderF; + float maxGlyphLeftXF; + float maxGlyphBaseYF; + float minGlyphCenterXF; + float maxGlyphTopYF; + float maxGlyphAdvanceXF; + float maxGlyphAdvanceYF; + + // Bitmap dimensions. + short maxGlyphWidth; + short maxGlyphHeight; + int charMapLength; // Number of elements in the font's charmap. + int shadowMapLength; // Number of elements in the font's shadow charmap. + + // Font style (used by font comparison functions). + PGFFontStyle fontStyle; + + int BPP; // Font's BPP. +}; + +#pragma pack(pop) + +class PGF { +public: + PGF(); + ~PGF(); + + void ReadPtr(const u8 *ptr, size_t dataSize); + + bool GetCharInfo(int charCode, PGFCharInfo *ci); + void GetFontInfo(PGFFontInfo *fi); + void DrawCharacter(u32 base, int bpl, int bufWidth, int bufHeight, int x, int y, int clipX, int clipY, int clipWidth, int clipHeight, int pixelformat, int charCode, int altCharCode, int glyphType); + + void DoState(PointerWrap &p); + + PGFHeader header; + +private: + bool GetGlyph(const u8 *fontdata, size_t charPtr, int glyphType, Glyph &glyph); + bool GetCharGlyph(int charCode, int glyphType, Glyph &glyph); + + // Unused + int GetCharIndex(int charCode, const std::vector &charmapCompressed); + + void SetFontPixel(u32 base, int bpl, int bufWidth, int bufHeight, int x, int y, int pixelColor, int pixelformat); + + PGFHeaderRev3Extra rev3extra; + + // Font character image data + u8 *fontData; + size_t fontDataSize; + + std::string fileName; + + std::vector dimensionTable[2]; + std::vector xAdjustTable[2]; + std::vector yAdjustTable[2]; + std::vector advanceTable[2]; + + // Unused + std::vector charmapCompressionTable1[2]; + std::vector charmapCompressionTable2[2]; + + u8 *charMap; + u8 *shadowCharMap; + u8 *charPointerTable; + + std::vector charmap_compr; + std::vector charmap; + + std::vector glyphs; + std::vector shadowGlyphs; + int firstGlyph; +}; diff --git a/Core/HLE/FunctionWrappers.h b/Core/HLE/FunctionWrappers.h index 85468754b8..4ef0f71991 100644 --- a/Core/HLE/FunctionWrappers.h +++ b/Core/HLE/FunctionWrappers.h @@ -96,6 +96,11 @@ template void WrapF_V() { RETURNF(func()); } +// TODO: Not sure about the floating point parameter passing +template void WrapF_IFU() { + RETURNF(func(PARAM(0), PARAMF(0), PARAM(1))); +} + template void WrapU_U() { u32 retval = func(PARAM(0)); RETURN(retval); @@ -133,7 +138,7 @@ template void WrapI_UU() { template void WrapI_UFF() { // Not sure about the float arguments. - int retval = func(PARAM(0), currentMIPS->f[0], currentMIPS->f[1]); + int retval = func(PARAM(0), currentMIPS->f[12], currentMIPS->f[13]); RETURN(retval); } @@ -481,6 +486,11 @@ template void WrapU_UUUU() { RETURN(retval); } +template void WrapU_UCUU() { + u32 retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), PARAM(3)); + RETURN(retval); +} + template void WrapU_UUUI() { u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); RETURN(retval); diff --git a/Core/HLE/HLE.h b/Core/HLE/HLE.h index 3b5558fbe5..40b4a17dbc 100644 --- a/Core/HLE/HLE.h +++ b/Core/HLE/HLE.h @@ -53,6 +53,7 @@ struct Syscall }; #define PARAM(n) currentMIPS->r[4+n] +#define PARAMF(n) currentMIPS->f[12+n] #define RETURN(n) currentMIPS->r[2]=n #define RETURNF(fl) currentMIPS->f[0]=fl diff --git a/Core/HLE/sceFont.cpp b/Core/HLE/sceFont.cpp index 867d7ea664..c33032a3a0 100644 --- a/Core/HLE/sceFont.cpp +++ b/Core/HLE/sceFont.cpp @@ -5,6 +5,33 @@ #include "HLE.h" #include "../MIPS/MIPS.h" #include "ChunkFile.h" +#include "Core/FileSystems/FileSystem.h" +#include "Core/System.h" +#include "Core/HLE/sceKernel.h" +#include "Core/Font/PGF.h" +#include "Core/HLE/sceKernelThread.h" + +enum { + ERROR_FONT_INVALID_LIBID = 0x80460002, + ERROR_FONT_INVALID_PARAMETER = 0x80460003, + ERROR_FONT_TOO_MANY_OPEN_FONTS = 0x80460009, +}; + +enum { + FONT_IS_CLOSED = 0, + FONT_IS_OPEN = 1, +}; + +// Actions +static int actionPostAllocCallback; +static int actionPostOpenCallback; + +// Monster Hunter sequence: +// 36:46:998 c:\dev\ppsspp\core\hle\scefont.cpp:469 E[HLE]: sceFontNewLib 89ad4a0, 9fff5cc +// 36:46:998 c:\dev\ppsspp\core\hle\scefont.cpp:699 E[HLE]: UNIMPL sceFontGetNumFontList 1, 9fff5cc +// 36:46:998 c:\dev\ppsspp\core\hle\scefont.cpp:526 E[HLE]: sceFontFindOptimumFont 1, 9fff524, 9fff5cc +// 36:46:999 c:\dev\ppsspp\core\hle\scefont.cpp:490 E[HLE]: sceFontOpenFont 1, 1, 0, 9fff5cc +// 36:46:999 c:\dev\ppsspp\core\hle\scefont.cpp:542 E[HLE]: sceFontGetFontInfo 1, 997140c typedef u32 FontLibraryHandle; typedef u32 FontHandle; @@ -25,109 +52,6 @@ struct FontNewLibParams { u32 ioFinishFuncAddr; }; -typedef enum Family { - FONT_FAMILY_SANS_SERIF = 1, - FONT_FAMILY_SERIF = 2, -}; - -typedef enum Style { - FONT_STYLE_REGULAR = 1, - FONT_STYLE_ITALIC = 2, - FONT_STYLE_BOLD = 5, - FONT_STYLE_BOLD_ITALIC = 6, - FONT_STYLE_DB = 103, // Demi-Bold / semi-bold -}; - -typedef enum Language { - FONT_LANGUAGE_JAPANESE = 1, - FONT_LANGUAGE_LATIN = 2, - FONT_LANGUAGE_KOREAN = 3, -}; - -struct FontStyle { - float fontH; - float fontV; - float fontHRes; - float fontVRes; - float fontWeight; - u16 fontFamily; - u16 fontStyle; - // Check. - u16 fontStyleSub; - u16 fontLanguage; - u16 fontRegion; - u16 fontCountry; - char fontName[64]; - char fontFileName[64]; - u32 fontAttributes; - u32 fontExpire; -}; - -struct FontInfo { - // Glyph metrics (in 26.6 signed fixed-point). - u32 maxGlyphWidthI; - u32 maxGlyphHeightI; - u32 maxGlyphAscenderI; - u32 maxGlyphDescenderI; - u32 maxGlyphLeftXI; - u32 maxGlyphBaseYI; - u32 minGlyphCenterXI; - u32 maxGlyphTopYI; - u32 maxGlyphAdvanceXI; - u32 maxGlyphAdvanceYI; - - // Glyph metrics (replicated as float). - float maxGlyphWidthF; - float maxGlyphHeightF; - float maxGlyphAscenderF; - float maxGlyphDescenderF; - float maxGlyphLeftXF; - float maxGlyphBaseYF; - float minGlyphCenterXF; - float maxGlyphTopYF; - float maxGlyphAdvanceXF; - float maxGlyphAdvanceYF; - - // Bitmap dimensions. - short maxGlyphWidth; - short maxGlyphHeight; - u32 charMapLength; // Number of elements in the font's charmap. - u32 shadowMapLength; // Number of elements in the font's shadow charmap. - - // Font style (used by font comparison functions). - FontStyle fontStyle; - - u8 BPP; // Font's BPP. - u8 pad[3]; -}; - -struct CharInfo { - u32 bitmapWidth; - u32 bitmapHeight; - u32 bitmapLeft; - u32 bitmapTop; - // Glyph metrics (in 26.6 signed fixed-point). - u32 spf26Width; - u32 spf26Height; - s32 spf26Ascender; - s32 spf26Descender; - s32 spf26BearingHX; - s32 spf26BearingHY; - s32 spf26BearingVX; - s32 spf26BearingVY; - s32 spf26AdvanceH; - s32 spf26AdvanceV; - u8 pad[4]; -}; - -enum FontPixelFormat { - PSP_FONT_PIXELFORMAT_4 = 0, - PSP_FONT_PIXELFORMAT_4_REV = 1, - PSP_FONT_PIXELFORMAT_8 = 2, - PSP_FONT_PIXELFORMAT_24 = 3, - PSP_FONT_PIXELFORMAT_32 = 4 -}; - struct GlyphImage { FontPixelFormat pixelFormat; s32 xPos64; @@ -139,184 +63,624 @@ struct GlyphImage { u32 bufferPtr; }; -FontNewLibParams fontLib; +struct FontRegistryEntry { + int hSize; + int vSize; + int hResolution; + int vResolution; + int extraAttributes; + int weight; + int familyCode; + int style; + int styleSub; + int languageCode; + int regionCode; + int countryCode; + const char *fileName; + const char *fontName; + int expireDate; + int shadow_option; +}; -void __FontInit() -{ - memset(&fontLib, 0, sizeof(fontLib)); +static const FontRegistryEntry fontRegistry[] = { + {0x288, 0x288, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SANS_SERIF, FONT_STYLE_DB, 0, FONT_LANGUAGE_JAPANESE, 0, 1, "jpn0.pgf", "FTT-NewRodin Pro DB", 0, 0}, + {0x288, 0x288, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SANS_SERIF, FONT_STYLE_REGULAR, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn0.pgf", "FTT-NewRodin Pro Latin", 0, 0}, + {0x288, 0x288, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SERIF, FONT_STYLE_REGULAR, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn1.pgf", "FTT-Matisse Pro Latin", 0, 0}, + {0x288, 0x288, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SANS_SERIF, FONT_STYLE_ITALIC, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn2.pgf", "FTT-NewRodin Pro Latin", 0, 0}, + {0x288, 0x288, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SERIF, FONT_STYLE_ITALIC, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn3.pgf", "FTT-Matisse Pro Latin", 0, 0}, + {0x288, 0x288, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SANS_SERIF, FONT_STYLE_BOLD, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn4.pgf", "FTT-NewRodin Pro Latin", 0, 0}, + {0x288, 0x288, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SERIF, FONT_STYLE_BOLD, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn5.pgf", "FTT-Matisse Pro Latin", 0, 0}, + {0x288, 0x288, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SANS_SERIF, FONT_STYLE_BOLD_ITALIC, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn6.pgf", "FTT-NewRodin Pro Latin", 0, 0}, + {0x288, 0x288, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SERIF, FONT_STYLE_BOLD_ITALIC, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn7.pgf", "FTT-Matisse Pro Latin", 0, 0}, + {0x1c0, 0x1c0, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SANS_SERIF, FONT_STYLE_REGULAR, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn8.pgf", "FTT-NewRodin Pro Latin", 0, 0}, + {0x1c0, 0x1c0, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SERIF, FONT_STYLE_REGULAR, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn9.pgf", "FTT-Matisse Pro Latin", 0, 0}, + {0x1c0, 0x1c0, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SANS_SERIF, FONT_STYLE_ITALIC, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn10.pgf", "FTT-NewRodin Pro Latin", 0, 0}, + {0x1c0, 0x1c0, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SERIF, FONT_STYLE_ITALIC, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn11.pgf", "FTT-Matisse Pro Latin", 0, 0}, + {0x1c0, 0x1c0, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SANS_SERIF, FONT_STYLE_BOLD, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn12.pgf", "FTT-NewRodin Pro Latin", 0, 0}, + {0x1c0, 0x1c0, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SERIF, FONT_STYLE_BOLD, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn13.pgf", "FTT-Matisse Pro Latin", 0, 0}, + {0x1c0, 0x1c0, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SANS_SERIF, FONT_STYLE_BOLD_ITALIC, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn14.pgf", "FTT-NewRodin Pro Latin", 0, 0}, + {0x1c0, 0x1c0, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SERIF, FONT_STYLE_BOLD_ITALIC, 0, FONT_LANGUAGE_LATIN, 0, 1, "ltn15.pgf", "FTT-Matisse Pro Latin", 0, 0}, + {0x288, 0x288, 0x2000, 0x2000, 0, 0, FONT_FAMILY_SANS_SERIF, FONT_STYLE_REGULAR, 0, FONT_LANGUAGE_KOREAN, 0, 3, "kr0.pgf", "AsiaNHH(512Johab)", 0, 0}, +}; + +static const float pointDPI = 72.f; + +class FontLib; + +// TODO: Merge this class with PGF? That'd make it harder to support .bwfon +// fonts though, unless that's added directly to PGF. +class Font { +public: + Font(const u8 *data, size_t dataSize) { + pgf_.ReadPtr(data, dataSize); + style_.fontH = pgf_.header.hSize / 64.0f; + style_.fontV = pgf_.header.vSize / 64.0f; + style_.fontHRes = pgf_.header.hResolution / 64.0f; + style_.fontVRes = pgf_.header.vResolution / 64.0f; + } + + Font(const u8 *data, size_t dataSize, const FontRegistryEntry &entry) { + pgf_.ReadPtr(data, dataSize); + style_.fontH = entry.hSize / 64.f; + style_.fontV = entry.vSize / 64.f; + style_.fontHRes = entry.hResolution / 64.f; + style_.fontVRes = entry.vResolution / 64.f; + style_.fontWeight = (float)entry.weight; + style_.fontFamily = (u16)entry.familyCode; + style_.fontStyle = (u16)entry.style; + style_.fontStyleSub = (u16)entry.styleSub; + style_.fontLanguage = (u16)entry.languageCode; + style_.fontRegion = (u16)entry.regionCode; + style_.fontCountry = (u16)entry.countryCode; + strncpy(style_.fontName, entry.fontName, sizeof(style_.fontName)); + strncpy(style_.fontFileName, entry.fileName, sizeof(style_.fontFileName)); + style_.fontAttributes = entry.extraAttributes; + style_.fontExpire = entry.expireDate; + } + + const PGFFontStyle &GetFontStyle() const { return style_; } + + bool MatchesStyle(const PGFFontStyle &style, bool optimum) const { + // TODO + return true; + } + + PGF *GetPGF() { return &pgf_; } + +private: + PGF pgf_; + PGFFontStyle style_; + DISALLOW_COPY_AND_ASSIGN(Font); +}; + +class LoadedFont { +public: + LoadedFont(Font *font, FontLib *fontLib, u32 handle) + : font_(font), fontLib_(fontLib), handle_(handle) {} + + Font *GetFont() { return font_; } + FontLib *GetFontLib() { return fontLib_; } + u32 Handle() const { return handle_; } + + bool IsOpen() const { return fontLib_ != 0; } + void Close() { + fontLib_ = 0; + // We keep the rest around until deleted, as some queries are allowed + // on closed fonts (which is rather strange). + } + +private: + FontLib *fontLib_; + Font *font_; + u32 handle_; + DISALLOW_COPY_AND_ASSIGN(LoadedFont); +}; + +class FontLib; + +class PostAllocCallback : public Action { +public: + PostAllocCallback() {} + static Action *Create() { return new PostAllocCallback(); } + void DoState(PointerWrap &p) { /*TODO*/ p.DoMarker("PostAllocCallback"); } + void run(MipsCall &call); + void SetFontLib(FontLib *fontLib) { fontLib_ = fontLib; } + +private: + FontLib *fontLib_; +}; + +class PostOpenCallback : public Action { +public: + PostOpenCallback() {} + static Action *Create() { return new PostOpenCallback(); } + void DoState(PointerWrap &p) { /*TODO*/ p.DoMarker("PostOpenCallback"); } + void run(MipsCall &call); + void SetFontLib(FontLib *fontLib) { fontLib_ = fontLib; } + +private: + FontLib *fontLib_; +}; + +// A "fontLib" is a container of loaded fonts. +// One can open either "internal" fonts or custom fonts into a fontlib. +class FontLib { +public: + FontLib(u32 paramPtr) : fontHRes_(128.0f), fontVRes_(128.0f) { + Memory::ReadStruct(paramPtr, ¶ms_); + + // We use the same strange scheme that JPCSP uses. + int allocSize = 4 + 4 * params_.numFonts; + PostAllocCallback *action = (PostAllocCallback*) __KernelCreateAction(actionPostAllocCallback); + action->SetFontLib(this); + u32 args[1] = { allocSize }; + __KernelDirectMipsCall(params_.allocFuncAddr, action, args, 1, false); + } + + void Close() { + __KernelDirectMipsCall(params_.closeFuncAddr, 0, 0, 0, false); + } + + void Done() { + u32 args[1] = { handle_ }; + __KernelDirectMipsCall(params_.freeFuncAddr, 0, args, 1, false); + } + + void AllocDone(u32 allocatedAddr) { + handle_ = allocatedAddr; + fonts_.resize(params_.numFonts); + for (size_t i = 0; i < fonts_.size(); i++) { + u32 addr = allocatedAddr + 4 + i * 4; + Memory::Write_U32(FONT_IS_CLOSED, addr); + fonts_[i] = addr; + } + } + + u32 handle() const { return handle_; } + int numFonts() const { return params_.numFonts; } + + void SetResolution(float hres, float vres) { + fontHRes_ = hres; + fontVRes_ = vres; + } + + float FontHRes() const { return fontHRes_; } + float FontVRes() const { return fontVRes_; } + + void SetAltCharCode(int charCode) { altCharCode_ = charCode; } + + int GetFontHandle(int index) { + return fonts_[index]; + } + + LoadedFont *OpenFont(Font *font) { + int freeFontIndex = -1; + for (size_t i = 0; i < fonts_.size(); i++) { + if (Memory::Read_U32(fonts_[i]) == FONT_IS_CLOSED) { + freeFontIndex = (int)i; + break; + } + } + if (freeFontIndex < 0) { + ERROR_LOG(HLE, "Too many fonts opened in FontLib"); + return 0; + } + LoadedFont *loadedFont = new LoadedFont(font, this, fonts_[freeFontIndex]); + Memory::Write_U32(FONT_IS_OPEN, fonts_[freeFontIndex]); + return loadedFont; + } + + void CloseFont(LoadedFont *font) { + for (size_t i = 0; i < fonts_.size(); i++) { + if (fonts_[i] == font->Handle()) { + Memory::Write_U32(FONT_IS_CLOSED, font->Handle()); + } + } + font->Close(); + } + + void DoState(PointerWrap &p) { + p.Do(fonts_); + p.Do(params_); + p.Do(fontHRes_); + p.Do(fontVRes_); + p.Do(fileFontHandle_); + p.Do(handle_); + p.Do(altCharCode_); + } + + void SetFileFontHandle(u32 handle) { + fileFontHandle_ = handle; + } + + u32 GetAltCharCode() const { return altCharCode_; } + +private: + std::vector fonts_; + + FontNewLibParams params_; + float fontHRes_; + float fontVRes_; + int fileFontHandle_; + int handle_; + int altCharCode_; + DISALLOW_COPY_AND_ASSIGN(FontLib); +}; + + +// These should not need to be state saved. +static std::vector internalFonts; +// However, these we must save - but we could take a shortcut +// for LoadedFonts that point to internal fonts. +static std::map fontMap; +static std::map fontLibMap; + +void PostAllocCallback::run(MipsCall &call) { + u32 v0 = currentMIPS->r[0]; + fontLib_->AllocDone(call.savedV0); + fontLibMap[fontLib_->handle()] = fontLib_; + call.setReturnValue(fontLib_->handle()); } -void __FontDoState(PointerWrap &p) -{ - p.Do(fontLib); +void PostOpenCallback::run(MipsCall &call) { + fontLib_->SetFileFontHandle(call.savedV0); +} + +FontLib *GetFontLib(u32 handle) { + if (fontLibMap.find(handle) != fontLibMap.end()) { + return fontLibMap[handle]; + } else { + ERROR_LOG(HLE, "No fontlib with handle %08x", handle); + return 0; + } +} + +LoadedFont *GetLoadedFont(u32 handle, bool allowClosed) { + auto iter = fontMap.find(handle); + if (iter != fontMap.end()) { + if (iter->second->IsOpen() || allowClosed) { + return fontMap[handle]; + } else { + ERROR_LOG(HLE, "Font exists but is closed, which was not allowed in this call."); + return 0; + } + } else { + ERROR_LOG(HLE, "No font with handle %08x", handle); + return 0; + } +} + +void __LoadInternalFonts() { + std::string fontPath = "flash0:/font/"; + for (size_t i = 0; i < ARRAY_SIZE(fontRegistry); i++) { + const FontRegistryEntry &entry = fontRegistry[i]; + std::string fontFilename = fontPath + entry.fileName; + PSPFileInfo info = pspFileSystem.GetFileInfo(fontFilename); + if (info.exists) { + u8 *buffer = new u8[(size_t)info.size]; + u32 handle = pspFileSystem.OpenFile(fontFilename, FILEACCESS_READ); + pspFileSystem.ReadFile(handle, buffer, info.size); + pspFileSystem.CloseFile(handle); + + internalFonts.push_back(new Font(buffer, (size_t)info.size, entry)); + + delete [] buffer; + INFO_LOG(HLE, "Loaded font %s", fontFilename.c_str()); + } else { + INFO_LOG(HLE, "Font file not found: %s", fontFilename.c_str()); + } + } +} + +Style FontStyleFromString(const std::string &str) { + if (str == "Regular") + return FONT_STYLE_REGULAR; + else if (str == "Italic") + return FONT_STYLE_ITALIC; + else if (str == "Bold") + return FONT_STYLE_BOLD; + else if (str == "Bold Italic") + return FONT_STYLE_BOLD_ITALIC; + return FONT_STYLE_REGULAR; +} + +Font *GetOptimumFont(const PGFFontStyle &requestedStyle, Font *optimumFont, Font *candidateFont) { + if (!optimumFont) + return candidateFont; + PGFFontStyle optimumStyle = optimumFont->GetFontStyle(); + PGFFontStyle candidateStyle = candidateFont->GetFontStyle(); + + bool testH = requestedStyle.fontH != 0.0f || requestedStyle.fontV == 0.0f; + if (testH && fabsf(requestedStyle.fontH - optimumStyle.fontH) > fabsf(requestedStyle.fontH - candidateStyle.fontH)) { + return candidateFont; + } + + // Check the fontV if it is specified or both fontH and fontV are unspecified + bool testV = requestedStyle.fontV != 0.f || requestedStyle.fontH == 0.f; + if (testV && fabsf(requestedStyle.fontV - optimumStyle.fontV) > fabsf(requestedStyle.fontV - candidateStyle.fontV)) { + return candidateFont; + } + + return optimumFont; +} + +int GetInternalFontIndex(Font *font) { + for (size_t i = 0; i < internalFonts.size(); i++) { + if (internalFonts[i] == font) + return i; + } + return 0; +} + +void __FontInit() { + __LoadInternalFonts(); + actionPostAllocCallback = __KernelRegisterActionType(PostAllocCallback::Create); + actionPostOpenCallback = __KernelRegisterActionType(PostOpenCallback::Create); +} + +void __FontShutdown() { + for (auto iter = fontMap.begin(); iter != fontMap.end(); iter++) { + iter->second->GetFontLib()->CloseFont(iter->second); + } + fontMap.clear(); + for (auto iter = fontLibMap.begin(); iter != fontLibMap.end(); iter++) { + delete iter->second; + } + fontLibMap.clear(); + for (auto iter = internalFonts.begin(); iter != internalFonts.end(); ++iter) { + delete *iter; + } + internalFonts.clear(); +} + +void __FontDoState(PointerWrap &p) { + // TODO: Needs much work. + + p.Do(actionPostAllocCallback); + __KernelRestoreActionType(actionPostAllocCallback, PostAllocCallback::Create); + p.Do(actionPostOpenCallback); + __KernelRestoreActionType(actionPostOpenCallback, PostOpenCallback::Create); p.DoMarker("sceFont"); } -u32 sceFontNewLib(u32 FontNewLibParamsPtr, u32 errorCodePtr) -{ - ERROR_LOG(HLE, "sceFontNewLib %x, %x", FontNewLibParamsPtr, errorCodePtr); +u32 sceFontNewLib(u32 paramPtr, u32 errorCodePtr) { + INFO_LOG(HLE, "sceFontNewLib(%08x, %08x)", paramPtr, errorCodePtr); - if (Memory::IsValidAddress(FontNewLibParamsPtr)&&Memory::IsValidAddress(errorCodePtr)) - { + if (Memory::IsValidAddress(paramPtr) && Memory::IsValidAddress(errorCodePtr)) { Memory::Write_U32(0, errorCodePtr); - Memory::ReadStruct(FontNewLibParamsPtr, &fontLib); + + FontLib *newLib = new FontLib(paramPtr); + // The game should never see this value, the return value is replaced + // by the action. + return 0xDEADDEAD; } - return 1; -} - - -int sceFontDoneLib(u32 FontLibraryHandlePtr) -{ - ERROR_LOG(HLE, "sceFontDoneLib %x", FontLibraryHandlePtr); return 0; } - -u32 sceFontOpen(u32 libHandle, u32 index, u32 mode, u32 errorCodePtr) -{ - ERROR_LOG(HLE, "sceFontDoneLib %x, %x, %x, %x", libHandle, index, mode, errorCodePtr); - if (Memory::IsValidAddress(errorCodePtr)) - { - Memory::Write_U32(0, errorCodePtr); +int sceFontDoneLib(u32 fontLibHandle) { + INFO_LOG(HLE, "sceFontDoneLib(%08x)", fontLibHandle); + FontLib *fl = GetFontLib(fontLibHandle); + if (fl) { + fl->Done(); } - return 1; + return 0; } -u32 sceFontOpenUserMemory(u32 libHandle, u32 memoryFontAddrPtr, u32 memoryFontLength, u32 errorCodePtr) -{ +// Open internal font into a FontLib +u32 sceFontOpen(u32 libHandle, u32 index, u32 mode, u32 errorCodePtr) { + INFO_LOG(HLE, "sceFontOpen(%x, %x, %x, %x)", libHandle, index, mode, errorCodePtr); + if (!Memory::IsValidAddress(errorCodePtr)) { + Memory::Write_U32(ERROR_FONT_INVALID_PARAMETER, errorCodePtr); + return 0; + } + + FontLib *fontLib = GetFontLib(libHandle); + if (index < 0 || index >= internalFonts.size()) { + Memory::Write_U32(ERROR_FONT_INVALID_PARAMETER, errorCodePtr); + return 0; + } + + LoadedFont *font = fontLib->OpenFont(internalFonts[index]); + if (font) { + fontMap[font->Handle()] = font; + Memory::Write_U32(0, errorCodePtr); + return font->Handle(); + } else { + Memory::Write_U32(ERROR_FONT_TOO_MANY_OPEN_FONTS, errorCodePtr); + return 0; + } +} + +// Open a user font in RAM into a FontLib +u32 sceFontOpenUserMemory(u32 libHandle, u32 memoryFontAddrPtr, u32 memoryFontLength, u32 errorCodePtr) { ERROR_LOG(HLE, "sceFontOpenUserMemory %x, %x, %x, %x", libHandle, memoryFontAddrPtr, memoryFontLength, errorCodePtr); - if (Memory::IsValidAddress(errorCodePtr)) - { - Memory::Write_U32(0, errorCodePtr); + if (!Memory::IsValidAddress(errorCodePtr) || !Memory::IsValidAddress(memoryFontAddrPtr)) { + Memory::Write_U32(ERROR_FONT_INVALID_PARAMETER, errorCodePtr); + return 0; + } + + FontLib *fontLib = GetFontLib(libHandle); + if (!fontLib) { + Memory::Write_U32(ERROR_FONT_INVALID_PARAMETER, errorCodePtr); + return 0; + } + + const u8 *fontData = Memory::GetPointer(memoryFontAddrPtr); + LoadedFont *font = fontLib->OpenFont(new Font(fontData, memoryFontLength)); + if (font) { + fontMap[font->Handle()] = font; + Memory::Write_U32(0, errorCodePtr); + return font->Handle(); + } else { + Memory::Write_U32(ERROR_FONT_TOO_MANY_OPEN_FONTS, errorCodePtr); + return 0; } - return 1; } -u32 sceFontOpenUserFile(u32 libHandle, u32 fileNamePtr, u32 mode, u32 errorCodePtr) -{ - ERROR_LOG(HLE, "sceFontOpenUserFile %x, %x, %x, %x", libHandle, fileNamePtr, mode, errorCodePtr); - if (Memory::IsValidAddress(errorCodePtr)) - { - Memory::Write_U32(0, errorCodePtr); +// Open a user font in a file into a FontLib +u32 sceFontOpenUserFile(u32 libHandle, const char *fileName, u32 mode, u32 errorCodePtr) { + ERROR_LOG(HLE, "sceFontOpenUserFile(%08x, %s, %08x, %08x)", libHandle, fileName, mode, errorCodePtr); + if (!Memory::IsValidAddress(errorCodePtr)) + return ERROR_FONT_INVALID_PARAMETER; + + PSPFileInfo info = pspFileSystem.GetFileInfo(fileName); + if (!info.exists) { + Memory::Write_U32(ERROR_FONT_INVALID_PARAMETER, errorCodePtr); + return 0; + } + + FontLib *fontLib = GetFontLib(libHandle); + if (!fontLib) { + Memory::Write_U32(ERROR_FONT_INVALID_PARAMETER, errorCodePtr); + return 0; + } + + u8 *buffer = new u8[(size_t)info.size]; + + u32 fileHandle = pspFileSystem.OpenFile(fileName, FILEACCESS_READ); + pspFileSystem.ReadFile(fileHandle, buffer, info.size); + pspFileSystem.CloseFile(fileHandle); + + LoadedFont *font = fontLib->OpenFont(new Font(buffer, (size_t)info.size)); + if (font) { + fontMap[font->Handle()] = font; + Memory::Write_U32(0, errorCodePtr); + return font->Handle(); + } else { + Memory::Write_U32(ERROR_FONT_TOO_MANY_OPEN_FONTS, errorCodePtr); + return 0; } - return 1; } -int sceFontClose(u32 fontHandle) -{ - ERROR_LOG(HLE, "sceFontClose %x", fontHandle); +int sceFontClose(u32 fontHandle) { + INFO_LOG(HLE, "sceFontClose(%x)", fontHandle); + LoadedFont *font = GetLoadedFont(fontHandle, false); + FontLib *fontLib = font->GetFontLib(); + fontLib->CloseFont(font); return 0; } -int sceFontFindOptimumFont(u32 libHandlePtr, u32 fontStylePtr, u32 errorCodePtr) -{ - ERROR_LOG(HLE, "sceFontFindOptimumFont %x, %x, %x", libHandlePtr, fontStylePtr, errorCodePtr); - if (Memory::IsValidAddress(errorCodePtr)) - { - Memory::Write_U32(0, errorCodePtr); +int sceFontFindOptimumFont(u32 libHandlePtr, u32 fontStylePtr, u32 errorCodePtr) { + ERROR_LOG(HLE, "sceFontFindOptimumFont(%08x, %08x, %08x)", libHandlePtr, fontStylePtr, errorCodePtr); + if (!fontStylePtr) + return 0; + + if (!Memory::IsValidAddress(errorCodePtr)) + return SCE_KERNEL_ERROR_INVALID_ARGUMENT; + + PGFFontStyle requestedStyle; + Memory::ReadStruct(fontStylePtr, &requestedStyle); + + Font *optimumFont = 0; + for (size_t i = 0; i < internalFonts.size(); i++) { + if (internalFonts[i]->MatchesStyle(requestedStyle, true)) { + optimumFont = GetOptimumFont(requestedStyle, optimumFont, internalFonts[i]); + } + } + if (optimumFont) { + Memory::Write_U32(0, errorCodePtr); + return GetInternalFontIndex(optimumFont); + } else { + Memory::Write_U32(0, errorCodePtr); + return 0; } - return 1; } -int sceFontFindFont(u32 libHandlePtr, u32 fontStylePtr, u32 errorCodePtr) -{ - ERROR_LOG(HLE, "sceFontFindFont %x, %x, %x", libHandlePtr, fontStylePtr, errorCodePtr); - return 1; +// Returns the font index, not handle +int sceFontFindFont(u32 libHandlePtr, u32 fontStylePtr, u32 errorCodePtr) { + ERROR_LOG(HLE, "sceFontFindFont(%x, %x, %x)", libHandlePtr, fontStylePtr, errorCodePtr); + if (!Memory::IsValidAddress(errorCodePtr)) { + Memory::Write_U32(ERROR_FONT_INVALID_PARAMETER, errorCodePtr); + return 0; + } + + PGFFontStyle style; + Memory::ReadStruct(fontStylePtr, &style); + + for (size_t i = 0; i < internalFonts.size(); i++) { + if (internalFonts[i]->MatchesStyle(style, false)) { + Memory::Write_U32(0, errorCodePtr); + return i; + } + } + return -1; } -int sceFontGetFontInfo(u32 fontHandle, u32 fontInfoPtr) -{ - ERROR_LOG(HLE, "sceFontGetFontInfo %x, %x", fontHandle, fontInfoPtr); +int sceFontGetFontInfo(u32 fontHandle, u32 fontInfoPtr) { + ERROR_LOG(HLE, "sceFontGetFontInfo(%x, %x)", fontHandle, fontInfoPtr); - FontInfo fi; + PGFFontInfo fi; memset (&fi, 0, sizeof(fi)); - if (Memory::IsValidAddress(fontInfoPtr)) - { - fi.BPP = 4; - fi.charMapLength = 255; - fi.maxGlyphAdvanceXF = 2.0; - fi.maxGlyphAdvanceXI = 2; - fi.maxGlyphAdvanceYF = 2.0; - fi.maxGlyphAdvanceYI = 32 << 6; - fi.maxGlyphAscenderF = 32 << 6; - fi.maxGlyphAscenderI = 32 << 6; - fi.maxGlyphBaseYF = 0.0; - fi.maxGlyphBaseYI = 0; - fi.maxGlyphDescenderF = 0; - fi.maxGlyphDescenderI = 0; - fi.maxGlyphHeight = 32; - fi.maxGlyphHeightF = 32; - fi.maxGlyphHeightI = 32; - fi.maxGlyphLeftXF = 0; - fi.maxGlyphLeftXI = 0; - fi.maxGlyphTopYF = 0; - fi.maxGlyphTopYI = 0; - fi.maxGlyphWidth = 32; - fi.maxGlyphWidthF = 32; - fi.maxGlyphWidthI = 32; - fi.minGlyphCenterXF = 16; - fi.minGlyphCenterXI = 16; - fi.shadowMapLength = 0; - fi.fontStyle.fontAttributes=1; - fi.fontStyle.fontCountry= 1; - fi.fontStyle.fontExpire= 1; - fi.fontStyle.fontFamily= 1; - strcpy(fi.fontStyle.fontFileName, "asd"); - fi.fontStyle.fontH=32; - fi.fontStyle.fontHRes=32; - fi.fontStyle.fontLanguage=1; - strcpy(fi.fontStyle.fontName, "ppsspp"); - fi.fontStyle.fontRegion=9; - fi.fontStyle.fontV=32; - fi.fontStyle.fontVRes=32; - fi.fontStyle.fontWeight= 32; - Memory::WriteStruct(fontInfoPtr, &fi); - } + if (!Memory::IsValidAddress(fontInfoPtr)) + return 0; + LoadedFont * font = GetLoadedFont(fontHandle, true); + if (!font) + return 0; + PGF *pgf = font->GetFont()->GetPGF(); + pgf->GetFontInfo(&fi); + fi.fontStyle = font->GetFont()->GetFontStyle(); + + Memory::WriteStruct(fontInfoPtr, &fi); return 0; } -int sceFontGetFontInfoByIndexNumber(u32 libHandle, u32 fontInfoPtr, u32 unknown, u32 fontIndex) -{ - ERROR_LOG(HLE, "HACK sceFontGetFontInfoByIndexNumber %x, %x, %x, %x", libHandle, fontInfoPtr, unknown, fontIndex); - // clearly wrong.. - return sceFontGetFontInfo(libHandle, fontInfoPtr); - +int sceFontGetFontInfoByIndexNumber(u32 libHandle, u32 fontInfoPtr, u32 unknown, u32 fontIndex) { + ERROR_LOG(HLE, "HACK sceFontGetFontInfoByIndexNumber(%x, %x, %i, %i)", libHandle, fontInfoPtr, unknown, fontIndex); + FontLib *fl = GetFontLib(libHandle); + u32 fontHandle = fl->GetFontHandle(fontIndex); + return sceFontGetFontInfo(fontHandle, fontInfoPtr); } -int sceFontGetCharInfo(u32 fontHandle, u32 charCode, u32 charInfoPtr) -{ - ERROR_LOG(HLE, "HACK sceFontGetCharInfo %x, %x, %x", fontHandle, charCode, charInfoPtr); - if (Memory::IsValidAddress(charInfoPtr)) - { - CharInfo pspCharInfo; - memset(&pspCharInfo, 0, sizeof(pspCharInfo)); - pspCharInfo.bitmapWidth = 16; - pspCharInfo.bitmapHeight = 16; +int sceFontGetCharInfo(u32 fontHandle, u32 charCode, u32 charInfoPtr) { + INFO_LOG(HLE, "sceFontGetCharInfo(%08x, %i, %08x)", fontHandle, charCode, charInfoPtr); + if (!Memory::IsValidAddress(charInfoPtr)) + return -1; - pspCharInfo.spf26Width = pspCharInfo.bitmapWidth << 6; - pspCharInfo.spf26Height = pspCharInfo.bitmapHeight << 6; - pspCharInfo.spf26AdvanceH = pspCharInfo.bitmapWidth << 6; - pspCharInfo.spf26AdvanceV = pspCharInfo.bitmapHeight << 6; - Memory::WriteStruct(charInfoPtr, &pspCharInfo); + PGFCharInfo charInfo; + memset(&charInfo, 0, sizeof(charInfo)); + LoadedFont *font = GetLoadedFont(fontHandle, false); + if (font) { + font->GetFont()->GetPGF()->GetCharInfo(charCode, &charInfo); + } else { + ERROR_LOG(HLE, "sceFontGetCharInfo - invalid font"); + } + Memory::WriteStruct(charInfoPtr, &charInfo); + return 0; +} + +// Not sure about the arguments. +int sceFontGetShadowInfo(u32 fontHandle, u32 charCode, u32 shadowCharInfoPtr) { + ERROR_LOG(HLE, "UNIMPL sceFontGetShadowInfo(%08x, %i, %08x)", fontHandle, charCode, shadowCharInfoPtr); + // TODO + return 0; +} + +int sceFontGetCharImageRect(u32 fontHandle, u32 charCode, u32 charRectPtr) { + ERROR_LOG(HLE, "HACK sceFontGetCharImageRect(%08x, %i, %08x) (char: %c)", fontHandle, charCode, charRectPtr, (char)charCode); + if (!Memory::IsValidAddress(charRectPtr)) + return -1; + + PGFCharInfo charInfo; + LoadedFont *font = GetLoadedFont(fontHandle, false); + if (font) { + font->GetFont()->GetPGF()->GetCharInfo(charCode, &charInfo); + Memory::Write_U16(charInfo.bitmapWidth, charRectPtr); // character bitmap width in pixels + Memory::Write_U16(charInfo.bitmapHeight, charRectPtr + 2); // character bitmap height in pixels + } else { + ERROR_LOG(HLE, "sceFontGetCharImageRect - invalid font"); } return 0; } -int sceFontGetCharImageRect(u32 fontHandle, u32 charCode, u32 charRectPtr) -{ - ERROR_LOG(HLE, "HACK sceFontGetCharImageRect %x, %x (%c)", fontHandle, charRectPtr, charCode); - if (Memory::IsValidAddress(charRectPtr)) { - Memory::Write_U16(16, charRectPtr); // character bitmap width in pixels - Memory::Write_U16(16, charRectPtr + 2); // character bitmap height in pixels - } +int sceFontGetShadowImageRect(u32 fontHandle, u32 charCode, u32 charRectPtr) { + ERROR_LOG(HLE, "UNIMPL sceFontGetShadowImageRect()"); return 0; } -int sceFontGetCharGlyphImage(u32 fontHandle, u32 charCode, u32 glyphImagePtr) -{ - ERROR_LOG(HLE, "HACK sceFontGetCharGlyphImage %x, %x, %x (%c)", fontHandle, charCode, glyphImagePtr, charCode); +int sceFontGetCharGlyphImage(u32 fontHandle, u32 charCode, u32 glyphImagePtr) { + ERROR_LOG(HLE, "HACK sceFontGetCharGlyphImage(%x, %x, %x) (char: %c)", fontHandle, charCode, glyphImagePtr, (char)charCode); int pixelFormat = Memory::Read_U32(glyphImagePtr); int xPos64 = Memory::Read_U32(glyphImagePtr+4); @@ -326,74 +690,119 @@ int sceFontGetCharGlyphImage(u32 fontHandle, u32 charCode, u32 glyphImagePtr) int bytesPerLine = Memory::Read_U16(glyphImagePtr+16); int buffer = Memory::Read_U32(glyphImagePtr+20); - // Small chessboard. Does not respect pixelformat currently... + LoadedFont *font = GetLoadedFont(fontHandle, false); + int altCharCode = font->GetFontLib()->GetAltCharCode(); + font->GetFont()->GetPGF()->DrawCharacter(buffer, bytesPerLine, bufWidth, bufHeight, xPos64 >> 6, yPos64 >> 6, 0, 0, 8192, 8192, pixelFormat, charCode, altCharCode, FONT_PGF_CHARGLYPH); + return 0; +} - // Actually should be really easy to substitute in a proper font here... - // could even grab pixel data from the PPGe one. - for (int y = 0; y < bufHeight; y++) - { - for (int x = 0; x < bytesPerLine; x++) - { - Memory::Write_U8((((x >> 1) ^ (y >> 1)) & 1) ? 0xff : 0x00, buffer + (y * bytesPerLine + x)); - } +int sceFontGetCharGlyphImage_Clip(u32 fontHandle, u32 charCode, u32 glyphImagePtr, int clipXPos, int clipYPos, int clipWidth, int clipHeight) { + ERROR_LOG(HLE, "sceFontGetCharGlyphImage_Clip(%08x, %i, %08x, %i, %i, %i, %i) (%c)", fontHandle, charCode, glyphImagePtr, clipXPos, clipYPos, clipWidth, clipHeight, charCode); + + int pixelFormat = Memory::Read_U32(glyphImagePtr); + int xPos64 = Memory::Read_U32(glyphImagePtr+4); + int yPos64 = Memory::Read_U32(glyphImagePtr+8); + int bufWidth = Memory::Read_U16(glyphImagePtr+12); + int bufHeight = Memory::Read_U16(glyphImagePtr+14); + int bytesPerLine = Memory::Read_U16(glyphImagePtr+16); + int buffer = Memory::Read_U32(glyphImagePtr+20); + + LoadedFont *font = GetLoadedFont(fontHandle, false); + if (!font) { + ERROR_LOG(HLE, "%08x is not a valid font handle!", fontHandle); + return 0; } - + int altCharCode = font->GetFontLib()->GetAltCharCode(); + font->GetFont()->GetPGF()->DrawCharacter(buffer, bytesPerLine, bufWidth, bufHeight, xPos64 >> 6, yPos64 >> 6, clipXPos, clipYPos, clipXPos + clipWidth, clipYPos + clipHeight, pixelFormat, charCode, altCharCode, FONT_PGF_CHARGLYPH); return 0; } -int sceFontGetCharGlyphImage_Clip(u32 libHandler, u32 charCode, u32 glyphImagePtr, int clipXPos, int clipYPos, int clipWidth, int clipHeight) -{ - ERROR_LOG(HLE, "sceFontGetCharGlyphImage_Clip %x, %x, %x (%c)", libHandler, charCode, glyphImagePtr, charCode); - //sceFontGetCharGlyphImage(libHandler, charCode, glyphImagePtr); +int sceFontSetAltCharacterCode(u32 fontLibHandle, u32 charCode) { + INFO_LOG(HLE, "sceFontSetAltCharacterCode(%08x) (%c)", fontLibHandle, charCode); + FontLib *fl = GetFontLib(fontLibHandle); + if (fl) { + fl->SetAltCharCode(charCode); + } return 0; } -int sceFontSetAltCharacterCode(u32 libHandle, u32 charCode) -{ - ERROR_LOG(HLE, "sceFontSetAltCharacterCode %x (%c)", libHandle, charCode); +int sceFontFlush(u32 fontHandle) { + INFO_LOG(HLE, "sceFontFlush(%i)", fontHandle); + // Probably don't need to do anything here. return 0; } -int sceFontFlush(u32 fontHandle) -{ - DEBUG_LOG(HLE, "sceFontFlush(%i)", fontHandle); - return 0; -} - -int sceFontGetFontList(u32 fontLibHandle, u32 fontStylePtr, u32 numFonts) -{ - ERROR_LOG(HLE, "sceFontGetFontList %x, %x, %x", fontLibHandle, fontStylePtr, numFonts); - - FontStyle style; - memset(&style, 0, sizeof (style)); - - style.fontH = 20 / 64.f; - style.fontV = 20 / 64.f; - style.fontHRes = 20 / 64.f; - style.fontVRes = 20 / 64.f; - style.fontStyle = 1; - //style.fontFamily - +// One would think that this should loop through the fonts loaded in the fontLibHandle, +// but it seems not. +int sceFontGetFontList(u32 fontLibHandle, u32 fontStylePtr, u32 numFonts) { + ERROR_LOG(HLE, "sceFontGetFontList(%08x, %08x, %i)", fontLibHandle, fontStylePtr, numFonts); + numFonts = std::min(numFonts, (u32)internalFonts.size()); for (u32 i = 0; i < numFonts; i++) { - Memory::WriteStruct(fontStylePtr + (sizeof(style)) * i, &style); + PGFFontStyle style = internalFonts[i]->GetFontStyle(); + Memory::WriteStruct(fontStylePtr, &style); + fontStylePtr += sizeof(style); } return 0; } -int sceFontGetNumFontList(u32 libHandle, u32 errorCodePtr) -{ - ERROR_LOG(HLE, "UNIMPL sceFontGetNumFontList %x, %x", libHandle, errorCodePtr); +int sceFontGetNumFontList(u32 fontLibHandle, u32 errorCodePtr) { + INFO_LOG(HLE, "sceFontGetNumFontList(%08x, %08x)", fontLibHandle, errorCodePtr); if (Memory::IsValidAddress(errorCodePtr)) - { Memory::Write_U32(0, errorCodePtr); - } - return 1; + return internalFonts.size(); } -int sceFontSetResolution(u32 fontLibHandle, float hRes, float vRes) -{ - ERROR_LOG(HLE, "UNIMPL sceFontSetResolution(%i, %f, %f)", fontLibHandle, hRes, vRes); +int sceFontSetResolution(u32 fontLibHandle, float hRes, float vRes) { + INFO_LOG(HLE, "sceFontSetResolution(%08x, %f, %f)", fontLibHandle, hRes, vRes); + FontLib *fl = GetFontLib(fontLibHandle); + if (fl) { + fl->SetResolution(hRes, vRes); + } + return 0; +} + +float sceFontPixelToPointH(int fontLibHandle, float fontPixelsH, u32 errorCodePtr) { + INFO_LOG(HLE, "sceFontPixelToPointH(%08x, %f, %08x)", fontLibHandle, fontPixelsH, errorCodePtr); + if (Memory::IsValidAddress(errorCodePtr)) + Memory::Write_U32(0, errorCodePtr); + FontLib *fl = GetFontLib(fontLibHandle); + if (fl) { + return fontPixelsH * pointDPI / fl->FontHRes(); + } + return 0; +} + +float sceFontPixelToPointV(int fontLibHandle, float fontPixelsV, u32 errorCodePtr) { + INFO_LOG(HLE, "UNIMPL sceFontPixelToPointV(%08x, %f, %08x)", fontLibHandle, fontPixelsV, errorCodePtr); + if (Memory::IsValidAddress(errorCodePtr)) + Memory::Write_U32(0, errorCodePtr); + FontLib *fl = GetFontLib(fontLibHandle); + if (fl) { + return fontPixelsV * pointDPI / fl->FontVRes(); + } + return 0; +} + +float sceFontPointToPixelH(int fontLibHandle, float fontPointsH, u32 errorCodePtr) { + INFO_LOG(HLE, "UNIMPL sceFontPointToPixelH(%08x, %f, %08x)", fontLibHandle, fontPointsH, errorCodePtr); + if (Memory::IsValidAddress(errorCodePtr)) + Memory::Write_U32(0, errorCodePtr); + FontLib *fl = GetFontLib(fontLibHandle); + if (fl) { + return fontPointsH * fl->FontHRes() / pointDPI; + } + return 0; +} + +float sceFontPointToPixelV(int fontLibHandle, float fontPointsV, u32 errorCodePtr) { + INFO_LOG(HLE, "UNIMPL sceFontPointToPixelV(%08x, %f, %08x)", fontLibHandle, fontPointsV, errorCodePtr); + if (Memory::IsValidAddress(errorCodePtr)) + Memory::Write_U32(0, errorCodePtr); + FontLib *fl = GetFontLib(fontLibHandle); + if (fl) { + return fontPointsV * fl->FontVRes() / pointDPI; + } return 0; } @@ -402,10 +811,17 @@ int sceFontCalcMemorySize() { return 0; } +int sceFontGetShadowGlyphImage() { + ERROR_LOG(HLE, "UNIMPL sceFontGetShadowGlyphImage()"); + return 0; +} +int sceFontGetShadowGlyphImage_Clip() { + ERROR_LOG(HLE, "UNIMPL sceFontGetShadowGlyphImage_Clip()"); + return 0; +} -const HLEFunction sceLibFont[] = -{ +const HLEFunction sceLibFont[] = { {0x67f17ed7, WrapU_UU, "sceFontNewLib"}, {0x574b6fbc, WrapI_U, "sceFontDoneLib"}, {0x48293280, WrapI_UFF, "sceFontSetResolution"}, @@ -416,28 +832,27 @@ const HLEFunction sceLibFont[] = {0x2f67356a, WrapI_V, "sceFontCalcMemorySize"}, {0x5333322d, WrapI_UUUU, "sceFontGetFontInfoByIndexNumber"}, {0xa834319d, WrapU_UUUU, "sceFontOpen"}, - {0x57fcb733, WrapU_UUUU, "sceFontOpenUserFile"}, + {0x57fcb733, WrapU_UCUU, "sceFontOpenUserFile"}, {0xbb8e7fe6, WrapU_UUUU, "sceFontOpenUserMemory"}, {0x3aea8cb6, WrapI_U, "sceFontClose"}, {0x0da7535e, WrapI_UU, "sceFontGetFontInfo"}, {0xdcc80c2f, WrapI_UUU, "sceFontGetCharInfo"}, + {0xaa3de7b5, WrapI_UUU, "sceFontGetShadowInfo"}, {0x5c3e4a9e, WrapI_UUU, "sceFontGetCharImageRect"}, + {0x48b06520, WrapI_UUU, "sceFontGetShadowImageRect"}, {0x980f4895, WrapI_UUU, "sceFontGetCharGlyphImage"}, {0xca1e6945, WrapI_UUUIIII, "sceFontGetCharGlyphImage_Clip"}, - {0x74b21701, 0, "sceFontPixelToPointH"}, - {0xf8f0752e, 0, "sceFontPixelToPointV"}, - {0x472694cd, 0, "sceFontPointToPixelH"}, - {0x3c4b7e82, 0, "sceFontPointToPixelV"}, + {0x74b21701, WrapF_IFU, "sceFontPixelToPointH"}, + {0xf8f0752e, WrapF_IFU, "sceFontPixelToPointV"}, + {0x472694cd, WrapF_IFU, "sceFontPointToPixelH"}, + {0x3c4b7e82, WrapF_IFU, "sceFontPointToPixelV"}, {0xee232411, WrapI_UU, "sceFontSetAltCharacterCode"}, - {0xaa3de7b5, 0, "sceFontGetShadowInfo"}, - {0x48b06520, 0, "sceFontGetShadowImageRect"}, - {0x568be516, 0, "sceFontGetShadowGlyphImage"}, - {0x5dcf6858, 0, "sceFontGetShadowGlyphImage_Clip"}, + {0x568be516, WrapI_V, "sceFontGetShadowGlyphImage"}, + {0x5dcf6858, WrapI_V, "sceFontGetShadowGlyphImage_Clip"}, {0x02d7f94b, WrapI_U, "sceFontFlush"}, - }; -void Register_sceFont() -{ + +void Register_sceFont() { RegisterModule("sceLibFont", ARRAY_SIZE(sceLibFont), sceLibFont); } diff --git a/Core/HLE/sceFont.h b/Core/HLE/sceFont.h index 81d095c5bb..c8b8cf9b07 100644 --- a/Core/HLE/sceFont.h +++ b/Core/HLE/sceFont.h @@ -5,4 +5,5 @@ class PointerWrap; void Register_sceFont(); void __FontInit(); +void __FontShutdown(); void __FontDoState(PointerWrap &p); diff --git a/Core/HLE/sceIo.cpp b/Core/HLE/sceIo.cpp index b6899606e0..3e076e02b8 100644 --- a/Core/HLE/sceIo.cpp +++ b/Core/HLE/sceIo.cpp @@ -197,7 +197,7 @@ void __IoInit() { char path_buffer[_MAX_PATH], drive[_MAX_DRIVE] ,dir[_MAX_DIR], file[_MAX_FNAME], ext[_MAX_EXT]; char memstickpath[_MAX_PATH]; - char flashpath[_MAX_PATH]; + char flash0path[_MAX_PATH]; GetModuleFileName(NULL,path_buffer,sizeof(path_buffer)); @@ -210,24 +210,23 @@ void __IoInit() { // Mount a couple of filesystems sprintf(memstickpath, "%s%sMemStick\\", drive, dir); - sprintf(flashpath, "%s%sFlash\\", drive, dir); + sprintf(flash0path, "%s%sflash0\\", drive, dir); #else // TODO std::string memstickpath = g_Config.memCardDirectory; - std::string flashpath = g_Config.flashDirectory; + std::string flash0path = g_Config.flashDirectory; #endif - DirectoryFileSystem *memstick; - DirectoryFileSystem *flash; - memstick = new DirectoryFileSystem(&pspFileSystem, memstickpath); - flash = new DirectoryFileSystem(&pspFileSystem, flashpath); + DirectoryFileSystem *memstick = new DirectoryFileSystem(&pspFileSystem, memstickpath); + DirectoryFileSystem *flash0 = new DirectoryFileSystem(&pspFileSystem, flash0path); + DirectoryFileSystem *flash1 = new DirectoryFileSystem(&pspFileSystem, flash0path); pspFileSystem.Mount("ms0:", memstick); pspFileSystem.Mount("fatms0:", memstick); pspFileSystem.Mount("fatms:", memstick); - pspFileSystem.Mount("flash0:", flash); - pspFileSystem.Mount("flash1:", flash); + pspFileSystem.Mount("flash0:", flash0); + pspFileSystem.Mount("flash1:", flash1); __KernelListenThreadEnd(&TellFsThreadEnded); } diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp index 0fc342f1c3..3b31b7fbe3 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -128,6 +128,8 @@ void __KernelShutdown() INFO_LOG(HLE, "Shutting down kernel - %i kernel objects alive", kernelObjects.GetCount()); kernelObjects.Clear(); + __FontShutdown(); + __MpegShutdown(); __PsmfShutdown(); __PPGeShutdown(); diff --git a/Core/Util/BlockAllocator.cpp b/Core/Util/BlockAllocator.cpp index 227d28f1ab..abd5bf9cf1 100644 --- a/Core/Util/BlockAllocator.cpp +++ b/Core/Util/BlockAllocator.cpp @@ -1,3 +1,20 @@ +// Copyright (c) 2012- PPSSPP Project. + +// 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, version 2.0 or later versions. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + #include "Log.h" #include "BlockAllocator.h" #include "ChunkFile.h" diff --git a/Core/Util/BlockAllocator.h b/Core/Util/BlockAllocator.h index 98cb3e1cd2..b385fedcb9 100644 --- a/Core/Util/BlockAllocator.h +++ b/Core/Util/BlockAllocator.h @@ -1,3 +1,19 @@ +// Copyright (c) 2012- PPSSPP Project. + +// 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, version 2.0 or later versions. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #pragma once @@ -9,8 +25,7 @@ class PointerWrap; -// Generic allocator thingy -// Allocates blocks from a range +// Generic allocator thingy. Allocates blocks from a range. class BlockAllocator { diff --git a/Core/Util/Pool.h b/Core/Util/Pool.h deleted file mode 100644 index dee8633c10..0000000000 --- a/Core/Util/Pool.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include "../../Globals.h" - -// pool allocator -template -class Pool -{ - T pool[size]; - int count; -public: - Pool() - { - Reset(); - } - void Reset() - { - count=0; - } - T* Alloc() - { - _dbg_assert_msg_(CPU,count