//======================================================== // Transforms - a simple applet demonstrating transformations // Written by Chris DeCoro - cdecoro@cat.nyu.edu // Sept. 9, 2002 //======================================================== import java.util.*; import java.awt.*; import java.awt.event.*; import Geometry.*; public class Transforms extends TransformableApplet { public int randChar() { return (int)(Math.random()*255.0); } public void render(Graphics g) { if (damage) { setContext(g); transform( (new Matrix3x3()) ); begin(RENDER_POLYGON); color(255, 255, 255); vertex(0, 0); vertex(bounds().width, 0); vertex(bounds().width, bounds().height); vertex(0, bounds().height); end(); double hw=bounds().width/2, hh=bounds().height/2; transform( (new Matrix3x3()) .scale(scaleX,-1*scaleY) .rotate(theta) .translate(translateX+hw,translateY+hh) ); //Draw the axis lines /* begin(RENDER_LINES); color(127, 127, 0); vertex(0, 0); vertex(300, 0); color(127, 0, 127); vertex(0, 0); vertex(0, 300); end(); */ //Draw the two triangles for the eyes begin(RENDER_TRIANGLE); color(randChar(), randChar(), randChar()); vertex(-50, 50); vertex(-20, 50); vertex(-35, 80); color(randChar(), randChar(), randChar()); vertex(50, 50); vertex(20, 50); vertex(35, 80); end(); //Draw the square for the nose begin(RENDER_POLYGON); color(255, 0, 0); vertex(-15, 15); vertex(-15, -15); vertex( 15, -15); vertex( 15, 15); end(); //Draw the line strip for the mouth begin(RENDER_LINE_STRIP); color(127, 64, 64); vertex(-45, -30); vertex(-25, -40); vertex(+25, -40); vertex(+45, -30); end(); //Draw the border of the face begin(RENDER_OPEN_POLYGON); vertex(-50, 100); vertex(-60, 90); vertex(-60, -50); vertex(-50, -60); vertex(+50, -60); vertex(+60, -50); vertex(+60, 90); vertex(+50, 100); end(); setContext(null); } } public boolean mouseDown(Event e, int x, int y) { boolean leftButton, centerButton, rightButton; centerButton = ((e.modifiers & e.ALT_MASK) > 0); rightButton = ((e.modifiers & e.META_MASK) > 0); leftButton = !centerButton && !rightButton; downX = x; downY = y; oldTranslateX = translateX; oldTranslateY = translateY; oldScaleX = scaleX; oldScaleY = scaleY; oldTheta = theta; setDamage(); return true; } public boolean mouseDrag(Event e, int x, int y) { boolean leftButton, centerButton, rightButton; centerButton = ((e.modifiers & e.ALT_MASK) > 0); rightButton = ((e.modifiers & e.META_MASK) > 0); leftButton = !centerButton && !rightButton; if( downX == -1 ) return true; if(rightButton) { System.out.println("Right button"); scaleX = oldScaleX + (x - downX)/10.0; scaleY = oldScaleY + -(y - downY)/10.0; //if( Math.abs(scaleX) < 0.1 ) scaleX = 0.1; // scaleX = ( scaleX < 0 ? -1 : 1 ); //if( Math.abs(scaleY) < 0.1 ) scaleY = 0.1; //scaleY = ( scaleY < 0 ? -1 : 1 ); } else if(centerButton) { theta = oldTheta + ((x - downX))/2; } else if(leftButton) { translateX = oldTranslateX + (x - downX); translateY = oldTranslateY + (y - downY); } setDamage(); return true; } public boolean mouseUp(Event e, int x, int y) { boolean leftButton, centerButton, rightButton; centerButton = ((e.modifiers & e.ALT_MASK) > 0); rightButton = ((e.modifiers & e.META_MASK) > 0); leftButton = !centerButton && !rightButton; if( downX == -1 ) return true; downX = -1; downY = -1; setDamage(); return true; } int downX=-1, downY=-1; double translateX=0, translateY=0; double oldTranslateX=0, oldTranslateY=0; double scaleX=1, scaleY=1; double oldScaleX=1, oldScaleY=1; double theta=0, oldTheta=0; } class TransformableApplet extends GenericApplet { int x = 100, y = 100; void setContext(Graphics g) { graphics = g; } void begin(int shapeType) { if( renderState != RENDER_NONE ) { throw new RuntimeException("Cannot call begin() twice without intervening end()"); } if( shapeType < RENDER_NONE || shapeType > RENDER_LAST ) { throw new RuntimeException("Attempted to draw an invalid primitive"); } renderState = shapeType; sentVertices = 0; polygon = new Polygon(); } void end() { if( renderState == RENDER_NONE ) { throw new RuntimeException("Cannot call end() without begin()"); } else if( renderState == RENDER_POLYGON ) { graphics.fillPolygon(polygon); } else if( renderState == RENDER_OPEN_POLYGON ) { graphics.drawPolygon(polygon); } renderState = RENDER_NONE; } void color(int r, int g, int b) { graphics.setColor(new Color(r,g,b)); } void vertex(int x, int y) { Vector3 worldCoord, screenCoord; worldCoord = new Vector3(x, y, 1); screenCoord = transformMatrix.mul(worldCoord); int screenX, screenY; screenX = (int)screenCoord.array()[0]; screenY = (int)screenCoord.array()[1]; if( renderState == RENDER_NONE ) { throw new RuntimeException("Must call begin() before sending a vertex"); } else if( renderState == RENDER_LINES ) { if( sentVertices == 0 ) { lineX = screenX; lineY = screenY; sentVertices++; } else { System.out.println(lineX + " " + lineY +" " + screenX + " " + screenY); graphics.drawLine(lineX, lineY, screenX, screenY); sentVertices = 0; } } else if( renderState == RENDER_LINE_STRIP ) { if( sentVertices > 0 ) graphics.drawLine(lineX, lineY, screenX, screenY); lineX = screenX; lineY = screenY; sentVertices++; } else if( renderState == RENDER_POLYGON || renderState == RENDER_OPEN_POLYGON || renderState == RENDER_TRIANGLE || renderState == RENDER_OPEN_TRIANGLE ) { polygon.addPoint(screenX, screenY); sentVertices++; } if( renderState == RENDER_TRIANGLE && sentVertices == 3 ) { graphics.fillPolygon(polygon); polygon = new Polygon(); sentVertices = 0; } else if( renderState == RENDER_OPEN_TRIANGLE && sentVertices == 3 ) { graphics.drawPolygon(polygon); polygon = new Polygon(); sentVertices = 0; } } void transform(Matrix3x3 mat) { transformMatrix = mat; } void setDamage() { damage = true; } void printMatrix(Matrix3x3 matr) { double[][] mat = matr.array(); System.out.println("| " + mat[0][0] + " " + mat[0][1] + " " + mat[0][2] + " |"); System.out.println("| " + mat[1][0] + " " + mat[1][1] + " " + mat[1][2] + " |"); System.out.println("| " + mat[2][0] + " " + mat[2][1] + " " + mat[2][2] + " |"); } static int RENDER_NONE=0; static int RENDER_LINES=1; static int RENDER_LINE_STRIP=2; static int RENDER_POLYGON=3; static int RENDER_OPEN_POLYGON=4; static int RENDER_TRIANGLE=5; static int RENDER_OPEN_TRIANGLE=6; static int RENDER_LAST=RENDER_OPEN_TRIANGLE; //Current transform matrix, which takes world coord to screen coord private Matrix3x3 transformMatrix = new Matrix3x3(); //Current Render state; which primitive, if any, is being rendered private int renderState = RENDER_NONE; //Storage for any polygon-based primitive being submitted private Polygon polygon = new Polygon(); //Storage for the last coordinate for a line-based primitive private int lineX= 0; private int lineY= 0; //Counts the number of vertices sent for the current primitive private int sentVertices = 0; //Current rendering context private Graphics graphics = null; } class GenericApplet extends java.applet.Applet implements Runnable { public boolean damage = true; // you can force a render public void render(Graphics g) { } // you can define how to render private Image image = null; private Graphics buffer = null; private Thread t; private Rectangle r = new Rectangle(0, 0, 0, 0); public void start() { if (t == null) { t = new Thread(this); t.start(); } } public void stop() { if (t != null) { t.stop(); t = null; } } public void run() { try { while (true) { repaint(); t.sleep(30); } } catch(InterruptedException e){}; } public void update(Graphics g) { if (r.width != bounds().width || r.height != bounds().height) { image = createImage(bounds().width, bounds().height); buffer = image.getGraphics(); r = bounds(); damage = true; } render(buffer); damage = false; if (image != null) g.drawImage(image,0,0,this); } }