30 Lines of JavaFX Coding Challenge Theme – Time

1 10 2009


Space Time (updated!)

My entry is called ‘Space Time‘. A 3D cube clock. The full source code that is readable is below the article.

Wow, it is amazing at what you can you do in 30 lines of JavaFX code or 3000 characters.   JFXStudio is running a contest and the theme has to do with “TIME”. Although I posted my entry very last minute, there will be other chances for you to enter. Please visit http://jfxstudio.wordpress.com/2009/08/31/jfxstudio-challenge-small-is-the-new-big/

Space Time

Space Time

My entry including the import statements are just at 30 lines with each line containing less than or equal to 100 characters.  Click on the image to launch the demo.

Instructions:

  • Observe the cube rotating as each tick a second.
  • Observe the Space Time Title’s Distant lighting effect as seconds go by
  • Use mouse drag to rotate 3D cube
  • import javafx.animation.*;import javafx.scene.*;import javafx.scene.paint.Color;import javafx.scene
    .effect.*;import javafx.scene.text.*;import javafx.scene.shape.*;import javafx.scene.input.
    MouseEvent;import javafx.util.Math;class P{var x:Number;var y:Number;var z:Number;var sX:Number;var
    sY:Number;}class E{var a:Integer;var b:Integer;}var w:Number=800;var h:Number=600;var a:Number=30;
    var e:Number=30;var vs:P[]=[];function av(x:Integer,y:Integer,z:Integer){insert P{x:x,y:y,z:z}into
    vs;}av(-1,-1,-1);av(-1,-1,1);av(-1,1,-1);av(-1,1,1);av(1,-1,-1);av(1,-1,1);av(1,1,-1);av(1,1,1);var
    es:E[]=[];function aE(a:Integer,b:Integer){insert E{a:a,b:b}into es;}aE(0,1);aE(0,2);aE(0,4);aE(1,3
    );aE(1,5);aE(2,3);aE(2,6);aE(3,7);aE(4,5);aE(4,6);aE(5,7);aE(6,7);var ps:Circle[]=[];var ls:Line[]=
    [];function mps(c:Boolean):Void{var th:Number=bind 0.017453*a;var ph=0.017453*e;var cT=Math.cos(th)
    ;var sT=Math.sin(th);var cP=Math.cos(ph);var sP=Math.sin(ph);var cTcP=cT*cP;var cTsP=cT*sP;var sTcP
    =sT*cP;var sTsP=sT*sP;var sf=bind w/4;for(i in[0..sizeof vs-1]){var x0=vs[i].x;var y0=vs[i].y;var
    z0=vs[i].z;var x1=cT*x0+sT*z0;var y1=-sTsP*x0+cP*y0+cTsP*z0;var z1=cTcP*z0-sTcP*x0-sP*y0;x1=x1*3/(
    z1+4.5);y1=y1*3/(z1+4.5);vs[i].sX=x1;vs[i].sY=y1;if(c)insert Circle{centerX:bind w/2+sf*vs[i].sX+.5
    ,centerY: bind h/2-sf*vs[i].sY+.5,radius:2 fill:Color.BLUE}into ps;}if(c)for(e in es){insert Line{
    startX:bind ps[e.a].centerX startY:bind ps[e.a].centerY endX:bind ps[e.b].centerX endY:bind ps[e.b]
    .centerY strokeWidth:2,stroke:Color.BLUE}into ls;}}mps(true);var mx:Number;var my:Number;var g:
    Rectangle=Rectangle{x:0,y:0 width:bind w,height:bind h fill:Color.BLACK onMousePressed:function(me:
    MouseEvent):Void{mx=me.x;my=me.y;}onMouseDragged:function(me:MouseEvent):Void{var new_mx=me.x;a-=
    new_mx-mx;var new_my=me.y;e+=new_my-my;mx=new_mx;my=new_my;mps(false);}}var ct:String=new java.util
    .Date().toString();var tz:Integer=-125;var t=Group{content:[Text{effect:Lighting{light:javafx.scene
    .effect.light.DistantLight{azimuth:bind tz elevation:40}surfaceScale:5} x:10 y:50 content:"Space "
    "Time" fill:Color.RED font:Font{name:"Arial Bold" letterSpacing:0.20 size:50}},Text{x:10 y:80
    content:bind ct fill:Color.BLUE font:Font{name:"Arial Bold" letterSpacing:0.20 size:20}}]}var bc=
    Group{content:[Rectangle{x:10,y:bind h-85,arcHeight:5,arcWidth:5,width:bind w-30,height:30,fill:
    Color.RED,opacity:.5},Text{effect:DropShadow{offsetX:10,offsetY:10,color:Color.BLACK,radius:10}
    opacity:.5 x:15,y:bind h-65,content:"by Carl Dea - carlfx.wordpress.com"fill:Color.WHITE font:Font{
    name:"Arial Bold"letterSpacing:.20 size:20}}]}var scene:Scene=Scene{content:bind[g,ps,ls,t,bc]};var
    anim=Timeline{keyFrames:[KeyFrame{time:1s action:function():Void{a-=1;mps(false);ct=new java.util.
    Date().toString();if(tz>125){tz=-125;}tz+=2;}}]repeatCount:Timeline.INDEFINITE};anim.play();javafx.
    stage.Stage{width:bind w with inverse height:bind h with inverse scene:scene}

    Enjoy!
    Please vote for me…
    Let me know what you think. :)

    Here is the readable source code below:

    /**
     * Main.fx
     *
     * Check out http://www.comp.brad.ac.uk/research/GIP/tutorials/project1.html for all the math.
     * Created on Dec 20, 2009, 11:06:15 PM
     */
    
    package bigsmall.part8;
    
    import javafx.animation.*;
    import javafx.scene.*;
    import javafx.scene.paint.Color;
    import javafx.scene.effect.*;
    import javafx.scene.effect.light.DistantLight;
    import javafx.scene.text.*;
    import javafx.scene.shape.*;
    import javafx.scene.input.MouseEvent;
    import javafx.stage.*;
    import java.util.Date;
    import javafx.util.Math;
    
    class Point3D {
    
        var x: Number;
        var y: Number;
        var z: Number;
        var screenX: Number;
        var screenY: Number;
    }
    
    class Edge {
        var a: Integer;
        var b: Integer;
    }
    var width: Number = 800;
    var height: Number = 600;
    var azimuth: Number = 30;
    var elevation: Number = 30;
    var vertices: Point3D[] = [];
    
    function addVertex(x: Integer, y: Integer, z: Integer) {
        insert Point3D {x: x,
            y: y, z: z} into vertices;
    }
    
    addVertex(-1, -1, -1);
    addVertex(-1, -1, 1);
    addVertex(-1, 1, -1);
    addVertex(-1, 1, 1);
    addVertex(1, -1, -1);
    addVertex(1, -1, 1);
    addVertex(1, 1, -1);
    addVertex(1, 1, 1);
    
    var edges: Edge[] = [];
    
    function addEdge(a: Integer, b: Integer) {
        insert Edge {a: a, b: b} into edges;
    }
    
    addEdge(0, 1);
    addEdge(0, 2);
    addEdge(0, 4);
    addEdge(1, 3);
    addEdge(1, 5);
    addEdge(2, 3);
    addEdge(2, 6);
    addEdge(3, 7);
    addEdge(4, 5);
    addEdge(4, 6);
    addEdge(5, 7);
    addEdge(6, 7);
    
    var points: Circle[] = [];
    var lines: Line[] = [];
    
    function movePoints(createFirstTime: Boolean): Void {
        var theta: Number = bind 0.017453 * azimuth;
        var phi = 0.017453 * elevation;
        var cosTheta = Math.cos(theta);
        var sinTheta = Math.sin(theta);
        var cosPhi = Math.cos(phi);
        var sinPhi = Math.sin(phi);
        var cosThetaCosPhi = cosTheta * cosPhi;
        var cosThetaSinPhi = cosTheta * sinPhi;
        var sinThetaCosPhi = sinTheta * cosPhi;
        var sinThetaSinPhi = sinTheta * sinPhi;
        var scaleFactor = bind width / 4;
        for (i in [0..sizeof vertices - 1]) {
            var x0 = vertices[i].x;
            var y0 = vertices[i].y;
            var z0 = vertices[i].z;
            var x1 = cosTheta * x0 + sinTheta * z0;
            var y1 = -sinThetaSinPhi * x0 + cosPhi * y0 + cosThetaSinPhi * z0;
            var z1 = cosThetaCosPhi * z0 - sinThetaCosPhi * x0 - sinPhi * y0;
            x1 = x1 * 3 / (z1 + 4.5);
            y1 = y1 * 3 / (z1 + 4.5);
            vertices[i].screenX = x1;
            vertices[i].screenY = y1;
            if (createFirstTime) {
                insert
                    Circle { centerX: bind width / 2 + scaleFactor * vertices[i].screenX + 0.5,
                             centerY: bind height / 2 - scaleFactor * vertices[i].screenY + 0.5,
                             radius: 2
                             fill: Color.BLUE
                    }
                into points;
            }
        }
    
        if (createFirstTime) {
            for (edge in edges) {
                insert
                    Line {   startX: bind points[edge.a].centerX
                                startY: bind points[edge.a].centerY
                                endX: bind points[edge.b].centerX
                                endY: bind points[edge.b].centerY
                                strokeWidth: 2,
                                stroke: Color.BLUE
                    }
                into lines;
            }
        }
    }
    
    // create the first time; draw cube.
    movePoints(true);
    
    var mouseX: Number;
    var mouseY: Number;
    
    // Space region that changes the azimuth and recalculates the cube
    var galaxy: Rectangle = Rectangle { x: 0,
                                        y: 0
                                        width: bind width,
                                        height: bind height
                                        fill: Color.BLACK
                                        onMousePressed: function (me: MouseEvent): Void {
                                            mouseX = me.x;
                                            mouseY = me.y;
                                        }
                                        onMouseDragged: function (me: MouseEvent): Void {
                                            var new_mx = me.x;
                                            azimuth -= new_mx - mouseX;
                                            var new_my = me.y;
                                            elevation += new_my - mouseY;
                                            mouseX = new_mx;
                                            mouseY = new_my;
                                            movePoints(false);
                                        }
    } // galaxy
    
    var currentTime: String = new Date().toString();
    var initialAzimuth: Integer = -125;
    
    // Title with current time seconds.
    var titleDisplay = Group { content: [Text {    effect: Lighting {  light: DistantLight {   azimuth: bind initialAzimuth
                                                                                               elevation: 40
                                                                              }
                                                   surfaceScale: 5
                                                           }
                                        x: 10
                                        y: 50
                                        content: "Space Time"
                                        fill: Color.RED
                                        font: Font {    name: "Arial Bold"
                                                        letterSpacing: 0.20
                                                        size: 50
                                              }
                              },
                              Text {    x: 10
                                        y: 80
                                        content: bind currentTime
                                        fill: Color.BLUE
                                        font: Font {    name: "Arial Bold"
                                                        letterSpacing: 0.20
                                                        size: 20
                                              }
                              }
                    ]
         }
    
    // This is the bottom display credits
    var byCarl = Group {    content: [Rectangle {   x: 10,
                                                    y: bind height - 85,
                                                    arcHeight: 5,
                                                    arcWidth: 5,
                                                    width: bind width - 30,
                                                    height: 30,
                                                    fill: Color.RED,
                                                    opacity: .5
                                      },
                                      Text {    effect: DropShadow {    offsetX: 10,
                                                                        offsetY: 10,
                                                                        color: Color.BLACK,
                                                                        radius: 10
                                                        }
                                                opacity: .5
                                                x: 15,
                                                y: bind height - 65,
                                                content: "by Carl Dea - carlfx.wordpress.com"
                                                fill: Color.WHITE
                                                font: Font {    name: "Arial Bold"
                                                                letterSpacing: .20
                                                                size: 20
                                                      }
                                      }
                           ]
    } // by Carl
    var scene: Scene = Scene {  content: bind [galaxy, points, lines, titleDisplay, byCarl]};
    
    // this is the ticking motion of the cube.
    var anim = Timeline {   keyFrames: [KeyFrame {time: 1s
                                                  action: function (): Void {
                                                        azimuth -= 1;
                                                        movePoints(false);
                                                        currentTime = new Date().toString();
                                                        if (initialAzimuth > 125) {
                                                            initialAzimuth = -125;
                                                        }
                                                        initialAzimuth += 2;
                                                 }
                                        }
                            ]
                            repeatCount: Timeline.INDEFINITE
    }; // animation
    
    anim.play();
    
    Stage { title: "Space Time"
            width: bind width with inverse
            height: bind height with inverse
            scene: scene
    }
    

    Actions

    Information

    5 responses

    1 10 2009
    Space Time « JFXStudio: sketch, hack, share

    [...] To see the code and read more go here. [...]

    1 10 2009
    Matthew

    Looks good. Any chance you can post the formatted source code?

    1 10 2009
    carldea

    Mathew,

    Sure. By coincidence I was going to not enter the contest and play with 3D Math and create a blog entry for my game programming habit. So, I thought the code could be short enough to enter the contest. But, if you don’t mind I will create similar source code and my intended blog entry to help others learn about 3D programming (so, stay tuned during the week)(It will be simple without all the bells and whistles). My goal is to re-learn my old math skills. I plan to play with graphics in general (texture mapping, 3D surfaces, animation, collision, etc).

    Carl

    4 10 2009
    Matthew

    Sure – look forward to reading the future posts

    5 11 2009
    maksim

    Looks great!!! I am a novice in JFX and am trying to study it. Your blog helps me on my way. Thank you!

    Leave a comment