mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-18 11:48:02 -04:00
Improve .hex font loading code.
- Optimize string logic to reduce unnecessary object churn (~2x faster font load times). - Add support for multiple font.hex IResources - this allows resource packs to only partially override the OpenComputers font without removing existing glyphs, opening the door for non-compatibility-breaking glyph addition packs or partial alternate fonts.
This commit is contained in:
parent
707ffc57a5
commit
dc55abe1c4
@ -6,6 +6,7 @@ import li.cil.oc.OpenComputers;
|
||||
import li.cil.oc.Settings;
|
||||
import li.cil.oc.util.FontUtils;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.resources.IResource;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import org.lwjgl.BufferUtils;
|
||||
|
||||
@ -14,6 +15,7 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
public class FontParserHex implements IGlyphProvider {
|
||||
private static final byte[] OPAQUE = {(byte) 255, (byte) 255, (byte) 255, (byte) 255};
|
||||
@ -21,18 +23,36 @@ public class FontParserHex implements IGlyphProvider {
|
||||
|
||||
private final TIntObjectMap<byte[]> glyphs = new TIntObjectHashMap<>();
|
||||
|
||||
private static int hex2int(char c) {
|
||||
if (c >= '0' && c <= '9') {
|
||||
return c - '0';
|
||||
} else if (c >= 'A' && c <= 'F') {
|
||||
return c - ('A' - 10);
|
||||
} else if (c >= 'a' && c <= 'f') {
|
||||
return c - ('a' - 10);
|
||||
} else {
|
||||
throw new RuntimeException("invalid char: " + c);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
try {
|
||||
final InputStream font = Minecraft.getMinecraft().getResourceManager().getResource(new ResourceLocation(Settings.resourceDomain(), "font.hex")).getInputStream();
|
||||
glyphs.clear();
|
||||
|
||||
OpenComputers.log().info("Loading Unicode glyphs...");
|
||||
long time = System.currentTimeMillis();
|
||||
int glyphCount = 0;
|
||||
|
||||
ResourceLocation loc = new ResourceLocation(Settings.resourceDomain(), "font.hex");
|
||||
for (IResource resource : (List<IResource>) Minecraft.getMinecraft().getResourceManager().getAllResources(loc)) {
|
||||
final InputStream font = resource.getInputStream();
|
||||
try {
|
||||
OpenComputers.log().info("Initializing unicode glyph provider.");
|
||||
final BufferedReader input = new BufferedReader(new InputStreamReader(font));
|
||||
String line;
|
||||
int glyphCount = 0;
|
||||
while ((line = input.readLine()) != null) {
|
||||
final String[] info = line.split(":");
|
||||
final int charCode = Integer.parseInt(info[0], 16);
|
||||
final String info = line.substring(0, line.indexOf(':'));
|
||||
final int charCode = Integer.parseInt(info, 16);
|
||||
if (charCode < 0 || charCode >= FontUtils.codepoint_limit()) {
|
||||
OpenComputers.log().warn(String.format("Unicode font contained unexpected glyph: U+%04X, ignoring", charCode));
|
||||
continue; // Out of bounds.
|
||||
@ -40,11 +60,12 @@ public class FontParserHex implements IGlyphProvider {
|
||||
final int expectedWidth = FontUtils.wcwidth(charCode);
|
||||
if (expectedWidth < 1) continue; // Skip control characters.
|
||||
// Two chars representing one byte represent one row of eight pixels.
|
||||
final byte[] glyph = new byte[info[1].length() >> 1];
|
||||
int glyphStrOfs = info.length() + 1;
|
||||
final byte[] glyph = new byte[(line.length() - glyphStrOfs) >> 1];
|
||||
final int glyphWidth = glyph.length / getGlyphHeight();
|
||||
if (expectedWidth == glyphWidth) {
|
||||
for (int i = 0; i < glyph.length; i++) {
|
||||
glyph[i] = (byte) Integer.parseInt(info[1].substring(i * 2, i * 2 + 2), 16);
|
||||
for (int i = 0; i < glyph.length; i++, glyphStrOfs += 2) {
|
||||
glyph[i] = (byte) ((hex2int(line.charAt(glyphStrOfs)) << 4) | (hex2int(line.charAt(glyphStrOfs + 1))));
|
||||
}
|
||||
if (!glyphs.containsKey(charCode)) {
|
||||
glyphCount++;
|
||||
@ -54,7 +75,6 @@ public class FontParserHex implements IGlyphProvider {
|
||||
OpenComputers.log().warn(String.format("Size of glyph for code point U+%04X (%s) in font (%d) does not match expected width (%d), ignoring.", charCode, String.valueOf((char) charCode), glyphWidth, expectedWidth));
|
||||
}
|
||||
}
|
||||
OpenComputers.log().info("Loaded " + glyphCount + " glyphs.");
|
||||
} finally {
|
||||
try {
|
||||
font.close();
|
||||
@ -62,6 +82,9 @@ public class FontParserHex implements IGlyphProvider {
|
||||
OpenComputers.log().warn("Error parsing font.", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OpenComputers.log().info("Loaded " + glyphCount + " glyphs in " + (System.currentTimeMillis() - time) + " milliseconds.");
|
||||
} catch (IOException ex) {
|
||||
OpenComputers.log().warn("Failed loading glyphs.", ex);
|
||||
}
|
||||
@ -72,7 +95,7 @@ public class FontParserHex implements IGlyphProvider {
|
||||
if (!glyphs.containsKey(charCode))
|
||||
return null;
|
||||
final byte[] glyph = glyphs.get(charCode);
|
||||
if (glyph == null || glyph.length <= 0)
|
||||
if (glyph == null || glyph.length == 0)
|
||||
return null;
|
||||
final ByteBuffer buffer = BufferUtils.createByteBuffer(glyph.length * getGlyphWidth() * 4);
|
||||
for (byte aGlyph : glyph) {
|
||||
|
@ -138,23 +138,28 @@ object FontUtils {
|
||||
else if ((charCode == 0xe0001) || ((charCode - 0xe0020) < 0x5f) || ((charCode - 0xe0100) < 0xef)) 0
|
||||
else 1
|
||||
}
|
||||
OpenComputers.log.info("Initializing unicode wcwidth.")
|
||||
{
|
||||
OpenComputers.log.info("Initializing font glyph width cache...")
|
||||
val time = System.currentTimeMillis()
|
||||
for (i <- 0 until codepoint_limit) {
|
||||
if (c_wcwidth(i) == 2)
|
||||
defined_double_wide += i
|
||||
}
|
||||
OpenComputers.log.info("Initialized font glyph width cache in " + (System.currentTimeMillis() - time) + " milliseconds.")
|
||||
}
|
||||
try {
|
||||
OpenComputers.log.info("Initializing font glyph widths.")
|
||||
OpenComputers.log.info("Initializing font glyph width overrides...")
|
||||
val time = System.currentTimeMillis()
|
||||
val font = FontUtils.getClass.getResourceAsStream("/assets/opencomputers/font.hex")
|
||||
try {
|
||||
var line: String = null
|
||||
val input = new BufferedReader(new InputStreamReader(font, StandardCharsets.UTF_8))
|
||||
var out_of_range_glyph: Int = 0
|
||||
while ({line = input.readLine; line != null}) {
|
||||
val info = line.split(":")
|
||||
val charCode = Integer.parseInt(info(0), 16)
|
||||
val info = line.substring(0, line.indexOf(':'))
|
||||
val charCode = Integer.parseInt(info, 16)
|
||||
if (charCode >= 0 && charCode < codepoint_limit) {
|
||||
info(1).trim.length match {
|
||||
line.length - info.length - 1 match {
|
||||
case 64 => defined_double_wide += charCode
|
||||
case 32 => defined_double_wide -= charCode
|
||||
case n => OpenComputers.log.warn(s"Invalid glyph size detected in font.hex. Expected 64 or 32, got: $n")
|
||||
@ -163,8 +168,8 @@ object FontUtils {
|
||||
out_of_range_glyph += 1
|
||||
}
|
||||
}
|
||||
if (out_of_range_glyph > 1) {
|
||||
OpenComputers.log.info(f"${out_of_range_glyph} total non-BMP glyph char codes detected in font.hex")
|
||||
if (out_of_range_glyph >= 1) {
|
||||
OpenComputers.log.info(f"${out_of_range_glyph} total out-of-bounds glyph char codes detected in font.hex")
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
@ -173,9 +178,9 @@ object FontUtils {
|
||||
case ex: Throwable => OpenComputers.log.error(s"Error closing font.hex: $ex")
|
||||
}
|
||||
}
|
||||
OpenComputers.log.info("Initialized font glyph width overrides in " + (System.currentTimeMillis() - time) + " milliseconds.")
|
||||
} catch {
|
||||
case ex: Throwable => OpenComputers.log.error(s"Error parsing glyphs to determine widths: $ex")
|
||||
}
|
||||
OpenComputers.log.info("glyph width ready.")
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user