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
             }
          }
       ]
    }; // titleDisplay Group
    
    
    // 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
             }
          }
       ] // byCarl contents Group
    }; // 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;
             }
          }
       ] // keyFrames
       repeatCount: Timeline.INDEFINITE
    }; // animation
    
    anim.play();
    
    Stage { 
       title: "Space Time"
       width: bind width with inverse
       height: bind height with inverse
       scene: scene
    }
    
    
    About these ads

    Actions

    Information

    10 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!

    5 01 2010
    Kishore

    Great work, It runs so smooth.

    16 07 2010
    Binky

    Can you explain the use of the number 3 and the 4.5 in line 106 and 107. I was trying to expand the box to actual pixels and until I changed both numbers by a factor of 100 the display was quite strange.

    16 07 2010
    Binky

    Also the constant of 0.017453 on line 88 and 89. Thanks

    19 07 2010
    carldea

    Brinkley,

    line 88 is supposed to be: var theta:Number = Math.PI * azimuth / 180.0;
    line 89 is supposed to be: var phi = Math.PI * elevation / 180.0;

    Taking Math.PI / 180 will give you 0.017453
    My attempt to squish the code as small as possible.

    19 07 2010
    carldea

    Binky,
    In the processes of making the the code smaller I lost the original code. So, I was trying to make the code readable by getting it back to what it was. So, I missed those lines you mentioned. Yes I hope my explanation below will help.

    var eyeToNearPlane= 3; // distance from eye to near plane
    var nearToCenterOfObj:Number = 1.5; // distance from near plane to center of object

    x1 = x1*eyeToNearPlane/(z1+eyeToNearPlane+nearToCenterOfObj);
    y1 = y1*eyeToNearPlane/(z1+eyeToNearPlane+nearToCenterOfObj);

    My silly attempt to squish the code.
    Thanks!
    -Carl

    Leave a Reply

    Fill in your details below or click an icon to log in:

    WordPress.com Logo

    You are commenting using your WordPress.com account. Log Out / Change )

    Twitter picture

    You are commenting using your Twitter account. Log Out / Change )

    Facebook photo

    You are commenting using your Facebook account. Log Out / Change )

    Google+ photo

    You are commenting using your Google+ account. Log Out / Change )

    Connecting to %s




    Follow

    Get every new post delivered to your Inbox.

    Join 68 other followers

    %d bloggers like this: