package net.sf.jiga.xtended.impl;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.geom.Rectangle2D;
import java.io.*;
import java.util.List;
import java.util.*;
import java.util.logging.Logger;
import javax.media.jai.GraphicsJAI;
import net.sf.jiga.xtended.JXAException;
import net.sf.jiga.xtended.impl.game.HUD;
import net.sf.jiga.xtended.impl.game.RenderingScene;
import net.sf.jiga.xtended.impl.game.RenderingSceneComponent;
import net.sf.jiga.xtended.impl.game.TextLayout;
import net.sf.jiga.xtended.impl.game.TextLayout.POS;
import net.sf.jiga.xtended.impl.game.gl.AnimationGLHandler;
import net.sf.jiga.xtended.impl.game.gl.GLFX;
import net.sf.jiga.xtended.impl.game.gl.RenderingSceneGL;
import net.sf.jiga.xtended.impl.game.gl.geom.GLGeom;
import net.sf.jiga.xtended.kernel.*;
import net.sf.jiga.xtended.kernel.Console;
import org.lwjgl.opengl.GL11;
/**
* This class integrates a Console and implements the InputlogListener to listen
* to Console event, while it is drawn on a Graphics instance
*
* @author www.b23prodtm.info
*/
public final class GUIConsoleOutput implements Debugger, RenderingSceneComponent, InputLogListener, Threaded, KeyEventDispatcher, Resource {
private List<Long> pickLines(Object g2) {
/**
* defines MAX lines amount
*/
int MAXLINES = _getCharsResolution(g2, layout.bounds.getSize(), layout.interline, layout.margin).height;
_screenLines.setListCapacity(MAXLINES);
SortedSet<Long> lines = new TreeSet<Long>(screenLines.keySet());
/**
* PICK SCREENLINES SUBSET "end" is a timestamp, where the headset will
* end, "end" value excl.
*/
List<Long> pickLines = new ArrayList<Long>(lines.headSet(outputLastTimestamp));
/**
* fill up with as many lines as necessary from "end" boundary set incl.
* will be of size <= MAXLINES
*/
SortedSet<Long> pickMoreLines = lines.tailSet(outputLastTimestamp);
int fillCount = 0;
int fill = MAXLINES - pickLines.size();
if (fill > 0) {
for (Iterator<Long> it = pickMoreLines.iterator(); it.hasNext() && fillCount < fill; fillCount++) {
pickLines.add(it.next());
}
} else if (!pickLines.isEmpty()) {
/**
* or trim to MAXLINES size
*/
pickLines = pickLines.subList(Math.max(0, pickLines.size() - MAXLINES), pickLines.size());
}
/**
* END PICKING SCREENLINES SUBSET
*
*/
/**
* UPDATE END BOUNDARY with the new timestamp bound to the last line of
* text displayed = last + 1.0 millis
*/
outputLastTimestamp = pickLines.isEmpty() ? outputLastTimestamp : pickLines.get(pickLines.size() - 1) + 1L;
return pickLines;
}
/**
* a charsequence that is fast to serialize and deserialize
*
* @see #sb()
*/
public static class LineBuffer implements Externalizable {
private StringBuffer sb = new StringBuffer();
public LineBuffer() {
}
public LineBuffer(String str) {
sb.append(str);
}
/**
* string builder, the buffer content actually
*/
public StringBuffer sb() {
return sb;
}
@Override
public String toString() {
return sb.toString();
}
@Override
public boolean equals(Object obj) {
return obj == null ? false : obj.toString().equals(toString());
}
@Override
public int hashCode() {
return toString().hashCode();
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(sb.toString().toCharArray());
out.flush();
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
sb.append((char[]) in.readObject());
}
}
static {
DebugMap._getInstance().associateDebugLevel(GUIConsoleOutput.class, Sprite.DBUG_RENDER_LOW);
}
/**
* the screen lines buffer
*/
SpritesCacheManager<Long, LineBuffer> _screenLines;
/**
* the screen lines synchronized buffer view
*/
SortedMap<Long, LineBuffer> screenLines;
/**
* the integrated console
*/
private Console console = new Console();
/**
* the dis/enable switch for the console. default is disabled (false)
*/
private boolean enabled = false;
private HUD hud;
private LineBuffer getLine(long linestamp) {
if (screenLines.isEmpty()) {
return new LineBuffer();
} else {
return !screenLines.containsKey(linestamp) ? new LineBuffer() : screenLines.get(linestamp);
}
}
private LineBuffer getLastLine() {
return screenLines.isEmpty() ? new LineBuffer() : getLine(screenLines.lastKey());
}
private long getLastLineKey() {
return screenLines.isEmpty() ? System.nanoTime() : screenLines.lastKey();
}
private long insertLine(long timestamp, int appendBegin, String appendChars) {
LineBuffer line = getLine(timestamp);
/**
* is the line ending with a cariage return then a new line is created
*/
if (!line.sb.substring(0, appendBegin).endsWith(Console.newLine)) {
line.sb.insert(appendBegin, appendChars);
} else {
timestamp = timestamp + 1;
line = getLine(timestamp);
line.sb.append(appendChars);
}
screenLines.put(timestamp, line);
return timestamp;
}
/**
*
* @param timestamp line key stamp
* @param deleteBegin start index inclusive
* @param deleteEnd end index exclusive
* @return
*/
private long deleteLine(long timestamp, int deleteBegin, int deleteEnd) {
LineBuffer line = getLine(timestamp);
line.sb.delete(deleteBegin, deleteEnd);
if (line.sb.length() < 1) {
screenLines.remove(timestamp);
} else {
screenLines.put(timestamp, line);
}
return timestamp;
}
/**
* used to post a new packet message to log
*
* @param message to packet message to log
* @see #pushBuffer(String)
*/
private void pushBuffer(String message) {
if (!enabled) {
return;
}
LineBuffer packet = new LineBuffer(message);
final Monitor monitor = popMonitor;
try {
synchronized (monitor) {
while (popping) {
monitor.waitOnQueue(50);
}
pushing = true;
if (packet.sb.length() > 0) {
String[] lines = packet.toString().split(Console.newLine);
if (packet.toString().equals(Console.newLine)) {
lines = new String[]{" "};
/**
* its only a carriage return
*/
}
for (int i = 0; i < lines.length; i++) {
String line = lines[i];
if (i < lines.length - 1) {
/**
* insert carriage return
*/
line += Console.newLine;
} else {
/**
* is the last line ending in carriage return ? then
* add it or not
*/
line += packet.toString().endsWith(Console.newLine) ? Console.newLine : "";
}
LineBuffer strBuf = getLastLine();
long strKey = getLastLineKey();
insertLine(strKey, strBuf.sb.length(), line);
}
}
monitor.notify();
}
} catch (InterruptedException ex) {
if (isDebugEnabled()) {
ex.printStackTrace();
}
} finally {
final Monitor monitor1 = pushMonitor;
synchronized (monitor1) {
pushing = false;
monitor1.notifyAll();
}
}
}
public void deleteBufferChars(final int len) {
try {
aSynclogThreadPackets.doAndWait(new Runnable() {
@Override
public void run() {
_deleteBufferChars(len);
}
});
} catch (InterruptedException ex) {
if (isDebugEnabled()) {
ex.printStackTrace();
}
}
}
private void _deleteBufferChars(int len) {
final Monitor monitor = popMonitor;
try {
synchronized (monitor) {
while (popping) {
monitor.waitOnQueue(50);
}
pushing = true;
if (!_screenLines.isEmpty()) {
LineBuffer line = getLastLine();
deleteLine(getLastLineKey(), Math.max(0, line.sb.length() - len), line.sb.length());
}
}
} catch (InterruptedException ex) {
if (isDebugEnabled()) {
ex.printStackTrace();
}
} finally {
final Monitor monitor1 = pushMonitor;
synchronized (monitor1) {
pushing = false;
monitor1.notifyAll();
}
}
}
ThreadWorks aSynclogThreadPackets = new ThreadWorks("GCO-logpackets");
/**
* the method send the log packet to the screenlines buffer that is further
* drawn on Graphics.
*
* @param pmessage the message to send to buffer
* @see #newLogPacket(String)
*/
@Override
public void newLogPacket(String pmessage) {
/*
* try {
*/
final String message = pmessage;
Runnable r = new Runnable() {
@Override
public void run() {
pushBuffer(message);
}
};
aSynclogThreadPackets.doLater(r, _screenLines);
}
private TextLayout layout = new TextLayout(new Point(), POS.CENTER, POS.TOP, 2, 2, new Rectangle());
/**
* alpha transparency of the component on Graphics
*/
private float alpha = 0.8f;
/**
* cursor animation
*/
private GUICursor cursor;
/**
* push on buffer monitor
*/
private boolean pushing = false;
/**
* pop on buffer monitor
*/
private boolean popping = false;
/**
* push monitor
*/
private Monitor pushMonitor;
/**
* pop monitor
*/
private Monitor popMonitor;
/**
* sets thread group
*
* @param tg Thread to make it parent of all threads in this instance, if
* null, the current Thread parent Threadgroup is used
*/
@Override
public void setGroupMonitor(Monitor... tg) {
pushMonitor = tg[0];
popMonitor = tg[1];
}
/**
* hash
*/
private long hash = System.nanoTime();
/**
* returns the hash-code
*
* @return the hash-code
* @see #equals(Object)
*/
@Override
public int hashCode() {
return (int) hash;
}
/**
* returns true or false, whether this instance is equal to the specified
* Object or not, resp.
*
* @param o the object to compare against
* @return true or false, whether this instance is equal to the specified
* Object or not, resp.
* @see #hashCode()
*/
@Override
public boolean equals(Object o) {
return o == null ? false : hashCode() == o.hashCode();
}
/**
* Creates a new instance of GUIConsoleOutput
*
* @param screenLinesBufferSize the buffer size
* @param size the size of the Sprite
* @param enabled whether to enable or disable console
*/
public GUIConsoleOutput(RenderingScene scene, Dimension size, boolean enabled) {
setRenderingScene(scene);
setGroupMonitor(new Monitor(), new Monitor());
hud = HUD._new(scene);
setSize(size);
_screenLines = new SpritesCacheManager<Long, LineBuffer>();
screenLines = Collections.synchronizedSortedMap(_screenLines);
_screenLines.setSwapDiskEnabled(true);
console.setStdoutEnabled(true);
setConsoleEnabled(enabled);
try {
cursor = new GUICursor("cursor", true, new Dimension(5, 10));
} catch (Exception ex) {
if (DebugMap._getInstance().isDebugLevelEnabled(RenderingScene.DBUG_RENDER)) {
ex.printStackTrace();
}
}
}
/**
* dis/enables to read the System.out
*
* @param b dis/enable
* @throws IOException if std console cannot be dis/enabled
*/
public void setLogStdoutEnabled(boolean b) throws IOException {
console.setLogStdoutEnabled(b);
}
/**
* draws one line of characters to Graphics
*
* @param args the arg's to format the output
* @param g2 the Graphics2D or GLAutoDrawable instance to paint on
* @param currentLine the current line to eventually append new chars
* @param line characters data to draw
* @param newLine whether it has to be a new line or not
* @see #_newArgsMap(Rectangle)
*/
public static Rectangle _drawLine(TextLayout args, Object g2, LineBuffer line, LineBuffer currentLine, boolean newLine, double z) {
return _drawLine(args, g2, line, currentLine, newLine, z, true);
}
/**
* @param draw if false, returns hud_helpcommands dirty region without
* painting
* @param currentLine -ignored-
*
*/
public static Rectangle _drawLine(TextLayout args, Object g2, LineBuffer textLine, LineBuffer currentLine, boolean newLine, double z, boolean draw) {
if (textLine == null) {
return new Rectangle();
}
if (textLine.sb.length() <= 0) {
return new Rectangle();
}
if (currentLine == null) {
currentLine = new LineBuffer();
}
try {
Shape clip;
Dimension appendDim, clipSize;
clipSize = args.bounds.getSize();
if (g2 instanceof Graphics2D) {
clip = ((Graphics2D) g2).getClip();
((Graphics2D) g2).clipRect(0, 0, clipSize.width, clipSize.height);
appendDim = RenderingScene._toGraphicalMetrics(textLine.toString(), (Graphics2D) g2);
} else {
clip = null;
appendDim = RenderingSceneGL._GLtoGraphicalMetrics(textLine.toString(), (RenderingSceneGL) g2);
}
Point pos = (Point) args.nextOutputPX.clone();
/*
* to place "cursor" (console prints up-to-down and left-to-right
* exception for bottom valign that prints down-to-up) vertically
*/
switch (args.valign) {
case CENTER:
if (pos.y == 0) {
pos.y = Math.round((float) (clipSize.height + appendDim.height) / 2.0f);
}
if (newLine) {
pos.y += args.interline + appendDim.height;
}
break;
case TOP:
if (pos.y == 0) {
pos.y = args.interline + appendDim.height;
}
if (newLine) {
pos.y += args.interline + appendDim.height;
}
break;
case BOTTOM:
if (pos.y == 0) {
pos.y = clipSize.height - args.interline;
}
if (newLine) {
pos.y -= args.interline + appendDim.height;
}
break;
default:
pos.y = 0;
break;
}
/*
* horizontally
*/
switch (args.align) {
case CENTER:
if (newLine) {
pos.x = Math.round((float) (clipSize.width - appendDim.width) / 2.0f);
}
break;
case RIGHT:
if (newLine) {
pos.x = Math.round(clipSize.width - appendDim.width - args.margin);
}
break;
case LEFT:
if (newLine) {
pos.x = args.margin;
}
break;
default:
pos.x = 0;
break;
}
Rectangle dirtyArea = new Rectangle();
/*
* text length is to wide ? wrap lines, cut text
*/
if ((pos.x + appendDim.width) > clipSize.width) {
int textLineEndIndex = 0;
/**
* cut string
*/
int clpSz = (newLine ? clipSize.width : clipSize.width - (pos.x + args.margin));
if (g2 instanceof Graphics2D) {
textLineEndIndex = (int) Math.min(RenderingScene._toMaxCharsCOLS(
clpSz,
args.margin,
(Graphics2D) g2), textLine.sb.length()) - 1;
} else {
textLineEndIndex = (int) Math.min(RenderingSceneGL._GLtoMaxCharsCOLS(
clpSz,
args.margin, (RenderingSceneGL) g2), textLine.sb.length()) - 1;
}
if (textLineEndIndex < 1) {
/**
* end of line
*/
return dirtyArea;
}
/**
* send line wrap
*/
dirtyArea.setBounds(_drawLine(args, g2, new LineBuffer(textLine.sb.substring(0, textLineEndIndex)), null, false, z, draw));
dirtyArea.add(_drawNewLine(args, g2, new LineBuffer(textLine.sb.substring(textLineEndIndex)), z, draw));
return dirtyArea;
}
/*
* >>>> to draw line <<<<
*/
if (pos.x < clipSize.width && pos.y < clipSize.height && pos.y > 0) {
if (draw) {
if (g2 instanceof Graphics2D) {
((Graphics2D) g2).drawString(textLine.toString(), pos.x, pos.y);
} else {
RenderingSceneGL._GLRenderText2D((RenderingSceneGL) g2, textLine.toString(), pos.x, pos.y, z);
}
}
dirtyArea.setBounds(pos.x, pos.y - appendDim.height, appendDim.width, appendDim.height);
pos.x += appendDim.width;
args.nextOutputPX = pos;
if (g2 instanceof Graphics2D) {
((Graphics2D) g2).setClip(clip);
}
}
return dirtyArea;
} catch (Exception ex) {
if (DebugMap._getInstance().isDebuggerEnabled(GUIConsoleOutput.class)) {
ex.printStackTrace();
}
return new Rectangle();
}
}
/**
* draws a new line to the specified GraphicsJAI instance
*
* @param args the arg's to format the output
* @param g2 the Graphics2D or GLAutoDrawable instance to paint on
* @param line characters data to draw
* @see #_newArgsMap(Rectangle)
*/
public static Rectangle _drawNewLine(TextLayout args, Object g2, LineBuffer line, double z) {
return _drawNewLine(args, g2, line, z, true);
}
/**
* @param draw if false, returns hud_helpcommands dirty region without
* painting
*/
public static Rectangle _drawNewLine(TextLayout args, Object g2, LineBuffer line, double z, boolean draw) {
return _drawLine(args, g2, line, null, true, z, draw);
}
/**
* sets the alpha transparency value
*
* @param alpha alpha transparency value .0f is the transparent while 1.0f
* is opaque
* @see AlphaComposite#getInstance(int, float)
*/
public void setAlpha(float alpha) {
this.alpha = alpha;
}
/**
* sets the horizontal alignement for the characters
*
* @param align the horizontal alignement
* @see #RIGHT
* @see #CENTER
* @see #LEFT
*/
public void setAlign(POS align) {
this.layout.align = align;
}
/**
* sets the vertical alignment for the characters
*
* @param valign the vertical alignement
* @see #TOP
* @see #CENTER
* @see #BOTTOM
*/
public void setValign(POS valign) {
this.layout.valign = valign;
}
/**
* clears the contents of the screen and the buffer
*
* @see Console#clearContents()
*/
public void clearContents() {
screenLines.clear();
_screenLines.clearMemorySwap();
hud.reset();
}
/**
* @see #setInterline(Integer)
*/
public void setMargin(Integer margin) {
this.layout.margin = margin;
}
/**
* *
* @see #setMargin(Integer)
*/
public void setInterline(Integer interline) {
this.layout.interline = interline;
}
/**
* out-set for the output buffer
*/
long outputLastTimestamp = 0;
/**
* scrolls the buffer up (one step)
*
* @see #scrollDown()
*/
public void scrollUp() {
synchronized (popMonitor) {
try {
while (popping) {
popMonitor.waitOnQueue(50);
}
/**
* current picking
*/
SortedSet<Long> set = new TreeSet(screenLines.keySet()).headSet(outputLastTimestamp);
/**
* take one timestamp before
*/
outputLastTimestamp = set.size() < 2 ? outputLastTimestamp : set.headSet(set.last()).last() + 1L;
scrolling = true;
} catch (InterruptedException ex) {
ex.printStackTrace();
} finally {
popMonitor.notify();
}
}
}
/**
* scrolls the buffer down (one step)
*
* @see #scrollUp()
*/
public void scrollDown() {
synchronized (popMonitor) {
try {
while (popping) {
popMonitor.waitOnQueue(50);
}
SortedSet<Long> set = new TreeSet(screenLines.keySet()).tailSet(outputLastTimestamp);
outputLastTimestamp = set.isEmpty() ? outputLastTimestamp : set.first() + 1L;
scrolling = true;
} catch (InterruptedException ex) {
ex.printStackTrace();
} finally {
popMonitor.notify();
}
}
}
/**
* scrolls the buffer to the first key/line
*/
public void scrollTop() {
synchronized (popMonitor) {
try {
while (popping) {
popMonitor.waitOnQueue(50);
}
outputLastTimestamp = screenLines.isEmpty() ? 0 : screenLines.firstKey() + 1L;
scrolling = true;
} catch (InterruptedException ex) {
ex.printStackTrace();
} finally {
popMonitor.notify();
}
}
}
/**
* scrolls the buffer to the last key/line
*/
public void scrollBottom() {
synchronized (popMonitor) {
try {
while (popping) {
popMonitor.waitOnQueue(50);
}
outputLastTimestamp = screenLines.isEmpty() ? System.nanoTime() : screenLines.lastKey() + 1L;
scrolling = true;
} catch (InterruptedException ex) {
ex.printStackTrace();
} finally {
popMonitor.notify();
}
}
}
/**
* interrupts the scrolling (this will bring the cursor to the last output)
*
* @see #scrollDown()
* @see #scrollUp()
*/
public void stopScroll() {
synchronized (popMonitor) {
try {
while (popping) {
popMonitor.waitOnQueue(50);
}
scrolling = false;
} catch (InterruptedException ex) {
ex.printStackTrace();
} finally {
popMonitor.notify();
}
}
}
/**
* scroll switch
*/
boolean scrolling = false;
/**
*
*/
public boolean draw(Component obs, Graphics g) throws InterruptedException {
try {
return __draw(obs, g, 0);
} catch (Exception ex) {
InterruptedException ie = new InterruptedException();
ie.initCause(ex);
throw ie;
}
}
/**
*
*/
public void GLdraw(RenderingSceneGL c, double z) throws InterruptedException {
try {
GLFX._GLpushRender("__draw", this, new Object[]{c, c, z}, new Class[]{Component.class, Object.class, double.class});
} catch (Exception ex) {
InterruptedException ie = new InterruptedException();
ie.initCause(ex);
throw ie;
}
}
Point cursorInput = new Point(0, 0);
Dimension charDim = new Dimension();
/**
* INTERNAL USE ONLY draws the contents to the given Graphics. This method
* is already synchronized with the buffer.
*
* @param g a Graphics2D instance to draw onto(Java2D soft rendering) or an
* RenderingSceneGL instance (LWJGL rendering)
* @param obs the observer to use
* @param z used for z depth coord in GL mode
* @return true or false whether the painting was complete or not
* @throws InterruptedException
*/
public boolean __draw(Component obs, Object g, double z) throws InterruptedException, Exception {
boolean complete = true;
Composite cps = null;
Color c = null;
Shape clip = null;
final Monitor monitor0 = pushMonitor;
boolean interrupt_ = false;
try {
synchronized (monitor0) {
while (pushing) {
monitor0.wait();
}
popping = true;
/**
* console translucent background
*/
if (g instanceof Graphics2D) {
cps = ((Graphics2D) g).getComposite();
((Graphics2D) g).setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
c = ((Graphics2D) g).getColor();
((Graphics2D) g).setColor(getBackground());
clip = ((Graphics2D) g).getClip();
((Graphics2D) g).clipRect(layout.bounds.x + layout.margin, layout.bounds.y + layout.interline, -(int) (2f * (float) layout.margin) + layout.bounds.width, -(int) (2f * (float) layout.interline) + layout.bounds.height);
((Graphics2D) g).fillRoundRect(layout.bounds.x, layout.bounds.y, layout.bounds.width, layout.bounds.height, layout.margin, layout.interline);
((Graphics2D) g).setColor(getForeground().brighter());
((Graphics2D) g).drawRoundRect(layout.bounds.x, layout.bounds.y, layout.bounds.width, layout.bounds.height, layout.margin, layout.interline);
((Graphics2D) g).setColor(getForeground());
} else {
GLGeom._GLfillPolygon((RenderingSceneGL) g, true, layout.bounds, z, 0, null, GLGeom.getGlowingColor(getBackground(), alpha));
GLGeom._GLdrawPolygon((RenderingSceneGL) g, true, layout.bounds, z, 0, null, GLGeom.getGlowingColor(getForeground().brighter(), alpha));
}
/**
* scroll bar
*/
Rectangle2D scrollBar = new Rectangle(layout.bounds.width - layout.margin - 2, layout.interline, 4, layout.bounds.height - (int) ((float) layout.interline * 2f));
if (g instanceof Graphics2D) {
((Graphics2D) g).translate(layout.bounds.x, layout.bounds.y);
((Graphics2D) g).fillRoundRect((int) scrollBar.getX(), (int) scrollBar.getY(), (int) scrollBar.getWidth(), (int) scrollBar.getHeight(), layout.margin, layout.interline);
} else {
GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glPushMatrix();
GL11.glTranslatef(layout.bounds.x, layout.bounds.y, 0);
GLGeom._GLfillPolygon((RenderingSceneGL) g, true, scrollBar.getBounds(), GLGeom.getCWrgbaColors(getForeground(), alpha), z);
}
if (!scrolling) {
outputLastTimestamp = System.nanoTime();
}
float offset = (float) screenLines.headMap(outputLastTimestamp).size() / (float) screenLines.size();
if (screenLines.tailMap(outputLastTimestamp).isEmpty()) {
scrolling = false;
}
Rectangle scrollBarPath = new Rectangle(layout.bounds.width - layout.margin - 6, (int) scrollBar.getY() + (int) (offset * (float) scrollBar.getHeight()) - 6, 12, 12);
if (g instanceof Graphics2D) {
((Graphics2D) g).fillRoundRect(scrollBarPath.x, scrollBarPath.y, scrollBarPath.width, scrollBarPath.height, layout.margin, layout.interline);
((Graphics2D) g).translate(-layout.bounds.x, -layout.bounds.y);
} else {
GLGeom._GLfillPolygon((RenderingSceneGL) g, true, scrollBarPath.getBounds(), GLGeom.getCWrgbaColors(getForeground(), alpha), z);
GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glPopMatrix();
}
/**
* end scrollbar
*/
drawScreenBuffer(g, z);
if (DebugMap._getInstance().isDebuggerEnabled(GUIConsoleOutput.class)) {
System.out.println("gcolayout : " + layout);
}
/**
* console text cursor
*/
if (g instanceof Graphics2D) {
((Graphics2D) g).translate(layout.bounds.x, layout.bounds.y);
} else {
GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glPushMatrix();
GL11.glTranslatef(layout.bounds.x, layout.bounds.y, 0);
}
if (g instanceof Graphics2D) {
charDim = RenderingScene._toGraphicalMetrics((Graphics2D) g);
} else {
charDim = RenderingSceneGL._GLtoGraphicalMetrics((RenderingSceneGL) g);
}
Point p = layout.nextOutputPX;
if (g instanceof Graphics2D) {
cursor.play();
cursor.setSize(RenderingScene._toGraphicalMetrics(((Graphics2D) g)));
cursor.runValidate();
cursor.setLocation(p.x, p.y - cursor.getHeight());
complete = cursor.draw(obs, ((Graphics2D) g), GLFX.gfx.FX_SHADOW.bit(), new Point(1, 1), Color.ORANGE) && complete;
((Graphics2D) g).translate(-layout.bounds.x, -layout.bounds.y);
((Graphics2D) g).setClip(clip);
((Graphics2D) g).setColor(c);
((Graphics2D) g).setComposite(cps);
} else {
cursor.setSize(RenderingSceneGL._GLtoGraphicalMetrics((RenderingSceneGL) g));
cursor.setLocation(p.x, p.y - cursor.getHeight());
if ((RenderingSceneGL._GLgetLoadState(cursor) & RenderingSceneGL._GLLOADSTATE_Cleared) != 0) {
RenderingSceneGL._GLloadAnim(cursor, (RenderingSceneGL) getRenderingScene(), RenderingSceneGL.PTY_ANIM);
}
AnimationGLHandler hdr = Animation._GLHandlers.getHandler(cursor);
hdr.play();
hdr.runValidate();
Animation._GLRenderAnimation((RenderingSceneGL) g, hdr, cursor.getBounds(new Rectangle()), z, 0, null, null, null, GLGeom.getCWrgbaColors(getRenderingScene().getForeground(), alpha));
GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glPopMatrix();
}
monitor0.notify();
}
} catch (InterruptedException e) {
if (isDebugEnabled()) {
e.printStackTrace();
}
interrupt_ = true;
} finally {
final Monitor monitor1 = popMonitor;
synchronized (monitor1) {
popping = false;
monitor1.notifyAll();
}
if (interrupt_) {
throw new InterruptedException("GUIConsole has caught an interruption.");
}
return complete;
}
}
/**
* the PrintStream instance
*/
private PrintStream printStream = null;
/**
* returns the PrintStream instance to accept inputs
*
* @return the PrintStream instance to accept inputs
*/
public PrintStream getPrintStream() {
if (printStream != null) {
return printStream;
}
printStream = console.getNewPrintStream(new ErrorListener() {
@Override
public void printStreamError(IOException ioe) {
ioe.printStackTrace();
}
});
return printStream;
}
private Color background = Color.GRAY;
private Color foreground = Color.WHITE;
public Color getBackground() {
return background;
}
public Color getForeground() {
return foreground;
}
public void setBackground(Color c) {
background = c;
}
public void setForeground(Color c) {
foreground = c;
}
/**
* processes the keyboard Events (essentially KeyEvent.KEY_TYPED events)
*
* @param e the keyboard Event to process
* @return true or false, whether the KeyEvent has been accepted or not
*/
@Override
public boolean dispatchKeyEvent(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_BACK_SPACE:
if (e.getID() == KeyEvent.KEY_PRESSED) {
deleteBufferChars(1);
}
return true;
case KeyEvent.VK_ENTER:
if (e.getID() == KeyEvent.KEY_PRESSED) {
newLogPacket("" + Console.newLine);
}
return true;
default:
break;
}
if (e.getID() == KeyEvent.KEY_TYPED && e.getKeyChar() != KeyEvent.CHAR_UNDEFINED) {
newLogPacket("" + e.getKeyChar());
return true;
}
return false;
}
/**
* returns the current Console instance.
*
* @return the current Console
*/
public Console getConsole() {
return console;
}
/**
* dis/enables to draw additional lines
*
* @param b dis/enables subsequent lines
* @see Console#setLogStdoutEnabled(boolean)
*/
public void setConsoleEnabled(boolean b) {
enabled = b;
boolean b2 = console.isLogStdoutEnabled();
try {
console.setLogStdoutEnabled(false);
} catch (IOException ex) {
if (isDebugEnabled()) {
ex.printStackTrace();
}
} finally {
if (b) {
console.addInputLogListener(this);
} else {
console.removeInputLogListener(this);
}
try {
console.setLogStdoutEnabled(b2);
} catch (IOException ex) {
if (isDebugEnabled()) {
ex.printStackTrace();
}
}
}
}
public void setBounds(int x, int y, int width, int height) {
Rectangle nbounds = new Rectangle(x, y, width, height);
if (!nbounds.equals(layout.bounds)) {
setDirty(true);
}
layout.bounds.setBounds(nbounds);
}
public void setBounds(Rectangle r) {
setBounds(r.x, r.y, r.width, r.height);
}
public void setSize(int width, int height) {
setSize(new Dimension(width, height));
}
public void setSize(Dimension size) {
assert size != null : "null size was given";
setBounds(layout.bounds.x, layout.bounds.y, size.width, size.height);
}
public Dimension getSize() {
return layout.bounds.getSize();
}
public Rectangle getBounds(Rectangle rv) {
if (rv != null) {
rv.setBounds(layout.bounds);
} else {
rv = layout.bounds.getBounds();
}
return rv;
}
public Rectangle getBounds() {
return layout.bounds.getBounds();
}
public void setLocation(Point p) {
setBounds(p.x, p.y, layout.bounds.width, layout.bounds.height);
}
public void setLocation(int x, int y) {
setLocation(new Point(x, y));
}
/**
* <u>disabled check by default;</u>
* {@code DebugMap._getInstance().setDebugLevelEnabled(true, RenderingScene.DBUG_RENDER)}
* enables this method functionality. <br>It checks for the specified arg's
* map if they're valid to be used for
* {@link #_drawLine(net.sf.jiga.xtended.impl.game.TextLayout, java.lang.Object, net.sf.jiga.xtended.impl.GUIConsoleOutput.LineBuffer, net.sf.jiga.xtended.impl.GUIConsoleOutput.LineBuffer, boolean, double) drawing Fonts}
*
* @param args the map that contains the arg's
* @throws JXAException if the arguments objects are not of the correct
* Class instances
* @throws ClassNotFoundException if an argument object is missing
* @see #_newArgsMap(Rectangle)
*/
public boolean drawHeadlines = true;
/**
* draws the current buffer beginning at 0,0 (it's the RasterPos for a GL
* context)
*
* @param g2 the GraphicsJAI or RenderingScene instance to paint on
* @param GLend GLend bound timestamp (though contents beyond this bound may
* be displayed to fill up the screen)
* @see #screenLines
*/
private void drawScreenBuffer(Object g2, double z) {
/**
* HUD console contents BEGIN
*/
hud.setBounds(layout.bounds, z);
hud.pushContent("TITLE", "Console HUD", POS.CENTER, POS.TOP, true);
Dimension r = layout.bounds.getSize();
hud.pushContent("INFO", r.width + "x" + r.height, POS.CENTER, POS.TOP, true);
if (g2 instanceof RenderingScene) {
hud.GLbegin();
} else {
hud.begin();
}
/**
* first the headlines (set in the constructor)
*/
hud.updateContentVisiblity("TITLE", drawHeadlines);
hud.updateContentVisiblity("INFO", drawHeadlines);
Dimension res = _getCharsResolution(g2, layout.bounds.getSize(), layout.interline, layout.margin);
hud.updateContent("INFO", res.width + "x" + res.height);
/**
*/
synchronized (screenLines) {
List<Long> pickLines = pickLines(g2);
/**
* PickedLines are pushed into the HUD trays (MAXLINES count), ready
* to display.
*/
Iterator<Long> it = pickLines.iterator();
for (int i = 0; i < pickLines.size(); i++) {
String lineKey = "GCO_line-" + i;
LineBuffer sb = null;
if (it.hasNext()) {
Long l = it.next();
sb = screenLines.get(l);
}
hud.pushContent(lineKey, sb == null ? "" : sb.toString(), layout.align, layout.valign, true);
}
}
if (g2 instanceof RenderingSceneGL) {
hud.GLrenderContents((RenderingSceneGL) g2);
hud.GLend();
} else {
hud.renderContents((Graphics2D) g2);
hud.end();
}
/*
* HUD END
*/
/**
* cursor position handle
*/
layout.nextOutputPX.setLocation(hud.getHUDArgs(layout.align, layout.valign).nextOutputPX);
}
/**
* overriden to terminate the console before loosing the component
*
* @throws Throwable if the Console finalization fails
*/
@Override
public void finalize() throws Throwable {
console.finalize();
super.finalize();
}
/**
* the multi-threading switch private boolean multiThreading = true;
*/
/**
* returns true or false, whether the multi-threading mode is enabled or
* not, resp.
*
* @return true or false, whether the multi-threading mode is enabled or
* not, resp.
*/
@Override
public boolean isMultiThreadingEnabled() {
return renderable.isMultiThreadingEnabled();
}
/**
* dis/enables the multi-threading mode
*
* @param b dis/enables the multi-threading mode
*/
@Override
public void setMultiThreadingEnabled(boolean b) {
renderable.setMultiThreadingEnabled(b);
}
/**
*
*/
@Override
public Monitor[] getGroupMonitor() {
return new Monitor[]{pushMonitor, popMonitor};
}
/**
* return the current RenderingScene instance using this instance
*
* @return the current RenderingScene instance using this instance
*/
@Override
public RenderingScene getRenderingScene() {
return renderable.getRenderingScene();
}
/**
* sets up the RenderingScene instance that is using this instance
* (corresponding settings are updated, e.g. multi-threading)
*
* @param renderingScene the RenderingScene that is using this instance
*/
@Override
public void setRenderingScene(RenderingScene renderingScene) {
renderable.setRenderingScene(renderingScene);
}
/**
* returns true or false, whether this instance is using hardware
* acceleration or not, resp.
*
* @return true or false, whether this instance is using hardware
* acceleration or not, resp.
*/
@Override
public boolean isHardwareAccel() {
return renderable.isHardwareAccel();
}
/**
* dis/enables hardware acceleration
*
* @param b dis/enables hardware acceleration
*/
@Override
public void setHardwareAccel(boolean b) {
renderable.setHardwareAccel(b);
}
/**
* returns true or false, whether the debugging mode is enabled or not,
* resp.
*
* @return true or false, whether the debugging mode is enabled or not,
* resp.
*/
public boolean isDebugEnabled() {
return renderable.isDebugEnabled();
}
/**
* dis/enables the debugging mode
*
* @param b dis/enables the debugging mode
*/
public void setDebugEnabled(boolean b) {
renderable.setDebugEnabled(b);
}
Sf3RenderableImpl renderable = new Sf3RenderableImpl(GUIConsoleOutput.class);
/**
* returns the average resolution for multi-character output in the
* specified Graphics clipping bounds
*
* @param graphics a Graphics2D instance or RenderingScene instance
* @param clipSize the clip (rectangle) size
* @param interline the padding for rows
* @param leftAndRightInsets the padding for left and right sides
* @return the average resolution for multi-character output in the
* specified Graphics clip
*/
public static Dimension _getCharsResolution(Object graphics, Dimension clipSize, int rowPadding, int leftAndRightInsets) {
if (graphics instanceof Graphics2D) {
Graphics2D off = (Graphics2D) graphics;
return new Dimension(
RenderingScene._toMaxCharsCOLS((int) clipSize.getWidth(), leftAndRightInsets, off),
(int) Math.floor(((float) (clipSize.getHeight() - 2 * rowPadding)) / (float) (RenderingScene._toGraphicalMetrics(off).height + rowPadding)));
} else {
return new Dimension(
RenderingSceneGL._GLtoMaxCharsCOLS((int) clipSize.getWidth(), leftAndRightInsets, (RenderingSceneGL) graphics),
(int) Math.floor(((float) (clipSize.getHeight() - 2 * rowPadding)) / (float) (RenderingSceneGL._GLtoGraphicalMetrics((RenderingSceneGL) graphics).height + rowPadding)));
}
}
@Override
public Object loadResource() {
return hud.loadResource();
}
/**
* frees up the resources associated to this instance, like the console
* printstreams. The instance may be reuseable after a call to
* {@link #loadResource()}.
*/
@Override
public Object clearResource() {
hud.clearResource();
console.clearResource();
if (printStream != null) {
printStream.close();
}
printStream = null;
return null;
}
@Override
public boolean isResourceLoaded() {
return hud.isResourceLoaded();
}
/**
* will force redraw on next rendering frame
*
* @param resetPbo resets PBO (vram buffer) so that it needs to recreate
* itself
*/
public void setDirty(boolean resetPbo) {
if (resetPbo) {
hud.clearResource();
} else {
hud.resetContentsToDirty();
}
}
}