import com.ms.dxmedia.*; import java.util.*; import java.net.*; import Piece; public class ChessModel extends Model { // here are a bunch of constants we'll use: // the size of each square on the board, and the location of square 0,0 protected NumberBvr squareSize = toBvr(1.0/8.0); protected Vector3Bvr pieceOrigin = vector3(toBvr(-3.5/8),toBvr(0),toBvr(3.5/8)); //static URL mybase = null; // the geometry for the pieces (initialized in SetupBoard()) protected GeometryBvr knight = null; protected GeometryBvr queen = null; protected GeometryBvr rook = null; protected GeometryBvr bishop = null; protected GeometryBvr king = null; protected GeometryBvr pawn = null; protected SoundBvr moveSnd = null; protected SoundBvr captureSnd = null; // end of constants // The geoArray keeps track of which geometry is at each board location // The switcherArray keeps track of the switchers needed to tell these // geometries to move around protected GeometryBvr[][] m_geoArray = new GeometryBvr[8][8]; protected ModifiableBehavior[][] m_switcherArray = new ModifiableBehavior[8][8]; // Same information is needed for captured geometries protected Vector m_capturedGeos = new Vector(); protected Vector m_capturedSws = new Vector(); protected int[] m_capturedCounts = new int[2]; // Switcher requires to get an updating behavior of the canvas size. protected ModifiableBehavior m_sizeSw = null; public LabelImage m_resultLabel = null; public void createModel(BvrsToRun b2run) { //mybase = getImportBase(); m_resultLabel = new LabelImage(); // here we setup the size Behavior to give us the size of the canvas. Every time // SetSize() is called the switcher is used to change the behavior. m_sizeSw = new ModifiableBehavior(vector2(mul(toBvr(320),pixelBvr), mul(toBvr(240),pixelBvr))); Vector2Bvr size = (Vector2Bvr) m_sizeSw.getBvr(); // This sets up the arrow buttons to rotate the board ButtonPanel bp = new ButtonPanel(); ImageBvr buttons = bp.getImg(); Vector2Bvr rots = bp.getRots(); // calculate the vector to put the buttonpanel in the upper right corner Vector2Bvr buttonXform = add(size.div(toBvr(2)), sub(origin2,buttons.boundingBox().getMax())); buttonXform = vector2(mul(buttonXform.getX(),toBvr(-1)), mul(buttonXform.getY(),toBvr(-1))); buttons = buttons.transform(translate(buttonXform)); //problem with making the buttons work. // set up the buttons for zooming in and out ZoomPanel zp = new ZoomPanel(); ImageBvr zoomButtons = zp.getImg(); NumberBvr zoomNum = (NumberBvr)zp.getZoom().runOnce(); //Transform2Bvr imgScale = scale2(zp.getZoom()); Transform3Bvr zoomScale = scale(zoomNum, zoomNum,toBvr(1)); // calculate the translate to put it in the lower right corner Vector2Bvr zbtranslate = add(size.div(2), sub(origin2,zoomButtons.boundingBox().getMax())); zbtranslate = vector2(zbtranslate.getX(), mul(zbtranslate.getY(),toBvr(-1))); zoomButtons = zoomButtons.transform(translate(zbtranslate)); // setup the camera according to a pretty first position, and the rotation from the // button panel and scale the image with the info from the zoomPanel. Transform3Bvr cameraXform = compose( rotate(yVector3, neg(rots.getX())), compose(rotate(xVector3, add(toBvr(-Math.PI/6),rots.getY())), compose(zoomScale,translate(toBvr(0),toBvr(0),toBvr(2.5))))); CameraBvr camera= perspectiveCamera(toBvr(1),toBvr(0)).transform(compose( cameraXform,scale(toBvr(6),toBvr(6),toBvr(1)))); MicrophoneBvr mic = defaultMicrophone.transform(cameraXform); // setup the initial board geometry GeometryBvr geo = SetupBoard(); //geo = geo.transform(zoomScale); GeometryBvr headlight = directionalLight.lightColor(colorRgb(toBvr(.6),toBvr(.6),toBvr(.6))). transform(cameraXform); geo = union(geo,headlight); ImageBvr img = geo.render(camera); SoundBvr snd = geo.render(mic); // scale the image with the info from the zoomPanel //img = img.transform(imgScale); // overlay the rendered image with the buttons img = overlay(zoomButtons,overlay(buttons,img)); // make a pretty background color ImageBvr model = overlay(m_resultLabel.getBvr(), overlay(img, solidColorImage(colorRgb(toBvr(.2),toBvr(.27),toBvr(.3))))); setImage(model); setSound(snd); } // this updates size via the size Switcher when the model changes size. public void SetSize(int width, int height){ if (m_sizeSw != null) { Vector2Bvr size = vector2(mul(toBvr(width),pixelBvr), mul(toBvr(height),pixelBvr)); m_sizeSw.switchTo(size); } } protected GeometryBvr SetupBoard() { // import all the geometry we're going to use NumberBvr scale = toBvr(1.0/18.0); try { knight = importGeometry(new URL("file:///c:/program files/da_pgn_viewer/media/knight.x")).transform(scale3(scale)); knight = knight.transform(translate(0.28,0.0,0.38)); queen = importGeometry(new URL("file:///c:/program files/da_pgn_viewer/media/queen.x")).transform(scale3(scale)); queen = queen.transform(translate(-0.05,0,-0.40)); rook = importGeometry(new URL("file:///c:/program files/da_pgn_viewer/media/rook.x")).transform(scale3(scale)); rook = rook.transform(translate(0.38,0,0.38)); bishop = importGeometry(new URL("file:///c:/program files/da_pgn_viewer/media/bishop.x")).transform(scale3(scale)); bishop = bishop.transform(translate(0.17,0,-0.40)); king = importGeometry(new URL("file:///c:/program files/da_pgn_viewer/media/king.x")).transform(scale3(scale)); king = king.transform(translate(0.05,0,-0.40)); pawn = importGeometry(new URL("file:///c:/program files/da_pgn_viewer/media/pawn.x")).transform(scale3(scale)); pawn = pawn.transform(translate(-0.05,0,-0.28)); NumberBvr foo[] = new NumberBvr[2]; moveSnd = importSound(new URL("file:///c:/program files/da_pgn_viewer/media/zoomin2.wav"),foo); captureSnd = importSound(new URL("file:///c:/program files/da_pgn_viewer/media/bangblow.wav"),foo); } catch (MalformedURLException e) { System.err.println("malformed URL!!!!!!!!!!!"); } // set the middle part of the board to empty. for (int i = 2; i < 6; i++) { for (int j = 0; j < 8; j++) { m_switcherArray[i][j] = null; m_geoArray[i][j] = null; } } // put pieces on the rest of the board. setPiece(rook, 0, 0, Piece.WHITE); setPiece(knight, 1, 0, Piece.WHITE); setPiece(bishop, 2, 0, Piece.WHITE); setPiece(queen, 3, 0, Piece.WHITE); setPiece(king, 4, 0, Piece.WHITE); setPiece(bishop, 5, 0, Piece.WHITE); setPiece(knight, 6, 0, Piece.WHITE); setPiece(rook, 7, 0, Piece.WHITE); setPiece(pawn, 0, 1, Piece.WHITE); setPiece(pawn, 1, 1, Piece.WHITE); setPiece(pawn, 2, 1, Piece.WHITE); setPiece(pawn, 3, 1, Piece.WHITE); setPiece(pawn, 4, 1, Piece.WHITE); setPiece(pawn, 5, 1, Piece.WHITE); setPiece(pawn, 6, 1, Piece.WHITE); setPiece(pawn, 7, 1, Piece.WHITE); setPiece(pawn, 0, 6, Piece.BLACK); setPiece(pawn, 1, 6, Piece.BLACK); setPiece(pawn, 2, 6, Piece.BLACK); setPiece(pawn, 3, 6, Piece.BLACK); setPiece(pawn, 4, 6, Piece.BLACK); setPiece(pawn, 5, 6, Piece.BLACK); setPiece(pawn, 6, 6, Piece.BLACK); setPiece(pawn, 7, 6, Piece.BLACK); setPiece(rook, 0, 7, Piece.BLACK); setPiece(knight, 1, 7, Piece.BLACK); setPiece(bishop, 2, 7, Piece.BLACK); setPiece(queen, 3, 7, Piece.BLACK); setPiece(king, 4, 7, Piece.BLACK); setPiece(bishop, 5, 7, Piece.BLACK); setPiece(knight, 6, 7, Piece.BLACK); setPiece(rook, 7, 7, Piece.BLACK); // setup the board geometry GeometryBvr boardGeo = null; GeometryBvr whiteSquares = null; GeometryBvr blackSquares = null; GeometryBvr finalBoard = null; try { whiteSquares = importGeometry(new URL("file:///c:/program files/da_pgn_viewer/media/white_sqrs.x")); blackSquares = importGeometry(new URL("file:///c:/program files/da_pgn_viewer/media/blk_sqrs.x")); boardGeo = importGeometry(new URL("file:///c:/program files/da_pgn_viewer/media/board.x"));//.transform( //scale3(toBvr(1.0/15.0))); finalBoard = union(blackSquares,union(whiteSquares,boardGeo)); finalBoard = finalBoard.transform(scale3(toBvr(1.0/16.0))); // compose(rotate(xVector3, toBvr(-Math.PI/2)), scale3(toBvr(1.0/80.0)))); } catch (MalformedURLException e) { System.err.println("another bad URL!!!"); } GeometryBvr lights = union(union(directionalLight. lightColor(colorRgb(toBvr(.5),toBvr(.5),toBvr(.5))). transform(compose(rotate(xVector3,toBvr(-Math.PI/4)), rotate(yVector3,toBvr(0))) ), directionalLight.lightColor(colorRgb(toBvr(.5),toBvr(.5),toBvr(.5))). transform(compose( rotate(xVector3,toBvr(-.75*Math.PI)), rotate(yVector3,toBvr(0)) ))), ambientLight.lightColor(colorRgb(toBvr(.1),toBvr(.1),toBvr(.1)))); GeometryBvr allGeo = union(finalBoard, lights); // union the board geometry with the geometry of all the pieces. We get the geometry for the // pieces from the switchers so they can be changed by the switcher. for (int i = 0; i < 8; i++){ for (int j = 0; j < 8; j++){ if (m_switcherArray[i][j] != null) { allGeo = union(allGeo, (GeometryBvr)m_switcherArray[i][j].getBvr()); } } } return allGeo; } protected void setPiece(GeometryBvr geo, int x, int y, int color) { GeometryBvr cgeo = null; // color and rotate the piece appropriate to the player if (color == Piece.WHITE) { cgeo = geo.diffuseColor( colorRgb(toBvr(0.7),toBvr(0.7),toBvr(0.7)));/*. specularColor(colorRgb(toBvr(.9),toBvr(.9),toBvr(.9))). specularExponent(toBvr(10)); */ cgeo = cgeo.transform(rotate(yVector3,toBvr(Math.PI))); } else { cgeo = geo.diffuseColor( colorRgb(toBvr(0.6),toBvr(0),toBvr(0.3)));/*. specularColor(colorRgb(toBvr(.5),toBvr(.5),toBvr(.5))). specularExponent(toBvr(10)); */ } // put the piece on the board m_switcherArray[x][y] = new ModifiableBehavior(cgeo.transform(LocationToTransform(x,y))); m_geoArray[x][y] = cgeo; } // returns a vector that will translate a piece to a given spot on the board protected Vector3Bvr LocationToTranslate(int x, int y) { return add(pieceOrigin, vector3(toBvr(x),toBvr(0),toBvr(-y)).mul(squareSize)); } // same thing but returns a transform3Bvr protected Transform3Bvr LocationToTransform(int x, int y) { return translate(LocationToTranslate(x,y)); } // handy utility function, returns a nice number public static NumberBvr Smooth0to1(int duration) { NumberBvr rising = sub (toBvr(.5), div(cos(mul(div(localTime,toBvr(duration)), toBvr(Math.PI))),toBvr(2))); NumberBvr done = toBvr(1); DXMEvent ev = timer(toBvr(duration)); return (NumberBvr)(until(rising, ev, done)); } // returns a transform that will slide a piece from one location to another protected Transform3Bvr SlidingTransform(int xfrom, int yfrom, int xto, int yto,int duration) { Vector3Bvr fromVec = LocationToTranslate(xfrom,yfrom); Vector3Bvr toVec = LocationToTranslate(xto,yto); Vector3Bvr moveVec = sub(toVec, fromVec); return translate(add(moveVec.mul(Smooth0to1(duration)),LocationToTranslate(xfrom,yfrom))); } // animates a piece moving from one location to another public void MovePiece(int xfrom, int yfrom, int xto, int yto) { GeometryBvr newGeo = union(m_geoArray[xfrom][yfrom],soundSource(moveSnd)); newGeo = newGeo.transform(SlidingTransform(xfrom,yfrom,xto,yto,3)); m_switcherArray[xto][yto] = m_switcherArray[xfrom][yfrom]; m_switcherArray[xfrom][yfrom] = null; m_geoArray[xto][yto] = m_geoArray[xfrom][yfrom]; m_geoArray[xfrom][yfrom] = null; m_switcherArray[xto][yto].switchTo(newGeo); } public void CapturePiece(int x, int y, int player) { //keep track of the fact that its been captured m_capturedSws.addElement(m_switcherArray[x][y]); m_capturedGeos.addElement(m_geoArray[x][y]); // calculate where on the board to put the captured piece. We want two columns along side // the board int xTo = m_capturedCounts[player]/10; int yTo = m_capturedCounts[player]%10; if (player == Piece.WHITE) { xTo += 9; yTo -= 1; } else { xTo = -2 -xTo; yTo = 9 -yTo; } // calculate the transform to make it fly and twist in agony int duration = 4; Transform3Bvr slide = SlidingTransform(x,y,xTo,yTo,duration); // here is the height of the toss NumberBvr height = sub(mul(sin(mul(localTime,toBvr(Math.PI/duration))),toBvr(.35)), mul(div(localTime,toBvr(duration)),squareSize)); Transform3Bvr rot = rotate(vector3(toBvr(1),toBvr(0.2),toBvr(.5)), mul(localTime,toBvr(Math.PI*2/duration))); // this toss just puts a piece straight up int the air and then back down. Transform3Bvr toss = (Transform3Bvr)until(compose(translate(toBvr(0),height,toBvr(0)),rot), timer(toBvr(duration)),translate(toBvr(0),mul(toBvr(-1),squareSize),toBvr(0))); // add the slide to move the piece off the board Transform3Bvr capturedXform =compose(slide,toss); // tell the piece to execute the move with sound m_switcherArray[x][y].switchTo(union(m_geoArray[x][y],soundSource(captureSnd)).transform(capturedXform)); // take the piece off the board m_geoArray[x][y] = null; m_switcherArray[x][y] = null; m_capturedCounts[player]++; } public void RevivePiece(int x, int y, int player) { // move the last captured piece of color player back onto the board m_switcherArray[x][y] = (ModifiableBehavior)m_capturedSws.lastElement(); m_capturedSws.removeElementAt(m_capturedSws.size() -1); m_geoArray[x][y] = (GeometryBvr)m_capturedGeos.lastElement(); m_capturedGeos.removeElementAt(m_capturedGeos.size() -1); m_switcherArray[x][y].switchTo(m_geoArray[x][y].transform(LocationToTransform(x,y))); m_capturedCounts[player]--; } public void PromotePiece(int x, int y, int type) { // change the geometry of a specific piece switch (type) { case Piece.QUEEN: m_geoArray[x][y] = queen; break; case Piece.PAWN: m_geoArray[x][y] = pawn; break; case Piece.ROOK: m_geoArray[x][y] = rook; break; case Piece.KNIGHT: m_geoArray[x][y] = knight; break; case Piece.BISHOP: m_geoArray[x][y] = bishop; break; case Piece.KING: m_geoArray[x][y] = king; break; } m_switcherArray[x][y].switchTo(m_geoArray[x][y].transform(LocationToTransform(x,y))); } } // end ChessModel // class: ButtonPanel // this class generates the arrow buttons for the upper right hand corner of the screen. // we will get from this an image to put onscreen, and a vector2 that is the amount to // rotate the board on the X and Y axis. class ButtonPanel extends Statics implements UntilNotifier { DXMEvent m_arrowPick = null; Vector2Bvr m_rots = null; PickableImage m_pimg = null; public ButtonPanel() { // setup the pickable image try { m_pimg = new PickableImage(importImage(new URL("file:///c:/program files/da_pgn_viewer/media/arrows.gif"))); }catch (MalformedURLException e) { System.err.println("AWWWWWWWWWW!"); } m_arrowPick = m_pimg.getPickEvent(); // speeds is zero until we get clicked on... Vector2Bvr speeds = (Vector2Bvr)untilNotify(zeroVector2, andEvent(leftButtonDown,m_arrowPick), this); Vector2Bvr actualZoomSpeed = Vector2Bvr.newUninitBvr(); actualZoomSpeed.init(until( speeds,orEvent(notEvent(m_arrowPick),leftButtonUp), actualZoomSpeed)); // total amount to rotate is the integral of how long we've been holding // the button down. m_rots = integral(actualZoomSpeed); m_rots.runOnce(); } public ImageBvr getImg() { return m_pimg.getImageBvr(); } public Vector2Bvr getRots() { return m_rots; } // utility function public static NumberBvr sign(NumberBvr b) { return (NumberBvr)cond(gte(b, toBvr(0)), toBvr(1), toBvr(-1)); } public static NumberBvr min(NumberBvr a, NumberBvr b) { return (NumberBvr)cond(lte(a,b),a,b); } public static NumberBvr max(NumberBvr a, NumberBvr b) { return (NumberBvr)cond(gte(a,b),a,b); } // called when we're picked on public Behavior notify(Object eventData, Behavior prev, BvrsToRun b2r) { // cast the event data for easier access PairObject andEv = (PairObject)eventData; PairObject pickData = (PairObject)andEv.getSecond(); Point2Bvr pickPt= (Point2Bvr)pickData.getFirst(); Vector2Bvr pickVec = (Vector2Bvr)pickData.getSecond(); // the Pt picked on the image pickPt = add(pickPt,pickVec); // turn on/off latspeed/longspeed depending on which quadrant of the image we're in NumberBvr latSpeed = (NumberBvr)cond (gt(abs(pickPt.getX()), abs(pickPt.getY())), sign(pickPt.getX()),toBvr(0)); NumberBvr longSpeed = (NumberBvr)cond (gt(abs(pickPt.getX()), abs(pickPt.getY())), toBvr(0), sign(pickPt.getY())); longSpeed.runOnce(); NumberBvr cappedLongSpeed =(NumberBvr) cond(gte(m_rots.getY(), toBvr(Math.PI/2.0)),min(longSpeed,toBvr(0)),longSpeed); Vector2Bvr speeds = vector2(latSpeed,cappedLongSpeed).div(toBvr(3)); return speeds; // return the speeds we just calculated, until we either let go of the mouse button // or move the mouse of the picture, then become a zeroVector that will run through this // notifier when clicked on. //return until(speeds, orEvent(notEvent(m_arrowPick),leftButtonUp), // untilNotify(zeroVector2, andEvent(leftButtonDown,m_arrowPick), this)); } } // class: ZoomPanel // Very similar to the ButtonPanel, except here we only have to detect if we are on // the top or bottom half of the image. class ZoomPanel extends Statics implements UntilNotifier { DXMEvent m_zoomPick = null; NumberBvr m_zoom = null; PickableImage m_pimg = null; public ZoomPanel() { // set up the pickable image try { ImageBvr img = importImage(new URL("file:///c:/program files/da_pgn_viewer/media/zoom.bmp")); m_pimg = new PickableImage(img); }catch (MalformedURLException e) { System.err.println("AWWW!"); } m_zoomPick = m_pimg.getPickEvent(); // set zoomspeed to be zero until we get clicked on NumberBvr zoomSpeed = (NumberBvr)untilNotify(toBvr(0), andEvent(leftButtonDown,m_zoomPick), this); NumberBvr actualZoomSpeed = NumberBvr.newUninitBvr(); actualZoomSpeed.init(until( zoomSpeed,orEvent(notEvent(m_zoomPick),leftButtonUp), actualZoomSpeed)); // integrate the zoom speed and scale it to look nice. m_zoom = add(div(integral(actualZoomSpeed),toBvr(4)),toBvr(1)); } public ImageBvr getImg() { return m_pimg.getImageBvr(); } public NumberBvr getZoom() { return m_zoom; } public static NumberBvr sign(NumberBvr b) { return (NumberBvr)cond(gte(b, toBvr(0)), toBvr(-1), toBvr(1)); } public Behavior notify(Object eventData, Behavior prev, BvrsToRun b2r) { // get at the event data PairObject andEv = (PairObject)eventData; PairObject pickData = (PairObject)andEv.getSecond(); Point2Bvr pickPt= (Point2Bvr)pickData.getFirst(); Vector2Bvr pickVec = (Vector2Bvr)pickData.getSecond(); // pickPt is the pt that the mouse is currently on in image coordinates pickPt = add(pickPt,pickVec); // are we on the top or bottom of the image NumberBvr zoomSpeed = sign(pickPt.getY()); return zoomSpeed; } } class LabelImage extends Statics { ModifiableBehavior sw = null; LabelImage() { sw = new ModifiableBehavior(emptyImage); } ImageBvr getBvr() { return (ImageBvr)sw.getBvr(); } void switchText(String text) { FontStyleBvr fs = defaultFont.bold().color(white); if (text == null) { sw.switchTo(emptyImage); } else { ImageBvr textIm = textImage(text,fs).transform(scale2(2)); Bbox2Bvr bbox = textIm.boundingBox(); ImageBvr background = solidColorImage(black) .crop(bbox.getMin(), bbox.getMax()).opacity(.5). transform(scale(2,1)); sw.switchTo(overlay(textIm,background)); } } }