Vita: System fonts at least draw something now

This commit is contained in:
UnknownShadow200 2023-08-23 20:23:16 +10:00
parent 38dfc3ae32
commit 93f941e217
2 changed files with 303 additions and 19 deletions

View file

@ -13,23 +13,27 @@ ClassiCube runs on:
* iOS - 10.3 or later
* Most web browsers (even runs on IE11)
And also runs on:
* Raspberry Pi - needs `libcurl` and `libopenal`
* FreeBSD - needs `libexecinfo`, `curl` and `openal-soft` packagea
* NetBSD - needs `libexecinfo`, `curl` and `openal-soft` packages
* OpenBSD - needs `libexecinfo`, `curl` and `openal` packages
* Solaris - needs `curl` and `openal` packages
* Haiku - needs `openal` package
* BeOS - untested on actual hardware
* IRIX - needs `curl` and `openal` packages
* SerenityOS - needs SDL2
* 3DS - unfinished, but [usable](https://github.com/UnknownShadow200/ClassiCube/actions/workflows/build_3ds.yml)
* Wii - unfinished, but [usable](https://github.com/UnknownShadow200/ClassiCube/actions/workflows/build_wiigc.yml)
* GameCube - unfinished, but [usable](https://github.com/UnknownShadow200/ClassiCube/actions/workflows/build_wiigc.yml)
* PSP - unfinished, rendering issues
* Dreamcast - unfinished, but renders
* PS Vita - majorly unfinished
* Xbox - majorly unfinished
<details>
<summary>And also runs on:</summary>
<ul>
<li> Raspberry Pi - needs <code>libcurl</code> and <code>libopenal</code> </li>
<li> FreeBSD - needs <code>libexecinfo</code>, <code>curl</code> and <code>openal-soft</code> packages </li>
<li> NetBSD - needs <code>libexecinfo</code>, <code>curl</code> and <code>openal-soft</code> packages </li>
<li> OpenBSD - needs <code>libexecinfo</code>, <code>curl</code> and <code>openal</code> packages </li>
<li> Solaris - needs <code>curl</code> and <code>openal</code> packages </li>
<li> Haiku - needs <code>openal</code> package </li>
<li> BeOS - untested on actual hardware </li>
<li> IRIX - needs <code>curl</code> and <code>openal</code> packages </li>
<li> SerenityOS - needs <code>SDL2</code> </li>
<li> 3DS - unfinished, but <a href="https://github.com/UnknownShadow200/ClassiCube/actions/workflows/build_3ds.yml">usable</a> </li>
<li> Wii - unfinished, but <a href="https://github.com/UnknownShadow200/ClassiCube/actions/workflows/build_wiigc.yml">usable</a> </li>
<li> GameCube - unfinished, but <a href="https://github.com/UnknownShadow200/ClassiCube/actions/workflows/build_wiigc.yml">usable</a> </li>
<li> PSP - unfinished, rendering issues </li>
<li> Dreamcast - unfinished, but renders </li>
<li> PS Vita - majorly unfinished </li>
<li> Xbox - majorly unfinished </li>
</ul>
</details>
You can download ClassiCube [from here](https://www.classicube.net/download/) and the very latest builds [from here](https://www.classicube.net/nightlies/).
@ -47,6 +51,9 @@ If you're interested in documenting or verifying the behaviour of the original M
* Lightweight, minimal memory usage compared to original Minecraft Classic
* Much better performance than original Minecraft Classic
* Works with effectively all graphics cards that support OpenGL or Direct3D 9
* Runs on Windows, macOS, Linux, Android, iOS, and in a web browser
* Also runs on OpenBSD, FreeBSD, NetBSD, Solaris, Haiku, IRIX, SerenityOS
* Although still work in progresses, also runs on various consoles
#### What ClassiCube isn't
* It does not work with Minecraft Java or Bedrock edition servers

View file

@ -721,7 +721,7 @@ int SysFont_TextWidth(struct DrawTextArgs* args) {
void SysFont_DrawText(struct DrawTextArgs* args, struct Bitmap* bmp, int x, int y, cc_bool shadow) {
interop_SysTextDraw(args, bmp, x, y, shadow);
}
#elif defined CC_BUILD_PSP || defined CC_BUILD_PSVITA
#elif defined CC_BUILD_PSP
void SysFonts_Register(const cc_string* path) { }
const cc_string* SysFonts_UNSAFE_GetDefault(void) { return &String_Empty; }
@ -1118,4 +1118,281 @@ void SysFont_DrawText(struct DrawTextArgs* args, struct Bitmap* bmp, int x, int
}
}
}
#endif
#elif defined CC_BUILD_PSVITA
#include <vitasdk.h>
struct SysFont {
ScePvfFontId fontID;
};
#define TEXT_CEIL(x) (((x) + 63) >> 6)
static void* lib_handle;
static int inited;
#define ALIGNUP4(x) (((x) + 3) & ~0x03)
static void* Pvf_Alloc(void* userdata, unsigned int size) {
return Mem_TryAlloc(ALIGNUP4(size), 1);
}
static void* Pvf_Realloc(void* userdata, void* old_ptr, unsigned int size) {
return Mem_TryRealloc(old_ptr, ALIGNUP4(size), 1);
}
static void Pvf_Free(void* userdata, void* ptr) {
Mem_Free(ptr);
}
static void InitPvfLib(void) {
if (inited) return;
inited = true;
ScePvfInitRec params = {
NULL, SCE_PVF_MAX_OPEN, NULL, NULL,
Pvf_Alloc, Pvf_Realloc, Pvf_Free
};
ScePvfError error = 0;
lib_handle = scePvfNewLib(&params, &error);
if (error) {
Platform_Log1("PVF ERROR: %i", &error);
return;
}
for (int i = 0; i < 128; i++)
{
ScePvfFontStyleInfo fs;
error = scePvfGetFontInfoByIndexNumber(lib_handle, &fs, i);
if (error) {
Platform_Log1("PVF F ERROR: %i", &error); continue;
}
Platform_Log4("FONT %i = %c / %c / %c", &i, fs.fontName, fs.styleName, fs.fileName);
int FC = fs. familyCode;
int ST = fs. style;
int LC = fs. languageCode;
int RC = fs. regionCode;
int CC = fs. countryCode;
Platform_Log2("F_STYLE: %i, %i", &FC, &ST);
Platform_Log3("F_CODES: %i, %i, %i", &LC, &RC, &CC);
}
Platform_LogConst("--pgf fonts");
}
void SysFonts_Register(const cc_string* path) { }
const cc_string* SysFonts_UNSAFE_GetDefault(void) { return &String_Empty; }
void SysFonts_GetNames(struct StringsBuffer* buffer) {
InitPvfLib();
if (!lib_handle) return;
ScePvfError error = 0;
int count = scePvfGetNumFontList(lib_handle, &error);
if (error) return;
for (int i = 0; i < count; i++)
{
ScePvfFontStyleInfo fs;
error = scePvfGetFontInfoByIndexNumber(lib_handle, &fs, i);
if (error) { Platform_Log1("PVF ERROR: %i", &error); continue; }
if (fs.languageCode == SCE_PVF_LANGUAGE_LATIN) {
cc_string name = String_FromRawArray(fs.fileName);
StringsBuffer_Add(buffer, &name);
}
}
}
static ScePvfFontIndex FindFontByName(const cc_string* fontName) {
ScePvfError error = 0;
int count = scePvfGetNumFontList(lib_handle, &error);
if (error) return -1;
for (int i = 0; i < count; i++)
{
ScePvfFontStyleInfo fs;
error = scePvfGetFontInfoByIndexNumber(lib_handle, &fs, i);
if (error) { Platform_Log1("PVF FBN ERROR: %i", &error); continue; }
cc_string name = String_FromRawArray(fs.fileName);
if (String_CaselessEquals(fontName, &name)) return i;
}
return -1;
}
static ScePvfFontIndex FindDefaultFont(void) {
ScePvfFontStyleInfo style = { 0 };
style.languageCode = SCE_PVF_LANGUAGE_LATIN;
ScePvfError error = 0;
int index = scePvfFindOptimumFont(lib_handle, &style, &error);
if (error) { Platform_Log1("PVF FDF ERROR: %i", &error); index = -1; }
return index;
}
static cc_result MakeSysFont(struct FontDesc* desc, const cc_string* fontName, int size, int flags) {
desc->size = size;
desc->flags = flags;
desc->height = Drawer2D_AdjHeight(size);
InitPvfLib();
if (!lib_handle) return ERR_NOT_SUPPORTED;
struct SysFont* font = Mem_AllocCleared(sizeof(struct SysFont), 1, "font");
desc->handle = font;
ScePvfFontIndex idx = -1;
if (fontName) {
idx = FindFontByName(fontName);
} else {
idx = FindDefaultFont();
}
if (idx == -1) return ERR_INVALID_ARGUMENT;
ScePvfError error = 0;
font->fontID = scePvfOpen(lib_handle, idx, 1, &error);
Platform_Log1("FONT ID: %i", &font->fontID);
if (!error) scePvfSetCharSize(font->fontID, size, size);
return error;
}
cc_result SysFont_Make(struct FontDesc* desc, const cc_string* fontName, int size, int flags) {
return MakeSysFont(desc, fontName, size, flags);
}
void SysFont_MakeDefault(struct FontDesc* desc, int size, int flags) {
cc_result res = MakeSysFont(desc, NULL, size, flags);
if (res) Logger_Abort2(res, "Failed to init default font");
}
void SysFont_Free(struct FontDesc* desc) {
struct SysFont* font = (struct SysFont*)desc->handle;
if (font->fontID) scePvfClose(font->fontID);
Mem_Free(font);
}
int SysFont_TextWidth(struct DrawTextArgs* args) {
struct SysFont* font = (struct SysFont*)args->font->handle;
ScePvfCharInfo charInfo;
cc_string left = args->text, part;
char colorCode = 'f';
int width = 0;
while (Drawer2D_UNSAFE_NextPart(&left, &part, &colorCode))
{
for (int i = 0; i < part.length; i++)
{
// TODO optimise
ScePvfError error = scePvfGetCharInfo(font->fontID, (cc_uint8)part.buffer[i], &charInfo);
if (error) { Platform_Log1("PVF TW ERROR: %i", &error); continue; }
width += charInfo.glyphMetrics.horizontalAdvance64;
}
}
width = TEXT_CEIL(width);
Platform_Log2("TEXT WIDTH: %i (%s)", &width, &args->text);
if (args->useShadow) width += 2;
return max(1, width);
}
// TODO optimise
static void RasteriseGlyph(ScePvfUserImageBufferRec* glyph, struct Bitmap* bmp, int x, int y) {
cc_uint8* src = glyph->buffer;
int glyphHeight = glyph->rect.height;
int glyphWidth = glyph->rect.width;
for (int glyphY = 0; glyphY < glyphHeight; glyphY++)
{
int dstY = glyphY + y;
if (dstY < 0 || dstY >= bmp->height) continue;
for (int glyphX = 0; glyphX < glyphWidth; glyphX++)
{
int dstX = glyphX + x;
if (dstX < 0 || dstX >= bmp->width) continue;
cc_uint8 I = src[glyphY * glyphWidth + glyphX];
Bitmap_GetPixel(bmp, dstX, dstY) = BitmapCol_Make(I, I, I, 255);
}
}
}
// TODO optimise
// See https://freetype.org/freetype2/docs/glyphs/glyphs-3.html
static int DrawGlyph(struct SysFont* font, struct Bitmap* bmp, int x, int y, cc_uint8 c) {
ScePvfCharInfo charInfo;
ScePvfIrect charRect;
ScePvfError error;
error = scePvfGetCharInfo(font->fontID, c, &charInfo);
if (error) { Platform_Log1("PVF DG_GCI ERROR: %i", &error); return 0; }
error = scePvfGetCharImageRect(font->fontID, c, &charRect);
if (error) { Platform_Log1("PVF DG_GCIR ERROR: %i", &error); return 0; }
ScePvfUserImageBufferRec glyph = { 0 };
cc_uint8* tmp = Mem_Alloc(charRect.width * charRect.height, 1, "temp font bitmap");
glyph.pixelFormat = SCE_PVF_USERIMAGE_DIRECT8;
glyph.rect.width = charRect.width;
glyph.rect.height = charRect.height;
glyph.bytesPerLine = charRect.width;
glyph.buffer = tmp;
// TODO: use charInfo.glyphMetrics.horizontalBearingX64 and Y64
Platform_Log1("ABOUT %r:", &c);
int BX = charInfo.glyphMetrics.horizontalBearingX64;
int BY = charInfo.glyphMetrics.horizontalBearingY64;
//Platform_Log4(" Bitmap: %i,%i --> %i, %i", &charInfo.bitmapLeft, &charInfo.bitmapTop, &charInfo.bitmapWidth, &charInfo.bitmapHeight);
int W = charInfo.glyphMetrics.width64, W2 =TEXT_CEIL(W);
int H = charInfo.glyphMetrics.height64, H2 =TEXT_CEIL(H);
int A = charInfo.glyphMetrics.ascender64, A2 =TEXT_CEIL(A);
int D = charInfo.glyphMetrics.descender64, D2 =TEXT_CEIL(D);
Platform_Log4(" Size: %i,%i (%i, %i)", &W, &H, &W2, &H2);
Platform_Log4(" Vert: %i,%i (%i, %i)", &A, &D, &A2, &D2);
Platform_Log2(" Bearings: %i,%i", &BX, &BY);
int CW = charRect.width, CH = charRect.height;
Platform_Log2(" CharSize: %i,%i", &CW, &CH);
error = scePvfGetCharGlyphImage(font->fontID, c, &glyph);
if (!error) RasteriseGlyph(&glyph, bmp, x, y);
Mem_Free(tmp);
if (error) { Platform_Log1("PVF DG_CCGI ERROR: %i", &error); return 0; }
return TEXT_CEIL(charInfo.glyphMetrics.horizontalAdvance64);
}
// TODO better shadow support
void SysFont_DrawText(struct DrawTextArgs* args, struct Bitmap* bmp, int x, int y, cc_bool shadow) {
struct SysFont* font = (struct SysFont*)args->font->handle;
if (shadow) return;//{ x += 2; y += 2; }
cc_string left = args->text, part;
char colorCode = 'f';
BitmapCol color;
while (Drawer2D_UNSAFE_NextPart(&left, &part, &colorCode))
{
color = Drawer2D_GetColor(colorCode);
if (shadow) color = GetShadowColor(color);
for (int i = 0; i < part.length; i++)
{
x += DrawGlyph(font, bmp, x, y, (cc_uint16)part.buffer[i]);
}
}
}
#endif