package uk.org.floop.epq3d; import uk.ac.manchester.tornado.api.annotations.Parallel; import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.awt.image.BufferedImage; import java.util.ArrayList; public class Screen extends JPanel implements ActionListener, KeyListener, MouseListener, MouseMotionListener { // __working variables__ public boolean initialised; public long lastTime; // mouse private boolean captured = false; private final Point2D mouseRel = new Point2D(0,0); private final Cursor invisibleCursor; // uber class for storing all draw data which needs to be passed to functions public final drawData drawData; // mainCollection stores all the background information in the scene public ObjectCollection mainCollection; // stores the skybox // I should probably make this work at some point public Object3d skyBox; // suppress serialization warning (future me says ??) private static final long serialVersionUID = 490905409104883233L; // keep a reference to the frameTimer object that triggers actionPerformed() in // case we need access to it in another method private final Timer frameTimer; private final Player player; public Screen(ObjectCollection _mainCollection) { mainCollection = _mainCollection; // initialise drawData drawData = new drawData("config.json"); // set the game board size setPreferredSize(new Dimension(drawData.scrX, drawData.scrY)); // set the game board background color setBackground(new Color(232, 232, 232)); // hide the mouse cursor (https://stackoverflow.com/questions/191592/how-do-i-get-rid-of-the-mouse-cursor-in-full-screen-exclusive-mode) Toolkit toolkit = Toolkit.getDefaultToolkit(); Point hotSpot = new Point(0,0); BufferedImage cursorImage = new BufferedImage(1, 1, BufferedImage.TRANSLUCENT); invisibleCursor = toolkit.createCustomCursor(cursorImage, hotSpot, "InvisibleCursor"); // initialize the game state player = new Player(drawData); lastTime = System.nanoTime(); // this frameTimer will call the actionPerformed() method every DELAY ms frameTimer = new Timer(drawData.delay, this); frameTimer.start(); initialised = true; } @Override public void actionPerformed(ActionEvent e) { // get mouse rel drawData.mouseRel = get_mouse_rel(); // run the tick of the player before the board is redrawn player.tick(drawData); // draw screen repaint(); } @Override public void paintComponent(Graphics g) { super.paintComponent(g); // draw graphics. drawScreen(g); // player.draw(g, this); Toolkit.getDefaultToolkit().sync(); } private void drawScreen(Graphics g) { drawData.lastFrameTime = (System.nanoTime()- lastTime)/1000000d; lastTime = System.nanoTime(); mainCollection.invalidate(true); ArrayList<Integer> FrustumInfo = new ArrayList<>(); for(int i = 0; i<6; i += 1){FrustumInfo.add(i);} mainCollection.draw(drawData, FrustumInfo); // DEBUG DRAWING { //debugImg.getGraphics().drawString(Math.round(1000 / (float) (System.currentTimeMillis() - lastTime)) + " fps", 10, 10); drawData.debugImg.getGraphics().drawString("FrameTime: " + (drawData.lastFrameTime) + " millis", 10, 10); if(drawData.debugHud) { drawData.debugImg.getGraphics().drawString("fpPos: " + String.format("%.2f", player.FPWorldPos.x) + " " + String.format("%.2f", player.FPWorldPos.y) + " " + String.format("%.2f", player.FPWorldPos.z) + " ", 100, 30); g.drawImage(drawData.debugImg, 0, 0, this); drawData.debugImg.getGraphics().drawString("playerPos: " + String.format("%.2f", player.getPos().x) + " " + String.format("%.2f", player.getPos().y) + " " + String.format("%.2f", player.getPos().z) + " ", 100, 50); drawData.debugImg.getGraphics().drawString("rotation: " + Math.round(Math.toDegrees(player.getRot().x)) + " " + Math.round(Math.toDegrees(player.getRot().y)) + " " + Math.round(Math.toDegrees(player.getRot().z)) + " ", 300, 50); drawData.debugImg.getGraphics().drawString("viewVec: " + String.format("%.2f", player.viewVector.x) + " " + String.format("%.2f", player.viewVector.y) + " " + String.format("%.2f", player.viewVector.z) + " ", 100, 70); for (int i = 0; i < 4; i += 1) { drawData.debugImg.getGraphics().drawString("camPoint " + i + ": " + String.format("%.2f", player.ScreenCornerPosS[i].getRotatedPoint().x) + " " + String.format("%.2f", player.ScreenCornerPosS[i].getRotatedPoint().y) + " " + String.format("%.2f", player.ScreenCornerPosS[i].getRotatedPoint().z), 10, 90 + 20 * i); } for (int i = 0; i < 6; i += 1) { drawData.debugImg.getGraphics().drawString("plane " + i + ": " + String.format("%.2f", drawData.frustumPlanes[i].mainPoint.x) + " " + String.format("%.2f", drawData.frustumPlanes[i].mainPoint.y) + " " + String.format("%.2f", drawData.frustumPlanes[i].mainPoint.z) + ", normal: " + String.format("%.2f", drawData.frustumPlanes[i].normalVector.x) + " " + String.format("%.2f", drawData.frustumPlanes[i].normalVector.y) + " " + String.format("%.2f", drawData.frustumPlanes[i].normalVector.z), 10, 170 + 20 * i); } } long drawTime = System.nanoTime(); //DataBuffer db = drawData.bufImg.getRaster().getDataBuffer(); for(@Parallel int x = 0; x < drawData.scrX; x +=1){ //drawData.bufImg.setRGB(x, 0, 1, drawData.scrY, drawData.drawImg[x], 0, 1); for(@Parallel int y = 0; y < drawData.scrY; y += 1){ //db.setElem(y* drawData.scrX + x, drawData.drawImg[x][y]); //drawData.bufImg.setRGB(x, y, drawData.drawImg[x][y]); //drawData.drawImg[x][y] = 0; drawData.zBuf[x][y] = 0; } } g.drawImage(drawData.bufImg, 0, 0, this); drawData.bufImg.getGraphics().fillRect(0,0,drawData.scrX, drawData.scrY); drawTime = System.nanoTime() - drawTime; long current = System.nanoTime(); System.out.println("Frame: " + "total: " + (current - lastTime)/1000000d + " drawing: " + (drawTime)/1000000d + " chopping: " + drawData.timeSpentChoppingFaces + " tris : " + drawData.timeSpentDrawingNormalFaces + " pixels : " + drawData.timeSpentGettingPixels/1000000d ); System.out.print("TriBreakdown: "); for (int x = 0; x<10; x+=1) { System.out.print(drawData.trisTimeList[x]/1000000d + ", "); drawData.trisTimeList[x] = 0; } System.out.println(); } drawData.timeSpentChoppingFaces = 0; drawData.timeSpentDrawingNormalFaces = 0; drawData.timeSpentDrawingTris = 0; drawData.timeSpentGettingPixels = 0; } @Override public void keyTyped(KeyEvent e) {} @Override public void keyPressed(KeyEvent e) { int key = e.getKeyCode(); if (key == KeyEvent.VK_ESCAPE){ captured = false; setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); } // pass key-press to the player, so they can handle it as well player.keyPressed(key, drawData); } @Override public void keyReleased(KeyEvent e) { int key = e.getKeyCode(); // pass key-release to the player, so they can handle it as well player.keyReleased(key); } // gets the relative position of the mouse since the last time this function was called public Point2D get_mouse_rel(){ Point2D rel; // this doesn't work if the mouse isn't captured. If I need it to, I can // probably make it, but I don't know what the functionality looks like. if (captured) { rel = new Point2D(MouseInfo.getPointerInfo().getLocation().x - getLocationOnScreen().x - getSize().width / 2 + mouseRel.x, MouseInfo.getPointerInfo().getLocation().y - getLocationOnScreen().y - getSize().height / 2 + mouseRel.y); mouseRel.set(0, 0); // set the position of the mouse back to (0,0) try { Robot robot = new Robot(); robot.mouseMove(getLocationOnScreen().x + getSize().width / 2, getLocationOnScreen().y + getSize().height / 2); } catch (AWTException ex) { ex.printStackTrace(); } } else{ rel = new Point2D(0,0); } return rel; } @Override public void mouseClicked(MouseEvent mouseEvent) { if (mouseEvent.getButton() == MouseEvent.BUTTON1){ captured = true; get_mouse_rel(); setCursor(invisibleCursor); } } @Override public void mousePressed(MouseEvent mouseEvent) {} @Override public void mouseReleased(MouseEvent mouseEvent) {} @Override public void mouseEntered(MouseEvent mouseEvent) {} @Override public void mouseExited(MouseEvent mouseEvent) { if (captured) { // add current mouse relative location to mouseRel so mouse movements are not lost mouseRel.x += mouseEvent.getX() - getSize().width / 2d; mouseRel.y += mouseEvent.getY() - getSize().height / 2d; // System.out.println(mouseEvent.getX() + " " + mouseEvent.getY()); // set the position of the mouse back to (0,0) try { Robot robot = new Robot(); robot.mouseMove(getLocationOnScreen().x + getSize().width / 2, getLocationOnScreen().y + getSize().height / 2); } catch (AWTException ex) { ex.printStackTrace(); } } } @Override public void mouseDragged(MouseEvent mouseEvent) {} @Override public void mouseMoved(MouseEvent mouseEvent) { } }