blob: 8b10e37ec8a4851625a20a04badf501eec6e7369 [file] [log] [blame] [raw]
package gamax92.ocsymon;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import li.cil.oc.api.machine.LimitReachedException;
import li.cil.oc.api.machine.Machine;
import li.cil.oc.api.network.Network;
import li.cil.oc.api.network.Node;
/*
* So, Symon communicates via a dummy terminal (It used JTerminal, which acts
* like a VT100 terminal) However, Because I don't feel like importing all of
* that, and because I can't display a Swing Terminal on top of the screen, we
* use this instead.
*/
public class ConsoleDriver {
private Machine machine;
private String gpuADDR;
private String screenADDR;
private boolean canWrite = false;
private boolean canRead = false;
private LinkedList<Integer> fifo = new LinkedList<Integer>();
private LinkedList<Integer> databuf = new LinkedList<Integer>();
private int X = 1;
private int Y = 1;
private int W;
private int H;
public ConsoleDriver(Machine machine) {
this.machine = machine;
Map<String, String> components = this.machine.components();
Iterator<Map.Entry<String, String>> entries = components.entrySet().iterator();
Object[] response;
while (entries.hasNext()) {
Map.Entry<String, String> entry = entries.next();
String address = entry.getKey();
String type = entry.getValue();
if (type.equals("gpu") && gpuADDR == null) {
gpuADDR = address;
}
if (type.equals("screen") && screenADDR == null) {
screenADDR = address;
}
}
if (gpuADDR != null && screenADDR != null) {
try {
// Attempt to setup the GPU
machine.invoke(gpuADDR, "bind", new Object[] { screenADDR });
response = machine.invoke(gpuADDR, "getResolution", new Object[] {});
this.W = (Integer) response[0];
this.H = (Integer) response[1];
machine.invoke(gpuADDR, "setResolution", new Object[] { (double) this.W, (double) this.H });
machine.invoke(gpuADDR, "setBackground", new Object[] { (double) 0x000000 });
machine.invoke(gpuADDR, "setForeground", new Object[] { (double) 0xFFFFFF });
machine.invoke(gpuADDR, "fill", new Object[] { (double) 1, (double) 1, (double) this.W, (double) this.H, " " });
canWrite = true;
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void scroll() {
// Try to scroll the screen upwards.
try {
machine.invoke(gpuADDR, "copy", new Object[] { (double) 1, (double) 1, (double) this.W, (double) this.H, (double) 0, (double) -1 });
machine.invoke(gpuADDR, "fill", new Object[] { (double) 1, (double) this.H, (double) this.W, (double) 1, " " });
} catch (Exception e) {
e.printStackTrace();
}
this.Y = this.H;
}
// TODO: needs ANSI escape codes.
public void write(int character) {
if (canWrite) {
databuf.add(character);
}
}
public void flush() {
if (canWrite) {
try {
while (!databuf.isEmpty()) {
int character = databuf.getFirst();
switch (character) {
case 13:
break;
case 10:
this.X = 1;
this.Y = this.Y + 1;
if (this.Y > this.H)
scroll();
break;
default:
machine.invoke(gpuADDR, "set", new Object[] { (double) this.X, (double) this.Y, Character.toString((char) character) });
this.X = this.X + 1;
if (this.X > this.W) {
this.Y = this.Y + 1;
this.X = 1;
if (this.Y > this.H)
scroll();
}
}
databuf.removeFirst();
}
} catch (LimitReachedException e) {} catch (Exception e) {
e.printStackTrace();
}
}
}
public void pushChar(int character) {
fifo.add(character);
}
public boolean hasInput() {
return !fifo.isEmpty();
}
public int read() {
return fifo.removeFirst();
}
}