Finish up non english fonts

This commit is contained in:
James Lambert 2023-10-28 19:24:21 -06:00
parent 3bfe6f4a76
commit f2f94ed7af
9 changed files with 3921 additions and 740 deletions

View file

@ -335,6 +335,7 @@ build/src/menu/save_game_menu.o: build/src/audio/clips.h
build/src/scene/scene_animator.o: build/src/audio/clips.h
build/src/levels/intro.o: build/src/audio/clips.h build/assets/materials/images.h
build/src/menu/savefile_list.o: build/assets/materials/ui.h build/src/audio/clips.h
build/src/font/dejavusans_images.o: build/assets/materials/ui.h
build/src/player/player.o: build/assets/models/player/chell.h build/assets/materials/static.h build/src/audio/subtitles.h
build/src/scene/ball_catcher.o: build/assets/models/props/combine_ball_catcher.h build/assets/materials/static.h build/assets/models/dynamic_animated_model_list.h
build/src/scene/ball_launcher.o: build/assets/models/props/combine_ball_launcher.h build/assets/materials/static.h build/assets/models/dynamic_animated_model_list.h

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,6 @@
Below are the characters used in each of the font pages
Note that the space charcter is intentionally left in the first group
/¡¿!%'()*,-.0123456789:;<>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]abcdefghijklmnopqrstuvwxyz“”„…
ÀÁÂÃÄÅÆÇÈÉÊÍÎÑÓÔÖØÚÜÝßàáâãäåæçèéêëìíîïñòóôõöøùúûüýĂ㥹ćČčďĘęĚěĞğİıŁłŃń
ŇňŐőŘřŚśŞşŠšŢţťůűźŻżŽžȘșțΆΈΉΊΌΏΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΩάέήίΰαβγδεζηθικλ

View file

@ -4,5 +4,6 @@
#include "font.h"
extern struct Font gDejaVuSansFont;
extern Gfx* gDejaVuSansImages[];
#endif

View file

@ -0,0 +1,11 @@
#include "dejavusans.h"
#include "../build/assets/materials/ui.h"
Gfx* gDejaVuSansImages[] = {
ui_dejavu_sans_0,
ui_dejavu_sans_1,
ui_dejavu_sans_2,
ui_dejavu_sans_3,
ui_dejavu_sans_4,
};

View file

@ -1,5 +1,7 @@
#include "font.h"
#define TEXTURE_IMAGE_INDEX_TO_MASK(index) (1 << (index))
int fontDetermineKerning(struct Font* font, short first, short second) {
unsigned index = ((unsigned)first * (unsigned)font->kerningMultiplier + (unsigned)second) & (unsigned)font->kerningMask;
int maxIterations = font->kerningMaxCollisions;
@ -23,13 +25,13 @@ int fontDetermineKerning(struct Font* font, short first, short second) {
}
struct FontSymbol* fontFindSymbol(struct Font* font, short id) {
unsigned index = ((unsigned)id * (unsigned)font->symbolMultiplier) & (unsigned)font->kerningMask;
unsigned index = ((unsigned)id * (unsigned)font->symbolMultiplier) & (unsigned)font->symbolMask;
int maxIterations = font->symbolMaxCollisions;
do {
struct FontSymbol* symbol = &font->symbols[index];
if (symbol->id == 0) {
if (symbol->textureIndex == -1) {
return NULL;
}
@ -143,4 +145,164 @@ struct Vector2s16 fontMeasure(struct Font* font, char* message) {
result.y = y + font->charHeight;
return result;
}
short fontNextUtf8Character(char** strPtr) {
char* curr = *strPtr;
// in the middle of a code point
// try to find the start of a charcter
while ((*curr & 0xC0) == 0x80) {
++curr;
}
if (!(*curr & 0x80)) {
*strPtr = curr + 1;
return *curr;
}
if ((*curr & 0xE0) == 0xC0) {
*strPtr = curr + 2;
return ((short)(curr[0] & 0x1F) << 6) | (short)(curr[1] & 0x3F);
} else if ((*curr & 0xF0) == 0xE0) {
*strPtr = curr + 3;
return ((short)(curr[0] & 0xF) << 12) | ((short)(curr[1] & 0x3F) << 6) | (short)(curr[2] & 0x3F);
} else if ((*curr & 0xF8) == 0xF0) {
*strPtr = curr + 4;
// utf character out of range of a short
return 0;
} else {
// invalid unicode character
*strPtr = curr + 1;
return 0;
}
}
int fontRendererFindBreak(struct FontRenderer* renderer) {
for (int search = renderer->currentSymbol - 1; search > 0; --search) {
if (renderer->symbols[search].canBreak) {
return search + 1;
}
}
return renderer->currentSymbol - 1;
}
void fontRendererWrap(struct FontRenderer* renderer, int from, int xOffset, int yOffset) {
for (int i = from; i < renderer->currentSymbol; ++i) {
renderer->symbols[i].x += xOffset;
renderer->symbols[i].y += yOffset;
}
}
void fontRendererLayout(struct FontRenderer* renderer, struct Font* font, char* message, int maxWidth) {
renderer->width = 0;
renderer->height = 0;
renderer->currentSymbol = 0;
renderer->usedImageIndices = 0;
short prev = 0;
short curr = 0;
int x = 0;
int y = 0;
int currentMaxWidth = 0;
while (*message && renderer->currentSymbol < FONT_RENDERER_MAX_SYBMOLS) {
prev = curr;
// also advances message to the next character
curr = fontNextUtf8Character(&message);
if (curr == '\n') {
currentMaxWidth = MAX(currentMaxWidth, x);
y += font->charHeight;
x = 0;
continue;
}
struct FontSymbol* symbol = fontFindSymbol(font, curr);
if (!symbol) {
continue;
}
x += fontDetermineKerning(font, prev, curr);
struct SymbolLocation* target = &renderer->symbols[renderer->currentSymbol];
target->x = x + symbol->xoffset;
target->y = y + symbol->yoffset;
target->width = symbol->width;
target->height = symbol->height;
target->canBreak = curr == ' ';
target->sourceX = symbol->x;
target->sourceY = symbol->y;
target->imageIndex = symbol->textureIndex;
renderer->usedImageIndices |= TEXTURE_IMAGE_INDEX_TO_MASK(symbol->textureIndex);
++renderer->currentSymbol;
x += symbol->xadvance;
if (x > maxWidth) {
int breakAt = fontRendererFindBreak(renderer);
if (breakAt == renderer->currentSymbol) {
currentMaxWidth = MAX(currentMaxWidth, x);
y += font->charHeight;
x = 0;
} else {
int lastCharacterX = renderer->symbols[breakAt].x;
currentMaxWidth = MAX(currentMaxWidth, lastCharacterX);
fontRendererWrap(renderer, breakAt, -lastCharacterX, font->charHeight);
y += font->charHeight;
x -= lastCharacterX;
}
}
}
renderer->width = MAX(currentMaxWidth, x);
renderer->height = y + font->charHeight;
}
Gfx* fontRendererBuildGfx(struct FontRenderer* renderer, struct Font* font, Gfx** fontImages, int x, int y, struct Coloru8* color, Gfx* gfx) {
int imageMask = renderer->usedImageIndices;
int imageIndex = 0;
while (imageMask) {
if (imageMask & 0x1) {
gSPDisplayList(gfx++, fontImages[imageIndex]);
if (color) {
gDPSetEnvColor(gfx++, color->r, color->g, color->b, color->a);
}
for (int i = 0; i < renderer->currentSymbol; ++i) {
struct SymbolLocation* target = &renderer->symbols[i];
if (target->imageIndex != imageIndex) {
continue;
}
int finalX = target->x + x;
int finalY = target->y + y;
gSPTextureRectangle(
gfx++,
finalX << 2, finalY << 2,
(finalX + target->width) << 2,
(finalY + target->height) << 2,
G_TX_RENDERTILE,
target->sourceX << 5, target->sourceY << 5,
0x400, 0x400
);
}
}
imageMask >>= 1;
++imageIndex;
}
return gfx;
}

View file

@ -3,6 +3,7 @@
#include <ultra64.h>
#include "../math/vector2s16.h"
#include "../graphics/color.h"
struct FontKerning {
char amount;
@ -22,7 +23,6 @@ struct FontSymbol {
struct Font {
struct FontKerning* kerning;
struct FontSymbol* symbols;
Gfx* images;
char base;
char charHeight;
@ -35,22 +35,33 @@ struct Font {
unsigned short kerningMaxCollisions;
};
struct SymbolLocation {
short x;
short y;
short symbolIndex;
};
// legacy methods for a font that fits into a single page
Gfx* fontRender(struct Font* font, char* message, int x, int y, Gfx* dl);
int fontCountGfx(struct Font* font, char* message);
struct Vector2s16 fontMeasure(struct Font* font, char* message);
struct FontRenderer {
struct SymbolLocation symbols[128];
short currentSymbol;
struct SymbolLocation {
short x;
short y;
char sourceX;
char sourceY;
char width;
char height;
char canBreak;
char imageIndex;
};
void fontRendererRender(struct FontRenderer* renderer, struct Font* font, char* message, int x, int y, int maxWidth);
Gfx* fontRendererBuildGfx(struct FontRenderer* renderer, struct Font* font, Gfx* gfx);
#define FONT_RENDERER_MAX_SYBMOLS 128
struct FontRenderer {
struct SymbolLocation symbols[FONT_RENDERER_MAX_SYBMOLS];
short currentSymbol;
short width;
short height;
short usedImageIndices;
};
void fontRendererLayout(struct FontRenderer* renderer, struct Font* font, char* message, int maxWidth);
Gfx* fontRendererBuildGfx(struct FontRenderer* renderer, struct Font* font, Gfx** fontImages, int x, int y, struct Coloru8* color, Gfx* gfx);
#endif

View file

@ -4,6 +4,7 @@
#include "../font/font.h"
#include "../controls/controller.h"
#include "../audio/soundplayer.h"
#include "../util/memory.h"
#include "../build/assets/materials/ui.h"
@ -513,7 +514,8 @@ void controlsRenderPrompt(enum ControllerAction action, char* message, float opa
}
void controlsRenderSubtitle(char* message, float textOpacity, float backgroundOpacity, struct RenderState* renderState, enum SubtitleType subtitleType) {
struct Vector2s16 size = fontMeasure(&gDejaVuSansFont, message);
struct FontRenderer* fontRender = stackMalloc(sizeof(struct FontRenderer));
fontRendererLayout(fontRender, &gDejaVuSansFont, message, SCREEN_WD - (SUBTITLE_SIDE_MARGIN + SUBTITLE_PADDING) * 2);
int textOpacityAsInt = (int)(255 * textOpacity);
@ -532,7 +534,7 @@ void controlsRenderSubtitle(char* message, float textOpacity, float backgroundOp
}
int textPositionX = (SUBTITLE_SIDE_MARGIN + SUBTITLE_PADDING);
int textPositionY = (SCREEN_HT - SUBTITLE_BOTTOM_MARGIN - SUBTITLE_PADDING) - size.y;
int textPositionY = (SCREEN_HT - SUBTITLE_BOTTOM_MARGIN - SUBTITLE_PADDING) - fontRender->height;
gSPDisplayList(renderState->dl++, ui_material_list[SOLID_TRANSPARENT_OVERLAY_INDEX]);
gDPSetEnvColor(renderState->dl++, 0, 0, 0, backgroundOpacityAsInt);
@ -545,19 +547,21 @@ void controlsRenderSubtitle(char* message, float textOpacity, float backgroundOp
);
gSPDisplayList(renderState->dl++, ui_material_revert_list[SOLID_TRANSPARENT_OVERLAY_INDEX]);
gSPDisplayList(renderState->dl++, ui_material_list[DEJAVU_SANS_0_INDEX]);
if (subtitleType == SubtitleTypeCloseCaption){
gDPSetEnvColor(renderState->dl++, 255, 140, 155, textOpacityAsInt);
} else if (subtitleType == SubtitleTypeCaption){
gDPSetEnvColor(renderState->dl++, 255, 255, 255, textOpacityAsInt);
struct Coloru8 textColor;
if (subtitleType == SubtitleTypeCloseCaption) {
textColor.r = 255;
textColor.g = 140;
textColor.b = 155;
} else if (subtitleType == SubtitleTypeCaption) {
textColor = gColorWhite;
}
renderState->dl = fontRender(
&gDejaVuSansFont,
message,
textPositionX,
textPositionY,
renderState->dl
);
textColor.a = textOpacityAsInt;
renderState->dl = fontRendererBuildGfx(fontRender, &gDejaVuSansFont, gDejaVuSansImages, textPositionX, textPositionY, &textColor, renderState->dl);
gSPDisplayList(renderState->dl++, ui_material_revert_list[DEJAVU_SANS_0_INDEX]);
stackMallocFree(fontRender);
}

View file

@ -60,20 +60,8 @@ def get_caption_keys_values_language(lines):
val = val.replace("<sfx>", "")
val = re.sub(r'\<len:.+\>','',val)
val = val.replace("<len>", "")
newval = ""
last_space = 0
addition = 0
for i,ch in enumerate(val):
if (i%38 == 0) and (i != 0):
newval = newval[:last_space+addition] + '\\n' + newval[last_space+addition+1:]
addition += 1
newval = newval + ch
else:
if ch == " ":
last_space = i
newval = newval + ch
keys.append(key)
values.append(newval)
values.append(val)
return keys, values, language
@ -155,7 +143,7 @@ def determine_invalid_characters(lang_name, lang_lines, good_characters):
invalid = used_characters - good_characters
if len(invalid) == 0:
return
return used_characters
print(f"{lang_name} has {len(invalid)} invalid charcters\n{''.join(sorted(list(invalid)))}")