mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-01-22 09:01:57 -05:00
Vita: System fonts at least draw something now
This commit is contained in:
parent
38dfc3ae32
commit
93f941e217
2 changed files with 303 additions and 19 deletions
41
readme.md
41
readme.md
|
@ -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
|
||||
|
|
|
@ -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(¶ms, &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
|
||||
|
|
Loading…
Reference in a new issue