package life.v41d; /************************************************************** LifeGUI.java (c) 1996-2001 by Alan Hensel. All Rights Reserved. **************************************************************/ import java.awt.*; class LifeGUI extends Panel { private int fieldWidth, fieldHeight; private int fieldSizeX, fieldSizeY; private int cellMagnitude, pixelsPerCell, ppc, ppc2; private boolean specialCase; // for awful bug, Netscape 4.05 and lower private Color fgColor = new Color(0, 0, 160); private Color bgColor = Color.lightGray; private Color gridColor = Color.gray; private boolean grids; private int toolbarHeight; public int oX=1, oY=1; // applet coordinates at upper left of the viewing window public int xOrig, yOrig; // universe location at the upper left of the viewing window private Graphics g; private boolean viewChanged=true; private int[] xTranslate, yTranslate; private boolean boundsCheck=true; // ----------------------------------------------------------------------- // All the stuff between these lines used to belong to the class StateTable, // but it was inlined for performance reasons. (8%) private boolean[][] field; private boolean[] column; public boolean getState(int x, int y) { if (x>=0 && y>=0 && x=0 && y>=0 && x=0 && y>=0 && x 1 && grids)? 1:0); if (!LifeButton.clearRectBroken) { ppc2 = ppc; // normal specialCase=false; } else { ppc2 = ppc-1; // for Netscapes 4.05 and below if (ppc2==0) specialCase=true; else specialCase=false; } createTranslationTables(); } private void createTranslationTables() { xTranslate=new int[fieldSizeX]; for (int i=0; i>cellMagnitude; } public int convertAppletToFieldY(int y) { return (y-oY-toolbarHeight)>>cellMagnitude; } public int convertFieldToUniverseX(int x) { return x + xOrig; } public int convertFieldToUniverseY(int y) { return y + yOrig; } public void setGraphicsContext(Graphics gr) { g=gr; g.setColor(fgColor); g.setXORMode(bgColor); } public void drawCell(int x, int y) { drawCell(x,y, getState(x,y)); } public void drawCell(int x, int y, boolean state) { /* This is the less efficient solution, which is not broken in Netscape 3.0. if (state) g.setColor(fgColor); else g.setColor(bgColor); g.fillRect(xTranslate[x], yTranslate[y], ppc, ppc); */ // This is the more efficient solution, which is unfortunately // broken in Netscape 3.0. if (state) g.fillRect(xTranslate[x], yTranslate[y], ppc, ppc); else { if (specialCase) { g.setColor(bgColor); g.fillRect(xTranslate[x], yTranslate[y], 1, 1); g.setColor(fgColor); } else { g.clearRect(xTranslate[x], yTranslate[y], ppc2, ppc2); } } } public void drawGrid() { int origX = oX-1, origY = oY-1; // no xor mode for the grid g.setPaintMode(); /* This is the less efficient solution, which is not broken in Netscape 3.0. g.setColor(bgColor); g.fillRect(oX, oY, fieldWidth+oX, fieldHeight+oY); */ // This is the solution which is guaranteed to agree with // the more efficient solution in drawCell(). g.clearRect(oX, oY, fieldWidth+oX, fieldHeight+oY); g.setColor(gridColor); if (cellMagnitude>1 && grids) { for (int i=0; i<=fieldSizeY; i++) { g.drawLine(origX, i*pixelsPerCell+origY, fieldWidth+origX, i*pixelsPerCell+origY); } for (int i=0; i<=fieldSizeX; i++) { g.drawLine(i*pixelsPerCell+origX, origY, i*pixelsPerCell+origX, fieldHeight+origY); } } else // cells are too small for a full grid: { int rightX = fieldWidth+oX; int bottomY = fieldHeight+oY; g.drawLine(origX, origY, rightX, origY); g.drawLine(origX, bottomY, rightX, bottomY); g.drawLine(origX, origY, origX, bottomY); g.drawLine(rightX, origY, rightX, bottomY); } g.setColor(fgColor); g.setXORMode(bgColor); } public boolean cellState(int x, int y) { return getState(x,y); } public void changeCell(int x, int y) { toggleState(x,y); } public void changeCell(int x, int y, boolean state) { setState(x,y,state); } public void clear() { field = new boolean[fieldSizeX][fieldSizeY]; createTranslationTables(); } private void updateCell(int x, int y, boolean state) { if (boundsCheck) { if (x<0 || x>=fieldSizeX) return; column = field[x]; if (y<0 || y>=fieldSizeY) return; } else { column = field[x]; } if (column[y]!=state) { column[y]=state; g.fillRect(xTranslate[x], yTranslate[y], ppc, ppc); } } private void updateCel(int x, int y, boolean state) { if (boundsCheck) { if (x<0 || x>=fieldSizeX || y<0 || y>=fieldSizeY) return; } if (column[y]!=state) { column[y]=state; g.fillRect(xTranslate[x], yTranslate[y], ppc, ppc); } } private boolean display_p(LifeGen u) { // check only those with "display" bit set; skip the rest. // display only those quadrants with hibernation and morgue // bits = 0. // traverse both the living & hibernating lists. // return false if couldn't complete the generation. short c,d,e,f; LifeCell nextc; int i; int j0,j1,j2,j3,j4,j5,j6,j7,j8,j9,j10,j11,j12,j13,j14,j15; for (LifeCell cell=u.display; cell != null; cell=nextc) { nextc=cell.DisplayNext; if ((cell.flags & 0x02)!=0) { u.removeFromDisplay(cell); } i = cell.x*16 - xOrig; j0 = cell.y*16 - yOrig; if (i +16 < 0 || i +1 > fieldSizeX || j0+16 < 0 || j0+1 > fieldSizeY) { u.removeFromDisplay(cell); } else { j1=j0+1; j2=j1+1; j3=j2+1; j4=j3+1; j5=j4+1; j6=j5+1; j7=j6+1; j8=j7+1; j9=j8+1; j10=j9+1; j11=j10+1; j12=j11+1; j13=j12+1; j14=j13+1; j15=j14+1; if (i >=0 && i+15=0 && j15 fieldSizeX || j0+15 < 0 || j0 > fieldSizeY) { u.removeFromDisplay(cell); } else { j1=j0+1; j2=j1+1; j3=j2+1; j4=j3+1; j5=j4+1; j6=j5+1; j7=j6+1; j8=j7+1; j9=j8+1; j10=j9+1; j11=j10+1; j12=j11+1; j13=j12+1; j14=j13+1; j15=j14+1; if (i >=0 && i+15=0 && j15