Updated char width map for new font and made the width file resource-packable. Closes #1760.

This commit is contained in:
Florian Nücke 2016-04-14 22:40:37 +02:00
parent d24d70554b
commit e45acd967b
7 changed files with 31 additions and 22 deletions

View File

@ -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

View File

@ -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")

View File

@ -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]

View File

@ -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;
}

View File

@ -12,7 +12,7 @@ public interface IGlyphProvider {
* <p/>
* 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.
* <p/>
* Each glyph provided is expected to have the same height.
*/
public int getGlyphHeight();
int getGlyphHeight();
}

View File

@ -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
}