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/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/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/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/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_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
|
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–—‘’“”„…
|
/¡¿!%'()*,-.0123456789:;<>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]abcdefghijklmnopqrstuvwxyz–—‘’“”„…
|
||||||
ÀÁÂÃÄÅÆÇÈÉÊÍÎÑÓÔÖØÚÜÝßàáâãäåæçèéêëìíîïñòóôõöøùúûüýĂ㥹ćČčďĘęĚěĞğİıŁłŃń
|
ÀÁÂÃÄÅÆÇÈÉÊÍÎÑÓÔÖØÚÜÝßàáâãäåæçèéêëìíîïñòóôõöøùúûüýĂ㥹ćČčďĘęĚěĞğİıŁłŃń
|
||||||
ŇňŐőŘřŚśŞşŠšŢţťůűźŻżŽžȘșțΆΈΉΊΌΏΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΩάέήίΰαβγδεζηθικλ
|
ŇňŐőŘřŚśŞşŠšŢţťůűźŻżŽžȘșțΆΈΉΊΌΏΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΩάέήίΰαβγδεζηθικλ
|
||||||
|
|
|
@ -4,5 +4,6 @@
|
||||||
#include "font.h"
|
#include "font.h"
|
||||||
|
|
||||||
extern struct Font gDejaVuSansFont;
|
extern struct Font gDejaVuSansFont;
|
||||||
|
extern Gfx* gDejaVuSansImages[];
|
||||||
|
|
||||||
#endif
|
#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"
|
#include "font.h"
|
||||||
|
|
||||||
|
#define TEXTURE_IMAGE_INDEX_TO_MASK(index) (1 << (index))
|
||||||
|
|
||||||
int fontDetermineKerning(struct Font* font, short first, short second) {
|
int fontDetermineKerning(struct Font* font, short first, short second) {
|
||||||
unsigned index = ((unsigned)first * (unsigned)font->kerningMultiplier + (unsigned)second) & (unsigned)font->kerningMask;
|
unsigned index = ((unsigned)first * (unsigned)font->kerningMultiplier + (unsigned)second) & (unsigned)font->kerningMask;
|
||||||
int maxIterations = font->kerningMaxCollisions;
|
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) {
|
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;
|
int maxIterations = font->symbolMaxCollisions;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
struct FontSymbol* symbol = &font->symbols[index];
|
struct FontSymbol* symbol = &font->symbols[index];
|
||||||
|
|
||||||
if (symbol->id == 0) {
|
if (symbol->textureIndex == -1) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,4 +145,164 @@ struct Vector2s16 fontMeasure(struct Font* font, char* message) {
|
||||||
result.y = y + font->charHeight;
|
result.y = y + font->charHeight;
|
||||||
|
|
||||||
return result;
|
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 <ultra64.h>
|
||||||
#include "../math/vector2s16.h"
|
#include "../math/vector2s16.h"
|
||||||
|
#include "../graphics/color.h"
|
||||||
|
|
||||||
struct FontKerning {
|
struct FontKerning {
|
||||||
char amount;
|
char amount;
|
||||||
|
@ -22,7 +23,6 @@ struct FontSymbol {
|
||||||
struct Font {
|
struct Font {
|
||||||
struct FontKerning* kerning;
|
struct FontKerning* kerning;
|
||||||
struct FontSymbol* symbols;
|
struct FontSymbol* symbols;
|
||||||
Gfx* images;
|
|
||||||
|
|
||||||
char base;
|
char base;
|
||||||
char charHeight;
|
char charHeight;
|
||||||
|
@ -35,22 +35,33 @@ struct Font {
|
||||||
unsigned short kerningMaxCollisions;
|
unsigned short kerningMaxCollisions;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SymbolLocation {
|
// legacy methods for a font that fits into a single page
|
||||||
short x;
|
|
||||||
short y;
|
|
||||||
short symbolIndex;
|
|
||||||
};
|
|
||||||
|
|
||||||
Gfx* fontRender(struct Font* font, char* message, int x, int y, Gfx* dl);
|
Gfx* fontRender(struct Font* font, char* message, int x, int y, Gfx* dl);
|
||||||
int fontCountGfx(struct Font* font, char* message);
|
int fontCountGfx(struct Font* font, char* message);
|
||||||
struct Vector2s16 fontMeasure(struct Font* font, char* message);
|
struct Vector2s16 fontMeasure(struct Font* font, char* message);
|
||||||
|
|
||||||
struct FontRenderer {
|
struct SymbolLocation {
|
||||||
struct SymbolLocation symbols[128];
|
short x;
|
||||||
short currentSymbol;
|
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);
|
#define FONT_RENDERER_MAX_SYBMOLS 128
|
||||||
Gfx* fontRendererBuildGfx(struct FontRenderer* renderer, struct Font* font, Gfx* gfx);
|
|
||||||
|
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
|
#endif
|
|
@ -4,6 +4,7 @@
|
||||||
#include "../font/font.h"
|
#include "../font/font.h"
|
||||||
#include "../controls/controller.h"
|
#include "../controls/controller.h"
|
||||||
#include "../audio/soundplayer.h"
|
#include "../audio/soundplayer.h"
|
||||||
|
#include "../util/memory.h"
|
||||||
|
|
||||||
#include "../build/assets/materials/ui.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) {
|
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);
|
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 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]);
|
gSPDisplayList(renderState->dl++, ui_material_list[SOLID_TRANSPARENT_OVERLAY_INDEX]);
|
||||||
gDPSetEnvColor(renderState->dl++, 0, 0, 0, backgroundOpacityAsInt);
|
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_revert_list[SOLID_TRANSPARENT_OVERLAY_INDEX]);
|
||||||
|
|
||||||
gSPDisplayList(renderState->dl++, ui_material_list[DEJAVU_SANS_0_INDEX]);
|
struct Coloru8 textColor;
|
||||||
if (subtitleType == SubtitleTypeCloseCaption){
|
|
||||||
gDPSetEnvColor(renderState->dl++, 255, 140, 155, textOpacityAsInt);
|
if (subtitleType == SubtitleTypeCloseCaption) {
|
||||||
} else if (subtitleType == SubtitleTypeCaption){
|
textColor.r = 255;
|
||||||
gDPSetEnvColor(renderState->dl++, 255, 255, 255, textOpacityAsInt);
|
textColor.g = 140;
|
||||||
|
textColor.b = 155;
|
||||||
|
} else if (subtitleType == SubtitleTypeCaption) {
|
||||||
|
textColor = gColorWhite;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderState->dl = fontRender(
|
textColor.a = textOpacityAsInt;
|
||||||
&gDejaVuSansFont,
|
|
||||||
message,
|
renderState->dl = fontRendererBuildGfx(fontRender, &gDejaVuSansFont, gDejaVuSansImages, textPositionX, textPositionY, &textColor, renderState->dl);
|
||||||
textPositionX,
|
|
||||||
textPositionY,
|
|
||||||
renderState->dl
|
|
||||||
);
|
|
||||||
gSPDisplayList(renderState->dl++, ui_material_revert_list[DEJAVU_SANS_0_INDEX]);
|
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 = val.replace("<sfx>", "")
|
||||||
val = re.sub(r'\<len:.+\>','',val)
|
val = re.sub(r'\<len:.+\>','',val)
|
||||||
val = val.replace("<len>", "")
|
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)
|
keys.append(key)
|
||||||
values.append(newval)
|
values.append(val)
|
||||||
|
|
||||||
return keys, values, language
|
return keys, values, language
|
||||||
|
|
||||||
|
@ -155,7 +143,7 @@ def determine_invalid_characters(lang_name, lang_lines, good_characters):
|
||||||
invalid = used_characters - good_characters
|
invalid = used_characters - good_characters
|
||||||
|
|
||||||
if len(invalid) == 0:
|
if len(invalid) == 0:
|
||||||
return
|
return used_characters
|
||||||
|
|
||||||
print(f"{lang_name} has {len(invalid)} invalid charcters\n{''.join(sorted(list(invalid)))}")
|
print(f"{lang_name} has {len(invalid)} invalid charcters\n{''.join(sorted(list(invalid)))}")
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue