diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/Assets/openfl.svg b/projects/flixel-desktop-habit-puzzle-game/JigsawX/Assets/openfl.svg
new file mode 100644
index 00000000..6d02f403
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/Assets/openfl.svg
@@ -0,0 +1,593 @@
+
+
+
+
+
+
+
+
+
+
+]>
+
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/Assets/tablecloth.jpg b/projects/flixel-desktop-habit-puzzle-game/JigsawX/Assets/tablecloth.jpg
new file mode 100644
index 00000000..0448e4ed
Binary files /dev/null and b/projects/flixel-desktop-habit-puzzle-game/JigsawX/Assets/tablecloth.jpg differ
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/LICENSE b/projects/flixel-desktop-habit-puzzle-game/JigsawX/LICENSE
new file mode 100644
index 00000000..b1a7c324
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2017 nanjizal
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/README.md b/projects/flixel-desktop-habit-puzzle-game/JigsawX/README.md
new file mode 100644
index 00000000..c6b83d25
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/README.md
@@ -0,0 +1,11 @@
+# JigsawX
+
+WIP - needs reoganising folders.
+
+Jigsaw generation engine, many attributes are adjustable.
+
+versions: NME / OpenFL / Swing / Flash / Javascript ( uses div's and canvas ).
+
+[Demo Haxe Javascript Jigsaw](https://rawgit.com/nanjizal/JigsawX/master/bin/JigsawDivtastic.html)
+
+
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/application.xml b/projects/flixel-desktop-habit-puzzle-game/JigsawX/application.xml
new file mode 100644
index 00000000..9e39dc78
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/application.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/compileApplet.hxml b/projects/flixel-desktop-habit-puzzle-game/JigsawX/compileApplet.hxml
new file mode 100644
index 00000000..22993332
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/compileApplet.hxml
@@ -0,0 +1,16 @@
+
+# loading the images in browser does not work because of security signing stuff
+# but the appletviewer should work if I could rem the right setup!!
+-D applet
+-java java
+-main JigsawxJava
+#-resource tablecloth.jpg@tablecloth
+-D haxe3
+--next
+-cmd cd java/src
+-cmd javac haxe/root/JigsawxJava.java -d ../
+-cmd cd ..
+-debug
+-cmd jar cvf jigsawx.jar *
+-cmd appletviewer jigsawxjava.html
+#-cmd open -a /Applications/Opera.app http://localhost:8080/jigsawxjava.html
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/compileFlash.hxml b/projects/flixel-desktop-habit-puzzle-game/JigsawX/compileFlash.hxml
new file mode 100644
index 00000000..8b3edb8c
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/compileFlash.hxml
@@ -0,0 +1,28 @@
+# Compile switches useful for testing
+#-D noVideo
+#-D noRandom
+#-D showCamSource
+#-D videoFeedback
+
+-swf flash/jigsawx_progressiveVideo.swf
+-swf-version 11
+-swf-header 500:500:30:0000000
+-main jigsawxtargets.hxflash.JigsawProgressiveVideo
+
+# useful if your on a mac
+-cmd open -a /Applications/chrome.app flash/jigsawx_progressiveVideo.swf
+
+--next
+
+# Compile switches useful for testing
+#-D noVideo
+#-D noRandom
+#-D showCamSource
+
+-swf flash/jigsawx_webCam.swf
+-swf-version 11
+-swf-header 500:500:30:0000000
+-main jigsawxtargets.hxflash.JigsawWebCam
+
+# Useful if your on a mac
+-cmd open -a /Applications/chrome.app flash/jigsawx_webCam.swf
\ No newline at end of file
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/compileJS.hxml b/projects/flixel-desktop-habit-puzzle-game/JigsawX/compileJS.hxml
new file mode 100644
index 00000000..cfab9916
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/compileJS.hxml
@@ -0,0 +1,11 @@
+# Test options
+-D noVideo
+#-D noRandom
+-cp divtastic
+-main jigsawxtargets.hxjs.JigsawDivtastic
+-js bin/jigsawdivtastic.js
+# this line excludes JQuery in haxe 2.08
+-D noEmbedJS
+-D haxe3
+# useful for mac users
+-cmd open -a /Applications/firefox.app bin/JigsawDivtastic.html
\ No newline at end of file
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/compileOpenfl.hxml b/projects/flixel-desktop-habit-puzzle-game/JigsawX/compileOpenfl.hxml
new file mode 100644
index 00000000..0e967e57
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/compileOpenfl.hxml
@@ -0,0 +1,18 @@
+
+#-cmd lime test windows
+#-cmd lime test windows -neko
+#-cmd lime test mac
+#--next
+-cmd haxelib run nme cpp -bin binNme
+#-cmd lime test mac -neko
+#-cmd lime test linux
+#-cmd lime test linux -neko
+#-cmd lime test ios
+#-cmd lime test ios -simulator
+#-cmd lime test android
+#-cmd lime test blackberry
+#-cmd lime test blackberry -simulator
+#-cmd lime test tizen
+#-cmd lime test tizen -simulator
+#-cmd lime test flash
+#-cmd lime test html5
\ No newline at end of file
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/compileSwing.hxml b/projects/flixel-desktop-habit-puzzle-game/JigsawX/compileSwing.hxml
new file mode 100644
index 00000000..ba93191e
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/compileSwing.hxml
@@ -0,0 +1,22 @@
+
+# Set this if you want to use Timer to control update
+-D update_task
+
+#
+-java java
+-main jigsawxtargets.hxjava.JigsawxJava
+#-resource tablecloth.jpg@tablecloth
+-D haxe3
+
+#
+--next
+-cmd cd java/src
+#-cmd javac jigsawxtargets/hxjava/JigsawxJava.java -d ../
+-cmd cd ..
+-cmd cd ..
+#-cmd java jigsawxtargets/hxjava/JigsawxJava
+#-cmd java -jar *.jar
+-cmd cp java/*.jar bin/
+-cmd rm -R java
+-cmd cd bin
+-cmd java -jar *.jar
\ No newline at end of file
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/compileWebkit.hxml b/projects/flixel-desktop-habit-puzzle-game/JigsawX/compileWebkit.hxml
new file mode 100644
index 00000000..c24786e2
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/compileWebkit.hxml
@@ -0,0 +1,17 @@
+# Test options
+-D noVideo
+#-D noRandom
+-cp divtastic
+-main jigsawxtargets.hxjs.JigsawDivtastic
+-js deploy/jigsawdivtastic.js
+# this line excludes JQuery in haxe 2.08
+-D noEmbedJS
+-D haxe3
+# useful for mac users
+--next
+# do by hand in the deploy directory
+# zip app.nw *
+# because this line is not working
+#-cmd zip -r deploy/app.nw deploy/jigsawDivtastic.html deploy/package.json deploy/tablecloth.jpg deploy/jigsawdivtastic.js
+--next
+-cmd open -n -a node-webkit "deploy/app.nw"
\ No newline at end of file
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/core/CSSenterFrame.hx b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/core/CSSenterFrame.hx
new file mode 100644
index 00000000..906d3e37
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/core/CSSenterFrame.hx
@@ -0,0 +1,31 @@
+//TODO: use htmlhelper
+package core;
+import js.html.Event;
+import js.Browser;
+import js.html.Element;
+import js.html.CSSStyleDeclaration;
+class CSSenterFrame
+{
+
+ var onEnterFrame: Void -> Void;
+
+ public function new( onEnterFrame_: Void->Void )
+ {
+ onEnterFrame = onEnterFrame_;
+ var s = Browser.document.createStyleElement();
+ s.innerHTML = "@keyframes spin { from { transform:rotate( 0deg ); } to { transform:rotate( 360deg ); } }";
+ Browser.document.getElementsByTagName("head")[0].appendChild( s );
+ //.addEventListener("animationiteration", onEnterFrame, false );
+ (cast s).animation = "spin 1s linear infinite";
+ loop( 60 );
+ }
+
+
+ private function loop( tim: Float ):Bool
+ {
+ Browser.window.requestAnimationFrame( loop );
+ onEnterFrame( );
+ return true;
+ }
+
+}
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/core/DisplayDiv.hx b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/core/DisplayDiv.hx
new file mode 100644
index 00000000..e8085f25
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/core/DisplayDiv.hx
@@ -0,0 +1,865 @@
+package core;
+
+import js.Lib;
+import core.ImageDiv;
+import core.GlobalDiv;
+import core.WebBrowser;
+import zpartanlite.DispatchTo;
+import js.html.Element;
+import js.html.DivElement;
+import js.html.CSSStyleSheet;
+import js.html.VideoElement;
+import js.html.Event;
+import js.html.HTMLDocument;
+import js.html.CanvasElement;
+import js.html.CanvasRenderingContext2D;
+import js.html.CSSStyleDeclaration;
+import js.html.MouseEvent;
+using core.GlobalDiv;
+class DisplayDiv
+{
+
+ private var isIE: Bool;
+ public var fixedTextWidth: Int;
+ public var fixedTextHeight: Int;
+
+
+ public var _d: Int;
+ public var _negd: Int;
+ public var _dom: Element;
+
+ private var _style: CSSStyleDeclaration;
+ private var _bgColor: String;
+ private var _img: String;
+ private var _tile: Bool;
+ private var offSetX: Int;
+ private var offSetY: Int;
+ private var imageDiv: ImageDiv;
+ private var viz: Bool;
+
+ private var _clientX: Float;
+ private var _clientY: Float;
+
+ public var press: DispatchTo;
+ public var release: DispatchTo;
+ public var out: DispatchTo;
+ public var over: DispatchTo;
+ public var dragging: DispatchTo;
+ public var draggingParent: DispatchTo;
+
+ public var _vid: VideoElement;
+ private var _src: String;
+ public var dragInform: Bool;
+
+ private var _scale: Float;
+ private var _scaleY: Float;
+ private var _scaleX: Float;
+ private var _alpha: Float;
+ private var _rotation: Float;
+ private var _angle: Int;
+ private var _y: Float;
+ private var _x: Float;
+ private var _width: Float;
+ private var _height: Float;
+ public var afflines: Array;
+
+
+
+ public function new( ?img: String )
+ {
+
+ if( isVideo( img ) )
+ {
+ _vid = ROOT().createVideoElement();
+ _dom = cast _vid;
+ }
+ else
+ {
+
+ if( img == 'canvas' )
+ {
+ _dom = ROOT().createCanvasElement();
+ }
+ else
+ {
+ _dom = ROOT().createDivElement();
+ }
+
+ }
+
+ _style = _dom.style;
+ isIE = ( WebBrowser.browserType == IE );
+
+ // sets up mouse signals and maps them so the dispatch.
+ out = new DispatchTo();
+ out.tellEnabled = outEnabled;
+ out.tellDisabled = outDisabled;
+
+ over = new DispatchTo();
+ over.tellEnabled = overEnabled;
+ over.tellDisabled = overDisabled;
+
+ release = new DispatchTo();
+ release.tellEnabled = releaseEnabled;
+ release.tellDisabled = releaseDisabled;
+
+ press = new DispatchTo();
+ press.tellEnabled = pressEnabled;
+ press.tellDisabled = pressDisabled;
+
+ dragging = new DispatchTo();
+ dragInform = false;
+
+ draggingParent = new DispatchTo();
+
+ set_tile( false );
+ if( img != null )
+ {
+ set_image( img );
+ }
+
+ _style.position = "absolute";
+
+ }
+
+
+ public function getGlobalMouseXY():List
+ {
+
+ var globalPos = getGlobalXY();
+ var pos = new List();
+ pos.add( globalPos.first() + _clientX );
+ pos.add( globalPos.last() + _clientY );
+ return pos;
+
+ }
+
+
+ //TODO: Take into account rotation and scale?
+ public function getGlobalXY():List
+ {
+ var p = this;
+ var gX = p.x;
+ var gY = p.y;
+
+ while( p.parent != null )
+ {
+ p = p.parent;
+ gX += p.x;
+ gY += p.y;
+ }
+ var pos: List = new List();
+ pos.add( gX );
+ pos.add( gY );
+ return pos;
+ }
+
+
+ private function pressEnabled()
+ {
+ _dom.onmousedown = function( e )
+ {
+ var em: MouseEvent = cast e;
+ _clientX = em.clientX;
+ _clientY = em.clientY;
+ press.dispatch();
+ };
+ }
+
+
+ private function pressDisabled()
+ {
+ _dom.onmousedown = null;
+ }
+
+
+ private function releaseEnabled()
+ {
+ _dom.onmouseup = function( e: Event )
+ {
+ var em: MouseEvent = cast e;
+ _clientX = em.clientX;
+ _clientY = em.clientY;
+ release.dispatch();
+ };
+ }
+
+
+ public function releaseDisabled()
+ {
+ _dom.onmouseup = null;
+ }
+
+
+ private function overEnabled()
+ {
+ _dom.onmouseover = function( e ){ over.dispatch(); };
+ }
+
+
+ private function overDisabled()
+ {
+ _dom.onmouseover = null;
+ }
+
+ private function outEnabled()
+ {
+ _dom.onmouseout = function( e ){ out.dispatch(); };
+ }
+
+ private function outDisabled()
+ {
+ _dom.onmouseout = null;
+ }
+
+
+ public function setupDrag()
+ {
+ _style.cursor = "pointer";
+ press.add( startDrag );
+ release.add( stopDrag );
+/*
+ ROOT().onmousedown = function( e )
+ {
+ stopDrag();
+ }
+*/
+ }
+
+ public function startDrag()
+ {
+ offSetX = Std.int( _clientX - x );
+ offSetY = Std.int( _clientY - y );
+ ROOT().onmousemove = drag;
+ }
+
+
+ public function stopDrag()
+ {
+ ROOT().onmousemove = null;
+ }
+
+
+ private function drag( e: Event )
+ {
+ if( dragInform ) dragging.dispatch();
+ var em: MouseEvent = cast e;
+ x = em.clientX - offSetX;
+ y = em.clientY - offSetY;
+ }
+
+
+ public function setupParentDrag()
+ {
+ var me = this;
+ _style.cursor = "pointer";
+ press.add( parentStartDrag );
+ release.add( parentStopDrag );
+ }
+
+
+ public function parentStartDrag()
+ {
+ offSetX = Std.int( _clientX - parent.x );
+ offSetY = Std.int( _clientY - parent.y );
+ ROOT().onmousemove = parentDrag;
+ }
+
+
+ public function parentStopDrag()
+ {
+ ROOT().onmousemove = null;
+ }
+
+
+ private function parentDrag( e: Event )
+ {
+ if( dragInform ) draggingParent.dispatch();
+ var em: MouseEvent = cast e;
+ parent.x = em.clientX - offSetX;
+ parent.y = em.clientY - offSetY;
+ }
+
+
+ public function play()
+ {
+ if( _vid != null ) _vid.play();
+ }
+
+
+ private function isVideo( img ): Bool
+ {
+
+ if( img == null ) return false;
+ var arr: Array = img.split('.');
+ if( arr.length == null ) return false;
+ var str: String = arr[ 1 ];
+ switch( str )
+ {
+ case 'ogv', 'mpeg', 'mov', 'mp4', 'webm':
+ videoType = 'video/'+str;
+ return true;
+ }
+ return false;
+
+ }
+ private var videoType: String;
+
+ public function set_image( img: String )
+ {
+
+ _img = img;
+
+ if ( isIE ) createImageDivIfNot();
+
+ if( img.split('.').length > 1 )
+ {
+ if ( isIE )
+ {
+ imageDiv.set_image( img );
+ }
+ else
+ {
+ if( _vid == null )
+ {
+ _style.backgroundImage = 'url(' + img +')';
+ }
+ else
+ {
+ _dom.setAttribute( 'src', img );
+ _dom.setAttribute( 'type', videoType );
+ }
+ }
+ }
+ else
+ {
+ if ( isIE )
+ {
+ imageDiv.set_image( img );
+ }
+ else
+ {
+ _dom.className = img ;
+ }
+ }
+ }
+
+
+ // for width and height to be adjustable ( tweenable ) you need to set this.
+ public function setClip()
+ {
+ _style.overflow = 'Hidden';
+ }
+
+
+ public var tile( get_tile, set_tile ):Bool;
+
+
+ private function get_tile():Bool
+ {
+ if( _tile == null )
+ {
+ set_tile( false ) ;
+ }
+ return _tile ;
+ }
+
+
+ private function set_tile( tile_: Bool ):Bool
+ {
+
+ _tile = tile_;
+
+ if ( isIE )
+ {
+ createImageDivIfNot();
+ }
+
+ if( _tile )
+ {
+ if ( isIE )
+ {
+ imageDiv.tile = true;
+ }
+ else
+ {
+ _style.backgroundRepeat = 'repeat';
+ }
+ }
+ else
+ {
+ if ( isIE )
+ {
+ imageDiv.tile = false;
+ }
+ else
+ {
+ _style.backgroundRepeat = 'no-repeat';
+ }
+ }
+ return tile_;
+ }
+
+
+ public function createImageDivIfNot(): ImageDiv
+ {
+ if( imageDiv == null )
+ {
+ imageDiv = new ImageDiv();
+ imageDiv.x = 0 ;
+ imageDiv.y = 0 ;
+ addChild2( imageDiv );
+ }
+ imageDiv.width = width ;
+ imageDiv.height = height ;
+ return imageDiv;
+ }
+
+
+ public function getInstance(): Element
+ {
+ return _dom;
+ }
+
+
+ public function getStyle(): CSSStyleDeclaration
+ {
+
+ return _style;
+
+ }
+
+
+ public var text( get_text, set_text ): String;
+
+ public function set_text( txt: String ): String
+ {
+
+ // TODO: look at this code not sure it is ideal but seems useful at moment.
+ _dom.innerHTML = '';
+ set_width( 0 );
+ set_height( 0 );
+ if( parent != null ) parent.updateSizeBasedOnChild( this );
+ _dom.innerHTML = txt;
+ // TODO: not ideal to have browser type in this class think about moving?
+ switch( WebBrowser.browserType )
+ {
+ case FireFox: untyped _style.MozUserSelect = 'none';
+ case WebKitOther, Safari, Chrome: untyped _style.webkitUserSelect = 'none';
+ case IE, Opera: untyped _style.unselectable = 'on';
+ }
+ set_width( _width );
+ set_height( _height );
+ if( parent != null ) parent.updateSizeBasedOnChild( this );
+ return txt;
+ }
+
+
+ public function updateText( txt: String )
+ {
+ _dom.innerHTML = '';
+ set_width( 0 );
+ set_height( 0 );
+ _dom.innerHTML = txt;
+ _style.width = Std.string( fixedTextWidth );
+ if( fixedTextHeight != null ) _style.height = Std.string( fixedTextHeight );
+ _style.overflow = 'Hidden';
+ }
+
+
+ public function get_text(): String
+ {
+ return _dom.innerHTML;
+ }
+
+
+ public var visible( get_visible, set_visible ): Bool;
+
+ public function set_visible( val: Bool ): Bool
+ {
+ //TODO: consider collapse
+ if( val )
+ {
+ _style.visibility = "visible";
+ }
+ else
+ {
+ _style.visibility = "hidden";
+ }
+ viz = val;
+ return viz;
+ }
+
+
+ public function get_visible(): Bool
+ {
+ if( viz == null ) viz = true;
+ return viz;
+ }
+
+
+ public var fill( get_fill, set_fill ): String;
+
+ public function set_fill( c: String ): String
+ {
+ if ( isIE )
+ {
+ createImageDivIfNot();
+ imageDiv.fill = c;
+ }
+ else
+ {
+ _style.backgroundColor = c;
+ }
+ _bgColor = c;
+ return c;
+ }
+
+
+ public function get_fill(): String
+ {
+ return _bgColor;
+ }
+
+
+ public function addChild( mc: DisplayDiv ): DisplayDiv
+ {
+ //trace( 'adding child ' + mc );
+ _dom.appendChild( mc.getInstance() );
+ //trace( mc.getInstance() );
+ mc.parent = this;
+ updateSizeBasedOnChild( mc );
+ mc.appended();
+ return mc;
+ //trace( 'new width ' + mc.width );
+ }
+
+
+ public function addChild2( mc: ImageDiv ): ImageDiv
+ {
+ _dom.appendChild( mc.getInstance() );
+ mc.parent = this;
+ updateSizeBasedOnChild2( mc );
+ mc.appended();
+ return mc;
+ }
+
+ public function appended()
+ {
+
+ }
+
+ public var _parent: DisplayDiv;
+ public var parent( get_parent, set_parent ): DisplayDiv;
+
+ public function set_parent( mc: DisplayDiv ): DisplayDiv
+ {
+ _parent = mc;
+ return mc;
+ }
+
+
+ public function get_parent(): DisplayDiv
+ {
+ return _parent;
+ }
+
+
+ public function updateSizeBasedOnChild2( mc: ImageDiv )
+ {
+ if( width < mc.width + mc.x ) set_width( mc.width + mc.x );
+ if( height < mc.height + mc.y ) set_height( mc.height + mc.y );
+ }
+
+ public function updateSizeBasedOnChild( mc: DisplayDiv )
+ {
+ if( width < mc.width + mc.x ) set_width( mc.width + mc.x );
+ if( height < mc.height + mc.y ) set_height( mc.height + mc.y );
+ }
+
+
+ public var height( get_height, set_height ): Float;
+ public function set_height( val: Float ): Float
+ {
+ _height = val;
+ if( _twoD == null )
+ {
+ _style.paddingTop = val + "px";
+ }
+ else
+ {
+ _style.paddingTop = "0px";
+ }
+ return val;
+ }
+
+ public function get_height(): Float
+ {
+ if( _height == null || _height < _dom.clientHeight )
+ {
+ _height = _dom.clientHeight;
+ }
+ return _height;
+ }
+
+ public var width( get_width, set_width ): Float;
+ public function set_width( val: Float ): Float
+ {
+ _width = val;
+ if( _twoD == null )
+ {
+ _style.paddingLeft = val + "px";
+ }
+ else
+ {
+ _style.paddingLeft = "0px";
+ }
+ return val;
+ }
+
+ private function get_width(): Float
+ {
+ if( _width == null || _width < _dom.clientWidth )
+ {
+ _width = _dom.clientWidth;
+ }
+ return _width;
+ }
+
+ public var y( get_y, set_y ): Float;
+
+ private function set_y( val: Float ): Float
+ {
+ _y = val;
+ _style.top = val + "px";
+ return val;
+ }
+
+ private function get_y(): Float
+ {
+ return _y;
+ }
+
+
+ public var x( get_x, set_x ): Float;
+
+ private function set_x( val: Float ): Float
+ {
+ _x = val;
+ _style.left = val + "px";
+ return val;
+ }
+
+ private function get_x(): Float
+ {
+ return _x;
+ }
+
+
+ private var _canvas: CanvasElement;
+ private var _twoD: CanvasRenderingContext2D;
+
+ public var twoD( get_twoD, null ): CanvasRenderingContext2D;
+
+ private function get_twoD(): CanvasRenderingContext2D
+ {
+ if( _canvas == null ) _canvas = cast _dom;
+ if( _twoD == null ) _twoD = _canvas.getContext2d();
+ return _twoD;
+ }
+
+ public var scale( get_scale, set_scale ): Float;
+
+ private function get_scale( ):Float
+ {
+ if( _scale == null )
+ {
+ _scale = 1;
+ _scaleX = 1;
+ _scaleY = 1;
+ }
+ return _scale;
+ }
+
+ private function set_scale( scale_: Float ): Float
+ {
+ var scaleStr = Std.string( scale_ );
+ var str = "scale("+ scaleStr + ', ' + scaleStr + ")";
+ switch( WebBrowser.browserType )
+ {
+ case WebKitOther, Safari, Chrome: untyped _style.WebkitTransform = str;
+ case Opera: untyped _style.OTransform = str;
+ case FireFox: untyped _style.MozTransform = str;
+ case IE: affineTrans( scale_, 0, 0, scale_, 0, 0 ) ;
+ }
+ _scale = scale_;
+ _scaleX = scale_;
+ _scaleY = scale_;
+ return _scale;
+ }
+
+
+ public var scaleY( get_scaleY, set_scaleY ): Float;
+
+ private function get_scaleY( ):Float
+ {
+ if( _scaleY == null ) _scaleY = 1;
+ return _scaleY;
+ }
+
+ private function set_scaleY( scaleY_: Float ): Float
+ {
+ switch( WebBrowser.browserType )
+ {
+ case WebKitOther, Chrome, Safari: untyped _style.WebkitTransform = "scaleY("+ Std.string( scaleY_ ) + ")";
+ case Opera: untyped _style.OTransform = "scaleY("+ Std.string( scaleY_ ) + ")";
+ case FireFox: untyped _style.MozTransform = "scaleY("+ Std.string( scaleY_ ) + ")";
+ case IE: affineTrans( scaleX, 0, 0, scaleY_, 0, 0 ) ;
+ }
+ _scaleY = scaleY_;
+ return _scaleY;
+ }
+
+
+
+ public var scaleX( get_scaleX, set_scaleX ): Float;
+
+ private function get_scaleX( ):Float
+ {
+ if( _scaleX == null ) _scaleX = 1;
+ return _scaleX;
+ }
+
+ private function set_scaleX( scaleX_: Float ): Float
+ {
+ // a and d
+ switch( WebBrowser.browserType )
+ {
+ case WebKitOther, Safari, Chrome: untyped _style.WebkitTransform = "scaleX("+ Std.string( scaleX_ ) + ")";
+ case Opera: untyped _style.OTransform = "scaleX("+ Std.string( scaleX_ ) + ")";
+ case FireFox: untyped _style.MozTransform = "scaleX("+ Std.string( scaleX_ ) + ")";
+ case IE: affineTrans( scaleX_, 0, 0, scaleY, 0, 0 ) ;
+ }
+ _scaleX = scaleX_;
+ return _scaleX;
+ }
+
+
+ /*
+
+ http://c2.com/cgi/wiki?AffineTransformation
+
+ xnew = a*x + c*y + e
+ ynew = b*x + d*y + f
+
+ */
+ public function affineTrans( a: Float, b: Float, c: Float, d: Float, e: Float, f: Float )
+ {
+ afflines = [a,b,c,d,e,f];
+ var mat0 = 'matrix( '+ Std.string( a ) + ', ' + Std.string( b ) + ', ' + Std.string( c ) + ', ' + Std.string( d ) + ', ' ;
+ var matrixFirefox = mat0 + Std.string( e ) + 'px, ' + Std.string( e ) + 'px ) ';
+ var matrixGeneral = mat0 + Std.string( e ) + Std.string( e ) + ' ) ';
+ switch( WebBrowser.browserType )
+ {
+
+ case WebKitOther, Chrome, Safari: untyped _style.WebkitTransform = matrixGeneral;
+ case Opera: untyped _style.OTransform = matrixGeneral;
+ case FireFox: untyped _style.MozTransform = matrixFirefox ;
+ case IE: affineTransIE( a, b, c, d, e, f );
+
+ }
+
+
+ }
+
+
+ // credit to http://extremelysatisfactorytotalitarianism.com/blog/?p=922 for code ( I am on a mac so untested! )
+ private function affineTransIE( a: Float, b: Float, c: Float, d: Float, e: Float, f: Float )
+ {
+
+ // set linear transformation via Matrix Filter
+ untyped _style.filter = 'progid:DXImageTransform.Microsoft.Matrix(M11=' + a + ', M21=' + b + ', M12=' + c + ', M22=' + d + ', SizingMethod="auto expand")';
+ var w2 = width/2;//style.offsetWidth
+ var h2 = height/2;//offsetHeight?
+ x = Math.round( x + e - ( Math.abs(a) - 1)*w2 + Math.abs(c)*h2 ) ;
+ y = Math.round( y + f - Math.abs(b)*w2 + (Math.abs(d) - 1)*h2 ) ;
+
+ }
+
+
+ public var rotation( get_rotation, set_rotation ): Float;
+
+ /*
+ xnew = a*x + c*y + e
+ ynew = b*x + d*y + f
+ xnew = cos(r)*x - sin(r)*y + e
+ ynew = sin(r)*x + cos(r)*y + f
+ */
+ public function set_rotation( angle: Float ): Float
+ {
+
+ _rotation = angle;
+
+ //if( _angle != Std.int( angle ) )
+ //{
+ _angle = Std.int( angle );
+ var rad = _rotation*(Math.PI/180);
+ var cos = Math.cos( rad );
+ var sin = Math.sin( rad );
+
+ switch( WebBrowser.browserType )
+ {
+ case WebKitOther, Safari, Chrome: untyped _style.WebkitTransform = "rotate("+ Std.string( _angle ) + "deg)";
+ case Opera: untyped _style.OTransform = "rotate("+ Std.string( _angle ) + "deg)";
+ case FireFox: untyped _style.MozTransform = "rotate("+ Std.string( _angle ) + "deg)";
+ case IE: affineTrans( cos, -sin, sin, cos, 0, 0 );
+ //case IE: untyped _style.filter = "progid:DXImageTransform.Microsoft.BasicImage(rotation=" + _angle + ")";
+ }
+
+ //}
+
+ return angle;
+
+ }
+
+
+ public function get_rotation( ): Float
+ {
+ if( _rotation == null )
+ {
+ _rotation = 0;
+ _angle = 0;
+ }
+ return _rotation;
+ }
+
+
+ public var alpha( get_alpha, set_alpha ): Float;
+
+ public function get_alpha(): Float
+ {
+ if( _alpha == null ) _alpha = 1;
+ return _alpha;
+ }
+
+ public function set_alpha( alpha_: Float ): Float
+ {
+ switch( WebBrowser.browserType )
+ {
+ case FireFox, Opera, WebKitOther, Chrome, Safari: untyped _style.opacity = alpha_ ;
+ case IE: untyped _style.filter = 'alpha(opacity=' + Std.String( Math.round( alpha_*10 ) ) + ')';
+ /*
+ case IE:
+ var val = 'alpha(opacity' + Std.string( Math.round( alpha_ * 10 ) ) + ')';
+ untyped _style.filter = val;
+
+ untyped _dom.filters.item("progid:DXImageTransform.Microsoft.Alpha").opacity = Std.String( Math.round(alpha_ * 10) );
+ untyped _style.-ms-filter = 'progid:DXImageTransform.Microsoft.Alpha(opacity=' + Std.String( Math.round(alpha_*10) ) + ')';
+ untyped _style.filter = 'alpha(opacity=' + Std.String( alpha_*10 ) + ')';
+ */
+ }
+ _alpha = alpha_;
+ return _alpha;
+ }
+
+}
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/core/DivDrawing.hx b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/core/DivDrawing.hx
new file mode 100644
index 00000000..1ee72b32
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/core/DivDrawing.hx
@@ -0,0 +1,614 @@
+package core;
+import js.html.Element;
+import js.html.DivElement;
+import js.html.CSSStyleDeclaration;
+import js.Browser;
+import core.DivDrawing;
+import zpartanlite.Enumerables;
+/*
+//TODO: change some code to use this
+enum Compass
+{
+ North;
+ South;
+ East;
+ West;
+}
+
+enum Orientation
+{
+ Horizontal;
+ Vertical;
+}
+*/
+using core.DivDrawing;
+class DivDrawing
+{
+
+ public static function curveFromTo ( ddiv: DisplayDiv
+ , p1x: Float
+ , p1y: Float
+ , p2x: Float
+ , p2y: Float
+ , p3x: Float
+ , p3y: Float
+ , _lineWidth: Int
+ , _lineHeight: Int
+ , ?c0: String = '#ff0000'
+ ): List
+ {
+ //Credits for info PIXELWIT see: http://www.pixelwit.com/blog/2007/11/curveto-visualization/
+ var p12x: Float;
+ var p12y: Float;
+ var p23x: Float;
+ var p23y: Float;
+ var p123x: Int;
+ var p123y: Int;
+ var ratio: Float = 0;
+ var _points = new List>();
+ var _grads = new List();
+ var __curve: DivElement;
+ var __point: List;
+ var __style: CSSStyleDeclaration;
+ var steps: Int = 2*Math.ceil( Math.pow( Math.pow( p1x - p3x, 2) + Math.pow( p1y - p3y, 2), 0.5 ) );
+
+ var inter = new IntIterator( 0, steps );
+ var i: Int;
+
+ for( i in inter )
+ {
+
+ __point = new List();
+ ratio = i/steps;
+ p12x = p1x + ( p2x - p1x )*ratio;
+ p23x = p2x + ( p3x - p2x )*ratio;
+ p123x = Std.int( p12x + ( p23x - p12x )*ratio );
+ p12y = p1y + ( p2y - p1y )*ratio;
+ p23y = p2y + ( p3y - p2y )*ratio;
+ p123y = Std.int( p12y + ( p23y - p12y )*ratio );
+
+ __curve = Browser.document.createDivElement(); //Element( 'div' );//+ ddiv._d++
+ _grads.push( __curve );
+ __point.add( p123x );
+ __point.add( p123y );
+ _points.add( __point );
+
+ __style = __curve.style;
+ __style.paddingTop = _lineHeight + 'px';
+ __style.paddingLeft = _lineWidth + 'px';
+ __style.top = p123y + 'px';
+ __style.left = p123x + 'px';
+
+ __style.backgroundColor = c0;
+ __style.position = 'absolute';
+
+ ddiv._dom.appendChild( __curve );
+
+
+ }
+
+
+ // TODO: REMOVE EXTRA POINTS
+ var _points2 = new List>();
+ var old: Int = 10000;
+
+ for( i in _points.iterator() )
+ {
+
+ if( i.last() != old )
+ {
+
+ _points2.add(i);
+
+ }
+
+ old = i.last();
+
+ }
+
+
+ //return _points2;
+ return _grads;
+ //Need to add clever code to only create on new points (maybe have a lookup of previous points)
+ //Need current pen?
+ }
+
+
+ // Maybe not best way!!
+ public static function drawElipse( ddiv: DisplayDiv,
+ cx: Float,
+ cy: Float,
+ rx: Float,
+ ry: Float,
+ _lineWidth: Int,
+ _lineHeight: Int
+ ): Array>
+ {
+
+ var px: Float;
+ var py: Float;
+ var theta: Float = ( 2*Math.PI ) /8;
+ var points = new Array>();
+
+ var iterPoints = new IntIterator( 0, 9 );
+
+ for( i in iterPoints )
+ {
+
+ var point = new List();
+
+ point.add( cx + rx*Math.sin( theta*i ));
+ point.add( cy + ry*Math.cos( theta*i ));
+ points[ i ] = point;
+
+ }
+
+ var j: Int = 0;
+ while( j < 8 )
+ {
+
+ ddiv.curveThru(
+ points[ j ].first(), points[ j ].last(),
+ points[ j + 1 ].first(), points[ j + 1 ].last(),
+ points[ j + 2 ].first(), points[ j + 2 ].last(),
+ _lineWidth, _lineHeight
+ );
+
+ j += 2;
+
+ }
+
+ return points;
+
+ }
+
+
+ public static function drawGradient( ddiv: DisplayDiv,
+ x0: Int,
+ y0: Int,
+ w0: Int,
+ h0: Int,
+ c1_: Int,
+ c0_: Int,
+ ?_minPixel: Int = 1,
+ ?direction: Orientation = null
+ ): List
+ {
+
+ var _tot: Int;
+ var _grads = new List();
+ var __grad: DivElement;
+ var __style: CSSStyleDeclaration;
+
+ //var point = drawElipse( x0 + w0/2, y0 + h0/2, w0/2, h0/2, 1 ,1 );
+
+ if( direction == Horizontal )
+ {
+ _tot = Std.int( Math.floor( w0/_minPixel ) );
+ var iter = new IntIterator( 0, _tot );
+
+ for( i in iter)
+ {
+ __grad = Browser.document.createDivElement(); //Element( 'div' );//+ ddiv._d++
+ _grads.add( __grad );
+ __style = __grad.style;
+ __style.height = h0 + 'px';//__style.paddingTop
+ __style.width = _minPixel + 'px';//__style.paddingLeft
+ __style.top = y0 + 'px';
+ __style.left = (x0 + _minPixel*i) + 'px';
+ __style.position = 'absolute';
+
+ ddiv._dom.appendChild( __grad );
+
+ }
+
+ }
+ else
+ {
+
+ _tot = Std.int( Math.floor( h0/_minPixel ) );
+ var iter = new IntIterator( 0, _tot );
+
+ for( i in iter)
+ {
+ __grad = Browser.document.createDivElement(); //Element( 'div' );//+ ddiv._d++
+ _grads.add( __grad );
+ __style = __grad.style;
+ __style.height = _minPixel +'px';
+ __style.width = w0 + 'px';
+ __style.top = ( y0 + _minPixel*i ) + 'px';
+ __style.left = x0 +'px';
+ __style.position = 'absolute';
+
+ ddiv._dom.appendChild( __grad );
+
+ }
+
+ }
+
+ var gradfill = new GradientFiller( _grads );
+ gradfill.fill( c0_, c1_ );
+ return _grads;
+
+ }
+
+
+ public static function drawGradElipse( ddiv: DisplayDiv,
+ x0: Int,
+ y0: Int,
+ w0: Int,
+ h0: Int,
+ c1_: Int,
+ c0_: Int,
+ ?_minPixel: Int = 1,
+ ?direction: Orientation = null
+ ): List
+ {
+
+ var _tot: Int;
+ var _grads = new List();
+ var __grad: DivElement;
+ var __style: CSSStyleDeclaration;
+
+ // Elipse Equations
+ // x2/a2 + y2/b2 = 1;
+ // so...
+ // y2 = b2( 1 - x2/a2 )
+
+ var rx0 = w0/2;
+ //var a2 = Math.pow( rx0, 2 );
+ var ry0 = h0/2;
+ //var b2 = Math.pow( ry0, 2 );
+ var cx0 = x0 + rx0;
+ var cy0 = y0 + ry0;
+
+ var delta: Float;
+
+
+ //trace( 'direction ' + direction ) ;
+ if( direction == Horizontal )
+ {
+ //trace('horizontal') ;
+
+ _tot = Std.int( Math.floor( w0/_minPixel ) );
+ var iter = new IntIterator( 0, _tot );
+
+ for( i in iter)
+ {
+ __grad = Browser.document.createDivElement();//( 'div' );//+ ddiv._d++
+ _grads.add( __grad );
+ __style = __grad.style;
+ __style.width = _minPixel + 'px';//__style.paddingLeft
+ delta = Math.pow( Math.pow( ry0, 2 )*( 1 - Math.pow( i - rx0 , 2 )/Math.pow( rx0, 2 ) ), 0.5 );
+ __style.top = Std.string( ( cy0 - delta) )+ 'px';
+ __style.height = Std.string( ( 2*delta) )+ 'px';
+ __style.left = (x0 + _minPixel*i) + 'px';
+ __style.position = 'absolute';
+
+ ddiv._dom.appendChild( __grad );
+
+ }
+
+ }
+ else
+ {
+ _tot = Std.int( Math.floor( h0/_minPixel ) );
+ var iter = new IntIterator( 0, _tot );
+
+ for( i in iter)
+ {
+ __grad = Browser.document.createDivElement(); //( 'div' );//+ ddiv._d++
+ _grads.add( __grad );
+ __style = __grad.style;
+ __style.height = _minPixel + 'px';
+ delta = Math.pow( Math.pow( rx0, 2 )*( 1 - Math.pow( i - ry0 , 2 )/Math.pow( ry0, 2 ) ), 0.5 );
+ __style.left = Std.string( ( cx0 - delta) )+ 'px';
+ __style.width = Std.string( ( 2*delta) )+ 'px';
+ __style.top = (y0 + _minPixel*i) + 'px';
+ __style.position = 'absolute';
+
+ ddiv._dom.appendChild( __grad );
+
+ }
+ }
+
+ var gradfill = new GradientFiller( _grads );
+ gradfill.fill( c0_, c1_ );
+ return _grads;
+
+ }
+
+
+
+ public static function drawGradHexagon( ddiv: DisplayDiv,
+ x0: Int,
+ y0: Int,
+ w0: Int,
+ h0: Int,
+ c1_: Int,
+ c0_: Int,
+ ?_minPixel: Int = 1,
+ ?direction: Orientation = null
+ ): List
+ {
+ var _tot: Int;
+ var _grads = new List();
+ var __grad: DivElement;
+ var __style: CSSStyleDeclaration;
+
+ //trace( 'direction ' + direction ) ;
+ if( direction == Horizontal )
+ {
+
+ _tot = Std.int( Math.floor( w0/_minPixel ) );
+ var iter = new IntIterator( 0, _tot );
+ var deg30 = Math.PI/6;
+
+ var smallTriBase = h0/2;
+ var smallHypot = smallTriBase/Math.cos(deg30);
+ var leftDist = smallHypot*Math.sin(deg30);
+ // side length = smallHypot
+ var rightDist = _tot - leftDist;
+
+ for( i in iter)
+ {
+ __grad = Browser.document.createDivElement();//( 'div' );//+ ddiv._d++
+ _grads.add( __grad );
+ __style = __grad.style;
+ __style.width = _minPixel + 'px';//__style.paddingLeft
+
+ if( i < leftDist )
+ {
+ //leftside
+ __style.height = Math.floor((h0/leftDist)*(i)) + 'px';
+ __style.top = y0 + h0/2 - Math.floor((h0/leftDist)*i/2)+'px';
+ }
+ else if( i > rightDist )
+ {
+ __style.height = Math.floor((h0/leftDist)*(leftDist + rightDist - i )) + 'px';
+ __style.top = y0 - Math.floor((h0/leftDist)*(rightDist-i)/2)+'px';
+ }
+ else
+ {
+ __style.height = cast h0 + 'px';
+ __style.top = cast y0 + 'px';
+ }
+
+
+ //__style.top = y0 + 'px';
+
+ __style.left = (x0 + _minPixel*i) + 'px';
+ __style.position = 'absolute';
+
+ ddiv._dom.appendChild( __grad );
+
+ }
+
+ }
+ else
+ {
+
+ _tot = Std.int( Math.floor( h0/_minPixel ) );
+ var iter = new IntIterator( 0, _tot );
+
+ for( i in iter)
+ {
+ __grad = Browser.document.createDivElement(); //( 'div' );//+ ddiv._d++
+ _grads.add( __grad );
+ __style = __grad.style;
+ __style.height = _minPixel +'px';
+
+ __style.top = ( y0 + _minPixel*i ) + 'px';
+ if( i > _tot/2 )
+ {
+ //draw bottom half
+ __style.width = Math.floor((w0/_tot)*(_tot-i+_tot/2)) + 'px';
+ __style.left = (x0 + w0/2 - Math.floor((w0/_tot)*(_tot-i+_tot/2)/2))+'px';
+ }
+ else
+ {
+ //draw top half
+ __style.width = Math.floor((w0/_tot)*(i+_tot/2)) + 'px';
+ __style.left = (x0 + w0/2 - Math.floor( (w0/_tot)*(i+_tot/2)/2 ))+'px';
+ }
+
+ __style.position = 'absolute';
+
+ ddiv._dom.appendChild( __grad );
+
+ }
+
+ }
+
+ var gradfill = new GradientFiller( _grads );
+ gradfill.fill( c0_, c1_ );
+ return _grads;
+
+ }
+
+
+ public static function drawGradTriangle( ddiv: DisplayDiv,
+ x0: Int,
+ y0: Int,
+ w0: Int,
+ h0: Int,
+ c1_: Int,
+ c0_: Int,
+ ?_compass: Compass = null,
+ ?_minPixel: Int = 1,
+ ?direction: Orientation = null
+ ): List
+ {
+ // add code for direction
+ var _tot: Int;
+ var _grads = new List();
+ var __grad: DivElement;
+ var __style: CSSStyleDeclaration;
+
+ if( direction == Horizontal )
+ {
+ //trace('horizontal') ;
+ _tot = Std.int( Math.floor( w0/_minPixel ) );
+ var iter = new IntIterator( 0, _tot );
+
+ for( i in iter)
+ {
+ __grad = Browser.document.createDivElement(); //Element( 'div' );//+ ddiv._d++
+ _grads.add( __grad );
+ __style = __grad.style;
+ //__style.height = h0 + 'px';//__style.paddingTop
+ __style.width = _minPixel + 'px';//__style.paddingLeft
+ if( _compass == West )
+ {
+ __style.height = Math.floor((h0/_tot)*(_tot-i)) + 'px';
+ __style.top = (y0 + h0/2 - Math.floor((h0/_tot)*(_tot-i))/2)+'px';
+ }
+ else
+ {
+ __style.height = Math.floor((h0/_tot)*i) + 'px';
+ __style.top = (y0 + h0/2 - Math.floor((h0/_tot)*i)/2)+'px';
+ }
+ /*
+
+
+ __style.top = y0 + 'px';
+ */
+ __style.left = (x0 + _minPixel*i) + 'px';
+ __style.position = 'absolute';
+
+ ddiv._dom.appendChild( __grad );
+
+ }
+
+ }
+ else
+ {
+
+ _tot = Std.int( Math.floor( h0/_minPixel ) );
+ var iter = new IntIterator( 0, _tot );
+
+ for( i in iter)
+ {
+ __grad = Browser.document.createDivElement(); //Element( 'div' );//+ ddiv._d++
+ _grads.add( __grad );
+ __style = __grad.style;
+ __style.height = _minPixel +'px';
+
+ __style.top = ( y0 + _minPixel*i ) + 'px';
+ if( _compass == South )
+ {
+ __style.width = Math.floor((w0/_tot)*(_tot-i)) + 'px';
+ __style.left = (x0 + w0/2 - Math.floor((w0/_tot)*(_tot-i))/2)+'px';
+ }
+ else
+ {
+ __style.width = Math.floor((w0/_tot)*i) + 'px';
+ __style.left = (x0 + w0/2 - Math.floor((w0/_tot)*i)/2)+'px';
+ }
+
+ __style.position = 'absolute';
+
+ ddiv._dom.appendChild( __grad );
+
+ }
+
+ }
+
+ var gradfill = new GradientFiller( _grads );
+ gradfill.fill( c0_, c1_ );
+ return _grads;
+ }
+
+
+ public static function lineFromTo( ddiv: DisplayDiv,
+ p1x: Float,
+ p1y: Float,
+ p2x: Float,
+ p2y: Float,
+ _lineWidth: Int,
+ _lineHeight: Int,
+ ?c0: String = '#ff0000'
+ ): List
+ {
+
+ var _grads = new List();
+ var __grad: DivElement;
+ var __style: CSSStyleDeclaration;
+ var ratio: Float;
+
+ if( p1x - p2x == 0 )
+ {
+
+ var steps: Int = 2*Math.ceil(Math.abs(p1y - p2y));
+
+ }
+ else if( p1y - p2y == 0 )
+ {
+
+ var steps: Int = 2*Math.ceil(Math.abs(p1x - p2x));
+
+ }
+
+ var steps: Int = Math.ceil( Math.pow( Math.pow( p1x - p2x, 2 ) + Math.pow( p1y - p2y, 2 ), 0.5 ) );
+ var px: Int;
+ var py: Int;
+
+ var inter = new IntIterator( 0, steps );
+ for( i in inter )
+ {
+ ratio = i/steps;
+ px = Std.int(p1x + ( p2x - p1x )*ratio );
+ py = Std.int(p1y + ( p2y - p1y )*ratio );
+ __grad = Browser.document.createDivElement(); //createElement( 'div' );//+ ddiv._d++
+
+ _grads.add( __grad );
+
+ __style = __grad.style;
+ __style.paddingTop = _lineHeight + 'px';
+ __style.paddingLeft = _lineWidth + 'px';
+ __style.top = py + 'px';
+ __style.left = px + 'px';
+ __style.backgroundColor = c0;
+ __style.position = 'absolute';
+
+ ddiv._dom.appendChild( __grad );
+
+ }
+ return _grads;
+
+ }
+
+
+
+
+ public static function curveThru( ddiv: DisplayDiv
+ , p1x: Float
+ , p1y: Float
+ , p2x: Float
+ , p2y: Float
+ , p3x: Float
+ , p3y: Float
+ , _lineWidth: Int
+ , _lineHeight: Int
+ , ?c0: String
+ ): List
+ {
+
+ var newx: Float = ( ( 2*p2x ) - .5*( p1x + p3x ) );
+ var newy: Float = ( ( 2*p2y ) - .5*( p1y + p3y ) );
+
+ return ddiv.curveFromTo(
+ p1x,
+ p1y,
+ newx,
+ newy,
+ p3x,
+ p3y,
+ _lineWidth,
+ _lineHeight,
+ c0
+ );
+
+ }
+
+}
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/core/GlobalDiv.hx b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/core/GlobalDiv.hx
new file mode 100644
index 00000000..b8e27b41
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/core/GlobalDiv.hx
@@ -0,0 +1,39 @@
+package core;
+import js.Lib;
+import js.Browser;
+import core.DisplayDiv;
+import js.html.HTMLDocument;
+class GlobalDiv{
+ public static var _root: HTMLDocument = Browser.document;
+ public static function ROOT( d: Dynamic ){
+ return _root;
+
+ }
+
+
+ public static function addChild( d: Dynamic, mc: DisplayDiv ):Void
+ {
+
+ _root.body.appendChild( mc.getInstance() );
+
+ }
+
+/*
+ public static function add( div: DisplayDiv, content: String ): DisplayDiv
+ {
+
+ var child = new DisplayDiv( content );
+
+ child.fill = '#ffffff';
+ child.x = 0;
+ child.y = 0;
+ child.width = 0;
+ child.height = 0;
+ child.getStyle().position = 'absolute';
+ div.addChild( child );
+
+ return child;
+
+ }*/
+
+}
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/core/GradientFiller.hx b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/core/GradientFiller.hx
new file mode 100644
index 00000000..f5f742f2
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/core/GradientFiller.hx
@@ -0,0 +1,79 @@
+package core;
+import js.html.DivElement;
+import js.html.CSSStyleDeclaration;
+class GradientFiller
+{
+
+ private var _grads: List;
+ private var _tot: Int;
+ private var _c0: Int;
+ private var _c1: Int;
+ private var _c0r: Int;
+ private var _c0g: Int;
+ private var _c0b: Int;
+ private var _c1r: Int;
+ private var _c1g: Int;
+ private var _c1b: Int;
+
+ public function setGrads( grads_: List )
+ {
+
+ _grads = grads_;
+ _tot = _grads.length;
+
+ }
+
+ public function new( ?grads_: List )
+ {
+ if( grads_ != null )
+ {
+ _grads = grads_;
+ _tot = _grads.length;
+ }
+ }
+
+
+ public function fill( c0_: Int, ?c1_: Int )
+ {
+ if( c1_ != null && c0_ != c1_ )
+ {
+ _c0 = c0_;
+ _c1 = c1_;
+ _c0r = ( _c0 >> 16);
+ _c0g = ( _c0 >> 8 & 0xff);
+ _c0b = ( _c0 & 0xff );
+ _c1r = ( _c1 >> 16);
+ _c1g = ( _c1 >> 8 & 0xff);
+ _c1b = ( _c1 & 0xff );
+
+ var newInt: List = Lambda.mapi( _grads, colorMap );
+
+ }
+ else
+ {
+
+ Lambda.map( _grads,
+ function( div: DivElement )
+ {
+ div.style.backgroundColor = '#' + StringTools.lpad( StringTools.hex( (c0_ >> 16) << 16 | ( c0_ >> 8 & 0xff) << 8 | ( c0_ & 0xff ) ), '0', 6 );
+ }
+ );
+
+ }
+
+ }
+
+
+ private function colorMap( i:Int, grad: DivElement ):DivElement
+ {
+
+ var t: Float = i*1/_tot;
+ var __style: CSSStyleDeclaration = grad.style;
+
+ __style.backgroundColor = '#' + StringTools.lpad( StringTools.hex( cast(_c0r+(_c1r-_c0r)*t) << 16 | cast(_c0g+(_c1g-_c0g)*t) << 8 | cast(_c0b+(_c1b-_c0b)*t) ), '0', 6 );
+
+ return grad;
+
+ }
+
+}
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/core/ImageDiv.hx b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/core/ImageDiv.hx
new file mode 100644
index 00000000..a05a8e67
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/core/ImageDiv.hx
@@ -0,0 +1,314 @@
+package core;
+
+// Used by internet explorer for displaying.
+
+
+import js.Lib;
+import js.html.Element;
+import js.html.CSSStyleDeclaration;
+using core.GlobalDiv;
+class ImageDiv
+{
+
+ public var fixedTextWidth: Int;
+ public var fixedTextHeight: Int;
+
+ // TODO: possibly remove
+ public var _d: Int;
+
+ // TODO: Check if this should be public?
+ public var _dom: Element;
+
+ private var _y: Float;
+ private var _x: Float;
+ private var _width: Float;
+ private var _height: Float;
+ private var _style: CSSStyleDeclaration;
+ private var _bgColor: String;
+ private var _img: String;
+ private var _tile: Bool;
+ private var offSetX: Int;
+ private var offSetY: Int;
+ private var viz: Bool;
+
+ // NOTE: Divtastic properties here so we can take them into account in getGlobalXY etc...
+
+ private var _scale: Float;
+ private var _scaleY: Float;
+ private var _scaleX: Float;
+ private var _alpha: Float;
+ private var _rotation: Float;
+ private var _angle: Int;
+
+ // NOTE: Not currently used possibly store affines when tested more.
+ public var afflines: Array;
+
+
+ public function new( ?img: String )
+ {
+ trace('imageDiv');
+ _dom = ROOT().createElement( "div" );
+ _style = _dom.style;
+
+ set_tile( false );
+ if( img != null )
+ {
+
+ set_image( img );
+
+ }
+
+ _style.position = "absolute";
+ _d = 0;
+
+ }
+
+
+ public function set_image( img: String )
+ {
+
+ _img = img;
+
+ if( img.split('.').length > 1 )
+ {
+
+ //trace('setting image to ' + img );
+ _style.backgroundImage = 'url(' + img +')';
+
+ }
+ else
+ {
+
+ _dom.className = img ;
+
+ }
+
+ }
+
+
+ public function appended()
+ {
+
+
+
+ }
+
+
+ // for width and height to be adjustable ( tweenable ) you need to set this.
+ public function setClip()
+ {
+
+ _style.overflow = 'Hidden';
+
+ }
+
+
+ public var tile( get_tile, set_tile ):Bool;
+
+
+ private function get_tile():Bool
+ {
+
+ if( _tile == null )
+ {
+
+ set_tile( false ) ;
+
+ }
+ return _tile ;
+
+ }
+
+
+ private function set_tile( tile_: Bool ):Bool
+ {
+
+ _tile = tile_;
+ if( _tile )
+ {
+
+ _style.backgroundRepeat = 'repeat';
+
+ }
+ else
+ {
+
+ _style.backgroundRepeat = 'no-repeat';
+
+ }
+ return tile_;
+
+ }
+
+
+ public function getInstance(): Element
+ {
+
+ return _dom;
+
+ }
+
+
+ public function getStyle(): CSSStyleDeclaration
+ {
+
+ return _style;
+
+ }
+
+
+ public var visible( get_visible, set_visible ): Bool;
+
+ public function set_visible( val: Bool ): Bool
+ {
+
+ //TODO: consider collapse
+
+ if( val )
+ {
+
+ _style.visibility = "visible";
+
+ }
+ else
+ {
+
+ _style.visibility = "hidden";
+
+ }
+
+ viz = val;
+
+ return viz;
+
+ }
+
+
+ public function get_visible(): Bool
+ {
+
+ if( viz == null )
+ {
+
+ viz = true;
+
+ }
+
+ return viz;
+
+ }
+
+
+ public var fill( get_fill, set_fill ): String;
+
+ public function set_fill( c: String ): String
+ {
+
+ _bgColor = c;
+ _style.backgroundColor = c;
+ return c;
+
+ }
+
+
+ public function get_fill(): String
+ {
+
+ return _bgColor;
+
+ }
+
+
+ public var height( get_height, set_height ): Float;
+ public function set_height( val: Float ): Float
+ {
+
+ _height = val;
+ _style.paddingTop = val + "px";
+ return val;
+
+ }
+ public function get_height(): Float
+ {
+
+ if( _height == null || _height < _dom.clientHeight )
+ {
+ _height = _dom.clientHeight;
+ }
+ return _height;
+
+ }
+
+
+ public var width( get_width, set_width ): Float;
+ public function set_width( val: Float ): Float
+ {
+
+ _width = val;
+ _style.paddingLeft = val + "px";
+ return val;
+
+ }
+ private function get_width(): Float
+ {
+
+ if( _width == null || _width < _dom.clientWidth )
+ {
+ _width = _dom.clientWidth;
+ }
+ return _width;
+
+ }
+
+
+ public var y( get_y, set_y ): Float;
+ private function set_y( val: Float ): Float
+ {
+
+ _y = val;
+ _style.top = val + "px";
+ return val;
+
+ }
+ private function get_y(): Float
+ {
+
+ return _y;
+
+ }
+
+ public var x( get_x, set_x ): Float;
+ private function set_x( val: Float ): Float
+ {
+
+ _x = val;
+ _style.left = val + "px";
+ return val;
+
+ }
+ private function get_x(): Float
+ {
+
+ return _x;
+
+ }
+
+
+ public var _parent: DisplayDiv;
+ public var parent( get_parent, set_parent ): DisplayDiv;
+ public function set_parent( mc: DisplayDiv ): DisplayDiv
+ {
+
+ _parent = mc;
+ return mc;
+
+ }
+ public function get_parent(): DisplayDiv
+ {
+
+ return _parent;
+
+ }
+
+
+}
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/core/ImageLoader.hx b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/core/ImageLoader.hx
new file mode 100644
index 00000000..e04474a8
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/core/ImageLoader.hx
@@ -0,0 +1,50 @@
+
+package core;
+import js.Lib;
+import js.html.ImageElement;
+import js.html.Event;
+import js.html.Document;
+import js.Browser;
+typedef Hash = haxe.ds.StringMap;
+
+class ImageLoader
+{
+
+ public var images: Hash;
+
+ private var loaded: Void -> Void;
+ private var count: Int;
+
+ public function new( imageNames: Array, loaded_: Void -> Void )
+ {
+ images = new Hash();
+ loaded = loaded_;
+ count = imageNames.length;
+ for( name in imageNames ) load( name );
+ }
+
+ private function load( img: String )
+ {
+ var image: ImageElement = js.Browser.document.createImageElement();
+ var imgStyle = image.style;
+ imgStyle.left = '0px';
+ imgStyle.top = '0px';
+ imgStyle.paddingLeft = "0px";
+ imgStyle.paddingTop = "0px";
+ image.onload = store.bind( image, img.split('/').pop() );
+ imgStyle.position = "absolute";
+ image.src = img;
+ }
+
+ private function store( image: ImageElement, name: String, e: Event )
+ {
+ count--;
+ trace( 'store ' + name + ' ' + count );
+ images.set( name, image );
+ if( count == 0 )
+ {
+ loaded();
+ }
+ }
+
+}
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/core/Leaf.hx b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/core/Leaf.hx
new file mode 100644
index 00000000..ee67a6bd
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/core/Leaf.hx
@@ -0,0 +1,242 @@
+
+package core;
+
+import js.Lib;
+import core.Leaf;
+import js.html.CanvasElement;
+import js.html.CanvasRenderingContext2D;
+import js.html.ImageElement;
+import js.Browser;
+using core.Leaf;
+
+
+typedef Point2D =
+{
+ var x: Int;
+ var y: Int;
+}
+typedef Axis =
+{
+ var beta: Float;
+ var hyp: Float;
+}
+
+
+class Leaf
+{
+ public static var showBoxes: Bool = false;
+ public static var showCrosses: Bool = false;
+ private static var canvas: CanvasElement;
+ private static var surface: CanvasRenderingContext2D;
+ private static var imageTemp: ImageElement;
+ public static var testSurface: CanvasRenderingContext2D;
+ public var parent: Leaf;
+ public var name: String;
+ // source
+ public var image( default, set_image ): ImageElement;
+ // image position
+ public var x: Int;
+ public var y: Int;
+ // image dim
+ public var w ( default, null ): Int;
+ public var h ( default, null ): Int;
+ // rotation point
+ public var rx: Float;
+ public var ry: Float;
+ // angle in radians
+ public var theta( default, set_theta ): Float;
+
+ // store by depth
+ public var leaves: Array;
+ public var leafCentre: Array;
+ public var leafAxis: Array;
+ public var left( default, default ): Int;
+ public var top( default, default ): Int;
+ public var wid( default, null ): Int;
+ public var hi( default, null ): Int;
+ public var cx( default, null ): Float;
+ public var cy( default, null ): Float;
+ public var hyp: Float;
+ public var beta: Float;
+ var dx: Float;
+ var dy: Float;
+ public var offset: Point2D;
+
+ public function set_image( image_: ImageElement ): ImageElement
+ {
+ image = image_;
+ w = image.width;
+ h = image.height;
+
+ return image;
+ }
+
+
+ public function set_theta( theta_: Float ): Float
+ {
+ if( theta == null ) theta = 0;
+ var dTheta = theta - theta_;
+ theta = theta_;
+ if( rx == null ) rx = 0;
+ if( ry == null ) ry = 0;
+ var sine = Math.sin( theta );
+ var cos = Math.cos( theta );
+
+ // new dimensions
+ wid = Std.int( Math.abs( w*cos ) + Math.abs( h*sine ) );
+ hi = Std.int( Math.abs( w*sine ) + Math.abs( h*cos ) );
+ // new centre
+ cx = wid/2;
+ cy = hi/2;
+
+ // calculates offset of pivot
+ offset = pivotOffset();
+ left = Std.int( x + offset.x );
+ top = Std.int( y + offset.y );
+
+ return theta_;
+
+ }
+
+ public function addLeaf( leaf: Leaf, rx_: Int, ry_: Int )
+ {
+ leafCentre.push( { x: rx_, y: ry_ } );
+ leaves.push( leaf );
+ }
+
+ public function rotate( theta_: Float, rx_: Float, ry_: Float )
+ {
+ rx = rx_;
+ ry = ry_;
+ theta = theta_;
+ for( i in 0...leafCentre.length )
+ {
+ if( leafAxis[i] == null )
+ {
+ var dx2 = rx - leafCentre[i].x;
+ var dy2 = ry - leafCentre[i].y;
+ leafAxis.push( { beta: Math.atan2( dy2, dx2 ), hyp: Math.pow( dx2*dx2 + dy2*dy2, 0.5 ) } );
+ }
+ }
+ }
+
+ public function new( image_: ImageElement, ?x_: Int = 0, ?y_: Int = 0 )
+ {
+ leaves = [];
+ leafAxis = new Array();
+ leafCentre = new Array();
+ image = image_;
+ x = x_;
+ y = y_;
+
+ }
+
+ public function pivotOffset(): Point2D
+ {
+ var dx = w/2 - rx;
+ var dy = h/2 - ry;
+ // calculates the angle from the old centre to the pivot point.
+ beta = Math.atan2( dy, dx );
+ // calculates the diagonal distance from the old centre to the pivot point.
+ hyp = Math.pow( dx*dx + dy*dy, 0.5 );
+ var bt = beta + theta;
+
+ return { x: Std.int( rx - cx + hyp*Math.cos( bt ) )
+ , y: Std.int( ry - cy + hyp*Math.sin( bt ) )
+ };
+ }
+
+ public function renderOn( surfaceOut: CanvasRenderingContext2D )
+ {
+
+ if( canvas == null )
+ {
+ // creates a canvas if one does not exist
+ var dom = Browser.document.createElement('Canvas');
+ canvas = cast dom;
+ surface = untyped canvas.getContext('2d');
+ imageTemp = untyped canvas;
+ }
+
+ canvas.width = wid;
+ canvas.height = hi;
+ // position canvas so whole rotation fits.
+ surface.translate( cx, cy );
+ surface.rotate( theta );
+ // draws to the temporary canvas
+ surface.drawImage( image, -w/2, -h/2, w, h );
+ //surfaceOut.clearRect( 0,0,768,1000);
+ surfaceOut.drawImage( imageTemp, left, top, wid, hi );
+ //var rotPoint = { x: Std.int( left + cx - hyp*Math.cos( beta + theta ) ), y: Std.int(top + cy - hyp*Math.sin( beta + theta ) ) };
+ var bt = beta + theta;
+ var rotX = left + cx - hyp*Math.cos( bt );
+ var rotY = top + cy - hyp*Math.sin( bt );
+ // show top cross
+ if( showCrosses ) surfaceOut.quickCross(
+ { x: Std.int( rotX )
+ , y: Std.int( rotY ) }
+ );
+ // show boxes
+ if( showBoxes ) addBox( surfaceOut, left, top, wid, hi );
+
+ surface.rotate( -theta );
+ surface.translate( -cx, -cy );
+ surface.clearRect( 0, 0, Math.ceil( cx ), Math.ceil( cy ) );
+
+ for( i in 0...leaves.length )
+ {
+ var axis = leafAxis[ i ];
+ var leaf = leaves[ i ];
+ var loff = leaf.offset;
+ var hyp2 = axis.hyp;
+ var b2t = axis.beta + theta;
+
+ // show bottom cross
+ if( showCrosses ) surfaceOut.quickCross(
+ { x: Std.int( rotX - hyp2*Math.cos( b2t ) )
+ , y: Std.int( rotY - hyp2*Math.sin( b2t ) ) }
+ );
+
+
+ leaf.left = Std.int( rotX - hyp2*Math.cos( b2t ) + loff.x - leaf.rx ) ;
+ leaf.top = Std.int( rotY - hyp2*Math.sin( b2t ) + loff.y - leaf.ry );
+
+ leaves[ i ].renderOn( surfaceOut );
+
+ }
+
+
+ }
+ //public var rotPoint: Point2D;
+
+ public static inline function addBox( surfaceOut: CanvasRenderingContext2D
+ , left: Int
+ , top: Int
+ , wid: Int
+ , hi: Int
+ )
+ {
+ surfaceOut.beginPath();
+ surfaceOut.strokeStyle = '#00000f';
+ surfaceOut.lineWidth = 0.1;
+ surfaceOut.moveTo( left, top );
+ surfaceOut.lineTo( left + wid, top );
+ surfaceOut.lineTo( left + wid, top + hi );
+ surfaceOut.lineTo( left, top + hi );
+ surfaceOut.lineTo( left, top );
+ surfaceOut.stroke();
+ }
+ public static inline function quickCross( surface: CanvasRenderingContext2D, p: Point2D )
+ {
+ surface.beginPath();
+ surface.strokeStyle = '#f000f0';
+ surface.lineWidth = 2;
+ surface.moveTo( p.x - 5, p.y );
+ surface.lineTo( p.x + 5, p.y );
+ surface.moveTo( p.x, p.y - 5 );
+ surface.lineTo( p.x, p.y + 5 );
+ surface.stroke();
+ }
+
+
+}
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/core/SetupCanvas.hx b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/core/SetupCanvas.hx
new file mode 100644
index 00000000..88147ab1
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/core/SetupCanvas.hx
@@ -0,0 +1,37 @@
+
+package core;
+import js.Browser;
+import js.html.Element;
+import js.html.CSSStyleDeclaration;
+import js.html.CanvasElement;
+import js.html.CanvasRenderingContext2D;
+import js.html.Element;
+import js.html.BodyElement;
+import js.html.ImageElement;
+
+class SetupCanvas
+{
+
+ public var surface: CanvasRenderingContext2D;
+ public var dom: Element;
+ public var image: ImageElement;
+ public var canvas: CanvasElement;
+ public var style: CSSStyleDeclaration;
+ public var body: Element;
+ public function new( ?wid: Int = 1024, ?hi: Int = 768 )
+ {
+ canvas = Browser.document.createCanvasElement();
+ dom = cast canvas;
+ body = Browser.document.body;
+ surface = canvas.getContext2d();
+ style = dom.style;
+ canvas.width = wid;
+ canvas.height = hi;
+ style.paddingLeft = "0px";
+ style.paddingTop = "0px";
+ style.left = Std.string( 0 + 'px' );
+ style.top = Std.string( 0 + 'px' );
+ style.position = "absolute";
+ image = cast dom;
+ }
+}
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/core/WebBrowser.hx b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/core/WebBrowser.hx
new file mode 100644
index 00000000..108d81fd
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/core/WebBrowser.hx
@@ -0,0 +1,133 @@
+
+package core;
+
+import js.Lib;
+import js.Browser;
+enum BrowserType
+{
+ Chrome;
+ Safari;
+ WebKitOther;
+ FireFox;
+ Opera;
+ IE;
+}
+
+class WebBrowser
+{
+
+ private static var _browserType: BrowserType;
+ private static var _userAgent: String;
+
+ public static var browserType( get_browserType, null ): BrowserType;
+ private static var _hasCanvas2d: Bool;
+ public static var hasCanvas2d( get_hasCanvas2d, null ): Bool;
+
+ private static function get_hasCanvas2d(): Bool
+ {
+
+ if( _hasCanvas2d == null )
+ {
+
+ set_hasCanvas2d();
+
+ }
+ return _hasCanvas2d;
+
+ }
+
+ private static function set_hasCanvas2d()
+ {
+
+ if( Browser.document.createCanvasElement().getContext == null )
+ {
+
+ _hasCanvas2d = false;
+
+ }
+ else
+ {
+
+ _hasCanvas2d = true;
+
+ }
+
+ }
+
+ private static function get_browserType(): BrowserType
+ {
+
+ if( _browserType == null )
+ {
+
+ set_browserType( Browser.window.navigator.userAgent );
+
+ }
+
+ return _browserType;
+
+ }
+
+ public static function traceAgent()
+ {
+ get_browserType();
+ trace( _userAgent );
+ }
+
+ private static function set_browserType( agent: String ): BrowserType
+ {
+
+ _userAgent = agent;
+
+ if( (~/WebKit/).match( agent ) )
+ {
+
+ if((~/Chrome/).match( agent ) )
+ {
+
+ _browserType = Chrome;
+
+ }
+ else if( (~/Safari/).match( agent ) )
+ {
+
+ _browserType = Safari;
+
+ }
+ else
+ {
+
+ _browserType = Opera;
+
+ }
+
+ }
+ else if( (~/Opera/).match( agent ) )
+ {
+ //(__js__("typeof window!='undefined'") && window.opera != null );
+ _browserType = Opera;
+
+ }
+ else if( (~/Mozilla/).match( agent ) )
+ {
+
+ var isIE = untyped (__js__("typeof document!='undefined'") && document.all != null && __js__("typeof window!='undefined'") && window.opera == null );
+ if ( isIE )
+ {
+ _browserType = IE;
+ }
+ else
+ {
+ _browserType = FireFox;
+ }
+ }
+ else
+ {
+ _browserType = IE;
+ }
+
+ return _browserType;
+
+ }
+
+}
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/utils/CalendarMonthUtil.hx b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/utils/CalendarMonthUtil.hx
new file mode 100644
index 00000000..5ddbed90
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/utils/CalendarMonthUtil.hx
@@ -0,0 +1,129 @@
+
+package utils;
+
+enum UKweekDays
+{
+ SUNDAY;
+ MONDAY;
+ TUESDAY;
+ WEDNESDAY;
+ THURSDAY;
+ FRIDAY;
+ SATURDAY;
+}
+enum UKmonths
+{
+ JANUARY;
+ FEBRUARY;
+ MARCH;
+ APRIL;
+ MAY;
+ JUNE;
+ JULY;
+ AUGUST;
+ SEPTEMBER;
+ OCTOBER;
+ NOVEMBER;
+ DECEMBER;
+}
+
+class CalendarMonthUtil
+{
+
+ public static inline var cols: Int = 7;
+
+ public var monthDays: Int;
+ public var dateInMonth: Int;
+ public var date: Date;
+ public var startOffset: Int;
+
+ public var rows: Int;
+ public var dayNo: Int;
+ public var currentMonth: Int;
+ public var monthBefore: Int;
+ public var monthAfter: Int;
+ public var currentMonthName: String;
+ public var monthBeforeName: String;
+ public var monthAfterName: String;
+ public var months: Array;
+ public var weekDays: Array;
+
+
+ public function new( date_: Date )
+ {
+
+ date = date_;
+
+ months = Type.allEnums( UKmonths );
+ weekDays = Type.allEnums( UKweekDays );
+
+ update();
+
+ }
+
+ public function monthOffset( no: Int )
+ {
+
+ date = new Date( date.getFullYear()
+ , date.getMonth() + no
+ , date.getDay()
+ , date.getHours()
+ , date.getMinutes()
+ , date.getSeconds()
+ );
+ update();
+
+ }
+
+ public function next()
+ {
+ date = new Date( date.getFullYear()
+ , date.getMonth() + 1
+ , date.getDay()
+ , date.getHours()
+ , date.getMinutes()
+ , date.getSeconds()
+ );
+ update();
+ }
+
+ public function previous()
+ {
+ date = new Date( date.getFullYear()
+ , date.getMonth()
+ , date.getDay()
+ , date.getHours()
+ , date.getMinutes()
+ , date.getSeconds()
+ );
+ update();
+ }
+
+ public function update()
+ {
+
+ monthDays = DateTools.getMonthDays( date );
+ dateInMonth = date.getDate();
+ dayNo = date.getDay();
+ var daysDifference = dayNo;
+ var defaultNameDay = dateInMonth % cols;
+
+ if( defaultNameDay > dayNo )
+ {
+ daysDifference += cols;
+ }
+
+ startOffset = -( daysDifference - defaultNameDay - 1 );
+ rows = Math.ceil( (monthDays - startOffset + 1)/cols );
+
+ currentMonth = date.getMonth();
+ monthBefore = ( currentMonth == 0 )? 11: currentMonth - 1;
+ monthAfter = ( currentMonth == 11 )? 0: currentMonth + 1;
+
+ currentMonthName = Std.string( months[ currentMonth ] );
+ monthBeforeName = Std.string( months[ monthBefore ] );
+ monthAfterName = Std.string( months[ monthAfter ] );
+
+ }
+
+}
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/utils/ColorHexagon.hx b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/utils/ColorHexagon.hx
new file mode 100644
index 00000000..88e4238e
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/utils/ColorHexagon.hx
@@ -0,0 +1,257 @@
+
+package utils;
+import core.DisplayDiv;
+import zpartanlite.Enumerables;
+import js.html.DivElement;
+using core.DivDrawing;
+typedef ColorHex =
+{
+ var div: DisplayDiv;
+ var firstColor: Int;
+ var secondColor: Int;
+ var xStart: Float;
+ var yStart: Float;
+ var hexGrad: List;
+}
+
+enum ColorPallet
+{
+
+ Light;
+ Dark;
+
+}
+
+
+
+class ColorHexagon
+{
+
+ private var _holder: DisplayDiv;
+ private var _firstColor: Int;
+ private var _secondColor: Int;
+ public var hexagons: Array;
+
+ public function new( holder_: DisplayDiv
+ , offX: Int
+ , offY: Int
+ , hexWidth: Int
+ , hexHeight: Int
+ , first_: ColorPallet
+ , second_: ColorPallet
+ , orientation: Orientation
+ )
+ {
+
+ switch( first_ )
+ {
+ case ColorPallet.Light:
+ _firstColor = 1;
+ case ColorPallet.Dark:
+ _firstColor = 0;
+ }
+
+ switch( second_ )
+ {
+ case ColorPallet.Light:
+ _secondColor = 1;
+ case ColorPallet.Dark:
+ _secondColor = 0;
+ }
+
+ _holder = holder_;
+ var colors: Array>> = [
+ [ [ 0xff00ff, 0xff00ff ]
+ , [ 0xCC00FF, 0xCC00FF ]
+ , [ 0x9900FF, 0x6600FF ]
+ , [ 0x6600FF, 0x6600ff ]
+ , [ 0x3300ff, 0x3300ff ]
+ , [ 0x0000ff, 0x0000ff ]
+ ],
+ [ [ 0xff00cc, 0xff00cc ]
+ , [ 0xcc00cc, 0xff33ff ]
+ , [ 0x9900cc, 0xcc33ff ]
+ , [ 0x6600cc, 0x9933ff ]
+ , [ 0x3300cc, 0x6633ff ]
+ , [ 0x0000cc, 0x3333ff ]
+ , [ 0x0033ff, 0x0033ff ]
+ ],
+ [ [ 0xff0099, 0xff0099 ]
+ , [ 0xcc0099, 0xff33cc ]
+ , [ 0x990099, 0xff66ff ]
+ , [ 0x660099, 0xcc66ff ]
+ , [ 0x330099, 0x9966ff ]
+ , [ 0x000099, 0x6666ff ]
+ , [ 0x0033cc, 0x3366ff ]
+ , [ 0x0066ff, 0x0066ff ]
+ ],
+ [ [ 0xff0066, 0xff0066 ]
+ , [ 0xcc0066, 0xff3399 ]
+ , [ 0x990066, 0xff66cc ]
+ , [ 0x660099, 0xff99ff ]
+ , [ 0x330066, 0xcc99ff ]
+ , [ 0x000066, 0x9999ff ]
+ , [ 0x003399, 0x6699ff ]
+ , [ 0x0066cc, 0x3399ff ]
+ , [ 0x0099ff, 0x0099ff ]
+ ],
+ [ [ 0xff0033, 0xff0033 ]
+ , [ 0xcc0033, 0xff3366 ]
+ , [ 0x990033, 0xff6699 ]
+ , [ 0x660033, 0xff99cc ]
+ , [ 0x330033, 0xffccff ]
+ , [ 0x000033, 0xccccff ]
+ , [ 0x003366, 0x99ccff ]
+ , [ 0x006699, 0x66ccff ]
+ , [ 0x0099cc, 0x33ccff ]
+ , [ 0x00ccff, 0x00ccff ]
+ ],
+ [ [ 0xff0000, 0xff0000 ]
+ , [ 0xcc0000, 0xff3333 ]
+ , [ 0x990000, 0xff6666 ]
+ , [ 0x660000, 0xff9999 ]
+ , [ 0x330000, 0xffcccc ]
+ , [ 0x000000, 0xffffff ]
+ , [ 0x003333, 0xccffff ]
+ , [ 0x006666, 0x99ffff ]
+ , [ 0x009999, 0x66ffff ]
+ , [ 0x00cccc, 0x33ffff ]
+ , [ 0x00ffff, 0x00ffff ]
+ ],
+ [ [ 0xff3300, 0xff3300 ]
+ , [ 0xcc3300, 0xff6633 ]
+ , [ 0x993300, 0xff9966 ]
+ , [ 0x663300, 0xffcc99 ]
+ , [ 0x333300, 0xffffcc ]
+ , [ 0x003300, 0xccffcc ]
+ , [ 0x006633, 0x99ffcc ]
+ , [ 0x009966, 0x66ffcc ]
+ , [ 0x00cc99, 0x33ffcc ]
+ , [ 0x00ffcc, 0x00ffcc ]
+ ],
+ [ [ 0xff6600, 0xff6600 ]
+ , [ 0xcc6600, 0xff9933 ]
+ , [ 0x996600, 0xffcc66 ]
+ , [ 0x666600, 0xffff99 ]
+ , [ 0x336600, 0xccff99 ]
+ , [ 0x006600, 0x99ff99 ]
+ , [ 0x009933, 0x66ff99 ]
+ , [ 0x00cc66, 0x33ff99 ]
+ , [ 0x00ff99, 0x00ff99 ]
+ ],
+ [ [ 0xff9900, 0xff9900 ]
+ , [ 0xcc9900, 0xffcc33 ]
+ , [ 0x999900, 0xffff66 ]
+ , [ 0x669900, 0xccff66 ]
+ , [ 0x339900, 0x99ff66 ]
+ , [ 0x009900, 0x66ff66 ]
+ , [ 0x00cc33, 0x33ff99 ]
+ , [ 0x00ff66, 0x00ff66 ]
+ ],
+ [ [ 0xffcc00, 0xffcc00 ]
+ , [ 0xcccc00, 0xffff33 ]
+ , [ 0x99cc00, 0xccff33 ]
+ , [ 0x66cc00, 0x99ff33 ]
+ , [ 0x33cc00, 0x66ff33 ]
+ , [ 0x00cc00, 0x33ff33 ]
+ , [ 0x00ff33, 0x00ff33 ]
+ ],
+ [ [ 0xffff00, 0xffff00 ]
+ , [ 0xccff00, 0xccff00 ]
+ , [ 0x99ff00, 0x99ff00 ]
+ , [ 0x66ff00, 0x66ff00 ]
+ , [ 0x33ff00, 0x33ff00 ]
+ , [ 0x00ff00, 0x00ff00 ]
+ ]
+ ];
+
+ var stepX = hexWidth;//15;//30;//*2;
+ var stepY = hexHeight;//12;//25;//*2;
+ var initX = offX;//200;
+ var initY = offY;//200;
+ var startY = initY;
+ var hex: DisplayDiv;
+ var hexGrad: List;
+ hexagons = new Array();
+ for( i in 0...6 )
+ {
+
+ for( j in 0...colors[ i ].length )
+ {
+
+ hex = new DisplayDiv();
+ _holder.addChild( hex );
+ hex.width = Std.int( stepX );
+ hex.height = Std.int( stepY );
+ hex.x = initX;
+ hex.y = initY;
+ hexGrad = hex.drawGradHexagon( 0
+ , 0
+ , Std.int( stepX )
+ , Std.int( stepY )
+ , colors[ i ][ j ][ _firstColor ]
+ , colors[ i ][ j ][ _secondColor ]
+ , 1
+ , orientation
+ ) ;
+ initY += stepY;
+ hexagons.push( { div: hex
+ , firstColor: colors[ i ][ j ][ _firstColor ]
+ , secondColor: colors[ i ][ j ][ _secondColor ]
+ , xStart: hex.x
+ , yStart: hex.y
+ , hexGrad: hexGrad
+ }
+ );
+ }
+
+ initX += Std.int( stepX*0.7 );
+ startY -= Std.int( stepY/2 );
+ initY = startY;
+
+ }
+
+ initY += Std.int( stepY );
+ startY = initY;
+
+ for( i in 6...11 )
+ {
+
+ for( j in 0...colors[ i ].length )
+ {
+
+ hex = new DisplayDiv();
+ _holder.addChild( hex );
+ hex.width = Std.int( stepX );
+ hex.height = Std.int( stepY );
+ hex.x = initX;
+ hex.y = initY;
+ hexGrad = hex.drawGradHexagon( 0
+ , 0
+ , Std.int( stepX )
+ , Std.int( stepY )
+ , colors[ i ][ j ][ _firstColor ]
+ , colors[ i ][ j ][ _secondColor ]
+ , 1
+ , orientation
+ ) ;
+ initY += stepY;
+ hexagons.push( { div: hex
+ , firstColor: colors[ i ][ j ][ _firstColor ]
+ , secondColor: colors[ i ][ j ][ _secondColor ]
+ , xStart: hex.x
+ , yStart: hex.y
+ , hexGrad: hexGrad
+ }
+ );
+ }
+
+ initX += Std.int( stepX*0.7 );
+ startY += Std.int( stepY/2 );
+ initY = startY;
+
+ }
+
+ }
+
+}
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/utils/ColorJs.hx b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/utils/ColorJs.hx
new file mode 100644
index 00000000..1e41eb6f
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/utils/ColorJs.hx
@@ -0,0 +1,409 @@
+
+package utils;
+
+typedef Pen =
+{
+ var fill: ColorHtml5;
+ var lineColor: ColorHtml5;
+ var thickness: Int;
+ var hasEdge: Bool;
+ var hasFill: Bool;
+}
+
+enum ColorHtml5
+{
+ AliceBlue; AntiqueWhite; Aqua; Aquamarine; Azure;
+ Beige; Bisque; Black; BlanchedAlmond; Blue; BlueViolet; Brown; BurlyWood;
+ CadetBlue; Chartreuse; Chocolate; Coral; CornflowerBlue; Cornsilk; Crimson; Cyan;
+ DarkBlue; DarkCyan; DarkGoldenRod; DarkGray; DarkGrey; DarkGreen; DarkKhaki;
+ DarkMagenta; DarkOliveGreen; Darkorange; DarkOrchid; DarkRed; DarkSalmon;
+ DarkSeaGreen; DarkSlateBlue; DarkSlateGray; DarkSlateGrey; DarkTurquoise; DarkViolet;
+ DeepPink; DeepSkyBlue; DimGray; DimGrey; DodgerBlue;
+ FireBrick; FloralWhite; ForestGreen; Fuchsia;
+ Gainsboro; GhostWhite; Gold; GoldenRod; Gray; Grey; Green; GreenYellow;
+ HoneyDew; HotPink;
+ IndianRed; Indigo; Ivory;
+ Khaki;
+ Lavender; LavenderBlush; LawnGreen; LemonChiffon;
+ LightBlue; LightCoral; LightCyan; LightGoldenRodYellow; LightGray; LightGrey;
+ LightGreen; LightPink; LightSalmon; LightSeaGreen; LightSkyBlue;
+ LightSlateGray; LightSlateGrey; LightSteelBlue; LightYellow;
+ Lime; LimeGreen; Linen;
+ Magenta; Maroon;
+ MediumAquaMarine; MediumBlue; MediumOrchid; MediumPurple; MediumSeaGreen;
+ MediumSlateBlue; MediumSpringGreen; MediumTurquoise; MediumVioletRed;
+ MidnightBlue; MintCream; MistyRose; Moccasin;
+ NavajoWhite; Navy;
+ OldLace; Olive; OliveDrab; Orange; OrangeRed; Orchid;
+ PaleGoldenRod; PaleGreen; PaleTurquoise; PaleVioletRed; PapayaWhip;
+ PeachPuff; Peru; Pink; Plum; PowderBlue; Purple;
+ Red; RosyBrown; RoyalBlue;
+ SaddleBrown; Salmon; SandyBrown; SeaGreen; SeaShell; Sienna; Silver;
+ SkyBlue; SlateBlue; SlateGray; SlateGrey; Snow; SpringGreen; SteelBlue;
+ Tan; Teal; Thistle; Tomato; Turquoise; Violet; Wheat; White; WhiteSmoke;
+ Yellow; YellowGreen;
+}
+/*
+enum ColorHtml
+{
+ Aqua; Black; Blue;
+ Brown; Chartreuse; Fuchsia;
+ Gray; Green; Lime;
+ Maroon; Navy; Olive;
+ Orange; Purple; Red;
+ Silver; Teal; Violet;
+ White; Yellow;
+}*/
+class Colorjs
+{
+ public function new()
+ {
+
+ }
+
+ public static function penClone( p: Pen ): Pen
+ {
+ return { fill: p.fill, lineColor: p.lineColor, thickness: p.thickness, hasEdge: p.hasEdge, hasFill: p.hasFill };
+ }
+
+ public static function redFill()
+ {
+ return { fill: Red, lineColor: White, thickness: 3, hasEdge: false, hasFill: true };
+ }
+/*
+ static public function colorHtmlAsHexString( color: ColorHtml )
+ {
+ switch( color )
+ {
+ case Aqua: "#00FFFF";
+ case Black: "#000000";
+ case Blue: "#0000FF";
+ case Brown: "#A02820";
+ case Chartreuse: "#80FF00";
+ case Fuchsia: "#FF00FF";
+ case Gray: "#808080";
+ case Green: "#008000";
+ case Lime: "#00FF00";
+ case Maroon: "#800000";
+ case Navy: "#000080";
+ case Olive: "#808000";
+ case Orange: "#FFA000";
+ case Purple: "#800080";
+ case Red: "FF0000";
+ case Silver: "#C0C0C0";
+ case Teal: "#008080";
+ case Violet: "#F080F0";
+ case White: "#FFFFFF";
+ case Yellow: "#FFFF00" ;
+ }
+ }
+ */
+ static inline public function str( color: ColorHtml5 ): String
+ {
+ return switch( color )
+ {
+ case AliceBlue: '#F0F8FF';
+ case AntiqueWhite: '#FAEBD7';
+ case Aqua: '#00FFFF';
+ case Aquamarine: '#7FFFD4';
+ case Azure: '#F0FFFF';
+ case Beige: '#F5F5DC';
+ case Bisque: '#FFE4C4';
+ case Black: '#000000';
+ case BlanchedAlmond: '#FFEBCD';
+ case Blue: '#0000FF';
+ case BlueViolet: '#8A2BE2';
+ case Brown: '#A52A2A';
+ case BurlyWood: '#DEB887';
+ case CadetBlue: '#5F9EA0';
+ case Chartreuse: '#7FFF00';
+ case Chocolate: '#D2691E';
+ case Coral: '#FF7F50';
+ case CornflowerBlue: '#6495ED';
+ case Cornsilk: '#FFF8DC';
+ case Crimson: '#DC143C';
+ case Cyan: '#00FFFF';
+ case DarkBlue: '#00008B';
+ case DarkCyan: '#008B8B';
+ case DarkGoldenRod: '#B8860B';
+ case DarkGray: '#A9A9A9';
+ case DarkGrey: '#A9A9A9';
+ case DarkGreen: '#006400';
+ case DarkKhaki: '#BDB76B';
+ case DarkMagenta: '#8B008B';
+ case DarkOliveGreen: '#556B2F';
+ case Darkorange: '#FF8C00';
+ case DarkOrchid: '#9932CC';
+ case DarkRed: '#8B0000';
+ case DarkSalmon: '#E9967A';
+ case DarkSeaGreen: '#8FBC8F';
+ case DarkSlateBlue: '#483D8B';
+ case DarkSlateGray: '#2F4F4F';
+ case DarkSlateGrey: '#2F4F4F';
+ case DarkTurquoise: '#00CED1';
+ case DarkViolet: '#9400D3';
+ case DeepPink: '#FF1493';
+ case DeepSkyBlue: '#00BFFF';
+ case DimGray: '#696969';
+ case DimGrey: '#696969';
+ case DodgerBlue: '#1E90FF';
+ case FireBrick: '#B22222';
+ case FloralWhite: '#FFFAF0';
+ case ForestGreen: '#228B22';
+ case Fuchsia: '#FF00FF';
+ case Gainsboro: '#DCDCDC';
+ case GhostWhite: '#F8F8FF';
+ case Gold: '#FFD700';
+ case GoldenRod: '#DAA520';
+ case Gray: '#808080';
+ case Grey: '#808080';
+ case Green: '#008000';
+ case GreenYellow: '#ADFF2F';
+ case HoneyDew: '#F0FFF0';
+ case HotPink: '#FF69B4';
+ case IndianRed: '#CD5C5C';
+ case Indigo: '#4B0082';
+ case Ivory: '#FFFFF0';
+ case Khaki: '#F0E68C';
+ case Lavender: '#E6E6FA';
+ case LavenderBlush: '#FFF0F5';
+ case LawnGreen: '#7CFC00';
+ case LemonChiffon: '#FFFACD';
+ case LightBlue: '#ADD8E6';
+ case LightCoral: '#F08080';
+ case LightCyan: '#E0FFFF';
+ case LightGoldenRodYellow: '#FAFAD2';
+ case LightGray: '#D3D3D3';
+ case LightGrey: '#D3D3D3';
+ case LightGreen: '#90EE90';
+ case LightPink: '#FFB6C1';
+ case LightSalmon: '#FFA07A';
+ case LightSeaGreen: '#20B2AA';
+ case LightSkyBlue: '#87CEFA';
+ case LightSlateGray: '#778899';
+ case LightSlateGrey: '#778899';
+ case LightSteelBlue: '#B0C4DE';
+ case LightYellow: '#FFFFE0';
+ case Lime: '#00FF00';
+ case LimeGreen: '#32CD32';
+ case Linen: '#FAF0E6';
+ case Magenta: '#FF00FF';
+ case Maroon: '#800000';
+ case MediumAquaMarine: '#66CDAA';
+ case MediumBlue: '#0000CD';
+ case MediumOrchid: '#BA55D3';
+ case MediumPurple: '#9370DB';
+ case MediumSeaGreen: '#3CB371';
+ case MediumSlateBlue: '#7B68EE';
+ case MediumSpringGreen: '#00FA9A';
+ case MediumTurquoise: '#48D1CC';
+ case MediumVioletRed: '#C71585';
+ case MidnightBlue: '#191970';
+ case MintCream: '#F5FFFA';
+ case MistyRose: '#FFE4E1';
+ case Moccasin: '#FFE4B5';
+ case NavajoWhite: '#FFDEAD';
+ case Navy: '#000080';
+ case OldLace: '#FDF5E6';
+ case Olive: '#808000';
+ case OliveDrab: '#6B8E23';
+ case Orange: '#FFA500';
+ case OrangeRed: '#FF4500';
+ case Orchid: '#DA70D6';
+ case PaleGoldenRod: '#EEE8AA';
+ case PaleGreen: '#98FB98';
+ case PaleTurquoise: '#AFEEEE';
+ case PaleVioletRed: '#DB7093';
+ case PapayaWhip: '#FFEFD5';
+ case PeachPuff: '#FFDAB9';
+ case Peru: '#CD853F';
+ case Pink: '#FFC0CB';
+ case Plum: '#DDA0DD';
+ case PowderBlue: '#B0E0E6';
+ case Purple: '#800080';
+ case Red: '#FF0000';
+ case RosyBrown: '#BC8F8F';
+ case RoyalBlue: '#4169E1';
+ case SaddleBrown: '#8B4513';
+ case Salmon: '#FA8072';
+ case SandyBrown: '#F4A460';
+ case SeaGreen: '#2E8B57';
+ case SeaShell: '#FFF5EE';
+ case Sienna: '#A0522D';
+ case Silver: '#C0C0C0';
+ case SkyBlue: '#87CEEB';
+ case SlateBlue: '#6A5ACD';
+ case SlateGray: '#708090';
+ case SlateGrey: '#708090';
+ case Snow: '#FFFAFA';
+ case SpringGreen: '#00FF7F';
+ case SteelBlue: '#4682B4';
+ case Tan: '#D2B48C';
+ case Teal: '#008080';
+ case Thistle: '#D8BFD8';
+ case Tomato: '#FF6347';
+ case Turquoise: '#40E0D0';
+ case Violet: '#EE82EE';
+ case Wheat: '#F5DEB3';
+ case White: '#FFFFFF';
+ case WhiteSmoke: '#F5F5F5';
+ case Yellow: '#FFFF00';
+ case YellowGreen: '#9ACD32';
+
+ }
+ }
+ static inline public function rgb( color: ColorHtml5 ): Array
+ {
+ return switch( color )
+ {
+ case AliceBlue: [ 0xF0, 0xF8, 0xFF ];
+ case AntiqueWhite: [ 0xFA, 0xEB, 0xD7 ];
+ case Aqua: [ 0x00, 0xFF, 0xFF ];
+ case Aquamarine: [ 0x7F, 0xFF, 0xD4 ];
+ case Azure: [ 0xF0, 0xFF, 0xFF ];
+ case Beige: [ 0xF5, 0xF5, 0xDC ];
+ case Bisque: [ 0xFF, 0xE4, 0xC4 ];
+ case Black: [ 0x00, 0x00, 0x00 ];
+ case BlanchedAlmond: [ 0xFF, 0xEB, 0xCD ];
+ case Blue: [ 0x00, 0x00, 0xFF ];
+ case BlueViolet: [ 0x8A, 0x2B, 0xE2 ];
+ case Brown: [ 0xA5, 0x2A, 0x2A ];
+ case BurlyWood: [ 0xDE, 0xB8, 0x87 ];
+ case CadetBlue: [ 0x5F, 0x9E, 0xA0 ];
+ case Chartreuse: [ 0x7F, 0xFF, 0x00 ];
+ case Chocolate: [ 0xD2, 0x69, 0x1E ];
+ case Coral: [ 0xFF, 0x7F, 0x50 ];
+ case CornflowerBlue: [ 0x64, 0x95, 0xED ];
+ case Cornsilk: [ 0xFF, 0xF8, 0xDC ];
+ case Crimson: [ 0xDC, 0x14, 0x3C ];
+ case Cyan: [ 0x00, 0xFF, 0xFF ];
+ case DarkBlue: [ 0x00, 0x00, 0x8B ];
+ case DarkCyan: [ 0x00, 0x8B, 0x8B ];
+ case DarkGoldenRod: [ 0xB8, 0x86, 0x0B ];
+ case DarkGray: [ 0xA9, 0xA9, 0xA9 ];
+ case DarkGrey: [ 0xA9, 0xA9, 0xA9 ];
+ case DarkGreen: [ 0x00, 0x64, 0x00 ];
+ case DarkKhaki: [ 0xBD, 0xB7, 0x6B ];
+ case DarkMagenta: [ 0x8B, 0x00, 0x8B ];
+ case DarkOliveGreen: [ 0x55, 0x6B, 0x2F ];
+ case Darkorange: [ 0xFF, 0x8C, 0x00 ];
+ case DarkOrchid: [ 0x99, 0x32, 0xCC ];
+ case DarkRed: [ 0x8B, 0x00, 0x00 ];
+ case DarkSalmon: [ 0xE9, 0x96, 0x7A ];
+ case DarkSeaGreen: [ 0x8F, 0xBC, 0x8F ];
+ case DarkSlateBlue: [ 0x48, 0x3D, 0x8B ];
+ case DarkSlateGray: [ 0x2F, 0x4F, 0x4F ];
+ case DarkSlateGrey: [ 0x2F, 0x4F, 0x4F ];
+ case DarkTurquoise: [ 0x00, 0xCE, 0xD1 ];
+ case DarkViolet: [ 0x94, 0x00, 0xD3 ];
+ case DeepPink: [ 0xFF, 0x14, 0x93 ];
+ case DeepSkyBlue: [ 0x00, 0xBF, 0xFF ];
+ case DimGray: [ 0x69, 0x69, 0x69 ];
+ case DimGrey: [ 0x69, 0x69, 0x69 ];
+ case DodgerBlue: [ 0x1E, 0x90, 0xFF ];
+ case FireBrick: [ 0xB2, 0x22, 0x22 ];
+ case FloralWhite: [ 0xFF, 0xFA, 0xF0 ];
+ case ForestGreen: [ 0x22, 0x8B, 0x22 ];
+ case Fuchsia: [ 0xFF, 0x00, 0xFF ];
+ case Gainsboro: [ 0xDC, 0xDC, 0xDC ];
+ case GhostWhite: [ 0xF8, 0xF8, 0xFF ];
+ case Gold: [ 0xFF, 0xD7, 0x00 ];
+ case GoldenRod: [ 0xDA, 0xA5, 0x20 ];
+ case Gray: [ 0x80, 0x80, 0x80 ];
+ case Grey: [ 0x80, 0x80, 0x80 ];
+ case Green: [ 0x00, 0x80, 0x00 ];
+ case GreenYellow: [ 0xAD, 0xFF, 0x2F ];
+ case HoneyDew: [ 0xF0, 0xFF, 0xF0 ];
+ case HotPink: [ 0xFF, 0x69, 0xB4 ];
+ case IndianRed: [ 0xCD, 0x5C, 0x5C ];
+ case Indigo: [ 0x4B, 0x00, 0x82 ];
+ case Ivory: [ 0xFF, 0xFF, 0xF0 ];
+ case Khaki: [ 0xF0, 0xE6, 0x8C ];
+ case Lavender: [ 0xE6, 0xE6, 0xFA ];
+ case LavenderBlush: [ 0xFF, 0xF0, 0xF5 ];
+ case LawnGreen: [ 0x7C, 0xFC, 0x00 ];
+ case LemonChiffon: [ 0xFF, 0xFA, 0xCD ];
+ case LightBlue: [ 0xAD, 0xD8, 0xE6 ];
+ case LightCoral: [ 0xF0, 0x80, 0x80 ];
+ case LightCyan: [ 0xE0, 0xFF, 0xFF ];
+ case LightGoldenRodYellow: [ 0xFA, 0xFA, 0xD2 ];
+ case LightGray: [ 0xD3, 0xD3, 0xD3 ];
+ case LightGrey: [ 0xD3, 0xD3, 0xD3 ];
+ case LightGreen: [ 0x90, 0xEE, 0x90 ];
+ case LightPink: [ 0xFF, 0xB6, 0xC1 ];
+ case LightSalmon: [ 0xFF, 0xA0, 0x7A ];
+ case LightSeaGreen: [ 0x20, 0xB2, 0xAA ];
+ case LightSkyBlue: [ 0x87, 0xCE, 0xFA ];
+ case LightSlateGray: [ 0x77, 0x88, 0x99 ];
+ case LightSlateGrey: [ 0x77, 0x88, 0x99 ];
+ case LightSteelBlue: [ 0xB0, 0xC4, 0xDE ];
+ case LightYellow: [ 0xFF, 0xFF, 0xE0 ];
+ case Lime: [ 0x00, 0xFF, 0x00 ];
+ case LimeGreen: [ 0x32, 0xCD, 0x32 ];
+ case Linen: [ 0xFA, 0xF0, 0xE6 ];
+ case Magenta: [ 0xFF, 0x00, 0xFF ];
+ case Maroon: [ 0x80, 0x00, 0x00 ];
+ case MediumAquaMarine: [ 0x66, 0xCD, 0xAA ];
+ case MediumBlue: [ 0x00, 0x00, 0xCD ];
+ case MediumOrchid: [ 0xBA, 0x55, 0xD3 ];
+ case MediumPurple: [ 0x93, 0x70, 0xDB ];
+ case MediumSeaGreen: [ 0x3C, 0xB3, 0x71 ];
+ case MediumSlateBlue: [ 0x7B, 0x68, 0xEE ];
+ case MediumSpringGreen: [ 0x00, 0xFA, 0x9A ];
+ case MediumTurquoise: [ 0x48, 0xD1, 0xCC ];
+ case MediumVioletRed: [ 0xC7, 0x15, 0x85 ];
+ case MidnightBlue: [ 0x19, 0x19, 0x70 ];
+ case MintCream: [ 0xF5, 0xFF, 0xFA ];
+ case MistyRose: [ 0xFF, 0xE4, 0xE1 ];
+ case Moccasin: [ 0xFF, 0xE4, 0xB5 ];
+ case NavajoWhite: [ 0xFF, 0xDE, 0xAD ];
+ case Navy: [ 0x00, 0x00, 0x80 ];
+ case OldLace: [ 0xFD, 0xF5, 0xE6 ];
+ case Olive: [ 0x80, 0x80, 0x00 ];
+ case OliveDrab: [ 0x6B, 0x8E, 0x23 ];
+ case Orange: [ 0xFF, 0xA5, 0x00 ];
+ case OrangeRed: [ 0xFF, 0x45, 0x00 ];
+ case Orchid: [ 0xDA, 0x70, 0xD6 ];
+ case PaleGoldenRod: [ 0xEE, 0xE8, 0xAA ];
+ case PaleGreen: [ 0x98, 0xFB, 0x98 ];
+ case PaleTurquoise: [ 0xAF, 0xEE, 0xEE ];
+ case PaleVioletRed: [ 0xDB, 0x70, 0x93 ];
+ case PapayaWhip: [ 0xFF, 0xEF, 0xD5 ];
+ case PeachPuff: [ 0xFF, 0xDA, 0xB9 ];
+ case Peru: [ 0xCD, 0x85, 0x3F ];
+ case Pink: [ 0xFF, 0xC0, 0xCB ];
+ case Plum: [ 0xDD, 0xA0, 0xDD ];
+ case PowderBlue: [ 0xB0, 0xE0, 0xE6 ];
+ case Purple: [ 0x80, 0x00, 0x80 ];
+ case Red: [ 0xFF, 0x00, 0x00 ];
+ case RosyBrown: [ 0xBC, 0x8F, 0x8F ];
+ case RoyalBlue: [ 0x41, 0x69, 0xE1 ];
+ case SaddleBrown: [ 0x8B, 0x45, 0x13 ];
+ case Salmon: [ 0xFA, 0x80, 0x72 ];
+ case SandyBrown: [ 0xF4, 0xA4, 0x60 ];
+ case SeaGreen: [ 0x2E, 0x8B, 0x57 ];
+ case SeaShell: [ 0xFF, 0xF5, 0xEE ];
+ case Sienna: [ 0xA0, 0x52, 0x2D ];
+ case Silver: [ 0xC0, 0xC0, 0xC0 ];
+ case SkyBlue: [ 0x87, 0xCE, 0xEB ];
+ case SlateBlue: [ 0x6A, 0x5A, 0xCD ];
+ case SlateGray: [ 0x70, 0x80, 0x90 ];
+ case SlateGrey: [ 0x70, 0x80, 0x90 ];
+ case Snow: [ 0xFF, 0xFA, 0xFA ];
+ case SpringGreen: [ 0x00, 0xFF, 0x7F ];
+ case SteelBlue: [ 0x46, 0x82, 0xB4 ];
+ case Tan: [ 0xD2, 0xB4, 0x8C ];
+ case Teal: [ 0x00, 0x80, 0x80 ];
+ case Thistle: [ 0xD8, 0xBF, 0xD8 ];
+ case Tomato: [ 0xFF, 0x63, 0x47 ];
+ case Turquoise: [ 0x40, 0xE0, 0xD0 ];
+ case Violet: [ 0xEE, 0x82, 0xEE ];
+ case Wheat: [ 0xF5, 0xDE, 0xB3 ];
+ case White: [ 0xFF, 0xFF, 0xFF ];
+ case WhiteSmoke: [ 0xF5, 0xF5, 0xF5 ];
+ case Yellow: [ 0xFF, 0xFF, 0x00 ];
+ case YellowGreen: [ 0x9A, 0xCD, 0x32 ];
+
+ }
+ }
+}
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/utils/LiteLetters.hx b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/utils/LiteLetters.hx
new file mode 100644
index 00000000..8c41e802
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/utils/LiteLetters.hx
@@ -0,0 +1,694 @@
+
+package utils;
+import Main;
+import js.html.CanvasRenderingContext2D;
+enum DrawingCommand
+{
+ MOVE;
+ LINE;
+ ARC;
+}
+typedef DrawInstruction =
+{
+ var instruction: DrawingCommand;
+ var param: Array;
+}
+class LiteLetters
+{
+
+ var surface: CanvasRenderingContext2D;
+ public var scale: Float;
+ public var dx: Int;
+ public var dy: Int;
+ var dia: Int;
+ var piSmall: Float;
+ var pi: Float;
+ var gap: Int;
+ var radius: Int;
+ var twoDia: Int;
+ var three4Dia: Int;
+ var oneHalfDia: Int;
+ var north: Float;
+ var south: Float;
+ var east: Float;
+ var west: Float;
+ var clock: Bool;
+ var dPix: Int;
+ var dPiy: Int;
+
+ public function new( surface_: CanvasRenderingContext2D )
+ {
+ surface = surface_;
+ dia = 8;
+ radius = Std.int( dia/2 );
+ dx = 100;
+ dy = 100;
+ twoDia = dia*2;
+ clock = false;
+ dPix = 3;
+ dPiy = 2;
+ oneHalfDia = Std.int(1.5*dia);
+ three4Dia = Std.int( dia*(3/4) );
+ gap = Std.int( dia/2.5);
+ piSmall = Math.PI/4;
+ pi = Math.PI;
+ north = -pi/2;
+ south = pi/2;
+ west = pi;
+ east = 0;
+ setColorStroke( '#ff0000', 1.5 );
+ }
+
+ public function setColorStroke( col: String, stroke: Float )
+ {
+ surface.strokeStyle = col;
+ surface.lineWidth = stroke;
+ }
+
+ public function letterChoose( letter: String ): Array
+ {
+ return switch( letter )
+ {
+ case 'a': [ { instruction: MOVE
+ , param: [ dx + radius + dPix, dy + dPiy ]
+ },
+ { instruction: ARC
+ , param: [ dx + radius, dy + radius, radius, north + piSmall, south - piSmall, true ]
+ },
+ { instruction: MOVE
+ , param: [ dx + radius + dPix + 2, dy + dia ]
+ },
+ { instruction: LINE
+ , param: [ dx + radius + dPix, dy + dia - 1 ]
+ },
+ { instruction: LINE
+ , param: [ dx + radius + dPix, dy - 1 ]
+ }
+ ];
+ case 'b': [ { instruction: MOVE
+ , param: [ dx + radius - dPix, dy + dPiy ]
+ },
+ { instruction: ARC
+ , param: [ dx + radius, dy + radius, radius, north - piSmall, south + piSmall, false ]
+ },
+ { instruction: MOVE
+ , param: [ dx + radius - dPix - 1, dy - dia + 1 ]
+ },
+ { instruction: LINE
+ , param: [ dx + radius - dPix - 1, dy + dia ]
+ }
+ ];
+ case 'c': [ { instruction: MOVE
+ , param: [ dx + radius + dPix, dy + dPiy ]
+ },
+ { instruction: ARC
+ , param: [ dx + radius, dy + radius, radius, north + piSmall, south - piSmall, true ]
+ }
+ ];
+ case 'd': [ { instruction: MOVE
+ , param: [ dx + radius + dPix, dy + dPiy ]
+ },
+ { instruction: ARC
+ , param: [ dx + radius, dy + radius, radius, north + piSmall, south - piSmall, true ]
+ },
+ { instruction: MOVE
+ , param: [ dx + radius + dPix, dy + dia ]
+ },
+ { instruction: LINE
+ , param: [ dx + radius + dPix, dy - dia + 1 ]
+ }
+ ];
+ case 'e': [ { instruction: MOVE
+ , param: [ dx + radius + dPix, dy + dPiy ]
+ },
+ { instruction: ARC
+ , param: [ dx + radius, dy + radius, radius, north + 1.5*piSmall, south - piSmall, true ]
+ },
+ { instruction: MOVE
+ , param: [ dx, dy + radius ]
+ },
+ { instruction: LINE
+ , param: [ dx + dia, dy + radius ]
+ }
+ ];
+ case 'f': [ { instruction: MOVE
+ , param: [ dx + dia, dy - radius + 1 ]
+ },
+ { instruction: ARC
+ , param: [ dx + radius, dy + radius - dia + 1, radius - 1, east - piSmall, west , true ]
+ },
+ { instruction: MOVE
+ , param: [ dx + 1, dy - radius + 1 ]
+ },
+ { instruction: LINE
+ , param: [ dx + 1, dy + dia ]
+ },
+ { instruction: MOVE
+ , param: [ dx, dy ]
+ },
+ { instruction: LINE
+ , param: [ dx + radius + 1, dy ]
+ }
+ ];
+ case 'g': [ { instruction: MOVE
+ , param: [ dx + radius + dPix, dy + dPiy ]
+ },
+ { instruction: ARC
+ , param: [ dx + radius, dy + radius, radius, north + piSmall, south - piSmall, true ]
+ },
+ { instruction: MOVE
+ , param: [ dx + radius + dPix, dy + dPiy ]
+ },
+ { instruction: LINE
+ , param: [ dx + radius + dPix, dy + dia + radius - 1 ]
+ },
+ { instruction: ARC
+ , param: [ dx + radius, dy + dia + radius - 1, radius - 1, east, west, false ]
+ }
+ ];
+ case 'h': [ { instruction: MOVE
+ , param: [ dx, dy + radius ]
+ },
+ { instruction: ARC
+ , param: [ dx + radius, dy + radius, radius, west, east, false ]
+ },
+ { instruction: MOVE
+ , param: [ dx, dy - dia + 1 ]
+ },
+ { instruction: LINE
+ , param: [ dx, dy + dia ]
+ },
+ { instruction: MOVE
+ , param: [ dx + dia, dy + radius ]
+ },
+ { instruction: LINE
+ , param: [ dx + dia, dy + dia ]
+ }
+ ];
+ case 'i': [ { instruction: MOVE
+ , param: [ dx + radius, dy ]
+ },
+ { instruction: LINE
+ , param: [ dx + radius, dy + dia ]
+ },
+ { instruction: MOVE
+ , param: [ dx + radius, dy - radius ]
+ },
+ { instruction: LINE
+ , param: [ dx + radius, dy - radius + 2 ]
+ }
+ ];
+ case 'j': [ { instruction: MOVE
+ , param: [ dx + radius, dy - radius ]
+ },
+ { instruction: LINE
+ , param: [ dx + radius, dy - radius + 2 ]
+ },
+ { instruction: MOVE
+ , param: [ dx + radius, dy ]
+ },
+ { instruction: ARC
+ , param: [ dx + Std.int(radius/2), dy + dia + radius - 1
+ , Std.int(radius/2), east - Math.PI/8, west
+ , false ]
+ }
+ ];
+ case 'k': [ { instruction: MOVE
+ , param: [ dx, dy + dia ]
+ },
+ { instruction: LINE
+ , param: [ dx, dy - dia + 1 ]
+ },
+ { instruction: MOVE
+ , param: [ dx, dy + radius ]
+ },
+ { instruction: LINE
+ , param: [ dx + dia - 1, dy ]
+ },
+ { instruction: MOVE
+ , param: [ dx + 2, dy + radius - 2 ]
+ },
+ { instruction: LINE
+ , param: [ dx + dia - 1, dy + dia ]
+ },
+ ];
+ case 'l': [ { instruction: MOVE
+ , param: [ dx + radius, dy - dia + 1 ]
+ },
+ { instruction: LINE
+ , param: [ dx + radius, dy + dia - 1 ]
+ },
+ { instruction: LINE
+ , param: [ dx + radius + 2, dy + dia ]
+ }
+ ];
+ //re-think this letter?
+ case 'm': [ { instruction: MOVE
+ , param: [ dx, dy + 3 ]
+ },
+ { instruction: LINE
+ , param: [ dx + 2, dy ]
+ },
+ { instruction: LINE
+ , param: [ dx + radius, dy + 4 ]
+ },
+ { instruction: LINE
+ , param: [ dx + radius, dy + dia - 2 ]
+ },
+ { instruction: LINE
+ , param: [ dx + radius, dy + 4 ]
+ },
+ { instruction: LINE
+ , param: [ dx + dia - 2, dy ]
+ },
+ { instruction: LINE
+ , param: [ dx + dia, dy + 3 ]
+ },
+ { instruction: LINE
+ , param: [ dx + dia, dy + dia ]
+ },
+ { instruction: MOVE
+ , param: [ dx - 1, dy ]
+ },
+ { instruction: LINE
+ , param: [ dx, dy + dia ]
+ }
+ ];
+ case 'n': [ { instruction: MOVE
+ , param: [ dx, dy + radius ]
+ },
+ { instruction: ARC
+ , param: [ dx + radius, dy + radius, radius, west, east, false ]
+ },
+ { instruction: MOVE
+ , param: [ dx, dy - 1 ]
+ },
+ { instruction: LINE
+ , param: [ dx, dy + dia ]
+ },
+ { instruction: MOVE
+ , param: [ dx + dia, dy + radius ]
+ },
+ { instruction: LINE
+ , param: [ dx + dia, dy + dia ]
+ },
+ ];
+ case 'o': [ { instruction: MOVE
+ , param: [ dx, dy + radius ]
+ },
+ { instruction: ARC
+ , param: [ dx + radius, dy + radius, radius, west + pi*2, west, true ]
+ }
+ ];
+ case 'p': [ { instruction: MOVE
+ , param: [ dx + radius - dPix, dy + dPiy ]
+ },
+ { instruction: ARC
+ , param: [ dx + radius, dy + radius, radius, north - piSmall, south + piSmall, false ]
+ },
+ { instruction: MOVE
+ , param: [ dx + radius - dPix - 1, dy ]
+ },
+ { instruction: LINE
+ , param: [ dx + radius - dPix - 1, dy + 2*dia - 1 ]
+ },
+ ];
+ case 'q': [ { instruction: MOVE
+ , param: [ dx + radius + dPix, dy + dPiy ]
+ },
+ { instruction: ARC
+ , param: [ dx + radius, dy + radius, radius, north + piSmall, south - piSmall, true ]
+ },
+ { instruction: MOVE
+ , param: [ dx + radius + dPix, dy ]
+ },
+ { instruction: LINE
+ , param: [ dx + radius + dPix, dy + 2*dia - 1 ]
+ }
+ ];
+ case 'r': [ { instruction: MOVE
+ , param: [ dx, dy + radius ]
+ },
+ { instruction: ARC
+ , param: [ dx + radius, dy + radius, radius, west, north + piSmall, false ]
+ },
+ { instruction: MOVE
+ , param: [ dx, dy - 1 ]
+ },
+ { instruction: LINE
+ , param: [ dx, dy + dia ]
+ }
+ ];
+ case 's': [ { instruction: MOVE
+ , param: [ dx + dia - 1, dy + 2 ]
+ },
+ { instruction: LINE
+ , param: [ dx + radius, dy ]
+ },
+ { instruction: LINE
+ , param: [ dx + 2, dy + 2 ]
+ },
+ { instruction: LINE
+ , param: [ dx + radius, dy + radius ]
+ },
+ { instruction: LINE
+ , param: [ dx + dia - 2, dy + 6 ]
+ },
+ { instruction: LINE
+ , param: [ dx + radius, dy + dia ]
+ },
+ { instruction: LINE
+ , param: [ dx + 1, dy + dia -1 ]
+ }
+ ];
+ case 't': [ { instruction: MOVE
+ , param: [ dx + radius - 1, dy - radius ]
+ },
+ { instruction: LINE
+ , param: [ dx + radius - 1, dy + dia - 1 ]
+ },
+ { instruction: LINE
+ , param: [ dx + radius + 1, dy + dia ]
+ },
+ { instruction: LINE
+ , param: [ dx + radius + 3, dy + dia - 1 ]
+ },
+ { instruction: MOVE
+ , param: [ dx, dy ]
+ },
+ { instruction: LINE
+ , param: [ dx + dia - dPix, dy ]
+ }
+ ];
+ case 'u': [ { instruction: MOVE
+ , param: [ dx, dy - 1 ]
+ },
+ { instruction: LINE
+ , param: [ dx, dy + radius - 1 ]
+ },
+ { instruction: ARC
+ , param: [ dx + radius, dy + radius - 1, radius, west, east, true ]
+ },
+ { instruction: LINE
+ , param: [ dx + dia, dy - 1 ]
+ },
+ { instruction: LINE
+ , param: [ dx + dia, dy + dia ]
+ }
+ ];
+ case 'v': [ { instruction: MOVE
+ , param: [ dx, dy ]
+ },
+ { instruction: LINE
+ , param: [ dx + radius, dy + dia ]
+ },
+ { instruction: LINE
+ , param: [ dx + dia, dy ]
+ }
+
+ ];
+ case 'w': [ { instruction: MOVE
+ , param: [ dx, dy ]
+ },
+ { instruction: LINE
+ , param: [ dx + 1, dy + dia ]
+ },
+ { instruction: LINE
+ , param: [ dx + radius, dy + radius - 1 ]
+ },
+ { instruction: LINE
+ , param: [ dx + dia - 1, dy + dia ]
+ },
+ { instruction: LINE
+ , param: [ dx + dia, dy ]
+ }
+ ];
+ case 'x': [ { instruction: MOVE
+ , param: [ dx, dy ]
+ },
+ { instruction: LINE
+ , param: [ dx + dia, dy + dia ]
+ },
+ { instruction: MOVE
+ , param: [ dx + dia, dy ]
+ },
+ { instruction: LINE
+ , param: [ dx, dy + dia ]
+ }
+ ];
+ case 'y': [ { instruction: MOVE
+ , param: [ dx, dy ]
+ },
+ { instruction: LINE
+ , param: [ dx, dy + radius ]
+ },
+ { instruction: ARC
+ , param: [ dx + radius, dy + radius, radius, west, east, true ]
+ },
+ { instruction: LINE
+ , param: [ dx + dia, dy ]
+ },
+ { instruction: LINE
+ , param: [ dx + dia, dy + dia + radius - 1 ]
+ },
+ { instruction: ARC
+ , param: [ dx + radius + 1, dy + dia + radius, radius - 1, east, west, false ]
+ }
+ ];
+ case 'z': [ { instruction: MOVE
+ , param: [ dx, dy ]
+ },
+ { instruction: LINE
+ , param: [ dx + dia -1, dy ]
+ },
+ { instruction: LINE
+ , param: [ dx, dy + dia ]
+ },
+ { instruction: LINE
+ , param: [ dx + dia, dy + dia ]
+ }
+ ];
+ case '0': [ { instruction: MOVE
+ , param: [ dx + 1, dy - radius + 1 ]
+ },
+ { instruction: ARC
+ , param: [ dx + radius, dy - radius + 1, radius-0.7, west, east, false ]
+ },
+ { instruction: ARC
+ , param: [ dx + radius, dy + radius, radius, east , west, false ]
+ },
+ { instruction: LINE
+ , param: [ dx + 1, dy - radius + 1 ]
+ },
+ { instruction: MOVE
+ , param: [ dx + 1, dy + radius + 4 ]
+ },
+ { instruction: LINE
+ , param: [ dx + dia - 1, dy - radius - 1 ]
+ }
+ ];
+ case '1': [ { instruction: MOVE
+ , param: [ dx + radius - dPix, dy - dia + dPiy + 1 ]
+ },
+ { instruction: LINE
+ , param: [ dx + radius, dy - dia + 1 ]
+ },
+ { instruction: LINE
+ , param: [ dx + radius, dy + dia ]
+ },
+ { instruction: LINE
+ , param: [ dx + radius - dPix, dy + dia ]
+ },
+ { instruction: LINE
+ , param: [ dx + radius + dPix, dy + dia ]
+ }
+ ];
+ case '2': [ { instruction: MOVE
+ , param: [ dx, dy - radius - 1 ]
+ },
+ { instruction: ARC
+ , param: [ dx + radius, dy - radius + 1, radius, west, east + piSmall, false ]
+ },
+ { instruction: LINE
+ , param: [ dx + 2, dy + dia - 4 ]
+ },
+ { instruction: LINE
+ , param: [ dx, dy + dia ]
+ },
+ { instruction: LINE
+ , param: [ dx + dia, dy + dia ]
+ }
+ ];
+ case '3': [ { instruction: MOVE
+ , param: [ dx, dy - radius - 1 ]
+ },
+ { instruction: ARC
+ , param: [ dx + radius, dy - radius + 1, radius, west, east + piSmall, false ]
+ },
+ { instruction: ARC
+ , param: [ dx + radius, dy + radius, radius, east - piSmall, west, false ]
+ },
+ { instruction: MOVE
+ , param: [ dx + radius-1, dy ]
+ },
+ { instruction: LINE
+ , param: [ dx + radius + 3, dy ]
+ }
+ ];
+ case '4': [ { instruction: MOVE
+ , param: [ dx + dia + 1, dy + 1 ]
+ },
+ { instruction: LINE
+ , param: [ dx, dy + 1 ]
+ },
+ { instruction: LINE
+ , param: [ dx, dy ]
+ },
+ { instruction: LINE
+ , param: [ dx + radius + 2, dy - dia + 1 ]
+ },
+ { instruction: LINE
+ , param: [ dx + radius + 2, dy + dia ]
+ }
+ ];
+ case '5': [ { instruction: MOVE
+ , param: [ dx + dia, dy - dia + 1 ]
+ },
+ { instruction: LINE
+ , param: [ dx, dy - dia + 1 ]
+ },
+ { instruction: LINE
+ , param: [ dx, dy ]
+ },
+ { instruction: LINE
+ , param: [ dx + radius - 2, dy - 1 ]
+ },
+ { instruction: ARC
+ , param: [ dx + radius, dy + radius - 1, radius, north, east, false ]
+ },
+ { instruction: ARC
+ , param: [ dx + radius, dy + radius, radius, east, west, false ]
+ }
+ ];
+ case '6': [ { instruction: MOVE
+ , param: [ dx, dy + radius ]
+ },
+ { instruction: ARC
+ , param: [ dx + radius, dy + radius, radius, west + 2*pi, west, true ]
+ },
+ { instruction: ARC
+ , param: [ dx + radius, dy - radius + 1, radius, west, east - piSmall, false ]
+ }
+ ];
+ case '7': [ { instruction: MOVE
+ , param: [ dx, dy - dia + 1 ]
+ },
+ { instruction: LINE
+ , param: [ dx + dia, dy - dia + 1 ]
+ },
+ { instruction: LINE
+ , param: [ dx + dia, dy - dia + 3 ]
+ },
+ { instruction: LINE
+ , param: [ dx + 2 + 1, dy + radius -1 ]
+ },
+ { instruction: LINE
+ , param: [ dx + 2, dy + dia ]
+ }
+ ];
+ case '8': [ { instruction: MOVE
+ , param: [ dx + radius, dy ]
+ },
+ { instruction: ARC
+ , param: [ dx + radius, dy - radius, radius - 1, south, south + pi*2, false ]
+ },
+ { instruction: ARC
+ , param: [ dx + radius, dy + radius, radius, north, north + pi*2, true ]
+ }
+ ];
+ case '9': [ { instruction: MOVE
+ , param: [ dx + dia, dy - radius + 1 ]
+ },
+ { instruction: ARC
+ , param: [ dx + radius, dy - radius + 1, radius-0.5, east, east + pi*2, true ]
+ },
+ { instruction: ARC
+ , param: [ dx + radius, dy + radius, radius, east , west- 1.4*piSmall, false ]
+ }
+ ];
+ default: null;
+ }
+
+ }
+
+ public function write( str: String )
+ {
+ surface.beginPath();
+ for( ii in 0...str.length)
+ {
+ var letter = str.charAt( ii );
+ if( letter == " " )
+ {
+ nextLetter();
+ continue;
+ }
+ letter = letter.toLowerCase();
+ var letterCommands = letterChoose( letter );
+ if( letterCommands == null )
+ {
+ nextLetter();
+ continue;
+ }
+ for( jj in 0...letterCommands.length )
+ {
+ var drawCommand = letterCommands[ jj ];
+ var instruction = switch( drawCommand.instruction )
+ {
+ case MOVE: 'moveTo';
+ case LINE: 'lineTo';
+ case ARC: 'arc' ;
+ };
+ var param = drawCommandScale( drawCommand );
+ Reflect.callMethod ( surface
+ , Reflect.field( surface, instruction )
+ , param
+ );
+ }
+ nextLetter();
+ }
+ end();
+ }
+
+ public function drawCommandScale( command: DrawInstruction ): Array
+ {
+ var param = command.param;
+ var dy_ = dy;
+ var dx_ = dx;
+ return switch( command.instruction )
+ {
+ case MOVE, LINE:
+ [ scale*( param[ 0 ] - dx ) + dx_
+ , scale*( param[ 1 ] - dy ) + dy_
+ ];
+ case ARC:
+ [ scale*( param[ 0 ] - dx ) + dx_
+ , scale*( param[ 1 ] - dy ) + dy_
+ , scale*param[ 2 ]
+ , param[ 3 ]
+ , param[ 4 ]
+ , param[ 5 ]
+ ];
+ }
+ }
+
+ public function nextLetter()
+ {
+ dx += gap + Math.ceil( dia*scale );
+ }
+
+ public function end()
+ {
+ surface.stroke();
+ }
+
+}
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/utils/Movement.hx b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/utils/Movement.hx
new file mode 100644
index 00000000..8b9a0350
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/utils/Movement.hx
@@ -0,0 +1,60 @@
+
+package utils;
+
+class Movement
+{
+
+ // See this link for more information...
+ // http://jonmanatee.blogspot.com/2011/03/moving-beyond-linear-bezier.html
+ // you just need to use one for each axis..
+ // see http://www.codng.com/2005/07/intersecting-quadcurve2d-part-ii.html
+ // and then modify it to go through the point I think penner has a curveThru
+ // for instance see my code here:
+ // http://forums.swishzone.com/index.php?s=d8b09993f33ccb9361b069fda0bbae89&showtopic=923
+ //
+ public static function quadraticBezierThru ( t: Float
+ , startPoint: Float
+ , controlPoint: Float
+ , endPoint: Float
+ )
+ {
+
+ var newControlPoint = ( 2*controlPoint ) - .5*( startPoint + endPoint );
+ var u = 1 - t;
+ return Math.pow( u, 2) * startPoint + 2 * u * t * newControlPoint + Math.pow( t, 2 ) * endPoint;
+
+ }
+
+
+ public static function quadraticBezier ( t: Float
+ , startPoint: Float
+ , controlPoint: Float
+ , endPoint: Float
+ )
+ {
+
+ var u = 1 - t;
+ return Math.pow( u, 2) * startPoint + 2 * u * t * controlPoint + Math.pow( t, 2 ) * endPoint;
+
+ }
+
+
+ public static function cubicBezier( t: Float
+ , startPoint: Float
+ , controlPoint1: Float
+ , controlPoint2: Float
+ , endPoint: Float
+ )
+ {
+
+ var u = 1 - t;
+
+ return Math.pow( u, 3 ) * startPoint + 3 * Math.pow( u, 2 ) * t * controlPoint1 +
+ 3* u * Math.pow( t, 2 ) * controlPoint2 + Math.pow( t, 3 ) * endPoint;
+
+ }
+
+
+}
+
+
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/utils/Simple3d.hx b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/utils/Simple3d.hx
new file mode 100644
index 00000000..ca99861b
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/utils/Simple3d.hx
@@ -0,0 +1,40 @@
+
+package utils;
+typedef Point2D =
+{
+ var x: Float;
+ var y: Float;
+}
+typedef Point3D =
+{
+ > Point2D,
+ var z : Float;
+}
+
+class Simple3D
+{
+ public static inline var fl: Float = 420;
+
+ public function new()
+ {
+
+ }
+
+ public static inline function scale( z: Float )
+ {
+ return 1-(-z)/fl;
+ }
+
+ public static inline function twoD( p: Point3D ): Point2D
+ {
+ var s = scale( p.z );
+ return { x: p.x/s, y: p.y/s };
+ }
+
+ public static inline function rgbTwoD( rgb: Array, offSet: Point2D ): Point2D
+ {
+ var s = scale( rgb[2] );
+ return { x: rgb[0]/s + offSet.x, y: rgb[1]/s + offSet.y };
+ }
+
+}
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/utils/SimpleAtom.hx b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/utils/SimpleAtom.hx
new file mode 100644
index 00000000..63ea9db2
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/utils/SimpleAtom.hx
@@ -0,0 +1,266 @@
+
+package divtastic.rss;
+import js.Lib;
+import haxe.Http;
+import haxe.xml.Fast;
+
+typedef Feed =
+{
+
+ var id: String;
+ var title: String;
+ var updated: Date;
+ var link_atom: String;
+ var link_html: String;
+ var subtitle: String;
+
+}
+
+typedef Entry =
+{
+
+ var id: String;
+ var title: String;
+ var published: Date;
+ var updated: Date;
+ var author_name: String;
+ var content: String;
+ var link_html: String;
+
+}
+
+typedef Topic =
+{
+ var topic: String;
+ var entries: Array;
+}
+
+class SimpleAtom
+{
+
+ public var feedInfo: Feed;
+ public var entries: Array;
+ public var topics: Array;
+ private var file: String;
+ private var atomXML: Fast;
+
+
+ public function new()
+ {
+
+ }
+
+ public function load( file )
+ {
+
+ var r = new Http( file );
+ r.onError = Lib.alert;
+ r.onData = atomLoaded;
+ r.request( false );
+
+ }
+
+
+ public function atomLoaded( r )
+ {
+
+ atomXML = new Fast( Xml.parse( r ).firstElement() );
+ createFeedInfo();
+ createEntries();
+ }
+
+
+ private function createFeedInfo( )
+ {
+ feedInfo = { id: atomXML.node.id.innerData
+ , title: atomXML.node.title.innerData
+ , updated: createDate( atomXML.node.updated.innerData )
+ , link_atom: atomXML.nodes.link.first().att.href
+ , link_html: atomXML.nodes.link.last().att.href
+ , subtitle: atomXML.node.subtitle.innerData
+ }
+
+ }
+
+
+ // TODO: content here may need to be decoded to html
+ // TODO: Split up sorting as not all Atoms need topic sorting
+ // TODO: Add dispatchTo signal for when finished loading... and or parsing
+ public function createEntries()
+ {
+
+ var content: String;
+ entries = new Array();
+ var aEntries: Entry;
+
+ for( anEntry in atomXML.nodes.entry )
+ {
+ if( anEntry.hasNode.content )
+ {
+
+ content = anEntry.node.content.innerData;
+
+ }
+ else
+ {
+
+ content = anEntry.node.summary.innerData;
+
+ }
+ var content =
+ aEntries = { id: anEntry.node.id.innerData
+ , title: anEntry.node.title.innerData
+ , published: createDate( anEntry.node.published.innerData )
+ , updated: createDate( anEntry.node.updated.innerData )
+ , author_name: anEntry.node.author.node.name.innerData
+ , content: content
+ , link_html: anEntry.node.link.att.href
+ }
+
+ entries.push( aEntries );
+
+ }
+
+ entries.sort( byTopic );
+
+ topics = new Array();
+ var topic: Topic = null;
+ var currTopic = '';
+ var newTopic: String;
+ var topicEntries: Array= new Array();
+
+ for( i in 0...entries.length )
+ {
+
+ aEntries = entries[ i ];
+ newTopic = aEntries.title;
+
+ if( newTopic != currTopic )
+ {
+ if( topicEntries.length != 0 )
+ {
+ topicEntries.sort( byDate );
+ topic = { topic: aEntries.title, entries: topicEntries };
+ topics.push( topic );
+ }
+
+ topicEntries = new Array();
+
+ }
+
+ topicEntries.push( aEntries );
+
+ }
+ topics.push( topic );
+ //trace(entries.last());
+ trace(topics[0]);
+ }
+
+
+ private function byDate( a: Entry, b: Entry ): Int
+ {
+
+ return Reflect.compare( a.published, b.published );
+
+ }
+
+
+ private function byTopic( a: Entry, b: Entry ): Int
+ {
+
+ return Reflect.compare( a.title.toLowerCase(), b.title.toLowerCase() );
+
+ }
+
+
+ private function createDate( dateS: String ): Date
+ {
+
+ if( dateS.split('T').length != 2 || dateS.substr(dateS.length-1,1) != 'Z' )
+ {
+
+ trace( 'date format has failed please modify code!!') ;
+ return Date.now();
+
+ }
+
+ return new Date ( /* var year = */ Std.parseInt( dateS.substr( 0, 4 ) )
+ , /* var month = */ Std.parseInt( dateS.substr( 6, 2 ) )
+ , /* var day = */ Std.parseInt( dateS.substr( 8, 2 ) )
+ , /* var hour = */ Std.parseInt( dateS.substr( 10, 2 ) )
+ , /* var min = */ Std.parseInt( dateS.substr( 12, 2 ) )
+ , /* var sec = */ Std.parseInt( dateS.substr( 14, 2 ) )
+ );
+ }
+
+}
+
+
+/** Notes on Atom Dates **
+for this code and simplicity assumes date in nabble are as per the haxe mailing list atom:
+'YYYY-MM-DD' + 'T' + 'HH:MM:SS' + 'Z'
+
+but notes below for future reference
+
+ Standard for ARPA Internet Text Messages
+
+
+
+5. DATE AND TIME SPECIFICATION
+
+
+
+5.1. SYNTAX
+
+
+ date-time = [ day "," ] date time ; dd mm yy
+ ; hh:mm:ss zzz
+
+ day = "Mon" / "Tue" / "Wed" / "Thu"
+ / "Fri" / "Sat" / "Sun"
+
+ date = 1*2DIGIT month 2DIGIT ; day month year
+ ; e.g. 20 Jun 82
+
+ month = "Jan" / "Feb" / "Mar" / "Apr"
+ / "May" / "Jun" / "Jul" / "Aug"
+ / "Sep" / "Oct" / "Nov" / "Dec"
+
+ time = hour zone ; ANSI and Military
+
+ hour = 2DIGIT ":" 2DIGIT [":" 2DIGIT]
+ ; 00:00:00 - 23:59:59
+
+ zone = "UT" / "GMT" ; Universal Time
+ ; North American : UT
+ / "EST" / "EDT" ; Eastern: - 5/ - 4
+ / "CST" / "CDT" ; Central: - 6/ - 5
+ / "MST" / "MDT" ; Mountain: - 7/ - 6
+ / "PST" / "PDT" ; Pacific: - 8/ - 7
+ / 1ALPHA ; Military: Z = UT;
+ ; A:-1; (J not used)
+ ; M:-12; N:+1; Y:+12
+ / ( ("+" / "-") 4DIGIT ) ; Local differential
+ ; hours+min. (HHMM)
+
+
+5.2. SEMANTICS
+
+
+ If included, day-of-week must be the day implied by the date
+ specification.
+
+ Time zone may be indicated in several ways. "UT" is Univer-
+ sal Time (formerly called "Greenwich Mean Time"); "GMT" is per-
+ mitted as a reference to Universal Time. The military standard
+ uses a single character for each zone. "Z" is Universal Time.
+ "A" indicates one hour earlier, and "M" indicates 12 hours ear-
+ lier; "N" is one hour later, and "Y" is 12 hours later. The
+ letter "J" is not used. The other remaining two forms are taken
+ from ANSI standard X3.51-1975. One allows explicit indication of
+ the amount of offset from UT; the other uses common 3-character
+ strings for indicating time zones in North America.
+
+
+ August 13, 1982 - 26 - RFC #822
+*/
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/utils/SwipeView.hx b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/utils/SwipeView.hx
new file mode 100644
index 00000000..6823aad7
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/utils/SwipeView.hx
@@ -0,0 +1,203 @@
+
+package utils;
+import zpartanlite.Enumerables;
+import core.DisplayDiv;
+import zpartanlite.Pages;
+import zpartanlite.DispatchTo;
+import haxe.Timer;
+
+class SwipeView
+{
+
+
+ private var velocity: Int;
+ public var index0: Int;
+ public var index1: Int;
+
+ private var _old: DisplayDiv;
+ private var _curr: DisplayDiv;
+ private var _oldContent: DisplayDiv;
+ private var _distance: Int;
+ private var pages: Pages;
+ private var _direction: Orientation;
+ private var _enabled: Bool;
+ public var pageChange: DispatchTo;
+ private var tim: Float;
+ private var timerMovement: Timer;
+
+ // _oldcontent should be within _old for this class to work
+ public function new( direction_: Orientation
+ , distance_: Int
+ , curr_: DisplayDiv
+ , old_: DisplayDiv
+ , oldContent_: DisplayDiv
+ , pages_: Pages
+ )
+ {
+
+ pageChange = new DispatchTo();
+ _direction = direction_;
+ _distance = distance_;
+ _curr = curr_;
+ _old = old_;
+ pages = pages_;
+ _oldContent = oldContent_;
+ _curr.setClip();
+ _old.setClip();
+ _oldContent.setClip();
+ _enabled = true;
+ velocity = 500;
+ pages.pageChange.add( setImage );
+
+ }
+
+
+ public var orientation( get_orientation, set_orientation ):Orientation;
+
+ private function get_orientation():Orientation
+ {
+ return _direction;
+ }
+
+ public function set_orientation( val: Orientation ): Orientation
+ {
+ _direction = val;
+ return val;
+ }
+
+
+ public var enabled( get_enabled, set_enabled ):Bool;
+
+ private function get_enabled(): Bool
+ {
+
+ return _enabled;
+
+ }
+
+ private function set_enabled( val: Bool )
+ {
+ var was = _enabled;
+ _enabled = val;
+ if( _enabled && was != _enabled )
+ {
+ pages.pageChange.add( setImage );
+ }
+ else if( !_enabled && was != _enabled )
+ {
+ pages.pageChange.remove( setImage );
+ }
+ return _enabled;
+ }
+
+
+ public function setImage()
+ {
+ _curr.visible = false;
+ _oldContent.visible = false;
+ var s: Int;
+ switch( pages.dir )
+ {
+ case Forward:
+ _oldContent.set_image( pages.last );
+ index0 = pages.getLastIndex();
+ _curr.set_image( pages.curr );
+ index1 = pages.getIndex();
+ s = 0;
+ case Back:
+ index0 = pages.getIndex();
+ _oldContent.set_image( pages.curr );
+ _curr.set_image( pages.last );
+ index1 = pages.getLastIndex();
+ s = _distance;
+ }
+ pageChange.dispatch();
+ switch( _direction )
+ {
+ case Horizontal:
+ _curr.width = s;
+ _old.width = _distance - s;
+ _old.x = _curr.x + s;
+ _oldContent.x = -s;
+ case Vertical:
+ _curr.height = s;
+ _old.height = _distance - s;
+ _old.y = _curr.y + s;
+ _oldContent.y = -s;
+ }
+ _curr.visible = true;
+ _oldContent.visible = true;
+ if( timerMovement != null )
+ {
+ timerMovement.stop();
+ timerMovement = null;
+ }
+ timerMovement = new Timer( 10 );
+ tim = 0;
+ var duration = 100;
+ switch( _direction )
+ {
+ case Horizontal:
+ timerMovement.run = swipeHorizMovement.bind( duration, pages.dir );
+ case Vertical:
+ timerMovement.run = swipeVertMovement.bind( duration, pages.dir );
+ }
+ }
+
+ private function swipeHorizMovement( duration: Int, travel: Travel )
+ {
+ if ( tim > duration )
+ {
+ tim = 0;
+ timerMovement.stop();
+ timerMovement = null;
+ }
+ else
+ {
+ var e: Float;
+ switch( travel )
+ {
+ case Forward:
+ e = _distance*tim/duration;
+ case Back:
+ e = _distance - _distance*tim/duration;
+ }
+
+ _curr.width = e;
+ _old.width = _distance - e;
+ _old.x = _curr.x + e;
+ _oldContent.x = -e;
+ tim++;
+ }
+
+ }
+
+ private function swipeVertMovement( duration: Int, travel: Travel )
+ {
+ if ( tim > duration )
+ {
+ tim = 0;
+ timerMovement.stop();
+ timerMovement = null;
+ }
+ else
+ {
+
+ var e: Float;
+ switch( travel )
+ {
+ case Forward:
+ e = _distance*tim/duration;
+ case Back:
+ e = _distance - _distance*tim/duration;
+ }
+
+ _curr.height = e;
+ _old.height = _distance - e;
+ _old.y = _curr.y + e;
+ _oldContent.y = -e;
+ tim++;
+ }
+ }
+
+}
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/utils/WindowView.hx b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/utils/WindowView.hx
new file mode 100644
index 00000000..f6183760
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/utils/WindowView.hx
@@ -0,0 +1,236 @@
+
+package utils;
+
+import core.DisplayDiv;
+import core.GradientFiller;
+import haxe.Timer;
+import zpartanlite.Enumerables;
+import core.WebBrowser;
+import zpartanlite.DispatchTo;
+
+// Example draggable window.
+// Note: Requires fillColor.png for header bar.
+// The displayDiv for WindowView is passed in rather than inherited so that a Divtastic DisplayDiv can be used if required.
+
+using core.DivDrawing;
+class WindowView
+{
+
+ public static inline var headerHeight: Int = 20;
+ private var headerBarBg: DisplayDiv;
+ private var bodyBg: DisplayDiv;
+ private var headerBarTitle: DisplayDiv;
+ private var minimizeButton: DisplayDiv;
+ private var minimizeButtonBg: DisplayDiv;
+ private var heightMax: Int;
+ private var widthMax: Int;
+ private var widthMin: Int;
+ private var _holder: DisplayDiv;//Divtastic;
+ private var gradFill: GradientFiller;
+ public var onMinimized: DispatchTo;
+ public var onMaximized: DispatchTo;
+ public var timerMovement: Timer;
+ public var tim: Float;
+
+ public function new( holder_: DisplayDiv,
+ title_: String,
+ x_: Int,
+ y_: Int,
+ width_: Int,
+ height_: Int,
+ fill_: String
+ )
+ {
+
+ onMinimized = new DispatchTo();
+ onMaximized = new DispatchTo();
+ _holder = holder_;
+ _holder.x = x_;
+ _holder.y = y_;
+ _holder.width = width_;
+ _holder.height = height_;
+ heightMax = height_;
+ widthMax = width_;
+ headerBarBg = new DisplayDiv();
+ headerBarBg.tile = true;
+ headerBarBg.x = 0;
+ headerBarBg.y = 0;
+ headerBarBg.height = headerHeight;
+ headerBarBg.width = width_;
+
+ headerBarBg.set_image('img/fillColor.png');
+ _holder.addChild( headerBarBg );
+ headerBarBg.setupParentDrag();
+
+ headerBarTitle = new DisplayDiv();
+ headerBarTitle.x = 9;
+ headerBarTitle.y = 4;
+
+
+ headerBarTitle.getStyle().cursor = "pointer";
+ headerBarBg.addChild( headerBarTitle );
+
+
+ var txStyle = headerBarTitle.getStyle();
+ txStyle.fontFamily = 'Arial';
+ txStyle.color = '#aaaaaa';
+ txStyle.lineHeight = '1.3';
+ txStyle.letterSpacing = '1px';
+ txStyle.fontSize = '10px';
+ title = title_;
+ widthMin = Std.int( headerBarTitle.width + headerBarTitle.x + 30 );
+
+ bodyBg = new DisplayDiv();
+ bodyBg.x = 0;
+ bodyBg.fill = fill_;
+ bodyBg.y = headerHeight;
+ bodyBg.height = height_ - headerHeight;
+ bodyBg.width = width_;
+
+ _holder.addChild( bodyBg );
+ //_holder.alpha = 0.9;
+ minimizeButton = new DisplayDiv();
+ minimizeButton.x = width_ - 18 - 4 + 1;
+ minimizeButton.y = 7;
+ minimizeButton.width = 15;
+ minimizeButton.height = 10;
+ var closeDivs = minimizeButton.drawGradHexagon( 0
+ , 0
+ , 9 + 2
+ , 6
+ , 0xd67297
+ , 0xd67297
+ , 1
+ , Horizontal
+ );
+ headerBarBg.addChild( minimizeButton );
+
+ //currently not supported
+ if ( WebBrowser.browserType != IE )
+ {
+ _holder.getStyle().overflow = 'Hidden';
+ }
+
+ gradFill = new GradientFiller( closeDivs );
+ minPressSetup() ;
+
+ }
+
+ private var _title: String;
+ public var title( get_title, set_title ): String;
+
+ public function get_title(): String
+ {
+ return _title;
+ }
+
+ public function set_title( title_: String ): String
+ {
+ headerBarTitle.text = title_;
+ _title = title_;
+ widthMin = Std.int( headerBarTitle.width + headerBarTitle.x + 30 );
+ return title_;
+ }
+
+
+ public function set_fill( fill: Int ): Int
+ {
+ //TODO: Need to simplify this code!!
+ bodyBg.fill = '#' + StringTools.lpad( StringTools.hex( (fill >> 16) << 16 | ( fill >> 8 & 0xff) << 8 | ( fill & 0xff ) ), '0', 6 );
+ return fill;
+ }
+
+
+ public function minPressSetup()
+ {
+
+ minimizeButton.press.swap( maximize, minimize );
+ onMinimized.dispatch();
+
+ }
+
+
+ public function minimize()
+ {
+
+ gradFill.fill( 0x9d9e6a, 0x9d9e6a );
+ if( timerMovement != null )
+ {
+ timerMovement.stop();
+ timerMovement = null;
+ }
+ timerMovement = new Timer( 10 );
+ tim = 0;
+ var duration = 50;
+ timerMovement.run = minimizeMove.bind( _holder, duration );
+ }
+
+ public function minimizeMove( instance: DisplayDiv, duration )
+ {
+ if ( tim > duration )
+ {
+ tim = 0;
+ timerMovement.stop();
+ timerMovement = null;
+ maxPressSetup();
+ }
+ else
+ {
+ var t = 1 - tim/duration;
+ instance.height = t*( heightMax - headerHeight ) + headerHeight;
+ instance.width = t*( widthMax - widthMin ) + widthMin;
+ minimizeButton.x = instance.width - 18 - 4 + 1;
+ tim++;
+ }
+
+ }
+
+
+ public function maxPressSetup()
+ {
+
+ minimizeButton.press.swap( minimize, maximize );
+ onMaximized.dispatch();
+
+ }
+
+
+ public function maximize()
+ {
+
+ gradFill.fill( 0xd67297, 0xd67297 );
+ if( timerMovement != null )
+ {
+ timerMovement.stop();
+ timerMovement = null;
+ }
+ timerMovement = new Timer( 10 );
+ tim = 0;
+ var duration = 50;
+ timerMovement.run = maximizeMove.bind( _holder, duration );
+ }
+
+ public function maximizeMove( instance: DisplayDiv, duration )
+ {
+ if ( tim > duration )
+ {
+ tim = 0;
+ timerMovement.stop();
+ timerMovement = null;
+ minPressSetup();
+ }
+ else
+ {
+ var t = tim/duration;
+ instance.height = t*( heightMax - headerHeight ) + headerHeight;
+ instance.width = t*( widthMax - widthMin ) + widthMin;
+ minimizeButton.x = instance.width - 18 - 4 + 1;
+ tim++;
+ }
+
+ }
+
+
+ // TODO add functionality for changing height and width of box.
+
+}
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/zpartanlite/DispatchTo.hx b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/zpartanlite/DispatchTo.hx
new file mode 100644
index 00000000..f8df2637
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/zpartanlite/DispatchTo.hx
@@ -0,0 +1,296 @@
+
+package zpartanlite;
+
+class DispatchTo
+{
+
+ // don't use an array unless there are lots of signals.
+ // have to return dynamic because sometimes need to allow a return type not void
+ private var func0: Void -> Void ;
+ private var times0: Int;
+
+ private var func: Array Void> ;
+ private var times: Array ;
+ public var length( get_length, null ): Int ;
+
+ // Allows events like mouse down to be added removed.
+ public var tellEnabled: Void -> Void;
+ public var tellDisabled: Void -> Void;
+ public var kill: Void -> Void;
+
+ public function enableKill()
+ {
+
+ kill = killAll;
+
+ }
+
+ public function disableKill()
+ {
+
+ kill = function()
+ {
+ trace("Can't kill other listeners unless enableKill");
+ }
+
+ }
+
+ private function get_length(): Int
+ {
+
+ if( func == null )
+ if( func0 != null )
+ {
+
+ return 1;
+
+ }
+ else
+ {
+ return null;
+ }
+
+ return func.length;
+
+ }
+
+
+ public function new()
+ {
+
+ // by default...
+ disableKill();
+
+ }
+
+
+ public function add( f_: Void -> Void, ?once: Bool, ?amount: Int )
+ {
+
+ // Store first...
+
+ if( length == null )
+ {
+
+ func0 = f_;
+ if( tellEnabled != null )
+ {
+ tellEnabled();
+ }
+ if( once != null )
+ {
+
+ if( once == true )
+ {
+
+ times0 = 1;
+
+ }
+ else
+ {
+
+ times0 = -1;
+
+ }
+
+ }
+ else if( amount != null )
+ {
+
+ times0 = amount;
+
+ }
+ else
+ {
+ times0 = -1;
+ }
+
+ return;
+
+ }
+ else if( func == null )
+ {
+
+ func = new Array() ;
+ times = new Array() ;
+ func.push( func0 );
+ times.push( times0 );
+ func0 = null;
+ times0 = null;
+ }
+
+ // Store second...
+
+ func.push( f_ ) ;
+
+ if( once != null )
+ {
+
+ if( once == true )
+ {
+
+ times.push( 1 ) ;
+
+ }
+ else
+ {
+
+ times.push( -1 ) ;
+
+ }
+
+ }
+ else if( amount != null )
+ {
+
+ times.push( amount ) ;
+
+ }
+ else
+ {
+
+ times.push( -1 ) ;
+
+ }
+
+ }
+
+
+ public function swap( current_: Void -> Void, new_: Void -> Void )
+ {
+
+ remove( current_ );
+ add( new_ );
+
+ }
+
+
+ public function remove( f_: Void -> Void )
+ {
+
+ if( length == null ) return;
+ if( length == 1 )
+ {
+
+ if( Reflect.compareMethods( f_, func0 ) )
+ {
+
+ func0 = null;
+ times0 = null;
+ if( tellDisabled != null )
+ {
+
+ tellDisabled();
+
+ }
+ }
+ return;
+ }
+ for( i in 0...func.length )
+ {
+
+ if( Reflect.compareMethods( func[ i ], f_ ) )
+ {
+
+ func.splice( i, 1 ) ;
+ times.splice( i, 1 ) ;
+
+ }
+
+ }
+ if( length == 1 )
+ {
+ func0 = func[0];
+ times0 = times[0];
+ func = null;
+ times0 = null;
+ }
+ }
+
+ // This is private by default and accessed by kill if enableKill
+ // seems over the top but should not be able to remove all listeners by default
+ // only in special cases.
+ private function killAll()
+ {
+
+ if( length == 1 )
+ {
+
+ func0 = null;
+ times0 = null;
+ return;
+
+ }
+
+ for( i in 0...func.length )
+ {
+
+ func.splice( i, 1 ) ;
+ times.splice( i, 1 ) ;
+
+ }
+ func = new Array() ;
+ times = new Array() ;
+
+ }
+
+
+ public function dispatch()
+ {
+
+ if( length == null ) return;
+ var count: Int ;
+
+ if( length == 1 )
+ {
+
+ func0();
+ if( times0 == -1 )
+ {
+ // don't remove if -1 as implies infinite Signal use until removed.
+ }
+ else
+ {
+ times0--;
+ if( times0 == 0 )
+ {
+ remove( func0 );
+ }
+ }
+ return;
+ }
+
+ for( i in 0...func.length )
+ {
+
+ func[ i ]() ;
+ count = times[ i ] ;
+
+ if( count == -1 )
+ {
+
+ // don't remove if -1 as implies infinite Signal use until removed.
+
+ }
+ else
+ {
+
+ count--;
+ times[ i ] = count ;
+
+ if( count == 0 )
+ {
+
+ remove( func[ i ] );
+ //func.splice( i, 1 ) ;
+ //times.splice( i, 1 ) ;
+
+ }
+
+ }
+
+ }
+
+ }
+
+}
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/zpartanlite/Enumerables.hx b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/zpartanlite/Enumerables.hx
new file mode 100644
index 00000000..c78bcaa6
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/zpartanlite/Enumerables.hx
@@ -0,0 +1,24 @@
+
+package zpartanlite;
+
+enum Compass
+{
+ North;
+ South;
+ East;
+ West;
+}
+
+enum Orientation
+{
+ Horizontal;
+ Vertical;
+}
+
+enum Travel
+{
+ Forward;
+ Back;
+}
+
+class Enumerables{}
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/zpartanlite/Pages.hx b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/zpartanlite/Pages.hx
new file mode 100644
index 00000000..643c5edd
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/divtastic/zpartanlite/Pages.hx
@@ -0,0 +1,305 @@
+
+package zpartanlite;
+import zpartanlite.Enumerables;
+
+class Pages
+{
+
+
+ private var index: Int ;
+ private var lastIndex: Int ;
+ private var len: Int ;
+ private var order: Array ;
+ private var history: Array ;
+ public var circle: Bool ;
+ public var last: T ;
+ public var curr: T ;
+ public var pageChange: DispatchTo ;
+ public var hideNext: DispatchTo ;
+ public var hidePrev: DispatchTo ;
+ public var dir: Travel;
+ public var looped: DispatchTo ;
+
+ public function new( ?arr_: Array, ?circle_: Bool = false )
+ {
+
+ circle = circle_ ;
+ pageChange = new DispatchTo() ;
+ hideNext = new DispatchTo() ;
+ hidePrev = new DispatchTo() ;
+ looped = new DispatchTo() ;
+ reset( arr_ ) ;
+
+ }
+
+
+ public function reset( ?arr_: Array ) : Void
+ {
+
+ if( arr_ == null )
+ {
+ order = new Array() ;
+ }
+ else
+ {
+ order = arr_ ;
+ }
+ index = 0;
+ len = order.length;
+ history = new Array() ;
+
+ }
+
+
+ public function next() : T
+ {
+
+ lastIndex = index ;
+ last = order[ index ];
+ dir = Forward;
+
+ index++ ;
+ if( index == len )
+ {
+ if( circle )
+ {
+ index = 0 ;
+ looped.dispatch();
+ }
+ else
+ {
+ index = len - 1 ;
+ }
+ }
+
+ curr = order[ index ] ;
+ if( lastIndex != index )
+ {
+
+ history.push( index ) ;
+
+ if( !circle )
+ {
+
+ if( !hasNext() )
+ {
+
+ hideNext.dispatch();
+
+ }
+
+ }
+ pageChange.dispatch();
+
+ }
+
+ return curr;
+
+ }
+
+
+ public function previous(): T
+ {
+
+ lastIndex = index ;
+ last = order[ index ];
+ dir = Back;
+
+ index-- ;
+ if( index == -1 )
+ {
+
+ if( circle )
+ {
+
+ index = len - 1 ;
+
+ }
+ else
+ {
+
+ index = 0 ;
+ }
+
+ }
+
+ curr = order[ index ];
+ if( lastIndex != index )
+ {
+
+ history.push( index ) ;
+
+ if( !circle )
+ {
+
+ if( !hasPrevious() )
+ {
+
+ hidePrev.dispatch();
+
+ }
+
+ }
+ pageChange.dispatch();
+ }
+
+
+ return curr;
+
+ }
+
+
+ public function getCurrent(): T
+ {
+
+ return order[ index ] ;
+
+ }
+
+
+ public function hasPrevious(): Bool
+ {
+
+ if( circle )
+ {
+
+ return true ;
+
+ }
+
+ if( index == 0 )
+ {
+
+ return false ;
+
+ }
+
+ return true ;
+
+ }
+
+
+ public function hasNext() : Bool
+ {
+
+ if( circle )
+ {
+
+ return true ;
+
+ }
+
+ if( index == len )
+ {
+
+ return false ;
+
+ }
+
+ return true ;
+
+ }
+
+
+ public function goto( index_: Int ): T
+ {
+
+ lastIndex = index ;
+ last = order[ index ] ;
+
+
+ index = index_ ;
+
+ curr = order[ index ];
+ if( lastIndex != index )
+ {
+
+ history.push( index ) ;
+
+ if( !circle )
+ {
+
+ if( !hasNext() )
+ {
+
+ hideNext.dispatch();
+
+ }
+ if( !hasPrevious() )
+ {
+
+ hidePrev.dispatch();
+
+ }
+ }
+
+ pageChange.dispatch();
+
+ }
+
+
+ return curr;
+
+ }
+
+
+ public function back(): T
+ {
+
+ lastIndex = index ;
+ last = order[ index ] ;
+
+ index = history.pop() ;
+
+ if( lastIndex != index )
+ {
+ if( !circle )
+ {
+
+ if( !hasNext() )
+ {
+
+ hideNext.dispatch() ;
+
+ }
+ if( !hasPrevious() )
+ {
+
+ hidePrev.dispatch() ;
+
+ }
+
+ }
+ pageChange.dispatch() ;
+
+ }
+
+ curr = order[ index ] ;
+ return curr;
+
+ }
+
+ public function isLast():Bool
+ {
+
+ if( index == len - 1 ) return true;
+ return false;
+
+ }
+
+ public function getIndex(): Int
+ {
+
+ return index ;
+
+ }
+
+ public function getLastIndex(): Int
+ {
+
+ return lastIndex;
+
+ }
+
+
+}
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawx/JigsawMagicNumbers.hx b/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawx/JigsawMagicNumbers.hx
new file mode 100644
index 00000000..142538ec
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawx/JigsawMagicNumbers.hx
@@ -0,0 +1,13 @@
+package jigsawx;
+
+class JigsawMagicNumbers{
+ // move to external file
+ public static inline var dMore: Float = 12*2/1.5;
+ public static inline var dinout: Float = 5*2/1.5;
+ public static inline var ellipseSmallx: Float = 2*18/6/1.5;
+ public static inline var ellipseSmally: Float = 2*11/6/1.5;
+ public static inline var ellipseLargex: Float = 2*45/8/1.5;
+ public static inline var ellipseLargey: Float = 2*18*2/8/1.5;
+ public static inline var stepSize: Float = 10/1.5;
+
+}
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawx/JigsawPiece.hx b/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawx/JigsawPiece.hx
new file mode 100644
index 00000000..eee73584
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawx/JigsawPiece.hx
@@ -0,0 +1,189 @@
+package jigsawx;
+import jigsawx.JigsawSideData;
+import jigsawx.math.Vec2;
+import jigsawx.JigsawMagicNumbers;
+enum Compass{
+ NORTH;
+ SOUTH;
+ EAST;
+ WEST;
+}
+class JigsawPiece{
+ public var enabled: Bool;
+ private var curveBuilder: OpenEllipse;
+ private var stepAngle: Float;
+ private var centre: Vec2;
+ private var points: Array;
+ public var sideData: JigsawPieceData;
+ private var first: Vec2;
+ public var xy: Vec2;
+ public var row: Int;
+ public var col: Int;
+ public function new( xy_: Vec2
+ , row: Int
+ , col: Int
+ , lt: Vec2, rt: Vec2, rb: Vec2, lb: Vec2
+ , sideData_: JigsawPieceData
+ ){
+ enabled = true;
+ xy = new Vec2( xy_.x, xy_.y );
+ sideData = sideData_;
+ points = [];
+ stepAngle = JigsawMagicNumbers.stepSize*Math.PI/180;
+ first = lt;
+ // NORTH side
+ if( sideData.north != null ) createVertSide( lt, rt, sideData.north, NORTH );
+ points.push( rt );
+ // EAST side
+ if( sideData.east != null ) createHoriSide( rt, rb, sideData.east, EAST );
+ points.push( rb );
+ // SOUTH side
+ if( sideData.south != null ) createVertSide( rb, lb, sideData.south, SOUTH );
+ points.push( lb );
+ // WEST side
+ if( sideData.west != null ) createHoriSide( lb, lt, sideData.west, WEST );
+ points.push( lt );
+ }
+ public function getPoints(): Array {
+ return points;
+ }
+ public function getFirst(): Vec2 {
+ return first;
+ }
+ private function createVertSide( A: Vec2
+ , B: Vec2
+ , side: JigsawSideData
+ , compass: Compass
+ ){
+ drawSide( A.x + ( B.x - A.x )/2 + JigsawMagicNumbers.dMore/2 - side.squew*( JigsawMagicNumbers.dMore )
+ , A.y + ( B.y - A.y )/2 + JigsawMagicNumbers.dinout/2 - side.inout*( JigsawMagicNumbers.dinout )
+ , side
+ , compass
+ );
+ }
+ private function createHoriSide ( A: Vec2
+ , B: Vec2
+ , side: JigsawSideData
+ , compass: Compass
+ ){
+
+ drawSide( A.x + ( B.x - A.x )/2 + JigsawMagicNumbers.dinout/2 - side.inout*( JigsawMagicNumbers.dinout )
+ , A.y + ( B.y - A.y )/2 + JigsawMagicNumbers.dMore/2 - side.squew*( JigsawMagicNumbers.dMore )
+ , side
+ , compass
+ );
+ }
+ private function drawSide( dx: Float, dy: Float, sideData: JigsawSideData, compass: Compass ){
+ var halfPI = Math.PI/2;
+ var dimensions = new Vec2();
+ var offsetCentre = new Vec2();
+ var bubble = sideData.bubble;
+ centre =
+ switch( compass )
+ {
+ case NORTH: new Vec2( dx, dy + 6*switch bubble{ case IN: 1; case OUT: -1; } );
+ case EAST: new Vec2( dx - 6*switch bubble{ case IN: 1; case OUT: -1; }, dy );
+ case SOUTH: new Vec2( dx, dy - 6*switch bubble{ case IN: 1; case OUT: -1; } );
+ case WEST: new Vec2( dx + 6*switch bubble{ case IN: 1; case OUT: -1; }, dy );
+ }
+ curveBuilder = new OpenEllipse();
+ curveBuilder.centre = centre;
+ // large Arc
+ dimensions.x = ( 1 + ( 0.5 - sideData.centreWide )/2 ) * JigsawMagicNumbers.ellipseLargex;
+ dimensions.y = ( 1 + ( 0.5 - sideData.centreHi )/2 ) * JigsawMagicNumbers.ellipseLargex;
+ curveBuilder.dimensions = dimensions;
+ curveBuilder.beginAngle = Math.PI/8;
+ curveBuilder.finishAngle = -Math.PI/8;
+ curveBuilder.stepAngle = stepAngle;
+ curveBuilder.rotation = switch bubble { case IN: 0; case OUT: Math.PI; }
+ switch( compass ){
+ case NORTH:
+ case EAST: curveBuilder.rotation += halfPI;
+ case SOUTH: curveBuilder.rotation += Math.PI;
+ case WEST: curveBuilder.rotation += 3*halfPI;
+ }
+ var secondPoints = curveBuilder.getRenderList();
+ if( bubble == IN ) secondPoints.reverse();
+ var theta = curveBuilder.beginAngle - curveBuilder.finishAngle + Math.PI;
+ var cosTheta = Math.cos( theta );
+ var sinTheta = Math.sin( theta );
+ var hyp = curveBuilder.getBeginRadius();
+ // left Arc
+ dimensions.x = ( 1 + ( 0.5 - sideData.leftWide )/2 ) * JigsawMagicNumbers.ellipseSmallx;
+ dimensions.y = ( 1 + ( 0.5 - sideData.leftHi )/2 ) * JigsawMagicNumbers.ellipseSmally;
+ curveBuilder.dimensions = dimensions;
+ curveBuilder.beginAngle = halfPI;
+ curveBuilder.finishAngle = -halfPI;
+ curveBuilder.stepAngle = stepAngle;
+ curveBuilder.rotation = theta + switch bubble { case IN: 0; case OUT: halfPI; };
+ switch( compass ){
+ case NORTH:
+ case EAST: curveBuilder.rotation += halfPI;
+ case SOUTH: curveBuilder.rotation += Math.PI;
+ case WEST: curveBuilder.rotation += 3*halfPI;
+ }
+ var hypLeft = hyp + curveBuilder.dimensions.x;
+ switch( compass ){
+ case NORTH:
+ offsetCentre.x = centre.x + hypLeft*cosTheta;
+ offsetCentre.y = centre.y + switch bubble { case IN: hypLeft*sinTheta; case OUT: -hypLeft*sinTheta; }
+ case EAST:
+ offsetCentre.x = centre.x + switch bubble { case IN: -hypLeft*cosTheta; case OUT: hypLeft*cosTheta; }
+ offsetCentre.y = centre.y + hypLeft*sinTheta;
+ case SOUTH:
+ offsetCentre.x = centre.x - hypLeft*cosTheta;
+ offsetCentre.y = centre.y - switch bubble { case IN: hypLeft*sinTheta; case OUT: - hypLeft*sinTheta; }
+ case WEST:
+ offsetCentre.x = centre.x + switch bubble { case IN: hypLeft*cosTheta; case OUT: -hypLeft*cosTheta; }
+ offsetCentre.y = centre.y - hypLeft*sinTheta;
+ }
+ curveBuilder.centre = offsetCentre;
+ var startPoint = curveBuilder.getBegin();
+ var firstPoints = curveBuilder.getRenderList();
+ if( sideData.bubble == OUT ) firstPoints.reverse();
+ firstPoints.pop();
+ firstPoints.pop();
+ secondPoints.shift();
+ secondPoints.shift();
+ secondPoints.shift();
+ points = points.concat( firstPoints.concat( secondPoints ) );
+ // right Arc
+ dimensions.x = ( 1 + ( 0.5 - sideData.rightWide )/2 ) * JigsawMagicNumbers.ellipseSmallx;
+ dimensions.y = ( 1 + ( 0.5 - sideData.rightHi )/2 ) * JigsawMagicNumbers.ellipseSmally;
+ curveBuilder.dimensions = dimensions;
+ curveBuilder.beginAngle = halfPI;
+ curveBuilder.finishAngle = -halfPI;
+ curveBuilder.stepAngle = stepAngle;
+ curveBuilder.rotation = theta + switch bubble { case IN: - halfPI; case OUT: Math.PI; };
+ switch( compass ){
+ case NORTH:
+ case EAST: curveBuilder.rotation += halfPI;
+ case SOUTH: curveBuilder.rotation += Math.PI;
+ case WEST: curveBuilder.rotation += 3*halfPI;
+ }
+ var hypRight = hyp + curveBuilder.dimensions.x;
+ switch( compass ){
+ case NORTH:
+ offsetCentre.x = centre.x - hypRight*cosTheta;
+ offsetCentre.y = centre.y + switch bubble { case IN: hypRight*sinTheta; case OUT: -hypRight*sinTheta; };
+ case EAST:
+ offsetCentre.x = centre.x + switch bubble { case IN: -hypLeft*cosTheta; case OUT: hypLeft*cosTheta; }
+ offsetCentre.y = centre.y - hypLeft*sinTheta;
+ case SOUTH:
+ offsetCentre.x = centre.x + hypRight*cosTheta;
+ offsetCentre.y = centre.y - switch bubble { case IN: hypRight*sinTheta; case OUT: -hypRight*sinTheta; };
+ case WEST:
+ offsetCentre.x = centre.x + switch bubble { case IN: hypLeft*cosTheta; case OUT: -hypLeft*cosTheta; }
+ offsetCentre.y = centre.y + hypLeft*sinTheta;
+ }
+ curveBuilder.centre = offsetCentre;
+ var thirdPoints = curveBuilder.getRenderList();
+ if( bubble == OUT ) thirdPoints.reverse();
+ thirdPoints.shift();
+ thirdPoints.shift();
+ points.pop();
+ points.pop();
+ points.pop();
+ points = points.concat( thirdPoints );
+ }
+}
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawx/JigsawSideData.hx b/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawx/JigsawSideData.hx
new file mode 100644
index 00000000..2a42b02c
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawx/JigsawSideData.hx
@@ -0,0 +1,93 @@
+package jigsawx;
+typedef JigsawPieceData = {
+ var north: JigsawSideData;
+ var east: JigsawSideData;
+ var south: JigsawSideData;
+ var west: JigsawSideData;
+}
+enum Bubble{
+ IN;
+ OUT;
+}
+class JigsawSideData{
+ // if the nobble is IN OUT or null ( flat side )
+ public var bubble: Bubble;
+ //offsets random multiplier
+ public var squew: Float;
+ // inout random multiplier
+ public var inout: Float;
+ //ellipse width and height random multiplier, drawn in the order left, centre, right
+ public var leftWide: Float;
+ public var leftHi: Float;
+ public var centreWide: Float;
+ public var centreHi: Float;
+ public var rightWide: Float;
+ public var rightHi: Float;
+ // returns half a jigsawPieceData, the other side is populated from piece above and from left
+ public static function halfPieceData(): JigsawPieceData{
+ #if !noRandom return { north: null, east: create(), south: create(), west: null };
+ // Test use -D noRandom
+ #else return { north: null, east: createSimple(), south: createSimple(), west: null };
+ #end
+ }
+ private static function createBubble(): Bubble {
+ return ( Math.round( Math.random() ) == 1 )? IN: OUT;
+ }
+ private static function swapBubble( bubble: Bubble ): Bubble {
+ if( bubble == OUT ) return IN;
+ if( bubble == IN ) return OUT;
+ return null;
+ }
+ // reflect side
+ public static function reflect( j: JigsawSideData ): JigsawSideData {
+ var side = new JigsawSideData();
+ side.bubble = swapBubble( j.bubble );
+ //left right or up dawn offset.
+ side.squew = j.squew;
+ // in out
+ side.inout = j.inout;
+ // radii of ellipses
+ side.leftWide = j.rightWide;
+ side.leftHi = j.rightHi;
+ side.centreWide = j.centreWide;
+ side.centreHi = j.centreHi;
+ side.rightWide = j.leftWide;
+ side.rightHi = j.leftHi;
+ return side;
+ }
+ // when you want to test no random.
+ public static function createSimple(): JigsawSideData {
+ var side = new JigsawSideData();
+ side.bubble = createBubble();
+ //left right or up dawn offset.
+ side.squew = 0.5;
+ // in out
+ side.inout = 0.5;
+ // radii of ellipses
+ side.leftWide = 0.5;
+ side.leftHi = 0.5;
+ side.centreWide = 0.5;
+ side.centreHi = 0.5;
+ side.rightWide = 0.5;
+ side.rightHi = 0.5;
+ return side;
+ }
+ public static function create(): JigsawSideData {
+ var side = new JigsawSideData();
+ side.bubble = createBubble();
+ //left right or up dawn offset.
+ side.squew = Math.random();
+ // in out
+ side.inout = Math.random();
+ // radii of ellipses
+ side.leftWide = Math.random();
+ side.leftHi = Math.random();
+ side.centreWide = Math.random();
+ side.centreHi = Math.random();
+ side.rightWide = Math.random();
+ side.rightHi = Math.random();
+ return side;
+ }
+ // use create instead
+ private function new(){}
+}
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawx/Jigsawx.hx b/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawx/Jigsawx.hx
new file mode 100644
index 00000000..93ee52df
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawx/Jigsawx.hx
@@ -0,0 +1,73 @@
+package jigsawx ;
+import jigsawx.OpenEllipse ;
+import jigsawx.JigsawPiece ;
+import jigsawx.math.Vec2;
+import jigsawx.JigsawSideData;
+class Jigsawx {
+ private var rows: Int;
+ private var cols: Int;
+ private var pieces: Array>;
+ public var jigs: Array;
+ private var sides: Array>;
+ private var lt: Float;
+ private var rt: Float;
+ private var rb: Float;
+ private var lb: Float;
+ private var dx: Float;
+ private var dy: Float;
+ private var length: Int;
+ public function new( dx_: Float
+ , dy_: Float
+ , rows_: Int
+ , cols_: Int
+ ) {
+ pieces = [];
+ jigs = [];
+ sides = [];
+ dx = dx_;
+ dy = dy_;
+ rows = rows_;
+ cols = cols_;
+ //corners, theoretically JigsawSideData could be modified to allow these to have a random element.
+ var xy = new Vec2( 20, 20 );
+ var lt = new Vec2( 20, 20 );
+ var rt = new Vec2( 20 + dx, 20 );
+ var rb = new Vec2( 20 + dx, dy + 20 );
+ var lb = new Vec2( 20, dy + 20 );
+ length = 0;
+ var last: JigsawPieceData;
+ for( row in 0...rows ){
+ last = { north: null, east: null, south: null, west: null };
+ sides.push( new Array() );
+ for( col in 0...cols ){
+ var jigsawPiece = JigsawSideData.halfPieceData();
+ if( last.east != null ) jigsawPiece.west = JigsawSideData.reflect( last.east );
+ if( col == cols - 1 ) jigsawPiece.east = null;
+ sides[ row ][ col ] = jigsawPiece;
+ last = jigsawPiece;
+ length++;
+ }
+ }
+ for( col in 0...cols ){
+ last = { north: null, east: null, south: null, west: null };
+ for( row in 0...rows ){
+ var jigsawPiece = sides[ row ][ col ];
+ if( last.south != null ) jigsawPiece.north = JigsawSideData.reflect( last.south );
+ if( row == rows - 1 ) jigsawPiece.south = null;
+ last = jigsawPiece;
+ }
+ }
+ var jig: JigsawPiece;
+ for( row in 0...rows ){
+ pieces.push( new Array() );
+ for( col in 0...cols ){
+ jig = new JigsawPiece( xy, row, col, lt, rt, rb, lb, sides[ row ][ col ] );
+ pieces[ row ][ col ] = jig;
+ jigs.push( jig );
+ xy.x += dx;
+ }
+ xy.x = 20;
+ xy.y += dy;
+ }
+ }
+}
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawx/OpenEllipse.hx b/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawx/OpenEllipse.hx
new file mode 100644
index 00000000..c678aea9
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawx/OpenEllipse.hx
@@ -0,0 +1,51 @@
+package jigsawx;
+import jigsawx.ds.CircleIter;
+import jigsawx.math.Vec2;
+class OpenEllipse {
+ public var rotation: Float;
+ public var beginAngle: Float;
+ public var finishAngle: Float;
+ public var stepAngle: Float;
+ public var centre: Vec2;
+ public var dimensions: Vec2;
+ private var circleIter: CircleIter;
+ private var _points: Array;
+ public function new(){}
+ public function getBegin(): Vec2 {
+ return createPoint( centre, dimensions, beginAngle );
+ }
+ public function getFinish(): Vec2 {
+ return createPoint( centre, dimensions, finishAngle );
+ }
+ public function getBeginRadius(){
+ return pointDistance( centre, getBegin() );
+ }
+ public function getFinishRadius(){
+ return pointDistance( centre, getFinish() );
+ }
+ private function pointDistance( A: Vec2, B: Vec2 ): Float {
+ var dx = A.x - B.x;
+ var dy = A.y - B.y;
+ return Math.sqrt( dx*dx + dy*dy );
+ }
+ public function setUp(){
+ circleIter = CircleIter.pi2pi( beginAngle, finishAngle, stepAngle );
+ }
+ public function getRenderList(): Array {
+ _points = new Array();
+ if( circleIter == null ) setUp();
+ _points.push( createPoint( centre, dimensions, beginAngle ) );
+ for( theta in CircleIter.pi2pi( beginAngle, finishAngle, stepAngle ).reset() ){
+ _points.push( createPoint( centre, dimensions, theta ) );
+ }
+ return _points;
+ }
+ public function createPoint( centre: Vec2, dimensions: Vec2, theta: Float ): Vec2 {
+ var offSetA = 3*Math.PI/2 - rotation;// arange so that angle moves from 0... could tidy up dxNew and dyNew!
+ var dx = dimensions.x*Math.sin( theta );// select the relevant sin cos so that 0 is upwards.
+ var dy = -dimensions.y*Math.cos( theta );
+ var dxNew = centre.x -dx*Math.sin( offSetA ) + dy*Math.cos( offSetA );
+ var dyNew = centre.y -dx*Math.cos( offSetA ) - dy*Math.sin( offSetA );
+ return new Vec2( dxNew, dyNew );
+ }
+}
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawx/ds/CircleIter.hx b/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawx/ds/CircleIter.hx
new file mode 100644
index 00000000..8520e91c
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawx/ds/CircleIter.hx
@@ -0,0 +1,61 @@
+package jigsawx.ds;
+enum Sign{
+ UP;
+ DOWN;
+}
+class CircleIter {
+ var begin: Float;
+ var fin: Float;
+ var step: Float;
+ var min: Float;
+ var max: Float;
+ var current: Float;
+ var onDirection: Sign;
+ public static function pi2( begin_: Float
+ , fin_: Float
+ , step_: Float
+ ){
+ return new CircleIter( begin_, fin_, step_, 0, 2*Math.PI );
+ }
+ public static function pi2pi( begin_: Float
+ , fin_: Float
+ , step_: Float
+ ){
+ return new CircleIter( begin_, fin_, step_, -Math.PI, Math.PI );
+ }
+ public function new ( begin_: Float
+ , fin_: Float
+ , step_: Float
+ , min_: Float
+ , max_: Float
+ ){
+ begin = begin_;
+ current = begin;
+ fin = fin_;
+ step = step_;
+ min = min_;
+ max = max_;
+ onDirection = ( step > 0 )? UP: DOWN;
+ }
+ public function reset(): CircleIter{
+ current = begin;
+ return this;
+ }
+ public function hasNext(): Bool {
+ switch onDirection {
+ case UP:
+ return ( ( current < fin && current + step > fin ) || current == fin )? false: true;
+ case DOWN:
+ return ( ( current > fin && (( current - step ) < fin) )|| current == fin )? false: true;
+ }
+ }
+ public function next() {
+ current += step;
+ switch onDirection{
+ case UP: if( current > max ) current = min + current - max;
+ case DOWN: if( current < min ) current = max + current - min;
+ }
+ if( !hasNext() ) return fin;
+ return current;
+ }
+}
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawx/math/Vec2.hx b/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawx/math/Vec2.hx
new file mode 100644
index 00000000..34f5bc44
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawx/math/Vec2.hx
@@ -0,0 +1,9 @@
+package jigsawx.math;
+class Vec2{
+ public var x: Float;
+ public var y: Float;
+ public function new( x_ = .0, y_ = .0 ){
+ x = x_;
+ y = y_;
+ }
+}
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawxtargets/hxflash/JigsawWebCam.hx b/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawxtargets/hxflash/JigsawWebCam.hx
new file mode 100644
index 00000000..82292d2b
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawxtargets/hxflash/JigsawWebCam.hx
@@ -0,0 +1,309 @@
+/*
+* Copyright (c) 2012, Justinfront Ltd
+* author: Justin L Mills
+* email: JLM at Justinfront dot net
+* created: 17 June 2012
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+* * Neither the name of the Justinfront Ltd nor the
+* names of its contributors may be used to endorse or promote products
+* derived from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY Justinfront Ltd ''AS IS'' AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL Justinfront Ltd BE LIABLE FOR ANY
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+package jigsawxtargets.hxflash;
+
+import flash.Lib;
+import flash.display.Sprite ;
+import flash.display.Graphics;
+import flash.events.MouseEvent;
+
+import flash.display.Bitmap;
+import flash.display.BitmapData;
+import flash.geom.Rectangle;
+import flash.geom.Point;
+import flash.display.PixelSnapping;
+import flash.geom.Matrix;
+
+import haxe.Timer;
+
+import jigsawx.JigsawPiece ;
+import jigsawx.Jigsawx;
+import jigsawx.math.Vec2;
+import zpartan.media.WebCameraView;
+import zpartan.media.ProgressiveVideo;
+import flash.net.NetConnection;
+
+
+class JigsawWebCam
+{
+
+
+ private var progressiveVideo: ProgressiveVideo;
+ private var webcam: WebCameraView;
+
+ private var holder : Sprite;
+ private var hit: Sprite;
+ private var jigsawx : Jigsawx;
+ private var videoSource: Sprite;
+ private var wid: Float;
+ private var hi: Float;
+ private var rows: Int;
+ private var cols: Int;
+ private var count: Int;
+ private var atimer: Timer;
+ private var depth: Int;
+
+ private var tiles: Array;
+ private var surfaces: Array;
+ private var offset: Array;
+ private var current: Sprite;
+
+ private var webcamHolder: Sprite;
+ private var videoHolder: Sprite;
+
+
+
+ static function main(){ new JigsawWebCam(); }
+
+ public function new()
+ {
+ current = Lib.current;
+ holder = new Sprite();
+ holder.x = 0;
+ holder.y = 0;
+
+ current.addChild( holder ) ;
+ count = 0;
+ rows = 8;
+ cols = 8;
+ wid = 40;
+ hi = 40;
+
+ createVisuals();
+ #if !noVideo
+ webcamDisplay();
+ #end
+
+ var allTiles = tiles;
+ Lib.current.addEventListener( MouseEvent.MOUSE_UP, function( e: MouseEvent )
+ {
+
+ // TODO: Need to add is close snap code for this case...
+ for( all in allTiles ) all.stopDrag();
+
+ });
+
+ }
+
+
+ public function webcamDisplay()
+ {
+
+ webcamHolder = new Sprite();
+ webcamHolder.x = 0;
+ webcamHolder.y = 0;
+
+ atimer = new Timer( 40 );
+ atimer.run = copyAcross;
+
+ #if showCamSource
+ holder.addChild( webcamHolder );
+ #end
+
+ webcam = new WebCameraView( webcamHolder );
+ var nc = new NetConnection();
+ webcam.send( nc );
+
+ }
+
+
+ private function copyAcross()
+ {
+ count++;
+
+ //if( count > 1000 ) atimer.stop();
+
+ var off: Vec2;
+ var xy = new Vec2( 0, 0 );
+ var count = 0;
+
+ for( row in 0...rows )
+ {
+
+ for( col in 0...cols )
+ {
+
+ off = offset[ count ];
+ // optimisation could try render blitting to single surface and implement dragging in the same way as javascript.
+ // scale 1.5 times
+ surfaces[ count ].bitmapData.draw( webcamHolder, new Matrix( 1.5, 0, 0, 1.5, -xy.x - off.x, -xy.y - off.y) );
+
+ xy.x += wid;
+ count++;
+
+ }
+
+ xy.x = 0;
+ xy.y += hi;
+
+ }
+
+ }
+
+
+ public function createVisuals()
+ {
+
+ var sp: Sprite;
+ var maskSp: Sprite;
+ var tile: Sprite;
+
+ var surface: Graphics;
+ tiles = [];
+ surfaces = [];
+ offset = [];
+ var first: Vec2;
+
+ jigsawx = new Jigsawx( wid, hi, rows, cols );
+ depth = 0;
+
+ for( jig in jigsawx.jigs )
+ {
+
+ // create sprite and surface and mask
+
+ sp = new Sprite();
+ tiles.push( sp );
+ holder.addChild( sp );
+ tile = new Sprite();
+ sp.addChild( tile );
+
+ //sp.fill = '#ffffff';
+
+ sp.x = jig.xy.x;
+ sp.y = jig.xy.y;
+ maskSp = new Sprite();
+ tile.mask = maskSp;
+ maskSp.x = -wid/2;
+ maskSp.y = -hi/2;
+ surface = maskSp.graphics;
+
+ sp.addChild( maskSp );
+
+ // local copies so that local functions can get the the current loop variables, not sure if they are all needed.
+ var tempSp = sp;
+ var wid_ = wid/2;
+ var hi_ = hi/2;
+ var ajig = jig;
+
+ // Select some pieces out of place.
+ if( Math.random()*5 > 2 )
+ {
+
+ sp.x = 600 - Math.random()*200;
+ sp.y = 400 - Math.random()*400;
+ sp.alpha = 0.7;
+
+ drawEdge( surface, jig, 0x0000ff );
+
+ sp.addEventListener( MouseEvent.MOUSE_DOWN, function( e: MouseEvent )
+ {
+
+ tempSp.parent.addChild( tempSp );
+ tempSp.startDrag();
+
+ });
+
+
+ sp.addEventListener( MouseEvent.MOUSE_UP, function( e: MouseEvent )
+ {
+
+ if( Math.abs( ajig.xy.x - tempSp.x ) < ( wid_ + hi_ )/4 && Math.abs( ajig.xy.y - tempSp.y ) < ( wid_ + hi_ )/4 )
+ {
+
+ tempSp.x = ajig.xy.x;
+ tempSp.y = ajig.xy.y;
+ tempSp.alpha = 1;
+ jig.enabled = false;
+ tempSp.mouseEnabled = false;
+ tempSp.mouseChildren = false;
+ tempSp.buttonMode = false;
+ tempSp.useHandCursor = false;
+
+ }
+
+ tempSp.stopDrag();
+
+ });
+
+ }
+ else
+ {
+
+ maskSp.alpha = 0;
+ jig.enabled = false;
+ tempSp.mouseEnabled = true;
+ tempSp.mouseChildren = true;
+ tempSp.buttonMode = true;
+ tempSp.useHandCursor = true;
+
+ drawEdge( surface, jig, 0x000000 );
+
+ }
+
+ var bounds = maskSp.getBounds( sp );
+ tile.x = bounds.x;
+ tile.y = bounds.y;
+ var tileW = Std.int( maskSp.width );
+ var tileH = Std.int( maskSp.height );
+ var bd = new BitmapData( tileW, tileH, true, 0x000000 );
+ var bm = new Bitmap( bd, PixelSnapping.ALWAYS, true );
+
+ // May not need this line... possibly change bm to not transparent.
+ bd.fillRect( new Rectangle( 0, 0, tileW, tileH ), 0xff000000 );
+
+ tile.addChild( bm );
+ surfaces.push( bm );
+ offset.push( new Vec2( bounds.x, bounds.y ) );
+
+ }
+
+ }
+
+
+ public function drawEdge( surface: Graphics, jig: JigsawPiece, c: Int )
+ {
+
+ surface.lineStyle( 1, c, 1 );
+ surface.beginFill( c, 1 );
+ var first = jig.getFirst();
+
+ surface.moveTo( first.x, first.y );
+
+ for( v in jig.getPoints() ) { surface.lineTo( v.x, v.y ); }
+
+ surface.endFill();
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawxtargets/hxflash/jigsawProgressiveVideo.hx b/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawxtargets/hxflash/jigsawProgressiveVideo.hx
new file mode 100644
index 00000000..c46b9b0d
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawxtargets/hxflash/jigsawProgressiveVideo.hx
@@ -0,0 +1,314 @@
+/*
+* Copyright (c) 2012, Justinfront Ltd
+* author: Justin L Mills
+* email: JLM at Justinfront dot net
+* created: 17 June 2012
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+* * Neither the name of the Justinfront Ltd nor the
+* names of its contributors may be used to endorse or promote products
+* derived from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY Justinfront Ltd ''AS IS'' AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL Justinfront Ltd BE LIABLE FOR ANY
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+package jigsawxtargets.hxflash;
+
+import flash.Lib;
+import flash.display.Sprite ;
+import flash.display.Graphics;
+import flash.events.MouseEvent;
+
+import flash.display.Bitmap;
+import flash.display.BitmapData;
+import flash.geom.Rectangle;
+import flash.geom.Point;
+import flash.display.PixelSnapping;
+import flash.geom.Matrix;
+
+import haxe.Timer;
+
+import jigsawx.JigsawPiece ;
+import jigsawx.Jigsawx;
+import jigsawx.math.Vec2;
+import zpartan.media.WebCameraView;
+import zpartan.media.ProgressiveVideo;
+import flash.net.NetConnection;
+
+
+class JigsawProgressiveVideo
+{
+
+
+ private var progressiveVideo: ProgressiveVideo;
+ private var webcam: WebCameraView;
+
+ private var holder : Sprite;
+ private var hit: Sprite;
+ private var jigsawx : Jigsawx;
+ private var videoSource: Sprite;
+ private var wid: Float;
+ private var hi: Float;
+ private var rows: Int;
+ private var cols: Int;
+ private var count: Int;
+ private var atimer: Timer;
+ private var depth: Int;
+
+ private var tiles: Array;
+ private var surfaces: Array;
+ private var offset: Array;
+ private var current: Sprite;
+
+ private var videoHolder: Sprite;
+
+ private inline static var videoSrc: String = 'big_buck_bunny.flv';
+
+
+ static function main(){ new JigsawProgressiveVideo(); }
+
+ public function new()
+ {
+
+ current = Lib.current;
+ holder = new Sprite();
+ holder.x = 0;
+ holder.y = 0;
+
+ current.addChild( holder ) ;
+ count = 0;
+ rows = 8;
+ cols = 8;
+ wid = 40;
+ hi = 40;
+
+ createVisuals();
+ #if !noVideo
+ progressiveVideoDisplay();
+ #end
+
+ var allTiles = tiles;
+ Lib.current.addEventListener( MouseEvent.MOUSE_UP, function( e: MouseEvent )
+ {
+
+ // TODO: Need to add is close snap code for this case...
+ for( all in allTiles ) all.stopDrag();
+
+ });
+
+ }
+
+
+ public function progressiveVideoDisplay()
+ {
+
+ var progressiveVideo = new ProgressiveVideo();
+ videoHolder = progressiveVideo.getHolder();
+ progressiveVideo.setVideo( videoSrc );
+ progressiveVideo.playVideo();
+
+ atimer = new Timer( 40 );
+ atimer.run = copyAcross;
+
+ #if showCamSource
+
+ videoHolder = progressiveVideo.getHolder();
+ videoHolder.x = 0;
+ videoHolder.y = 0;
+ holder.addChild( videoHolder );
+
+ #end
+
+
+
+ }
+
+
+ private function copyAcross()
+ {
+ count++;
+
+ //if( count > 1000 ) atimer.stop();
+
+ var off: Vec2;
+ var xy = new Vec2( 0, 0 );
+ var count = 0;
+
+ for( row in 0...rows )
+ {
+
+ for( col in 0...cols )
+ {
+
+ off = offset[ count ];
+ // optimisation could try render blitting to single surface and implement dragging in the same way as javascript.
+ // scale 1.2 times
+ surfaces[ count ].bitmapData.draw( videoHolder, new Matrix( 1.2, 0, 0, 1.2, -xy.x - off.x, -xy.y - off.y) );
+
+ xy.x += wid;
+ count++;
+
+ }
+
+ xy.x = 0;
+ xy.y += hi;
+
+ }
+
+ }
+
+
+ public function createVisuals()
+ {
+
+ var sp: Sprite;
+ var maskSp: Sprite;
+ var tile: Sprite;
+
+ var surface: Graphics;
+ tiles = [];
+ surfaces = [];
+ offset = [];
+ var first: Vec2;
+
+ jigsawx = new Jigsawx( wid, hi, rows, cols );
+ depth = 0;
+
+ for( jig in jigsawx.jigs )
+ {
+
+ // create sprite and surface and mask
+
+ sp = new Sprite();
+ tiles.push( sp );
+ holder.addChild( sp );
+ tile = new Sprite();
+ sp.addChild( tile );
+
+ //sp.fill = '#ffffff';
+
+ sp.x = jig.xy.x;
+ sp.y = jig.xy.y;
+ maskSp = new Sprite();
+ tile.mask = maskSp;
+ maskSp.x = -wid/2;
+ maskSp.y = -hi/2;
+ surface = maskSp.graphics;
+
+ sp.addChild( maskSp );
+
+ // local copies so that local functions can get the the current loop variables, not sure if they are all needed.
+ var tempSp = sp;
+ var wid_ = wid/2;
+ var hi_ = hi/2;
+ var ajig = jig;
+
+ // Select some pieces out of place.
+ if( Math.random()*5 > 2 )
+ {
+
+ sp.x = 600 - Math.random()*200;
+ sp.y = 400 - Math.random()*400;
+ sp.alpha = 0.7;
+
+ drawEdge( surface, jig, 0x0000ff );
+
+ sp.addEventListener( MouseEvent.MOUSE_DOWN, function( e: MouseEvent )
+ {
+
+ tempSp.parent.addChild( tempSp );
+ tempSp.startDrag();
+
+ });
+
+
+ sp.addEventListener( MouseEvent.MOUSE_UP, function( e: MouseEvent )
+ {
+
+ if( Math.abs( ajig.xy.x - tempSp.x ) < ( wid_ + hi_ )/4 && Math.abs( ajig.xy.y - tempSp.y ) < ( wid_ + hi_ )/4 )
+ {
+
+ tempSp.x = ajig.xy.x;
+ tempSp.y = ajig.xy.y;
+ tempSp.alpha = 1;
+ jig.enabled = false;
+ tempSp.mouseEnabled = false;
+ tempSp.mouseChildren = false;
+ tempSp.buttonMode = false;
+ tempSp.useHandCursor = false;
+
+ }
+
+ tempSp.stopDrag();
+
+ });
+
+ }
+ else
+ {
+
+ maskSp.alpha = 0;
+ jig.enabled = false;
+ tempSp.mouseEnabled = true;
+ tempSp.mouseChildren = true;
+ tempSp.buttonMode = true;
+ tempSp.useHandCursor = true;
+
+ drawEdge( surface, jig, 0x000000 );
+
+ }
+
+ var bounds = maskSp.getBounds( sp );
+ tile.x = bounds.x;
+ tile.y = bounds.y;
+ var tileW = Std.int( maskSp.width );
+ var tileH = Std.int( maskSp.height );
+ var bd = new BitmapData( tileW, tileH, true, 0x000000 );
+ var bm = new Bitmap( bd, PixelSnapping.ALWAYS, true );
+
+ // May not need this line... possibly change bm to not transparent.
+ bd.fillRect( new Rectangle( 0, 0, tileW, tileH ), 0xff000000 );
+
+ tile.addChild( bm );
+ surfaces.push( bm );
+ offset.push( new Vec2( bounds.x, bounds.y ) );
+
+ }
+
+ }
+
+
+ public function drawEdge( surface: Graphics, jig: JigsawPiece, c: Int )
+ {
+
+ surface.lineStyle( 1, c, 1 );
+ surface.beginFill( c, 1 );
+ var first = jig.getFirst();
+
+ surface.moveTo( first.x, first.y );
+
+ for( v in jig.getPoints() ) { surface.lineTo( v.x, v.y ); }
+
+ surface.endFill();
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawxtargets/hxjava/GraphicsTexture.hx b/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawxtargets/hxjava/GraphicsTexture.hx
new file mode 100644
index 00000000..21dcb276
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawxtargets/hxjava/GraphicsTexture.hx
@@ -0,0 +1,193 @@
+/*
+* Copyright (c) 2013 Justinfront Ltd
+* author: Justin L Mills
+* email: JLM at Justinfront dot net
+* created: 8 August 2013
+* language: Haxe 3
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+* * Neither the name of the Justinfront Ltd nor the
+* names of its contributors may be used to endorse or promote products
+* derived from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY Justinfront Ltd ''AS IS'' AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL Justinfront Ltd BE LIABLE FOR ANY
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+package jigsawxtargets.hxjava;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.GeneralPath;
+import java.awt.TexturePaint;
+import java.awt.image.BufferedImage;
+import java.awt.Image;
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
+import java.awt.image.RescaleOp;
+
+import java.NativeArray;
+import java.javax.imageio.ImageIO;
+
+import jigsawx.JigsawPiece;
+import jigsawx.math.Vec2;
+import jigsawxtargets.hxjava.JigsawxJava;
+
+#if applet
+ import java.javax.swing.JApplet;
+ import java.net.URL;
+
+#else
+ import java.io.File;
+ import java.io.IOException;
+#end
+
+class GraphicsTexture
+{
+
+ public var textureRectangle: Rectangle;
+ public var generalPath: GeneralPath;
+ var x: Float = 0;
+ var y: Float = 0;
+ var sx: Float;
+ var sy: Float;
+ public var jig: JigsawPiece;
+ public var image: BufferedImage;
+
+ @:isVar var texturePaint( get, null ): TexturePaint;
+
+ public function new( jig_: JigsawPiece
+ , imageSrc: String
+ , textureRectangle_ : Rectangle
+ , sx_: Float
+ , sy_: Float
+ )
+ {
+
+
+ jig = jig_;
+ createPath( jig_ );
+ sx = sx_;
+ sy = sy_;
+ alpha = 1.;
+ image = GraphicsTexture.bufferedImage( imageSrc );
+ textureRectangle = textureRectangle_;
+
+ }
+
+ @:isVar public var alpha( get, set ): Float;
+ public function get_alpha( ) : Float
+ {
+ return alpha;
+ }
+ public function set_alpha( alpha_: Float ): Float
+ {
+ alpha = alpha_;
+ return alpha;
+ }
+
+
+ private function createPath( jig: JigsawPiece )
+ {
+ generalPath = new GeneralPath();
+ var first = jig.getFirst();
+ generalPath.moveTo( first.x, first.y );
+ for( v in jig.getPoints() ) generalPath.lineTo( v.x, v.y );
+ generalPath.closePath();
+ }
+
+ public function get_texturePaint( ): TexturePaint
+ {
+ return texturePaint;
+ }
+
+ public function getLocation(): Vec2
+ {
+ return new Vec2( x, y );
+ }
+
+ public function setLocation( x_: Float, y_: Float )
+ {
+ generalPath.transform( AffineTransform.getTranslateInstance( x_ - x, y_ - y ) );
+ textureRectangle = new Rectangle( Std.int( x_ - sx + 25 )
+ , Std.int( y_ - sy + 25)
+ , Std.int( 360 * 3/2 )
+ , Std.int( 240 * 3/2 ) );
+ texturePaint = new TexturePaint( cast image, textureRectangle );
+ x = x_;
+ y = y_;
+ }
+
+ public function render( g2D: Graphics2D )
+ {
+
+ g2D.setClip( generalPath );
+
+ var arr = [ 1., 1., 1., alpha ];
+ var scaleFactors = new NativeArray( 4 );
+ for ( i in 0...arr.length ) scaleFactors[ i ] = arr[ i ];
+
+ var offsets = new NativeArray( 4 );
+ for ( i in 0...arr.length ) offsets[ i ] = arr[ i ];
+ arr = [ 0., 0., 0., 0. ];
+
+ var rescaleOp = new RescaleOp( scaleFactors, offsets, null );
+ var alphaImage = rescaleOp.filter( image, null );
+ g2D.drawImage( alphaImage
+ , textureRectangle.x
+ , textureRectangle.y
+ , textureRectangle.width
+ , textureRectangle.height
+ , null );
+
+ }
+
+ public static function bufferedImage( imageSrc: String ): BufferedImage
+ {
+ try{
+ var alphaImage = new BufferedImage( 100, 50
+ , BufferedImage.TYPE_INT_ARGB );
+ #if applet
+ // Issue with permissions
+ #else
+ var file = new File( imageSrc );
+ var loadedImg = ImageIO.read( file );
+ alphaImage = new BufferedImage(
+ loadedImg.getWidth( null )
+ , loadedImg.getHeight( null )
+ , BufferedImage.TYPE_INT_ARGB);
+ alphaImage.getGraphics().drawImage( loadedImg, 0, 0, null );
+ #end
+ return alphaImage;
+ }
+ catch
+ #if applet
+ ( e: Dynamic )
+ #else
+ ( e: IOException )
+ #end
+ {
+ #if applet
+ e.printStackTrace();
+ #end
+ trace('image load fail');
+ }
+ return new BufferedImage( 100, 50, BufferedImage.TYPE_INT_ARGB );
+ }
+
+}
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawxtargets/hxjava/JigsawxJava.hx b/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawxtargets/hxjava/JigsawxJava.hx
new file mode 100644
index 00000000..d35378d1
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawxtargets/hxjava/JigsawxJava.hx
@@ -0,0 +1,376 @@
+/*
+* Copyright (c) 2013 Justinfront Ltd
+* author: Justin L Mills
+* email: JLM at Justinfront dot net
+* created: 8 August 2013
+* language: Haxe 3
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+* * Neither the name of the Justinfront Ltd nor the
+* names of its contributors may be used to endorse or promote products
+* derived from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY Justinfront Ltd ''AS IS'' AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL Justinfront Ltd BE LIABLE FOR ANY
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package jigsawxtargets.hxjava;
+
+import jigsawx.Jigsawx;
+import java.javax.swing.JPanel;
+import java.awt.Color;
+import java.awt.Rectangle;
+import java.awt.Cursor;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
+import java.awt.event.MouseEvent;
+import java.awt.image.BufferedImage;
+import java.awt.Image;
+import java.awt.Point;
+import java.javax.swing.JSlider;
+import java.StdTypes;// Int64
+
+#if applet
+ import javax.swing.JApplet;
+#elseif update_task
+ import java.lang.System;
+ import java.javax.swing.JFrame;
+ import java.util.Timer;
+ import java.util.TimerTask;
+ import jigsawxtargets.hxjava.UpdateTask;
+#else
+ import java.lang.System;
+ import java.javax.swing.JFrame;
+#end
+
+class JigsawxJava
+#if applet
+ extends JApplet
+#else
+ extends JFrame
+#end
+implements KeyListener
+implements MouseListener
+implements MouseMotionListener
+{
+
+ var wid: Int;
+ var hi: Int;
+ var rows: Int;
+ var cols: Int;
+ var jigsawx: Jigsawx;
+ var surface: Surface;
+ var currentGraphic: GraphicsTexture;
+ var pressPoint: Point;
+ var enabledMove: Bool;
+ var up = KeyEvent.VK_UP;
+ var down = KeyEvent.VK_DOWN;
+ var right = KeyEvent.VK_RIGHT;
+ var left = KeyEvent.VK_LEFT;
+ #if applet
+ public static var japplet: JigsawxJava;
+ #elseif update_task
+ var mutex: Dynamic;
+ var updateTask: UpdateTask;
+ var updateTimer: Timer;
+ static var slowUpdateSpeed: Int64;
+ #end
+
+ inline static var imageSrc: String = "tablecloth.jpg";
+
+ function setup()
+ {
+ setSize( 700, 500 );
+
+ #if applet
+ japplet = this;
+ #else
+ setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
+ setBackground( Color.black );
+ #end
+
+ }
+
+ public static function main() { new JigsawxJava(); } public function new()
+ {
+ #if applet
+ super();
+ #else
+ super( 'Jigsawx Java Example' );
+ System.setProperty( "sun.java2d.opengl", "True" );
+ #end
+
+ setup();
+ createSurface();
+
+ setVisible( true );
+ }
+
+ function createSurface()
+ {
+ #if update_task
+ var mutex = {};
+ #end
+
+ surface = new Surface(
+
+ );
+ #if applet
+ #elseif update_task
+ surface.mutex = mutex;
+ #end
+ surface.graphicsTextures = createGraphicsTextures();
+ getContentPane().add( surface );
+
+
+ surface.addKeyListener( this );
+ surface.setFocusable( true );
+ surface.requestFocusInWindow();
+ addMouseListener( this );
+ addMouseMotionListener( this );
+
+ #if update_task
+ updateTimer = new java.util.Timer();
+ updateTask = new UpdateTask();
+ updateTask.newMore( surface, mutex );
+ // Re-retrieve this value before directly starting the timer for max
+ // accuracy.
+ updateTask.oldTime = System.nanoTime();
+ // Start the timer in 0ms (right away), updating every
+ // "slowUpdateSpeed" milliseconds
+ slowUpdateSpeed = 20;
+ var startAt: Int64 = 0;
+ updateTimer.schedule( updateTask
+ , startAt
+ , slowUpdateSpeed
+ );
+ #end
+
+ }
+
+ public function mousePressed( e: MouseEvent )
+ {
+ for( graphicsTexture in surface.graphicsTextures )
+ {
+ if( graphicsTexture.jig.enabled == true )
+ {
+ var point = e.getPoint();
+ pressPoint = new Point(
+ cast graphicsTexture.getLocation().x - point.x
+ , cast graphicsTexture.getLocation().y - point.y );
+ point.y -= 20;
+
+ if( graphicsTexture.generalPath.contains( point ) )
+ {
+ currentGraphic = graphicsTexture;
+ surface.moveToTop( graphicsTexture );
+ enabledMove = true;
+ }
+ }
+ }
+ }
+
+ public function mouseDragged( e: MouseEvent )
+ {
+ if( enabledMove == true )
+ {
+ var x = e.getX();
+ var y = e.getY();// + 20;
+
+ if( checkLock( new Point( x, y ) ) == true ) return;
+ currentGraphic.setLocation( x + pressPoint.x, y + pressPoint.y );
+
+ #if applet
+ surface.repaint();
+ #elseif update_task
+
+ #else
+ surface.repaint();
+ #end
+ }
+ }
+
+ public function mouseExited( e: MouseEvent )
+ {
+ enabledMove = false;
+ }
+
+ public function mouseMoved( e: MouseEvent ) {
+ overCheck( e );
+ }
+
+ public function overCheck( e: MouseEvent )
+ {
+ var showCursor = false;
+ for( graphicsTexture in surface.graphicsTextures )
+ {
+ if( currentGraphic.jig.enabled == true )
+ {
+ var point = e.getPoint();
+ point.y -= 20;
+ if( graphicsTexture.generalPath.contains( point ) )
+ {
+ showCursor = true;
+ }
+ }
+ }
+ if( showCursor )
+ {
+ e.getComponent().setCursor(
+ Cursor.getPredefinedCursor( Cursor.HAND_CURSOR )
+ );
+ }
+ else
+ {
+ e.getComponent().setCursor(
+ Cursor.getPredefinedCursor( Cursor.DEFAULT_CURSOR )
+ );
+ }
+ }
+
+ public function mouseEntered( e: MouseEvent ) {}
+ public function mouseClicked( e: MouseEvent ) {}
+ public function mouseReleased( e: MouseEvent )
+ {
+ enabledMove = false;
+ }
+
+ private function checkLock( tempSp: Point ):Bool
+ {
+ if( !enabledMove ) return true;
+ var jig = currentGraphic.jig;
+ if( jig == null ) return true;
+ if( Math.abs( jig.xy.x - ( tempSp.x - wid ) ) < ( wid + hi )/7 &&
+ Math.abs( jig.xy.y - ( tempSp.y - hi ) ) < ( wid + hi )/7 )
+ {
+
+ currentGraphic.setLocation( jig.xy.x, jig.xy.y );
+ currentGraphic.alpha = 1;
+ jig.enabled = false;
+ enabledMove = false;
+ #if applet
+ surface.repaint();
+ #elseif update_task
+
+ #else
+ surface.repaint();
+ #end
+ return true;
+ }
+ return false;
+ }
+
+ public function keyTyped( e: KeyEvent ){}
+ public function keyReleased(e: KeyEvent ){}
+ public function keyPressed( e: KeyEvent ) nudge( e );
+
+ private function nudge( e: KeyEvent ){
+ var location = currentGraphic.getLocation();
+ switch( e.getKeyCode() )
+ {
+ case up:
+ currentGraphic.setLocation( location.x, location.y - 1 );
+ case down:
+ currentGraphic.setLocation( location.x, location.y + 1 );
+ case left:
+ currentGraphic.setLocation( location.x - 1, location.y );
+ case right:
+ currentGraphic.setLocation( location.x + 1, location.y );
+ }
+
+ #if applet
+ surface.repaint();
+ #elseif update_task
+
+ #else
+ surface.repaint();
+ #end
+ }
+
+ function createGraphicsTextures(): Array
+ {
+ var arr = new Array();
+ rows = 3;//6;
+ cols = 5;//10;
+ wid = 100;//50;
+ hi = 100;//50;
+ jigsawx = new Jigsawx( wid, hi, rows, cols );
+
+ var count = 0;
+ var isRandom = false;
+ var unCompletedPieces = new Array();
+
+ for( jig in jigsawx.jigs )
+ {
+ var rec = new Rectangle( Std.int( wid/2 )
+ , Std.int( hi/2 )
+ , Std.int( 360 * 3/2 )
+ , Std.int( 240 * 3/2 )
+ );
+
+ var graphicsTexture = new GraphicsTexture( jig
+ , imageSrc
+ , rec
+ , jig.xy.x
+ , jig.xy.y
+ );
+ var randX = 0.;
+ var randY = 0.;
+
+ if( Math.random()*5 > 2 )
+ {
+ randX = Math.random()*200;
+ randY = Math.random()*100;
+ isRandom = true;
+ graphicsTexture.alpha = 0.6;
+ }
+ else
+ {
+ isRandom = false;
+ graphicsTexture.jig.enabled = false;
+ }
+
+ graphicsTexture.setLocation( jig.xy.x + randX, jig.xy.y + randY );
+
+ if( isRandom )
+ {
+ unCompletedPieces.push( graphicsTexture );
+ }
+ else
+ {
+ arr.push( graphicsTexture );
+ }
+
+ count++;
+ }
+
+ currentGraphic = arr[0];
+
+ // push un completed on top
+ for( graphicsTexture in unCompletedPieces ) arr.push( graphicsTexture );
+
+ return arr;
+
+ }
+}
+
+
+
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawxtargets/hxjava/Surface.hx b/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawxtargets/hxjava/Surface.hx
new file mode 100644
index 00000000..bd3fd839
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawxtargets/hxjava/Surface.hx
@@ -0,0 +1,91 @@
+/*
+* Copyright (c) 2013 Justinfront Ltd
+* author: Justin L Mills
+* email: JLM at Justinfront dot net
+* created: 8 August 2013
+* language: Haxe 3
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+* * Neither the name of the Justinfront Ltd nor the
+* names of its contributors may be used to endorse or promote products
+* derived from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY Justinfront Ltd ''AS IS'' AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL Justinfront Ltd BE LIABLE FOR ANY
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package jigsawxtargets.hxjava;
+
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+
+import java.javax.swing.JPanel;
+
+import jigsawxtargets.hxjava.GraphicsTexture;
+
+class Surface extends JPanel
+{
+
+ public var graphicsTextures: Array;
+
+ #if applet
+ #elseif update_task
+ public var mutex: Dynamic;
+ #else
+ #end
+
+ public function moveToTop( graphicsTexture: GraphicsTexture )
+ {
+ graphicsTextures.remove( graphicsTexture );
+ graphicsTextures.push( graphicsTexture );
+ }
+
+ public function new()
+ {
+ super( true );
+ }
+ @:overload override
+ public function paintComponent( g: Graphics )
+ {
+
+ #if applet
+ #elseif update_task
+ untyped __lock__(mutex,
+ {
+ #else
+ #end
+ super.paintComponent( g );
+ var g2D: Graphics2D = cast g;
+ g2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+ RenderingHints.VALUE_ANTIALIAS_ON );
+ g2D.setRenderingHint(RenderingHints.KEY_RENDERING,
+ RenderingHints.VALUE_RENDER_QUALITY );
+ for( i in 0...graphicsTextures.length ) graphicsTextures[ i ].render( g2D );
+ g2D.dispose();
+ 1;
+ #if applet
+ #elseif update_task
+ });
+ #else
+ #end
+
+
+ }
+
+}
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawxtargets/hxjava/UpdateTask.hx b/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawxtargets/hxjava/UpdateTask.hx
new file mode 100644
index 00000000..54c82122
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawxtargets/hxjava/UpdateTask.hx
@@ -0,0 +1,112 @@
+/*
+* Copyright (c) 2013 Justinfront Ltd
+* author: Justin L Mills
+* email: JLM at Justinfront dot net
+* created: 8 August 2013
+* language: Haxe 3
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+* * Neither the name of the Justinfront Ltd nor the
+* names of its contributors may be used to endorse or promote products
+* derived from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY Justinfront Ltd ''AS IS'' AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL Justinfront Ltd BE LIABLE FOR ANY
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package jigsawxtargets.hxjava;
+
+import java.util.Timer;
+import java.util.TimerTask;
+import java.javax.swing.JPanel;
+import java.lang.System;
+import java.StdTypes;// Int64
+
+class UpdateTask extends TimerTask
+{
+ // Set true to limit fps (sleep the thread), false to not
+ var limitingFPS: Bool;
+ // Set true to sync draws and updates together, false to not
+ var syncingUpdates: Bool;
+ public var oldTime: Int64;
+ var nanoseconds: Int64;
+ var frames: Int;
+ var updates: Int;
+ // Holds the latest calculated value of updates per second
+ var fps: Int;
+ // Holds the latest calculated value of updates per second
+ var ups: Int;
+ var jpanel: JPanel;
+ var mutex: Dynamic;
+
+ public function new()
+ {
+ super();
+ }
+
+ public function newMore(jpanel_: JPanel, mutex_: Dynamic )
+ {
+ jpanel = jpanel_;
+ mutex = mutex_;
+ init();
+ }
+
+ public function init()
+ {
+ oldTime = System.nanoTime();
+ limitingFPS = true;
+ syncingUpdates = true;
+ nanoseconds = 0;
+ frames = 0;
+ updates = 0;
+ fps = 0;
+ ups = 0;
+ }
+
+ @:overload override public function run()
+ {
+
+ //synchronized( mutex )
+ untyped __lock__( mutex,
+ {
+ // Calculating a new fps/ups value every second
+ if( nanoseconds >= 1000000000 )
+ {
+ fps = frames;
+ ups = updates;
+ nanoseconds = nanoseconds - 1000000000;
+ frames = 0;
+ updates = 0;
+ }
+
+ var elapsedTime: Int64 = System.nanoTime();
+ elapsedTime = elapsedTime - oldTime;
+ oldTime = oldTime - elapsedTime;
+ nanoseconds = nanoseconds + elapsedTime;
+ //update(elapsedTime);
+ // An update occured, increment.
+ updates++;
+
+ // Ask for a repaint
+ jpanel.repaint();
+ 1;
+ });
+
+
+ }
+}
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawxtargets/hxjs/JigsawDivtastic.hx b/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawxtargets/hxjs/JigsawDivtastic.hx
new file mode 100644
index 00000000..a052bbc9
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawxtargets/hxjs/JigsawDivtastic.hx
@@ -0,0 +1,383 @@
+/*
+* Copyright (c) 2012, Justinfront Ltd
+* author: Justin L Mills
+* email: JLM at Justinfront dot net
+* created: 17 June 2012
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+* * Neither the name of the Justinfront Ltd nor the
+* names of its contributors may be used to endorse or promote products
+* derived from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY Justinfront Ltd ''AS IS'' AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL Justinfront Ltd BE LIABLE FOR ANY
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+package jigsawxtargets.hxjs;
+
+import js.Browser;
+
+import core.DisplayDiv;
+import js.html.Event;
+import js.html.MouseEvent;
+import haxe.Timer;
+import js.html.CanvasRenderingContext2D;
+import jigsawx.JigsawPiece;
+import jigsawx.Jigsawx;
+import jigsawx.math.Vec2;
+import js.html.ImageElement;
+import core.ImageLoader;
+import haxe.ds.StringMap;
+import core.SetupCanvas;
+//https://developer.mozilla.org/En/Manipulating_video_using_canvas
+
+using core.GlobalDiv;
+
+class JigsawDivtastic
+{
+
+ var holder: DisplayDiv;
+ var hit: DisplayDiv;
+ var jigsawx: Jigsawx;
+ var visualSource: DisplayDiv;
+ var wid: Float;
+ var hi: Float;
+ var rows: Int;
+ var cols: Int;
+ var count: Int;
+ var atimer: Timer;
+ var depth: Int;
+ var tiles: Array;
+ var surfaces: Array;
+ var loader: ImageLoader;
+ inline static var videoSrc: String = 'big_buck_bunny.webm';
+ inline static var imageSrc: String = "tablecloth.jpg";
+
+ static function main(){ new JigsawDivtastic(); }
+
+ public function new()
+ {
+
+ holder = new DisplayDiv() ;
+ holder.x = 0 ;
+ holder.y = 0 ;
+ holder.width = 520 ;
+ holder.height = 260 ;
+ count = 0;
+ addChild( holder ) ;
+
+
+ createVisuals();
+ createHit();
+ #if !noVideo
+ visualDisplay();
+ #else
+ loader = new ImageLoader( [ imageSrc ], onLoaded );
+ #end
+ }
+
+ public function onLoaded()
+ {
+ var count = 0;
+ var images: StringMap = loader.images;
+ var tablecloth = images.get('tablecloth.jpg');
+ var xy = new Vec2( 20, 20 );
+ for( row in 0...rows )
+ {
+
+ for( col in 0...cols )
+ {
+
+ surfaces[ count ].drawImage( tablecloth, 32 - xy.x, 42 - xy.y, tablecloth.width*0.81, tablecloth.height*0.81 );
+ xy.x += wid;
+ count++;
+ }
+
+ xy.x = 20;
+ xy.y += hi;
+
+ }
+ }
+
+
+ public function createHit()
+ {
+
+ hit = new DisplayDiv() ;
+ hit.x = 0 ;
+ hit.y = 0 ;
+ hit.width = 1000 ;
+ hit.height = 1000 ;
+ hit.getStyle().cursor = 'pointer';
+ hit.getStyle().zIndex = Std.string( 1000000000 );
+
+ addChild( hit ) ;
+ hit.press.add( checkForDrag );
+
+ }
+
+
+ public function checkForDrag()
+ {
+
+ ROOT().onmousemove = null;
+
+ var pos = hit.getGlobalMouseXY();
+ var px = pos.first();
+ var py = pos.last();
+ var distance = 1000000000.;
+
+ // set a default value
+ var closest = tiles[ 0 ];
+ var jig = jigsawx.jigs[ 0 ];
+ var surface = surfaces[ 0 ];
+ var currI = 0;
+
+ var dx: Float;
+ var dy: Float;
+ var dr2: Float;
+ var vXY: DisplayDiv;
+
+ for( i in 0...tiles.length )
+ {
+
+ if( jigsawx.jigs[ i ].enabled )
+ {
+
+ dx = tiles[ i ].x - px;
+ dy = tiles[ i ].y - py;
+ dr2 = dx * dx + dy * dy;
+
+ if( dr2 < distance )
+ {
+
+ closest = tiles[ i ];
+ jig = jigsawx.jigs[ i ];
+ surface = surfaces[ i ];
+ distance = dr2;
+ currI = i;
+ }
+
+ }
+
+ }
+
+ var wid_ = wid/2;
+ var hi_ = hi/2;
+
+ if( distance < wid * hi )
+ {
+
+ closest.getStyle().zIndex = Std.string( depth++ );
+
+ ROOT().onmouseup = function( e: Event )
+ {
+ var em: MouseEvent = cast e;
+ if( closest.alpha != 1 )
+ {
+ closest.x = em.clientX - wid_/2;
+ closest.y = em.clientY - hi_/2;
+ closest.alpha = 0.74;
+ }
+
+ if( Math.abs( jig.xy.x - closest.x ) < ( wid_ + hi_ )/6 && Math.abs( jig.xy.y - closest.y ) < ( wid_ + hi_ )/6 )
+ {
+
+ closest.x = jig.xy.x;
+ closest.y = jig.xy.y;
+ //drawEdge( surface, jigsawx.jigs[ currI ], 'white' );
+ closest.alpha = 1;
+ jig.enabled = false;
+
+ }
+
+ ROOT().onmousemove = null;
+
+ }
+
+ ROOT().onmousemove = function( e: Event )
+ {
+ var em: MouseEvent = cast e;
+ if( closest.alpha != 1 )
+ {
+ closest.x = em.clientX - wid_/2;
+ closest.y = em.clientY - hi_/2;
+ closest.alpha = 0.87;
+ }
+ }
+ }
+
+ }
+
+
+ public function drawEdge( surface: CanvasRenderingContext2D
+ , jig: JigsawPiece
+ , c: String
+ )
+ {
+ surface.strokeStyle = c;
+ surface.lineWidth = 2;
+ surface.beginPath();
+
+ var first = jig.getFirst();
+
+ surface.moveTo( first.x + 3, first.y + 3 );
+
+ for( v in jig.getPoints() ) surface.lineTo( v.x + 3, v.y + 3 );
+
+ surface.stroke();
+ surface.closePath();
+ // make it a mask
+ surface.clip();
+
+ }
+
+
+
+
+ public function visualDisplay()
+ {
+ //371x262
+ visualSource = new DisplayDiv( videoSrc );
+
+ visualSource.x = 0;
+ visualSource.y = 0;
+ visualSource.width = 10;
+ visualSource.height = 10;
+
+ // if you want to show the source video ( or image) uncomment this line:
+ holder.addChild( visualSource ) ;
+ visualSource.play();
+ visualSource.getStyle().position = 'absolute';
+
+ atimer = new Timer( 40 );
+ atimer.run = copyAcross;
+
+ }
+
+
+ public function createVisuals()
+ {
+
+ var sp: DisplayDiv;
+ // holder for canvs
+ var canvasSp: DisplayDiv;
+ var surface: CanvasRenderingContext2D;
+ var first: Vec2;
+
+ surfaces = [];
+ tiles = [];
+ rows = 3;//6;
+
+ #if !noVideo
+ cols = 5;//10;
+ #else
+ cols = 4;
+ #end
+
+ wid = 70;//100//50;
+ hi = 70;//100//50;
+ jigsawx = new Jigsawx( wid, hi, rows, cols );
+ depth = 0;
+
+ for( jig in jigsawx.jigs )
+ {
+
+ // create sprite and surface
+ sp = new DisplayDiv();
+ holder.addChild( sp );
+ tiles.push( sp );
+
+ // if you want to check position
+ //sp.fill = '#ffffff';
+
+ sp.x = jig.xy.x;
+ sp.y = jig.xy.y;
+ sp.width = 0;
+ sp.height = 0;
+ canvasSp = new DisplayDiv( 'canvas' );
+ canvasSp.x = -wid/2 + -5;
+ canvasSp.y = -hi/2 + -5;
+ surface = canvasSp.twoD;
+ sp.getStyle().zIndex = Std.string( depth++ );
+
+ sp.addChild( canvasSp );
+
+ // select a random number to be out of place ( 2/5 th's )
+ if( Math.random()*5 > 2 )
+ {
+
+ sp.x = 215+520/2 - Math.random()*(520-350);
+ sp.y = 260/2 - Math.random()*255/2 + 15;
+ sp.alpha = 0.74;
+
+ drawEdge( surface, jig, 'white' );
+
+ }
+ else
+ {
+
+ // Disable movement of correctly placed jigsaw pieces
+ jig.enabled = false;
+ drawEdge( surface, jig, 'white' );
+
+ }
+
+ surfaces.push( surface );
+
+ }
+
+ }
+
+
+ private function copyAcross()
+ {
+
+ count++;
+
+ // if you want to stop video early
+ //if( count > 1000 ) atimer.stop();
+
+ var xy = new Vec2( 20, 20 );
+ trace( visualSource.getInstance() );
+ var image: ImageElement = cast visualSource.getInstance();
+ var count = 0;
+
+ for( row in 0...rows )
+ {
+
+ for( col in 0...cols )
+ {
+
+ surfaces[ count ].drawImage( image, -xy.x, -xy.y );
+
+ xy.x += wid;
+ count++;
+
+ }
+
+ xy.x = 20;
+ xy.y += hi;
+
+ }
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawxtargets/hxopenfl/JigsawxOpenfl.hx b/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawxtargets/hxopenfl/JigsawxOpenfl.hx
new file mode 100644
index 00000000..fca7dc31
--- /dev/null
+++ b/projects/flixel-desktop-habit-puzzle-game/JigsawX/jigsawxtargets/hxopenfl/JigsawxOpenfl.hx
@@ -0,0 +1,313 @@
+/*
+* Copyright (c) 2012, Justinfront Ltd
+* author: Justin L Mills
+* email: JLM at Justinfront dot net
+* created: 17 June 2012
+* updated to openfl: 23 Feburary 2014
+*
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+* * Neither the name of the Justinfront Ltd nor the
+* names of its contributors may be used to endorse or promote products
+* derived from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY Justinfront Ltd ''AS IS'' AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL Justinfront Ltd BE LIABLE FOR ANY
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+package jigsawxtargets.hxopenfl;
+
+
+
+import flash.Lib;
+import flash.display.Sprite ;
+import flash.display.Graphics;
+import flash.events.MouseEvent;
+import flash.events.Event;
+import flash.display.Loader;
+import flash.display.DisplayObject;
+import flash.display.Bitmap;
+import flash.display.BitmapData;
+import flash.geom.Rectangle;
+import flash.geom.Point;
+import flash.display.PixelSnapping;
+import flash.geom.Matrix;
+import flash.events.IOErrorEvent;
+//import neash.display.BitmapInt32;
+import haxe.Timer;
+import flash.net.URLRequest;
+import jigsawx.JigsawPiece ;
+import jigsawx.Jigsawx;
+import jigsawx.math.Vec2;
+
+
+class JigsawxOpenfl extends Sprite
+{
+
+ private var holder : Sprite;
+ private var hit: Sprite;
+ private var jigsawx : Jigsawx;
+ private var videoSource: Sprite;
+ private var wid: Float;
+ private var hi: Float;
+ private var rows: Int;
+ private var cols: Int;
+ private var count: Int;
+ private var atimer: Timer;
+ private var depth: Int;
+
+ private var tiles: Array;
+ private var surfaces: Array;
+ private var offset: Array;
+ private var current: Sprite;
+ private var spCloth: Sprite;
+ private var loader: Loader;
+
+ private inline static var imageSrc: String = "tablecloth.jpg";
+
+
+ public function new()
+ {
+ super();
+ current = Lib.current;
+ holder = new Sprite();
+ holder.x = 0;
+ holder.y = 0;
+
+ current.addChild( holder ) ;
+ count = 0;
+ rows = 7;
+ cols = 10;
+ wid = 45;
+ hi = 45;
+
+ createVisuals();
+ tableClothDisplay();
+ Lib.current.addEventListener( MouseEvent.MOUSE_UP, allTilesStop );
+
+ }
+
+
+ public function allTilesStop( e: MouseEvent )
+ {
+
+ // TODO: Need to add is close snap code for this case...
+ for( all in tiles ) all.stopDrag();
+
+ }
+
+
+ public function tableClothDisplay()
+ {
+
+ spCloth = new Sprite();
+ loader = new Loader();
+ trace( 'tableClothDisplay' );
+ loader.contentLoaderInfo.addEventListener(Event.COMPLETE, copyAcross );
+ loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, traceNotFound );
+ loader.load( new URLRequest( 'assets/' + imageSrc ) );
+
+ #if showImageSource
+ holder.addChild( spCloth );
+ #end
+
+ }
+
+ private function traceNotFound( e: IOErrorEvent )
+ {
+ trace( 'error ' + e );
+ }
+
+ private function copyAcross( e: Event )
+ {
+ trace( 'copyAccoss ');
+ count++;
+ var bmp: Bitmap = cast loader.content;
+ trace( bmp );
+ spCloth.addChild( new Bitmap( bmp.bitmapData ) );
+
+ //if( count > 1000 ) atimer.stop();
+
+ var off: Vec2;
+ var xy = new Vec2( 0, 0 );
+ var count = 0;
+
+ for( row in 0...rows )
+ {
+
+ for( col in 0...cols )
+ {
+
+ off = offset[ count ];
+ // optimisation could try render blitting to single surface and implement dragging in the same way as javascript.
+ // scale 1.2 times
+ surfaces[ count ].bitmapData.draw( spCloth, new Matrix( 1.2, 0, 0, 1.2, -xy.x - off.x, -xy.y - off.y) );
+
+ xy.x += wid;
+ count++;
+
+ }
+
+ xy.x = 0;
+ xy.y += hi;
+
+ }
+
+ }
+
+
+ public function createVisuals()
+ {
+
+ var sp: Sprite;
+ var maskSp: Sprite;
+ var tile: Sprite;
+
+ var surface: Graphics;
+ tiles = [];
+ surfaces = [];
+ offset = [];
+ var first: Vec2;
+
+ jigsawx = new Jigsawx( wid, hi, rows, cols );
+ depth = 0;
+
+ for( jig in jigsawx.jigs )
+ {
+
+ // create sprite and surface and mask
+
+ sp = new Sprite();
+ tiles.push( sp );
+ holder.addChild( sp );
+ tile = new Sprite();
+ sp.addChild( tile );
+
+ //sp.fill = '#ffffff';
+
+ sp.x = jig.xy.x;
+ sp.y = jig.xy.y;
+ maskSp = new Sprite();
+ tile.mask = maskSp;
+ maskSp.x = -wid/2;
+ maskSp.y = -hi/2;
+ surface = maskSp.graphics;
+
+ sp.addChild( maskSp );
+
+ // local copies so that local functions can get the the current loop variables, not sure if they are all needed.
+ var tempSp = sp;
+ var wid_ = wid/2;
+ var hi_ = hi/2;
+ var ajig = jig;
+
+ // Select some pieces out of place.
+ if( Math.random()*5 > 2 )
+ {
+
+ sp.x = 900 - Math.random()*400;
+ sp.y = 400 - Math.random()*400;
+ sp.alpha = 0.7;
+
+ drawEdge( surface, jig, 0x0000ff );
+
+ sp.addEventListener( MouseEvent.MOUSE_DOWN, function( e: MouseEvent )
+ {
+
+ tempSp.parent.addChild( tempSp );
+ tempSp.startDrag();
+
+ });
+
+
+ sp.addEventListener( MouseEvent.MOUSE_UP, function( e: MouseEvent )
+ {
+
+ if( Math.abs( ajig.xy.x - tempSp.x ) < ( wid_ + hi_ )/4 && Math.abs( ajig.xy.y - tempSp.y ) < ( wid_ + hi_ )/4 )
+ {
+
+ tempSp.x = ajig.xy.x;
+ tempSp.y = ajig.xy.y;
+ tempSp.alpha = 1;
+ jig.enabled = false;
+ tempSp.mouseEnabled = false;
+ tempSp.mouseChildren = false;
+ tempSp.buttonMode = false;
+ tempSp.useHandCursor = false;
+
+ }
+
+ tempSp.stopDrag();
+
+ });
+
+ }
+ else
+ {
+
+ maskSp.alpha = 0;
+ jig.enabled = false;
+ tempSp.mouseEnabled = true;
+ tempSp.mouseChildren = true;
+ tempSp.buttonMode = true;
+ tempSp.useHandCursor = true;
+
+ drawEdge( surface, jig, 0x000000 );
+
+ }
+
+ // significant change required for nme
+ var bounds = maskSp.getBounds( sp );
+ tile.x = bounds.x;
+ tile.y = bounds.y;
+
+ var tileW = Std.int( maskSp.width );
+ var tileH = Std.int( maskSp.height );
+ // for alpha colors you can't use an Int directly in nme BitmapData.createColor( 0xff,0xffffff )
+ var bd = new BitmapData( tileW, tileH, true, 0xffffffff );
+ var bm = new Bitmap( bd, PixelSnapping.ALWAYS, true );
+
+ // May not need this line... possibly change bm to not transparent.
+ bd.fillRect( new Rectangle( 0, 0, tileW, tileH ), 0x000000ff );
+
+ tile.addChild( bm );
+ surfaces.push( bm );
+ offset.push( new Vec2( bounds.x, bounds.y ) );
+
+ }
+
+ }
+
+
+ public function drawEdge( surface: Graphics, jig: JigsawPiece, c: Int )
+ {
+
+ surface.lineStyle( 1, c, 1 );
+ surface.beginFill( c, 1 );
+ var first = jig.getFirst();
+
+ surface.moveTo( first.x, first.y );
+
+ for( v in jig.getPoints() ) { surface.lineTo( v.x, v.y ); }
+
+ surface.endFill();
+
+ }
+
+}
\ No newline at end of file