diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf index c0f9ceeb8..a662f9621 100644 --- a/src/main/resources/application.conf +++ b/src/main/resources/application.conf @@ -72,10 +72,10 @@ opencomputers { # Defaults to white, feel free to make it some other color, tho! monochromeColor: 0xFFFFFF - # Which font renderer to use. Defaults to `unifont` if invalid. + # Which font renderer to use. Defaults to `hexfont` if invalid. # Possible values: - # - unifont: the (since 1.3.2) default font renderer. Based on the - # Unifont and capable of rendering many unicode glyphs. + # - hexfont: the (since 1.3.2) default font renderer. Font in .hex format + # capable of rendering many unicode glyphs. # The used font data can be swapped out using resource packs, # but is harder to work with, since it involves binary data. # - texture: the old, font-texture based font renderer that was used @@ -84,7 +84,7 @@ opencomputers { # is slightly less efficient than the new one, and more # importantly, can only render code page 437 (as opposed to... # a *lot* of unicode). - fontRenderer: "unifont" + fontRenderer=hexfont # The sample rate used for generating beeps of computers' internal # speakers. Use custom values at your own responsibility here; if it @@ -1480,7 +1480,7 @@ opencomputers { # Logs information about malformed glyphs (i.e. glyphs that deviate in # width from what wcwidth says). - logUnifontErrors: false + logHexFontErrors: false # Extract the native library with Lua into the system's temporary # directory instead of the game directory (e.g. /tmp on Linux). The diff --git a/src/main/resources/assets/opencomputers/wcwidth.bin b/src/main/resources/assets/opencomputers/wcwidth.bin index 9339c9b4e..7fa116d28 100644 Binary files a/src/main/resources/assets/opencomputers/wcwidth.bin and b/src/main/resources/assets/opencomputers/wcwidth.bin differ diff --git a/src/main/scala/li/cil/oc/Settings.scala b/src/main/scala/li/cil/oc/Settings.scala index f9ca26017..8eb7f165d 100644 --- a/src/main/scala/li/cil/oc/Settings.scala +++ b/src/main/scala/li/cil/oc/Settings.scala @@ -405,7 +405,7 @@ class Settings(val config: Config) { val logFullLibLoadErrors = config.getBoolean("debug.logFullNativeLibLoadErrors") val forceNativeLib = config.getString("debug.forceNativeLibWithName") val logOpenGLErrors = config.getBoolean("debug.logOpenGLErrors") - val logUnifontErrors = config.getBoolean("debug.logUnifontErrors") + val logHexFontErrors = config.getBoolean("debug.logHexFontErrors") val alwaysTryNative = config.getBoolean("debug.alwaysTryNative") val debugPersistence = config.getBoolean("debug.verbosePersistenceErrors") val nativeInTmpDir = config.getBoolean("debug.nativeInTmpDir") diff --git a/src/main/scala/li/cil/oc/client/renderer/font/DynamicFontRenderer.scala b/src/main/scala/li/cil/oc/client/renderer/font/DynamicFontRenderer.scala index f04cf39f3..0d3df8a69 100644 --- a/src/main/scala/li/cil/oc/client/renderer/font/DynamicFontRenderer.scala +++ b/src/main/scala/li/cil/oc/client/renderer/font/DynamicFontRenderer.scala @@ -19,7 +19,7 @@ import scala.collection.mutable */ class DynamicFontRenderer extends TextureFontRenderer with IResourceManagerReloadListener { private val glyphProvider: IGlyphProvider = Settings.get.fontRenderer match { - case _ => new FontParserUnifont() + case _ => new FontParserHex() } private val textures = mutable.ArrayBuffer.empty[CharTexture] diff --git a/src/main/scala/li/cil/oc/client/renderer/font/FontParserUnifont.java b/src/main/scala/li/cil/oc/client/renderer/font/FontParserHex.java similarity index 78% rename from src/main/scala/li/cil/oc/client/renderer/font/FontParserUnifont.java rename to src/main/scala/li/cil/oc/client/renderer/font/FontParserHex.java index caf7c9715..21909c33b 100644 --- a/src/main/scala/li/cil/oc/client/renderer/font/FontParserUnifont.java +++ b/src/main/scala/li/cil/oc/client/renderer/font/FontParserHex.java @@ -13,7 +13,7 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.nio.ByteBuffer; -public class FontParserUnifont implements IGlyphProvider { +public class FontParserHex implements IGlyphProvider { private static final byte[] OPAQUE = {(byte) 255, (byte) 255, (byte) 255, (byte) 255}; private static final byte[] TRANSPARENT = {0, 0, 0, 0}; @@ -26,17 +26,19 @@ public class FontParserUnifont implements IGlyphProvider { } try { final InputStream font = Minecraft.getMinecraft().getResourceManager().getResource(new ResourceLocation(Settings.resourceDomain(), "font.hex")).getInputStream(); - OpenComputers.log().info("Initialized Unifont glyph provider."); + OpenComputers.log().info("Initialized unicode glyph provider."); try { - OpenComputers.log().info("Initializing Unifont glyph provider."); + 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); + if (charCode < 0 || charCode >= glyphs.length) continue; // Out of bounds. 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]; final int glyphWidth = glyph.length / getGlyphHeight(); if (expectedWidth == glyphWidth) { @@ -47,15 +49,16 @@ public class FontParserUnifont implements IGlyphProvider { glyphCount++; } glyphs[charCode] = glyph; - } else if (Settings.get().logUnifontErrors()) { - OpenComputers.log().warn(String.format("Size of glyph for code point U+%04X (%s) in Unifont (%d) does not match expected width (%d), ignoring.", charCode, String.valueOf((char) charCode), glyphWidth, expectedWidth)); + } else if (Settings.get().logHexFontErrors()) { + 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(); - } catch (IOException ignored) { + } catch (IOException ex) { + OpenComputers.log().warn("Error parsing font.", ex); } } } catch (IOException ex) { @@ -71,8 +74,10 @@ public class FontParserUnifont implements IGlyphProvider { final ByteBuffer buffer = BufferUtils.createByteBuffer(glyph.length * getGlyphWidth() * 4); for (byte aGlyph : glyph) { int c = ((int) aGlyph) & 0xFF; + // Grab all bits by grabbing the leftmost one then shifting. for (int j = 0; j < 8; j++) { - if ((c & 128) > 0) buffer.put(OPAQUE); + final boolean isBitSet = (c & 0x80) > 0; + if (isBitSet) buffer.put(OPAQUE); else buffer.put(TRANSPARENT); c <<= 1; } diff --git a/src/main/scala/li/cil/oc/client/renderer/font/IGlyphProvider.java b/src/main/scala/li/cil/oc/client/renderer/font/IGlyphProvider.java index cba6960c4..230b2bab4 100644 --- a/src/main/scala/li/cil/oc/client/renderer/font/IGlyphProvider.java +++ b/src/main/scala/li/cil/oc/client/renderer/font/IGlyphProvider.java @@ -12,7 +12,7 @@ public interface IGlyphProvider { *
* This should usually also be called from the implementation's constructor. */ - public void initialize(); + void initialize(); /** * Get a byte array of RGBA data describing the specified char. @@ -30,9 +30,9 @@ public interface IGlyphProvider { * * @param charCode the char to get the render glyph data for. * @return the RGBA byte array representing the char. - * @see li.cil.oc.client.renderer.font.FontParserUnifont#getGlyph(int) See the Unifont parser for a reference implementation. + * @see FontParserHex#getGlyph(int) See the hexfont parser for a reference implementation. */ - public ByteBuffer getGlyph(int charCode); + ByteBuffer getGlyph(int charCode); /** * Get the single-width glyph width for this provider, in pixels. @@ -41,12 +41,12 @@ public interface IGlyphProvider { * a glyphs actual width (in pixels) is expected to be this value times * {@link li.cil.oc.util.FontUtils#wcwidth(int)} (for a specific char). */ - public int getGlyphWidth(); + int getGlyphWidth(); /** * Get the glyph height for this provider, in pixels. * * Each glyph provided is expected to have the same height. */ - public int getGlyphHeight(); + int getGlyphHeight(); } diff --git a/src/main/scala/li/cil/oc/util/FontUtils.scala b/src/main/scala/li/cil/oc/util/FontUtils.scala index dcc614c84..a3a5a637b 100644 --- a/src/main/scala/li/cil/oc/util/FontUtils.scala +++ b/src/main/scala/li/cil/oc/util/FontUtils.scala @@ -1,8 +1,12 @@ package li.cil.oc.util import java.io.IOException +import java.io.InputStream import li.cil.oc.OpenComputers +import li.cil.oc.Settings +import net.minecraft.client.Minecraft +import net.minecraft.util.ResourceLocation object FontUtils { // Note: we load the widths from a file (one byte per width) because the Scala @@ -11,14 +15,14 @@ object FontUtils { // who would have known! private val widths = { val ba = Array.fill[Byte](0x10000)(-1) - val is = FontUtils.getClass.getResourceAsStream("/assets/opencomputers/wcwidth.bin") - if (is != null) { - try { + Minecraft.getMinecraft.getResourceManager.getResource(new ResourceLocation(Settings.resourceDomain, "wcwidth.bin")).getInputStream match { + case is: InputStream => try { is.read(ba) is.close() } catch { case e: IOException => OpenComputers.log.warn("Failed loading character widths. Font rendering will probably be derpy as all hell.", e) } + case _ => // Null. } ba }