package TaiGameCore; import static java.awt.event.KeyEvent.KEY_TYPED; import static java.awt.event.KeyEvent.VK_BACK_SPACE; import static java.awt.event.KeyEvent.VK_DELETE; import static java.awt.event.KeyEvent.VK_ENTER; import static java.awt.event.KeyEvent.VK_ESCAPE; import static java.awt.event.KeyEvent.VK_TAB; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.geom.Rectangle2D; import java.util.ArrayList; import java.util.ConcurrentModificationException; import java.util.TreeMap; import javax.media.opengl.GL; import javax.media.opengl.GL2; import javax.media.opengl.glu.GLU; import processing.core.PApplet; import processing.core.PMatrix3D; import processing.opengl.PGraphicsOpenGL; import BulletGame$1.BulletGame$1Engine$ABasicEngine.ModalDialog; public class P5GLExtend extends KeyAdapter { public PApplet g; public int currentViewPortWidth; public int currentViewPortHeight; public int currentViewPortX; public int currentViewPortY; public P5GLExtend(PApplet hold) { g = hold; if (g != null) { g.registerDispose(this); } } /* public ProceGLHybrid(ProceGLHybrid hold){ g = hold.g; } */ /** * Non-square pixel correction factor due to 0.0.1.1 pix mapping not matching game ar (640x480) */ public float NSPH = 640f / 480; /** * NOTE: in RATIOS of total width/ height. */ private double[] viewportStack = new double[] { 0.0, 0.0, 1.0, 1.0 }; public void viewport(double xp, double yp, double wp, double hp) { viewportStack[0] = xp; viewportStack[1] = yp; viewportStack[2] = wp; viewportStack[3] = hp; PGraphicsOpenGL gog = (PGraphicsOpenGL) (g.g); GL gl = gog.gl; //Don't try this at home! gl.glViewport(currentViewPortX = (int) (xp * g.width), currentViewPortY = (int) ((1 - yp - hp) * g.height), currentViewPortWidth = (int) (wp * g.width), currentViewPortHeight = (int) (hp * g.height)); //NSPH = currentViewPortWidth/(float)currentViewPortHeight; WRONG } /** For convenience, use a rectangle works as well **/ public void viewport(Rectangle2D area) { viewport(area.getMinX(), area.getMinY(), area.getWidth(), area .getHeight()); } /** * If the viewport doesn't hvae ar= wantedWidth/wantedHeight, you get squishing: That's desired behavior. * * NOTE: this metohd causes the p5 matrixes and opengl's to be NONSYNCED> to return to normalcy, return to * the screen2D. */ public void view3D(float wantedWidth, float wantedHeight) { GLU glu = ((PGraphicsOpenGL) g.g).glu; GL2 gl = ((PGraphicsOpenGL) g.g).gl; gl.glMatrixMode(gl.GL_PROJECTION); // Select The Projection Matrix gl.glLoadIdentity(); // Reset The Projection Matrix glu.gluPerspective(45.0f, wantedWidth / wantedHeight, .1f, 100.0f); // Reset The Current Modelview Matrix gl.glMatrixMode(gl.GL_MODELVIEW); gl.glLoadIdentity(); gl.glTranslatef(0.0f, 0.0f, -g.sqrt(2) - 1); // Center The Triangle } /** * If the viewport doesn't hvae ar= viewportWidth/viewPortHeight, you get squishing: That's desired behavior. * * NOTE: calling this method resets the modelviewmatrix. Also desired behavior. */ public void screen2D() { GL2 gl = ((PGraphicsOpenGL) g.g).gl; gl.glClear(GL.GL_DEPTH_BUFFER_BIT); //Copy the viewport: double[] oldViewport = new double[] { viewportStack[0], viewportStack[1], viewportStack[2], viewportStack[3] }; viewport(0, 0, 1, 1); //Taken from PApplet.beginDraw gl.glMatrixMode(GL2.GL_PROJECTION); PMatrix3D projection = ((PGraphicsOpenGL) g.g).projection; float[] projectionFloats = new float[] { projection.m00, projection.m10, projection.m20, projection.m30, projection.m01, projection.m11, projection.m21, projection.m31, projection.m02, projection.m12, projection.m22, projection.m32, projection.m03, projection.m13, projection.m23, projection.m33 }; gl.glLoadMatrixf(projectionFloats, 0); g.perspective(); g.camera(); gl.glMatrixMode(GL2.GL_MODELVIEW); // apply this modelview and get to work gl.glLoadIdentity(); gl.glScalef(1, -1, 1); float n = (currentViewPortWidth - .5f) / 2; float nY = (currentViewPortHeight - .5f) / 2; gl.glTranslatef(g.width * n, g.height * nY, 0); float mag = n + .5f; float mag2 = nY + .5f; float scX = 2f, scY = 2f; gl.glScalef(scX * mag, scY * mag2, 1); viewport(oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3]); } public void screen2D4GL(float wantedWidth, float wantedHeight) { GL2 gl = ((PGraphicsOpenGL) g.g).gl; /* screen2D(); */ float[] vals = g.getMatrix().get(null); //gl.glTranslatef(vals[3],vals[7],vals[11]); view3D(wantedWidth, wantedHeight); gl.glScalef(1 / (wantedHeight / wantedWidth), -1, 1); gl.glTranslatef(-1, -1, 0); gl.glScalef(2, 2, 1 / vals[11]); } /* public static abstract class TeGl extends TraceGL2{ public TeGl(GL2 gl, PrintStream arg1,ProceGLHybrid g) { super(gl, arg1); ProceGLthis = g; draw(gl); } public ProceGLHybrid ProceGLthis; private static final PrintStream crapStream = new PrintStream(new OutputStream(){ public void write(int b) throws IOException { } }); public TeGl(ProceGLHybrid gh){ this(((PGraphicsOpenGL)gh.g.g).gl,crapStream,gh); } public abstract void draw(GL2 gl); } */ /** * Has capability to consume a "hotkey" with returning false. */ public boolean keyEventSyncSuper() { return true; }; private ArrayList<KeyListener> klist = new ArrayList(); public TreeMap<Integer, Boolean> keyboard = new TreeMap(); /** * key handling is done only in draw loops. */ public void handleInputAtBeginningOfDraw() { try { if (g.keyEvent == null) { //keyEvent is used for querying things that SHOULD be passed with keyTyped. if (g.keyCode == 0) return; //No input this frame; g.keyEvent = new KeyEvent(g, KeyEvent.KEY_PRESSED, System .currentTimeMillis(), 0, g.keyCode, '?'); } else if (g.keyEvent.getID() == KEY_TYPED) { int[] remapping = new int[] { 10, VK_ENTER, 8, VK_BACK_SPACE, 27, VK_ESCAPE, 9, VK_TAB, 127, VK_DELETE, 'z', KeyEvent.VK_Z, 'Z', KeyEvent.VK_Z, 'x', KeyEvent.VK_X, 'X', KeyEvent.VK_X, }; for (int k = 0; k < remapping.length; k += 2) { if (g.keyEvent.getKeyChar() == remapping[k]) { g.keyCode = remapping[k + 1]; g.keyEvent.setKeyCode(remapping[k + 1]); } } } if (g.keyEvent.getID() == KeyEvent.KEY_RELEASED) { keyboard.put(g.keyEvent.getKeyCode(), false); g.keyCode = 0; //Make sure to pass it through, neutralized. It's like a "cleanser". g.keyEvent.setKeyCode(0); g.keyEvent.setKeyChar('?'); } if (g.keyEvent.isShiftDown()) { keyboard.put(KeyEvent.VK_SHIFT, true); } if (g.keyEvent.isControlDown()) { keyboard.put(KeyEvent.VK_CONTROL, true); } if (g.keyEvent.getID() == KeyEvent.KEY_PRESSED) { keyboard.put(g.keyEvent.getKeyCode(), true); } //.out.println(g.keyEvent.getKeyChar()+" "+g.keyEvent.getKeyCode()); if (keyEventSyncSuper()) { // System.out.println(g.keyEvent.getKeyCode()+" "+g.keyEvent.getKeyChar()+" "+g.keyEvent.getID()); for (int newFirst = klist.size() - 1; newFirst >= 0; newFirst--) { KeyListener kl = klist.get(newFirst); kl.keyPressed(g.keyEvent); //KEY_TYPED, OR KEY_PRESSED if (kl instanceof ModalDialog) { break; //Nothing under a modaldialog gets keypresses. } } } } catch (ConcurrentModificationException f) { //Nonfatal. } finally { g.keyEvent = null; //g.keyCode==0 } } //public boolean isShiftHeld, isCtrlHeld, isLeftHeld, isRightHeld, isUpHeld, isDownHeld; public void removeSubKeyListener(KeyListener kl) { klist.remove(kl); } public void addSubKeyListener(KeyListener kl) { klist.add(kl); } public void outlineViewport() { g.stroke(0); g.noFill(); g.rect(1f / currentViewPortWidth, 1f / currentViewPortHeight, 1 - 2f / currentViewPortWidth, 1 - 2f / currentViewPortHeight); } public void dispose() { } /** * Renders a rectangle, just outside the coordinates specified by r. */ public void rectB(Rectangle2D.Float r) { g.rect(((int)(r.x * currentViewPortWidth)) / (float)currentViewPortWidth, ((int)(r.y * currentViewPortHeight)) / (float)currentViewPortHeight, ((int)((r.x + r.width) * currentViewPortWidth)) / (float)currentViewPortWidth - r.x, ((int)((r.y + r.height) * currentViewPortHeight)) / (float)currentViewPortHeight - r.y); } /** * Not strictly inside, exactly on border is "in". */ public boolean isInRect(Rectangle2D.Float r, float x, float y) { boolean isInX = r.x <= x && r.x + r.width >= x; if (!isInX) return isInX; boolean isInY = r.y <= y && r.y + r.height >= y; return isInY; } /** * A modified str.split(), where if * str.substring(str.length()-endCaseW).matches(regex), then an * additional (empty) string is appended to the normal split result * * NEW: additionally, the split is limited to 1 match. */ public String[] modSplit(String str, String regex, int endCaseW) { boolean hasExtra = str.substring(str.length() - endCaseW) .matches(regex); String[] got = str.split(regex, 2); if (hasExtra) { String[] toRet = new String[got.length + 1]; for (int k = 0; k < got.length; k++) { toRet[k] = got[k]; } toRet[got.length] = ""; return toRet; } else { return got; } } public boolean truth(Boolean k) { return !(k == null) && (k == true); } public static class RArea extends Rectangle2D.Float { public RArea(double f, double g, double h, double i) { super((float)f,(float)g,(float)h,(float)i); } } }