/* Credits: Books: Herbert Shieldt. "The complete reference. Java 2." Fifth edition. Page 825. Kenneth Litwak "Pure Java 2" SAMS 2000 www.samspublishing.com */ import java.awt.*; import java.awt.image.PixelGrabber; import java.awt.image.MemoryImageSource; import java.applet.*; import Globals.*; import Approximations.*; /* TODO Questions marked as do1 and do2 Make GUI to enter parameters in one place */ public class Editor extends Applet implements Runnable{ //Control parameters: static final int TRANSPARENT_COLOR = 0; //"Yes" means ... dimensions of both images //are equal, and they are coisided: boolean spriteFitsBase; int animationFramesNumber; int rotationCenterOnBaseX; int rotationCenterOnBaseY; int leftTopOfSpriteOnBaseX; int leftTopOfSpriteOnBaseY; Image baseIm; Image spriteIm; Image topIm; //Auxiliary: MediaTracker mt; Graphics baseG; Graphics spriteG; PixelGrabber spritePG; PixelGrabber basePG; int[] spriteArr; int[] baseArr; int[] baseArrBuff; Image baseWithSprite; Image resultIm; Graphics resultG; int columnNumber; int rowNumber; int resultX; int resultY; int baseW; int baseH; int spriteW; int spriteH; //Auxiliary members: private static boolean imageIsReady; private static int frameNumber = 0; private static Thread calculateThread; private static final long frameDelay = 20; private static long timeToPrintNewFrame; private static long timeLeftAfterCalculations; Dimension scrDimension; public void init() { //Control parameters: spriteFitsBase = true; columnNumber = 4; rowNumber = 4; animationFramesNumber = columnNumber*rowNumber - 2; resultX = -1; //Flag. scrDimension = getSize(); imageIsReady = false; frameNumber = 0; //Principals: mt = new MediaTracker(this); baseIm = getImage( getCodeBase(), "Resources/base.gif" ); spriteIm = getImage( getCodeBase(), "Resources/sprite.gif" ); topIm = getImage( getCodeBase(), "Resources/top.gif" ); mt.addImage( baseIm, 0 ); mt.addImage( spriteIm, 1 ); mt.addImage( topIm, 2 ); //do2 Why mt does not load without these?: mt.statusID(0, true); mt.statusID(1, true); mt.statusID(2, true); //do1 infinite loops: try { while( !mt.checkAll() ) { GS.con("Still downloading images ... " + "base=" + trackerStatus(mt,0) + " sprite=" + trackerStatus(mt,1) ); Thread.sleep(1000); } while( baseIm.getWidth(this) <=0 || baseIm.getHeight(this) <=0 || spriteIm.getWidth(this) <=0 || spriteIm.getHeight(this) <=0 ) { GS.con("Still negative dimensions ... "); Thread.sleep(1000); } baseW=baseIm.getWidth(this); baseH=baseIm.getHeight(this); spriteW=baseIm.getWidth(this); spriteH=baseIm.getHeight(this); //Do control: rotationCenterOnBaseX = baseW/2; rotationCenterOnBaseY = baseH/2; leftTopOfSpriteOnBaseX = baseW/5; leftTopOfSpriteOnBaseY = baseH/5; if( spriteFitsBase ) { leftTopOfSpriteOnBaseX = 0; leftTopOfSpriteOnBaseY = 0; } } catch (Exception e) { e.printStackTrace(); } if( mt.isErrorAny() ) { GS.con("Problems with some images ... "); //int st = mt.statusID(0, false); } else { GS.con( "All images downloaded successfully." ); //do2: Strangerly: these calls "shakes" dimensions and //enables them later: //GS.con( "Width=" + baseIm.getWidth(this) + // " Height=" + baseIm.getHeight(this) ); resultX = -2; //Success. } ICos.generate(); GS.con("Init finished"); } //init() private String trackerStatus( MediaTracker mt, int index ) { String s = ""; int st = mt.statusID(index, false); if( 0 == st ) { s = "NOT STARTED"; return s; } if( (st & MediaTracker.ABORTED) !=0 ) s = s + "ABORTED "; if( (st & MediaTracker.COMPLETE) !=0 ) s = s + "COMPLETE "; if( (st & MediaTracker.ERRORED) !=0 ) s = s + "ERRORED "; if( (st & MediaTracker.LOADING) !=0 ) s = s + "LOADING "; return s; } public void start() { timeToPrintNewFrame = System.currentTimeMillis(); if( calculateThread == null ) { calculateThread = new Thread(this); calculateThread.setName("Calc"); calculateThread.start(); GS.con( calculateThread.getName() + " initiated." ); } } public void run() { try { while( Thread.currentThread() == calculateThread ) { timeLeftAfterCalculations = timeToPrintNewFrame - System.currentTimeMillis(); repaint(); Thread.sleep(Math.max(0, timeLeftAfterCalculations)); frameNumber++; //GS.con( "Finished sleeping..." ); timeToPrintNewFrame = System.currentTimeMillis() + frameDelay; if( resultX == -2 ) { resultX = columnNumber * baseW; resultY = columnNumber * baseH; GS.con ("w=" + resultX + " h=" + resultY); resultIm = createImage(resultX,resultY); resultG = resultIm.getGraphics(); GS.con("Result image graphics created."); spriteArr = new int[spriteW*spriteH]; baseArr = new int[baseW*baseH]; baseArrBuff = new int[baseW*baseH]; spritePG = new PixelGrabber(spriteIm, 0, 0, spriteW, spriteH, spriteArr, 0, spriteW); basePG = new PixelGrabber(baseIm, 0, 0, baseW, baseH, baseArr, 0, baseW ); /* PixelGrabber(Image img, int x, int y, int w, int h, int[] pix, int off, int scansize) */ try { spritePG.grabPixels(); basePG.grabPixels(); } catch (InterruptedException e) { GS.con("Faile grab pixels: " + e); this.stop(); } GS.con("Pixels grabbed successfully ... "); calculateImage(); this.stop(); //Debug: //this.stop(); } } } catch (InterruptedException e) { GS.con( "In method run" + e ); } } //run() public void update( Graphics g ) { if( imageIsReady && resultIm != null ) { //Move result image to master image: g.drawImage( resultIm, 0,0, null ); g.drawImage( spriteIm, resultX, 0, null ); g.drawImage( baseWithSprite, resultX, baseH, null ); int wi = frameNumber % animationFramesNumber; int animationI = wi % columnNumber; int animationJ = (wi - animationI )/columnNumber; //Put animated image last: g.drawImage( resultIm, //=Source //Target: resultX, baseH*2, resultX+baseW-1, baseH*3 -1, //Source: animationI*baseW, animationJ*baseH, animationI*baseW+baseW-1, animationJ*baseH+baseH-1, null //=ImageObserver ); //Debug: //g.drawString( "Frame=" + frameNumber + // "wi=" + wi + " i=" + animationI + // " j=" + animationJ, 0, resultY/2 ); //Debug: //calculateThread.stop(); } else { g.setColor( new Color(0) ); g.drawString( "Image is not ready yet", 0,0 ); } paint(g); } void calculateImage() { //Debug resultG.setColor(new Color( (255<<16) | (155<<8) | 255 ) ); resultG.fillRect(0,0,resultX-1,resultY-1); resultG.setColor( new Color( 0, 0, 0 ) ); resultG.drawString("Image Created", 3, 3 ); for( int i=0; i<columnNumber; i++ ) { for( int j=0; j<rowNumber; j++ ) { resultG.drawImage( baseIm, i*baseW, j*baseH, null ); //if( 1 == i && 1 == j ) { drawRotatedSprite( rotationCenterOnBaseX, rotationCenterOnBaseY, leftTopOfSpriteOnBaseX, leftTopOfSpriteOnBaseY, ICos.argMax4/3, animationFramesNumber, j*columnNumber + i ); resultG.drawImage( baseWithSprite, i*baseW, j*baseH, null ); //} } } //Debug for cos, sin: //ICos.drawTest( resultG, resultY ); GS.con( "Mutiframe image created." ); imageIsReady = true; } public void drawRotatedSprite( int circleCenterX, int circleCenterY, int spritePosX, int spritePosY, int startAngle, int framesNumber, int currentFrame ) { int argI = (ICos.argMax4*currentFrame)/framesNumber; if(argI>ICos.argMax4) argI = ICos.argMax4; int cosI = ICos.cosI[argI]; int sinI = ICos.sinI[argI]; int sinMax = ICos.sinMax; int spRelPosX = spritePosX - circleCenterX; int spRelPosY = -(spritePosY- circleCenterY); //Normal, not screen coord. //GS.b("Copying to buffer.."); for(int i=0; i<baseW; i++ ) { //do1 use copyMem for(int j=0; j<baseH; j++ ) { int ix = j*baseW + i; baseArrBuff[ix] = baseArr[ix]; } } //GS.m("rotating.."); for(int i=0; i<spriteW; i++) { int fullX = i + spRelPosX; for(int j=0; j<spriteH; j++ ) { int color = spriteArr[j*baseW + i]; //if( (color & 0xFFFFFF ) != TRANSPARENT_COLOR ) { int fullY = spRelPosY-j; int xS = (fullX*cosI + fullY*sinI)/sinMax + circleCenterX; int yS = circleCenterY -((-fullX*sinI) + fullY*cosI)/sinMax; if( xS < baseW && xS > -1 && yS < baseH && yS > -1 ) { int ix = yS*baseW + xS; baseArrBuff[ix] = color; } //} } } //GS.e("rotated."); baseWithSprite= createImage( new MemoryImageSource( baseW, baseH, baseArrBuff, 0, baseW)); //GS.con("Created from arr to graph. ... "); } //drawRotatedSprite() /* Credits: Books: Herbert Shieldt. "The complete reference. Java 2." Fifth edition. Page 825. Kenneth Litwak "Pure Java 2" SAMS 2000 www.samspublishing.com */ } // class