package sig.engine; import java.awt.Graphics; import java.awt.Image; import java.awt.Toolkit; import java.awt.image.ColorModel; import java.awt.image.MemoryImageSource; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionListener; import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; import java.awt.GraphicsEnvironment; import java.awt.GraphicsConfiguration; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.event.MouseInputListener; import java.awt.event.KeyListener; import java.awt.Graphics2D; import java.awt.RenderingHints; import sig.JavaProjectTemplate; public class Panel extends JPanel implements Runnable,KeyListener { JFrame window; static JavaProjectTemplate gameInstance; public int pixel[]; final int CIRCLE_PRECISION=32; final int OUTLINE_COL=Color.BRIGHT_WHITE.getColor(); private Thread thread; private Image imageBuffer; private MemoryImageSource mImageProducer; private ColorModel cm; int scanLine=0; int nextScanLine=0; double x_offset=0; double y_offset=0; int frameCount=0; long lastSecond=0; boolean resizing=false; long lastUpdate=System.nanoTime(); final long TARGET_FRAMETIME = 8333333l; public double nanaX = 0; public double nanaY = 0; public int button = 0; public HashMap MOUSE = new HashMap<>(); private Point mousePosition = new Point(0,0); private MouseScrollValue scrollWheel=null; public static final int UPDATE_LOOP_FRAMERATE = 244; public static final long UPDATE_LOOP_NANOTIME = (long)((1d/UPDATE_LOOP_FRAMERATE)*1000000000l); public static final double UPDATE_MULT = 1d / UPDATE_LOOP_FRAMERATE; public static RenderingHints RENDERHINTS = new RenderingHints(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF); static long lastReportedTime = System.currentTimeMillis(); public static long TIME = 0; public static long scaleTime; public static Panel p; public static JFrame f; public static void InitializeEngine(JavaProjectTemplate instance){ System.setProperty("sun.java2d.transaccel", "True"); System.setProperty("sun.java2d.d3d", "True"); System.setProperty("sun.java2d.ddforcevram", "True"); System.setProperty("sun.java2d.xrender", "True"); gameInstance=instance; RENDERHINTS.put(RenderingHints.KEY_COLOR_RENDERING,RenderingHints.VALUE_COLOR_RENDER_SPEED); RENDERHINTS.put(RenderingHints.KEY_DITHERING,RenderingHints.VALUE_DITHER_DISABLE); RENDERHINTS.put(RenderingHints.KEY_FRACTIONALMETRICS,RenderingHints.VALUE_FRACTIONALMETRICS_OFF); RENDERHINTS.put(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_SPEED); f = new JFrame(JavaProjectTemplate.PROGRAM_NAME); f.setResizable(false); f.setSize(JavaProjectTemplate.WINDOW_WIDTH,JavaProjectTemplate.WINDOW_HEIGHT); p = new Panel(f); JavaProjectTemplate.game=p; p.init(); f.add(p); f.addKeyListener(p); f.setLocation((int) ((Toolkit.getDefaultToolkit().getScreenSize().getWidth() - f.getWidth()) / 2), (int) ((Toolkit.getDefaultToolkit().getScreenSize().getHeight() - f.getHeight()) / 2)); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setVisible(true); p.render(); long lastGameTime = System.nanoTime(); long dt = 0; while (true) { dt += System.nanoTime() - lastGameTime; lastGameTime = System.nanoTime(); while (dt >= UPDATE_LOOP_NANOTIME) { gameInstance.updateGame(UPDATE_LOOP_NANOTIME/1000000000d); dt -= UPDATE_LOOP_NANOTIME; TIME += UPDATE_LOOP_NANOTIME; } gameUpdateLoopStabilizer(dt); //This is hackish. Removing this slows down the game by about 30%. The timer runs slower. ??? } } private static void gameUpdateLoopStabilizer(long dt) { if (dt < UPDATE_LOOP_NANOTIME) { lastReportedTime = System.currentTimeMillis(); } else { if (System.currentTimeMillis() - lastReportedTime > 5000) { System.out.println("WARNING! Game is lagging behind! Frames Behind: " + (dt / UPDATE_LOOP_NANOTIME)); lastReportedTime = System.currentTimeMillis(); } } try { Thread.sleep(4); } catch (InterruptedException e) { e.printStackTrace(); } } public Panel(JFrame f) { super(true); this.window=f; thread = new Thread(this, "MyPanel Thread"); this.addMouseListener(new MouseInputListener(){ @Override public void mouseClicked(MouseEvent e) { } @Override public void mousePressed(MouseEvent e) { MOUSE.put(e.getButton(),true); } @Override public void mouseReleased(MouseEvent e) { MOUSE.put(e.getButton(),false); } @Override public void mouseEntered(MouseEvent e) { } @Override public void mouseExited(MouseEvent e) { } @Override public void mouseDragged(MouseEvent e) { } @Override public void mouseMoved(MouseEvent e) { } }); this.addMouseMotionListener(new MouseMotionListener(){ @Override public void mouseDragged(MouseEvent e) { mousePosition.set(e.getX(),e.getY()); } @Override public void mouseMoved(MouseEvent e) { mousePosition.set(e.getX(),e.getY()); } }); this.addMouseWheelListener(new MouseWheelListener(){ //-1 is UP, 1 is DOWN @Override public void mouseWheelMoved(MouseWheelEvent e) { scrollWheel=MouseScrollValue.getValue(e.getWheelRotation()); } }); } /** * Get Best Color model available for current screen. * @return color model */ protected static ColorModel getCompatibleColorModel(){ GraphicsConfiguration gfx_config = GraphicsEnvironment. getLocalGraphicsEnvironment().getDefaultScreenDevice(). getDefaultConfiguration(); return gfx_config.getColorModel(); } /** * Call it after been visible and after resizes. */ public void init(){ cm = getCompatibleColorModel(); int screenSize = JavaProjectTemplate.WINDOW_WIDTH * JavaProjectTemplate.WINDOW_HEIGHT; if(pixel == null || pixel.length < screenSize){ pixel = new int[screenSize]; } mImageProducer = new MemoryImageSource(JavaProjectTemplate.WINDOW_WIDTH, JavaProjectTemplate.WINDOW_HEIGHT, cm, pixel,0, JavaProjectTemplate.WINDOW_WIDTH); mImageProducer.setAnimated(true); mImageProducer.setFullBufferUpdates(true); imageBuffer = Toolkit.getDefaultToolkit().createImage(mImageProducer); if(thread.isInterrupted() || !thread.isAlive()){ thread.start(); } } @Override public void paintComponent(Graphics g) { //super.paintComponent(g); // perform draws on pixels long startTime = System.currentTimeMillis(); g.drawImage(this.imageBuffer,0,0,JavaProjectTemplate.WINDOW_WIDTH,JavaProjectTemplate.WINDOW_HEIGHT,0,0,JavaProjectTemplate.WINDOW_WIDTH,JavaProjectTemplate.WINDOW_HEIGHT,this); scaleTime=System.currentTimeMillis()-startTime; } /** * Overrides ImageObserver.imageUpdate. * Always return true, assuming that imageBuffer is ready to go when called */ @Override public boolean imageUpdate(Image image, int a, int b, int c, int d, int e) { return true; } /** * Do your draws in here !! * pixel is your canvas! */ public /* abstract */ void render(){ gameInstance.drawGame(); } public void FillCircle(double center_x,double center_y,double r,Color col) { int counter=0; Point[] points = new Point[CIRCLE_PRECISION]; for (double theta=0;theta edges_sorted = new ArrayList(); for (int i=0;i=edges[i].min_y) { edges_sorted.add(j,edges[i]); inserted=true; break; } } if (!inserted) { edges_sorted.add(edges[i]); } } } } //System.out.println(edges_sorted); List active_edges = new ArrayList(); scanLine = edges_sorted.get(0).min_y-1; nextScanLine = scanLine+1; do { for (int i=0;i=active_edges.size()-1) break; Edge e1 = active_edges.get(i); Edge e2 = active_edges.get(i+1); //System.out.println("Drawing from "+((int)Math.round(e1.x_of_min_y))+" to "+e2.x_of_min_y+" on line "+scanLine); for (int x=(int)Math.round(e1.x_of_min_y);x<=e2.x_of_min_y;x++) { if (x<0||x>JavaProjectTemplate.WINDOW_WIDTH) continue; int index = (scanLine+(int)y_offset)*getWidth()+x+(int)x_offset; if (index=0) { Draw(index,col.getColor()); } } } List new_active_edges = new ArrayList(); for (int i=0;ie.x_of_min_y) { new_active_edges.add(j,e); inserted=true; break; } } if (!inserted) { new_active_edges.add(e); } } active_edges=new_active_edges; GetNextScanLineEdges(edges_sorted, active_edges); } while (active_edges.size()>0); } private void GetNextScanLineEdges(List edges_sorted, List active_edges) { if (scanLine==nextScanLine) { for (int i=0;iscanLine) { nextScanLine=e.min_y; break; } } } } public void Draw(int x, int y, Color col) { Draw(y*JavaProjectTemplate.WINDOW_WIDTH+x,col.getColor()); } void Draw(int index, int col) { pixel[index]=col; } @Override public void run() { while (true) { // request a JPanel re-drawing render(); mImageProducer.newPixels(); if (f!=null) { Graphics2D g2 = (Graphics2D)f.getGraphics(); if (g2!=null) { g2.setRenderingHints(RENDERHINTS); try { repaint(); } finally { g2.dispose(); } } } updateFPSCounter(); //System.out.println("Repaint "+frameCount++); waitForNextFrame(); } } private void waitForNextFrame() { long newTime = System.nanoTime(); if (newTime-lastUpdate=1000) { window.setTitle(JavaProjectTemplate.PROGRAM_NAME+" - FPS: "+(frameCount)); frameCount=0; lastSecond=System.currentTimeMillis(); } frameCount++; } @Override public void keyTyped(KeyEvent e) { } @Override public void keyPressed(KeyEvent e) { if (!Key.isKeyHeld(e.getKeyCode())) { Key.setKeyHeld(e.getKeyCode(), true); } //System.out.println("Key List: "+KEYS); } @Override public void keyReleased(KeyEvent e) { Key.setKeyHeld(e.getKeyCode(), false); //System.out.println("Key List: "+KEYS); } public void Draw_Text(double x, double y, String s, Font f) { Draw_Text_Ext(x,y,s,f,Color.BLACK); } public void Draw_Text_Ext(double x, double y, String s, Font f, Color col) { java.lang.String finalS = s.toString(); int charCount=0; int yOffset=0; int xOffset=0; Color currentCol = col; for (int i=0;i=0) { x=x1;y=y1;xe=x2-1; } else { x=x2-1;y=y2-1;xe=x1; } while (x0&&dy>0)) { y=y+1; } else { y=y-1; } px=px+2*(dy1-dx1); } Draw(y*JavaProjectTemplate.WINDOW_WIDTH+x,col.getColor()); } } else { if (dy>=0) { x=x1;y=y1;ye=y2-1; } else { x=x2-1;y=y2-1;ye=y1; } Draw(y*JavaProjectTemplate.WINDOW_WIDTH+x,col.getColor()); while (y0&&dy>0)) { x=x+1; } else { x=x-1; } py=py+2*(dx1-dy1); } Draw(y*JavaProjectTemplate.WINDOW_WIDTH+x,col.getColor()); } } } public void Fill_Rect(double x,double y,double w,double h,Color col) { for (int xx=0;xx=0&&y+yy>=0&&x+xx=JavaProjectTemplate.WINDOW_WIDTH||Y-yOffset+y>=JavaProjectTemplate.WINDOW_HEIGHT) { continue; } else { int index = ((vertical? sprite.getHeight()-(Y-(int)yOffset): (Y-(int)yOffset)) +(int)y)*JavaProjectTemplate.WINDOW_WIDTH+ (horizontal? sprite.getWidth()-(X-(int)xOffset): (X-(int)xOffset)) +(int)x; if (((sprite.getImg().getRGB(X,Y)>>>24)&0xFF)==0||index<0||index>=pixel.length) { continue; } else { Draw(index,(col==Color.WHITE)?sprite.getImg().getRGB(X,Y):col.getColor()); } } } } } public void Draw_Rect(double x,double y, double w, double h, Color col) { Draw_Line((int)x, (int)y, (int)x+(int)w, (int)y, col); Draw_Line((int)x+(int)w, (int)y, (int)x+(int)w, (int)y+(int)h, col); Draw_Line((int)x+(int)w, (int)y+(int)h, (int)x, (int)y+(int)h, col); Draw_Line((int)x, (int)y+(int)h, (int)x, (int)y, col); } public void Draw_Triangle(double x1, double y1, double x2, double y2, double x3, double y3, Color col) { Draw_Line((int)x1, (int)y1, (int)x2, (int)y2, col); Draw_Line((int)x2, (int)y2, (int)x3, (int)y3, col); Draw_Line((int)x3, (int)y3, (int)x1, (int)y1, col); } private void drawline(int sx,int ex,int ny,Color col){ for (int i = sx; i <= ex; i++) Draw(i, ny, col); } public void Fill_Triangle(double x1, double y1, double x2, double y2, double x3, double y3, Color col){ int t1x, t2x, y, minx, maxx, t1xp, t2xp; boolean changed1 = false; boolean changed2 = false; int signx1, signx2, dx1, dy1, dx2, dy2; int e1, e2; // Sort vertices int temp; if (y1 > y2) {temp=(int)y1;y1=y2;y2=temp;temp=(int)x1;x1=x2;x2=temp;} if (y1 > y3) {temp=(int)y1;y1=y3;y3=temp;temp=(int)x1;x1=x3;x3=temp;} if (y2 > y3) {temp=(int)y2;y2=y3;y3=temp;temp=(int)x2;x2=x3;x3=temp;} t1x = t2x = (int)x1; y = (int)y1; // Starting points dx1 = (int)(x2 - x1); if (dx1 < 0) { dx1 = -dx1; signx1 = -1; } else signx1 = 1; dy1 = (int)(y2 - y1); dx2 = (int)(x3 - x1); if (dx2 < 0) { dx2 = -dx2; signx2 = -1; } else signx2 = 1; dy2 = (int)(y3 - y1); if (dy1 > dx1) {temp=dx1;dx1=dy1;dy1=temp;changed1 = true; } if (dy2 > dx2) {temp=dx2;dx2=dy2;dy2=temp;changed2 = true; } e2 = (int)(dx2 >> 1); // Flat top, just process the second half boolean firstHalfDone=false; if (y1 == y2) firstHalfDone=true; if (!firstHalfDone) { e1 = (int)(dx1 >> 1); for (int i = 0; i < dx1;) { t1xp = 0; t2xp = 0; if (t1x < t2x) { minx = t1x; maxx = t2x; } else { minx = t2x; maxx = t1x; } // process first line until y value is about to change next0: while (i < dx1) { i++; e1 += dy1; while (e1 >= dx1) { e1 -= dx1; if (changed1) t1xp = signx1;//t1x += signx1; else { break next0; } } if (changed1) break; else t1x += signx1; } // Move line next1: // process second line until y value is about to change while (true) { e2 += dy2; while (e2 >= dx2) { e2 -= dx2; if (changed2) t2xp = signx2;//t2x += signx2; else { break next1; } } if (changed2) break; else t2x += signx2; } if (minx > t1x) minx = t1x; if (minx > t2x) minx = t2x; if (maxx < t1x) maxx = t1x; if (maxx < t2x) maxx = t2x; drawline(minx, maxx, y, col); // Draw line from min to max points found on the y // Now increase y if (!changed1) t1x += signx1; t1x += t1xp; if (!changed2) t2x += signx2; t2x += t2xp; y += 1; if (y == y2) break; } } // Second half dx1 = (int)(x3 - x2); if (dx1 < 0) { dx1 = -dx1; signx1 = -1; } else signx1 = 1; dy1 = (int)(y3 - y2); t1x = (int)x2; if (dy1 > dx1) { // swap values temp=dy1;dx1=dy1;dy1=temp; changed1 = true; } else changed1 = false; e1 = (int)(dx1 >> 1); for (int i = 0; i <= dx1; i++) { t1xp = 0; t2xp = 0; if (t1x < t2x) { minx = t1x; maxx = t2x; } else { minx = t2x; maxx = t1x; } // process first line until y value is about to change next3: while (i < dx1) { e1 += dy1; while (e1 >= dx1) { e1 -= dx1; if (changed1) { t1xp = signx1; break; }//t1x += signx1; else break next3; } if (changed1) break; else t1x += signx1; if (i < dx1) i++; } next4: // process second line until y value is about to change while (t2x != x3) { e2 += dy2; while (e2 >= dx2) { e2 -= dx2; if (changed2) t2xp = signx2; else break next4; } if (changed2) break; else t2x += signx2; } if (minx > t1x) minx = t1x; if (minx > t2x) minx = t2x; if (maxx < t1x) maxx = t1x; if (maxx < t2x) maxx = t2x; drawline(minx, maxx, y,col); if (!changed1) t1x += signx1; t1x += t1xp; if (!changed2) t2x += signx2; t2x += t2xp; y += 1; if (y > y3) return; } } public void Clear(Color col){ for (int y=0;y