Cleaned up terminal rendering code, in particular made it more robust when scaled.
This commit is contained in:
@@ -20,11 +20,11 @@ public final class TerminalScreen extends Screen {
|
||||
private static final ResourceLocation BACKGROUND = new ResourceLocation(API.MOD_ID, "textures/gui/screen/terminal.png");
|
||||
private static final ResourceLocation BACKGROUND_TERMINAL_FOCUSED = new ResourceLocation(API.MOD_ID, "textures/gui/screen/terminal_focused.png");
|
||||
private static final int TEXTURE_SIZE = 512;
|
||||
private static final int SCREEN_WIDTH = 8 + 80 * 9 / 2 + 8;
|
||||
private static final int SCREEN_WIDTH = 8 + 80 * 8 / 2 + 8;
|
||||
private static final int SCREEN_HEIGHT = 8 + 24 * 16 / 2 + 8;
|
||||
private static final int TERMINAL_AREA_X = 8;
|
||||
private static final int TERMINAL_AREA_Y = 8;
|
||||
private static final int TERMINAL_AREA_WIDTH = 80 * 9 / 2;
|
||||
private static final int TERMINAL_AREA_WIDTH = 80 * 8 / 2;
|
||||
private static final int TERMINAL_AREA_HEIGHT = 24 * 16 / 2;
|
||||
|
||||
private final ComputerTileEntity tileEntity;
|
||||
|
||||
@@ -6,7 +6,6 @@ import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import it.unimi.dsi.fastutil.bytes.ByteArrayFIFOQueue;
|
||||
import li.cil.ceres.api.Serialized;
|
||||
import li.cil.oc2.api.API;
|
||||
import li.cil.oc2.client.render.font.MonospaceFontRenderer;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.audio.SimpleSound;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
@@ -29,18 +28,6 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
// Implements a couple of control sequences from here: https://en.wikipedia.org/wiki/ANSI_escape_code#CSI_sequences
|
||||
@Serialized
|
||||
public final class Terminal {
|
||||
private static final int CHAR_WIDTH = 8;
|
||||
private static final int CHAR_HEIGHT = 16;
|
||||
|
||||
private static final ResourceLocation LOCATION_FONT_TEXTURE = new ResourceLocation(API.MOD_ID, "textures/font/terminus.png");
|
||||
private static final int TEXTURE_RESOLUTION = 256;
|
||||
private static final int TEXTURE_COLUMNS = 16;
|
||||
private static final int TEXTURE_BOLD_SHIFT = TEXTURE_COLUMNS; // Bold chars are in right half of texture.
|
||||
private static final float U_SIZE = CHAR_WIDTH / (float) TEXTURE_RESOLUTION;
|
||||
private static final float V_SIZE = CHAR_HEIGHT / (float) TEXTURE_RESOLUTION;
|
||||
private static final float U_STEP = CHAR_WIDTH / (float) TEXTURE_RESOLUTION;
|
||||
private static final float V_STEP = CHAR_HEIGHT / (float) TEXTURE_RESOLUTION;
|
||||
|
||||
private static final int TAB_WIDTH = 4;
|
||||
private static final int WIDTH = 80, HEIGHT = 24;
|
||||
|
||||
@@ -53,27 +40,8 @@ public final class Terminal {
|
||||
private static final int COLOR_CYAN = 6;
|
||||
private static final int COLOR_WHITE = 7;
|
||||
|
||||
private static final int[] COLORS = {
|
||||
0x010101, // Black
|
||||
0xEE3322, // Red
|
||||
0x33DD44, // Green
|
||||
0xFFCC11, // Yellow
|
||||
0x1188EE, // Blue
|
||||
0xDD33CC, // Magenta
|
||||
0x22CCDD, // Cyan
|
||||
0xEEEEEE, // White
|
||||
};
|
||||
|
||||
private static final int[] DIM_COLORS = {
|
||||
0x010101, // Black
|
||||
0x772211, // Red
|
||||
0x116622, // Green
|
||||
0x886611, // Yellow
|
||||
0x115588, // Blue
|
||||
0x771177, // Magenta
|
||||
0x116677, // Cyan
|
||||
0x777777, // White
|
||||
};
|
||||
private static final int CHAR_WIDTH = 8;
|
||||
private static final int CHAR_HEIGHT = 16;
|
||||
|
||||
private static final int COLOR_MASK = 0b111;
|
||||
private static final int COLOR_FOREGROUND_SHIFT = 3;
|
||||
@@ -112,29 +80,28 @@ public final class Terminal {
|
||||
// Style info packed into one byte for compact storage
|
||||
private byte style = DEFAULT_STYLE;
|
||||
|
||||
private final transient Object[] lines = new Object[HEIGHT]; // Cached vertex buffers for rendering, untyped for server.
|
||||
// Rendering data for client
|
||||
private final transient AtomicInteger dirty = new AtomicInteger(-1);
|
||||
private transient Object lastMatrix; // Untyped for server.
|
||||
private transient Object renderer;
|
||||
|
||||
public Terminal() {
|
||||
clear();
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return WIDTH * MonospaceFontRenderer.INSTANCE.getCharWidth();
|
||||
return WIDTH * CHAR_WIDTH;
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return HEIGHT * MonospaceFontRenderer.INSTANCE.getCharHeight();
|
||||
return HEIGHT * CHAR_HEIGHT;
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public void render(final MatrixStack stack) {
|
||||
renderBuffer(stack);
|
||||
|
||||
if (System.currentTimeMillis() % 1000 > 500) {
|
||||
renderCursor(stack);
|
||||
if (renderer == null) {
|
||||
renderer = new Renderer(this);
|
||||
}
|
||||
((Renderer) renderer).render(dirty, stack);
|
||||
}
|
||||
|
||||
public synchronized int readInput() {
|
||||
@@ -433,141 +400,6 @@ public final class Terminal {
|
||||
}
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
private void renderBuffer(final MatrixStack stack) {
|
||||
validateLineCache(stack);
|
||||
|
||||
GlStateManager.depthMask(false);
|
||||
Minecraft.getInstance().getTextureManager().bindTexture(LOCATION_FONT_TEXTURE);
|
||||
|
||||
final BufferBuilder buffer = Tessellator.getInstance().getBuffer();
|
||||
for (final Object line : lines) {
|
||||
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR_TEX);
|
||||
buffer.setVertexState((BufferBuilder.State) line);
|
||||
buffer.finishDrawing();
|
||||
WorldVertexBufferUploader.draw(buffer);
|
||||
}
|
||||
|
||||
GlStateManager.depthMask(true);
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
private void validateLineCache(final MatrixStack stack) {
|
||||
if (!Objects.equals(lastMatrix, stack.getLast().getMatrix())) {
|
||||
lastMatrix = stack.getLast().getMatrix();
|
||||
dirty.set(-1);
|
||||
}
|
||||
|
||||
if (dirty.get() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
final BufferBuilder buffer = Tessellator.getInstance().getBuffer();
|
||||
|
||||
final int mask = dirty.getAndSet(0);
|
||||
for (int row = 0; row < lines.length; row++) {
|
||||
if ((mask & (1 << row)) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
stack.push();
|
||||
stack.translate(0, row * CHAR_HEIGHT, 0);
|
||||
final Matrix4f matrix = stack.getLast().getMatrix();
|
||||
|
||||
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR_TEX);
|
||||
|
||||
float tx = 0f;
|
||||
for (int col = 0, index = row * WIDTH; col < WIDTH; col++, index++) {
|
||||
final int character = this.buffer[index] & 0xFF;
|
||||
final byte colors = this.colors[index];
|
||||
final byte style = this.styles[index];
|
||||
|
||||
if ((style & STYLE_HIDDEN_MASK) != 0) continue;
|
||||
|
||||
final int x = character % TEXTURE_COLUMNS + ((style & STYLE_BOLD_MASK) != 0 ? TEXTURE_BOLD_SHIFT : 0);
|
||||
final int y = character / TEXTURE_COLUMNS;
|
||||
final float u = x * U_STEP;
|
||||
final float v = y * V_STEP;
|
||||
|
||||
final int[] palette = (style & STYLE_DIM_MASK) != 0 ? DIM_COLORS : COLORS;
|
||||
|
||||
final int foreground = palette[(colors >> COLOR_FOREGROUND_SHIFT) & COLOR_MASK];
|
||||
final int background = palette[colors & COLOR_MASK];
|
||||
|
||||
final int color = (style & STYLE_INVERT_MASK) != 0 ? background : foreground;
|
||||
final float r = ((color >> 16) & 0xFF) / 255f;
|
||||
final float g = ((color >> 8) & 0xFF) / 255f;
|
||||
final float b = ((color) & 0xFF) / 255f;
|
||||
|
||||
if (isPrintableCharacter((char) character)) {
|
||||
buffer.pos(matrix, tx, CHAR_HEIGHT, 0).color(r, g, b, 1).tex(u, v + V_SIZE).endVertex();
|
||||
buffer.pos(matrix, tx + CHAR_WIDTH, CHAR_HEIGHT, 0).color(r, g, b, 1).tex(u + U_SIZE, v + V_SIZE).endVertex();
|
||||
buffer.pos(matrix, tx + CHAR_WIDTH, 0, 0).color(r, g, b, 1).tex(u + U_SIZE, v).endVertex();
|
||||
buffer.pos(matrix, tx, 0, 0).color(r, g, b, 1).tex(u, v).endVertex();
|
||||
}
|
||||
|
||||
if ((style & STYLE_UNDERLINE_MASK) != 0) {
|
||||
final float ulu = (TEXTURE_RESOLUTION - 1) / (float) TEXTURE_RESOLUTION;
|
||||
final float ulv = 1 / (float) TEXTURE_RESOLUTION;
|
||||
|
||||
buffer.pos(matrix, tx, CHAR_HEIGHT - 3, 0).color(r, g, b, 1).tex(ulu, ulv).endVertex();
|
||||
buffer.pos(matrix, tx + CHAR_WIDTH, CHAR_HEIGHT - 3, 0).color(r, g, b, 1).tex(ulu, ulv).endVertex();
|
||||
buffer.pos(matrix, tx + CHAR_WIDTH, CHAR_HEIGHT - 2, 0).color(r, g, b, 1).tex(ulu, ulv).endVertex();
|
||||
buffer.pos(matrix, tx, CHAR_HEIGHT - 2, 0).color(r, g, b, 1).tex(ulu, ulv).endVertex();
|
||||
}
|
||||
|
||||
tx += CHAR_WIDTH;
|
||||
}
|
||||
|
||||
lines[row] = buffer.getVertexState();
|
||||
buffer.finishDrawing();
|
||||
buffer.discard();
|
||||
|
||||
stack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isPrintableCharacter(final char ch) {
|
||||
return ch == 0 ||
|
||||
(ch > ' ' && ch <= '~') ||
|
||||
ch >= 177;
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
private void renderCursor(final MatrixStack stack) {
|
||||
if (x < 0 || x >= WIDTH || y < 0 || y >= HEIGHT) {
|
||||
return;
|
||||
}
|
||||
|
||||
GlStateManager.depthMask(false);
|
||||
RenderSystem.disableTexture();
|
||||
|
||||
stack.push();
|
||||
stack.translate(x * CHAR_WIDTH, y * CHAR_HEIGHT, 0);
|
||||
|
||||
final Matrix4f matrix = stack.getLast().getMatrix();
|
||||
final BufferBuilder buffer = Tessellator.getInstance().getBuffer();
|
||||
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR);
|
||||
|
||||
final int foreground = COLORS[COLOR_WHITE];
|
||||
final float r = ((foreground >> 16) & 0xFF) / 255f;
|
||||
final float g = ((foreground >> 8) & 0xFF) / 255f;
|
||||
final float b = ((foreground) & 0xFF) / 255f;
|
||||
|
||||
buffer.pos(matrix, 0, CHAR_HEIGHT, 0).color(r, g, b, 1).endVertex();
|
||||
buffer.pos(matrix, CHAR_WIDTH, CHAR_HEIGHT, 0).color(r, g, b, 1).endVertex();
|
||||
buffer.pos(matrix, CHAR_WIDTH, 0, 0).color(r, g, b, 1).endVertex();
|
||||
buffer.pos(matrix, 0, 0, 0).color(r, g, b, 1).endVertex();
|
||||
|
||||
buffer.finishDrawing();
|
||||
WorldVertexBufferUploader.draw(buffer);
|
||||
|
||||
stack.pop();
|
||||
|
||||
RenderSystem.enableTexture();
|
||||
GlStateManager.depthMask(true);
|
||||
}
|
||||
|
||||
private void setCursorPos(final int x, final int y) {
|
||||
this.x = Math.max(0, Math.min(WIDTH - 1, x));
|
||||
this.y = Math.max(0, Math.min(HEIGHT - 1, y));
|
||||
@@ -627,7 +459,6 @@ public final class Terminal {
|
||||
System.arraycopy(buffer, WIDTH, buffer, 0, buffer.length - WIDTH);
|
||||
System.arraycopy(colors, WIDTH, colors, 0, colors.length - WIDTH);
|
||||
System.arraycopy(styles, WIDTH, styles, 0, styles.length - WIDTH);
|
||||
System.arraycopy(lines, 1, lines, 0, lines.length - 1);
|
||||
Arrays.fill(buffer, WIDTH * HEIGHT - WIDTH, WIDTH * HEIGHT, (byte) ' ');
|
||||
Arrays.fill(colors, WIDTH * HEIGHT - WIDTH, WIDTH * HEIGHT, DEFAULT_COLORS);
|
||||
Arrays.fill(styles, WIDTH * HEIGHT - WIDTH, WIDTH * HEIGHT, DEFAULT_STYLE);
|
||||
@@ -635,4 +466,189 @@ public final class Terminal {
|
||||
// Offset is baked into buffers so we must rebuild them all.
|
||||
dirty.set(-1);
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
private static final class Renderer {
|
||||
private static final ResourceLocation LOCATION_FONT_TEXTURE = new ResourceLocation(API.MOD_ID, "textures/font/terminus.png");
|
||||
private static final int TEXTURE_RESOLUTION = 256;
|
||||
private static final float ONE_OVER_TEXTURE_RESOLUTION = 1.0f / (float) TEXTURE_RESOLUTION;
|
||||
private static final int TEXTURE_COLUMNS = 16;
|
||||
private static final int TEXTURE_BOLD_SHIFT = TEXTURE_COLUMNS; // Bold chars are in right half of texture.
|
||||
|
||||
private static final int[] COLORS = {
|
||||
0x010101, // Black
|
||||
0xEE3322, // Red
|
||||
0x33DD44, // Green
|
||||
0xFFCC11, // Yellow
|
||||
0x1188EE, // Blue
|
||||
0xDD33CC, // Magenta
|
||||
0x22CCDD, // Cyan
|
||||
0xEEEEEE, // White
|
||||
};
|
||||
|
||||
private static final int[] DIM_COLORS = {
|
||||
0x010101, // Black
|
||||
0x772211, // Red
|
||||
0x116622, // Green
|
||||
0x886611, // Yellow
|
||||
0x115588, // Blue
|
||||
0x771177, // Magenta
|
||||
0x116677, // Cyan
|
||||
0x777777, // White
|
||||
};
|
||||
|
||||
private final Terminal terminal;
|
||||
|
||||
private final Object[] lines = new Object[HEIGHT]; // Cached vertex buffers for rendering, untyped for server.
|
||||
private Object lastMatrix; // Untyped for server.
|
||||
|
||||
public Renderer(final Terminal terminal) {
|
||||
this.terminal = terminal;
|
||||
}
|
||||
|
||||
public void render(final AtomicInteger dirty, final MatrixStack stack) {
|
||||
validateLineCache(dirty, stack);
|
||||
renderBuffer();
|
||||
|
||||
if (System.currentTimeMillis() % 1000 > 500) {
|
||||
renderCursor(stack);
|
||||
}
|
||||
}
|
||||
|
||||
private void renderBuffer() {
|
||||
GlStateManager.depthMask(false);
|
||||
Minecraft.getInstance().getTextureManager().bindTexture(LOCATION_FONT_TEXTURE);
|
||||
|
||||
final BufferBuilder buffer = Tessellator.getInstance().getBuffer();
|
||||
for (final Object line : lines) {
|
||||
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR_TEX);
|
||||
buffer.setVertexState((BufferBuilder.State) line);
|
||||
buffer.finishDrawing();
|
||||
WorldVertexBufferUploader.draw(buffer);
|
||||
}
|
||||
|
||||
GlStateManager.depthMask(true);
|
||||
}
|
||||
|
||||
private void validateLineCache(final AtomicInteger dirty, final MatrixStack stack) {
|
||||
if (!Objects.equals(lastMatrix, stack.getLast().getMatrix())) {
|
||||
lastMatrix = stack.getLast().getMatrix();
|
||||
dirty.set(-1);
|
||||
}
|
||||
|
||||
if (dirty.get() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
final BufferBuilder buffer = Tessellator.getInstance().getBuffer();
|
||||
|
||||
final int mask = dirty.getAndSet(0);
|
||||
for (int row = 0; row < lines.length; row++) {
|
||||
if ((mask & (1 << row)) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
stack.push();
|
||||
stack.translate(0, row * CHAR_HEIGHT, 0);
|
||||
final Matrix4f matrix = stack.getLast().getMatrix();
|
||||
|
||||
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR_TEX);
|
||||
|
||||
float tx = 0f;
|
||||
for (int col = 0, index = row * WIDTH; col < WIDTH; col++, index++) {
|
||||
final int character = terminal.buffer[index] & 0xFF;
|
||||
final byte colors = terminal.colors[index];
|
||||
final byte style = terminal.styles[index];
|
||||
|
||||
if ((style & STYLE_HIDDEN_MASK) != 0) continue;
|
||||
|
||||
final int x = character % TEXTURE_COLUMNS + ((style & STYLE_BOLD_MASK) != 0 ? TEXTURE_BOLD_SHIFT : 0);
|
||||
final int y = character / TEXTURE_COLUMNS;
|
||||
// The +0.5f is to sample the center of our texture pixels. This counteracts small
|
||||
// floating point inaccuracies in our texture coordinates introduced by varying
|
||||
// render resolution. And since we use point sampling it doesn't matter where
|
||||
// exactly inside a pixel we sample.
|
||||
final float u0 = (x * CHAR_WIDTH + 0.5f) * ONE_OVER_TEXTURE_RESOLUTION;
|
||||
final float u1 = ((x + 1) * CHAR_WIDTH + 0.5f) * ONE_OVER_TEXTURE_RESOLUTION;
|
||||
final float v0 = (y * CHAR_HEIGHT + 0.5f) * ONE_OVER_TEXTURE_RESOLUTION;
|
||||
final float v1 = ((y + 1) * CHAR_HEIGHT + 0.5f) * ONE_OVER_TEXTURE_RESOLUTION;
|
||||
|
||||
final int[] palette = (style & STYLE_DIM_MASK) != 0 ? DIM_COLORS : COLORS;
|
||||
|
||||
final int foreground = palette[(colors >> COLOR_FOREGROUND_SHIFT) & COLOR_MASK];
|
||||
final int background = palette[colors & COLOR_MASK];
|
||||
|
||||
final int color = (style & STYLE_INVERT_MASK) != 0 ? background : foreground;
|
||||
final float r = ((color >> 16) & 0xFF) / 255f;
|
||||
final float g = ((color >> 8) & 0xFF) / 255f;
|
||||
final float b = ((color) & 0xFF) / 255f;
|
||||
|
||||
if (isPrintableCharacter((char) character)) {
|
||||
buffer.pos(matrix, tx, CHAR_HEIGHT, 0).color(r, g, b, 1).tex(u0, v1).endVertex();
|
||||
buffer.pos(matrix, tx + CHAR_WIDTH, CHAR_HEIGHT, 0).color(r, g, b, 1).tex(u1, v1).endVertex();
|
||||
buffer.pos(matrix, tx + CHAR_WIDTH, 0, 0).color(r, g, b, 1).tex(u1, v0).endVertex();
|
||||
buffer.pos(matrix, tx, 0, 0).color(r, g, b, 1).tex(u0, v0).endVertex();
|
||||
}
|
||||
|
||||
if ((style & STYLE_UNDERLINE_MASK) != 0) {
|
||||
final float ulu = (TEXTURE_RESOLUTION - 1) / (float) TEXTURE_RESOLUTION;
|
||||
final float ulv = 1 / (float) TEXTURE_RESOLUTION;
|
||||
|
||||
buffer.pos(matrix, tx, CHAR_HEIGHT - 3, 0).color(r, g, b, 1).tex(ulu, ulv).endVertex();
|
||||
buffer.pos(matrix, tx + CHAR_WIDTH, CHAR_HEIGHT - 3, 0).color(r, g, b, 1).tex(ulu, ulv).endVertex();
|
||||
buffer.pos(matrix, tx + CHAR_WIDTH, CHAR_HEIGHT - 2, 0).color(r, g, b, 1).tex(ulu, ulv).endVertex();
|
||||
buffer.pos(matrix, tx, CHAR_HEIGHT - 2, 0).color(r, g, b, 1).tex(ulu, ulv).endVertex();
|
||||
}
|
||||
|
||||
tx += CHAR_WIDTH;
|
||||
}
|
||||
|
||||
lines[row] = buffer.getVertexState();
|
||||
buffer.finishDrawing();
|
||||
buffer.discard();
|
||||
|
||||
stack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
private void renderCursor(final MatrixStack stack) {
|
||||
if (terminal.x < 0 || terminal.x >= WIDTH || terminal.y < 0 || terminal.y >= HEIGHT) {
|
||||
return;
|
||||
}
|
||||
|
||||
GlStateManager.depthMask(false);
|
||||
RenderSystem.disableTexture();
|
||||
|
||||
stack.push();
|
||||
stack.translate(terminal.x * CHAR_WIDTH, terminal.y * CHAR_HEIGHT, 0);
|
||||
|
||||
final Matrix4f matrix = stack.getLast().getMatrix();
|
||||
final BufferBuilder buffer = Tessellator.getInstance().getBuffer();
|
||||
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR);
|
||||
|
||||
final int foreground = COLORS[COLOR_WHITE];
|
||||
final float r = ((foreground >> 16) & 0xFF) / 255f;
|
||||
final float g = ((foreground >> 8) & 0xFF) / 255f;
|
||||
final float b = ((foreground) & 0xFF) / 255f;
|
||||
|
||||
buffer.pos(matrix, 0, CHAR_HEIGHT, 0).color(r, g, b, 1).endVertex();
|
||||
buffer.pos(matrix, CHAR_WIDTH, CHAR_HEIGHT, 0).color(r, g, b, 1).endVertex();
|
||||
buffer.pos(matrix, CHAR_WIDTH, 0, 0).color(r, g, b, 1).endVertex();
|
||||
buffer.pos(matrix, 0, 0, 0).color(r, g, b, 1).endVertex();
|
||||
|
||||
buffer.finishDrawing();
|
||||
WorldVertexBufferUploader.draw(buffer);
|
||||
|
||||
stack.pop();
|
||||
|
||||
RenderSystem.enableTexture();
|
||||
GlStateManager.depthMask(true);
|
||||
}
|
||||
|
||||
private static boolean isPrintableCharacter(final char ch) {
|
||||
return ch == 0 ||
|
||||
(ch > ' ' && ch <= '~') ||
|
||||
ch >= 177;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
package li.cil.oc2.client.render.font;
|
||||
|
||||
import net.minecraft.client.renderer.Matrix4f;
|
||||
|
||||
/**
|
||||
* Base interface for font renderers.
|
||||
*/
|
||||
public interface FontRenderer {
|
||||
/**
|
||||
* Render the specified string.
|
||||
*
|
||||
* @param matrix transformation of the text to draw.
|
||||
* @param value the string to render.
|
||||
*/
|
||||
void drawString(final Matrix4f matrix, final CharSequence value);
|
||||
|
||||
/**
|
||||
* Render up to the specified amount of characters of the specified string.
|
||||
* <p>
|
||||
* This is intended as a convenience method for clamped-width rendering,
|
||||
* avoiding additional string operations such as <tt>substring</tt>.
|
||||
*
|
||||
* @param matrix transformation of the text to draw.
|
||||
* @param value the string to render.
|
||||
* @param maxChars the maximum number of characters to render.
|
||||
*/
|
||||
void drawString(final Matrix4f matrix, final CharSequence value, final int maxChars);
|
||||
|
||||
/**
|
||||
* Get the width of the characters drawn with the font renderer, in pixels.
|
||||
*
|
||||
* @return the width of the drawn characters.
|
||||
*/
|
||||
int getCharWidth();
|
||||
|
||||
/**
|
||||
* Get the height of the characters drawn with the font renderer, in pixels.
|
||||
*
|
||||
* @return the height of the drawn characters.
|
||||
*/
|
||||
int getCharHeight();
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
package li.cil.oc2.client.render.font;
|
||||
|
||||
import com.mojang.blaze3d.platform.GlStateManager;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
||||
import li.cil.oc2.api.API;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.Matrix4f;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
public final class MonospaceFontRenderer implements FontRenderer {
|
||||
public static final FontRenderer INSTANCE = new MonospaceFontRenderer();
|
||||
|
||||
private static final ResourceLocation LOCATION_FONT_TEXTURE = new ResourceLocation(API.MOD_ID, "textures/font/monospace.png");
|
||||
private static final String CHARS = "\0\u263a\u263b\u2665\u2666\u2663\u2660\u2022\u25d8\u25cb\u25d9\u2642\u2640\u266a\u266b\u263c\u25ba\u25c4\u2195\u203c\u00b6\u00a7\u25ac\u21a8\u2191\u2193\u2192\u2190\u221f\u2194\u25b2\u25bc !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u2302\u00c7\u00fc\u00e9\u00e2\u00e4\u00e0\u00e5\u00e7\u00ea\u00eb\u00e8\u00ef\u00ee\u00ec\u00c4\u00c5\u00c9\u00e6\u00c6\u00f4\u00f6\u00f2\u00fb\u00f9\u00ff\u00d6\u00dc\u00a2\u00a3\u00a5\u20a7\u0192\u00e1\u00ed\u00f3\u00fa\u00f1\u00d1\u00aa\u00ba\u00bf\u2310\u00ac\u00bd\u00bc\u00a1\u00ab\u00bb\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255d\u255c\u255b\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u255e\u255f\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256b\u256a\u2518\u250c\u2588\u2584\u258c\u2590\u2580\u03b1\u00df\u0393\u03c0\u03a3\u03c3\u00b5\u03c4\u03a6\u0398\u03a9\u03b4\u221e\u03c6\u03b5\u2229\u2261\u00b1\u2265\u2264\u2320\u2321\u00f7\u2248\u00b0\u2219\u00b7\u221a\u207f\u00b2\u25a0";
|
||||
private static final int TEXTURE_RESOLUTION = 256;
|
||||
|
||||
private final Int2IntMap CHAR_MAP;
|
||||
|
||||
private final int COLUMNS = TEXTURE_RESOLUTION / getCharWidth();
|
||||
private final float U_SIZE = getCharWidth() / (float) TEXTURE_RESOLUTION;
|
||||
private final float V_SIZE = getCharHeight() / (float) TEXTURE_RESOLUTION;
|
||||
private final float U_STEP = getCharWidth() / (float) TEXTURE_RESOLUTION;
|
||||
private final float V_STEP = getCharHeight() / (float) TEXTURE_RESOLUTION;
|
||||
|
||||
private MonospaceFontRenderer() {
|
||||
CHAR_MAP = new Int2IntOpenHashMap();
|
||||
final CharSequence chars = CHARS;
|
||||
for (int index = 0; index < chars.length(); index++) {
|
||||
CHAR_MAP.put(chars.charAt(index), index);
|
||||
}
|
||||
}
|
||||
|
||||
public void drawString(final Matrix4f matrix, final CharSequence value) {
|
||||
drawString(matrix, value, value.length());
|
||||
}
|
||||
|
||||
public void drawString(final Matrix4f matrix, final CharSequence value, final int maxChars) {
|
||||
GlStateManager.depthMask(false);
|
||||
|
||||
Minecraft.getInstance().getTextureManager().bindTexture(LOCATION_FONT_TEXTURE);
|
||||
|
||||
final Tessellator tessellator = Tessellator.getInstance();
|
||||
final BufferBuilder buffer = tessellator.getBuffer();
|
||||
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
|
||||
|
||||
float tx = 0f;
|
||||
final int end = Math.min(maxChars, value.length());
|
||||
for (int i = 0; i < end; i++) {
|
||||
final char ch = value.charAt(i);
|
||||
drawChar(matrix, tx, ch, buffer);
|
||||
tx += getCharWidth();
|
||||
}
|
||||
|
||||
tessellator.draw();
|
||||
|
||||
GlStateManager.depthMask(true);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------- //
|
||||
// FontRenderer
|
||||
|
||||
@Override
|
||||
public int getCharWidth() {
|
||||
return 9;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCharHeight() {
|
||||
return 16;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------- //
|
||||
|
||||
private void drawChar(final Matrix4f matrix, final float x, final char ch, final BufferBuilder buffer) {
|
||||
if (Character.isWhitespace(ch) || Character.isISOControl(ch)) {
|
||||
return;
|
||||
}
|
||||
final int index = getCharIndex(ch);
|
||||
|
||||
final int column = index % COLUMNS;
|
||||
final int row = index / COLUMNS;
|
||||
final float u = column * U_STEP;
|
||||
final float v = row * V_STEP;
|
||||
|
||||
buffer.pos(matrix, x, getCharHeight(), 0).tex(u, v + V_SIZE).endVertex();
|
||||
buffer.pos(matrix, x + getCharWidth(), getCharHeight(), 0).tex(u + U_SIZE, v + V_SIZE).endVertex();
|
||||
buffer.pos(matrix, x + getCharWidth(), 0, 0).tex(u + U_SIZE, v).endVertex();
|
||||
buffer.pos(matrix, x, 0, 0).tex(u, v).endVertex();
|
||||
}
|
||||
|
||||
private int getCharIndex(final char ch) {
|
||||
if (!CHAR_MAP.containsKey(ch)) {
|
||||
return CHAR_MAP.get('?');
|
||||
}
|
||||
return CHAR_MAP.get(ch);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
package li.cil.oc2.client.render.font;
|
||||
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
94
src/main/resources/assets/oc2/textures/font/OFL.TXT
Normal file
94
src/main/resources/assets/oc2/textures/font/OFL.TXT
Normal file
@@ -0,0 +1,94 @@
|
||||
Copyright (c) 2019 Dimitar Toshkov Zhekov,
|
||||
with Reserved Font Name "Terminus Font".
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 6.3 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 6.1 KiB |
Reference in New Issue
Block a user