skunkworks/com/danitheskunk/skunkworks/gfx/vt/Terminal.java

693 lines
16 KiB
Java

package com.danitheskunk.skunkworks.gfx.vt;
import com.danitheskunk.skunkworks.Recti;
import com.danitheskunk.skunkworks.Vec2i;
import com.danitheskunk.skunkworks.gfx.Color;
import com.danitheskunk.skunkworks.gfx.font.Cp437;
import com.danitheskunk.skunkworks.gfx.font.IFont;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.List;
public class Terminal {
private final List<Cell> cells;
private final Vec2i fullCharSize;
private final IFont fullFont;
private Vec2i halfCharSize;
private final IFont halfFont;
private final Vec2i size;
public Terminal(Vec2i size, IFont fullFont, IFont halfFont) {
this.cells = new ArrayList<>();
this.size = size;
this.fullFont = fullFont;
this.halfFont = halfFont;
if(!fullFont.isMonospace() || !halfFont.isMonospace()) {
throw new RuntimeException("Fonts need to be monospace");
}
this.fullCharSize = fullFont.getMonospaceSize();
this.halfCharSize = halfFont.getMonospaceSize();
if(fullCharSize.getY() != halfCharSize.getY() ||
fullCharSize.getX() != halfCharSize.getX() * 2) {
throw new RuntimeException(
"halfFont needs to be half width of fullFont");
}
for(int i = 0; i < size.getY() * size.getX(); ++i) {
var cell = new Cell();
cell.fullChar = 0;
cell.secondChar = 0;
cell.halfWidth = false;
cell.bgColor = Color.TRANS_BLACK;
cell.fgColor = Color.WHITE;
cells.add(cell);
}
}
public Terminal(Vec2i size, IFont fullFont) {
this.cells = new ArrayList<>();
this.size = size;
this.fullFont = fullFont;
this.halfFont = null;
if(!fullFont.isMonospace()) {
throw new RuntimeException("Fonts need to be monospace");
}
this.fullCharSize = fullFont.getMonospaceSize();
for(int i = 0; i < size.getY() * size.getX(); ++i) {
var cell = new Cell();
cell.fullChar = 0;
cell.secondChar = 0;
cell.halfWidth = false;
cell.bgColor = Color.BLACK;
cell.fgColor = Color.WHITE;
cells.add(cell);
}
}
public void clear(Color bg) {
for(var cell : cells) {
cell.halfWidth = false;
cell.fullChar = 0;
cell.bgColor = bg;
}
}
public void drawBoxDouble(Recti rect) {
var pos = rect.getPos();
setChar(pos, Cp437.BOX_DOUBLE_RIGHT_BOTTOM);
setChar(Vec2i.add(pos, new Vec2i(rect.getWidth() - 1, 0)),
Cp437.BOX_DOUBLE_BOTTOM_LEFT
);
setChar(Vec2i.add(pos, new Vec2i(0, rect.getHeight() - 1)),
Cp437.BOX_DOUBLE_TOP_RIGHT
);
setChar(
Vec2i.add(pos,
new Vec2i(rect.getWidth() - 1, rect.getHeight() - 1)
),
Cp437.BOX_DOUBLE_TOP_LEFT
);
drawHorizontalDoubleLine(Vec2i.add(pos, new Vec2i(1, 0)),
rect.getWidth() - 2
);
drawHorizontalDoubleLine(Vec2i.add(pos,
new Vec2i(1, rect.getHeight() - 1)
), rect.getWidth() - 2);
drawVerticalDoubleLine(Vec2i.add(pos, new Vec2i(0, 1)),
rect.getHeight() - 2
);
drawVerticalDoubleLine(Vec2i.add(pos,
new Vec2i(rect.getWidth() - 1, 1)
), rect.getHeight() - 2);
}
public void drawBoxDouble(Recti rect, Color foregroundColor) {
var pos = rect.getPos();
setChar(pos, Cp437.BOX_DOUBLE_RIGHT_BOTTOM, foregroundColor);
setChar(Vec2i.add(pos, new Vec2i(rect.getWidth() - 1, 0)),
Cp437.BOX_DOUBLE_BOTTOM_LEFT,
foregroundColor
);
setChar(Vec2i.add(pos, new Vec2i(0, rect.getHeight() - 1)),
Cp437.BOX_DOUBLE_TOP_RIGHT,
foregroundColor
);
setChar(
Vec2i.add(pos,
new Vec2i(rect.getWidth() - 1, rect.getHeight() - 1)
),
Cp437.BOX_DOUBLE_TOP_LEFT,
foregroundColor
);
drawHorizontalDoubleLine(Vec2i.add(pos, new Vec2i(1, 0)),
rect.getWidth() - 2,
foregroundColor
);
drawHorizontalDoubleLine(
Vec2i.add(pos, new Vec2i(1, rect.getHeight() - 1)),
rect.getWidth() - 2,
foregroundColor
);
drawVerticalDoubleLine(Vec2i.add(pos, new Vec2i(0, 1)),
rect.getHeight() - 2,
foregroundColor
);
drawVerticalDoubleLine(
Vec2i.add(pos, new Vec2i(rect.getWidth() - 1, 1)),
rect.getHeight() - 2,
foregroundColor
);
}
public void drawBoxDouble(
Recti rect, Color foregroundColor, Color backgroundColor
) {
drawBoxDouble(rect, foregroundColor, backgroundColor, true);
}
public void drawBoxDouble(
Recti rect, Color foregroundColor, Color backgroundColor, boolean fill
) {
var pos = rect.getPos();
setChar(pos,
Cp437.BOX_DOUBLE_RIGHT_BOTTOM,
foregroundColor,
backgroundColor
);
setChar(Vec2i.add(pos, new Vec2i(rect.getWidth() - 1, 0)),
Cp437.BOX_DOUBLE_BOTTOM_LEFT,
foregroundColor,
backgroundColor
);
setChar(Vec2i.add(pos, new Vec2i(0, rect.getHeight() - 1)),
Cp437.BOX_DOUBLE_TOP_RIGHT,
foregroundColor,
backgroundColor
);
setChar(
Vec2i.add(pos,
new Vec2i(rect.getWidth() - 1, rect.getHeight() - 1)
),
Cp437.BOX_DOUBLE_TOP_LEFT,
foregroundColor,
backgroundColor
);
drawHorizontalDoubleLine(Vec2i.add(pos, new Vec2i(1, 0)),
rect.getWidth() - 2,
foregroundColor,
backgroundColor
);
drawHorizontalDoubleLine(
Vec2i.add(pos, new Vec2i(1, rect.getHeight() - 1)),
rect.getWidth() - 2,
foregroundColor,
backgroundColor
);
drawVerticalDoubleLine(Vec2i.add(pos, new Vec2i(0, 1)),
rect.getHeight() - 2,
foregroundColor,
backgroundColor
);
drawVerticalDoubleLine(
Vec2i.add(pos, new Vec2i(rect.getWidth() - 1, 1)),
rect.getHeight() - 2,
foregroundColor,
backgroundColor
);
if(fill) {
//todo: use draw rect
var x = rect.getX() + 1;
var y = rect.getY() + 1;
for(int iy = 0; iy < rect.getWidth() - 2; ++iy) {
for(int ix = 0; ix < rect.getWidth() - 2; ++ix) {
setBackgroundColor(new Vec2i(x + ix, y + iy),
backgroundColor
);
}
}
}
}
public void drawBoxSingle(Recti rect) {
var pos = rect.getPos();
setChar(pos, Cp437.BOX_SINGLE_RIGHT_BOTTOM);
setChar(Vec2i.add(pos, new Vec2i(rect.getWidth() - 1, 0)),
Cp437.BOX_SINGLE_BOTTOM_LEFT
);
setChar(Vec2i.add(pos, new Vec2i(0, rect.getHeight() - 1)),
Cp437.BOX_SINGLE_TOP_RIGHT
);
setChar(
Vec2i.add(pos,
new Vec2i(rect.getWidth() - 1, rect.getHeight() - 1)
),
Cp437.BOX_SINGLE_TOP_LEFT
);
drawHorizontalSingleLine(Vec2i.add(pos, new Vec2i(1, 0)),
rect.getWidth() - 2
);
drawHorizontalSingleLine(Vec2i.add(pos,
new Vec2i(1, rect.getHeight() - 1)
), rect.getWidth() - 2);
drawVerticalSingleLine(Vec2i.add(pos, new Vec2i(0, 1)),
rect.getHeight() - 2
);
drawVerticalSingleLine(Vec2i.add(pos,
new Vec2i(rect.getWidth() - 1, 1)
), rect.getHeight() - 2);
}
public void drawBoxSingle(Recti rect, Color foregroundColor) {
var pos = rect.getPos();
setChar(pos, Cp437.BOX_SINGLE_RIGHT_BOTTOM, foregroundColor);
setChar(Vec2i.add(pos, new Vec2i(rect.getWidth() - 1, 0)),
Cp437.BOX_SINGLE_BOTTOM_LEFT,
foregroundColor
);
setChar(Vec2i.add(pos, new Vec2i(0, rect.getHeight() - 1)),
Cp437.BOX_SINGLE_TOP_RIGHT,
foregroundColor
);
setChar(
Vec2i.add(pos,
new Vec2i(rect.getWidth() - 1, rect.getHeight() - 1)
),
Cp437.BOX_SINGLE_TOP_LEFT,
foregroundColor
);
drawHorizontalSingleLine(Vec2i.add(pos, new Vec2i(1, 0)),
rect.getWidth() - 2,
foregroundColor
);
drawHorizontalSingleLine(
Vec2i.add(pos, new Vec2i(1, rect.getHeight() - 1)),
rect.getWidth() - 2,
foregroundColor
);
drawVerticalSingleLine(Vec2i.add(pos, new Vec2i(0, 1)),
rect.getHeight() - 2,
foregroundColor
);
drawVerticalSingleLine(
Vec2i.add(pos, new Vec2i(rect.getWidth() - 1, 1)),
rect.getHeight() - 2,
foregroundColor
);
}
public void drawBoxSingle(
Recti rect, Color foregroundColor, Color backgroundColor
) {
drawBoxSingle(rect, foregroundColor, backgroundColor, true);
}
public void drawBoxSingle(
Recti rect, Color foregroundColor, Color backgroundColor, boolean fill
) {
var pos = rect.getPos();
setChar(pos,
Cp437.BOX_SINGLE_RIGHT_BOTTOM,
foregroundColor,
backgroundColor
);
setChar(Vec2i.add(pos, new Vec2i(rect.getWidth() - 1, 0)),
Cp437.BOX_SINGLE_BOTTOM_LEFT,
foregroundColor,
backgroundColor
);
setChar(Vec2i.add(pos, new Vec2i(0, rect.getHeight() - 1)),
Cp437.BOX_SINGLE_TOP_RIGHT,
foregroundColor,
backgroundColor
);
setChar(
Vec2i.add(pos,
new Vec2i(rect.getWidth() - 1, rect.getHeight() - 1)
),
Cp437.BOX_SINGLE_TOP_LEFT,
foregroundColor,
backgroundColor
);
drawHorizontalSingleLine(Vec2i.add(pos, new Vec2i(1, 0)),
rect.getWidth() - 2,
foregroundColor,
backgroundColor
);
drawHorizontalSingleLine(
Vec2i.add(pos, new Vec2i(1, rect.getHeight() - 1)),
rect.getWidth() - 2,
foregroundColor,
backgroundColor
);
drawVerticalSingleLine(Vec2i.add(pos, new Vec2i(0, 1)),
rect.getHeight() - 2,
foregroundColor,
backgroundColor
);
drawVerticalSingleLine(
Vec2i.add(pos, new Vec2i(rect.getWidth() - 1, 1)),
rect.getHeight() - 2,
foregroundColor,
backgroundColor
);
if(fill) {
//todo: use draw rect
var x = rect.getX() + 1;
var y = rect.getY() + 1;
for(int iy = 0; iy < rect.getWidth() - 2; ++iy) {
for(int ix = 0; ix < rect.getWidth() - 2; ++ix) {
setBackgroundColor(new Vec2i(x + ix, y + iy),
backgroundColor
);
}
}
}
}
public void drawHalfString(Vec2i pos, String str) {
drawHalfString(pos, str, null);
}
public void drawHalfString(Vec2i pos, String str, Color foregroundColor) {
drawHalfString(pos, str, foregroundColor, null);
}
public void drawHalfString(
Vec2i pos, String str, Color foregroundColor, Color backgroundColor
) {
IntBuffer buf;
try {
buf = ByteBuffer.wrap(str.getBytes("UTF-32")).asIntBuffer();
} catch(UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
for(int i = 0; i < str.length(); i += 2) {
var ch1 = buf.get(i);
var ch2 = i + 1 == str.length() ? 0 : buf.get(i + 1);
var cpos = new Vec2i(pos.getX() + i / 2, pos.getY());
if(ch1 < 0 || ch1 >= 256) ch1 = 0;
if(ch2 < 0 || ch2 >= 256) ch2 = 0;
setHalfChars(cpos, ch1, ch2);
if(foregroundColor != null) {
setForegroundColor(cpos, foregroundColor);
}
if(backgroundColor != null) {
setBackgroundColor(cpos, backgroundColor);
}
}
}
public void drawHorizontalDoubleLine(Vec2i pos, int len) {
var x = pos.getX();
var y = pos.getY();
for(int i = 0; i < len; ++i) {
setChar(new Vec2i(x + i, y), Cp437.BOX_DOUBLE_HORIZONTAL);
}
}
public void drawHorizontalDoubleLine(
Vec2i pos, int len, Color foregroundColor
) {
var x = pos.getX();
var y = pos.getY();
for(int i = 0; i < len; ++i) {
setChar(new Vec2i(x + i, y),
Cp437.BOX_DOUBLE_HORIZONTAL,
foregroundColor
);
}
}
public void drawHorizontalDoubleLine(
Vec2i pos, int len, Color foregroundColor, Color backgroundColor
) {
var x = pos.getX();
var y = pos.getY();
for(int i = 0; i < len; ++i) {
setChar(new Vec2i(x + i, y),
Cp437.BOX_DOUBLE_HORIZONTAL,
foregroundColor,
backgroundColor
);
}
}
public void drawHorizontalSingleLine(Vec2i pos, int len) {
var x = pos.getX();
var y = pos.getY();
for(int i = 0; i < len; ++i) {
setChar(new Vec2i(x + i, y), Cp437.BOX_SINGLE_HORIZONTAL);
}
}
public void drawHorizontalSingleLine(
Vec2i pos, int len, Color foregroundColor
) {
var x = pos.getX();
var y = pos.getY();
for(int i = 0; i < len; ++i) {
setChar(new Vec2i(x + i, y),
Cp437.BOX_SINGLE_HORIZONTAL,
foregroundColor
);
}
}
public void drawHorizontalSingleLine(
Vec2i pos, int len, Color foregroundColor, Color backgroundColor
) {
var x = pos.getX();
var y = pos.getY();
for(int i = 0; i < len; ++i) {
setChar(new Vec2i(x + i, y),
Cp437.BOX_SINGLE_HORIZONTAL,
foregroundColor,
backgroundColor
);
}
}
public void drawString(Vec2i pos, String str) {
drawString(pos, str, null);
}
public void drawString(Vec2i pos, String str, Color foregroundColor) {
drawString(pos, str, foregroundColor, null);
}
public void drawString(
Vec2i pos, String str, Color foregroundColor, Color backgroundColor
) {
IntBuffer buf;
try {
buf = ByteBuffer.wrap(str.getBytes("UTF-32")).asIntBuffer();
} catch(UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
for(int i = 0; i < str.length(); ++i) {
var ch = buf.get(i);
var cpos = new Vec2i(pos.getX() + i, pos.getY());
if(ch > 0 && ch < 256) {
setChar(cpos, ch);
}
if(foregroundColor != null) {
setForegroundColor(cpos, foregroundColor);
}
if(backgroundColor != null) {
setBackgroundColor(cpos, backgroundColor);
}
}
}
public void drawVerticalDoubleLine(Vec2i pos, int len) {
var x = pos.getX();
var y = pos.getY();
for(int i = 0; i < len; ++i) {
setChar(new Vec2i(x, y + i), Cp437.BOX_DOUBLE_VERTICAL);
}
}
public void drawVerticalDoubleLine(
Vec2i pos, int len, Color foregroundColor
) {
var x = pos.getX();
var y = pos.getY();
for(int i = 0; i < len; ++i) {
setChar(new Vec2i(x, y + i),
Cp437.BOX_DOUBLE_VERTICAL,
foregroundColor
);
}
}
public void drawVerticalDoubleLine(
Vec2i pos, int len, Color foregroundColor, Color backgroundColor
) {
var x = pos.getX();
var y = pos.getY();
for(int i = 0; i < len; ++i) {
setChar(new Vec2i(x, y + i),
Cp437.BOX_DOUBLE_VERTICAL,
foregroundColor,
backgroundColor
);
}
}
public void drawVerticalSingleLine(Vec2i pos, int len) {
var x = pos.getX();
var y = pos.getY();
for(int i = 0; i < len; ++i) {
setChar(new Vec2i(x, y + i), Cp437.BOX_SINGLE_VERTICAL);
}
}
public void drawVerticalSingleLine(
Vec2i pos, int len, Color foregroundColor
) {
var x = pos.getX();
var y = pos.getY();
for(int i = 0; i < len; ++i) {
setChar(new Vec2i(x, y + i),
Cp437.BOX_SINGLE_VERTICAL,
foregroundColor
);
}
}
public void drawVerticalSingleLine(
Vec2i pos, int len, Color foregroundColor, Color backgroundColor
) {
var x = pos.getX();
var y = pos.getY();
for(int i = 0; i < len; ++i) {
setChar(new Vec2i(x, y + i),
Cp437.BOX_SINGLE_VERTICAL,
foregroundColor,
backgroundColor
);
}
}
public Color getBackgroundColor(Vec2i pos) {
return cells.get(vecToPos(pos)).bgColor;
}
public int getChar(Vec2i pos) {
return cells.get(vecToPos(pos)).fullChar;
}
public Color getForegroundColor(Vec2i pos) {
return cells.get(vecToPos(pos)).fgColor;
}
public Vec2i getFullCharSize() {
return fullCharSize;
}
public IFont getFullFont() {
return fullFont;
}
public Vec2i getHalfCharSize() {
return halfCharSize;
}
public IFont getHalfFont() {
return halfFont;
}
public int getLeftHalfChar(Vec2i pos) {
return cells.get(vecToPos(pos)).fullChar;
}
public Vec2i getPixelSize() {
return Vec2i.mul(size, fullCharSize);
}
public int getRightHalfChar(Vec2i pos) {
return cells.get(vecToPos(pos)).secondChar;
}
public Vec2i getSize() {
return size;
}
public boolean isHalfWidth(Vec2i pos) {
return cells.get(vecToPos(pos)).halfWidth;
}
public void setBackgroundColor(Vec2i pos, Color color) {
var cell = cells.get(vecToPos(pos));
cell.bgColor = color;
}
public void setChar(Vec2i pos, int ch) {
var cell = cells.get(vecToPos(pos));
cell.fullChar = ch;
cell.halfWidth = false;
}
public void setChar(Vec2i pos, int ch, Color foregroundColor) {
var cell = cells.get(vecToPos(pos));
cell.fullChar = ch;
cell.halfWidth = false;
cell.fgColor = foregroundColor;
}
public void setChar(
Vec2i pos, int ch, Color foregroundColor, Color backgroundColor
) {
var cell = cells.get(vecToPos(pos));
cell.fullChar = ch;
cell.halfWidth = false;
cell.fgColor = foregroundColor;
cell.bgColor = backgroundColor;
}
public void setForegroundColor(Vec2i pos, Color color) {
var cell = cells.get(vecToPos(pos));
cell.fgColor = color;
}
public void setHalfChars(Vec2i pos, int chLeft, int chRight) {
var cell = cells.get(vecToPos(pos));
cell.fullChar = chLeft;
cell.secondChar = chRight;
cell.halfWidth = true;
}
public void setHalfChars(
Vec2i pos, int chLeft, int chRight, Color foregroundColor
) {
var cell = cells.get(vecToPos(pos));
cell.fullChar = chLeft;
cell.secondChar = chRight;
cell.halfWidth = true;
cell.fgColor = foregroundColor;
}
public void setHalfChars(
Vec2i pos, int chLeft, int chRight, Color foregroundColor,
Color backgroundColor
) {
var cell = cells.get(vecToPos(pos));
cell.fullChar = chLeft;
cell.secondChar = chRight;
cell.halfWidth = true;
cell.fgColor = foregroundColor;
cell.bgColor = backgroundColor;
}
private int vecToPos(Vec2i pos) {
return pos.getX() + pos.getY() * size.getX();
}
private class Cell {
Color bgColor;
Color fgColor;
int fullChar;
boolean halfWidth;
int secondChar;
}
}