Finish up non english fonts
This commit is contained in:
parent
3bfe6f4a76
commit
f2f94ed7af
1
Makefile
1
Makefile
|
@ -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
|
@ -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–—‘’“”„…
|
||||
ÀÁÂÃÄÅÆÇÈÉÊÍÎÑÓÔÖØÚÜÝßàáâãäåæçèéêëìíîïñòóôõöøùúûüýĂ㥹ćČčďĘęĚěĞğİıŁłŃń
|
||||
ŇňŐőŘřŚśŞşŠšŢţťůűźŻżŽžȘșțΆΈΉΊΌΏΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΩάέήίΰαβγδεζηθικλ
|
||||
|
|
|
@ -4,5 +4,6 @@
|
|||
#include "font.h"
|
||||
|
||||
extern struct Font gDejaVuSansFont;
|
||||
extern Gfx* gDejaVuSansImages[];
|
||||
|
||||
#endif
|
11
src/font/dejavusans_images.c
Normal file
11
src/font/dejavusans_images.c
Normal 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,
|
||||
};
|
166
src/font/font.c
166
src/font/font.c
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)))}")
|
||||
|
||||
|
|
Loading…
Reference in a new issue