Package net.sf.jiga.xtended.impl

Source Code of net.sf.jiga.xtended.impl.GUIConsoleOutput$LineBuffer

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();
        }
    }
}
TOP

Related Classes of net.sf.jiga.xtended.impl.GUIConsoleOutput$LineBuffer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.