Browse Source

merged heaps

Nicolas Cannasse 11 years ago
parent
commit
b880ea2e90
100 changed files with 3022 additions and 4768 deletions
  1. 3 10
      .gitignore
  2. 20 0
      LICENSE
  3. 6 30
      README.md
  4. 14 0
      all.hxml
  5. 0 12
      engine.hxml
  6. 0 1
      extraParams.hxml
  7. 25 14
      h2d/Anim.hx
  8. 1 1
      h2d/Bitmap.hx
  9. 12 11
      h2d/CachedBitmap.hx
  10. 20 20
      h2d/Console.hx
  11. 120 489
      h2d/Drawable.hx
  12. 11 11
      h2d/Font.hx
  13. 3 4
      h2d/Graphics.hx
  14. 3 50
      h2d/HtmlText.hx
  15. 1 1
      h2d/Interactive.hx
  16. 9 9
      h2d/Layers.hx
  17. 0 186
      h2d/Matrix.hx
  18. 154 1
      h2d/RenderContext.hx
  19. 31 31
      h2d/ScaleGrid.hx
  20. 13 2
      h2d/Scene.hx
  21. 4 4
      h2d/Scene3D.hx
  22. 49 14
      h2d/SpriteBatch.hx
  23. 19 15
      h2d/Text.hx
  24. 36 58
      h2d/Tile.hx
  25. 0 214
      h2d/TileColorGroup.hx
  26. 127 29
      h2d/TileGroup.hx
  27. 0 69
      h2d/Tools.hx
  28. 4 4
      h2d/col/Circle.hx
  29. 0 0
      h2d/col/Delaunay.hx
  30. 6 6
      h2d/col/Line.hx
  31. 7 7
      h2d/col/Point.hx
  32. 8 8
      h2d/col/Poly.hx
  33. 13 13
      h2d/col/Polynomial.hx
  34. 3 3
      h2d/col/RoundRect.hx
  35. 5 5
      h2d/col/Seg.hx
  36. 7 7
      h2d/col/Triangle.hx
  37. 17 17
      h2d/col/Voronoi.hx
  38. 5 5
      h2d/comp/Box.hx
  39. 6 6
      h2d/comp/Button.hx
  40. 7 7
      h2d/comp/Checkbox.hx
  41. 7 7
      h2d/comp/Color.hx
  42. 61 61
      h2d/comp/ColorPicker.hx
  43. 1 2
      h2d/comp/Component.hx
  44. 9 9
      h2d/comp/Context.hx
  45. 76 76
      h2d/comp/GradientEditor.hx
  46. 9 9
      h2d/comp/Input.hx
  47. 8 8
      h2d/comp/Interactive.hx
  48. 7 7
      h2d/comp/ItemList.hx
  49. 18 18
      h2d/comp/JQuery.hx
  50. 6 6
      h2d/comp/Label.hx
  51. 7 7
      h2d/comp/Parser.hx
  52. 12 12
      h2d/comp/Select.hx
  53. 6 6
      h2d/comp/Slider.hx
  54. 3 3
      h2d/css/Fill.hx
  55. 5 5
      h2d/css/Parser.hx
  56. 6 6
      h2d/css/Style.hx
  57. 2 0
      h2d/css/default.css
  58. 30 14
      h3d/Buffer.hx
  59. 26 26
      h3d/Camera.hx
  60. 0 24
      h3d/Drawable.hx
  61. 62 86
      h3d/Engine.hx
  62. 6 6
      h3d/Indexes.hx
  63. 48 0
      h3d/Matrix.hx
  64. 23 23
      h3d/Quat.hx
  65. 43 31
      h3d/Vector.hx
  66. 11 15
      h3d/anim/FrameAnimation.hx
  67. 7 10
      h3d/anim/LinearAnimation.hx
  68. 5 5
      h3d/anim/SimpleBlend.hx
  69. 16 16
      h3d/anim/Skin.hx
  70. 8 8
      h3d/anim/SmoothTransition.hx
  71. 8 8
      h3d/anim/Transition.hx
  72. 26 26
      h3d/col/Bounds.hx
  73. 17 17
      h3d/col/Plane.hx
  74. 12 12
      h3d/col/Point.hx
  75. 10 10
      h3d/col/Ray.hx
  76. 5 5
      h3d/col/Seg.hx
  77. 77 69
      h3d/impl/Driver.hx
  78. 338 1114
      h3d/impl/GlDriver.hx
  79. 303 0
      h3d/impl/LogDriver.hx
  80. 8 8
      h3d/impl/ManagedBuffer.hx
  81. 2 2
      h3d/impl/MemoryManager.hx
  82. 0 188
      h3d/impl/Shader.hx
  83. 0 88
      h3d/impl/Shaders.hx
  84. 249 63
      h3d/impl/Stage3dDriver.hx
  85. 0 15
      h3d/mat/Bitmap.hx
  86. 9 0
      h3d/mat/BlendMode.hx
  87. 22 1
      h3d/mat/Data.hx
  88. 95 74
      h3d/mat/Material.hx
  89. 53 835
      h3d/mat/MeshMaterial.hx
  90. 0 168
      h3d/mat/PartMaterial.hx
  91. 131 0
      h3d/mat/Pass.hx
  92. 26 19
      h3d/mat/Texture.hx
  93. 20 20
      h3d/parts/Data.hx
  94. 71 71
      h3d/parts/Editor.hx
  95. 43 40
      h3d/parts/Emitter.hx
  96. 12 26
      h3d/parts/Material.hx
  97. 9 9
      h3d/parts/Particle.hx
  98. 29 0
      h3d/pass/Base.hx
  99. 84 0
      h3d/pass/Blur.hx
  100. 66 0
      h3d/pass/Border.hx

+ 3 - 10
.gitignore

@@ -1,12 +1,5 @@
-
-/engine.swf
-/samples/*.swf
 *.n
 *.n
 *.swf
 *.swf
-*.n
-
-/samples/comps/arial.ttf
-/engine.js
-/engine.js.map
-/samples/2d/demo.js
-/bin
+*.js
+*.js.map
+/bin

+ 20 - 0
LICENSE

@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2013 Nicolas Cannasse
+
+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.

+ 6 - 30
README.md

@@ -1,30 +1,6 @@
-Haxe 3D Engine
-=========
-
-A lightweight 3D Engine for Haxe.
-
-Currently only supports Flash/Stage3D, but is abstracted to support other backends in the near future.
-
-In order to setup the engine, you can do :
-
-> var engine = new h3d.Engine();
-> engine.onReady = startMyApp;
-> engine.init();
-
-Then in your render loop you can do :
-
-> engine.begin();
-> ... render objects ...
-> engine.end()
-
-Objects can be created using a combination of a `h3d.mat.Material` (shader and blendmode) and `h3d.prim.Primitive` (geometry).
-
-You can look at available examples in `samples` directory.
-
-2D GPU Engine
--------------
-
-The `h2d` package contains classes that provides a complete 2D API that is built on top of `h3d`, and is then GPU accelerated.
-
-It contains an object hierarchy which base class is `h2d.Sprite` and root is `h2d.Scene`
-
+Heaps
+=====
+
+High Performance Game Framework
+
+http://heaps.io

+ 14 - 0
all.hxml

@@ -0,0 +1,14 @@
+-lib heaps
+--macro include('h3d')
+--macro include('h2d')
+--macro include('hxsl',true,['hxsl.Macros'])
+--macro include('hxd',true,['hxd.res.FileTree','hxd.Res','hxd.impl.BitsBuilder'])
+--no-output
+--each
+
+-js heaps.js
+
+--next
+
+-swf heaps.swf
+-swf-version 15

+ 0 - 12
engine.hxml

@@ -1,12 +0,0 @@
--cp samples/basic
--swf engine.swf
--swf-header 800:600:60:FFFFFF
---flash-strict
--swf-version 11.6
--main Test
--lib hxsl
--D h3d
--D resourcesPath=samples/res
---macro include('h3d')
---macro include('h2d')
---macro include('hxd',true,['hxd.res.FileTree'])

+ 0 - 1
extraParams.hxml

@@ -1 +0,0 @@
--swf-version 11.6

+ 25 - 14
h2d/Anim.hx

@@ -3,25 +3,36 @@ package h2d;
 class Anim extends Drawable {
 class Anim extends Drawable {
 
 
 	public var frames : Array<Tile>;
 	public var frames : Array<Tile>;
-	public var currentFrame : Float;
+	public var currentFrame(get,set) : Float;
 	public var speed : Float;
 	public var speed : Float;
 	public var loop : Bool = true;
 	public var loop : Bool = true;
+	var curFrame : Float;
 
 
 	public function new( ?frames, ?speed, ?parent ) {
 	public function new( ?frames, ?speed, ?parent ) {
 		super(parent);
 		super(parent);
 		this.frames = frames == null ? [] : frames;
 		this.frames = frames == null ? [] : frames;
-		this.currentFrame = 0;
+		this.curFrame = 0;
 		this.speed = speed == null ? 15 : speed;
 		this.speed = speed == null ? 15 : speed;
 	}
 	}
 
 
-	public function play( frames ) {
-		this.frames = frames;
-		this.currentFrame = 0;
+	inline function get_currentFrame() {
+		return curFrame;
+	}
+
+	public function play( frames, atFrame = 0. ) {
+		this.frames = frames == null ? [] : frames;
+		currentFrame = atFrame;
 	}
 	}
 
 
 	public dynamic function onAnimEnd() {
 	public dynamic function onAnimEnd() {
 	}
 	}
 
 
+	function set_currentFrame( frame : Float ) {
+		curFrame = frames.length == 0 ? 0 : frame % frames.length;
+		if( curFrame < 0 ) curFrame += frames.length;
+		return curFrame;
+	}
+
 	override function getBoundsRec( relativeTo, out ) {
 	override function getBoundsRec( relativeTo, out ) {
 		super.getBoundsRec(relativeTo, out);
 		super.getBoundsRec(relativeTo, out);
 		var tile = getFrame();
 		var tile = getFrame();
@@ -30,28 +41,28 @@ class Anim extends Drawable {
 
 
 	override function sync( ctx : RenderContext ) {
 	override function sync( ctx : RenderContext ) {
 		super.sync(ctx);
 		super.sync(ctx);
-		var prev = currentFrame;
-		currentFrame += speed * ctx.elapsedTime;
-		if( currentFrame < frames.length )
+		var prev = curFrame;
+		curFrame += speed * ctx.elapsedTime;
+		if( curFrame < frames.length )
 			return;
 			return;
 		if( loop ) {
 		if( loop ) {
-			currentFrame %= frames.length;
+			curFrame %= frames.length;
 			onAnimEnd();
 			onAnimEnd();
-		} else if( currentFrame >= frames.length ) {
-			currentFrame = frames.length;
-			if( currentFrame != prev ) onAnimEnd();
+		} else if( curFrame >= frames.length ) {
+			curFrame = frames.length;
+			if( curFrame != prev ) onAnimEnd();
 		}
 		}
 	}
 	}
 
 
 	public function getFrame() {
 	public function getFrame() {
-		var i = Std.int(currentFrame);
+		var i = Std.int(curFrame);
 		if( i == frames.length ) i--;
 		if( i == frames.length ) i--;
 		return frames[i];
 		return frames[i];
 	}
 	}
 
 
 	override function draw( ctx : RenderContext ) {
 	override function draw( ctx : RenderContext ) {
 		var t = getFrame();
 		var t = getFrame();
-		if( t != null ) drawTile(ctx.engine,t);
+		emitTile(ctx,t);
 	}
 	}
 
 
 }
 }

+ 1 - 1
h2d/Bitmap.hx

@@ -15,7 +15,7 @@ class Bitmap extends Drawable {
 	}
 	}
 
 
 	override function draw( ctx : RenderContext ) {
 	override function draw( ctx : RenderContext ) {
-		drawTile(ctx.engine,tile);
+		emitTile(ctx,tile);
 	}
 	}
 
 
 	public static function create( bmp : hxd.BitmapData, ?allocPos : h3d.impl.AllocPos ) {
 	public static function create( bmp : hxd.BitmapData, ?allocPos : h3d.impl.AllocPos ) {

+ 12 - 11
h2d/CachedBitmap.hx

@@ -5,10 +5,10 @@ class CachedBitmap extends Drawable {
 	public var width(default, set) : Int;
 	public var width(default, set) : Int;
 	public var height(default, set) : Int;
 	public var height(default, set) : Int;
 	public var freezed : Bool;
 	public var freezed : Bool;
-	
+
 	var renderDone : Bool;
 	var renderDone : Bool;
 	var tile : Tile;
 	var tile : Tile;
-	
+
 	public function new( ?parent, width = -1, height = -1 ) {
 	public function new( ?parent, width = -1, height = -1 ) {
 		super(parent);
 		super(parent);
 		this.width = width;
 		this.width = width;
@@ -26,7 +26,7 @@ class CachedBitmap extends Drawable {
 		clean();
 		clean();
 		super.onDelete();
 		super.onDelete();
 	}
 	}
-	
+
 	function set_width(w) {
 	function set_width(w) {
 		clean();
 		clean();
 		width = w;
 		width = w;
@@ -38,7 +38,7 @@ class CachedBitmap extends Drawable {
 		height = h;
 		height = h;
 		return h;
 		return h;
 	}
 	}
-	
+
 	public function getTile() {
 	public function getTile() {
 		if( tile == null ) {
 		if( tile == null ) {
 			var scene = getScene();
 			var scene = getScene();
@@ -53,9 +53,9 @@ class CachedBitmap extends Drawable {
 	}
 	}
 
 
 	override function drawRec( ctx : RenderContext ) {
 	override function drawRec( ctx : RenderContext ) {
-		drawTile(ctx.engine, tile);
+		emitTile(ctx, tile);
 	}
 	}
-	
+
 	override function sync( ctx : RenderContext ) {
 	override function sync( ctx : RenderContext ) {
 		if( posChanged ) {
 		if( posChanged ) {
 			calcAbsPos();
 			calcAbsPos();
@@ -69,7 +69,7 @@ class CachedBitmap extends Drawable {
 		var tile = getTile();
 		var tile = getTile();
 		if( !freezed || !renderDone ) {
 		if( !freezed || !renderDone ) {
 			var oldA = matA, oldB = matB, oldC = matC, oldD = matD, oldX = absX, oldY = absY;
 			var oldA = matA, oldB = matB, oldC = matC, oldD = matD, oldX = absX, oldY = absY;
-			
+
 			// init matrix without rotation
 			// init matrix without rotation
 			matA = 1;
 			matA = 1;
 			matB = 0;
 			matB = 0;
@@ -77,7 +77,7 @@ class CachedBitmap extends Drawable {
 			matD = 1;
 			matD = 1;
 			absX = 0;
 			absX = 0;
 			absY = 0;
 			absY = 0;
-			
+
 			// adds a pixels-to-viewport transform
 			// adds a pixels-to-viewport transform
 			var w = 2 / tile.width;
 			var w = 2 / tile.width;
 			var h = -2 / tile.height;
 			var h = -2 / tile.height;
@@ -94,11 +94,12 @@ class CachedBitmap extends Drawable {
 				c.sync(ctx);
 				c.sync(ctx);
 			}
 			}
 
 
+			throw "Should not draw in sync!";
 			ctx.engine.setTarget(tile.getTexture());
 			ctx.engine.setTarget(tile.getTexture());
 			for( c in childs )
 			for( c in childs )
 				c.drawRec(ctx);
 				c.drawRec(ctx);
 			ctx.engine.setTarget(null);
 			ctx.engine.setTarget(null);
-			
+
 			// restore
 			// restore
 			matA = oldA;
 			matA = oldA;
 			matB = oldB;
 			matB = oldB;
@@ -106,11 +107,11 @@ class CachedBitmap extends Drawable {
 			matD = oldD;
 			matD = oldD;
 			absX = oldX;
 			absX = oldX;
 			absY = oldY;
 			absY = oldY;
-			
+
 			renderDone = true;
 			renderDone = true;
 		}
 		}
 
 
 		super.sync(ctx);
 		super.sync(ctx);
 	}
 	}
-	
+
 }
 }

+ 20 - 20
h2d/Console.hx

@@ -13,7 +13,7 @@ enum ConsoleArg {
 class Console extends h2d.Sprite {
 class Console extends h2d.Sprite {
 
 
 	public static var HIDE_LOG_TIMEOUT = 3.;
 	public static var HIDE_LOG_TIMEOUT = 3.;
-	
+
 	var width : Int;
 	var width : Int;
 	var height : Int;
 	var height : Int;
 	var bg : h2d.Bitmap;
 	var bg : h2d.Bitmap;
@@ -28,9 +28,9 @@ class Console extends h2d.Sprite {
 	var logs : Array<String>;
 	var logs : Array<String>;
 	var logIndex:Int;
 	var logIndex:Int;
 	var curCmd:String;
 	var curCmd:String;
-	
+
 	public var shortKeyChar : Int = "/".code;
 	public var shortKeyChar : Int = "/".code;
-	
+
 	public function new(font:h2d.Font,parent) {
 	public function new(font:h2d.Font,parent) {
 		super(parent);
 		super(parent);
 		height = font.lineHeight + 2;
 		height = font.lineHeight + 2;
@@ -51,29 +51,29 @@ class Console extends h2d.Sprite {
 		addCommand("help", "Show help", [ { name : "command", t : AString, opt : true } ], showHelp);
 		addCommand("help", "Show help", [ { name : "command", t : AString, opt : true } ], showHelp);
 		addAlias("?", "help");
 		addAlias("?", "help");
 	}
 	}
-	
+
 	public function addCommand( name, help, args, callb : Dynamic ) {
 	public function addCommand( name, help, args, callb : Dynamic ) {
 		commands.set(name, { help : help, args:args, callb:callb } );
 		commands.set(name, { help : help, args:args, callb:callb } );
 	}
 	}
-	
+
 	public function addAlias( name, command ) {
 	public function addAlias( name, command ) {
 		aliases.set(name, command);
 		aliases.set(name, command);
 	}
 	}
-	
+
 	public function runCommand( commandLine : String ) {
 	public function runCommand( commandLine : String ) {
 		handleCommand(commandLine);
 		handleCommand(commandLine);
 	}
 	}
-	
+
 	override function onAlloc() {
 	override function onAlloc() {
 		super.onAlloc();
 		super.onAlloc();
 		getScene().addEventListener(onEvent);
 		getScene().addEventListener(onEvent);
 	}
 	}
-	
+
 	override function onDelete() {
 	override function onDelete() {
 		getScene().removeEventListener(onEvent);
 		getScene().removeEventListener(onEvent);
 		super.onDelete();
 		super.onDelete();
 	}
 	}
-	
+
 	function onEvent( e : hxd.Event ) {
 	function onEvent( e : hxd.Event ) {
 		switch( e.kind ) {
 		switch( e.kind ) {
 		case EWheel:
 		case EWheel:
@@ -89,7 +89,7 @@ class Console extends h2d.Sprite {
 		default:
 		default:
 		}
 		}
 	}
 	}
-	
+
 	function showHelp( ?command : String ) {
 	function showHelp( ?command : String ) {
 		var all;
 		var all;
 		if( command == null ) {
 		if( command == null ) {
@@ -128,16 +128,16 @@ class Console extends h2d.Sprite {
 			log(str);
 			log(str);
 		}
 		}
 	}
 	}
-	
+
 	public function isActive() {
 	public function isActive() {
 		return bg.visible;
 		return bg.visible;
 	}
 	}
-	
+
 	function set_cursorPos(v:Int) {
 	function set_cursorPos(v:Int) {
 		cursor.x = tf.calcTextWidth(tf.text.substr(0, v));
 		cursor.x = tf.calcTextWidth(tf.text.substr(0, v));
 		return cursorPos = v;
 		return cursorPos = v;
 	}
 	}
-	
+
 	function handleKey( e : hxd.Event ) {
 	function handleKey( e : hxd.Event ) {
 		if( e.charCode == shortKeyChar && !bg.visible ) {
 		if( e.charCode == shortKeyChar && !bg.visible ) {
 			bg.visible = true;
 			bg.visible = true;
@@ -201,12 +201,12 @@ class Console extends h2d.Sprite {
 			cursorPos++;
 			cursorPos++;
 		}
 		}
 	}
 	}
-	
+
 	function hide() {
 	function hide() {
 		bg.visible = false;
 		bg.visible = false;
 		tf.text = "";
 		tf.text = "";
 	}
 	}
-	
+
 	function handleCommand( command : String ) {
 	function handleCommand( command : String ) {
 		command = StringTools.trim(command);
 		command = StringTools.trim(command);
 		if( command.charCodeAt(0) == "/".code ) command = command.substr(1);
 		if( command.charCodeAt(0) == "/".code ) command = command.substr(1);
@@ -216,7 +216,7 @@ class Console extends h2d.Sprite {
 		}
 		}
 		logs.push(command);
 		logs.push(command);
 		logIndex = -1;
 		logIndex = -1;
-		
+
 		var args = ~/[ \t]+/g.split(command);
 		var args = ~/[ \t]+/g.split(command);
 		var cmdName = args[0];
 		var cmdName = args[0];
 		if( aliases.exists(cmdName) ) cmdName = aliases.get(cmdName);
 		if( aliases.exists(cmdName) ) cmdName = aliases.get(cmdName);
@@ -282,17 +282,17 @@ class Console extends h2d.Sprite {
 			log('ERROR $e', errorColor);
 			log('ERROR $e', errorColor);
 		}
 		}
 	}
 	}
-	
+
 	public function log( text : String, ?color ) {
 	public function log( text : String, ?color ) {
 		if( color == null ) color = tf.textColor;
 		if( color == null ) color = tf.textColor;
 		var oldH = logTxt.textHeight;
 		var oldH = logTxt.textHeight;
-		logTxt.htmlText += '<font color="#${StringTools.hex(color&0xFFFFFF,6)}">${StringTools.htmlEscape(text)}</font><br/>';
+		logTxt.text += '<font color="#${StringTools.hex(color&0xFFFFFF,6)}">${StringTools.htmlEscape(text)}</font><br/>';
 		if( logDY != 0 ) logDY += logTxt.textHeight - oldH;
 		if( logDY != 0 ) logDY += logTxt.textHeight - oldH;
 		logTxt.alpha = 1;
 		logTxt.alpha = 1;
 		logTxt.visible = true;
 		logTxt.visible = true;
 		lastLogTime = haxe.Timer.stamp();
 		lastLogTime = haxe.Timer.stamp();
 	}
 	}
-	
+
 	override function sync(ctx:h2d.RenderContext) {
 	override function sync(ctx:h2d.RenderContext) {
 		var scene = getScene();
 		var scene = getScene();
 		if( scene != null ) {
 		if( scene != null ) {
@@ -313,5 +313,5 @@ class Console extends h2d.Sprite {
 		}
 		}
 		super.sync(ctx);
 		super.sync(ctx);
 	}
 	}
-	
+
 }
 }

+ 120 - 489
h2d/Drawable.hx

@@ -1,525 +1,156 @@
 package h2d;
 package h2d;
 
 
-private class DrawableShader extends h3d.impl.Shader {
-	#if flash
-	static var SRC = {
-		var input : {
-			pos : Float2,
-			uv : Float2,
-			vanim : Float,
-			valpha : Float,
-			vcolor : Float4,
-		};
-		var tuv : Float2;
-		var tcolor : Float4;
-		var talpha : Float;
-
-		var hasVertexColor : Bool;
-		var hasVertexAlpha : Bool;
-		var uvScale : Float2;
-		var uvPos : Float2;
-		var skew : Float;
-		var zValue : Float;
-
-		var hasAnim : Bool;
-		var anims : Float3<64>;
-
-		function vertex( size : Float3, matA : Float3, matB : Float3 ) {
-			var tmp : Float4;
-			var spos = input.pos.xyw;
-			if( size != null ) spos *= size;
-			tmp.x = spos.dp3(matA);
-			tmp.y = spos.dp3(matB);
-			tmp.z = zValue;
-			tmp.w = skew != null ? 1 - skew * input.pos.y : 1;
-			out = tmp;
-			var t = input.uv;
-			if( uvScale != null ) t *= uvScale;
-			if( uvPos != null ) t += uvPos;
-			if( hasAnim ) {
-				var a = anims[input.vanim];
-				t.x = ((t.x - a.x) + a.z) % a.y + a.x;
-			}
-			tuv = t;
-			if( hasVertexColor ) tcolor = input.vcolor;
-			if( hasVertexAlpha ) talpha = input.valpha;
-		}
-
-		var hasAlpha : Bool;
-		var killAlpha : Bool;
-
-		var alpha : Float;
-		var colorAdd : Float4;
-		var colorMul : Float4;
-		var colorMatrix : M44;
-
-		var hasAlphaMap : Bool;
-		var alphaMap : Texture;
-		var alphaUV : Float4;
-		var filter : Bool;
-
-		var sinusDeform : Float3;
-		var tileWrap : Bool;
-
-		var hasMultMap : Bool;
-		var multMapFactor : Float;
-		var multMap : Texture;
-		var multUV : Float4;
-		var hasColorKey : Bool;
-		var colorKey : Int;
-
-		function fragment( tex : Texture ) {
-			var col = tex.get(sinusDeform != null ? [tuv.x + sin(tuv.y * sinusDeform.y + sinusDeform.x) * sinusDeform.z, tuv.y] : tuv, filter = ! !filter, wrap = tileWrap);
-			if( hasColorKey ) {
-				var cdiff = col.rgb - colorKey.rgb;
-				kill(cdiff.dot(cdiff) - 0.00001);
-			}
-			if( killAlpha ) kill(col.a - 0.001);
-			if( hasVertexAlpha ) col.a *= talpha;
-			if( hasVertexColor ) col *= tcolor;
-			if( hasAlphaMap ) col.a *= alphaMap.get(tuv * alphaUV.zw + alphaUV.xy).r;
-			if( hasMultMap ) col *= multMap.get(tuv * multUV.zw + multUV.xy) * multMapFactor;
-			if( hasAlpha ) col.a *= alpha;
-			if( colorMatrix != null ) col *= colorMatrix;
-			if( colorMul != null ) col *= colorMul;
-			if( colorAdd != null ) col += colorAdd;
-			out = col;
-		}
-
-
-	}
-
-	#elseif (js || cpp)
-
-
-	public var hasColorKey : Bool;
-
-	// not supported
-	public var sinusDeform : h3d.Vector;
-
-	// --
-
-	public var filter : Bool;
-	public var tileWrap : Bool;
-	public var killAlpha : Bool;
-	public var hasAlpha : Bool;
-	public var hasVertexAlpha : Bool;
-	public var hasVertexColor : Bool;
-	public var hasAlphaMap : Bool;
-	public var hasMultMap : Bool;
-	public var isAlphaPremul : Bool;
-
-	/**
-	 * This is the constant set, they are set / compiled for first draw and will enabled on all render thereafter
-	 *
-	 */
-	override function getConstants( vertex : Bool ) {
-		var cst = [];
-		if( vertex ) {
-			if( size != null ) cst.push("#define hasSize");
-			if( uvScale != null ) cst.push("#define hasUVScale");
-			if( uvPos != null ) cst.push("#define hasUVPos");
-		} else {
-			if( killAlpha ) cst.push("#define killAlpha");
-			if( hasColorKey ) cst.push("#define hasColorKey");
-			if( hasAlpha ) cst.push("#define hasAlpha");
-			if( colorMatrix != null ) cst.push("#define hasColorMatrix");
-			if( colorMul != null ) cst.push("#define hasColorMul");
-			if( colorAdd != null ) cst.push("#define hasColorAdd");
-		}
-		if( hasVertexAlpha ) cst.push("#define hasVertexAlpha");
-		if( hasVertexColor ) cst.push("#define hasVertexColor");
-		if( hasAlphaMap ) cst.push("#define hasAlphaMap");
-		if( hasMultMap ) cst.push("#define hasMultMap");
-		if( isAlphaPremul ) cst.push("#define isAlphaPremul");
-		return cst.join("\n");
-	}
-
-	static var VERTEX = "
-
-		attribute vec2 pos;
-		attribute vec2 uv;
-		#if hasVertexAlpha
-		attribute float valpha;
-		varying lowp float talpha;
-		#end
-		#if hasVertexColor
-		attribute vec4 vcolor;
-		varying lowp vec4 tcolor;
-		#end
-
-        #if hasSize
-		uniform vec3 size;
-		#end
-		uniform vec3 matA;
-		uniform vec3 matB;
-		uniform float zValue;
-
-        #if hasUVPos
-		uniform vec2 uvPos;
-		#end
-        #if hasUVScale
-		uniform vec2 uvScale;
-		#end
-
-		varying vec2 tuv;
-
-		void main(void) {
-			vec3 spos = vec3(pos.x,pos.y, 1.0);
-			#if hasSize
-				spos = spos * size;
-			#end
-			vec4 tmp;
-			tmp.x = dot(spos,matA);
-			tmp.y = dot(spos,matB);
-			tmp.z = zValue;
-			tmp.w = 1.;
-			gl_Position = tmp;
-			lowp vec2 t = uv;
-			#if hasUVScale
-				t *= uvScale;
-			#end
-			#if hasUVPos
-				t += uvPos;
-			#end
-			tuv = t;
-			#if hasVertexAlpha
-				talpha = valpha;
-			#end
-			#if hasVertexColor
-				tcolor = vcolor;
-			#end
-		}
-
-	";
-
-	static var FRAGMENT = "
-
-		varying vec2 tuv;
-		uniform sampler2D tex;
-
-		#if hasVertexAlpha
-		varying float talpha;
-		#end
-
-		#if hasVertexColor
-		varying vec4 tcolor;
-		#end
-
-		#if hasAlphaMap
-			uniform vec4 alphaUV;
-			uniform sampler2D alphaMap;
-		#end
-
-		#if hasMultMap
-			uniform float multMapFactor;
-			uniform vec4 multUV;
-			uniform sampler2D multMap;
-		#end
-
-		uniform float alpha;
-		uniform vec3 colorKey/*byte4*/;
-
-		uniform vec4 colorAdd;
-		uniform vec4 colorMul;
-		uniform mat4 colorMatrix;
-
-		void main(void) {
-			vec4 col = texture2D(tex, tuv).rgba;
-
-			#if killAlpha
-				if( col.a - 0.001 <= 0.0 ) discard;
-			#end
-
-			#if hasColorKey
-				vec3 dc = col.rgb - colorKey;
-				if( dot(dc, dc) < 0.00001 ) discard;
-			#end
-
-			#if isAlphaPremul
-				col.rgb /= col.a;
-			#end
-
-			#if hasVertexAlpha
-				col.a *= talpha;
-			#end
-
-			#if hasVertexColor
-				col *= tcolor;
-			#end
-
-			#if hasAlphaMap
-				col.a *= texture2D( alphaMap, tuv * alphaUV.zw + alphaUV.xy).r;
-			#end
-
-			#if hasMultMap
-				col *= multMapFactor * texture2D(multMap,tuv * multUV.zw + multUV.xy);
-			#end
-
-			#if hasAlpha
-				col.a *= alpha;
-			#end
-			#if hasColorMatrix
-				col *= colorMatrix;
-			#end
-			#if hasColorMul
-				col *= colorMul;
-			#end
-			#if hasColorAdd
-				col += colorAdd;
-			#end
-
-			#if isAlphaPremul
-				col.rgb *= col.a;
-			#end
-
-			gl_FragColor = col;
-		}
-
-	";
-
-	#end
-}
-
 class Drawable extends Sprite {
 class Drawable extends Sprite {
 
 
-	static inline var HAS_SIZE = 1;
-	static inline var HAS_UV_SCALE = 2;
-	static inline var HAS_UV_POS = 4;
-
-	var shader : DrawableShader;
-
+	public var color(default,null) : h3d.Vector;
 	public var alpha(get, set) : Float;
 	public var alpha(get, set) : Float;
-	#if !openfl
-	public var skew(get, set) : Null<Float>;
-	#end
-
-	public var filter(get, set) : Bool;
-	public var color(get, set) : h3d.Vector;
-	public var colorAdd(get, set) : h3d.Vector;
-	public var colorMatrix(get, set) : h3d.Matrix;
-
-	public var blendMode(default, set) : BlendMode;
-
-	public var alphaMap(default, set) : h2d.Tile;
-
-	public var sinusDeform(get, set) : h3d.Vector;
-	public var tileWrap(get, set) : Bool;
-	public var killAlpha(get, set) : Bool;
-
-	public var multiplyMap(default, set) : h2d.Tile;
-	public var multiplyFactor(get, set) : Float;
-
-	public var colorKey(get, set) : Int;
+	public var blendMode : BlendMode;
+	public var filter : Bool;
+	public var tileWrap : Bool;
+	public var colorKey(default, set) : Null<Int>;
+	public var colorMatrix(get, set) : Null<h3d.Matrix>;
 
 
-	public var writeAlpha : Bool;
+	var shaders : Array<hxsl.Shader>;
 
 
 	function new(parent) {
 	function new(parent) {
 		super(parent);
 		super(parent);
-		shader = new DrawableShader();
-		writeAlpha = true;
 		blendMode = Normal;
 		blendMode = Normal;
-		shader.alpha = 1;
-		shader.zValue = 0;
-		writeAlpha = true;
-	}
-
-	inline function get_alpha() {
-		return shader.alpha;
-	}
-
-	function set_alpha( v : Null<Float> ) {
-		shader.alpha = v;
-		shader.hasAlpha = v < 1;
-		return v;
-	}
-
-	function set_blendMode(b) {
-		blendMode = b;
-		return b;
-	}
-
-	#if !openfl
-	inline function get_skew() : Null<Float> {
-		return shader.skew;
-	}
-
-	inline function set_skew(v : Null<Float> ) {
-		return shader.skew = skew;
-	}
-	#end
-
-	inline function get_multiplyFactor() {
-		return shader.multMapFactor;
-	}
-
-	inline function set_multiplyFactor(v) {
-		return shader.multMapFactor = v;
-	}
-
-	function set_multiplyMap(t:h2d.Tile) {
-		multiplyMap = t;
-		shader.hasMultMap = t != null;
-		return t;
-	}
-
-	function set_alphaMap(t:h2d.Tile) {
-		alphaMap = t;
-		shader.hasAlphaMap = t != null;
-		return t;
-	}
-
-	inline function get_sinusDeform() {
-		return shader.sinusDeform;
-	}
-
-	inline function set_sinusDeform(v) {
-		return shader.sinusDeform = v;
-	}
-
-	inline function get_colorMatrix() {
-		return shader.colorMatrix;
-	}
-
-	inline function set_colorMatrix(m) {
-		return shader.colorMatrix = m;
-	}
-
-	inline function set_colorAdd(m) {
-		return shader.colorAdd = m;
-	}
-
-	inline function get_colorAdd() {
-		return shader.colorAdd;
-	}
-
-	inline function get_color() {
-		return shader.colorMul;
+		color = new h3d.Vector(1, 1, 1, 1);
+		shaders = [];
 	}
 	}
 
 
-	inline function set_color(m) {
-		return shader.colorMul = m;
+	function set_colorKey(v:Null<Int>) {
+		var s = getShader(h3d.shader.ColorKey);
+		if( s == null ) {
+			if( v != null )
+				s = addShader(new h3d.shader.ColorKey(0xFF000000 | v));
+		} else {
+			if( v == null )
+				removeShader(s);
+			else
+				s.colorKey.setColor(0xFF000000 | v);
+		}
+		return colorKey = v;
 	}
 	}
 
 
-	inline function get_filter() {
-		return shader.filter;
+	function get_colorMatrix() {
+		var s = getShader(h3d.shader.ColorMatrix);
+		return s == null ? null : s.matrix;
 	}
 	}
 
 
-	inline function set_filter(v) {
-		return shader.filter = v;
+	function set_colorMatrix(m:h3d.Matrix) {
+		var s = getShader(h3d.shader.ColorMatrix);
+		if( s == null ) {
+			if( m != null ) {
+				s = addShader(new h3d.shader.ColorMatrix());
+				s.matrix.loadFrom(m);
+			}
+		} else {
+			if( m == null )
+				removeShader(s);
+			else
+				s.matrix.loadFrom(m);
+		}
+		return m;
 	}
 	}
 
 
-	inline function get_tileWrap() {
-		return shader.tileWrap;
+	inline function get_alpha() {
+		return color.a;
 	}
 	}
 
 
-	inline function set_tileWrap(v) {
-		return shader.tileWrap = v;
+	inline function set_alpha(v) {
+		return color.a = v;
 	}
 	}
 
 
-	inline function get_killAlpha() {
-		return shader.killAlpha;
+	public function getDebugShaderCode( toHxsl = true ) {
+		var shader = @:privateAccess {
+			var ctx = getScene().ctx;
+			var shaders : Array<hxsl.Shader> = [ctx.baseShader];
+			shaders = shaders.concat(this.shaders);
+			ctx.manager.compileShaders(shaders);
+		}
+		var toString = toHxsl ? function(d) return hxsl.Printer.shaderToString(d,true) : hxsl.GlslOut.toGlsl;
+		return "VERTEX=\n" + toString(shader.vertex.data) + "\n\nFRAGMENT=\n" + toString(shader.fragment.data);
 	}
 	}
 
 
-	inline function set_killAlpha(v) {
-		return shader.killAlpha = v;
+	public function getShader< T:hxsl.Shader >( stype : Class<T> ) : T {
+		for( s in shaders )
+			if( Std.is(s, stype) )
+				return cast s;
+		return null;
 	}
 	}
 
 
-	inline function get_colorKey() {
-		return shader.colorKey;
+	public inline function getShaders() {
+		return new hxd.impl.ArrayIterator<hxsl.Shader>(shaders);
 	}
 	}
 
 
-	inline function set_colorKey(v) {
-		shader.hasColorKey = true;
-		return shader.colorKey = v;
+	public function addShader<T:hxsl.Shader>( s : T ) : T {
+		this.shaders.push(s);
+		return s;
 	}
 	}
 
 
-	function drawTile( engine, tile ) {
-		setupShader(engine, tile, HAS_SIZE | HAS_UV_POS | HAS_UV_SCALE);
-		engine.renderQuadBuffer(Tools.getCoreObjects().planBuffer);
+	public function removeShader( s : hxsl.Shader ) {
+		return this.shaders.remove(s);
 	}
 	}
 
 
-	function setupShader( engine : h3d.Engine, tile : h2d.Tile, options : Int ) {
-		var core = Tools.getCoreObjects();
-		var shader = shader;
-		var mat = core.tmpMaterial;
-
+	function emitTile( ctx : RenderContext, tile : Tile ) {
 		if( tile == null )
 		if( tile == null )
-			tile = core.nullTile;
-
-		var tex : h3d.mat.Texture = tile.getTexture();
-		var isTexPremul = false;
-		if( tex != null ) {
-			tex.filter = filter ? Linear : Nearest;
-			isTexPremul = tex.flags.has(AlphaPremultiplied);
-		}
-
-		switch( blendMode ) {
-		case Normal:
-			mat.blend(isTexPremul ? One : SrcAlpha, OneMinusSrcAlpha);
-		case None:
-			mat.blend(One, Zero);
-		case Add:
-			mat.blend(isTexPremul ? One : SrcAlpha, One);
-		case SoftAdd:
-			mat.blend(OneMinusDstColor, One);
-		case Multiply:
-			mat.blend(DstColor, OneMinusSrcAlpha);
-		case Erase:
-			mat.blend(Zero, OneMinusSrcAlpha);
-		}
-
-		if( options & HAS_SIZE != 0 ) {
-			var tmp = core.tmpSize;
-			// adds 1/10 pixel size to prevent precision loss after scaling
-			tmp.x = tile.width + 0.1;
-			tmp.y = tile.height + 0.1;
-			tmp.z = 1;
-			shader.size = tmp;
-		}
-		if( options & HAS_UV_POS != 0 ) {
-			core.tmpUVPos.x = tile.u;
-			core.tmpUVPos.y = tile.v;
-			shader.uvPos = core.tmpUVPos;
-		}
-		if( options & HAS_UV_SCALE != 0 ) {
-			core.tmpUVScale.x = tile.u2 - tile.u;
-			core.tmpUVScale.y = tile.v2 - tile.v;
-			shader.uvScale = core.tmpUVScale;
-		}
-
-		if( shader.hasAlphaMap ) {
-			shader.alphaMap = alphaMap.getTexture();
-			shader.alphaUV = new h3d.Vector(alphaMap.u, alphaMap.v, (alphaMap.u2 - alphaMap.u) / tile.u2, (alphaMap.v2 - alphaMap.v) / tile.v2);
-		}
-
-		if( shader.hasMultMap ) {
-			shader.multMap = multiplyMap.getTexture();
-			shader.multUV = new h3d.Vector(multiplyMap.u, multiplyMap.v, (multiplyMap.u2 - multiplyMap.u) / tile.u2, (multiplyMap.v2 - multiplyMap.v) / tile.v2);
-		}
-
-		var cm = writeAlpha ? 15 : 7;
-		if( mat.colorMask != cm ) mat.colorMask = cm;
-
-		var tmp = core.tmpMatA;
-		tmp.x = matA;
-		tmp.y = matC;
-		tmp.z = absX + tile.dx * matA + tile.dy * matC;
-		shader.matA = tmp;
-		var tmp = core.tmpMatB;
-		tmp.x = matB;
-		tmp.y = matD;
-		tmp.z = absY + tile.dx * matB + tile.dy * matD;
-		shader.matB = tmp;
-		shader.tex = tile.getTexture();
-		/*
-		shader.isAlphaPremul = isTexPremul
-		&& (shader.hasAlphaMap || shader.hasAlpha || shader.hasMultMap
-		|| shader.hasVertexAlpha || shader.hasVertexColor
-		|| shader.colorMatrix != null || shader.colorAdd != null
-		|| shader.colorMul != null );*/
-		mat.shader = shader;
-		engine.selectMaterial(mat);
+			tile = new Tile(null, 0, 0, 5, 5);
+		ctx.beginDrawBatch(this, tile.getTexture());
+
+		var ax = absX + tile.dx * matA + tile.dy * matC;
+		var ay = absY + tile.dx * matB + tile.dy * matD;
+		var buf = ctx.buffer;
+		var pos = ctx.bufPos;
+		buf.grow(pos + 4 * 8);
+
+		inline function emit(v:Float) buf[pos++] = v;
+
+		emit(ax);
+		emit(ay);
+		emit(tile.u);
+		emit(tile.v);
+		emit(color.r);
+		emit(color.g);
+		emit(color.b);
+		emit(color.a);
+
+
+		var tw = tile.width;
+		var th = tile.height;
+		var dx1 = tw * matA;
+		var dy1 = tw * matB;
+		var dx2 = th * matC;
+		var dy2 = th * matD;
+
+		emit(ax + dx1);
+		emit(ay + dy1);
+		emit(tile.u2);
+		emit(tile.v);
+		emit(color.r);
+		emit(color.g);
+		emit(color.b);
+		emit(color.a);
+
+		emit(ax + dx2);
+		emit(ay + dy2);
+		emit(tile.u);
+		emit(tile.v2);
+		emit(color.r);
+		emit(color.g);
+		emit(color.b);
+		emit(color.a);
+
+		emit(ax + dx1 + dx2);
+		emit(ay + dy1 + dy2);
+		emit(tile.u2);
+		emit(tile.v2);
+		emit(color.r);
+		emit(color.g);
+		emit(color.b);
+		emit(color.a);
+
+		ctx.bufPos = pos;
 	}
 	}
 
 
 }
 }

+ 11 - 11
h2d/Font.hx

@@ -11,22 +11,22 @@ class Kerning {
 }
 }
 
 
 class FontChar {
 class FontChar {
-	
+
 	public var t : h2d.Tile;
 	public var t : h2d.Tile;
 	public var width : Int;
 	public var width : Int;
 	var kerning : Null<Kerning>;
 	var kerning : Null<Kerning>;
-	
+
 	public function new(t,w) {
 	public function new(t,w) {
 		this.t = t;
 		this.t = t;
 		this.width = w;
 		this.width = w;
 	}
 	}
-	
+
 	public function addKerning( prevChar : Int, offset : Int ) {
 	public function addKerning( prevChar : Int, offset : Int ) {
 		var k = new Kerning(prevChar, offset);
 		var k = new Kerning(prevChar, offset);
 		k.next = kerning;
 		k.next = kerning;
 		kerning = k;
 		kerning = k;
 	}
 	}
-	
+
 	public function getKerningOffset( prevChar : Int ) {
 	public function getKerningOffset( prevChar : Int ) {
 		var k = kerning;
 		var k = kerning;
 		while( k != null ) {
 		while( k != null ) {
@@ -40,7 +40,7 @@ class FontChar {
 }
 }
 
 
 class Font {
 class Font {
-	
+
 	public var name(default, null) : String;
 	public var name(default, null) : String;
 	public var size(default, null) : Int;
 	public var size(default, null) : Int;
 	public var lineHeight(default, null) : Int;
 	public var lineHeight(default, null) : Int;
@@ -48,7 +48,7 @@ class Font {
 	public var charset : hxd.Charset;
 	public var charset : hxd.Charset;
 	var glyphs : Map<Int,FontChar>;
 	var glyphs : Map<Int,FontChar>;
 	var defaultChar : FontChar;
 	var defaultChar : FontChar;
-	
+
 	function new(name,size) {
 	function new(name,size) {
 		this.name = name;
 		this.name = name;
 		this.size = size;
 		this.size = size;
@@ -56,7 +56,7 @@ class Font {
 		defaultChar = new FontChar(new Tile(null, 0, 0, 0, 0),0);
 		defaultChar = new FontChar(new Tile(null, 0, 0, 0, 0),0);
 		charset = hxd.Charset.getDefault();
 		charset = hxd.Charset.getDefault();
 	}
 	}
-	
+
 	public inline function getChar( code : Int ) {
 	public inline function getChar( code : Int ) {
 		var c = glyphs.get(code);
 		var c = glyphs.get(code);
 		if( c == null ) {
 		if( c == null ) {
@@ -65,7 +65,7 @@ class Font {
 		}
 		}
 		return c;
 		return c;
 	}
 	}
-	
+
 	/**
 	/**
 		This is meant to create smoother fonts by creating them with double size while still keeping the original glyph size.
 		This is meant to create smoother fonts by creating them with double size while still keeping the original glyph size.
 	**/
 	**/
@@ -78,13 +78,13 @@ class Font {
 		lineHeight = Std.int(lineHeight * ratio);
 		lineHeight = Std.int(lineHeight * ratio);
 		this.size = size;
 		this.size = size;
 	}
 	}
-	
+
 	public function hasChar( code : Int ) {
 	public function hasChar( code : Int ) {
 		return glyphs.get(code) != null;
 		return glyphs.get(code) != null;
 	}
 	}
-	
+
 	public function dispose() {
 	public function dispose() {
 		tile.dispose();
 		tile.dispose();
 	}
 	}
-	
+
 }
 }

+ 3 - 4
h2d/Graphics.hx

@@ -59,10 +59,10 @@ private class GraphicsContent extends h3d.prim.Primitive {
 
 
 	override function alloc( engine : h3d.Engine ) {
 	override function alloc( engine : h3d.Engine ) {
 		if (index.length <= 0) return ;
 		if (index.length <= 0) return ;
-		buffer = h3d.Buffer.ofFloats(tmp, 8);
+		buffer = h3d.Buffer.ofFloats(tmp, 8, [RawFormat]);
 		indexes = h3d.Indexes.alloc(index);
 		indexes = h3d.Indexes.alloc(index);
 		for( b in buffers ) {
 		for( b in buffers ) {
-			if( b.vbuf == null || b.vbuf.isDisposed() ) b.vbuf = h3d.Buffer.ofFloats(b.buf, 8);
+			if( b.vbuf == null || b.vbuf.isDisposed() ) b.vbuf = h3d.Buffer.ofFloats(b.buf, 8, [RawFormat]);
 			if( b.ibuf == null || b.ibuf.isDisposed() ) b.ibuf = h3d.Indexes.alloc(b.idx);
 			if( b.ibuf == null || b.ibuf.isDisposed() ) b.ibuf = h3d.Indexes.alloc(b.idx);
 		}
 		}
 	}
 	}
@@ -123,7 +123,6 @@ class Graphics extends Drawable {
 	public function new(?parent) {
 	public function new(?parent) {
 		super(parent);
 		super(parent);
 		content = new GraphicsContent();
 		content = new GraphicsContent();
-		shader.hasVertexColor = true;
 		tile = h2d.Tile.fromColor(0xFFFFFFFF);
 		tile = h2d.Tile.fromColor(0xFFFFFFFF);
 		clear();
 		clear();
 	}
 	}
@@ -315,7 +314,7 @@ class Graphics extends Drawable {
 
 
 	override function draw(ctx:RenderContext) {
 	override function draw(ctx:RenderContext) {
 		flush();
 		flush();
-		setupShader(ctx.engine, tile, 0);
+		ctx.beginDrawObject(this, tile.getTexture());
 		content.render(ctx.engine);
 		content.render(ctx.engine);
 	}
 	}
 
 

+ 3 - 50
h2d/HtmlText.hx

@@ -1,39 +1,8 @@
 package h2d;
 package h2d;
 
 
-class HtmlText extends Drawable {
+class HtmlText extends Text {
 
 
-	public var font(default, null) : Font;
-	public var htmlText(default, set) : String;
-	public var textColor(default, set) : Int;
-	
-	public var textWidth(get, null) : Int;
-	public var textHeight(get, null) : Int;
-	
-	public var letterSpacing : Int;
-	
-	var glyphs : TileColorGroup;
-	
-	public function new( font : Font, ?parent ) {
-		super(parent);
-		this.font = font;
-		glyphs = new TileColorGroup(font.tile, this);
-		htmlText = "";
-		shader = glyphs.shader;
-		textColor = 0xFFFFFF;
-	}
-	
-	override function onAlloc() {
-		super.onAlloc();
-		if( htmlText != null ) initGlyphs();
-	}
-	
-	function set_htmlText(t) {
-		this.htmlText = t == null ? "null" : t;
-		if( allocated ) initGlyphs();
-		return t;
-	}
-	
-	function initGlyphs( rebuild = true ) {
+	override function initGlyphs( text : String, rebuild = true, ?lines : Array<Int> ) {
 		if( rebuild ) glyphs.reset();
 		if( rebuild ) glyphs.reset();
 		glyphs.setDefaultColor(textColor);
 		glyphs.setDefaultColor(textColor);
 		var x = 0, y = 0, xMax = 0;
 		var x = 0, y = 0, xMax = 0;
@@ -74,25 +43,9 @@ class HtmlText extends Drawable {
 				}
 				}
 			}
 			}
 		}
 		}
-		for( e in Xml.parse(htmlText) )
+		for( e in Xml.parse(text) )
 			loop(e);
 			loop(e);
 		return { width : x > xMax ? x : xMax, height : x > 0 ? y + font.lineHeight : y };
 		return { width : x > xMax ? x : xMax, height : x > 0 ? y + font.lineHeight : y };
 	}
 	}
-	
-	function get_textHeight() {
-		return initGlyphs(false).height;
-	}
-	
-	function get_textWidth() {
-		return initGlyphs(false).width;
-	}
-	
-	function set_textColor(c) {
-		if( textColor != c ) {
-			this.textColor = c;
-			if( allocated && htmlText != "" ) initGlyphs();
-		}
-		return c;
-	}
 
 
 }
 }

+ 1 - 1
h2d/Interactive.hx

@@ -33,7 +33,7 @@ class Interactive extends Drawable {
 	}
 	}
 
 
 	override function draw( ctx : RenderContext ) {
 	override function draw( ctx : RenderContext ) {
-		if( backgroundColor != null ) drawTile(ctx.engine,h2d.Tile.fromColor(backgroundColor,Std.int(width),Std.int(height)));
+		if( backgroundColor != null ) emitTile(ctx,h2d.Tile.fromColor(backgroundColor,Std.int(width),Std.int(height)));
 	}
 	}
 
 
 	override function getBoundsRec( relativeTo, out ) {
 	override function getBoundsRec( relativeTo, out ) {

+ 9 - 9
h2d/Layers.hx

@@ -1,25 +1,25 @@
 package h2d;
 package h2d;
 
 
 class Layers extends Sprite {
 class Layers extends Sprite {
-	
+
 	// the per-layer insert position
 	// the per-layer insert position
 	var layers : Array<Int>;
 	var layers : Array<Int>;
 	var layerCount : Int;
 	var layerCount : Int;
-	
+
 	public function new(?parent) {
 	public function new(?parent) {
 		super(parent);
 		super(parent);
 		layers = [];
 		layers = [];
 		layerCount = 0;
 		layerCount = 0;
 	}
 	}
-	
+
 	override function addChild(s) {
 	override function addChild(s) {
 		addChildAt(s, 0);
 		addChildAt(s, 0);
 	}
 	}
-	
+
 	public inline function add(s, layer) {
 	public inline function add(s, layer) {
 		return addChildAt(s, layer);
 		return addChildAt(s, layer);
 	}
 	}
-	
+
 	override function addChildAt( s : Sprite, layer : Int ) {
 	override function addChildAt( s : Sprite, layer : Int ) {
 		if( s.parent == this ) {
 		if( s.parent == this ) {
 			var old = s.allocated;
 			var old = s.allocated;
@@ -34,7 +34,7 @@ class Layers extends Sprite {
 		for( i in layer...layerCount )
 		for( i in layer...layerCount )
 			layers[i]++;
 			layers[i]++;
 	}
 	}
-	
+
 	override function removeChild( s : Sprite ) {
 	override function removeChild( s : Sprite ) {
 		for( i in 0...childs.length ) {
 		for( i in 0...childs.length ) {
 			if( childs[i] == s ) {
 			if( childs[i] == s ) {
@@ -50,7 +50,7 @@ class Layers extends Sprite {
 			}
 			}
 		}
 		}
 	}
 	}
-	
+
 	public function under( s : Sprite ) {
 	public function under( s : Sprite ) {
 		for( i in 0...childs.length )
 		for( i in 0...childs.length )
 			if( childs[i] == s ) {
 			if( childs[i] == s ) {
@@ -83,7 +83,7 @@ class Layers extends Sprite {
 				break;
 				break;
 			}
 			}
 	}
 	}
-	
+
 	public function ysort( layer : Int ) {
 	public function ysort( layer : Int ) {
 		if( layer >= layerCount ) return;
 		if( layer >= layerCount ) return;
 		var start = layer == 0 ? 0 : layers[layer - 1];
 		var start = layer == 0 ? 0 : layers[layer - 1];
@@ -109,5 +109,5 @@ class Layers extends Sprite {
 		}
 		}
 	}
 	}
 
 
-	
+
 }
 }

+ 0 - 186
h2d/Matrix.hx

@@ -1,186 +0,0 @@
-package h2d;
-import hxd.Math;
-import h2d.col.Point;
-
-class Matrix
-{
-	public var a : Float;
-	public var b : Float;
-	public var c : Float;
-	public var d : Float;
-	
-	public var tx : Float;
-	public var ty : Float;
-	
-	/**
-	 * Loaded with identity by default
-	 */
-	public inline function new(a=1.,b=0.,c=0.,d=1.,tx=0.,ty=0.) {
-		setTo(a, b, c, d, tx, ty);
-	}
-	
-	public inline function zero() {
-		a = b = c = d = tx = ty = 0.0;
-	}
-	
-	public inline function identity() {
-		a = 1.; b = 0.; c = 0.; d = 1.; tx = 0.; ty = 0.;
-	}
-	
-	public inline function setTo(a=1.,b=0.,c=0.,d=1.,tx=0.,ty=0.) {
-		this.a = a;	
-		this.b = b; 
-		this.c = c;
-		this.d = d;
-		
-		this.tx = tx;
-		this.ty = ty;
-	}
-	
-	public function invert ():Matrix {
-
-		var norm = a * d - b * c;
-		if (norm == 0) {
-
-			a = b = c = d = 0;
-			tx = -tx;
-			ty = -ty;
-		} else {
-			norm = 1.0 / norm;
-			var a1 = d * norm;
-			d = a * norm;
-			a = a1;
-			b *= -norm;
-			c *= -norm;
-
-			var tx1 = - a * tx - c * ty;
-			ty = - b * tx - d * ty;
-			tx = tx1;
-		}
-
-		return this;
-
-	}
-	
-	public inline function rotate (angle:Float):Void {
-		var c = Math.cos(angle);
-		var s=  Math.sin(angle);
-		concat32(	c, s, 
-					-s, c,
-					0.0,0.0 );
-	}
-
-	public inline function scale (x:Float, y:Float):Void {
-		a *= x;
-		b *= y;
-
-		c *= x;
-		d *= y;
-
-		tx *= x;
-		ty *= y;
-	}
-	
-	#if !debug inline #end
-	public 
-	function skew(x, y) {
-		concat32(	1.0, Math.tan(x), 
-					Math.tan(y), 1.0,
-					0.0,0.0 			);
-	}
-	
-	#if !debug inline #end 
-	public 
-	function makeSkew(x:Float, y:Float):Void {
-		identity();
-		b = Math.tan( x );
-		c = Math.tan( y );
-	}
-
-	public inline function setRotation (angle:Float, scale:Float = 1):Void {
-		a = Math.cos (angle) * scale;
-		c = Math.sin (angle) * scale;
-		b = -c;
-		d = a;
-		tx = ty = 0;
-	}
-
-	public function toString ():String {
-		return "(a=" + a + ", b=" + b + ", c=" + c + ", d=" + d + ", tx=" + tx + ", ty=" + ty + ")";
-	}
-
-	public inline function transformPoint (point:Point):Point {
-		return new Point (point.x * a + point.y * c + tx, point.x * b + point.y * d + ty);
-	}
-	
-	public function concat(m:Matrix):Void {
-		var a1 = a * m.a + b * m.c;
-		b = a * m.b + b * m.d;
-		a = a1;
-
-		var c1 = c * m.a + d * m.c;
-		d = c * m.b + d * m.d;
-
-		c = c1;
-
-		var tx1 = tx * m.a + ty * m.c + m.tx;
-		ty = tx * m.b + ty * m.d + m.ty;
-		tx = tx1;
-	}
-	
-	/**
-	 * Does not apply tx/ty
-	 */
-	public #if !debug inline #end function concat22(m:Matrix):Void {
-		var a1 = a * m.a + b * m.c;
-		b = a * m.b + b * m.d;
-		a = a1;
-
-		var c1 = c * m.a + d * m.c;
-		d = c * m.b + d * m.d;
-
-		c = c1;
-	}
-	
-	public #if !debug inline #end function concat32(ma:Float,mb:Float,mc:Float,md:Float,mtx:Float,mty:Float):Void {
-		var a1 = a * ma + b * mc;
-		b = a * mb + b * md;
-		a = a1;
-
-		var c1 = c * ma + d * mc;
-		d = c * mb + d * md;
-
-		c = c1;
-
-		var tx1 = tx * ma + ty * mc + mtx;
-		ty = tx * mb + ty * md + mty;
-		tx = tx1;
-	}
-	
-	/**
-	 * Same as transformPoint except allow memory conservation
-	 * @param	?res reuseable parameter
-	 */
-	public inline function transformPoint2 (pointx:Float, pointy : Float, ?res:Point):Point {
-		var p  = res == null?new Point():res;
-		var px = pointx;
-		var py = pointy;
-		p.x = px * a + py * c + tx;
-		p.y = px * b + py * d + ty;
-		return p;
-	}
-	
-	public inline function transformX (px:Float, py : Float):Float{
-		return px * a + py * c + tx;
-	}
-	
-	public inline function transformY (px:Float, py : Float):Float{
-		return px * b + py * d + ty;
-	}
-
-	public inline function translate (x:Float, y:Float):Void {
-		tx += x;
-		ty += y;
-	}
-	
-}

+ 154 - 1
h2d/RenderContext.hx

@@ -1,3 +1,156 @@
 package h2d;
 package h2d;
 
 
-typedef RenderContext = h3d.scene.RenderContext;
+class RenderContext {
+
+	public var engine : h3d.Engine;
+	public var time : Float;
+	public var elapsedTime : Float;
+	public var frame : Int;
+
+	public var buffer : hxd.FloatBuffer;
+	public var bufPos : Int;
+
+	var texture : h3d.mat.Texture;
+	var baseShader : h3d.shader.Base2d;
+	var manager : h3d.shader.Manager;
+	var compiledShader : hxsl.RuntimeShader;
+	var buffers : h3d.shader.Buffers;
+	var pass : h3d.mat.Pass;
+	var currentShaders : Array<hxsl.Shader>;
+	var currentObj : Drawable;
+	var stride : Int;
+
+	public function new() {
+		frame = 0;
+		time = 0.;
+		elapsedTime = 1. / hxd.Stage.getInstance().getFrameRate();
+		buffer = new hxd.FloatBuffer();
+		bufPos = 0;
+		manager = new h3d.shader.Manager(["output.position", "output.color"]);
+		pass = new h3d.mat.Pass("",null);
+		pass.depth(true, Always);
+		pass.culling = None;
+		baseShader = new h3d.shader.Base2d();
+		baseShader.zValue = 0.;
+	}
+
+	public function begin() {
+		texture = null;
+		currentObj = null;
+		bufPos = 0;
+		stride = 0;
+		initShaders([baseShader]);
+		engine.selectMaterial(pass);
+	}
+
+	function initShaders( shaders ) {
+		currentShaders = shaders;
+		compiledShader = manager.compileShaders(shaders);
+		if( buffers == null )
+			buffers = new h3d.shader.Buffers(compiledShader);
+		else
+			buffers.grow(compiledShader);
+		manager.fillGlobals(buffers, compiledShader);
+		engine.selectShader(compiledShader);
+		engine.uploadShaderBuffers(buffers, Globals);
+	}
+
+	public function end() {
+		flush();
+		texture = null;
+		currentObj = null;
+	}
+
+	public function flush() {
+		if( bufPos == 0 ) return;
+		beforeDraw();
+		var nverts = Std.int(bufPos / stride);
+		var tmp = new h3d.Buffer(nverts, stride, [Quads, Dynamic, RawFormat]);
+		tmp.uploadVector(buffer, 0, nverts);
+		engine.renderQuadBuffer(tmp);
+		tmp.dispose();
+		bufPos = 0;
+		texture = null;
+	}
+
+	public function beforeDraw() {
+		if( texture == null ) texture = h3d.mat.Texture.fromColor(0xFFFF00FF);
+		baseShader.texture = texture;
+		texture.filter = currentObj.filter ? Linear : Nearest;
+		texture.wrap = currentObj.tileWrap ? Repeat : Clamp;
+		switch( currentObj.blendMode ) {
+		case Normal:
+			pass.blend(SrcAlpha, OneMinusSrcAlpha);
+		case None:
+			pass.blend(One, Zero);
+		case Add:
+			pass.blend(SrcAlpha, One);
+		case SoftAdd:
+			pass.blend(OneMinusDstColor, One);
+		case Multiply:
+			pass.blend(DstColor, OneMinusSrcAlpha);
+		case Erase:
+			pass.blend(Zero, OneMinusSrcAlpha);
+		}
+		manager.fillParams(buffers, compiledShader, currentShaders);
+		engine.selectMaterial(pass);
+		engine.uploadShaderBuffers(buffers, Params);
+		engine.uploadShaderBuffers(buffers, Textures);
+	}
+
+	@:access(h2d.Drawable)
+	public function beginDrawObject( obj : h2d.Drawable, texture : h3d.mat.Texture ) {
+		beginDraw(obj, texture, true);
+		baseShader.color.set(obj.color.r, obj.color.g, obj.color.b, obj.color.a);
+		baseShader.absoluteMatrixA.set(obj.matA, obj.matC, obj.absX);
+		baseShader.absoluteMatrixB.set(obj.matB, obj.matD, obj.absY);
+		beforeDraw();
+	}
+
+	@:access(h2d.Drawable)
+	public function beginDrawBatch( obj : h2d.Drawable, texture : h3d.mat.Texture ) {
+		beginDraw(obj, texture, false);
+	}
+
+	@:access(h2d.Drawable)
+	function beginDraw(	obj : h2d.Drawable, texture : h3d.mat.Texture, isRelative : Bool ) {
+		var stride = 8;
+		if( currentObj != null && (texture != this.texture || stride != this.stride || obj.blendMode != currentObj.blendMode || obj.filter != currentObj.filter) )
+			flush();
+		var shaderChanged = false, paramsChanged = false;
+		if( obj.shaders.length + 1 != currentShaders.length )
+			shaderChanged = true;
+		else {
+			for( i in 0...obj.shaders.length ) {
+				var s = obj.shaders[i];
+				var t = currentShaders[i + 1];
+				if( s == t ) continue;
+				paramsChanged = true;
+				s.updateConstants(manager.globals);
+				@:privateAccess {
+					if( s.instance != t.instance )
+						shaderChanged = true;
+				}
+			}
+		}
+		if( baseShader.isRelative != isRelative )
+			shaderChanged = true;
+		if( shaderChanged ) {
+			flush();
+			var ns = obj.shaders.copy();
+			ns.unshift(baseShader);
+			baseShader.isRelative = isRelative;
+			initShaders(ns);
+		} else if( paramsChanged ) {
+			flush();
+			// copy so the next flush will fetch their params
+			for( i in 0...obj.shaders.length )
+				currentShaders[i+1] = obj.shaders[i];
+		}
+
+		this.texture = texture;
+		this.stride = stride;
+		this.currentObj = obj;
+	}
+
+}

+ 31 - 31
h2d/ScaleGrid.hx

@@ -1,16 +1,16 @@
 package h2d;
 package h2d;
 
 
 class ScaleGrid extends h2d.TileGroup {
 class ScaleGrid extends h2d.TileGroup {
-	
+
 
 
 	public var borderWidth : Int;
 	public var borderWidth : Int;
 	public var borderHeight : Int;
 	public var borderHeight : Int;
-	
+
 	public var width(default,set) : Int;
 	public var width(default,set) : Int;
 	public var height(default,set) : Int;
 	public var height(default,set) : Int;
-	
+
 	public var tileBorders(default,set) : Bool;
 	public var tileBorders(default,set) : Bool;
-	
+
 	public function new( tile, borderW, borderH, ?parent ) {
 	public function new( tile, borderW, borderH, ?parent ) {
 		super(tile,parent);
 		super(tile,parent);
 		borderWidth = borderW;
 		borderWidth = borderW;
@@ -24,7 +24,7 @@ class ScaleGrid extends h2d.TileGroup {
 		reset();
 		reset();
 		return b;
 		return b;
 	}
 	}
-	
+
 	function set_width(w) {
 	function set_width(w) {
 		this.width = w;
 		this.width = w;
 		reset();
 		reset();
@@ -36,71 +36,71 @@ class ScaleGrid extends h2d.TileGroup {
 		reset();
 		reset();
 		return h;
 		return h;
 	}
 	}
-	
+
 	override function draw( ctx : RenderContext ) {
 	override function draw( ctx : RenderContext ) {
 		if( content.isEmpty() ) {
 		if( content.isEmpty() ) {
 			var bw = borderWidth, bh = borderHeight;
 			var bw = borderWidth, bh = borderHeight;
-			
+
 			// 4 corners
 			// 4 corners
-			content.add(0, 0, tile.sub(0, 0, bw, bh));
-			content.add(width - bw, 0, tile.sub(tile.width - bw, 0, bw, bh));
-			content.add(0, height-bh, tile.sub(0, tile.height - bh, bw, bh));
-			content.add(width - bw, height - bh, tile.sub(tile.width - bw, tile.height - bh, bw, bh));
+			content.addColor(0, 0, curColor, tile.sub(0, 0, bw, bh));
+			content.addColor(width - bw, 0, curColor, tile.sub(tile.width - bw, 0, bw, bh));
+			content.addColor(0, height-bh, curColor, tile.sub(0, tile.height - bh, bw, bh));
+			content.addColor(width - bw, height - bh, curColor, tile.sub(tile.width - bw, tile.height - bh, bw, bh));
 
 
 			var sizeX = tile.width - bw * 2;
 			var sizeX = tile.width - bw * 2;
 			var sizeY = tile.height - bh * 2;
 			var sizeY = tile.height - bh * 2;
-			
+
 			if( !tileBorders ) {
 			if( !tileBorders ) {
-				
+
 				var w = width - bw * 2;
 				var w = width - bw * 2;
 				var h = height - bh * 2;
 				var h = height - bh * 2;
-				
+
 				var t = tile.sub(bw, 0, sizeX, bh);
 				var t = tile.sub(bw, 0, sizeX, bh);
 				t.scaleToSize(w, bh);
 				t.scaleToSize(w, bh);
-				content.add(bw, 0, t);
+				content.addColor(bw, 0, curColor, t);
 
 
 				var t = tile.sub(bw, tile.height - bh, sizeX, bh);
 				var t = tile.sub(bw, tile.height - bh, sizeX, bh);
 				t.scaleToSize(w, bh);
 				t.scaleToSize(w, bh);
-				content.add(bw, h + bh, t);
+				content.addColor(bw, h + bh, curColor, t);
 
 
 				var t = tile.sub(0, bh, bw, sizeY);
 				var t = tile.sub(0, bh, bw, sizeY);
 				t.scaleToSize(bw, h);
 				t.scaleToSize(bw, h);
-				content.add(0, bh, t);
+				content.addColor(0, bh, curColor, t);
 
 
 				var t = tile.sub(tile.width - bw, bh, bw, sizeY);
 				var t = tile.sub(tile.width - bw, bh, bw, sizeY);
 				t.scaleToSize(bw, h);
 				t.scaleToSize(bw, h);
-				content.add(w + bw, bh, t);
-				
+				content.addColor(w + bw, bh, curColor, t);
+
 			} else {
 			} else {
-				
+
 				var rw = Std.int((width - bw * 2) / sizeX);
 				var rw = Std.int((width - bw * 2) / sizeX);
 				for( x in 0...rw ) {
 				for( x in 0...rw ) {
-					content.add(bw + x * sizeX, 0, tile.sub(bw, 0, sizeX, bh));
-					content.add(bw + x * sizeX, height - bh, tile.sub(bw, tile.height - bh, sizeX, bh));
+					content.addColor(bw + x * sizeX, 0, curColor, tile.sub(bw, 0, sizeX, bh));
+					content.addColor(bw + x * sizeX, height - bh, curColor, tile.sub(bw, tile.height - bh, sizeX, bh));
 				}
 				}
 				var dx = width - bw * 2 - rw * sizeX;
 				var dx = width - bw * 2 - rw * sizeX;
 				if( dx > 0 ) {
 				if( dx > 0 ) {
-					content.add(bw + rw * sizeX, 0, tile.sub(bw, 0, dx, bh));
-					content.add(bw + rw * sizeX, height - bh, tile.sub(bw, tile.height - bh, dx, bh));
+					content.addColor(bw + rw * sizeX, 0, curColor, tile.sub(bw, 0, dx, bh));
+					content.addColor(bw + rw * sizeX, height - bh, curColor, tile.sub(bw, tile.height - bh, dx, bh));
 				}
 				}
 
 
 				var rh = Std.int((height - bh * 2) / sizeY);
 				var rh = Std.int((height - bh * 2) / sizeY);
 				for( y in 0...rh ) {
 				for( y in 0...rh ) {
-					content.add(0, bh + y * sizeY, tile.sub(0, bh, bw, sizeY));
-					content.add(width - bw, bh + y * sizeY, tile.sub(tile.width - bw, bh, bw, sizeY));
+					content.addColor(0, bh + y * sizeY, curColor, tile.sub(0, bh, bw, sizeY));
+					content.addColor(width - bw, bh + y * sizeY, curColor, tile.sub(tile.width - bw, bh, bw, sizeY));
 				}
 				}
 				var dy = height - bh * 2 - rh * sizeY;
 				var dy = height - bh * 2 - rh * sizeY;
 				if( dy > 0 ) {
 				if( dy > 0 ) {
-					content.add(0, bh + rh * sizeY, tile.sub(0, bh, bw, dy));
-					content.add(width - bw, bh + rh * sizeY, tile.sub(tile.width - bw, bh, bw, dy));
+					content.addColor(0, bh + rh * sizeY, curColor, tile.sub(0, bh, bw, dy));
+					content.addColor(width - bw, bh + rh * sizeY, curColor, tile.sub(tile.width - bw, bh, bw, dy));
 				}
 				}
 			}
 			}
-			
+
 			var t = tile.sub(bw, bh, sizeX, sizeY);
 			var t = tile.sub(bw, bh, sizeX, sizeY);
 			t.scaleToSize(width - bw * 2,height - bh * 2);
 			t.scaleToSize(width - bw * 2,height - bh * 2);
-			content.add(bw, bh, t);
+			content.addColor(bw, bh, curColor, t);
 		}
 		}
 		super.draw(ctx);
 		super.draw(ctx);
 	}
 	}
-	
+
 }
 }

+ 13 - 2
h2d/Scene.hx

@@ -382,6 +382,16 @@ class Scene extends Layers implements h3d.IDrawable {
 		var h = -2 / height;
 		var h = -2 / height;
 		absX = absX * w - 1;
 		absX = absX * w - 1;
 		absY = absY * h + 1;
 		absY = absY * h + 1;
+
+		// half pixel align !
+		var engine = h3d.Engine.getCurrent();
+		absX += 1 / engine.width;
+		#if flash
+		absY -= 1 / engine.height;
+		#else
+		absY += 1 / engine.height;
+		#end
+
 		matA *= w;
 		matA *= w;
 		matB *= h;
 		matB *= h;
 		matC *= w;
 		matC *= w;
@@ -419,9 +429,11 @@ class Scene extends Layers implements h3d.IDrawable {
 		ctx.engine = engine;
 		ctx.engine = engine;
 		ctx.frame++;
 		ctx.frame++;
 		ctx.time += ctx.elapsedTime;
 		ctx.time += ctx.elapsedTime;
-		ctx.currentPass = 0;
 		sync(ctx);
 		sync(ctx);
+		if( childs.length == 0 ) return;
+		ctx.begin();
 		drawRec(ctx);
 		drawRec(ctx);
+		ctx.end();
 	}
 	}
 
 
 	override function sync( ctx : RenderContext ) {
 	override function sync( ctx : RenderContext ) {
@@ -432,7 +444,6 @@ class Scene extends Layers implements h3d.IDrawable {
 			height = ctx.engine.height;
 			height = ctx.engine.height;
 			posChanged = true;
 			posChanged = true;
 		}
 		}
-		Tools.checkCoreObjects();
 		super.sync(ctx);
 		super.sync(ctx);
 	}
 	}
 
 

+ 4 - 4
h2d/Scene3D.hx

@@ -1,16 +1,16 @@
 package h2d;
 package h2d;
 
 
 class Scene3D extends Sprite {
 class Scene3D extends Sprite {
-	
+
 	public var scene : h3d.scene.Scene;
 	public var scene : h3d.scene.Scene;
-	
+
 	public function new( scene, ?parent ) {
 	public function new( scene, ?parent ) {
 		super(parent);
 		super(parent);
 		this.scene = scene;
 		this.scene = scene;
 	}
 	}
-	
+
 	override function draw( ctx : RenderContext ) {
 	override function draw( ctx : RenderContext ) {
 		scene.render(ctx.engine);
 		scene.render(ctx.engine);
 	}
 	}
-	
+
 }
 }

+ 49 - 14
h2d/SpriteBatch.hx

@@ -21,19 +21,31 @@ class BatchElement {
 	public var y : Float;
 	public var y : Float;
 	public var scale : Float;
 	public var scale : Float;
 	public var rotation : Float;
 	public var rotation : Float;
-	public var alpha : Float;
+	public var r : Float;
+	public var g : Float;
+	public var b : Float;
+	public var a : Float;
 	public var t : Tile;
 	public var t : Tile;
+	public var alpha(get,set) : Float;
 	public var batch(default, null) : SpriteBatch;
 	public var batch(default, null) : SpriteBatch;
 
 
 	var prev : BatchElement;
 	var prev : BatchElement;
 	var next : BatchElement;
 	var next : BatchElement;
 
 
 	function new(t) {
 	function new(t) {
-		x = 0; y = 0; alpha = 1;
+		x = 0; y = 0; r = 1; g = 1; b = 1; a = 1;
 		rotation = 0; scale = 1;
 		rotation = 0; scale = 1;
 		this.t = t;
 		this.t = t;
 	}
 	}
 
 
+	inline function get_alpha() {
+		return a;
+	}
+
+	inline function set_alpha(v) {
+		return a = v;
+	}
+
 	function update(et:Float) {
 	function update(et:Float) {
 		return true;
 		return true;
 	}
 	}
@@ -56,7 +68,6 @@ class SpriteBatch extends Drawable {
 	public function new(t,?parent) {
 	public function new(t,?parent) {
 		super(parent);
 		super(parent);
 		tile = t;
 		tile = t;
-		shader.hasVertexAlpha = true;
 	}
 	}
 
 
 	public function add(e:BatchElement) {
 	public function add(e:BatchElement) {
@@ -153,25 +164,37 @@ class SpriteBatch extends Drawable {
 				tmp[pos++] = (py * ca + px * sa) * e.scale + e.y;
 				tmp[pos++] = (py * ca + px * sa) * e.scale + e.y;
 				tmp[pos++] = t.u;
 				tmp[pos++] = t.u;
 				tmp[pos++] = t.v;
 				tmp[pos++] = t.v;
-				tmp[pos++] = e.alpha;
+				tmp[pos++] = e.r;
+				tmp[pos++] = e.g;
+				tmp[pos++] = e.b;
+				tmp[pos++] = e.a;
 				var px = t.dx + hx, py = t.dy;
 				var px = t.dx + hx, py = t.dy;
 				tmp[pos++] = (px * ca - py * sa) * e.scale + e.x;
 				tmp[pos++] = (px * ca - py * sa) * e.scale + e.x;
 				tmp[pos++] = (py * ca + px * sa) * e.scale + e.y;
 				tmp[pos++] = (py * ca + px * sa) * e.scale + e.y;
 				tmp[pos++] = t.u2;
 				tmp[pos++] = t.u2;
 				tmp[pos++] = t.v;
 				tmp[pos++] = t.v;
-				tmp[pos++] = e.alpha;
+				tmp[pos++] = e.r;
+				tmp[pos++] = e.g;
+				tmp[pos++] = e.b;
+				tmp[pos++] = e.a;
 				var px = t.dx, py = t.dy + hy;
 				var px = t.dx, py = t.dy + hy;
 				tmp[pos++] = (px * ca - py * sa) * e.scale + e.x;
 				tmp[pos++] = (px * ca - py * sa) * e.scale + e.x;
 				tmp[pos++] = (py * ca + px * sa) * e.scale + e.y;
 				tmp[pos++] = (py * ca + px * sa) * e.scale + e.y;
 				tmp[pos++] = t.u;
 				tmp[pos++] = t.u;
 				tmp[pos++] = t.v2;
 				tmp[pos++] = t.v2;
-				tmp[pos++] = e.alpha;
+				tmp[pos++] = e.r;
+				tmp[pos++] = e.g;
+				tmp[pos++] = e.b;
+				tmp[pos++] = e.a;
 				var px = t.dx + hx, py = t.dy + hy;
 				var px = t.dx + hx, py = t.dy + hy;
 				tmp[pos++] = (px * ca - py * sa) * e.scale + e.x;
 				tmp[pos++] = (px * ca - py * sa) * e.scale + e.x;
 				tmp[pos++] = (py * ca + px * sa) * e.scale + e.y;
 				tmp[pos++] = (py * ca + px * sa) * e.scale + e.y;
 				tmp[pos++] = t.u2;
 				tmp[pos++] = t.u2;
 				tmp[pos++] = t.v2;
 				tmp[pos++] = t.v2;
-				tmp[pos++] = e.alpha;
+				tmp[pos++] = e.r;
+				tmp[pos++] = e.g;
+				tmp[pos++] = e.b;
+				tmp[pos++] = e.a;
 			} else {
 			} else {
 				var sx = e.x + t.dx;
 				var sx = e.x + t.dx;
 				var sy = e.y + t.dy;
 				var sy = e.y + t.dy;
@@ -179,27 +202,39 @@ class SpriteBatch extends Drawable {
 				tmp[pos++] = sy;
 				tmp[pos++] = sy;
 				tmp[pos++] = t.u;
 				tmp[pos++] = t.u;
 				tmp[pos++] = t.v;
 				tmp[pos++] = t.v;
-				tmp[pos++] = e.alpha;
+				tmp[pos++] = e.r;
+				tmp[pos++] = e.g;
+				tmp[pos++] = e.b;
+				tmp[pos++] = e.a;
 				tmp[pos++] = sx + t.width + 0.1;
 				tmp[pos++] = sx + t.width + 0.1;
 				tmp[pos++] = sy;
 				tmp[pos++] = sy;
 				tmp[pos++] = t.u2;
 				tmp[pos++] = t.u2;
 				tmp[pos++] = t.v;
 				tmp[pos++] = t.v;
-				tmp[pos++] = e.alpha;
+				tmp[pos++] = e.r;
+				tmp[pos++] = e.g;
+				tmp[pos++] = e.b;
+				tmp[pos++] = e.a;
 				tmp[pos++] = sx;
 				tmp[pos++] = sx;
 				tmp[pos++] = sy + t.height + 0.1;
 				tmp[pos++] = sy + t.height + 0.1;
 				tmp[pos++] = t.u;
 				tmp[pos++] = t.u;
 				tmp[pos++] = t.v2;
 				tmp[pos++] = t.v2;
-				tmp[pos++] = e.alpha;
+				tmp[pos++] = e.r;
+				tmp[pos++] = e.g;
+				tmp[pos++] = e.b;
+				tmp[pos++] = e.a;
 				tmp[pos++] = sx + t.width + 0.1;
 				tmp[pos++] = sx + t.width + 0.1;
 				tmp[pos++] = sy + t.height + 0.1;
 				tmp[pos++] = sy + t.height + 0.1;
 				tmp[pos++] = t.u2;
 				tmp[pos++] = t.u2;
 				tmp[pos++] = t.v2;
 				tmp[pos++] = t.v2;
-				tmp[pos++] = e.alpha;
+				tmp[pos++] = e.r;
+				tmp[pos++] = e.g;
+				tmp[pos++] = e.b;
+				tmp[pos++] = e.a;
 			}
 			}
 			e = e.next;
 			e = e.next;
 		}
 		}
-		var buffer = h3d.Buffer.ofFloats(tmpBuf, 5, [Dynamic, Quads], Std.int(pos/5));
-		setupShader(ctx.engine, tile, 0);
+		var buffer = h3d.Buffer.ofSubFloats(tmpBuf, 8, Std.int(pos/8), [Dynamic, Quads, RawFormat]);
+		ctx.beginDrawObject(this, tile.getTexture());
 		ctx.engine.renderQuadBuffer(buffer);
 		ctx.engine.renderQuadBuffer(buffer);
 		buffer.dispose();
 		buffer.dispose();
 	}
 	}
@@ -207,7 +242,7 @@ class SpriteBatch extends Drawable {
 	public inline function isEmpty() {
 	public inline function isEmpty() {
 		return first == null;
 		return first == null;
 	}
 	}
-	
+
 	public inline function getElements() {
 	public inline function getElements() {
 		return new ElementsIterator(first);
 		return new ElementsIterator(first);
 	}
 	}

+ 19 - 15
h2d/Text.hx

@@ -35,7 +35,7 @@ class Text extends Drawable {
 		this.font = font;
 		this.font = font;
 		if( glyphs != null ) glyphs.remove();
 		if( glyphs != null ) glyphs.remove();
 		glyphs = new TileGroup(font == null ? null : font.tile, this);
 		glyphs = new TileGroup(font == null ? null : font.tile, this);
-		shader = glyphs.shader;
+		glyphs.visible = false;
 		rebuild();
 		rebuild();
 		return font;
 		return font;
 	}
 	}
@@ -64,20 +64,23 @@ class Text extends Drawable {
 	}
 	}
 
 
 	override function draw(ctx:RenderContext) {
 	override function draw(ctx:RenderContext) {
-		glyphs.blendMode = blendMode;
 		if( dropShadow != null ) {
 		if( dropShadow != null ) {
-			glyphs.x += dropShadow.dx;
-			glyphs.y += dropShadow.dy;
-			glyphs.calcAbsPos();
-			var old = glyphs.color;
-			glyphs.color = h3d.Vector.fromColor(dropShadow.color);
-			glyphs.color.w = dropShadow.alpha;
-			glyphs.draw(ctx);
-			glyphs.x -= dropShadow.dx;
-			glyphs.y -= dropShadow.dy;
-			glyphs.color = old;
+			var oldX = absX, oldY = absY;
+			absX += dropShadow.dx * matA + dropShadow.dy * matC;
+			absY += dropShadow.dx * matB + dropShadow.dy * matD;
+			var oldR = color.r;
+			var oldG = color.g;
+			var oldB = color.b;
+			var oldA = color.a;
+			color.setColor(dropShadow.color);
+			color.a = dropShadow.alpha;
+			glyphs.drawWith(ctx, this);
+			absX = oldX;
+			absY = oldY;
+			color.set(oldR, oldG, oldB, oldA);
+			calcAbsPos();
 		}
 		}
-		super.draw(ctx);
+		glyphs.drawWith(ctx,this);
 	}
 	}
 
 
 	function set_text(t) {
 	function set_text(t) {
@@ -176,8 +179,9 @@ class Text extends Drawable {
 
 
 	function set_textColor(c) {
 	function set_textColor(c) {
 		this.textColor = c;
 		this.textColor = c;
-		glyphs.color = h3d.Vector.fromColor(c);
-		glyphs.color.w = alpha;
+		var a = alpha;
+		color.setColor(c);
+		color.w = a;
 		return c;
 		return c;
 	}
 	}
 
 

+ 36 - 58
h2d/Tile.hx

@@ -3,7 +3,15 @@ package h2d;
 @:allow(h2d)
 @:allow(h2d)
 class Tile {
 class Tile {
 
 
-	static inline var EPSILON_PIXEL = 0.001;
+	#if flash
+	static inline var EPSILON_POS = 0.;
+	static inline var EPSILON_SIZE_U = 0.;
+	static inline var EPSILON_SIZE_V = 0.;
+	#else
+	static inline var EPSILON_POS = 0;
+	static inline var EPSILON_SIZE_U = 0;
+	static inline var EPSILON_SIZE_V = 0.0001;
+	#end
 
 
 	var innerTex : h3d.mat.Texture;
 	var innerTex : h3d.mat.Texture;
 
 
@@ -30,7 +38,7 @@ class Tile {
 		if( tex != null ) setTexture(tex);
 		if( tex != null ) setTexture(tex);
 	}
 	}
 
 
-	public function getTexture() : h3d.mat.Texture {
+	public inline function getTexture() {
 		return innerTex;
 		return innerTex;
 	}
 	}
 
 
@@ -41,10 +49,10 @@ class Tile {
 	function setTexture(tex) {
 	function setTexture(tex) {
 		this.innerTex = tex;
 		this.innerTex = tex;
 		if( tex != null ) {
 		if( tex != null ) {
-			this.u = (x + EPSILON_PIXEL) / tex.width;
-			this.v = (y + EPSILON_PIXEL) / tex.height;
-			this.u2 = (x + width - EPSILON_PIXEL) / tex.width;
-			this.v2 = (y + height - EPSILON_PIXEL) / tex.height;
+			this.u = (x + EPSILON_POS) / tex.width;
+			this.v = (y + EPSILON_POS) / tex.height;
+			this.u2 = (x + width - EPSILON_SIZE_U) / tex.width;
+			this.v2 = (y + height - EPSILON_SIZE_V) / tex.height;
 		}
 		}
 	}
 	}
 
 
@@ -60,15 +68,25 @@ class Tile {
 		return sub(0, 0, width, height, -dx, -dy);
 		return sub(0, 0, width, height, -dx, -dy);
 	}
 	}
 
 
+	public function flipX() {
+		var tmp = u; u = u2; u2 = tmp;
+		dx = -dx - width;
+	}
+
+	public function flipY() {
+		var tmp = v; v = v2; v2 = tmp;
+		dy = -dy - height;
+	}
+
 	public function setPos(x, y) {
 	public function setPos(x, y) {
 		this.x = x;
 		this.x = x;
 		this.y = y;
 		this.y = y;
 		var tex = innerTex;
 		var tex = innerTex;
 		if( tex != null ) {
 		if( tex != null ) {
-			u = (x + EPSILON_PIXEL) / tex.width;
-			v = (y + EPSILON_PIXEL) / tex.height;
-			u2 = (width + x - EPSILON_PIXEL) / tex.width;
-			v2 = (height + y - EPSILON_PIXEL) / tex.height;
+			u = (x + EPSILON_POS) / tex.width;
+			v = (y + EPSILON_POS) / tex.height;
+			u2 = (width + x - EPSILON_SIZE_U) / tex.width;
+			v2 = (height + y - EPSILON_SIZE_V) / tex.height;
 		}
 		}
 	}
 	}
 
 
@@ -77,8 +95,8 @@ class Tile {
 		this.height = h;
 		this.height = h;
 		var tex = innerTex;
 		var tex = innerTex;
 		if( tex != null ) {
 		if( tex != null ) {
-			u2 = (w + x - EPSILON_PIXEL) / tex.width;
-			v2 = (h + y - EPSILON_PIXEL) / tex.height;
+			u2 = (w + x - EPSILON_SIZE_U) / tex.width;
+			v2 = (h + y - EPSILON_SIZE_V) / tex.height;
 		}
 		}
 	}
 	}
 
 
@@ -97,16 +115,6 @@ class Tile {
 		y = Std.int(v * tex.height);
 		y = Std.int(v * tex.height);
 	}
 	}
 
 
-	public function flipX() {
-		var tmp = u; u = u2; u2 = tmp;
-		dx = -dx - width;
-	}
-
-	public function flipY() {
-		var tmp = v; v = v2; v2 = tmp;
-		dy = -dy - height;
-	}
-
 	public function dispose() {
 	public function dispose() {
 		if( innerTex != null ) innerTex.dispose();
 		if( innerTex != null ) innerTex.dispose();
 		innerTex = null;
 		innerTex = null;
@@ -192,6 +200,9 @@ class Tile {
 	}
 	}
 
 
 	public static function autoCut( bmp : hxd.BitmapData, width : Int, ?height : Int, ?allocPos : h3d.impl.AllocPos ) {
 	public static function autoCut( bmp : hxd.BitmapData, width : Int, ?height : Int, ?allocPos : h3d.impl.AllocPos ) {
+		#if js
+		bmp.lock();
+		#end
 		if( height == null ) height = width;
 		if( height == null ) height = width;
 		var colorBG = bmp.getPixel(bmp.width - 1, bmp.height - 1);
 		var colorBG = bmp.getPixel(bmp.width - 1, bmp.height - 1);
 		var tl = new Array();
 		var tl = new Array();
@@ -211,6 +222,9 @@ class Tile {
 				a.push(new Tile(tex,x*width+sz.dx, y*height+sz.dy, sz.w, sz.h, sz.dx, sz.dy));
 				a.push(new Tile(tex,x*width+sz.dx, y*height+sz.dy, sz.w, sz.h, sz.dx, sz.dy));
 			}
 			}
 		}
 		}
+		#if js
+		bmp.unlock();
+		#end
 		var main = new Tile(tex, 0, 0, bmp.width, bmp.height);
 		var main = new Tile(tex, 0, 0, bmp.width, bmp.height);
 		main.upload(bmp);
 		main.upload(bmp);
 		return { main : main, tiles : tl };
 		return { main : main, tiles : tl };
@@ -227,42 +241,6 @@ class Tile {
 		return new Tile(t, 0, 0, pixels.width, pixels.height);
 		return new Tile(t, 0, 0, pixels.width, pixels.height);
 	}
 	}
 
 
-	#if flash
-	public static function fromSprites( sprites : Array<flash.display.Sprite>, ?allocPos : h3d.impl.AllocPos ) {
-		var tmp = [];
-		var width = 0;
-		var height = 0;
-		for( s in sprites ) {
-			var g = s.getBounds(s);
-			var dx = Math.floor(g.left);
-			var dy = Math.floor(g.top);
-			var w = Math.ceil(g.right) - dx;
-			var h = Math.ceil(g.bottom) - dy;
-			tmp.push( { s : s, x : width, dx : dx, dy : dy, w : w, h : h } );
-			width += w;
-			if( height < h ) height = h;
-		}
-		var rw = 1, rh = 1;
-		while( rw < width )
-			rw <<= 1;
-		while( rh < height )
-			rh <<= 1;
-		var bmp = new flash.display.BitmapData(rw, rh, true, 0);
-		var m = new flash.geom.Matrix();
-		for( t in tmp ) {
-			m.tx = t.x-t.dx;
-			m.ty = -t.dy;
-			bmp.draw(t.s, m);
-		}
-		var main = fromBitmap(hxd.BitmapData.fromNative(bmp), allocPos);
-		bmp.dispose();
-		var tiles = [];
-		for( t in tmp )
-			tiles.push(main.sub(t.x, 0, t.w, t.h, t.dx, t.dy));
-		return tiles;
-	}
-	#end
-
 	static function isEmpty( b : hxd.BitmapData, px, py, width, height, bg : Int ) {
 	static function isEmpty( b : hxd.BitmapData, px, py, width, height, bg : Int ) {
 		var empty = true;
 		var empty = true;
 		var xmin = width, ymin = height, xmax = 0, ymax = 0;
 		var xmin = width, ymin = height, xmax = 0, ymax = 0;

+ 0 - 214
h2d/TileColorGroup.hx

@@ -1,214 +0,0 @@
-package h2d;
-
-private class TileLayerContent extends h3d.prim.Primitive {
-
-	var tmp : hxd.FloatBuffer;
-	public var xMin : Float;
-	public var yMin : Float;
-	public var xMax : Float;
-	public var yMax : Float;
-
-	public function new() {
-		reset();
-	}
-
-	public function reset() {
-		tmp = new hxd.FloatBuffer();
-		if( buffer != null ) buffer.dispose();
-		buffer = null;
-		xMin = hxd.Math.POSITIVE_INFINITY;
-		yMin = hxd.Math.POSITIVE_INFINITY;
-		xMax = hxd.Math.NEGATIVE_INFINITY;
-		yMax = hxd.Math.NEGATIVE_INFINITY;
-	}
-
-	override public function triCount() {
-		if( buffer == null )
-			return tmp.length >> 4;
-		var v = 0;
-		var b = buffer;
-		while( b != null ) {
-			v += b.vertices;
-			b = b.next;
-		}
-		return v >> 1;
-	}
-
-	public function add( x : Int, y : Int, r : Float, g : Float, b : Float, a : Float, t : Tile ) {
-		var sx = x + t.dx;
-		var sy = y + t.dy;
-		var sx2 = sx + t.width;
-		var sy2 = sy + t.height;
-		tmp.push(sx);
-		tmp.push(sy);
-		tmp.push(t.u);
-		tmp.push(t.v);
-		tmp.push(r);
-		tmp.push(g);
-		tmp.push(b);
-		tmp.push(a);
-		tmp.push(sx2);
-		tmp.push(sy);
-		tmp.push(t.u2);
-		tmp.push(t.v);
-		tmp.push(r);
-		tmp.push(g);
-		tmp.push(b);
-		tmp.push(a);
-		tmp.push(sx);
-		tmp.push(sy2);
-		tmp.push(t.u);
-		tmp.push(t.v2);
-		tmp.push(r);
-		tmp.push(g);
-		tmp.push(b);
-		tmp.push(a);
-		tmp.push(sx2);
-		tmp.push(sy2);
-		tmp.push(t.u2);
-		tmp.push(t.v2);
-		tmp.push(r);
-		tmp.push(g);
-		tmp.push(b);
-		tmp.push(a);
-		if( sx < xMin ) xMin = sx;
-		if( sy < yMin ) yMin = sy;
-		if( sx2 > xMax ) xMax = sx2;
-		if( sy2 > yMax ) yMax = sy2;
-	}
-
-	public function addPoint( x : Float, y : Float, color : Int ) {
-		tmp.push(x);
-		tmp.push(y);
-		tmp.push(0);
-		tmp.push(0);
-		insertColor(color);
-	}
-
-	inline function insertColor( c : Int ) {
-		tmp.push(((c >> 16) & 0xFF) / 255.);
-		tmp.push(((c >> 8) & 0xFF) / 255.);
-		tmp.push((c & 0xFF) / 255.);
-		tmp.push((c >>> 24) / 255.);
-	}
-
-	public inline function rectColor( x : Float, y : Float, w : Float, h : Float, color : Int ) {
-		tmp.push(x);
-		tmp.push(y);
-		tmp.push(0);
-		tmp.push(0);
-		insertColor(color);
-		tmp.push(x + w);
-		tmp.push(y);
-		tmp.push(1);
-		tmp.push(0);
-		insertColor(color);
-		tmp.push(x);
-		tmp.push(y + h);
-		tmp.push(0);
-		tmp.push(1);
-		insertColor(color);
-		tmp.push(x + w);
-		tmp.push(y + h);
-		tmp.push(1);
-		tmp.push(1);
-		insertColor(color);
-	}
-
-	public inline function rectGradient( x : Float, y : Float, w : Float, h : Float, ctl : Int, ctr : Int, cbl : Int, cbr : Int ) {
-		tmp.push(x);
-		tmp.push(y);
-		tmp.push(0);
-		tmp.push(0);
-		insertColor(ctl);
-		tmp.push(x + w);
-		tmp.push(y);
-		tmp.push(1);
-		tmp.push(0);
-		insertColor(ctr);
-		tmp.push(x);
-		tmp.push(y + h);
-		tmp.push(0);
-		tmp.push(1);
-		insertColor(cbl);
-		tmp.push(x + w);
-		tmp.push(y + h);
-		tmp.push(1);
-		tmp.push(0);
-		insertColor(cbr);
-	}
-
-	override public function alloc(engine:h3d.Engine) {
-		if( tmp == null ) reset();
-		buffer = h3d.Buffer.ofFloats(tmp, 8, [Quads]);
-	}
-
-	public function doRender(engine, min, len) {
-		if( buffer == null || buffer.isDisposed() ) alloc(engine);
-		engine.renderQuadBuffer(buffer, min, len);
-	}
-
-}
-
-class TileColorGroup extends Drawable {
-
-	var content : TileLayerContent;
-	var curColor : h3d.Vector;
-
-	public var tile : Tile;
-	public var rangeMin : Int;
-	public var rangeMax : Int;
-
-	public function new(t,?parent) {
-		super(parent);
-		tile = t;
-		rangeMin = rangeMax = -1;
-		shader.hasVertexColor = true;
-		curColor = new h3d.Vector(1, 1, 1, 1);
-		content = new TileLayerContent();
-	}
-
-	public function reset() {
-		content.reset();
-	}
-
-	override function getBoundsRec( relativeTo, out ) {
-		super.getBoundsRec(relativeTo, out);
-		addBounds(relativeTo, out, content.xMin, content.yMin, content.xMax - content.xMin, content.yMax - content.yMin);
-	}
-
-	/**
-		Returns the number of tiles added to the group
-	**/
-	public function count() {
-		return content.triCount() >> 1;
-	}
-
-	override function onDelete() {
-		content.dispose();
-		super.onDelete();
-	}
-
-	public function setDefaultColor( rgb : Int, alpha = 1.0 ) {
-		curColor.x = ((rgb >> 16) & 0xFF) / 255;
-		curColor.y = ((rgb >> 8) & 0xFF) / 255;
-		curColor.z = (rgb & 0xFF) / 255;
-		curColor.w = alpha;
-	}
-
-	public inline function add(x, y, t) {
-		content.add(x, y, curColor.x, curColor.y, curColor.z, curColor.w, t);
-	}
-
-	public inline function addColor(x, y, r, g, b, a, t) {
-		content.add(x, y, r, g, b, a, t);
-	}
-
-	override function draw(ctx:RenderContext) {
-		setupShader(ctx.engine, tile, 0);
-		var min = rangeMin < 0 ? 0 : rangeMin * 2;
-		var max = content.triCount();
-		if( rangeMax > 0 && rangeMax < max * 2 ) max = rangeMax * 2;
-		content.doRender(ctx.engine, min, max - min);
-	}
-}

+ 127 - 29
h2d/TileGroup.hx

@@ -8,15 +8,10 @@ private class TileLayerContent extends h3d.prim.Primitive {
 	public var xMax : Float;
 	public var xMax : Float;
 	public var yMax : Float;
 	public var yMax : Float;
 
 
-
 	public function new() {
 	public function new() {
 		reset();
 		reset();
 	}
 	}
 
 
-	public function isEmpty() {
-		return buffer == null;
-	}
-
 	public function reset() {
 	public function reset() {
 		tmp = new hxd.FloatBuffer();
 		tmp = new hxd.FloatBuffer();
 		if( buffer != null ) buffer.dispose();
 		if( buffer != null ) buffer.dispose();
@@ -27,40 +22,124 @@ private class TileLayerContent extends h3d.prim.Primitive {
 		yMax = hxd.Math.NEGATIVE_INFINITY;
 		yMax = hxd.Math.NEGATIVE_INFINITY;
 	}
 	}
 
 
-	public function add( x : Int, y : Int, t : Tile ) {
-		var sx = x + t.dx;
-		var sy = y + t.dy;
-		var sx2 = sx + t.width;
-		var sy2 = sy + t.height;
+	public function isEmpty() {
+		return triCount() == 0;
+	}
+
+	override public function triCount() {
+		return if( buffer == null ) tmp.length >> 4 else buffer.totalVertices() >> 1;
+	}
+
+	public inline function addColor( x : Int, y : Int, color : h3d.Vector, t : Tile ) {
+		add(x, y, color.r, color.g, color.b, color.a, t);
+	}
+
+	public function add( x : Int, y : Int, r : Float, g : Float, b : Float, a : Float, t : Tile ) {
+		// +0.001 required for directx9 (only ?)
+		var sx = x + t.dx + 0.001;
+		var sy = y + t.dy + 0.001;
 		tmp.push(sx);
 		tmp.push(sx);
 		tmp.push(sy);
 		tmp.push(sy);
 		tmp.push(t.u);
 		tmp.push(t.u);
 		tmp.push(t.v);
 		tmp.push(t.v);
-		tmp.push(sx2);
+		tmp.push(r);
+		tmp.push(g);
+		tmp.push(b);
+		tmp.push(a);
+		tmp.push(sx + t.width);
 		tmp.push(sy);
 		tmp.push(sy);
 		tmp.push(t.u2);
 		tmp.push(t.u2);
 		tmp.push(t.v);
 		tmp.push(t.v);
+		tmp.push(r);
+		tmp.push(g);
+		tmp.push(b);
+		tmp.push(a);
 		tmp.push(sx);
 		tmp.push(sx);
-		tmp.push(sy2);
+		tmp.push(sy + t.height);
 		tmp.push(t.u);
 		tmp.push(t.u);
 		tmp.push(t.v2);
 		tmp.push(t.v2);
-		tmp.push(sx2);
-		tmp.push(sy2);
+		tmp.push(r);
+		tmp.push(g);
+		tmp.push(b);
+		tmp.push(a);
+		tmp.push(sx + t.width);
+		tmp.push(sy + t.height);
 		tmp.push(t.u2);
 		tmp.push(t.u2);
 		tmp.push(t.v2);
 		tmp.push(t.v2);
-		if( sx < xMin ) xMin = sx;
-		if( sy < yMin ) yMin = sy;
-		if( sx2 > xMax ) xMax = sx2;
-		if( sy2 > yMax ) yMax = sy2;
+		tmp.push(r);
+		tmp.push(g);
+		tmp.push(b);
+		tmp.push(a);
 	}
 	}
 
 
-	override public function triCount() {
-		return if( buffer == null ) tmp.length >> 3 else buffer.totalVertices() >> 1;
+	public function addPoint( x : Float, y : Float, color : Int ) {
+		tmp.push(x);
+		tmp.push(y);
+		tmp.push(0);
+		tmp.push(0);
+		insertColor(color);
+		if( x < xMin ) xMin = x;
+		if( y < yMin ) yMin = y;
+		if( x > xMax ) xMax = x;
+		if( y > yMax ) yMax = y;
+	}
+
+	inline function insertColor( c : Int ) {
+		tmp.push(((c >> 16) & 0xFF) / 255.);
+		tmp.push(((c >> 8) & 0xFF) / 255.);
+		tmp.push((c & 0xFF) / 255.);
+		tmp.push((c >>> 24) / 255.);
+	}
+
+	public inline function rectColor( x : Float, y : Float, w : Float, h : Float, color : Int ) {
+		tmp.push(x);
+		tmp.push(y);
+		tmp.push(0);
+		tmp.push(0);
+		insertColor(color);
+		tmp.push(x + w);
+		tmp.push(y);
+		tmp.push(1);
+		tmp.push(0);
+		insertColor(color);
+		tmp.push(x);
+		tmp.push(y + h);
+		tmp.push(0);
+		tmp.push(1);
+		insertColor(color);
+		tmp.push(x + w);
+		tmp.push(y + h);
+		tmp.push(1);
+		tmp.push(1);
+		insertColor(color);
+	}
+
+	public inline function rectGradient( x : Float, y : Float, w : Float, h : Float, ctl : Int, ctr : Int, cbl : Int, cbr : Int ) {
+		tmp.push(x);
+		tmp.push(y);
+		tmp.push(0);
+		tmp.push(0);
+		insertColor(ctl);
+		tmp.push(x + w);
+		tmp.push(y);
+		tmp.push(1);
+		tmp.push(0);
+		insertColor(ctr);
+		tmp.push(x);
+		tmp.push(y + h);
+		tmp.push(0);
+		tmp.push(1);
+		insertColor(cbl);
+		tmp.push(x + w);
+		tmp.push(y + h);
+		tmp.push(1);
+		tmp.push(0);
+		insertColor(cbr);
 	}
 	}
 
 
 	override public function alloc(engine:h3d.Engine) {
 	override public function alloc(engine:h3d.Engine) {
 		if( tmp == null ) reset();
 		if( tmp == null ) reset();
-		buffer = h3d.Buffer.ofFloats(tmp, 4, [Quads]);
+		buffer = h3d.Buffer.ofFloats(tmp, 8, [Quads, RawFormat]);
 	}
 	}
 
 
 	public function doRender(engine, min, len) {
 	public function doRender(engine, min, len) {
@@ -73,16 +152,18 @@ private class TileLayerContent extends h3d.prim.Primitive {
 class TileGroup extends Drawable {
 class TileGroup extends Drawable {
 
 
 	var content : TileLayerContent;
 	var content : TileLayerContent;
+	var curColor : h3d.Vector;
 
 
 	public var tile : Tile;
 	public var tile : Tile;
 	public var rangeMin : Int;
 	public var rangeMin : Int;
 	public var rangeMax : Int;
 	public var rangeMax : Int;
 
 
 	public function new(t,?parent) {
 	public function new(t,?parent) {
+		super(parent);
 		tile = t;
 		tile = t;
 		rangeMin = rangeMax = -1;
 		rangeMin = rangeMax = -1;
+		curColor = new h3d.Vector(1, 1, 1, 1);
 		content = new TileLayerContent();
 		content = new TileLayerContent();
-		super(parent);
 	}
 	}
 
 
 	override function getBoundsRec( relativeTo, out ) {
 	override function getBoundsRec( relativeTo, out ) {
@@ -94,27 +175,44 @@ class TileGroup extends Drawable {
 		content.reset();
 		content.reset();
 	}
 	}
 
 
+	/**
+		Returns the number of tiles added to the group
+	**/
+	public function count() {
+		return content.triCount() >> 1;
+	}
+
 	override function onDelete() {
 	override function onDelete() {
 		content.dispose();
 		content.dispose();
 		super.onDelete();
 		super.onDelete();
 	}
 	}
 
 
+	public function setDefaultColor( rgb : Int, alpha = 1.0 ) {
+		curColor.x = ((rgb >> 16) & 0xFF) / 255;
+		curColor.y = ((rgb >> 8) & 0xFF) / 255;
+		curColor.z = (rgb & 0xFF) / 255;
+		curColor.w = alpha;
+	}
+
 	public inline function add(x, y, t) {
 	public inline function add(x, y, t) {
-		content.add(x, y, t);
+		content.add(x, y, curColor.x, curColor.y, curColor.z, curColor.w, t);
 	}
 	}
 
 
-	/**
-		Returns the number of tiles added to the group
-	**/
-	public function count() {
-		return content.triCount() >> 1;
+	public inline function addColor(x, y, r, g, b, a, t) {
+		content.add(x, y, r, g, b, a, t);
 	}
 	}
 
 
 	override function draw(ctx:RenderContext) {
 	override function draw(ctx:RenderContext) {
-		setupShader(ctx.engine, tile, 0);
+		drawWith(ctx,this);
+	}
+
+	@:allow(h2d)
+	function drawWith( ctx:RenderContext, obj : Drawable ) {
+		ctx.beginDrawObject(obj, tile.getTexture());
 		var min = rangeMin < 0 ? 0 : rangeMin * 2;
 		var min = rangeMin < 0 ? 0 : rangeMin * 2;
 		var max = content.triCount();
 		var max = content.triCount();
 		if( rangeMax > 0 && rangeMax < max * 2 ) max = rangeMax * 2;
 		if( rangeMax > 0 && rangeMax < max * 2 ) max = rangeMax * 2;
 		content.doRender(ctx.engine, min, max - min);
 		content.doRender(ctx.engine, min, max - min);
 	}
 	}
+
 }
 }

+ 0 - 69
h2d/Tools.hx

@@ -1,69 +0,0 @@
-package h2d;
-
-private class CoreObjects  {
-	
-	public var tmpMatA : h3d.Vector;
-	public var tmpMatB : h3d.Vector;
-	public var tmpSize : h3d.Vector;
-	public var tmpUVPos : h3d.Vector;
-	public var tmpUVScale : h3d.Vector;
-	public var tmpColor : h3d.Vector;
-	public var tmpMatrix : h3d.Matrix;
-	public var tmpMaterial : h3d.mat.Material;
-	public var planBuffer : h3d.Buffer;
-	public var nullTile : Tile;
-	
-	var emptyTexture : h3d.mat.Texture;
-	
-	public function new() {
-		tmpMatA = new h3d.Vector();
-		tmpMatB = new h3d.Vector();
-		tmpColor = new h3d.Vector();
-		tmpSize = new h3d.Vector();
-		tmpUVPos = new h3d.Vector();
-		tmpUVScale = new h3d.Vector();
-		tmpMatrix = new h3d.Matrix();
-		tmpMaterial = new h3d.mat.Material(null);
-		tmpMaterial.culling = None;
-		tmpMaterial.depth(false, Always);
-		
-		var vector = new hxd.FloatBuffer();
-		for( pt in [[0, 0], [1, 0], [0, 1], [1, 1]] ) {
-			vector.push(pt[0]);
-			vector.push(pt[1]);
-			vector.push(pt[0]);
-			vector.push(pt[1]);
-		}
-		
-		planBuffer = new h3d.Buffer(4, 4, [Quads]);
-		planBuffer.uploadVector(vector, 0, 4);
-		nullTile = new Tile(null, 0, 0, 5, 5);
-	}
-	
-}
-
-class Tools {
-	
-	static var CORE : CoreObjects = null;
-	
-	@:allow(h2d)
-	static function getCoreObjects() {
-		var c = CORE;
-		if( c == null ) {
-			c = new CoreObjects();
-			CORE = c;
-		}
-		return c;
-	}
-	
-	@:allow(h2d)
-	@:access(h3d.impl.BigBuffer)
-	static function checkCoreObjects() {
-		var c = CORE;
-		if( c == null ) return;
-		// if we have lost our context
-		if( c.planBuffer.isDisposed() )
-			CORE = null;
-	}
-	
-}

+ 4 - 4
h2d/col/Circle.hx

@@ -6,13 +6,13 @@ class Circle {
 	public var x : Float;
 	public var x : Float;
 	public var y : Float;
 	public var y : Float;
 	public var ray : Float;
 	public var ray : Float;
-	
+
 	public inline function new( x : Float, y : Float, ray : Float ) {
 	public inline function new( x : Float, y : Float, ray : Float ) {
 		this.x = x;
 		this.x = x;
 		this.y = y;
 		this.y = y;
 		this.ray = ray;
 		this.ray = ray;
 	}
 	}
-	
+
 	public inline function distanceSq( p : Point ) {
 	public inline function distanceSq( p : Point ) {
 		var dx = p.x - x;
 		var dx = p.x - x;
 		var dy = p.y - y;
 		var dy = p.y - y;
@@ -25,7 +25,7 @@ class Circle {
 		var dy = p.y - y;
 		var dy = p.y - y;
 		return ray * ray - (dx * dx + dy * dy);
 		return ray * ray - (dx * dx + dy * dy);
 	}
 	}
-	
+
 	public inline function collideCircle( c : Circle ) {
 	public inline function collideCircle( c : Circle ) {
 		var dx = x - c.x;
 		var dx = x - c.x;
 		var dy = y - c.y;
 		var dy = y - c.y;
@@ -35,5 +35,5 @@ class Circle {
 	public function toString() {
 	public function toString() {
 		return '{${Math.fmt(x)},${Math.fmt(y)},${Math.fmt(ray)}}';
 		return '{${Math.fmt(x)},${Math.fmt(y)},${Math.fmt(ray)}}';
 	}
 	}
-	
+
 }
 }

File diff suppressed because it is too large
+ 0 - 0
h2d/col/Delaunay.hx


+ 6 - 6
h2d/col/Line.hx

@@ -9,18 +9,18 @@ class Line {
 		this.p1 = p1;
 		this.p1 = p1;
 		this.p2 = p2;
 		this.p2 = p2;
 	}
 	}
-	
+
 	public inline function side( p : Point ) {
 	public inline function side( p : Point ) {
 		return (p2.x - p1.x) * (p.y - p1.y) - (p2.y - p1.y) * (p.x - p1.x);
 		return (p2.x - p1.x) * (p.y - p1.y) - (p2.y - p1.y) * (p.x - p1.x);
 	}
 	}
-	
+
 	public inline function project( p : Point ) {
 	public inline function project( p : Point ) {
 		var dx = p2.x - p1.x;
 		var dx = p2.x - p1.x;
 		var dy = p2.y - p1.y;
 		var dy = p2.y - p1.y;
 		var k = ((p.x - p1.x) * dx + (p.y - p1.y) * dy) / (dx * dx + dy * dy);
 		var k = ((p.x - p1.x) * dx + (p.y - p1.y) * dy) / (dx * dx + dy * dy);
 		return new Point(dx * k + p1.x, dy * k + p1.y);
 		return new Point(dx * k + p1.x, dy * k + p1.y);
 	}
 	}
-	
+
 	public inline function intersect( l : Line ) {
 	public inline function intersect( l : Line ) {
 		var d = (p1.x - p2.x) * (l.p1.y - l.p2.y) - (p1.y - p2.y) * (l.p1.x - l.p2.x);
 		var d = (p1.x - p2.x) * (l.p1.y - l.p2.y) - (p1.y - p2.y) * (l.p1.x - l.p2.x);
 		if( hxd.Math.abs(d) < hxd.Math.EPSILON )
 		if( hxd.Math.abs(d) < hxd.Math.EPSILON )
@@ -40,7 +40,7 @@ class Line {
 		pt.y = (a * (l.p1.y - l.p2.y) - (p1.y - p2.y) * b) / d;
 		pt.y = (a * (l.p1.y - l.p2.y) - (p1.y - p2.y) * b) / d;
 		return true;
 		return true;
 	}
 	}
-	
+
 	public inline function distanceSq( p : Point ) {
 	public inline function distanceSq( p : Point ) {
 		var dx = p2.x - p1.x;
 		var dx = p2.x - p1.x;
 		var dy = p2.y - p1.y;
 		var dy = p2.y - p1.y;
@@ -49,9 +49,9 @@ class Line {
 		var my = dy * k + p1.y - p.y;
 		var my = dy * k + p1.y - p.y;
 		return mx * mx + my * my;
 		return mx * mx + my * my;
 	}
 	}
-	
+
 	public inline function distance( p : Point ) {
 	public inline function distance( p : Point ) {
 		return hxd.Math.sqrt(distanceSq(p));
 		return hxd.Math.sqrt(distanceSq(p));
 	}
 	}
-	
+
 }
 }

+ 7 - 7
h2d/col/Point.hx

@@ -2,29 +2,29 @@ package h2d.col;
 import hxd.Math;
 import hxd.Math;
 
 
 class Point {
 class Point {
-	
+
 	public var x : Float;
 	public var x : Float;
 	public var y : Float;
 	public var y : Float;
-	
+
 	public inline function new(x = 0., y = 0.) {
 	public inline function new(x = 0., y = 0.) {
 		this.x = x;
 		this.x = x;
 		this.y = y;
 		this.y = y;
 	}
 	}
-	
+
 	public inline function distanceSq( p : Point ) {
 	public inline function distanceSq( p : Point ) {
 		var dx = x - p.x;
 		var dx = x - p.x;
 		var dy = y - p.y;
 		var dy = y - p.y;
 		return dx * dx + dy * dy;
 		return dx * dx + dy * dy;
 	}
 	}
-	
+
 	public inline function distance( p : Point ) {
 	public inline function distance( p : Point ) {
 		return Math.sqrt(distanceSq(p));
 		return Math.sqrt(distanceSq(p));
 	}
 	}
-	
+
 	public function toString() {
 	public function toString() {
 		return "{" + Math.fmt(x) + "," + Math.fmt(y) + "}";
 		return "{" + Math.fmt(x) + "," + Math.fmt(y) + "}";
 	}
 	}
-		
+
 	public inline function sub( p : Point ) {
 	public inline function sub( p : Point ) {
 		return new Point(x - p.x, y - p.y);
 		return new Point(x - p.x, y - p.y);
 	}
 	}
@@ -61,5 +61,5 @@ class Point {
 		x *= f;
 		x *= f;
 		y *= f;
 		y *= f;
 	}
 	}
-	
+
 }
 }

+ 8 - 8
h2d/col/Poly.hx

@@ -5,11 +5,11 @@ class Poly {
 
 
 	public var points : Array<Point>;
 	public var points : Array<Point>;
 	var segments : Array<Seg>;
 	var segments : Array<Seg>;
-	
+
 	public function new( points ) {
 	public function new( points ) {
 		this.points = points;
 		this.points = points;
 	}
 	}
-		
+
 	public function isConvex() {
 	public function isConvex() {
 		for( i in 0...points.length ) {
 		for( i in 0...points.length ) {
 			var p1 = points[i];
 			var p1 = points[i];
@@ -20,7 +20,7 @@ class Poly {
 		}
 		}
 		return true;
 		return true;
 	}
 	}
-	
+
 	public function calculateArea() {
 	public function calculateArea() {
 		var s = 0.;
 		var s = 0.;
 		for( i in 0...points.length ) {
 		for( i in 0...points.length ) {
@@ -41,14 +41,14 @@ class Poly {
 		}
 		}
 		return segments;
 		return segments;
 	}
 	}
-	
+
 	public function hasPoint( p : Point ) {
 	public function hasPoint( p : Point ) {
 		for( s in getSegments() )
 		for( s in getSegments() )
 			if( s.side(p) < 0 )
 			if( s.side(p) < 0 )
 				return false;
 				return false;
 		return true;
 		return true;
 	}
 	}
-	
+
 	public function project( p : Point ) : Point {
 	public function project( p : Point ) : Point {
 		var dmin = 1e20, smin = null;
 		var dmin = 1e20, smin = null;
 		for( s in getSegments() ) {
 		for( s in getSegments() ) {
@@ -60,7 +60,7 @@ class Poly {
 		}
 		}
 		return smin.project(p);
 		return smin.project(p);
 	}
 	}
-	
+
 	public function distanceSq( p : Point ) {
 	public function distanceSq( p : Point ) {
 		var dmin = 1e20;
 		var dmin = 1e20;
 		for( s in getSegments() ) {
 		for( s in getSegments() ) {
@@ -69,9 +69,9 @@ class Poly {
 		}
 		}
 		return dmin;
 		return dmin;
 	}
 	}
-	
+
 	public inline function distance( p : Point ) {
 	public inline function distance( p : Point ) {
 		return Math.sqrt(distanceSq(p));
 		return Math.sqrt(distanceSq(p));
 	}
 	}
-	
+
 }
 }

+ 13 - 13
h2d/col/Polynomial.hx

@@ -4,7 +4,7 @@ private class Matrix {
 	public var data : haxe.ds.Vector<haxe.ds.Vector<Float>>;
 	public var data : haxe.ds.Vector<haxe.ds.Vector<Float>>;
 	public var m : Int;
 	public var m : Int;
 	public var n : Int;
 	public var n : Int;
-	
+
 	public function new(m, n) {
 	public function new(m, n) {
 		this.m = m;
 		this.m = m;
 		this.n = n;
 		this.n = n;
@@ -12,7 +12,7 @@ private class Matrix {
 		for( i in 0...m )
 		for( i in 0...m )
 			data[i] = new haxe.ds.Vector(n);
 			data[i] = new haxe.ds.Vector(n);
 	}
 	}
-	
+
 	public function clone() {
 	public function clone() {
 		var m2 = new Matrix(m, n);
 		var m2 = new Matrix(m, n);
 		for( i in 0...m )
 		for( i in 0...m )
@@ -20,25 +20,25 @@ private class Matrix {
 				m2.data[i][j] = data[i][j];
 				m2.data[i][j] = data[i][j];
 		return m2;
 		return m2;
 	}
 	}
-	
+
 	function toString() {
 	function toString() {
 		return "[" + [for( k in data ) "\n" + Std.string(k)].join("") + "\n]";
 		return "[" + [for( k in data ) "\n" + Std.string(k)].join("") + "\n]";
 	}
 	}
 }
 }
 
 
 private class QR {
 private class QR {
-	
+
 	var qr : haxe.ds.Vector<haxe.ds.Vector<Float>>;
 	var qr : haxe.ds.Vector<haxe.ds.Vector<Float>>;
 	var rDiag : haxe.ds.Vector<Float>;
 	var rDiag : haxe.ds.Vector<Float>;
 	var m : Int;
 	var m : Int;
 	var n : Int;
 	var n : Int;
-	
+
 	public function new( mat : Matrix ) {
 	public function new( mat : Matrix ) {
 		this.m = mat.m;
 		this.m = mat.m;
 		this.n = mat.n;
 		this.n = mat.n;
 		qr = mat.clone().data;
 		qr = mat.clone().data;
 		rDiag = new haxe.ds.Vector(n);
 		rDiag = new haxe.ds.Vector(n);
-		
+
 		for( k in 0...n ) {
 		for( k in 0...n ) {
 			var nrm = 0.;
 			var nrm = 0.;
 			for( i in k...m )
 			for( i in k...m )
@@ -60,14 +60,14 @@ private class QR {
 			rDiag[k] = -nrm;
 			rDiag[k] = -nrm;
 		}
 		}
 	}
 	}
-	
+
 	function isFullRank() {
 	function isFullRank() {
 		for( j in 0...n )
 		for( j in 0...n )
 			if( rDiag[j] == 0 )
 			if( rDiag[j] == 0 )
 				return false;
 				return false;
 		return true;
 		return true;
 	}
 	}
-	
+
 	public function solve( b : Matrix ) {
 	public function solve( b : Matrix ) {
 		if( b.m != m ) throw "Invalid matrix size";
 		if( b.m != m ) throw "Invalid matrix size";
 		if( !isFullRank() ) return null;
 		if( !isFullRank() ) return null;
@@ -96,7 +96,7 @@ private class QR {
 			beta.push(X[i][0]);
 			beta.push(X[i][0]);
 		return beta;
 		return beta;
 	}
 	}
-	
+
 	function hypot( x : Float, y : Float ) {
 	function hypot( x : Float, y : Float ) {
 		if( x < 0 ) x = -x;
 		if( x < 0 ) x = -x;
 		if( y < 0 ) y = -y;
 		if( y < 0 ) y = -y;
@@ -109,7 +109,7 @@ private class QR {
 		t = t/x;
 		t = t/x;
 		return x * Math.sqrt(1+t*t);
 		return x * Math.sqrt(1+t*t);
 	}
 	}
-	
+
 }
 }
 
 
 class Polynomial {
 class Polynomial {
@@ -129,11 +129,11 @@ class Polynomial {
 		for( i in 0...n )
 		for( i in 0...n )
 			for( j in 0...degree+1 )
 			for( j in 0...degree+1 )
 				x.data[i][j] = Math.pow(xVals[i], j);
 				x.data[i][j] = Math.pow(xVals[i], j);
-				
+
 		var y = new Matrix(yVals.length, n);
 		var y = new Matrix(yVals.length, n);
 		for( i in 0...yVals.length )
 		for( i in 0...yVals.length )
 			y.data[i][0] = yVals[i];
 			y.data[i][0] = yVals[i];
-		
+
 		var qr = new QR(x);
 		var qr = new QR(x);
 		var beta = qr.solve(y);
 		var beta = qr.solve(y);
 		if( beta == null ) {
 		if( beta == null ) {
@@ -142,5 +142,5 @@ class Polynomial {
 		}
 		}
 		return beta;
 		return beta;
 	}
 	}
-	
+
 }
 }

+ 3 - 3
h2d/col/RoundRect.hx

@@ -9,7 +9,7 @@ class RoundRect {
 	var dy : Float;
 	var dy : Float;
 	var lenSq : Float;
 	var lenSq : Float;
 	var invLenSq : Float;
 	var invLenSq : Float;
-	
+
 	public inline function new(x:Float,y:Float,w:Float,h:Float,rotation:Float) {
 	public inline function new(x:Float,y:Float,w:Float,h:Float,rotation:Float) {
 		if( w < h ) {
 		if( w < h ) {
 			var tmp = w;
 			var tmp = w;
@@ -47,7 +47,7 @@ class RoundRect {
 			pdx * pdx + pdy * pdy;
 			pdx * pdx + pdy * pdy;
 		}
 		}
 	}
 	}
-	
+
 	public inline function inside( p : Point ) {
 	public inline function inside( p : Point ) {
 		return distanceCenterSq(p) - ray * ray < 0;
 		return distanceCenterSq(p) - ray * ray < 0;
 	}
 	}
@@ -55,7 +55,7 @@ class RoundRect {
 	public inline function distance( p : Point ) {
 	public inline function distance( p : Point ) {
 		return Math.sqrt(distanceCenterSq(p)) - ray;
 		return Math.sqrt(distanceCenterSq(p)) - ray;
 	}
 	}
-	
+
 	public inline function getNormalAt( p : Point ) {
 	public inline function getNormalAt( p : Point ) {
 		var px = p.x - x;
 		var px = p.x - x;
 		var py = p.y - y;
 		var py = p.y - y;

+ 5 - 5
h2d/col/Seg.hx

@@ -9,11 +9,11 @@ class Seg {
 	public var dy : Float;
 	public var dy : Float;
 	public var lenSq : Float;
 	public var lenSq : Float;
 	public var invLenSq : Float;
 	public var invLenSq : Float;
-	
+
 	public inline function new( p1 : Point, p2 : Point ) {
 	public inline function new( p1 : Point, p2 : Point ) {
 		setPoints(p1, p2);
 		setPoints(p1, p2);
 	}
 	}
-	
+
 	public inline function setPoints( p1 : Point, p2 : Point ) {
 	public inline function setPoints( p1 : Point, p2 : Point ) {
 		x = p1.x;
 		x = p1.x;
 		y = p1.y;
 		y = p1.y;
@@ -22,11 +22,11 @@ class Seg {
 		lenSq = dx * dx + dy * dy;
 		lenSq = dx * dx + dy * dy;
 		invLenSq = 1 / lenSq;
 		invLenSq = 1 / lenSq;
 	}
 	}
-	
+
 	public inline function side( p : Point ) {
 	public inline function side( p : Point ) {
 		return dx * (p.y - y) - dy * (p.x - x);
 		return dx * (p.y - y) - dy * (p.x - x);
 	}
 	}
-	
+
 	public inline function distanceSq( p : Point ) {
 	public inline function distanceSq( p : Point ) {
 		var px = p.x - x;
 		var px = p.x - x;
 		var py = p.y - y;
 		var py = p.y - y;
@@ -48,7 +48,7 @@ class Seg {
 	public inline function distance( p : Point ) {
 	public inline function distance( p : Point ) {
 		return Math.sqrt(distanceSq(p));
 		return Math.sqrt(distanceSq(p));
 	}
 	}
-	
+
 	public inline function project( p : Point ) : Point {
 	public inline function project( p : Point ) : Point {
 		var px = p.x - x;
 		var px = p.x - x;
 		var py = p.y - y;
 		var py = p.y - y;

+ 7 - 7
h2d/col/Triangle.hx

@@ -1,26 +1,26 @@
 package h2d.col;
 package h2d.col;
 
 
 class Triangle {
 class Triangle {
-	
+
 	static inline var UNDEF = 1.1315e-17;
 	static inline var UNDEF = 1.1315e-17;
-	
+
 	public var a : Point;
 	public var a : Point;
 	public var b : Point;
 	public var b : Point;
 	public var c : Point;
 	public var c : Point;
 	var area : Float;
 	var area : Float;
 	var invArea : Float;
 	var invArea : Float;
-	
+
 	public inline function new( a : Point, b : Point, c : Point ) {
 	public inline function new( a : Point, b : Point, c : Point ) {
 		this.a = a;
 		this.a = a;
 		this.b = b;
 		this.b = b;
 		this.c = c;
 		this.c = c;
 		area = UNDEF;
 		area = UNDEF;
 	}
 	}
-	
+
 	public inline function getCenter() {
 	public inline function getCenter() {
 		return new Point((a.x + b.x + c.x) / 3, (a.y + b.y + c.y) / 3);
 		return new Point((a.x + b.x + c.x) / 3, (a.y + b.y + c.y) / 3);
 	}
 	}
-	
+
 	public function getArea() {
 	public function getArea() {
 		if( area == UNDEF ) {
 		if( area == UNDEF ) {
 			area = ((a.y * b.x - a.x * b.y) + (b.y * c.x - b.x * c.y) + (c.y * a.x - c.x * a.y)) * -0.5;
 			area = ((a.y * b.x - a.x * b.y) + (b.y * c.x - b.x * c.y) + (c.y * a.x - c.x * a.y)) * -0.5;
@@ -33,7 +33,7 @@ class Triangle {
 		getArea();
 		getArea();
 		return invArea;
 		return invArea;
 	}
 	}
-	
+
 	/**
 	/**
 		Calculate barycentric coordinates for the point p
 		Calculate barycentric coordinates for the point p
 	**/
 	**/
@@ -43,5 +43,5 @@ class Triangle {
 		var t = area * (a.x * b.y - a.y * b.x + (a.y - b.y) * p.x + (b.x - a.x) * p.y);
 		var t = area * (a.x * b.y - a.y * b.x + (a.y - b.y) * p.x + (b.x - a.x) * p.y);
 		return new h3d.col.Point(1 - s - t, s, t);
 		return new h3d.col.Point(1 - s - t, s, t);
 	}
 	}
-	
+
 }
 }

+ 17 - 17
h2d/col/Voronoi.hx

@@ -32,9 +32,9 @@ private class RBNode<T:RBNode<T>> {
 }
 }
 
 
 @:generic private class RBTree<T:RBNode<T>> {
 @:generic private class RBTree<T:RBNode<T>> {
-	
+
 	public var root : T;
 	public var root : T;
-	
+
 	public function new() {
 	public function new() {
 		this.root = null;
 		this.root = null;
     }
     }
@@ -320,17 +320,17 @@ private class RBNode<T:RBNode<T>> {
 }
 }
 
 
 class Cell {
 class Cell {
-	
+
 	public var id : Int;
 	public var id : Int;
 	public var point : Point;
 	public var point : Point;
 	public var halfedges : Array<Halfedge>;
 	public var halfedges : Array<Halfedge>;
-	
+
 	public function new(id, point) {
 	public function new(id, point) {
 		this.id = id;
 		this.id = id;
 		this.point = point;
 		this.point = point;
 		this.halfedges = [];
 		this.halfedges = [];
     }
     }
-	
+
 	public function getCircle() {
 	public function getCircle() {
 		// still not the best enclosing circle
 		// still not the best enclosing circle
 		// would require implementing http://www.personal.kent.edu/~rmuhamma/Compgeometry/MyCG/CG-Applets/Center/centercli.htm for complete solution
 		// would require implementing http://www.personal.kent.edu/~rmuhamma/Compgeometry/MyCG/CG-Applets/Center/centercli.htm for complete solution
@@ -371,7 +371,7 @@ class Cell {
 		halfedges.sort(sortByAngle);
 		halfedges.sort(sortByAngle);
 		return halfedges.length;
 		return halfedges.length;
 	}
 	}
-	
+
 	static function sortByAngle(a:Halfedge, b:Halfedge) {
 	static function sortByAngle(a:Halfedge, b:Halfedge) {
 		return b.angle > a.angle ? 1 : (b.angle < a.angle ? -1 : 0);
 		return b.angle > a.angle ? 1 : (b.angle < a.angle ? -1 : 0);
 	}
 	}
@@ -455,7 +455,7 @@ class Cell {
 			}
 			}
 		return 1;
 		return 1;
 	}
 	}
-	
+
 }
 }
 
 
 class Edge {
 class Edge {
@@ -467,7 +467,7 @@ class Edge {
 	public var rCell : Null<Cell>;
 	public var rCell : Null<Cell>;
 	public var va : Null<Point>;
 	public var va : Null<Point>;
 	public var vb : Null<Point>;
 	public var vb : Null<Point>;
-	
+
 	public function new(lPoint, rPoint) {
 	public function new(lPoint, rPoint) {
 		this.lPoint = lPoint;
 		this.lPoint = lPoint;
 		this.rPoint = rPoint;
 		this.rPoint = rPoint;
@@ -477,11 +477,11 @@ class Edge {
 
 
 
 
 class Halfedge {
 class Halfedge {
-	
+
 	public var point : Point;
 	public var point : Point;
 	public var edge : Edge;
 	public var edge : Edge;
 	public var angle : Float;
 	public var angle : Float;
-	
+
 	public function new(edge, lPoint:Point, rPoint:Point) {
 	public function new(edge, lPoint:Point, rPoint:Point) {
 		this.point = lPoint;
 		this.point = lPoint;
 		this.edge = edge;
 		this.edge = edge;
@@ -504,7 +504,7 @@ class Halfedge {
 				: Math.atan2(va.x-vb.x, vb.y-va.y);
 				: Math.atan2(va.x-vb.x, vb.y-va.y);
 		}
 		}
 	}
 	}
-	
+
 	public inline function getStartpoint() {
 	public inline function getStartpoint() {
 		return this.edge.lPoint == this.point ? this.edge.va : this.edge.vb;
 		return this.edge.lPoint == this.point ? this.edge.va : this.edge.vb;
     }
     }
@@ -512,7 +512,7 @@ class Halfedge {
 	public inline function getEndpoint() {
 	public inline function getEndpoint() {
 		return this.edge.lPoint == this.point ? this.edge.vb : this.edge.va;
 		return this.edge.lPoint == this.point ? this.edge.vb : this.edge.va;
     }
     }
-	
+
 	public inline function getTarget() {
 	public inline function getTarget() {
 		return this.edge.lCell != null && this.edge.lCell.point != point ? this.edge.lCell : this.edge.rCell;
 		return this.edge.lCell != null && this.edge.lCell.point != point ? this.edge.lCell : this.edge.rCell;
 	}
 	}
@@ -547,7 +547,7 @@ private class CircleEvent extends RBNode<CircleEvent> {
 }
 }
 
 
 class Voronoi {
 class Voronoi {
-	
+
 	var epsilon : Float;
 	var epsilon : Float;
 	var beachline : RBTree<Beachsection>;
 	var beachline : RBTree<Beachsection>;
 	var vertices : Array<Point>;
 	var vertices : Array<Point>;
@@ -646,7 +646,7 @@ class Voronoi {
 	function setEdgeEndpoint(edge, lPoint, rPoint, vertex) {
 	function setEdgeEndpoint(edge, lPoint, rPoint, vertex) {
 		this.setEdgeStartpoint(edge, rPoint, lPoint, vertex);
 		this.setEdgeStartpoint(edge, rPoint, lPoint, vertex);
     }
     }
-	
+
 
 
 	// rhill 2011-06-02: A lot of Beachsection instanciations
 	// rhill 2011-06-02: A lot of Beachsection instanciations
 	// occur during the computation of the Voronoi diagram,
 	// occur during the computation of the Voronoi diagram,
@@ -1406,7 +1406,7 @@ class Voronoi {
 		var r = b.y - a.y;
 		var r = b.y - a.y;
 		return r < 0 ? -1 : (r > 0 ? 1 : (b.x > a.x ? 1 : b.x < a.x ? -1 : 0));
 		return r < 0 ? -1 : (r > 0 ? 1 : (b.x > a.x ? 1 : b.x < a.x ? -1 : 0));
 	}
 	}
-	
+
 	// rhill 2011-05-19:
 	// rhill 2011-05-19:
 	//   Voronoi points are kept client-side now, to allow
 	//   Voronoi points are kept client-side now, to allow
 	//   user to freely modify content. At compute time,
 	//   user to freely modify content. At compute time,
@@ -1463,7 +1463,7 @@ class Voronoi {
 			// all done, quit
 			// all done, quit
 			else
 			else
 				break;
 				break;
-				
+
 		}
 		}
 
 
 		// wrapping-up:
 		// wrapping-up:
@@ -1475,7 +1475,7 @@ class Voronoi {
 
 
 		//   add missing edges in order to close opened cells
 		//   add missing edges in order to close opened cells
 		this.closeCells(bbox);
 		this.closeCells(bbox);
-		
+
 		var eid = 0;
 		var eid = 0;
 		for( e in edges ) {
 		for( e in edges ) {
 			e.id = eid++;
 			e.id = eid++;

+ 5 - 5
h2d/comp/Box.hx

@@ -1,17 +1,17 @@
 package h2d.comp;
 package h2d.comp;
 
 
 class Box extends Component {
 class Box extends Component {
-	
+
 	var input : h2d.Interactive;
 	var input : h2d.Interactive;
 	var scrollX : Float = 0.;
 	var scrollX : Float = 0.;
 	var scrollY : Float = 0.;
 	var scrollY : Float = 0.;
-	
+
 	public function new(?layout,?parent) {
 	public function new(?layout,?parent) {
 		super("box", parent);
 		super("box", parent);
 		if( layout == null ) layout = h2d.css.Defs.Layout.Inline;
 		if( layout == null ) layout = h2d.css.Defs.Layout.Inline;
 		addClass(":"+layout.getName().toLowerCase());
 		addClass(":"+layout.getName().toLowerCase());
 	}
 	}
-	
+
 	override function resizeRec( ctx : Context ) {
 	override function resizeRec( ctx : Context ) {
 		var extX = extLeft();
 		var extX = extLeft();
 		var extY = extTop();
 		var extY = extTop();
@@ -213,6 +213,6 @@ class Box extends Component {
 			}
 			}
 		}
 		}
 	}
 	}
-	
-	
+
+
 }
 }

+ 6 - 6
h2d/comp/Button.hx

@@ -1,11 +1,11 @@
 package h2d.comp;
 package h2d.comp;
 
 
 class Button extends Interactive {
 class Button extends Interactive {
-	
+
 	var tf : h2d.Text;
 	var tf : h2d.Text;
-	
+
 	public var text(default, set) : String;
 	public var text(default, set) : String;
-	
+
 	public function new(text, ?parent) {
 	public function new(text, ?parent) {
 		super("button",parent);
 		super("button",parent);
 		tf = new h2d.Text(null, this);
 		tf = new h2d.Text(null, this);
@@ -15,12 +15,12 @@ class Button extends Interactive {
 	function get_text() {
 	function get_text() {
 		return tf.text;
 		return tf.text;
 	}
 	}
-	
+
 	function set_text(t) {
 	function set_text(t) {
 		needRebuild = true;
 		needRebuild = true;
 		return text = t;
 		return text = t;
 	}
 	}
-	
+
 	override function resize( ctx : Context ) {
 	override function resize( ctx : Context ) {
 		if( ctx.measure ) {
 		if( ctx.measure ) {
 			tf.font = getFont();
 			tf.font = getFont();
@@ -32,5 +32,5 @@ class Button extends Interactive {
 		}
 		}
 		super.resize(ctx);
 		super.resize(ctx);
 	}
 	}
-	
+
 }
 }

+ 7 - 7
h2d/comp/Checkbox.hx

@@ -1,19 +1,19 @@
 package h2d.comp;
 package h2d.comp;
 
 
 class Checkbox extends Interactive {
 class Checkbox extends Interactive {
-	
+
 	public var checked(default, set) : Bool;
 	public var checked(default, set) : Bool;
-	
+
 	public function new(?parent) {
 	public function new(?parent) {
 		super("checkbox", parent);
 		super("checkbox", parent);
 		checked = false;
 		checked = false;
 	}
 	}
-	
+
 	function set_checked(b) {
 	function set_checked(b) {
 		toggleClass(":checked", b);
 		toggleClass(":checked", b);
 		return checked = b;
 		return checked = b;
 	}
 	}
-	
+
 	override function resize( ctx : Context ) {
 	override function resize( ctx : Context ) {
 		super.resize(ctx);
 		super.resize(ctx);
 		if( !ctx.measure ) {
 		if( !ctx.measure ) {
@@ -25,13 +25,13 @@ class Checkbox extends Interactive {
 			}
 			}
 		}
 		}
 	}
 	}
-	
+
 	override function onClick() {
 	override function onClick() {
 		checked = !checked;
 		checked = !checked;
 		onChange(checked);
 		onChange(checked);
 	}
 	}
-	
+
 	public dynamic function onChange( checked : Bool ) {
 	public dynamic function onChange( checked : Bool ) {
 	}
 	}
-	
+
 }
 }

+ 7 - 7
h2d/comp/Color.hx

@@ -1,10 +1,10 @@
 package h2d.comp;
 package h2d.comp;
 
 
 class Color extends Component {
 class Color extends Component {
-	
+
 	var input : h2d.Interactive;
 	var input : h2d.Interactive;
 	public var value(default, set) : Int;
 	public var value(default, set) : Int;
-	
+
 	public function new(?parent) {
 	public function new(?parent) {
 		super("color", parent);
 		super("color", parent);
 		input = new h2d.Interactive(0, 0, bg);
 		input = new h2d.Interactive(0, 0, bg);
@@ -24,12 +24,12 @@ class Color extends Component {
 		};
 		};
 		value = 0;
 		value = 0;
 	}
 	}
-	
+
 	function set_value(v) {
 	function set_value(v) {
 		needRebuild = true;
 		needRebuild = true;
 		return value = v;
 		return value = v;
 	}
 	}
-	
+
 	override function resize( ctx : Context ) {
 	override function resize( ctx : Context ) {
 		super.resize(ctx);
 		super.resize(ctx);
 		if( !ctx.measure ) {
 		if( !ctx.measure ) {
@@ -38,7 +38,7 @@ class Color extends Component {
 			bg.fillRectColor(extLeft() - style.marginLeft, extTop() - style.marginTop, contentWidth, contentHeight, 0xFF000000 | value);
 			bg.fillRectColor(extLeft() - style.marginLeft, extTop() - style.marginTop, contentWidth, contentHeight, 0xFF000000 | value);
 		}
 		}
 	}
 	}
-	
+
 	function selectColor() {
 	function selectColor() {
 		var p : Component = this;
 		var p : Component = this;
 		while( p.parentComponent != null )
 		while( p.parentComponent != null )
@@ -56,8 +56,8 @@ class Color extends Component {
 			b.remove();
 			b.remove();
 		};
 		};
 	}
 	}
-	
+
 	public dynamic function onChange( color : Int ) {
 	public dynamic function onChange( color : Int ) {
 	}
 	}
-	
+
 }
 }

+ 61 - 61
h2d/comp/ColorPicker.hx

@@ -30,7 +30,7 @@ private enum CompStyle {
 private class Style {
 private class Style {
 	public function new () {
 	public function new () {
 	}
 	}
-	
+
 	public static function get(kind:CompStyle) {
 	public static function get(kind:CompStyle) {
 		var style = new h2d.css.Style();
 		var style = new h2d.css.Style();
 		switch(kind) {
 		switch(kind) {
@@ -62,13 +62,13 @@ private class Arrow extends h2d.css.Fill {
 
 
 private class Cross extends h2d.css.Fill {
 private class Cross extends h2d.css.Fill {
 	var size:Float;
 	var size:Float;
-	
+
 	public function new (parent, size:Float, color = 0xff000000) {
 	public function new (parent, size:Float, color = 0xff000000) {
 		super(parent);
 		super(parent);
 		this.size = size;
 		this.size = size;
 		lineRect(FillStyle.Color(color), 0, 0, size, size, 1);
 		lineRect(FillStyle.Color(color), 0, 0, size, size, 1);
 	}
 	}
-	
+
 	public function setColor(color:Int) {
 	public function setColor(color:Int) {
 		reset();
 		reset();
 		lineRect(FillStyle.Color(color), 0, 0, size, size, 1);
 		lineRect(FillStyle.Color(color), 0, 0, size, size, 1);
@@ -82,12 +82,12 @@ private class Color extends h2d.Sprite {
 	public var color(default, set):Int = 0xFFFFFFFF;
 	public var color(default, set):Int = 0xFFFFFFFF;
 	public var preview(default, set):Int = 0xFFFFFFFF;
 	public var preview(default, set):Int = 0xFFFFFFFF;
 	public var alpha(default, set):Float = 1.;
 	public var alpha(default, set):Float = 1.;
-	
+
 	var canvas:h2d.css.Fill;
 	var canvas:h2d.css.Fill;
 	var label : h2d.comp.Label;
 	var label : h2d.comp.Label;
 	var input : h2d.comp.Input;
 	var input : h2d.comp.Input;
-	
-	
+
+
 	public function new (picker,ix, iy, iw, ih, parent) {
 	public function new (picker,ix, iy, iw, ih, parent) {
 		super(parent);
 		super(parent);
 		this.picker = picker;
 		this.picker = picker;
@@ -97,7 +97,7 @@ private class Color extends h2d.Sprite {
 		height = ih;
 		height = ih;
 		init();
 		init();
 	}
 	}
-	
+
 	function set_color(v:Int) {
 	function set_color(v:Int) {
 		if(v != color) {
 		if(v != color) {
 			color = v;
 			color = v;
@@ -105,7 +105,7 @@ private class Color extends h2d.Sprite {
 		}
 		}
 		return color;
 		return color;
 	}
 	}
-	
+
 	function set_preview(v:Int) {
 	function set_preview(v:Int) {
 		if(v != preview) {
 		if(v != preview) {
 			preview = v;
 			preview = v;
@@ -113,18 +113,18 @@ private class Color extends h2d.Sprite {
 		}
 		}
 		return color;
 		return color;
 	}
 	}
-	
+
 	function set_alpha(v:Float) {
 	function set_alpha(v:Float) {
 		alpha = v;
 		alpha = v;
 		drawAll();
 		drawAll();
 		return color;
 		return color;
 	}
 	}
-	
+
 	public function updateColor(v:Int) {
 	public function updateColor(v:Int) {
 		color = v;
 		color = v;
 		input.value = StringTools.hex(preview, 6).substr(2);
 		input.value = StringTools.hex(preview, 6).substr(2);
 	}
 	}
-	
+
 	function init() {
 	function init() {
 		label = new h2d.comp.Label("#", this);
 		label = new h2d.comp.Label("#", this);
 		label.setStyle(Style.get(ColorLabel));
 		label.setStyle(Style.get(ColorLabel));
@@ -144,12 +144,12 @@ private class Color extends h2d.Sprite {
 				picker.change = SColor;
 				picker.change = SColor;
 			}
 			}
 		};
 		};
-		
+
 		canvas = new h2d.css.Fill(this);
 		canvas = new h2d.css.Fill(this);
 		canvas.y = 2 + height * 0.5;
 		canvas.y = 2 + height * 0.5;
 		drawAll();
 		drawAll();
 	}
 	}
-	
+
 	public function drawAll() {
 	public function drawAll() {
 		canvas.reset();
 		canvas.reset();
 		canvas.fillRectColor(0, 0, width, height * 0.5, preview);
 		canvas.fillRectColor(0, 0, width, height * 0.5, preview);
@@ -164,12 +164,12 @@ private class Palette extends h2d.Sprite {
 	public var width :Float;
 	public var width :Float;
 	public var height :Float;
 	public var height :Float;
 	public var color(default, set):Int;
 	public var color(default, set):Int;
-	
+
 	var picker : ColorPicker;
 	var picker : ColorPicker;
 	var canvas:h2d.css.Fill;
 	var canvas:h2d.css.Fill;
 	var interact:h2d.Interactive;
 	var interact:h2d.Interactive;
 	var cursor:h2d.Sprite;
 	var cursor:h2d.Sprite;
-	
+
 	public function new (picker, ix, iy, iw, ih, parent) {
 	public function new (picker, ix, iy, iw, ih, parent) {
 		super(parent);
 		super(parent);
 		this.picker = picker;
 		this.picker = picker;
@@ -179,7 +179,7 @@ private class Palette extends h2d.Sprite {
 		height = ih;
 		height = ih;
 		init();
 		init();
 	}
 	}
-	
+
 	function init() {
 	function init() {
 		canvas = new h2d.css.Fill(this);
 		canvas = new h2d.css.Fill(this);
 		cursor = new h2d.Sprite(this);
 		cursor = new h2d.Sprite(this);
@@ -202,7 +202,7 @@ private class Palette extends h2d.Sprite {
 		color = getColor(0);
 		color = getColor(0);
 		drawAll();
 		drawAll();
 	}
 	}
-	
+
 	function set_color(v:Int) {
 	function set_color(v:Int) {
 		color = v;
 		color = v;
 		if(!picker.change.equals(SPalette))
 		if(!picker.change.equals(SPalette))
@@ -210,12 +210,12 @@ private class Palette extends h2d.Sprite {
 		drawAll();
 		drawAll();
 		return color;
 		return color;
 	}
 	}
-	
+
 	function updateCursor() {
 	function updateCursor() {
 		var hsl = ColorPicker.INTtoHSL(color);
 		var hsl = ColorPicker.INTtoHSL(color);
 		cursor.y = Math.round(Math.max(0, Math.min(height, (1 - hsl[0]) * height)));
 		cursor.y = Math.round(Math.max(0, Math.min(height, (1 - hsl[0]) * height)));
 	}
 	}
-	
+
 	public function drawAll() {
 	public function drawAll() {
 		var s = 1;
 		var s = 1;
 		var l = 0.5;
 		var l = 0.5;
@@ -228,19 +228,19 @@ private class Palette extends h2d.Sprite {
 		}
 		}
 		canvas.lineRect(FillStyle.Color(ColorPicker.borderColor), 0, 0, width, height, 1);
 		canvas.lineRect(FillStyle.Color(ColorPicker.borderColor), 0, 0, width, height, 1);
 	}
 	}
-	
+
 	public function setCursor(dy:Float) {
 	public function setCursor(dy:Float) {
 		cursor.y = Math.round(Math.max(0, Math.min(height, dy)));
 		cursor.y = Math.round(Math.max(0, Math.min(height, dy)));
 		color = getColor(cursor.y);
 		color = getColor(cursor.y);
 	}
 	}
-	
+
 	public function getColor(py:Float) {
 	public function getColor(py:Float) {
 		var h = 1 - (py / height);
 		var h = 1 - (py / height);
 		var s = 1;
 		var s = 1;
 		var l = 0.5;
 		var l = 0.5;
 		return(ColorPicker.HSLtoINT(h, s, l));
 		return(ColorPicker.HSLtoINT(h, s, l));
 	}
 	}
-	
+
 	public function setColorFrom(newColor:Int) {
 	public function setColorFrom(newColor:Int) {
 		var rgb = ColorPicker.INTtoRGB(newColor);
 		var rgb = ColorPicker.INTtoRGB(newColor);
 		var hsl = ColorPicker.RGBtoHLS(rgb[0], rgb[1], rgb[2]);
 		var hsl = ColorPicker.RGBtoHLS(rgb[0], rgb[1], rgb[2]);
@@ -255,7 +255,7 @@ private class Chart extends h2d.Sprite{
 	public var height :Int;
 	public var height :Int;
 	public var refColor(default, set):Int = 0xffffffff;
 	public var refColor(default, set):Int = 0xffffffff;
 	public var color:Int = 0xffffffff;
 	public var color:Int = 0xffffffff;
-	
+
 	var picker : ColorPicker;
 	var picker : ColorPicker;
 	var ray :Float;
 	var ray :Float;
 	var canvas:h2d.css.Fill;
 	var canvas:h2d.css.Fill;
@@ -263,7 +263,7 @@ private class Chart extends h2d.Sprite{
 	var cursor:h2d.Sprite;
 	var cursor:h2d.Sprite;
 	var lastPos:h3d.Vector;
 	var lastPos:h3d.Vector;
 	var cross:Cross ;
 	var cross:Cross ;
-	
+
 	public function new (picker,ix, iy, iw, ih, ray, parent) {
 	public function new (picker,ix, iy, iw, ih, ray, parent) {
 		super(parent);
 		super(parent);
 		this.picker = picker;
 		this.picker = picker;
@@ -274,7 +274,7 @@ private class Chart extends h2d.Sprite{
 		this.ray = ray;
 		this.ray = ray;
 		init();
 		init();
 	}
 	}
-	
+
 	function init() {
 	function init() {
 		canvas = new h2d.css.Fill(this);
 		canvas = new h2d.css.Fill(this);
 		cursor = new h2d.Sprite(this);
 		cursor = new h2d.Sprite(this);
@@ -296,7 +296,7 @@ private class Chart extends h2d.Sprite{
 		drawAll();
 		drawAll();
 		setCursor(0, 0);
 		setCursor(0, 0);
 	}
 	}
-	
+
 	public function setCursor(dx:Float, dy:Float) {
 	public function setCursor(dx:Float, dy:Float) {
 		cursor.x = Math.max(ray + 1, Math.min(width - ray - 1, dx));
 		cursor.x = Math.max(ray + 1, Math.min(width - ray - 1, dx));
 		cursor.y = Math.max(ray + 1, Math.min(height - ray - 1, dy));
 		cursor.y = Math.max(ray + 1, Math.min(height - ray - 1, dy));
@@ -304,7 +304,7 @@ private class Chart extends h2d.Sprite{
 		color = getColor(lastPos.x, lastPos.y);
 		color = getColor(lastPos.x, lastPos.y);
 		cross.setColor(ColorPicker.complementaryColor(color));
 		cross.setColor(ColorPicker.complementaryColor(color));
 	}
 	}
-	
+
 	function set_refColor(v:Int) {
 	function set_refColor(v:Int) {
 		refColor = v;
 		refColor = v;
 		color = getColor(lastPos.x, lastPos.y);
 		color = getColor(lastPos.x, lastPos.y);
@@ -312,13 +312,13 @@ private class Chart extends h2d.Sprite{
 		drawAll();
 		drawAll();
 		return refColor;
 		return refColor;
 	}
 	}
-	
+
 	function normalizePos(dx:Float, dy:Float) {
 	function normalizePos(dx:Float, dy:Float) {
 		var px = 1 - Math.min(width, Math.max(0, dx)) / width;
 		var px = 1 - Math.min(width, Math.max(0, dx)) / width;
 		var py = 1 - Math.min(height, Math.max(0, dy)) / height;
 		var py = 1 - Math.min(height, Math.max(0, dy)) / height;
 		return new h3d.Vector(px, py);
 		return new h3d.Vector(px, py);
 	}
 	}
-	
+
 	public function drawAll() {
 	public function drawAll() {
 		canvas.reset();
 		canvas.reset();
 		var rgb = [(refColor >> 16) & 0xFF, (refColor >> 8) & 0xFF,  refColor & 0xFF];
 		var rgb = [(refColor >> 16) & 0xFF, (refColor >> 8) & 0xFF,  refColor & 0xFF];
@@ -341,7 +341,7 @@ private class Chart extends h2d.Sprite{
 		}
 		}
 		canvas.lineRect(FillStyle.Color(ColorPicker.borderColor), 0, 0, width, height, 1);
 		canvas.lineRect(FillStyle.Color(ColorPicker.borderColor), 0, 0, width, height, 1);
 	}
 	}
-	
+
 	function getColor(dw:Float, dh:Float) {
 	function getColor(dw:Float, dh:Float) {
 		var rgb = [(refColor >> 16) & 0xFF, (refColor >> 8) & 0xFF,  refColor & 0xFF];
 		var rgb = [(refColor >> 16) & 0xFF, (refColor >> 8) & 0xFF,  refColor & 0xFF];
 		var r = Math.round(rgb[0] * dh);
 		var r = Math.round(rgb[0] * dh);
@@ -353,14 +353,14 @@ private class Chart extends h2d.Sprite{
 		b = Math.round(b + (max - b) * dw);
 		b = Math.round(b + (max - b) * dw);
 		return ColorPicker.RGBtoINT(r, g, b);
 		return ColorPicker.RGBtoINT(r, g, b);
 	}
 	}
-	
+
 	public function setColorFrom(newColor:Int) {
 	public function setColorFrom(newColor:Int) {
 		var rgb = ColorPicker.INTtoRGB(newColor);
 		var rgb = ColorPicker.INTtoRGB(newColor);
 		var hsl = ColorPicker.RGBtoHLS(rgb[0], rgb[1], rgb[2]);
 		var hsl = ColorPicker.RGBtoHLS(rgb[0], rgb[1], rgb[2]);
 		hsl[1] = 1; hsl[2] = 0.5;
 		hsl[1] = 1; hsl[2] = 0.5;
 		rgb = ColorPicker.HSLtoRGB(hsl[0], hsl[1], hsl[2]);
 		rgb = ColorPicker.HSLtoRGB(hsl[0], hsl[1], hsl[2]);
 		refColor = ColorPicker.RGBtoINT(rgb[0], rgb[1], rgb[2]);
 		refColor = ColorPicker.RGBtoINT(rgb[0], rgb[1], rgb[2]);
-		
+
 		var rgb = ColorPicker.INTtoRGB(newColor);
 		var rgb = ColorPicker.INTtoRGB(newColor);
 		var min = Math.min(rgb[0], Math.min(rgb[1], rgb[2]));
 		var min = Math.min(rgb[0], Math.min(rgb[1], rgb[2]));
 		var max = Math.max(rgb[0], Math.max(rgb[1], rgb[2]));
 		var max = Math.max(rgb[0], Math.max(rgb[1], rgb[2]));
@@ -375,7 +375,7 @@ private class ColorGauge extends h2d.Sprite{
 	public var height :Int;
 	public var height :Int;
 	public var color(default, set):Int = 0xffffffff;
 	public var color(default, set):Int = 0xffffffff;
 	public var ratio(get, null):Float;
 	public var ratio(get, null):Float;
-	
+
 	var picker : ColorPicker;
 	var picker : ColorPicker;
 	var canvas:h2d.css.Fill;
 	var canvas:h2d.css.Fill;
 	var interact:h2d.Interactive;
 	var interact:h2d.Interactive;
@@ -394,7 +394,7 @@ private class ColorGauge extends h2d.Sprite{
 		bindTo = rgba;
 		bindTo = rgba;
 		init();
 		init();
 	}
 	}
-	
+
 	function init() {
 	function init() {
 		label = new h2d.comp.Label(bindTo.getName(), this);
 		label = new h2d.comp.Label(bindTo.getName(), this);
 		label.setStyle(Style.get(GaugeLabel));
 		label.setStyle(Style.get(GaugeLabel));
@@ -407,7 +407,7 @@ private class ColorGauge extends h2d.Sprite{
 		input.onChange = function(e) {
 		input.onChange = function(e) {
 			setCursor(cursor.x);
 			setCursor(cursor.x);
 		};
 		};
-		
+
 		canvas = new h2d.css.Fill(this);
 		canvas = new h2d.css.Fill(this);
 		cursor = new h2d.Sprite(this);
 		cursor = new h2d.Sprite(this);
 		cursor.x = width;
 		cursor.x = width;
@@ -429,7 +429,7 @@ private class ColorGauge extends h2d.Sprite{
 		}
 		}
 		drawAll();
 		drawAll();
 	}
 	}
-	
+
 	function set_color(v:Int) {
 	function set_color(v:Int) {
 		color = v;
 		color = v;
 		if(!bindTo.equals(RGBA.A))
 		if(!bindTo.equals(RGBA.A))
@@ -437,7 +437,7 @@ private class ColorGauge extends h2d.Sprite{
 		drawAll();
 		drawAll();
 		return color;
 		return color;
 	}
 	}
-	
+
 	function setState() {
 	function setState() {
 		picker.change = switch(bindTo) {
 		picker.change = switch(bindTo) {
 			case RGBA.R: SRed;
 			case RGBA.R: SRed;
@@ -446,11 +446,11 @@ private class ColorGauge extends h2d.Sprite{
 			case RGBA.A: SAlpha;
 			case RGBA.A: SAlpha;
 		}
 		}
 	}
 	}
-	
+
 	public function get_ratio() {
 	public function get_ratio() {
 		return cursor.x / width;
 		return cursor.x / width;
 	}
 	}
-	
+
 	public function updateCursor() {
 	public function updateCursor() {
 		var a = color >>> 24;
 		var a = color >>> 24;
 		var r = (color >> 16) & 0xFF;
 		var r = (color >> 16) & 0xFF;
@@ -464,7 +464,7 @@ private class ColorGauge extends h2d.Sprite{
 		});
 		});
 		input.value = Std.string(Std.int(255 * ratio));
 		input.value = Std.string(Std.int(255 * ratio));
 	}
 	}
-	
+
 	public function setCursor(dx:Float) {
 	public function setCursor(dx:Float) {
 		cursor.x = Math.round(Math.max(0, Math.min(width, dx)));
 		cursor.x = Math.round(Math.max(0, Math.min(width, dx)));
 		var r = (color >> 16) & 0xFF;
 		var r = (color >> 16) & 0xFF;
@@ -478,7 +478,7 @@ private class ColorGauge extends h2d.Sprite{
 		}
 		}
 		input.value = Std.string(Math.round(255 * ratio));
 		input.value = Std.string(Math.round(255 * ratio));
 	}
 	}
-	
+
 	public function drawAll() {
 	public function drawAll() {
 		var r = (color >> 16) & 0xFF;
 		var r = (color >> 16) & 0xFF;
 		var g =	(color >> 8) & 0xFF;
 		var g =	(color >> 8) & 0xFF;
@@ -503,9 +503,9 @@ private class ColorGauge extends h2d.Sprite{
 
 
 @:allow(h2d.comp)
 @:allow(h2d.comp)
 class ColorPicker extends h2d.comp.Component {
 class ColorPicker extends h2d.comp.Component {
-	
+
 	public static var borderColor = 0xFFaaaaaa;
 	public static var borderColor = 0xFFaaaaaa;
-	
+
 	var finalColor : Color;
 	var finalColor : Color;
 	var palette : Palette;
 	var palette : Palette;
 	var chart : Chart;
 	var chart : Chart;
@@ -515,18 +515,18 @@ class ColorPicker extends h2d.comp.Component {
 	var gaugeAlpha : ColorGauge;
 	var gaugeAlpha : ColorGauge;
 	var timer : haxe.Timer;
 	var timer : haxe.Timer;
 	var change : ChangeState;
 	var change : ChangeState;
-	
+
 	public var color(get, set) : Int;
 	public var color(get, set) : Int;
-	
+
 	public function new(?parent) {
 	public function new(?parent) {
 		super("colorpicker", parent);
 		super("colorpicker", parent);
 		init();
 		init();
 	}
 	}
-	
+
 	inline function get_color() {
 	inline function get_color() {
 		return (finalColor.color&0xFFFFFF) | Std.int(finalColor.alpha*255) << 24;
 		return (finalColor.color&0xFFFFFF) | Std.int(finalColor.alpha*255) << 24;
 	}
 	}
-	
+
 	function set_color(v) {
 	function set_color(v) {
 		finalColor.color = v;
 		finalColor.color = v;
 		finalColor.alpha = (v >>> 24) / 255;
 		finalColor.alpha = (v >>> 24) / 255;
@@ -538,7 +538,7 @@ class ColorPicker extends h2d.comp.Component {
 		gaugeAlpha.setCursor(finalColor.alpha * gaugeAlpha.width);
 		gaugeAlpha.setCursor(finalColor.alpha * gaugeAlpha.width);
 		return v;
 		return v;
 	}
 	}
-	
+
 	override function onAlloc() {
 	override function onAlloc() {
 		super.onAlloc();
 		super.onAlloc();
 		if( timer == null ) {
 		if( timer == null ) {
@@ -546,7 +546,7 @@ class ColorPicker extends h2d.comp.Component {
 			timer.run = doUpdate;
 			timer.run = doUpdate;
 		}
 		}
 	}
 	}
-	
+
 	override function onDelete() {
 	override function onDelete() {
 		super.onDelete();
 		super.onDelete();
 		if( timer != null ) {
 		if( timer != null ) {
@@ -554,7 +554,7 @@ class ColorPicker extends h2d.comp.Component {
 			timer = null;
 			timer = null;
 		}
 		}
 	}
 	}
-	
+
 	function init() {
 	function init() {
 		finalColor = new Color(this, 15, 8, 175, 45, this);
 		finalColor = new Color(this, 15, 8, 175, 45, this);
 		palette = new Palette(this, 16, 65, 20, 140, this);
 		palette = new Palette(this, 16, 65, 20, 140, this);
@@ -584,7 +584,7 @@ class ColorPicker extends h2d.comp.Component {
 			}
 			}
 			return;
 			return;
 		}
 		}
-			
+
 		switch(change) {
 		switch(change) {
 			case SColor:	palette.setColorFrom(finalColor.color);
 			case SColor:	palette.setColorFrom(finalColor.color);
 							chart.setColorFrom(finalColor.color);
 							chart.setColorFrom(finalColor.color);
@@ -601,32 +601,32 @@ class ColorPicker extends h2d.comp.Component {
 							onChange(color);
 							onChange(color);
 			default:
 			default:
 		}
 		}
-		
+
 		gaugeRed.color = chart.color;
 		gaugeRed.color = chart.color;
 		gaugeGreen.color = chart.color;
 		gaugeGreen.color = chart.color;
 		gaugeBlue.color = chart.color;
 		gaugeBlue.color = chart.color;
 	}
 	}
-	
+
 	public dynamic function onClose() {
 	public dynamic function onClose() {
 	}
 	}
-	
+
 	public dynamic function onChange( value : Int ) {
 	public dynamic function onChange( value : Int ) {
 	}
 	}
-	
+
 //////////////////
 //////////////////
 	public static function INTtoRGB(color:Int) {
 	public static function INTtoRGB(color:Int) {
 		return [(color >> 16) & 0xFF, (color >> 8) & 0xFF,  color & 0xFF];
 		return [(color >> 16) & 0xFF, (color >> 8) & 0xFF,  color & 0xFF];
 	}
 	}
-	
+
 	public static function INTtoHSL(color:Int) {
 	public static function INTtoHSL(color:Int) {
 		var rgb = INTtoRGB(color);
 		var rgb = INTtoRGB(color);
 		return RGBtoHLS(rgb[0], rgb[1], rgb[2]);
 		return RGBtoHLS(rgb[0], rgb[1], rgb[2]);
 	}
 	}
-	
+
 	public static function RGBtoINT(r:Int, g:Int, b:Int, a:Int = 255) {
 	public static function RGBtoINT(r:Int, g:Int, b:Int, a:Int = 255) {
 		return (a << 24) | (r << 16) | (g << 8) | b;
 		return (a << 24) | (r << 16) | (g << 8) | b;
 	}
 	}
-	
+
 	public static function RGBtoHLS(r:Float, g:Float, b:Float) {
 	public static function RGBtoHLS(r:Float, g:Float, b:Float) {
 		r /= 255;
 		r /= 255;
 		g /= 255;
 		g /= 255;
@@ -649,12 +649,12 @@ class ColorPicker extends h2d.comp.Component {
 		}
 		}
 		return [h, s, l];
 		return [h, s, l];
 	}
 	}
-	
+
 	public static function HSLtoINT(h:Float, s:Float, l:Float) {
 	public static function HSLtoINT(h:Float, s:Float, l:Float) {
 		var rgb = HSLtoRGB(h, s, l);
 		var rgb = HSLtoRGB(h, s, l);
 		return RGBtoINT(rgb[0], rgb[1], rgb[2]);
 		return RGBtoINT(rgb[0], rgb[1], rgb[2]);
 	}
 	}
-	
+
 	public static function HSLtoRGB(h:Float, s:Float, l:Float) {
 	public static function HSLtoRGB(h:Float, s:Float, l:Float) {
 		var r, g, b;
 		var r, g, b;
 		if(s == 0)
 		if(s == 0)
@@ -676,7 +676,7 @@ class ColorPicker extends h2d.comp.Component {
 		}
 		}
 		return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
 		return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
 	}
 	}
-	
+
 	public static function complementaryColor (color:Int) {
 	public static function complementaryColor (color:Int) {
 		var rgb = INTtoRGB(color);
 		var rgb = INTtoRGB(color);
 		var r = rgb[0] ^ 0xFF;
 		var r = rgb[0] ^ 0xFF;

+ 1 - 2
h2d/comp/Component.hx

@@ -248,8 +248,7 @@ class Component extends Sprite {
 				iconBmp.y = extTop() - style.paddingTop + style.iconTop;
 				iconBmp.y = extTop() - style.paddingTop + style.iconTop;
 				iconBmp.tile = Context.makeTileIcon(style.icon);
 				iconBmp.tile = Context.makeTileIcon(style.icon);
 				iconBmp.colorKey = 0xFFFF00FF;
 				iconBmp.colorKey = 0xFFFF00FF;
-				if( iconBmp.color == null ) iconBmp.color = new h3d.Vector(1, 1, 1, 1);
-				iconBmp.color.loadColor(style.iconColor != null ? style.iconColor : 0xFFFFFFFF);
+				iconBmp.color.setColor(style.iconColor != null ? style.iconColor : 0xFFFFFFFF);
 			} else if( iconBmp != null ) {
 			} else if( iconBmp != null ) {
 				iconBmp.remove();
 				iconBmp.remove();
 				iconBmp = null;
 				iconBmp = null;

+ 9 - 9
h2d/comp/Context.hx

@@ -1,7 +1,7 @@
 package h2d.comp;
 package h2d.comp;
 
 
 class Context {
 class Context {
-	
+
 	// measure props
 	// measure props
 	public var measure : Bool;
 	public var measure : Bool;
 	public var maxWidth : Float;
 	public var maxWidth : Float;
@@ -9,19 +9,19 @@ class Context {
 	// arrange props
 	// arrange props
 	public var xPos : Null<Float>;
 	public var xPos : Null<Float>;
 	public var yPos : Null<Float>;
 	public var yPos : Null<Float>;
-	
+
 	public function new(w, h) {
 	public function new(w, h) {
 		this.maxWidth = w;
 		this.maxWidth = w;
 		this.maxHeight = h;
 		this.maxHeight = h;
 		measure = true;
 		measure = true;
 	}
 	}
-	
+
 	// ------------- STATIC API ---------------------------------------
 	// ------------- STATIC API ---------------------------------------
-	
+
 	public static function getFont( name : String, size : Int ) {
 	public static function getFont( name : String, size : Int ) {
 		return hxd.res.FontBuilder.getFont(name, size);
 		return hxd.res.FontBuilder.getFont(name, size);
 	}
 	}
-	
+
 	public static function makeTileIcon( pixels : hxd.Pixels ) : h2d.Tile {
 	public static function makeTileIcon( pixels : hxd.Pixels ) : h2d.Tile {
 		var t = cachedIcons.get(pixels);
 		var t = cachedIcons.get(pixels);
 		if( t != null && !t.isDisposed() )
 		if( t != null && !t.isDisposed() )
@@ -30,11 +30,11 @@ class Context {
 		cachedIcons.set(pixels, t);
 		cachedIcons.set(pixels, t);
 		return t;
 		return t;
 	}
 	}
-	
+
 	static var cachedIcons = new Map<hxd.Pixels,h2d.Tile>();
 	static var cachedIcons = new Map<hxd.Pixels,h2d.Tile>();
-		
+
 	public static var DEFAULT_CSS = hxd.res.Embed.getFileContent("h2d/css/default.css");
 	public static var DEFAULT_CSS = hxd.res.Embed.getFileContent("h2d/css/default.css");
-	
+
 	static var DEF = null;
 	static var DEF = null;
 	public static function getDefaultCss() {
 	public static function getDefaultCss() {
 		if( DEF != null )
 		if( DEF != null )
@@ -43,5 +43,5 @@ class Context {
 		e.addRules(DEFAULT_CSS);
 		e.addRules(DEFAULT_CSS);
 		return e;
 		return e;
 	}
 	}
-	
+
 }
 }

+ 76 - 76
h2d/comp/GradientEditor.hx

@@ -18,7 +18,7 @@ private enum CompStyle {
 private class Style {
 private class Style {
 	public function new () {
 	public function new () {
 	}
 	}
-	
+
 	public static function get(kind:CompStyle) {
 	public static function get(kind:CompStyle) {
 		var style = new h2d.css.Style();
 		var style = new h2d.css.Style();
 		switch(kind) {
 		switch(kind) {
@@ -35,7 +35,7 @@ private class Style {
 }
 }
 
 
 private class CFlag extends h2d.css.Fill {
 private class CFlag extends h2d.css.Fill {
-	
+
 	public function new (parent, x:Float, y:Float, ang = 0., color = 0xff000000, border = 0xFFaaaaaa) {
 	public function new (parent, x:Float, y:Float, ang = 0., color = 0xff000000, border = 0xFFaaaaaa) {
 		super(parent);
 		super(parent);
 		var fill = this;
 		var fill = this;
@@ -43,26 +43,26 @@ private class CFlag extends h2d.css.Fill {
 		fill.x = x;
 		fill.x = x;
 		fill.y = y;
 		fill.y = y;
 		//bg
 		//bg
-		
+
 		// bgarrow
 		// bgarrow
 		fill.addPoint(-5, -4, border);
 		fill.addPoint(-5, -4, border);
 		fill.addPoint(5, -4, border);
 		fill.addPoint(5, -4, border);
 		fill.addPoint(0, 0, border);
 		fill.addPoint(0, 0, border);
 		fill.addPoint(0, 0, border);
 		fill.addPoint(0, 0, border);
-		
+
 		// bgsquare
 		// bgsquare
 		var dy = -5;
 		var dy = -5;
 		fill.addPoint(-5, -9 + dy, border);
 		fill.addPoint(-5, -9 + dy, border);
 		fill.addPoint(5, -9 + dy, border);
 		fill.addPoint(5, -9 + dy, border);
 		fill.addPoint(-5, 1 + dy, border);
 		fill.addPoint(-5, 1 + dy, border);
 		fill.addPoint(5, 1 + dy, border);
 		fill.addPoint(5, 1 + dy, border);
-		
+
 		// arrow
 		// arrow
 		fill.addPoint(-4, -5, color);
 		fill.addPoint(-4, -5, color);
 		fill.addPoint(4, -5, color);
 		fill.addPoint(4, -5, color);
 		fill.addPoint(0, 0, color);
 		fill.addPoint(0, 0, color);
 		fill.addPoint(0, 0, color);
 		fill.addPoint(0, 0, color);
-		
+
 		// square
 		// square
 		fill.addPoint(-4, -8+dy, color);
 		fill.addPoint(-4, -8+dy, color);
 		fill.addPoint(4, -8+dy, color);
 		fill.addPoint(4, -8+dy, color);
@@ -82,7 +82,7 @@ private class Cursor extends h2d.Sprite {
 	var ang:Float;
 	var ang:Float;
 	var interact:h2d.Interactive;
 	var interact:h2d.Interactive;
 	var flag:CFlag;
 	var flag:CFlag;
-	
+
 	public function new(gradient,ix, iy, kind, value, ang, parent) {
 	public function new(gradient,ix, iy, kind, value, ang, parent) {
 		super(parent);
 		super(parent);
 		this.gradient = gradient;
 		this.gradient = gradient;
@@ -93,7 +93,7 @@ private class Cursor extends h2d.Sprite {
 		this.kind = kind;
 		this.kind = kind;
 		init();
 		init();
 	}
 	}
-	
+
 	function set_value(v) {
 	function set_value(v) {
 		value = v;
 		value = v;
 		if(flag != null) {
 		if(flag != null) {
@@ -106,11 +106,11 @@ private class Cursor extends h2d.Sprite {
 		}
 		}
 		return value;
 		return value;
 	}
 	}
-	
+
 	function get_coeff() {
 	function get_coeff() {
 		return x / gradient.boxWidth;
 		return x / gradient.boxWidth;
 	}
 	}
-	
+
 	function init() {
 	function init() {
 		cursor = new h2d.Sprite(this);
 		cursor = new h2d.Sprite(this);
 		switch(kind) {
 		switch(kind) {
@@ -122,11 +122,11 @@ private class Cursor extends h2d.Sprite {
 		interact.x = -5;
 		interact.x = -5;
 		if(kind.equals(KAlpha))
 		if(kind.equals(KAlpha))
 			interact.y = -14;
 			interact.y = -14;
-			
+
 		interact.onPush = function(e) drag();
 		interact.onPush = function(e) drag();
 		interact.onRelease = function(e) stopDrag();
 		interact.onRelease = function(e) stopDrag();
 	}
 	}
-	
+
 	public function drag() {
 	public function drag() {
 		interact.startDrag(function(e) {
 		interact.startDrag(function(e) {
 			if( e.kind == EMove ){
 			if( e.kind == EMove ){
@@ -137,39 +137,39 @@ private class Cursor extends h2d.Sprite {
 			}
 			}
 			gradient.dragTarget = this ;
 			gradient.dragTarget = this ;
 		});
 		});
-			
+
 		gradient.updateTarget = this;
 		gradient.updateTarget = this;
 		this.parent.addChild(this);
 		this.parent.addChild(this);
 	}
 	}
-	
+
 	public function stopDrag() {
 	public function stopDrag() {
 		interact.stopDrag();
 		interact.stopDrag();
 		if( !visible ) remove();
 		if( !visible ) remove();
 		gradient.dragTarget = null ;
 		gradient.dragTarget = null ;
 		gradient.dragOut = false;
 		gradient.dragOut = false;
 	}
 	}
-	
+
 	public function select() {
 	public function select() {
 		bgcolor = 0xFFFF00FF;
 		bgcolor = 0xFFFF00FF;
 		flag.remove();
 		flag.remove();
 		flag = new CFlag(cursor, 0, 0, ang, color, bgcolor);
 		flag = new CFlag(cursor, 0, 0, ang, color, bgcolor);
-		
+
 		if(gradient.colorPicker.visible)
 		if(gradient.colorPicker.visible)
 			gradient.colorPicker.color = color;
 			gradient.colorPicker.color = color;
 	}
 	}
-	
+
 	public function unselect() {
 	public function unselect() {
 		bgcolor = 0xFFAAAAAA;
 		bgcolor = 0xFFAAAAAA;
 		flag.remove();
 		flag.remove();
 		flag = new CFlag(cursor, 0, 0, ang, color, bgcolor);
 		flag = new CFlag(cursor, 0, 0, ang, color, bgcolor);
 	}
 	}
-	
+
 	public function setCursor(px:Float) {
 	public function setCursor(px:Float) {
 		x = Math.max(0, Math.min(gradient.boxWidth, px));
 		x = Math.max(0, Math.min(gradient.boxWidth, px));
 	}
 	}
 }
 }
 
 
-	
+
 private class AlphaSelector extends h2d.Sprite {
 private class AlphaSelector extends h2d.Sprite {
 	public var target(default, set):Cursor;
 	public var target(default, set):Cursor;
 	var gradient : GradientEditor;
 	var gradient : GradientEditor;
@@ -178,7 +178,7 @@ private class AlphaSelector extends h2d.Sprite {
 	var alphaInput:h2d.comp.Input;
 	var alphaInput:h2d.comp.Input;
 	var locLabel:h2d.comp.Label;
 	var locLabel:h2d.comp.Label;
 	var locInput:h2d.comp.Input;
 	var locInput:h2d.comp.Input;
-	
+
 	public function new (gradient,ix, iy, parent) {
 	public function new (gradient,ix, iy, parent) {
 		super(parent);
 		super(parent);
 		this.gradient = gradient;
 		this.gradient = gradient;
@@ -186,16 +186,16 @@ private class AlphaSelector extends h2d.Sprite {
 		y = iy;
 		y = iy;
 		init();
 		init();
 	}
 	}
-	
+
 	function init() {
 	function init() {
 		title = new h2d.comp.Label("Alpha", this);
 		title = new h2d.comp.Label("Alpha", this);
 		title.addStyle(Style.get(CLabel));
 		title.addStyle(Style.get(CLabel));
-		
+
 		slider = new h2d.comp.Slider(this);
 		slider = new h2d.comp.Slider(this);
 		slider.x = 55; slider.y = 4;
 		slider.x = 55; slider.y = 4;
 		slider.onChange = function(v) { updateSlider(v); };
 		slider.onChange = function(v) { updateSlider(v); };
 		slider.value = 1;
 		slider.value = 1;
-		
+
 		alphaInput = new h2d.comp.Input(this);
 		alphaInput = new h2d.comp.Input(this);
 		alphaInput.addStyle(Style.get(CInputSmall));
 		alphaInput.addStyle(Style.get(CInputSmall));
 		alphaInput.x = 170;
 		alphaInput.x = 170;
@@ -208,7 +208,7 @@ private class AlphaSelector extends h2d.Sprite {
 				slider.value = v;
 				slider.value = v;
 			}
 			}
 		};
 		};
-		
+
 		locLabel = new h2d.comp.Label("Location             %", this);
 		locLabel = new h2d.comp.Label("Location             %", this);
 		locLabel.setStyle(Style.get(CLabel));
 		locLabel.setStyle(Style.get(CLabel));
 		locLabel.x = 255;
 		locLabel.x = 255;
@@ -224,13 +224,13 @@ private class AlphaSelector extends h2d.Sprite {
 			}
 			}
 		};
 		};
 	}
 	}
-	
+
 	public function update() {
 	public function update() {
 		if(target == null)
 		if(target == null)
 			return;
 			return;
 		locInput.value = Std.string(Math.floor(target.coeff * 100 * 100) / 100);
 		locInput.value = Std.string(Math.floor(target.coeff * 100 * 100) / 100);
 	}
 	}
-	
+
 	function set_target(cursor:Cursor) {
 	function set_target(cursor:Cursor) {
 		target = cursor;
 		target = cursor;
 		var v = target.value / 255;
 		var v = target.value / 255;
@@ -239,7 +239,7 @@ private class AlphaSelector extends h2d.Sprite {
 		updateSlider(v);
 		updateSlider(v);
 		return target;
 		return target;
 	}
 	}
-	
+
 	function updateSlider(v:Float) {
 	function updateSlider(v:Float) {
 		var alpha = Math.round(255 * v);
 		var alpha = Math.round(255 * v);
 		alphaInput.value = Std.string(alpha);
 		alphaInput.value = Std.string(alpha);
@@ -259,7 +259,7 @@ private class ColorSelector extends h2d.Sprite {
 	var canvas:h2d.css.Fill;
 	var canvas:h2d.css.Fill;
 	var color:Int = 0xFFFFFFFF;
 	var color:Int = 0xFFFFFFFF;
 	var interact : h2d.Interactive;
 	var interact : h2d.Interactive;
-	
+
 	public function new(gradient,ix, iy, parent) {
 	public function new(gradient,ix, iy, parent) {
 		super(parent);
 		super(parent);
 		this.gradient = gradient;
 		this.gradient = gradient;
@@ -267,13 +267,13 @@ private class ColorSelector extends h2d.Sprite {
 		y = iy;
 		y = iy;
 		init();
 		init();
 	}
 	}
-	
+
 	public function update() {
 	public function update() {
 		if(target == null)
 		if(target == null)
 			return;
 			return;
 		locInput.value = Std.string(Math.floor(target.coeff * 100 * 100) / 100);
 		locInput.value = Std.string(Math.floor(target.coeff * 100 * 100) / 100);
 	}
 	}
-	
+
 	function set_target(cursor:Cursor) {
 	function set_target(cursor:Cursor) {
 		target = cursor;
 		target = cursor;
 		locInput.value = Std.string(Math.floor(target.coeff * 100 * 100) / 100);
 		locInput.value = Std.string(Math.floor(target.coeff * 100 * 100) / 100);
@@ -282,11 +282,11 @@ private class ColorSelector extends h2d.Sprite {
 		redraw();
 		redraw();
 		return target;
 		return target;
 	}
 	}
-	
+
 	function init() {
 	function init() {
 		title = new h2d.comp.Label("Color                         #", this);
 		title = new h2d.comp.Label("Color                         #", this);
 		title.setStyle(Style.get(CLabel));
 		title.setStyle(Style.get(CLabel));
-		
+
 		canvas = new Fill(this);
 		canvas = new Fill(this);
 		canvas.x = 45;
 		canvas.x = 45;
 		canvas.y = -8;
 		canvas.y = -8;
@@ -296,7 +296,7 @@ private class ColorSelector extends h2d.Sprite {
 		interact.onPush = function(e) {
 		interact.onPush = function(e) {
 			if(target == null)
 			if(target == null)
 				return;
 				return;
-			
+
 			if(!gradient.colorPicker.visible) {
 			if(!gradient.colorPicker.visible) {
 				gradient.colorPicker.visible = true;
 				gradient.colorPicker.visible = true;
 				gradient.colorPicker.color = color;
 				gradient.colorPicker.color = color;
@@ -311,7 +311,7 @@ private class ColorSelector extends h2d.Sprite {
 				gradient.colorPicker.visible = false;
 				gradient.colorPicker.visible = false;
 			}
 			}
 		};
 		};
-		
+
 		colorInput = new h2d.comp.Input(this);
 		colorInput = new h2d.comp.Input(this);
 		colorInput.setStyle(Style.get(CInput));
 		colorInput.setStyle(Style.get(CInput));
 		colorInput.x = 175;
 		colorInput.x = 175;
@@ -328,11 +328,11 @@ private class ColorSelector extends h2d.Sprite {
 				redraw();
 				redraw();
 			}
 			}
 		};
 		};
-		
+
 		locLabel = new h2d.comp.Label("Location             %", this);
 		locLabel = new h2d.comp.Label("Location             %", this);
 		locLabel.setStyle(Style.get(CLabel));
 		locLabel.setStyle(Style.get(CLabel));
 		locLabel.x = 265;
 		locLabel.x = 265;
-		
+
 		locInput = new h2d.comp.Input(this);
 		locInput = new h2d.comp.Input(this);
 		locInput.setStyle(Style.get(CInput));
 		locInput.setStyle(Style.get(CInput));
 		locInput.x = 330;
 		locInput.x = 330;
@@ -345,57 +345,57 @@ private class ColorSelector extends h2d.Sprite {
 				target.setCursor( v * gradient.boxWidth / 100 );
 				target.setCursor( v * gradient.boxWidth / 100 );
 			}
 			}
 		};
 		};
-		
+
 		redraw();
 		redraw();
 	}
 	}
-	
+
 	function redraw() {
 	function redraw() {
 		canvas.reset();
 		canvas.reset();
 		canvas.fillRectColor(0, 0, 110, 25, color);
 		canvas.fillRectColor(0, 0, 110, 25, color);
 		canvas.lineRect(FillStyle.Color(gradient.borderColor), 0, 0, 110, 25, 1);
 		canvas.lineRect(FillStyle.Color(gradient.borderColor), 0, 0, 110, 25, 1);
 	}
 	}
 }
 }
-		
-		
+
+
 //////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////
 
 
 class GradientEditor extends h2d.comp.Component {
 class GradientEditor extends h2d.comp.Component {
-	
+
 	public var borderColor = 0xFF888888;
 	public var borderColor = 0xFF888888;
 	public var dragTarget:Cursor;
 	public var dragTarget:Cursor;
 	public var dragOut:Bool;
 	public var dragOut:Bool;
 	public var updateTarget:Cursor;
 	public var updateTarget:Cursor;
 	public var boxWidth = 430;
 	public var boxWidth = 430;
 	var boxHeight = 100;
 	var boxHeight = 100;
-	
+
 	var keys:Array<Key>;
 	var keys:Array<Key>;
 	var colorsKeys:Array<Cursor>;
 	var colorsKeys:Array<Cursor>;
 	var alphaKeys:Array<Cursor>;
 	var alphaKeys:Array<Cursor>;
-	
+
 	var box:h2d.Sprite;
 	var box:h2d.Sprite;
 	var gradient:Fill;
 	var gradient:Fill;
 	var hudAlpha: AlphaSelector;
 	var hudAlpha: AlphaSelector;
 	var hudColor: ColorSelector;
 	var hudColor: ColorSelector;
-	
+
 	public var colorPicker:ColorPicker;
 	public var colorPicker:ColorPicker;
-	
+
 	var interactUp:h2d.Interactive;
 	var interactUp:h2d.Interactive;
 	var interactDown:h2d.Interactive;
 	var interactDown:h2d.Interactive;
-		
+
 
 
 	var withAlpha : Bool;
 	var withAlpha : Bool;
 	var holdCursor:Cursor;
 	var holdCursor:Cursor;
-	
+
 	public function new(?withAlpha = true, ?parent) {
 	public function new(?withAlpha = true, ?parent) {
 		super("gradienteditor", parent);
 		super("gradienteditor", parent);
 		this.withAlpha = withAlpha;
 		this.withAlpha = withAlpha;
 		init();
 		init();
 	}
 	}
-	
+
 	function init() {
 	function init() {
 		colorsKeys = [];
 		colorsKeys = [];
 		alphaKeys = [];
 		alphaKeys = [];
-		
+
 		interactUp = new h2d.Interactive(boxWidth, 16, this);
 		interactUp = new h2d.Interactive(boxWidth, 16, this);
 		interactUp.x = 10;
 		interactUp.x = 10;
 		interactUp.y = 30 - 16;
 		interactUp.y = 30 - 16;
@@ -404,28 +404,28 @@ class GradientEditor extends h2d.comp.Component {
 		interactDown.x = 10;
 		interactDown.x = 10;
 		interactDown.y = 30 + boxHeight;
 		interactDown.y = 30 + boxHeight;
 		interactDown.onPush =  function(e) createColorKey(e.relX, boxHeight);
 		interactDown.onPush =  function(e) createColorKey(e.relX, boxHeight);
-		
+
 		box = new h2d.Sprite(this);
 		box = new h2d.Sprite(this);
 		box.x = 10;
 		box.x = 10;
 		box.y = 30;
 		box.y = 30;
 		drawChecker();
 		drawChecker();
-		
+
 		hudColor = new ColorSelector(this, 20, box.y + boxHeight + 30, this);
 		hudColor = new ColorSelector(this, 20, box.y + boxHeight + 30, this);
 		hudAlpha = new AlphaSelector(this, 20, box.y + boxHeight + 30, this);
 		hudAlpha = new AlphaSelector(this, 20, box.y + boxHeight + 30, this);
 		hudAlpha.visible = false;
 		hudAlpha.visible = false;
 		hudAlpha.y = 0;
 		hudAlpha.y = 0;
-		
+
 		colorPicker = new ColorPicker(this);
 		colorPicker = new ColorPicker(this);
 		colorPicker.y = 220;
 		colorPicker.y = 220;
 		colorPicker.visible = false;
 		colorPicker.visible = false;
 		colorPicker.onClose = function() colorPicker.visible = false;
 		colorPicker.onClose = function() colorPicker.visible = false;
-		
+
 		setKeys([ { x : 0, value:0xFFFFFFFF }, { x: 1, value:0xFFFFFFFF } ],null);
 		setKeys([ { x : 0, value:0xFFFFFFFF }, { x: 1, value:0xFFFFFFFF } ],null);
 	}
 	}
-	
+
 	public dynamic function onChange( keys : Array<Key> ) {
 	public dynamic function onChange( keys : Array<Key> ) {
 	}
 	}
-	
+
 	public function setKeys(keys:Array<Key>,?kalpha:Array<Key>) {
 	public function setKeys(keys:Array<Key>,?kalpha:Array<Key>) {
 		while( colorsKeys.length > 0 )
 		while( colorsKeys.length > 0 )
 			colorsKeys.shift().remove();
 			colorsKeys.shift().remove();
@@ -444,7 +444,7 @@ class GradientEditor extends h2d.comp.Component {
 		updateKeys();
 		updateKeys();
 		updateTarget = colorsKeys[0];
 		updateTarget = colorsKeys[0];
 	}
 	}
-	
+
 	override function sync(ctx) {
 	override function sync(ctx) {
 		if(dragTarget != null) {
 		if(dragTarget != null) {
 			if(dragOut) {
 			if(dragOut) {
@@ -469,23 +469,23 @@ class GradientEditor extends h2d.comp.Component {
 					case KAlpha: alphaKeys.push(dragTarget);
 					case KAlpha: alphaKeys.push(dragTarget);
 				}
 				}
 			}
 			}
-			
+
 			hudAlpha.update();
 			hudAlpha.update();
 			hudColor.update();
 			hudColor.update();
 		}
 		}
 		else holdCursor = null;
 		else holdCursor = null;
-		
+
 		if(updateTarget != null) {
 		if(updateTarget != null) {
 			changeHud(updateTarget);
 			changeHud(updateTarget);
 			updateFlags(updateTarget);
 			updateFlags(updateTarget);
 			updateTarget = null;
 			updateTarget = null;
 		}
 		}
-		
+
 		updateKeys();
 		updateKeys();
-		
+
 		super.sync(ctx);
 		super.sync(ctx);
 	}
 	}
-	
+
 	function createAlphaKey(px:Float, py:Float) {
 	function createAlphaKey(px:Float, py:Float) {
 		if( !withAlpha )
 		if( !withAlpha )
 			return;
 			return;
@@ -494,14 +494,14 @@ class GradientEditor extends h2d.comp.Component {
 		updateTarget = cursor;
 		updateTarget = cursor;
 		cursor.drag();
 		cursor.drag();
 	}
 	}
-	
+
 	function createColorKey(px:Float, py:Float) {
 	function createColorKey(px:Float, py:Float) {
 		var cursor = new Cursor(this, px, py, KColor, getColorAt(px / boxWidth), Math.PI, box);
 		var cursor = new Cursor(this, px, py, KColor, getColorAt(px / boxWidth), Math.PI, box);
 		colorsKeys.push(cursor);
 		colorsKeys.push(cursor);
 		updateTarget = cursor;
 		updateTarget = cursor;
 		cursor.drag();
 		cursor.drag();
 	}
 	}
-	
+
 	function updateKeys() {
 	function updateKeys() {
 		var keys = [];
 		var keys = [];
 		for (i in 0...colorsKeys.length) {
 		for (i in 0...colorsKeys.length) {
@@ -510,14 +510,14 @@ class GradientEditor extends h2d.comp.Component {
 			var rgb = INTtoRGB(k.value);
 			var rgb = INTtoRGB(k.value);
 			keys.push( { x:k.coeff, value:RGBtoINT(rgb[0], rgb[1], rgb[2], alpha) } );
 			keys.push( { x:k.coeff, value:RGBtoINT(rgb[0], rgb[1], rgb[2], alpha) } );
 		}
 		}
-		
+
 		for (i in 0...alphaKeys.length) {
 		for (i in 0...alphaKeys.length) {
 			var k = alphaKeys[i];
 			var k = alphaKeys[i];
 			var alpha = k.value;
 			var alpha = k.value;
 			var rgb = INTtoRGB(getColorAt(k.coeff));
 			var rgb = INTtoRGB(getColorAt(k.coeff));
 			keys.push( { x:k.coeff, value:RGBtoINT(rgb[0], rgb[1], rgb[2], alpha) } );
 			keys.push( { x:k.coeff, value:RGBtoINT(rgb[0], rgb[1], rgb[2], alpha) } );
 		}
 		}
-		
+
 		keys.sort(function(a, b) return Reflect.compare(a.x, b.x) );
 		keys.sort(function(a, b) return Reflect.compare(a.x, b.x) );
 		if(keys[0].x != 0)
 		if(keys[0].x != 0)
 			keys.insert(0, { x:0, value:keys[0].value } );
 			keys.insert(0, { x:0, value:keys[0].value } );
@@ -529,13 +529,13 @@ class GradientEditor extends h2d.comp.Component {
 			onChange(keys);
 			onChange(keys);
 		}
 		}
 	}
 	}
-	
+
 	function getARGBAt(x:Float) {
 	function getARGBAt(x:Float) {
 		var alpha = getAlphaAt(x);
 		var alpha = getAlphaAt(x);
 		var rgb = INTtoRGB(getColorAt(x));
 		var rgb = INTtoRGB(getColorAt(x));
 		return RGBtoINT(rgb[0], rgb[1], rgb[2], alpha);
 		return RGBtoINT(rgb[0], rgb[1], rgb[2], alpha);
 	}
 	}
-	
+
 	function getAlphaAt(x:Float) {
 	function getAlphaAt(x:Float) {
 		if( !withAlpha )
 		if( !withAlpha )
 			return 255;
 			return 255;
@@ -560,7 +560,7 @@ class GradientEditor extends h2d.comp.Component {
 		var d = (x - prev.coeff) / (next.coeff - prev.coeff);
 		var d = (x - prev.coeff) / (next.coeff - prev.coeff);
 		return Math.round(prev.value + (next.value - prev.value) * d);
 		return Math.round(prev.value + (next.value - prev.value) * d);
 	}
 	}
-	
+
 	function getColorAt(x:Float) {
 	function getColorAt(x:Float) {
 		colorsKeys.sort(function(a, b) return Reflect.compare(a.coeff, b.coeff) );
 		colorsKeys.sort(function(a, b) return Reflect.compare(a.coeff, b.coeff) );
 		var prev = null;
 		var prev = null;
@@ -580,7 +580,7 @@ class GradientEditor extends h2d.comp.Component {
 		}
 		}
 		if(next == null)
 		if(next == null)
 			return prev.value;
 			return prev.value;
-			
+
 		var d = (x - prev.coeff) / (next.coeff - prev.coeff);
 		var d = (x - prev.coeff) / (next.coeff - prev.coeff);
 		var pRGB = INTtoRGB(prev.value);
 		var pRGB = INTtoRGB(prev.value);
 		var nRGB = INTtoRGB(next.value);
 		var nRGB = INTtoRGB(next.value);
@@ -589,7 +589,7 @@ class GradientEditor extends h2d.comp.Component {
 			rgb.push(Math.round(pRGB[i] + (nRGB[i] - pRGB[i]) * d));
 			rgb.push(Math.round(pRGB[i] + (nRGB[i] - pRGB[i]) * d));
 		return RGBtoINT(rgb[0], rgb[1], rgb[2]);
 		return RGBtoINT(rgb[0], rgb[1], rgb[2]);
 	}
 	}
-	
+
 	function drawGradient() {
 	function drawGradient() {
 		box.removeChild(gradient);
 		box.removeChild(gradient);
 		gradient = new Fill(box);
 		gradient = new Fill(box);
@@ -600,7 +600,7 @@ class GradientEditor extends h2d.comp.Component {
 		}
 		}
 		gradient.lineRect(FillStyle.Color(borderColor), 0, 0, boxWidth, boxHeight, 2);
 		gradient.lineRect(FillStyle.Color(borderColor), 0, 0, boxWidth, boxHeight, 2);
 	}
 	}
-	
+
 	function drawChecker() {
 	function drawChecker() {
 		var checker = new Fill(box);
 		var checker = new Fill(box);
 		var nb = 90;
 		var nb = 90;
@@ -614,7 +614,7 @@ class GradientEditor extends h2d.comp.Component {
 			}
 			}
 		}
 		}
 	}
 	}
-	
+
 	function changeHud(cursor:Cursor) {
 	function changeHud(cursor:Cursor) {
 		switch(cursor.kind) {
 		switch(cursor.kind) {
 			case KAlpha: 	hudAlpha.target = cursor;
 			case KAlpha: 	hudAlpha.target = cursor;
@@ -627,7 +627,7 @@ class GradientEditor extends h2d.comp.Component {
 							hudAlpha.y =  0;
 							hudAlpha.y =  0;
 		}
 		}
 	}
 	}
-	
+
 	function updateFlags(cursor:Cursor) {
 	function updateFlags(cursor:Cursor) {
 		for (c in alphaKeys) {
 		for (c in alphaKeys) {
 			if (c == cursor)
 			if (c == cursor)
@@ -640,12 +640,12 @@ class GradientEditor extends h2d.comp.Component {
 			else c.unselect();
 			else c.unselect();
 		}
 		}
 	}
 	}
-	
-	
+
+
 	inline public static function INTtoRGB(color:Int) {
 	inline public static function INTtoRGB(color:Int) {
 		return [(color >> 16) & 0xFF, (color >> 8) & 0xFF,  color & 0xFF, color >>> 24];
 		return [(color >> 16) & 0xFF, (color >> 8) & 0xFF,  color & 0xFF, color >>> 24];
 	}
 	}
-	
+
 	inline public static function RGBtoINT(r:Int, g:Int, b:Int, a:Int = 255) {
 	inline public static function RGBtoINT(r:Int, g:Int, b:Int, a:Int = 255) {
 		return (a << 24) | (r << 16) | (g << 8) | b;
 		return (a << 24) | (r << 16) | (g << 8) | b;
 	}
 	}

+ 9 - 9
h2d/comp/Input.hx

@@ -3,13 +3,13 @@ import hxd.Key;
 
 
 @:access(h2d.comp.Input.scene)
 @:access(h2d.comp.Input.scene)
 class Input extends Interactive {
 class Input extends Interactive {
-	
+
 	var tf : h2d.Text;
 	var tf : h2d.Text;
 	var cursor : h2d.Bitmap;
 	var cursor : h2d.Bitmap;
 	var cursorPos(default,set) : Int;
 	var cursorPos(default,set) : Int;
-	
+
 	public var value(default, set) : String;
 	public var value(default, set) : String;
-	
+
 	public function new(?parent) {
 	public function new(?parent) {
 		super("input",parent);
 		super("input",parent);
 		tf = new h2d.Text(null, this);
 		tf = new h2d.Text(null, this);
@@ -64,7 +64,7 @@ class Input extends Interactive {
 		};
 		};
 		this.value = "";
 		this.value = "";
 	}
 	}
-	
+
 	function set_cursorPos(v:Int) {
 	function set_cursorPos(v:Int) {
 		textAlign(tf);
 		textAlign(tf);
 		cursor.x = tf.x + tf.calcTextWidth(value.substr(0, v)) + extLeft();
 		cursor.x = tf.x + tf.calcTextWidth(value.substr(0, v)) + extLeft();
@@ -80,16 +80,16 @@ class Input extends Interactive {
 		input.focus();
 		input.focus();
 		cursorPos = value.length;
 		cursorPos = value.length;
 	}
 	}
-	
+
 	function get_value() {
 	function get_value() {
 		return tf.text;
 		return tf.text;
 	}
 	}
-	
+
 	function set_value(t) {
 	function set_value(t) {
 		needRebuild = true;
 		needRebuild = true;
 		return value = t;
 		return value = t;
 	}
 	}
-	
+
 	override function resize( ctx : Context ) {
 	override function resize( ctx : Context ) {
 		if( ctx.measure ) {
 		if( ctx.measure ) {
 			tf.font = getFont();
 			tf.font = getFont();
@@ -119,8 +119,8 @@ class Input extends Interactive {
 
 
 	public dynamic function onFocus() {
 	public dynamic function onFocus() {
 	}
 	}
-	
+
 	public dynamic function onBlur() {
 	public dynamic function onBlur() {
 	}
 	}
-	
+
 }
 }

+ 8 - 8
h2d/comp/Interactive.hx

@@ -1,11 +1,11 @@
 package h2d.comp;
 package h2d.comp;
 
 
 class Interactive extends Component {
 class Interactive extends Component {
-	
+
 	var input : h2d.Interactive;
 	var input : h2d.Interactive;
 	var active : Bool;
 	var active : Bool;
 	var activeRight : Bool;
 	var activeRight : Bool;
-	
+
 	function new(kind,?parent) {
 	function new(kind,?parent) {
 		super(kind,parent);
 		super(kind,parent);
 		input = new h2d.Interactive(0, 0, bg);
 		input = new h2d.Interactive(0, 0, bg);
@@ -47,7 +47,7 @@ class Interactive extends Component {
 			}
 			}
 		};
 		};
 	}
 	}
-	
+
 	override function resize( ctx : Context ) {
 	override function resize( ctx : Context ) {
 		super.resize(ctx);
 		super.resize(ctx);
 		if( !ctx.measure ) {
 		if( !ctx.measure ) {
@@ -56,23 +56,23 @@ class Interactive extends Component {
 			input.visible = !hasClass(":disabled");
 			input.visible = !hasClass(":disabled");
 		}
 		}
 	}
 	}
-	
+
 	public dynamic function onMouseOver() {
 	public dynamic function onMouseOver() {
 	}
 	}
 
 
 	public dynamic function onMouseOut() {
 	public dynamic function onMouseOut() {
 	}
 	}
-	
+
 	public dynamic function onMouseDown() {
 	public dynamic function onMouseDown() {
 	}
 	}
 
 
 	public dynamic function onMouseUp() {
 	public dynamic function onMouseUp() {
 	}
 	}
-	
+
 	public dynamic function onClick() {
 	public dynamic function onClick() {
 	}
 	}
-	
+
 	public dynamic function onRightClick() {
 	public dynamic function onRightClick() {
 	}
 	}
-	
+
 }
 }

+ 7 - 7
h2d/comp/ItemList.hx

@@ -1,28 +1,28 @@
 package h2d.comp;
 package h2d.comp;
 
 
 class ItemList extends Box {
 class ItemList extends Box {
-	
+
 	public var selected(default,set) = -1;
 	public var selected(default,set) = -1;
 	var inputs : Array<h2d.Interactive>;
 	var inputs : Array<h2d.Interactive>;
-	
+
 	public function new(?parent) {
 	public function new(?parent) {
 		super(Vertical, parent);
 		super(Vertical, parent);
 		this.name = "itemlist";
 		this.name = "itemlist";
 		inputs = [];
 		inputs = [];
 	}
 	}
-	
+
 	function set_selected(v:Int) {
 	function set_selected(v:Int) {
 		needRebuild = true;
 		needRebuild = true;
 		return selected = v;
 		return selected = v;
 	}
 	}
-	
+
 	function onWheel( e : hxd.Event ) {
 	function onWheel( e : hxd.Event ) {
 		scrollY -= e.wheelDelta * (components.length == 0 ? 0 : (components[0].height + style.verticalSpacing));
 		scrollY -= e.wheelDelta * (components.length == 0 ? 0 : (components[0].height + style.verticalSpacing));
 		if( scrollY > 0 ) scrollY = 0;
 		if( scrollY > 0 ) scrollY = 0;
 		e.propagate = false;
 		e.propagate = false;
 		needRebuild = true;
 		needRebuild = true;
 	}
 	}
-	
+
 	override function resizeRec( ctx : Context ) {
 	override function resizeRec( ctx : Context ) {
 		super.resizeRec(ctx);
 		super.resizeRec(ctx);
 		if( !ctx.measure ) {
 		if( !ctx.measure ) {
@@ -85,8 +85,8 @@ class ItemList extends Box {
 
 
 	public dynamic function onItemOver( current : Int ) {
 	public dynamic function onItemOver( current : Int ) {
 	}
 	}
-	
+
 	public dynamic function onChange( selected : Int ) {
 	public dynamic function onChange( selected : Int ) {
 	}
 	}
-	
+
 }
 }

+ 18 - 18
h2d/comp/JQuery.hx

@@ -6,26 +6,26 @@ private typedef Query = Array<CssClass>;
 @:access(h2d.comp.Component)
 @:access(h2d.comp.Component)
 @:keep
 @:keep
 class JQuery {
 class JQuery {
-	
+
 	var root : Component;
 	var root : Component;
 	var select : Array<Component>;
 	var select : Array<Component>;
-	
+
 	public function new( root : Component, query : Dynamic ) {
 	public function new( root : Component, query : Dynamic ) {
 		while( root.parentComponent != null )
 		while( root.parentComponent != null )
 			root = root.parentComponent;
 			root = root.parentComponent;
 		this.root = root;
 		this.root = root;
 		select = getSet(query);
 		select = getSet(query);
 	}
 	}
-	
+
 	public function getComponents() {
 	public function getComponents() {
 		return select;
 		return select;
 	}
 	}
-	
+
 	public function toggleClass( cl : String, ?flag : Bool ) {
 	public function toggleClass( cl : String, ?flag : Bool ) {
 		for( s in select ) s.toggleClass(cl,flag);
 		for( s in select ) s.toggleClass(cl,flag);
 		return this;
 		return this;
 	}
 	}
-	
+
 	public function find( q : Dynamic ) {
 	public function find( q : Dynamic ) {
 		if( Std.is(q, Component) )
 		if( Std.is(q, Component) )
 			return new JQuery(root, Lambda.has(select, q) ? null : q);
 			return new JQuery(root, Lambda.has(select, q) ? null : q);
@@ -39,7 +39,7 @@ class JQuery {
 		throw "Invalid JQuery " + q;
 		throw "Invalid JQuery " + q;
 		return null;
 		return null;
 	}
 	}
-	
+
 	public function filter( q : Dynamic ) {
 	public function filter( q : Dynamic ) {
 		if( Std.is(q, Component) )
 		if( Std.is(q, Component) )
 			return new JQuery(root, Lambda.has(select, q) ? null : q);
 			return new JQuery(root, Lambda.has(select, q) ? null : q);
@@ -69,7 +69,7 @@ class JQuery {
 		throw "Invalid JQuery " + q;
 		throw "Invalid JQuery " + q;
 		return null;
 		return null;
 	}
 	}
-	
+
 	public function click( f : JQuery -> Void ) {
 	public function click( f : JQuery -> Void ) {
 		for( c in select ) {
 		for( c in select ) {
 			var int = Std.instance(c, Interactive);
 			var int = Std.instance(c, Interactive);
@@ -78,7 +78,7 @@ class JQuery {
 		}
 		}
 		return this;
 		return this;
 	}
 	}
-	
+
 	public function show() {
 	public function show() {
 		for( s in select )
 		for( s in select )
 			s.getStyle(true).display = true;
 			s.getStyle(true).display = true;
@@ -90,7 +90,7 @@ class JQuery {
 			s.getStyle(true).display = false;
 			s.getStyle(true).display = false;
 		return this;
 		return this;
 	}
 	}
-	
+
 	public function toggle() {
 	public function toggle() {
 		for( s in select ) {
 		for( s in select ) {
 			var s = s.getStyle(true);
 			var s = s.getStyle(true);
@@ -98,7 +98,7 @@ class JQuery {
 		}
 		}
 		return this;
 		return this;
 	}
 	}
-	
+
 	public function iterator() {
 	public function iterator() {
 		var it = select.iterator();
 		var it = select.iterator();
 		return {
 		return {
@@ -161,7 +161,7 @@ class JQuery {
 			"";
 			"";
 		}
 		}
 	}
 	}
-	
+
 	function _set_text(v:String) {
 	function _set_text(v:String) {
 		for( c in select )
 		for( c in select )
 			switch( c.name ) {
 			switch( c.name ) {
@@ -173,7 +173,7 @@ class JQuery {
 			}
 			}
 		return this;
 		return this;
 	}
 	}
-	
+
 	function _set_style(v:String) {
 	function _set_style(v:String) {
 		var s = new h2d.css.Style();
 		var s = new h2d.css.Style();
 		new h2d.css.Parser().parse(v, s);
 		new h2d.css.Parser().parse(v, s);
@@ -181,7 +181,7 @@ class JQuery {
 			c.addStyle(s);
 			c.addStyle(s);
 		return this;
 		return this;
 	}
 	}
-	
+
 	function getSet( query : Dynamic ) {
 	function getSet( query : Dynamic ) {
 		var set;
 		var set;
 		if( query == null )
 		if( query == null )
@@ -198,29 +198,29 @@ class JQuery {
 			throw "Invalid JQuery " + query;
 			throw "Invalid JQuery " + query;
 		return set;
 		return set;
 	}
 	}
-	
+
 	function lookup( root : Component, query : String ) {
 	function lookup( root : Component, query : String ) {
 		var set = [];
 		var set = [];
 		lookupRec(root, parseQuery(query), set);
 		lookupRec(root, parseQuery(query), set);
 		return set;
 		return set;
 	}
 	}
-	
+
 	function parseQuery(q) : Query {
 	function parseQuery(q) : Query {
 		return new h2d.css.Parser().parseClasses(q);
 		return new h2d.css.Parser().parseClasses(q);
 	}
 	}
-	
+
 	function matchQuery(q:Query, comp:Component) {
 	function matchQuery(q:Query, comp:Component) {
 		for( r in q )
 		for( r in q )
 			if( h2d.css.Engine.ruleMatch(r, comp) )
 			if( h2d.css.Engine.ruleMatch(r, comp) )
 				return true;
 				return true;
 		return false;
 		return false;
 	}
 	}
-	
+
 	function lookupRec(comp:Component, q, set : Array<Component> ) {
 	function lookupRec(comp:Component, q, set : Array<Component> ) {
 		if( matchQuery(q, comp) )
 		if( matchQuery(q, comp) )
 			set.push(comp);
 			set.push(comp);
 		for( s in comp.components )
 		for( s in comp.components )
 			lookupRec(s, q, set);
 			lookupRec(s, q, set);
 	}
 	}
-	
+
 }
 }

+ 6 - 6
h2d/comp/Label.hx

@@ -1,11 +1,11 @@
 package h2d.comp;
 package h2d.comp;
 
 
 class Label extends Component {
 class Label extends Component {
-	
+
 	var tf : h2d.Text;
 	var tf : h2d.Text;
-	
+
 	public var text(default, set) : String;
 	public var text(default, set) : String;
-	
+
 	public function new(text, ?parent) {
 	public function new(text, ?parent) {
 		super("label",parent);
 		super("label",parent);
 		tf = new h2d.Text(null, this);
 		tf = new h2d.Text(null, this);
@@ -15,12 +15,12 @@ class Label extends Component {
 	function get_text() {
 	function get_text() {
 		return tf.text;
 		return tf.text;
 	}
 	}
-	
+
 	function set_text(t) {
 	function set_text(t) {
 		needRebuild = true;
 		needRebuild = true;
 		return text = t;
 		return text = t;
 	}
 	}
-	
+
 	override function resize( ctx : Context ) {
 	override function resize( ctx : Context ) {
 		if( ctx.measure ) {
 		if( ctx.measure ) {
 			tf.font = getFont();
 			tf.font = getFont();
@@ -34,5 +34,5 @@ class Label extends Component {
 		if( !ctx.measure )
 		if( !ctx.measure )
 			textAlign(tf);
 			textAlign(tf);
 	}
 	}
-	
+
 }
 }

+ 7 - 7
h2d/comp/Parser.hx

@@ -16,13 +16,13 @@ private class CustomInterp extends hscript.Interp {
 #end
 #end
 
 
 class Parser {
 class Parser {
-	
+
 	var comps : Map < String, haxe.xml.Fast -> Component -> Component > ;
 	var comps : Map < String, haxe.xml.Fast -> Component -> Component > ;
 	#if hscript
 	#if hscript
 	var interp : hscript.Interp;
 	var interp : hscript.Interp;
 	#end
 	#end
 	var root : Component;
 	var root : Component;
-	
+
 	public function new(?api:{}) {
 	public function new(?api:{}) {
 		comps = new Map();
 		comps = new Map();
 		#if hscript
 		#if hscript
@@ -34,7 +34,7 @@ class Parser {
 				interp.variables.set(f, Reflect.field(api, f));
 				interp.variables.set(f, Reflect.field(api, f));
 		#end
 		#end
 	}
 	}
-	
+
 	public function build( x : haxe.xml.Fast, ?parent : Component ) {
 	public function build( x : haxe.xml.Fast, ?parent : Component ) {
 		var c : Component;
 		var c : Component;
 		switch( x.name.toLowerCase() ) {
 		switch( x.name.toLowerCase() ) {
@@ -246,11 +246,11 @@ class Parser {
 			build(e, c);
 			build(e, c);
 		return c;
 		return c;
 	}
 	}
-	
+
 	public function register(name, make) {
 	public function register(name, make) {
 		this.comps.set(name, make);
 		this.comps.set(name, make);
 	}
 	}
-	
+
 	function makeScript( c : Component, script : String ) {
 	function makeScript( c : Component, script : String ) {
 		#if hscript
 		#if hscript
 		var p = new hscript.Parser();
 		var p = new hscript.Parser();
@@ -269,7 +269,7 @@ class Parser {
 		return function() throw "Please compile with -lib hscript to get script access";
 		return function() throw "Please compile with -lib hscript to get script access";
 		#end
 		#end
 	}
 	}
-	
+
 	public static function fromHtml( html : String, ?api ) : Component {
 	public static function fromHtml( html : String, ?api ) : Component {
 		function lookupBody(x:Xml) {
 		function lookupBody(x:Xml) {
 			if( x.nodeType == Xml.Element && x.nodeName.toLowerCase() == "body" )
 			if( x.nodeType == Xml.Element && x.nodeName.toLowerCase() == "body" )
@@ -291,5 +291,5 @@ class Parser {
 		}
 		}
 		return new Parser(api).build(new haxe.xml.Fast(body),null);
 		return new Parser(api).build(new haxe.xml.Fast(body),null);
 	}
 	}
-	
+
 }
 }

+ 12 - 12
h2d/comp/Select.hx

@@ -7,7 +7,7 @@ class Select extends Interactive {
 	var list : ItemList;
 	var list : ItemList;
 	public var value(default, null) : String;
 	public var value(default, null) : String;
 	public var selectedIndex(default,set) : Int;
 	public var selectedIndex(default,set) : Int;
-	
+
 	public function new(?parent) {
 	public function new(?parent) {
 		super("select", parent);
 		super("select", parent);
 		tf = new h2d.Text(null, this);
 		tf = new h2d.Text(null, this);
@@ -18,11 +18,11 @@ class Select extends Interactive {
 	override function onClick() {
 	override function onClick() {
 		popup();
 		popup();
 	}
 	}
-	
+
 	public function getOptions() {
 	public function getOptions() {
 		return options.copy();
 		return options.copy();
 	}
 	}
-	
+
 	public function popup() {
 	public function popup() {
 		if( list != null || options.length == 0 )
 		if( list != null || options.length == 0 )
 			return;
 			return;
@@ -52,13 +52,13 @@ class Select extends Interactive {
 			}
 			}
 		},close);
 		},close);
 	}
 	}
-	
+
 	public function close() {
 	public function close() {
 		list.remove();
 		list.remove();
 		list = null;
 		list = null;
 		getScene().stopDrag();
 		getScene().stopDrag();
 	}
 	}
-	
+
 	public dynamic function onChange( value : String ) {
 	public dynamic function onChange( value : String ) {
 	}
 	}
 
 
@@ -68,7 +68,7 @@ class Select extends Interactive {
 		if( i != selectedIndex ) needRebuild = true;
 		if( i != selectedIndex ) needRebuild = true;
 		return selectedIndex = i;
 		return selectedIndex = i;
 	}
 	}
-	
+
 	public function setValue(v) {
 	public function setValue(v) {
 		var k = -1;
 		var k = -1;
 		for( i in 0...options.length )
 		for( i in 0...options.length )
@@ -86,8 +86,8 @@ class Select extends Interactive {
 		selectedIndex = k;
 		selectedIndex = k;
 		return value;
 		return value;
 	}
 	}
-	
-	
+
+
 	function updateListPos() {
 	function updateListPos() {
 		var scene = getScene();
 		var scene = getScene();
 		var s = new h2d.css.Style();
 		var s = new h2d.css.Style();
@@ -110,20 +110,20 @@ class Select extends Interactive {
 		if( list.customStyle == null || s.offsetX != list.customStyle.offsetX || s.offsetY != list.customStyle.offsetY || s.width != list.customStyle.width )
 		if( list.customStyle == null || s.offsetX != list.customStyle.offsetX || s.offsetY != list.customStyle.offsetY || s.width != list.customStyle.width )
 			list.setStyle(s);
 			list.setStyle(s);
 	}
 	}
-	
+
 	public function clear() {
 	public function clear() {
 		options = [];
 		options = [];
 		needRebuild = true;
 		needRebuild = true;
 		selectedIndex = 0;
 		selectedIndex = 0;
 	}
 	}
-	
+
 	public function addOption(label, ?value) {
 	public function addOption(label, ?value) {
 		options.push( { label : label, value : value } );
 		options.push( { label : label, value : value } );
 		needRebuild = true;
 		needRebuild = true;
 		if( selectedIndex == options.length - 1 )
 		if( selectedIndex == options.length - 1 )
 			selectedIndex = selectedIndex; // update value
 			selectedIndex = selectedIndex; // update value
 	}
 	}
-	
+
 	public dynamic function onItemOver( value : String ) {
 	public dynamic function onItemOver( value : String ) {
 	}
 	}
 
 
@@ -140,5 +140,5 @@ class Select extends Interactive {
 		if( !ctx.measure && list != null )
 		if( !ctx.measure && list != null )
 			updateListPos();
 			updateListPos();
 	}
 	}
-	
+
 }
 }

+ 6 - 6
h2d/comp/Slider.hx

@@ -1,20 +1,20 @@
 package h2d.comp;
 package h2d.comp;
 
 
 class Slider extends Component {
 class Slider extends Component {
-	
+
 	var cursor : Button;
 	var cursor : Button;
 	var input : h2d.Interactive;
 	var input : h2d.Interactive;
 	public var minValue : Float = 0.;
 	public var minValue : Float = 0.;
 	public var maxValue : Float = 1.;
 	public var maxValue : Float = 1.;
 	public var value(default, set) : Float;
 	public var value(default, set) : Float;
-	
+
 	@:access(h2d.comp.Button)
 	@:access(h2d.comp.Button)
 	public function new(?parent) {
 	public function new(?parent) {
 		super("slider", parent);
 		super("slider", parent);
 		cursor = new Button("", this);
 		cursor = new Button("", this);
 		cursor.input.cancelEvents = true;
 		cursor.input.cancelEvents = true;
 		cursor.onMouseDown = function() {
 		cursor.onMouseDown = function() {
-			
+
 		};
 		};
 		input = new h2d.Interactive(0, 0, this);
 		input = new h2d.Interactive(0, 0, this);
 		input.onPush = function(e) {
 		input.onPush = function(e) {
@@ -29,11 +29,11 @@ class Slider extends Component {
 		}
 		}
 		value = 0.;
 		value = 0.;
 	}
 	}
-	
+
 	function pixelToVal( e : hxd.Event ) {
 	function pixelToVal( e : hxd.Event ) {
 		return (Std.int(e.relX - (style.borderSize + cursor.width * 0.5) ) / (input.width - (style.borderSize * 2 + cursor.width))) * (maxValue - minValue) + minValue;
 		return (Std.int(e.relX - (style.borderSize + cursor.width * 0.5) ) / (input.width - (style.borderSize * 2 + cursor.width))) * (maxValue - minValue) + minValue;
 	}
 	}
-	
+
 	function gotoValue( v : Float ) {
 	function gotoValue( v : Float ) {
 		if( v < minValue ) v = minValue;
 		if( v < minValue ) v = minValue;
 		if( v > maxValue ) v = maxValue;
 		if( v > maxValue ) v = maxValue;
@@ -51,7 +51,7 @@ class Slider extends Component {
 			value = v;
 			value = v;
 		onChange(value);
 		onChange(value);
 	}
 	}
-	
+
 	function set_value(v:Float) {
 	function set_value(v:Float) {
 		if( v < minValue ) v = minValue;
 		if( v < minValue ) v = minValue;
 		if( v > maxValue ) v = maxValue;
 		if( v > maxValue ) v = maxValue;

+ 3 - 3
h2d/css/Fill.hx

@@ -1,12 +1,12 @@
 package h2d.css;
 package h2d.css;
 import h2d.css.Defs;
 import h2d.css.Defs;
 
 
-class Fill extends h2d.TileColorGroup {
+class Fill extends h2d.TileGroup {
 
 
 	public function new(?parent) {
 	public function new(?parent) {
 		super(h2d.Tile.fromColor(0xFFFFFFFF), parent);
 		super(h2d.Tile.fromColor(0xFFFFFFFF), parent);
 	}
 	}
-	
+
 	public inline function fillRectColor(x, y, w, h, c) {
 	public inline function fillRectColor(x, y, w, h, c) {
 		content.rectColor(x, y, w, h, c);
 		content.rectColor(x, y, w, h, c);
 	}
 	}
@@ -14,7 +14,7 @@ class Fill extends h2d.TileColorGroup {
 	public inline function fillRectGradient(x, y, w, h, ctl, ctr, cbl, cbr) {
 	public inline function fillRectGradient(x, y, w, h, ctl, ctr, cbl, cbr) {
 		content.rectGradient(x, y, w, h, ctl, ctr, cbl, cbr);
 		content.rectGradient(x, y, w, h, ctl, ctr, cbl, cbr);
 	}
 	}
-	
+
 	public inline function addPoint(x, y, color) {
 	public inline function addPoint(x, y, color) {
 		content.addPoint(x, y, color);
 		content.addPoint(x, y, color);
 	}
 	}

+ 5 - 5
h2d/css/Parser.hx

@@ -448,7 +448,7 @@ class Parser {
 			null;
 			null;
 		};
 		};
 	}
 	}
-	
+
 	function mapIdent<T:EnumValue>( v : Value, vals : Array<T> ) : T {
 	function mapIdent<T:EnumValue>( v : Value, vals : Array<T> ) : T {
 		var i = getIdent(v);
 		var i = getIdent(v);
 		if( i == null ) return null;
 		if( i == null ) return null;
@@ -544,7 +544,7 @@ class Parser {
 		default: null;
 		default: null;
 		};
 		};
 	}
 	}
-	
+
 	function getImage( v : Value ) {
 	function getImage( v : Value ) {
 		switch( v ) {
 		switch( v ) {
 		case VCall("url", [VString(url)]):
 		case VCall("url", [VString(url)]):
@@ -654,7 +654,7 @@ class Parser {
 		}
 		}
 		return rules;
 		return rules;
 	}
 	}
-	
+
 	public function parseClasses( css : String ) {
 	public function parseClasses( css : String ) {
 		this.css = css;
 		this.css = css;
 		pos = 0;
 		pos = 0;
@@ -683,7 +683,7 @@ class Parser {
 			unexpected(readToken());
 			unexpected(readToken());
 		return classes;
 		return classes;
 	}
 	}
-	
+
 	function updateClass( c : CssClass ) {
 	function updateClass( c : CssClass ) {
 		// map html types to comp ones
 		// map html types to comp ones
 		switch( c.node ) {
 		switch( c.node ) {
@@ -695,7 +695,7 @@ class Parser {
 		}
 		}
 		if( c.parent != null ) updateClass(c.parent);
 		if( c.parent != null ) updateClass(c.parent);
 	}
 	}
-	
+
 	function readClass( parent ) : CssClass {
 	function readClass( parent ) : CssClass {
 		var c = new CssClass();
 		var c = new CssClass();
 		c.parent = parent;
 		c.parent = parent;

+ 6 - 6
h2d/css/Style.hx

@@ -2,7 +2,7 @@ package h2d.css;
 import h2d.css.Defs;
 import h2d.css.Defs;
 
 
 class Style {
 class Style {
-	
+
 	public var fontName : Null<String>;
 	public var fontName : Null<String>;
 	public var fontSize : Null<Float>;
 	public var fontSize : Null<Float>;
 	public var color : Null<Int>;
 	public var color : Null<Int>;
@@ -41,10 +41,10 @@ class Style {
 	public var iconTop : Null<Float>;
 	public var iconTop : Null<Float>;
 	public var textAlign : Null<TextAlign>;
 	public var textAlign : Null<TextAlign>;
 	public var display : Null<Bool>;
 	public var display : Null<Bool>;
-	
+
 	public function new() {
 	public function new() {
 	}
 	}
-	
+
 	public function apply( s : Style ) {
 	public function apply( s : Style ) {
 		if( s.fontName != null ) fontName = s.fontName;
 		if( s.fontName != null ) fontName = s.fontName;
 		if( s.fontSize != null ) fontSize = s.fontSize;
 		if( s.fontSize != null ) fontSize = s.fontSize;
@@ -91,7 +91,7 @@ class Style {
 		if( s.textAlign != null ) textAlign = s.textAlign;
 		if( s.textAlign != null ) textAlign = s.textAlign;
 		if( s.display != null ) display = s.display;
 		if( s.display != null ) display = s.display;
 	}
 	}
-	
+
 	public function padding( v : Float ) {
 	public function padding( v : Float ) {
 		this.paddingTop = v;
 		this.paddingTop = v;
 		this.paddingLeft = v;
 		this.paddingLeft = v;
@@ -105,7 +105,7 @@ class Style {
 		this.marginRight = v;
 		this.marginRight = v;
 		this.marginBottom = v;
 		this.marginBottom = v;
 	}
 	}
-	
+
 	public function toString() {
 	public function toString() {
 		var fields = [];
 		var fields = [];
 		for( f in Type.getInstanceFields(Style) ) {
 		for( f in Type.getInstanceFields(Style) ) {
@@ -118,5 +118,5 @@ class Style {
 		}
 		}
 		return "{" + fields.join(", ") + "}";
 		return "{" + fields.join(", ") + "}";
 	}
 	}
-		
+
 }
 }

+ 2 - 0
h2d/css/default.css

@@ -6,6 +6,8 @@
 	border : none;
 	border : none;
 	background-color : transparent;
 	background-color : transparent;
 	text-align : left;
 	text-align : left;
+	padding : 0;
+	margin : 0;
 }
 }
 
 
 div.modal {
 div.modal {

+ 30 - 14
h3d/Buffer.hx

@@ -17,6 +17,10 @@ enum BufferFlag {
 		Will allocate the memory as part of an shared buffer pool, preventing a lot of small GPU buffers to be allocated.
 		Will allocate the memory as part of an shared buffer pool, preventing a lot of small GPU buffers to be allocated.
 	**/
 	**/
 	Managed;
 	Managed;
+	/**
+		Directly map the buffer content to the shader inputs, without assuming [pos:vec3,normal:vec3,uv:vec2] default prefix.
+	**/
+	RawFormat;
 	/**
 	/**
 		Used internaly
 		Used internaly
 	**/
 	**/
@@ -26,17 +30,23 @@ enum BufferFlag {
 class Buffer {
 class Buffer {
 	public static var GUID = 0;
 	public static var GUID = 0;
 	public var id : Int;
 	public var id : Int;
+	#if debug
+	var allocPos : h3d.impl.AllocPos;
+	#end
 
 
 	public var buffer(default,null) : h3d.impl.ManagedBuffer;
 	public var buffer(default,null) : h3d.impl.ManagedBuffer;
 	public var position(default,null) : Int;
 	public var position(default,null) : Int;
 	public var vertices(default,null) : Int;
 	public var vertices(default,null) : Int;
 	public var next(default,null) : Buffer;
 	public var next(default,null) : Buffer;
 	public var flags(default, null) : haxe.EnumFlags<BufferFlag>;
 	public var flags(default, null) : haxe.EnumFlags<BufferFlag>;
-	
-	public function new(vertices, stride, ?flags : Array<BufferFlag>) {
+
+	public function new(vertices, stride, ?flags : Array<BufferFlag>, ?allocPos : h3d.impl.AllocPos ) {
 		id = GUID++;
 		id = GUID++;
 		this.vertices = vertices;
 		this.vertices = vertices;
 		this.flags = new haxe.EnumFlags();
 		this.flags = new haxe.EnumFlags();
+		#if debug
+		this.allocPos = allocPos;
+		#end
 		if( flags != null )
 		if( flags != null )
 			for( f in flags )
 			for( f in flags )
 				this.flags.set(f);
 				this.flags.set(f);
@@ -49,7 +59,7 @@ class Buffer {
 	public function isDisposed() {
 	public function isDisposed() {
 		return buffer == null || buffer.isDisposed();
 		return buffer == null || buffer.isDisposed();
 	}
 	}
-	
+
 	public function dispose() {
 	public function dispose() {
 		if( buffer != null ) {
 		if( buffer != null ) {
 			buffer.freeBuffer(this);
 			buffer.freeBuffer(this);
@@ -57,7 +67,7 @@ class Buffer {
 			if( next != null ) next.dispose();
 			if( next != null ) next.dispose();
 		}
 		}
 	}
 	}
-	
+
 	/**
 	/**
 		Returns the total number of vertices including the potential next buffers if it is split.
 		Returns the total number of vertices including the potential next buffers if it is split.
 	**/
 	**/
@@ -70,7 +80,7 @@ class Buffer {
 		}
 		}
 		return count;
 		return count;
 	}
 	}
-	
+
 	public function uploadVector( buf : hxd.FloatBuffer, bufPos : Int, vertices : Int ) {
 	public function uploadVector( buf : hxd.FloatBuffer, bufPos : Int, vertices : Int ) {
 		var cur = this;
 		var cur = this;
 		while( vertices > 0 ) {
 		while( vertices > 0 ) {
@@ -82,7 +92,7 @@ class Buffer {
 			cur = cur.next;
 			cur = cur.next;
 		}
 		}
 	}
 	}
-	
+
 	public function uploadBytes( data : haxe.io.Bytes, dataPos : Int, vertices : Int ) {
 	public function uploadBytes( data : haxe.io.Bytes, dataPos : Int, vertices : Int ) {
 		var cur = this;
 		var cur = this;
 		while( vertices > 0 ) {
 		while( vertices > 0 ) {
@@ -94,28 +104,34 @@ class Buffer {
 			cur = cur.next;
 			cur = cur.next;
 		}
 		}
 	}
 	}
-	
-	public static function ofFloats( v : hxd.FloatBuffer, stride : Int, ?flags, ?vertices ) {
-		var nvert = vertices == null ? Std.int(v.length / stride) : vertices;
-		var b = new Buffer(nvert, stride, flags);
+
+	public static function ofFloats( v : hxd.FloatBuffer, stride : Int, ?flags, ?allocPos ) {
+		var nvert = Std.int(v.length / stride);
+		var b = new Buffer(nvert, stride, flags, allocPos);
 		b.uploadVector(v, 0, nvert);
 		b.uploadVector(v, 0, nvert);
 		return b;
 		return b;
 	}
 	}
-	
+
+	public static function ofSubFloats( v : hxd.FloatBuffer, stride : Int, vertices : Int, ?flags, ?allocPos ) {
+		var b = new Buffer(vertices, stride, flags, allocPos);
+		b.uploadVector(v, 0, vertices);
+		return b;
+	}
+
 }
 }
 
 
 class BufferOffset {
 class BufferOffset {
 	public var id : Int;
 	public var id : Int;
 	public var buffer : Buffer;
 	public var buffer : Buffer;
 	public var offset : Int;
 	public var offset : Int;
-	
+
 	/*
 	/*
 		This is used to return a list of BufferOffset without allocating an array
 		This is used to return a list of BufferOffset without allocating an array
 	*/
 	*/
 	public var next : BufferOffset;
 	public var next : BufferOffset;
-	
+
 	static var UID = 0;
 	static var UID = 0;
-	
+
 	public function new(buffer, offset) {
 	public function new(buffer, offset) {
 		this.id = UID++;
 		this.id = UID++;
 		this.buffer = buffer;
 		this.buffer = buffer;

+ 26 - 26
h3d/Camera.hx

@@ -3,39 +3,39 @@ package h3d;
 // use left-handed coordinate system, more suitable for 2D games X=0,Y=0 at screen top-left and Z towards user
 // use left-handed coordinate system, more suitable for 2D games X=0,Y=0 at screen top-left and Z towards user
 
 
 class Camera {
 class Camera {
-	
+
 	public var zoom : Float;
 	public var zoom : Float;
-	
+
 	/**
 	/**
 		The screenRatio represents the W/H screen ratio.
 		The screenRatio represents the W/H screen ratio.
 	 **/
 	 **/
 	public var screenRatio : Float;
 	public var screenRatio : Float;
-	
+
 	/**
 	/**
 		The horizontal FieldOfView, in degrees.
 		The horizontal FieldOfView, in degrees.
 	**/
 	**/
 	public var fovX : Float;
 	public var fovX : Float;
 	public var zNear : Float;
 	public var zNear : Float;
 	public var zFar : Float;
 	public var zFar : Float;
-	
+
 	/**
 	/**
 		Set orthographic bounds.
 		Set orthographic bounds.
 	**/
 	**/
 	public var orthoBounds : h3d.col.Bounds;
 	public var orthoBounds : h3d.col.Bounds;
-	
+
 	public var rightHanded : Bool;
 	public var rightHanded : Bool;
-	
+
 	public var mproj : Matrix;
 	public var mproj : Matrix;
 	public var mcam : Matrix;
 	public var mcam : Matrix;
 	public var m : Matrix;
 	public var m : Matrix;
-	
+
 	public var pos : Vector;
 	public var pos : Vector;
 	public var up : Vector;
 	public var up : Vector;
 	public var target : Vector;
 	public var target : Vector;
-	
+
 	public var viewX : Float = 0.;
 	public var viewX : Float = 0.;
 	public var viewY : Float = 0.;
 	public var viewY : Float = 0.;
-	
+
 	var minv : Matrix;
 	var minv : Matrix;
 	var needInv : Bool;
 	var needInv : Bool;
 
 
@@ -54,14 +54,14 @@ class Camera {
 		mproj = new Matrix();
 		mproj = new Matrix();
 		update();
 		update();
 	}
 	}
-	
+
 	/**
 	/**
 		Update the fovX value based on the requested fovY value (in degrees) and current screenRatio.
 		Update the fovX value based on the requested fovY value (in degrees) and current screenRatio.
 	**/
 	**/
 	public function setFovY( value : Float ) {
 	public function setFovY( value : Float ) {
 		fovX = Math.atan( Math.tan(value * Math.PI / 180) / screenRatio ) * 180 / Math.PI;
 		fovX = Math.atan( Math.tan(value * Math.PI / 180) / screenRatio ) * 180 / Math.PI;
 	}
 	}
-	
+
 	public function clone() {
 	public function clone() {
 		var c = new Camera(fovX, zoom, screenRatio, zNear, zFar, rightHanded);
 		var c = new Camera(fovX, zoom, screenRatio, zNear, zFar, rightHanded);
 		c.pos = pos.clone();
 		c.pos = pos.clone();
@@ -95,20 +95,20 @@ class Camera {
 		p.project(getInverseViewProj());
 		p.project(getInverseViewProj());
 		return p;
 		return p;
 	}
 	}
-	
+
 	public function update() {
 	public function update() {
 		makeCameraMatrix(mcam);
 		makeCameraMatrix(mcam);
 		makeFrustumMatrix(mproj);
 		makeFrustumMatrix(mproj);
 		m.multiply(mcam, mproj);
 		m.multiply(mcam, mproj);
 		needInv = true;
 		needInv = true;
 	}
 	}
-	
+
 	public function lostUp() {
 	public function lostUp() {
 		var p2 = pos.clone();
 		var p2 = pos.clone();
 		p2.normalize();
 		p2.normalize();
 		return Math.abs(p2.dot3(up)) > 0.999;
 		return Math.abs(p2.dot3(up)) > 0.999;
 	}
 	}
-	
+
 	public function movePosAxis( dx : Float, dy : Float, dz = 0. ) {
 	public function movePosAxis( dx : Float, dy : Float, dz = 0. ) {
 		var p = new Vector(dx, dy, dz);
 		var p = new Vector(dx, dy, dz);
 		p.project(mcam);
 		p.project(mcam);
@@ -124,7 +124,7 @@ class Camera {
 		target.y += p.y;
 		target.y += p.y;
 		target.z += p.z;
 		target.z += p.z;
 	}
 	}
-	
+
 	function makeCameraMatrix( m : Matrix ) {
 	function makeCameraMatrix( m : Matrix ) {
 		// in leftHanded the z axis is positive else it's negative
 		// in leftHanded the z axis is positive else it's negative
 		// this way we make sure that our [ax,ay,-az] matrix follow the same handness as our world
 		// this way we make sure that our [ax,ay,-az] matrix follow the same handness as our world
@@ -156,26 +156,26 @@ class Camera {
 		m._43 = -az.dot3(pos);
 		m._43 = -az.dot3(pos);
 		m._44 = 1;
 		m._44 = 1;
 	}
 	}
-	
+
 	function makeFrustumMatrix( m : Matrix ) {
 	function makeFrustumMatrix( m : Matrix ) {
 		m.zero();
 		m.zero();
-		
+
 		// this will take into account the aspect ratio and normalize the z value into [0,1] once it's been divided by w
 		// this will take into account the aspect ratio and normalize the z value into [0,1] once it's been divided by w
 		// Matrixes have to solve the following formulaes :
 		// Matrixes have to solve the following formulaes :
 		//
 		//
 		// transform P by Mproj and divide everything by
 		// transform P by Mproj and divide everything by
 		//    [x,y,-zNear,1] => [sx/zNear, sy/zNear, 0, 1]
 		//    [x,y,-zNear,1] => [sx/zNear, sy/zNear, 0, 1]
 		//    [x,y,-zFar,1] => [sx/zFar, sy/zFar, 1, 1]
 		//    [x,y,-zFar,1] => [sx/zFar, sy/zFar, 1, 1]
-		
+
 		// we apply the screen ratio to the height in order to have the fov being a horizontal FOV. This way we don't have to change the FOV when the screen is enlarged
 		// we apply the screen ratio to the height in order to have the fov being a horizontal FOV. This way we don't have to change the FOV when the screen is enlarged
-		
+
 		var bounds = orthoBounds;
 		var bounds = orthoBounds;
 		if( bounds != null ) {
 		if( bounds != null ) {
-			
+
 			var w = 1 / (bounds.xMax - bounds.xMin);
 			var w = 1 / (bounds.xMax - bounds.xMin);
 			var h = 1 / (bounds.yMax - bounds.yMin);
 			var h = 1 / (bounds.yMax - bounds.yMin);
 			var d = 1 / (bounds.zMax - bounds.zMin);
 			var d = 1 / (bounds.zMax - bounds.zMin);
-			
+
 			m._11 = 2 * w;
 			m._11 = 2 * w;
 			m._22 = 2 * h;
 			m._22 = 2 * h;
 			m._33 = d;
 			m._33 = d;
@@ -183,16 +183,16 @@ class Camera {
 			m._42 = -(bounds.yMin + bounds.yMax) * h;
 			m._42 = -(bounds.yMin + bounds.yMax) * h;
 			m._43 = -bounds.zMin * d;
 			m._43 = -bounds.zMin * d;
 			m._44 = 1;
 			m._44 = 1;
-			
+
 		} else {
 		} else {
-		
+
 			var scale = zoom / Math.tan(fovX * Math.PI / 360.0);
 			var scale = zoom / Math.tan(fovX * Math.PI / 360.0);
 			m._11 = scale;
 			m._11 = scale;
 			m._22 = scale * screenRatio;
 			m._22 = scale * screenRatio;
 			m._33 = zFar / (zFar - zNear);
 			m._33 = zFar / (zFar - zNear);
 			m._34 = 1;
 			m._34 = 1;
 			m._43 = -(zNear * zFar) / (zFar - zNear);
 			m._43 = -(zNear * zFar) / (zFar - zNear);
-			
+
 		}
 		}
 
 
 		m._11 += viewX * m._14;
 		m._11 += viewX * m._14;
@@ -204,12 +204,12 @@ class Camera {
 		m._22 += viewY * m._24;
 		m._22 += viewY * m._24;
 		m._32 += viewY * m._34;
 		m._32 += viewY * m._34;
 		m._42 += viewY * m._44;
 		m._42 += viewY * m._44;
-		
+
 		// our z is negative in that case
 		// our z is negative in that case
 		if( rightHanded ) {
 		if( rightHanded ) {
 			m._33 *= -1;
 			m._33 *= -1;
 			m._34 *= -1;
 			m._34 *= -1;
 		}
 		}
 	}
 	}
-		
+
 }
 }

+ 0 - 24
h3d/Drawable.hx

@@ -1,24 +0,0 @@
-package h3d;
-
-/**
-	A core object is a rendering context but completely outside of the 3d scene.
-	It is meant to be able to share a rendering context between several similar physical objects.
- **/
-class Drawable<S:h3d.impl.Shader> implements IDrawable {
-
-	public var shader : S;
-	public var primitive : h3d.prim.Primitive;
-	public var material : h3d.mat.Material;
-	
-	public function new(prim, shader) {
-		this.primitive = prim;
-		this.shader = shader;
-		this.material = new h3d.mat.Material(shader);
-	}
-	
-	public function render( engine : h3d.Engine ) {
-		engine.selectMaterial(material);
-		primitive.render(engine);
-	}
-	
-}

+ 62 - 86
h3d/Engine.hx

@@ -4,7 +4,7 @@ import h3d.mat.Data;
 class Engine {
 class Engine {
 
 
 	public var driver(default,null) : h3d.impl.Driver;
 	public var driver(default,null) : h3d.impl.Driver;
-	
+
 	public var mem(default,null) : h3d.impl.MemoryManager;
 	public var mem(default,null) : h3d.impl.MemoryManager;
 
 
 	public var hardware(default, null) : Bool;
 	public var hardware(default, null) : Bool;
@@ -16,23 +16,18 @@ class Engine {
 	public var drawCalls(default, null) : Int;
 	public var drawCalls(default, null) : Int;
 	public var shaderSwitches(default, null) : Int;
 	public var shaderSwitches(default, null) : Int;
 
 
-	public var backgroundColor : Int;
+	public var backgroundColor : Null<Int> = 0xFF000000;
 	public var autoResize : Bool;
 	public var autoResize : Bool;
 	public var fullScreen(default, set) : Bool;
 	public var fullScreen(default, set) : Bool;
-	
+
 	public var fps(get, never) : Float;
 	public var fps(get, never) : Float;
 	public var frameCount : Int = 0;
 	public var frameCount : Int = 0;
-	
-	public var forcedMatBits : Int = 0;
-	public var forcedMatMask : Int = 0xFFFFFF;
-	
+
 	var realFps : Float;
 	var realFps : Float;
 	var lastTime : Float;
 	var lastTime : Float;
 	var antiAlias : Int;
 	var antiAlias : Int;
-	
-	var debugPoint : h3d.Drawable<h3d.impl.Shaders.PointShader>;
-	var debugLine : h3d.Drawable<h3d.impl.Shaders.LineShader>;
-	
+	var tmpVector = new h3d.Vector();
+
 	@:allow(h3d)
 	@:allow(h3d)
 	var curProjMatrix : h3d.Matrix;
 	var curProjMatrix : h3d.Matrix;
 
 
@@ -41,14 +36,14 @@ class Engine {
 		this.hardware = hardware;
 		this.hardware = hardware;
 		this.antiAlias = aa;
 		this.antiAlias = aa;
 		this.autoResize = true;
 		this.autoResize = true;
-		
+
 		#if (!flash && openfl)
 		#if (!flash && openfl)
 			hxd.Stage.openFLBoot(start);
 			hxd.Stage.openFLBoot(start);
 		#else
 		#else
 			start();
 			start();
 		#end
 		#end
 	}
 	}
-	
+
 	function start() {
 	function start() {
 		fullScreen = !hxd.System.isWindowed;
 		fullScreen = !hxd.System.isWindowed;
 		var stage = hxd.Stage.getInstance();
 		var stage = hxd.Stage.getInstance();
@@ -65,20 +60,20 @@ class Engine {
 		if( CURRENT == null )
 		if( CURRENT == null )
 			CURRENT = this;
 			CURRENT = this;
 	}
 	}
-	
+
 	static var CURRENT : Engine = null;
 	static var CURRENT : Engine = null;
-	
+
 	static inline function check() {
 	static inline function check() {
 		#if debug
 		#if debug
 		if ( CURRENT == null ) throw "no current context, please do this operation after engine init/creation";
 		if ( CURRENT == null ) throw "no current context, please do this operation after engine init/creation";
 		#end
 		#end
 	}
 	}
-	
+
 	public static inline function getCurrent() {
 	public static inline function getCurrent() {
 		check();
 		check();
 		return CURRENT;
 		return CURRENT;
 	}
 	}
-	
+
 	public inline function setCurrent() {
 	public inline function setCurrent() {
 		CURRENT = this;
 		CURRENT = this;
 	}
 	}
@@ -90,38 +85,39 @@ class Engine {
 	public function driverName(details=false) {
 	public function driverName(details=false) {
 		return driver.getDriverName(details);
 		return driver.getDriverName(details);
 	}
 	}
-	
+
 	public function setCapture( bmp : hxd.BitmapData, callb : Void -> Void ) {
 	public function setCapture( bmp : hxd.BitmapData, callb : Void -> Void ) {
 		driver.setCapture(bmp,callb);
 		driver.setCapture(bmp,callb);
 	}
 	}
 
 
-	public function selectShader( shader : h3d.impl.Shader ) {
+	public function selectShader( shader : hxsl.RuntimeShader ) {
 		if( driver.selectShader(shader) )
 		if( driver.selectShader(shader) )
 			shaderSwitches++;
 			shaderSwitches++;
 	}
 	}
 
 
-	@:access(h3d.mat.Material.bits)
-	public function selectMaterial( m : h3d.mat.Material ) {
-		var mbits = (m.bits & forcedMatMask) | forcedMatBits;
-		driver.selectMaterial(mbits);
-		selectShader(m.shader);
+	public function selectMaterial( pass : h3d.mat.Pass ) {
+		driver.selectMaterial(pass);
+	}
+
+	public function uploadShaderBuffers(buffers, which) {
+		driver.uploadShaderBuffers(buffers, which);
 	}
 	}
 
 
-	function selectBuffer( buf : h3d.impl.ManagedBuffer ) {
+	function selectBuffer( buf : Buffer ) {
 		if( buf.isDisposed() )
 		if( buf.isDisposed() )
 			return false;
 			return false;
-		driver.selectBuffer(@:privateAccess buf.vbuf);
+		driver.selectBuffer(buf);
 		return true;
 		return true;
 	}
 	}
 
 
 	public inline function renderTriBuffer( b : Buffer, start = 0, max = -1 ) {
 	public inline function renderTriBuffer( b : Buffer, start = 0, max = -1 ) {
 		return renderBuffer(b, mem.triIndexes, 3, start, max);
 		return renderBuffer(b, mem.triIndexes, 3, start, max);
 	}
 	}
-	
+
 	public inline function renderQuadBuffer( b : Buffer, start = 0, max = -1 ) {
 	public inline function renderQuadBuffer( b : Buffer, start = 0, max = -1 ) {
 		return renderBuffer(b, mem.quadIndexes, 2, start, max);
 		return renderBuffer(b, mem.quadIndexes, 2, start, max);
 	}
 	}
-	
+
 	// we use preallocated indexes so all the triangles are stored inside our buffers
 	// we use preallocated indexes so all the triangles are stored inside our buffers
 	function renderBuffer( b : Buffer, indexes : Indexes, vertPerTri : Int, startTri = 0, drawTri = -1 ) {
 	function renderBuffer( b : Buffer, indexes : Indexes, vertPerTri : Int, startTri = 0, drawTri = -1 ) {
 		if( indexes.isDisposed() )
 		if( indexes.isDisposed() )
@@ -147,7 +143,7 @@ class Engine {
 					drawTri = 0;
 					drawTri = 0;
 				}
 				}
 			}
 			}
-			if( ntri > 0 && selectBuffer(b.buffer) ) {
+			if( ntri > 0 && selectBuffer(b) ) {
 				// *3 because it's the position in indexes which are always by 3
 				// *3 because it's the position in indexes which are always by 3
 				driver.draw(indexes.ibuf, pos * 3, ntri);
 				driver.draw(indexes.ibuf, pos * 3, ntri);
 				drawTriangles += ntri;
 				drawTriangles += ntri;
@@ -156,7 +152,7 @@ class Engine {
 			b = b.next;
 			b = b.next;
 		} while( b != null );
 		} while( b != null );
 	}
 	}
-	
+
 	// we use custom indexes, so the number of triangles is the number of indexes/3
 	// we use custom indexes, so the number of triangles is the number of indexes/3
 	public function renderIndexed( b : Buffer, indexes : Indexes, startTri = 0, drawTri = -1 ) {
 	public function renderIndexed( b : Buffer, indexes : Indexes, startTri = 0, drawTri = -1 ) {
 		if( b.next != null )
 		if( b.next != null )
@@ -165,14 +161,14 @@ class Engine {
 			return;
 			return;
 		var maxTri = Std.int(indexes.count / 3);
 		var maxTri = Std.int(indexes.count / 3);
 		if( drawTri < 0 ) drawTri = maxTri - startTri;
 		if( drawTri < 0 ) drawTri = maxTri - startTri;
-		if( drawTri > 0 && selectBuffer(b.buffer) ) {
+		if( drawTri > 0 && selectBuffer(b) ) {
 			// *3 because it's the position in indexes which are always by 3
 			// *3 because it's the position in indexes which are always by 3
 			driver.draw(indexes.ibuf, startTri * 3, drawTri);
 			driver.draw(indexes.ibuf, startTri * 3, drawTri);
 			drawTriangles += drawTri;
 			drawTriangles += drawTri;
 			drawCalls++;
 			drawCalls++;
 		}
 		}
 	}
 	}
-	
+
 	public function renderMultiBuffers( buffers : Buffer.BufferOffset, indexes : Indexes, startTri = 0, drawTri = -1 ) {
 	public function renderMultiBuffers( buffers : Buffer.BufferOffset, indexes : Indexes, startTri = 0, drawTri = -1 ) {
 		var maxTri = Std.int(indexes.count / 3);
 		var maxTri = Std.int(indexes.count / 3);
 		if( maxTri <= 0 ) return;
 		if( maxTri <= 0 ) return;
@@ -196,8 +192,9 @@ class Engine {
 
 
 	function onCreate( disposed ) {
 	function onCreate( disposed ) {
 		if( autoResize ) {
 		if( autoResize ) {
-			width = hxd.System.width;
-			height = hxd.System.height;
+			var stage = hxd.Stage.getInstance();
+			width = stage.width;
+			height = stage.height;
 		}
 		}
 		if( disposed )
 		if( disposed )
 			mem.onContextLost();
 			mem.onContextLost();
@@ -205,7 +202,7 @@ class Engine {
 			mem = new h3d.impl.MemoryManager(driver);
 			mem = new h3d.impl.MemoryManager(driver);
 			mem.init();
 			mem.init();
 		}
 		}
-		hardware = driver.isHardware();
+		hardware = driver.hasFeature(HardwareAccelerated);
 		set_debug(debug);
 		set_debug(debug);
 		set_fullScreen(fullScreen);
 		set_fullScreen(fullScreen);
 		resize(width, height);
 		resize(width, height);
@@ -214,29 +211,30 @@ class Engine {
 		else
 		else
 			onReady();
 			onReady();
 	}
 	}
-	
+
 	public dynamic function onContextLost() {
 	public dynamic function onContextLost() {
 	}
 	}
 
 
 	public dynamic function onReady() {
 	public dynamic function onReady() {
 	}
 	}
-	
+
 	function onStageResize() {
 	function onStageResize() {
 		if( autoResize && !driver.isDisposed() ) {
 		if( autoResize && !driver.isDisposed() ) {
-			var w = hxd.System.width, h = hxd.System.height;
+			var stage = hxd.Stage.getInstance();
+			var w = stage.width, h = stage.height;
 			if( w != width || h != height )
 			if( w != width || h != height )
 				resize(w, h);
 				resize(w, h);
 			onResized();
 			onResized();
 		}
 		}
 	}
 	}
-	
+
 	function set_fullScreen(v) {
 	function set_fullScreen(v) {
 		fullScreen = v;
 		fullScreen = v;
 		if( mem != null && hxd.System.isWindowed )
 		if( mem != null && hxd.System.isWindowed )
 			hxd.Stage.getInstance().setFullScreen(v);
 			hxd.Stage.getInstance().setFullScreen(v);
 		return v;
 		return v;
 	}
 	}
-	
+
 	public dynamic function onResized() {
 	public dynamic function onResized() {
 	}
 	}
 
 
@@ -252,14 +250,15 @@ class Engine {
 	public function begin() {
 	public function begin() {
 		if( driver.isDisposed() )
 		if( driver.isDisposed() )
 			return false;
 			return false;
-		driver.clear( ((backgroundColor>>16)&0xFF)/255 , ((backgroundColor>>8)&0xFF)/255, (backgroundColor&0xFF)/255, ((backgroundColor>>>24)&0xFF)/255);
 		// init
 		// init
 		frameCount++;
 		frameCount++;
 		drawTriangles = 0;
 		drawTriangles = 0;
 		shaderSwitches = 0;
 		shaderSwitches = 0;
 		drawCalls = 0;
 		drawCalls = 0;
 		curProjMatrix = null;
 		curProjMatrix = null;
+		currentTarget = null;
 		driver.begin(frameCount);
 		driver.begin(frameCount);
+		if( backgroundColor != null ) clear(backgroundColor, 1, 0);
 		return true;
 		return true;
 	}
 	}
 
 
@@ -267,18 +266,35 @@ class Engine {
 		driver.reset();
 		driver.reset();
 	}
 	}
 
 
+	public function hasFeature(f) {
+		return driver.hasFeature(f);
+	}
+
 	public function end() {
 	public function end() {
 		driver.present();
 		driver.present();
 		reset();
 		reset();
 		curProjMatrix = null;
 		curProjMatrix = null;
 	}
 	}
 
 
+	var currentTarget : h3d.mat.Texture;
+
+	public function getTarget() {
+		return currentTarget;
+	}
+
 	/**
 	/**
 	 * Setus a render target to do off screen rendering, might be costly on low end devices
 	 * Setus a render target to do off screen rendering, might be costly on low end devices
      * setTarget to null when you're finished rendering to it.
      * setTarget to null when you're finished rendering to it.
 	 */
 	 */
-	public function setTarget( tex : h3d.mat.Texture,  clearColor = 0 ) {
-		driver.setRenderTarget(tex, clearColor);
+	public function setTarget( tex : h3d.mat.Texture ) {
+		currentTarget = tex;
+		driver.setRenderTarget(tex);
+	}
+
+	public function clear( ?color : Int, ?depth : Float, ?stencil : Int ) {
+		if( color != null )
+			tmpVector.setColor(color);
+		driver.clear(color == null ? null : tmpVector, depth, stencil);
 	}
 	}
 
 
 	/**
 	/**
@@ -293,7 +309,7 @@ class Engine {
 		if( !begin() ) return false;
 		if( !begin() ) return false;
 		obj.render(this);
 		obj.render(this);
 		end();
 		end();
-				
+
 		var delta = haxe.Timer.stamp() - lastTime;
 		var delta = haxe.Timer.stamp() - lastTime;
 		lastTime += delta;
 		lastTime += delta;
 		if( delta > 0 ) {
 		if( delta > 0 ) {
@@ -305,54 +321,14 @@ class Engine {
 		}
 		}
 		return true;
 		return true;
 	}
 	}
-	
-	// debug functions
-	public function point( x : Float, y : Float, z : Float, color = 0x80FF0000, size = 1.0, depth = false ) {
-		if( curProjMatrix == null )
-			return;
-		if( debugPoint == null ) {
-			debugPoint = new Drawable(new h3d.prim.Plan2D(), new h3d.impl.Shaders.PointShader());
-			debugPoint.material.blend(SrcAlpha, OneMinusSrcAlpha);
-			debugPoint.material.depthWrite = false;
-			debugPoint.material.culling = None;
-		}
-		debugPoint.material.depthTest = depth ? h3d.mat.Data.Compare.LessEqual : h3d.mat.Data.Compare.Always;
-		debugPoint.shader.mproj = curProjMatrix;
-		debugPoint.shader.delta = new h3d.Vector(x, y, z, 1);
-		var gscale = 1 / 200;
-		debugPoint.shader.size = new h3d.Vector(size * gscale, size * gscale * width / height);
-		debugPoint.shader.color = color;
-		debugPoint.render(h3d.Engine.getCurrent());
-	}
-
-	public function line( x1 : Float, y1 : Float, z1 : Float, x2 : Float, y2 : Float, z2 : Float, color = 0x80FF0000, depth = false ) {
-		if( curProjMatrix == null )
-			return;
-		if( debugLine == null ) {
-			debugLine = new Drawable(new h3d.prim.Plan2D(), new h3d.impl.Shaders.LineShader());
-			debugLine.material.blend(SrcAlpha, OneMinusSrcAlpha);
-			debugLine.material.depthWrite = false;
-			debugLine.material.culling = None;
-		}
-		debugLine.material.depthTest = depth ? h3d.mat.Data.Compare.LessEqual : h3d.mat.Data.Compare.Always;
-		debugLine.shader.mproj = curProjMatrix;
-		debugLine.shader.start = new h3d.Vector(x1, y1, z1);
-		debugLine.shader.end = new h3d.Vector(x2, y2, z2);
-		debugLine.shader.color = color;
-		debugLine.render(h3d.Engine.getCurrent());
-	}
-
-	public function lineP( a : { x : Float, y : Float, z : Float }, b : { x : Float, y : Float, z : Float }, color = 0x80FF0000, depth = false ) {
-		line(a.x, a.y, a.z, b.x, b.y, b.z, color, depth);
-	}
 
 
 	public function dispose() {
 	public function dispose() {
 		driver.dispose();
 		driver.dispose();
 		hxd.Stage.getInstance().removeResizeEvent(onStageResize);
 		hxd.Stage.getInstance().removeResizeEvent(onStageResize);
 	}
 	}
-	
+
 	function get_fps() {
 	function get_fps() {
 		return Math.ceil(realFps * 100) / 100;
 		return Math.ceil(realFps * 100) / 100;
 	}
 	}
-	
+
 }
 }

+ 6 - 6
h3d/Indexes.hx

@@ -7,26 +7,26 @@ class Indexes {
 	var mem : h3d.impl.MemoryManager;
 	var mem : h3d.impl.MemoryManager;
 	var ibuf : h3d.impl.Driver.IndexBuffer;
 	var ibuf : h3d.impl.Driver.IndexBuffer;
 	public var count(default,null) : Int;
 	public var count(default,null) : Int;
-	
+
 	public function new(count) {
 	public function new(count) {
 		this.mem = h3d.Engine.getCurrent().mem;
 		this.mem = h3d.Engine.getCurrent().mem;
 		this.count = count;
 		this.count = count;
 		mem.allocIndexes(this);
 		mem.allocIndexes(this);
 	}
 	}
-	
+
 	public function isDisposed() {
 	public function isDisposed() {
 		return ibuf == null;
 		return ibuf == null;
 	}
 	}
-	
+
 	public function upload( indexes : hxd.IndexBuffer, pos : Int, count : Int, bufferPos = 0 ) {
 	public function upload( indexes : hxd.IndexBuffer, pos : Int, count : Int, bufferPos = 0 ) {
-		mem.driver.uploadIndexesBuffer(this.ibuf, pos, count, indexes, bufferPos);
+		mem.driver.uploadIndexBuffer(this.ibuf, pos, count, indexes, bufferPos);
 	}
 	}
-	
+
 	public function dispose() {
 	public function dispose() {
 		if( ibuf != null )
 		if( ibuf != null )
 			mem.deleteIndexes(this);
 			mem.deleteIndexes(this);
 	}
 	}
-	
+
 	public static function alloc( i : hxd.IndexBuffer ) {
 	public static function alloc( i : hxd.IndexBuffer ) {
 		var idx = new Indexes( i.length );
 		var idx = new Indexes( i.length );
 		idx.upload(i, 0, i.length);
 		idx.upload(i, 0, i.length);

+ 48 - 0
h3d/Matrix.hx

@@ -496,6 +496,54 @@ class Matrix {
 		_43 += brightness;
 		_43 += brightness;
 	}
 	}
 
 
+	public function colorBits( bits : Int, blend : Float ) {
+		var t11 = 0., t12 = 0., t13 = 0.;
+		var t21 = 0., t22 = 0., t23 = 0.;
+		var t31 = 0., t32 = 0., t33 = 0.;
+		var c = bits;
+		if( c & 1 == 1 ) t11 = 1; c >>= 1;
+		if( c & 1 == 1 ) t12 = 1; c >>= 1;
+		if( c & 1 == 1 ) t13 = 1; c >>= 1;
+		if( c & 1 == 1 ) t21 = 1; c >>= 1;
+		if( c & 1 == 1 ) t22 = 1; c >>= 1;
+		if( c & 1 == 1 ) t23 = 1; c >>= 1;
+		if( c & 1 == 1 ) t31 = 1; c >>= 1;
+		if( c & 1 == 1 ) t32 = 1; c >>= 1;
+		if( c & 1 == 1 ) t33 = 1; c >>= 1;
+		var r = t11 + t21 + t31;
+		var g = t12 + t22 + t32;
+		var b = t13 + t23 + t33;
+		if( r > 1 ) { t11 /= r; t21 /= r; t31 /= r; }
+		if( g > 1 ) { t12 /= r; t22 /= r; t32 /= r; }
+		if( b > 1 ) { t13 /= r; t23 /= r; t33 /= r; }
+
+		// multiply our 3x3 by current matrix
+
+		var b11 = _11 * t11 + _12 * t21 + _13 * t31;
+		var b12 = _11 * t12 + _12 * t22 + _13 * t32;
+		var b13 = _11 * t13 + _12 * t23 + _13 * t33;
+
+		var b21 = _21 * t11 + _22 * t21 + _23 * t31;
+		var b22 = _21 * t12 + _22 * t22 + _23 * t32;
+		var b23 = _21 * t13 + _22 * t23 + _23 * t33;
+
+		var b31 = _31 * t11 + _32 * t21 + _33 * t31;
+		var b32 = _31 * t12 + _32 * t22 + _33 * t32;
+		var b33 = _31 * t13 + _32 * t23 + _33 * t33;
+
+		// blend it
+		var ik = blend, k = 1 - ik;
+		_11 = _11 * k + b11 * ik;
+		_12 = _12 * k + b12 * ik;
+		_13 = _13 * k + b13 * ik;
+		_21 = _21 * k + b21 * ik;
+		_22 = _22 * k + b22 * ik;
+		_23 = _23 * k + b23 * ik;
+		_31 = _31 * k + b31 * ik;
+		_32 = _32 * k + b32 * ik;
+		_33 = _33 * k + b33 * ik;
+	}
+
 	// STATICS
 	// STATICS
 
 
 	public static function I() {
 	public static function I() {

+ 23 - 23
h3d/Quat.hx

@@ -2,43 +2,43 @@ package h3d;
 using hxd.Math;
 using hxd.Math;
 
 
 class Quat {
 class Quat {
-	
+
 	public var x : Float;
 	public var x : Float;
 	public var y : Float;
 	public var y : Float;
 	public var z : Float;
 	public var z : Float;
 	public var w : Float;
 	public var w : Float;
-	
+
 	public inline function new( x = 0., y = 0., z = 0., w = 1. ) {
 	public inline function new( x = 0., y = 0., z = 0., w = 1. ) {
 		this.x = x;
 		this.x = x;
 		this.y = y;
 		this.y = y;
 		this.z = z;
 		this.z = z;
 		this.w = w;
 		this.w = w;
 	}
 	}
-	
+
 	public inline function set(x, y, z, w) {
 	public inline function set(x, y, z, w) {
 		this.x = x;
 		this.x = x;
 		this.y = y;
 		this.y = y;
 		this.z = z;
 		this.z = z;
 		this.w = w;
 		this.w = w;
 	}
 	}
-	
+
 	public inline function identity() {
 	public inline function identity() {
 		x = y = z = 0;
 		x = y = z = 0;
 		w = 1;
 		w = 1;
 	}
 	}
-	
+
 	public inline function lengthSq() {
 	public inline function lengthSq() {
 		return x * x + y * y + z * z + w * w;
 		return x * x + y * y + z * z + w * w;
 	}
 	}
-	
+
 	public inline function length() {
 	public inline function length() {
 		return lengthSq().sqrt();
 		return lengthSq().sqrt();
 	}
 	}
-	
+
 	public function clone() {
 	public function clone() {
 		return new Quat(x, y, z, w);
 		return new Quat(x, y, z, w);
 	}
 	}
-	
+
 	public function initMoveTo( from : Vector, to : Vector ) {
 	public function initMoveTo( from : Vector, to : Vector ) {
 		//		H = Normalize(From + To)
 		//		H = Normalize(From + To)
 		//		Q = (From ^ H, From . H)
 		//		Q = (From ^ H, From . H)
@@ -54,7 +54,7 @@ class Quat {
 		w = from.x * hx + from.y * hy + from.z * hz;
 		w = from.x * hx + from.y * hy + from.z * hz;
 		normalize();
 		normalize();
 	}
 	}
-	
+
 	public function initDirection( dir : Vector ) {
 	public function initDirection( dir : Vector ) {
 		// inlined version of initRotationMatrix(Matrix.lookAtX(dir))
 		// inlined version of initRotationMatrix(Matrix.lookAtX(dir))
 		var ax = dir.clone().getNormalized();
 		var ax = dir.clone().getNormalized();
@@ -96,7 +96,7 @@ class Quat {
 			w = (ax.y - ay.x) * is;
 			w = (ax.y - ay.x) * is;
 		}
 		}
 	}
 	}
-	
+
 	public function initRotateAxis( x : Float, y : Float, z : Float, a : Float ) {
 	public function initRotateAxis( x : Float, y : Float, z : Float, a : Float ) {
 		var sin = (a / 2).sin();
 		var sin = (a / 2).sin();
 		var cos = (a / 2).cos();
 		var cos = (a / 2).cos();
@@ -106,7 +106,7 @@ class Quat {
 		this.w = cos * (x * x + y * y + z * z).sqrt(); // allow not normalized axis
 		this.w = cos * (x * x + y * y + z * z).sqrt(); // allow not normalized axis
 		normalize();
 		normalize();
 	}
 	}
-	
+
 	public function initRotateMatrix( m : Matrix ) {
 	public function initRotateMatrix( m : Matrix ) {
 		var tr = m._11 + m._22 + m._33;
 		var tr = m._11 + m._22 + m._33;
 		if( tr > 0 ) {
 		if( tr > 0 ) {
@@ -139,7 +139,7 @@ class Quat {
 			w = (m._12 - m._21) * is;
 			w = (m._12 - m._21) * is;
 		}
 		}
 	}
 	}
-	
+
 	public function normalize() {
 	public function normalize() {
 		var len = x * x + y * y + z * z + w * w;
 		var len = x * x + y * y + z * z + w * w;
 		if( len < hxd.Math.EPSILON ) {
 		if( len < hxd.Math.EPSILON ) {
@@ -153,7 +153,7 @@ class Quat {
 			w *= m;
 			w *= m;
 		}
 		}
 	}
 	}
-	
+
 	public function initRotate( ax : Float, ay : Float, az : Float ) {
 	public function initRotate( ax : Float, ay : Float, az : Float ) {
 		var sinX = ( ax * 0.5 ).sin();
 		var sinX = ( ax * 0.5 ).sin();
 		var cosX = ( ax * 0.5 ).cos();
 		var cosX = ( ax * 0.5 ).cos();
@@ -168,7 +168,7 @@ class Quat {
 		z = cosX * cosY * sinZ - sinX * sinY * cosZ;
 		z = cosX * cosY * sinZ - sinX * sinY * cosZ;
 		w = cosX * cosYZ + sinX * sinYZ;
 		w = cosX * cosYZ + sinX * sinYZ;
 	}
 	}
-	
+
 	public function multiply( q1 : Quat, q2 : Quat ) {
 	public function multiply( q1 : Quat, q2 : Quat ) {
 		var x2 = q1.x * q2.w + q1.w * q2.x + q1.y * q2.z - q1.z * q2.y;
 		var x2 = q1.x * q2.w + q1.w * q2.x + q1.y * q2.z - q1.z * q2.y;
 		var y2 = q1.w * q2.y - q1.x * q2.z + q1.y * q2.w + q1.z * q2.x;
 		var y2 = q1.w * q2.y - q1.x * q2.z + q1.y * q2.w + q1.z * q2.x;
@@ -179,13 +179,13 @@ class Quat {
 		z = z2;
 		z = z2;
 		w = w2;
 		w = w2;
 	}
 	}
-	
+
 	public function toMatrix() {
 	public function toMatrix() {
 		var m = new Matrix();
 		var m = new Matrix();
 		saveToMatrix(m);
 		saveToMatrix(m);
 		return m;
 		return m;
 	}
 	}
-	
+
 	public function toEuler() {
 	public function toEuler() {
 		return new Vector(
 		return new Vector(
 			hxd.Math.atan2(2 * (x * w + y * z), 1 - 2 * (x * x + z * z)),
 			hxd.Math.atan2(2 * (x * w + y * z), 1 - 2 * (x * x + z * z)),
@@ -193,7 +193,7 @@ class Quat {
 			(2 * (x * y + z * w)).asin()
 			(2 * (x * y + z * w)).asin()
 		);
 		);
 	}
 	}
-	
+
 	public inline function lerp( q1 : Quat, q2 : Quat, v : Float, nearest = false ) {
 	public inline function lerp( q1 : Quat, q2 : Quat, v : Float, nearest = false ) {
 		var v2;
 		var v2;
 		if( nearest && q1.dot(q2) < 0 )
 		if( nearest && q1.dot(q2) < 0 )
@@ -232,13 +232,13 @@ class Quat {
 		this.z = q1.z * a + q2.z * b;
 		this.z = q1.z * a + q2.z * b;
 		this.w = q1.w * a + q2.w * b;
 		this.w = q1.w * a + q2.w * b;
 	}
 	}
-	
+
 	public inline function conjugate() {
 	public inline function conjugate() {
 		x *= -1;
 		x *= -1;
 		y *= -1;
 		y *= -1;
 		z *= -1;
 		z *= -1;
 	}
 	}
-	
+
 	/**
 	/**
 		Negate the quaternion: this will not change the actual angle, use `conjugate` for that.
 		Negate the quaternion: this will not change the actual angle, use `conjugate` for that.
 	**/
 	**/
@@ -248,11 +248,11 @@ class Quat {
 		z *= -1;
 		z *= -1;
 		w *= -1;
 		w *= -1;
 	}
 	}
-	
+
 	public inline function dot( q : Quat ) {
 	public inline function dot( q : Quat ) {
 		return x * q.x + y * q.y + z * q.z + w * q.w;
 		return x * q.x + y * q.y + z * q.z + w * q.w;
 	}
 	}
-	
+
 	/**
 	/**
 		Save to a Left-Handed matrix
 		Save to a Left-Handed matrix
 	**/
 	**/
@@ -284,9 +284,9 @@ class Quat {
 		m._44 = 1;
 		m._44 = 1;
 		return m;
 		return m;
 	}
 	}
-	
+
 	public function toString() {
 	public function toString() {
 		return '{${x.fmt()},${y.fmt()},${z.fmt()},${w.fmt()}}';
 		return '{${x.fmt()},${y.fmt()},${z.fmt()},${w.fmt()}}';
 	}
 	}
-	
+
 }
 }

+ 43 - 31
h3d/Vector.hx

@@ -17,7 +17,7 @@ class Vector {
 		this.z = z;
 		this.z = z;
 		this.w = w;
 		this.w = w;
 	}
 	}
-	
+
 	public inline function distance( v : Vector ) {
 	public inline function distance( v : Vector ) {
 		return Math.sqrt(distanceSq(v));
 		return Math.sqrt(distanceSq(v));
 	}
 	}
@@ -41,7 +41,7 @@ class Vector {
 	public inline function cross( v : Vector ) {
 	public inline function cross( v : Vector ) {
 		return new Vector(y * v.z - z * v.y, z * v.x - x * v.z,  x * v.y - y * v.x, 1);
 		return new Vector(y * v.z - z * v.y, z * v.x - x * v.z,  x * v.y - y * v.x, 1);
 	}
 	}
-	
+
 	public inline function reflect( n : Vector ) {
 	public inline function reflect( n : Vector ) {
 		var k = 2 * this.dot3(n);
 		var k = 2 * this.dot3(n);
 		return new Vector(x - k * n.x, y - k * n.y, z - k * n.z, 1);
 		return new Vector(x - k * n.x, y - k * n.y, z - k * n.z, 1);
@@ -70,20 +70,20 @@ class Vector {
 		y *= k;
 		y *= k;
 		z *= k;
 		z *= k;
 	}
 	}
-	
+
 	public inline function getNormalized() {
 	public inline function getNormalized() {
 		var k = lengthSq();
 		var k = lengthSq();
 		if( k < hxd.Math.EPSILON ) k = 0 else k = k.invSqrt();
 		if( k < hxd.Math.EPSILON ) k = 0 else k = k.invSqrt();
 		return new Vector(x * k, y * k, z * k);
 		return new Vector(x * k, y * k, z * k);
 	}
 	}
 
 
-	public inline function set(x,y,z,w=1.) {
+	public inline function set(x=0.,y=0.,z=0.,w=1.) {
 		this.x = x;
 		this.x = x;
 		this.y = y;
 		this.y = y;
 		this.z = z;
 		this.z = z;
 		this.w = w;
 		this.w = w;
 	}
 	}
-	
+
 	public inline function load(v : Vector) {
 	public inline function load(v : Vector) {
 		this.x = v.x;
 		this.x = v.x;
 		this.y = v.y;
 		this.y = v.y;
@@ -96,7 +96,7 @@ class Vector {
 		y *= f;
 		y *= f;
 		z *= f;
 		z *= f;
 	}
 	}
-	
+
 	public inline function project( m : Matrix ) {
 	public inline function project( m : Matrix ) {
 		var px = x * m._11 + y * m._21 + z * m._31 + w * m._41;
 		var px = x * m._11 + y * m._21 + z * m._31 + w * m._41;
 		var py = x * m._12 + y * m._22 + z * m._32 + w * m._42;
 		var py = x * m._12 + y * m._22 + z * m._32 + w * m._42;
@@ -107,7 +107,7 @@ class Vector {
 		z = pz * iw;
 		z = pz * iw;
 		w = 1;
 		w = 1;
 	}
 	}
-	
+
 	public inline function lerp( v1 : Vector, v2 : Vector, k : Float ) {
 	public inline function lerp( v1 : Vector, v2 : Vector, k : Float ) {
 		var x = Math.lerp(v1.x, v2.x, k);
 		var x = Math.lerp(v1.x, v2.x, k);
 		var y = Math.lerp(v1.y, v2.y, k);
 		var y = Math.lerp(v1.y, v2.y, k);
@@ -118,7 +118,7 @@ class Vector {
 		this.z = z;
 		this.z = z;
 		this.w = w;
 		this.w = w;
 	}
 	}
-	
+
 	public inline function transform3x4( m : Matrix ) {
 	public inline function transform3x4( m : Matrix ) {
 		var px = x * m._11 + y * m._21 + z * m._31 + w * m._41;
 		var px = x * m._11 + y * m._21 + z * m._31 + w * m._41;
 		var py = x * m._12 + y * m._22 + z * m._32 + w * m._42;
 		var py = x * m._12 + y * m._22 + z * m._32 + w * m._42;
@@ -136,7 +136,7 @@ class Vector {
 		y = py;
 		y = py;
 		z = pz;
 		z = pz;
 	}
 	}
-	
+
 	public inline function transform( m : Matrix ) {
 	public inline function transform( m : Matrix ) {
 		var px = x * m._11 + y * m._21 + z * m._31 + w * m._41;
 		var px = x * m._11 + y * m._21 + z * m._31 + w * m._41;
 		var py = x * m._12 + y * m._22 + z * m._32 + w * m._42;
 		var py = x * m._12 + y * m._22 + z * m._32 + w * m._42;
@@ -147,38 +147,50 @@ class Vector {
 		z = pz;
 		z = pz;
 		w = pw;
 		w = pw;
 	}
 	}
-	
-	public inline function setColor( c : Int ) {
-		loadColor(c);
-	}
 
 
-	public inline function loadColor( c : Int, scale : Float = 1.0 ) {
-		var s = scale / 255;
-		x = ((c >> 16) & 0xFF) * s;
-		y = ((c >> 8) & 0xFF) * s;
-		z = (c & 0xFF) * s;
-		w = (c >>> 24) * s;
+	public inline function clone() {
+		return new Vector(x,y,z,w);
 	}
 	}
-	
+
 	public inline function toPoint() {
 	public inline function toPoint() {
 		return new h3d.col.Point(x, y, z);
 		return new h3d.col.Point(x, y, z);
 	}
 	}
-	
-	public inline function toColor() {
-		return (Std.int(w.clamp() * 255 + 0.499) << 24) | (Std.int(x.clamp() * 255 + 0.499) << 16) | (Std.int(y.clamp() * 255 + 0.499) << 8) | Std.int(z.clamp() * 255 + 0.499);
+
+	public function toString() {
+		return '{${x.fmt()},${y.fmt()},${z.fmt()},${w.fmt()}}';
 	}
 	}
-	
-	public static inline function fromColor( c : Int, scale : Float = 1.0 ) {
+
+	/// ----- COLOR FUNCTIONS
+
+	public var r(get, set) : Float;
+	public var g(get, set) : Float;
+	public var b(get, set) : Float;
+	public var a(get, set) : Float;
+
+	inline function get_r() return x;
+	inline function get_g() return y;
+	inline function get_b() return z;
+	inline function get_a() return w;
+	inline function set_r(v) return x = v;
+	inline function set_g(v) return y = v;
+	inline function set_b(v) return z = v;
+	inline function set_a(v) return w = v;
+
+	public inline function setColor( c : Int, scale : Float = 1.0 ) {
 		var s = scale / 255;
 		var s = scale / 255;
-		return new Vector(((c>>16)&0xFF)*s,((c>>8)&0xFF)*s,(c&0xFF)*s,(c >>> 24)*s);
+		r = ((c >> 16) & 0xFF) * s;
+		g = ((c >> 8) & 0xFF) * s;
+		b = (c & 0xFF) * s;
+		a = (c >>> 24) * s;
 	}
 	}
-	
-	public inline function clone() {
-		return new Vector(x,y,z,w);
+
+	public inline function toColor() {
+		return (Std.int(a.clamp() * 255 + 0.499) << 24) | (Std.int(r.clamp() * 255 + 0.499) << 16) | (Std.int(g.clamp() * 255 + 0.499) << 8) | Std.int(b.clamp() * 255 + 0.499);
 	}
 	}
 
 
-	public function toString() {
-		return '{${x.fmt()},${y.fmt()},${z.fmt()},${w.fmt()}}';
+	public static inline function fromColor( c : Int, scale : Float = 1.0 ) {
+		var s = scale / 255;
+		return new Vector(((c>>16)&0xFF)*s,((c>>8)&0xFF)*s,(c&0xFF)*s,(c >>> 24)*s);
 	}
 	}
 
 
 }
 }

+ 11 - 15
h3d/anim/FrameAnimation.hx

@@ -5,7 +5,7 @@ class FrameObject extends AnimatedObject {
 	public var frames : haxe.ds.Vector<h3d.Matrix>;
 	public var frames : haxe.ds.Vector<h3d.Matrix>;
 	public var alphas : haxe.ds.Vector<Float>;
 	public var alphas : haxe.ds.Vector<Float>;
 	public var uvs : haxe.ds.Vector<Float>;
 	public var uvs : haxe.ds.Vector<Float>;
-	
+
 	override function clone() : AnimatedObject {
 	override function clone() : AnimatedObject {
 		var o = new FrameObject(objectName);
 		var o = new FrameObject(objectName);
 		o.frames = frames;
 		o.frames = frames;
@@ -14,7 +14,7 @@ class FrameObject extends AnimatedObject {
 		return o;
 		return o;
 	}
 	}
 }
 }
-	
+
 class FrameAnimation extends Animation {
 class FrameAnimation extends Animation {
 
 
 	var syncFrame : Int;
 	var syncFrame : Int;
@@ -23,13 +23,13 @@ class FrameAnimation extends Animation {
 		super(name,frame,sampling);
 		super(name,frame,sampling);
 		syncFrame = -1;
 		syncFrame = -1;
 	}
 	}
-	
+
 	public function addCurve( objName, frames ) {
 	public function addCurve( objName, frames ) {
 		var f = new FrameObject(objName);
 		var f = new FrameObject(objName);
 		f.frames = frames;
 		f.frames = frames;
 		objects.push(f);
 		objects.push(f);
 	}
 	}
-	
+
 	public function addAlphaCurve( objName, alphas ) {
 	public function addAlphaCurve( objName, alphas ) {
 		var f = new FrameObject(objName);
 		var f = new FrameObject(objName);
 		f.alphas = alphas;
 		f.alphas = alphas;
@@ -41,25 +41,25 @@ class FrameAnimation extends Animation {
 		f.uvs = uvs;
 		f.uvs = uvs;
 		objects.push(f);
 		objects.push(f);
 	}
 	}
-	
+
 	inline function getFrames() : Array<FrameObject> {
 	inline function getFrames() : Array<FrameObject> {
 		return cast objects;
 		return cast objects;
 	}
 	}
-	
+
 	override function initInstance() {
 	override function initInstance() {
 		super.initInstance();
 		super.initInstance();
 		for( a in getFrames() )
 		for( a in getFrames() )
 			if( a.alphas != null && (a.targetObject == null || !a.targetObject.isMesh()) )
 			if( a.alphas != null && (a.targetObject == null || !a.targetObject.isMesh()) )
 				throw a.objectName + " should be a mesh";
 				throw a.objectName + " should be a mesh";
 	}
 	}
-	
+
 	override function clone(?a:Animation) {
 	override function clone(?a:Animation) {
 		if( a == null )
 		if( a == null )
 			a = new FrameAnimation(name, frameCount, sampling);
 			a = new FrameAnimation(name, frameCount, sampling);
 		super.clone(a);
 		super.clone(a);
 		return a;
 		return a;
 	}
 	}
-	
+
 	@:access(h3d.scene.Skin)
 	@:access(h3d.scene.Skin)
 	override function sync( decompose = false ) {
 	override function sync( decompose = false ) {
 		if( decompose ) throw "Decompose not supported on Frame Animation";
 		if( decompose ) throw "Decompose not supported on Frame Animation";
@@ -71,12 +71,8 @@ class FrameAnimation extends Animation {
 		for( o in getFrames() ) {
 		for( o in getFrames() ) {
 			if( o.alphas != null ) {
 			if( o.alphas != null ) {
 				var mat = o.targetObject.toMesh().material;
 				var mat = o.targetObject.toMesh().material;
-				if( mat.colorMul == null ) {
-					mat.colorMul = new Vector(1, 1, 1, 1);
-					if( mat.blendDst == Zero )
-						mat.blend(SrcAlpha, OneMinusSrcAlpha);
-				}
-				mat.colorMul.w = o.alphas[frame];
+				if( mat.blendMode == Normal ) mat.blendMode = Alpha;
+				mat.color.w = o.alphas[frame];
 			} else if( o.targetSkin != null ) {
 			} else if( o.targetSkin != null ) {
 				o.targetSkin.currentRelPose[o.targetJoint] = o.frames[frame];
 				o.targetSkin.currentRelPose[o.targetJoint] = o.frames[frame];
 				o.targetSkin.jointsUpdated = true;
 				o.targetSkin.jointsUpdated = true;
@@ -84,5 +80,5 @@ class FrameAnimation extends Animation {
 				o.targetObject.defaultTransform = o.frames[frame];
 				o.targetObject.defaultTransform = o.frames[frame];
 		}
 		}
 	}
 	}
-	
+
 }
 }

+ 7 - 10
h3d/anim/LinearAnimation.hx

@@ -101,22 +101,19 @@ class LinearAnimation extends Animation {
 		for( o in getFrames() ) {
 		for( o in getFrames() ) {
 			if( o.alphas != null ) {
 			if( o.alphas != null ) {
 				var mat = o.targetObject.toMesh().material;
 				var mat = o.targetObject.toMesh().material;
-				if( mat.colorMul == null ) {
-					mat.colorMul = new Vector(1, 1, 1, 1);
-					if( mat.blendDst == Zero )
-						mat.blend(SrcAlpha, OneMinusSrcAlpha);
-				}
-				mat.colorMul.w = o.alphas[frame1] * k1 + o.alphas[frame2] * k2;
+				if( mat.blendMode == Normal ) mat.blendMode = Alpha;
+				mat.color.w = o.alphas[frame1] * k1 + o.alphas[frame2] * k2;
 				continue;
 				continue;
 			}
 			}
 			if( o.uvs != null ) {
 			if( o.uvs != null ) {
 				var mat = o.targetObject.toMesh().material;
 				var mat = o.targetObject.toMesh().material;
-				if( mat.uvDelta == null ) {
-					mat.uvDelta = new Vector();
+				var s = mat.mainPass.getShader(h3d.shader.UVScroll);
+				if( s == null ) {
+					s = mat.mainPass.addShader(new h3d.shader.UVScroll());
 					mat.texture.wrap = Repeat;
 					mat.texture.wrap = Repeat;
 				}
 				}
-				mat.uvDelta.x = o.uvs[frame1 << 1] * k1 + o.uvs[frame2 << 1] * k2;
-				mat.uvDelta.y = o.uvs[(frame1 << 1) | 1] * k1 + o.uvs[(frame2 << 1) | 1] * k2;
+				s.uvDelta.x = o.uvs[frame1 << 1] * k1 + o.uvs[frame2 << 1] * k2;
+				s.uvDelta.y = o.uvs[(frame1 << 1) | 1] * k1 + o.uvs[(frame2 << 1) | 1] * k2;
 				continue;
 				continue;
 			}
 			}
 			var f1 = o.frames[frame1], f2 = o.frames[frame2];
 			var f1 = o.frames[frame1], f2 = o.frames[frame2];

+ 5 - 5
h3d/anim/SimpleBlend.hx

@@ -1,14 +1,14 @@
 package h3d.anim;
 package h3d.anim;
 
 
 class SimpleBlend extends Transition {
 class SimpleBlend extends Transition {
-	
+
 	public var objectsMap : Map<String,Bool>;
 	public var objectsMap : Map<String,Bool>;
-	
+
 	public function new( anim1 : Animation, anim2 : Animation, objects : Map < String, Bool > ) {
 	public function new( anim1 : Animation, anim2 : Animation, objects : Map < String, Bool > ) {
 		super("blend", anim1, anim2);
 		super("blend", anim1, anim2);
 		this.objectsMap = objects;
 		this.objectsMap = objects;
 	}
 	}
-	
+
 	override function clone(?a : Animation) : Animation {
 	override function clone(?a : Animation) : Animation {
 		var a : SimpleBlend = cast a;
 		var a : SimpleBlend = cast a;
 		if( a == null )
 		if( a == null )
@@ -17,7 +17,7 @@ class SimpleBlend extends Transition {
 		a.objectsMap = objectsMap;
 		a.objectsMap = objectsMap;
 		return a;
 		return a;
 	}
 	}
-	
+
 	override function createInstance( base ) {
 	override function createInstance( base ) {
 		var a = new SimpleBlend(anim1, anim2, objectsMap);
 		var a = new SimpleBlend(anim1, anim2, objectsMap);
 		a.anim1 = anim1.createInstance(base);
 		a.anim1 = anim1.createInstance(base);
@@ -31,5 +31,5 @@ class SimpleBlend extends Transition {
 		a.isInstance = true;
 		a.isInstance = true;
 		return a;
 		return a;
 	}
 	}
-	
+
 }
 }

+ 16 - 16
h3d/anim/Skin.hx

@@ -10,12 +10,12 @@ class Joint {
 	public var transPos : h3d.Matrix; // inverse pose matrix
 	public var transPos : h3d.Matrix; // inverse pose matrix
 	public var parent : Joint;
 	public var parent : Joint;
 	public var subs : Array<Joint>;
 	public var subs : Array<Joint>;
-	
+
 	public function new() {
 	public function new() {
 		bindIndex = -1;
 		bindIndex = -1;
 		subs = [];
 		subs = [];
 	}
 	}
-	
+
 }
 }
 
 
 private class Influence {
 private class Influence {
@@ -28,7 +28,7 @@ private class Influence {
 }
 }
 
 
 class Skin {
 class Skin {
-	
+
 	public var vertexCount(default, null) : Int;
 	public var vertexCount(default, null) : Int;
 	public var bonesPerVertex(default,null) : Int;
 	public var bonesPerVertex(default,null) : Int;
 	public var vertexJoints : haxe.ds.Vector<Int>;
 	public var vertexJoints : haxe.ds.Vector<Int>;
@@ -38,13 +38,13 @@ class Skin {
 	public var allJoints(default,null) : Array<Joint>;
 	public var allJoints(default,null) : Array<Joint>;
 	public var boundJoints(default,null) : Array<Joint>;
 	public var boundJoints(default,null) : Array<Joint>;
 	public var primitive : h3d.prim.Primitive;
 	public var primitive : h3d.prim.Primitive;
-	
+
 	// spliting
 	// spliting
 	public var splitJoints(default, null) : Array<Array<Joint>>;
 	public var splitJoints(default, null) : Array<Array<Joint>>;
 	public var triangleGroups : haxe.ds.Vector<Int>;
 	public var triangleGroups : haxe.ds.Vector<Int>;
-	
+
 	var envelop : Array<Array<Influence>>;
 	var envelop : Array<Array<Influence>>;
-	
+
 	public function new( vertexCount, bonesPerVertex ) {
 	public function new( vertexCount, bonesPerVertex ) {
 		this.vertexCount = vertexCount;
 		this.vertexCount = vertexCount;
 		this.bonesPerVertex = bonesPerVertex;
 		this.bonesPerVertex = bonesPerVertex;
@@ -52,7 +52,7 @@ class Skin {
 		vertexWeights = new haxe.ds.Vector(vertexCount * bonesPerVertex);
 		vertexWeights = new haxe.ds.Vector(vertexCount * bonesPerVertex);
 		envelop = [];
 		envelop = [];
 	}
 	}
-	
+
 	public function setJoints( joints : Array<Joint>, roots : Array<Joint> ) {
 	public function setJoints( joints : Array<Joint>, roots : Array<Joint> ) {
 		rootJoints = roots;
 		rootJoints = roots;
 		allJoints = joints;
 		allJoints = joints;
@@ -61,7 +61,7 @@ class Skin {
 			if( j.name != null )
 			if( j.name != null )
 				namedJoints.set(j.name, j);
 				namedJoints.set(j.name, j);
 	}
 	}
-	
+
 	public inline function addInfluence( vid : Int, j : Joint, w : Float ) {
 	public inline function addInfluence( vid : Int, j : Joint, w : Float ) {
 		var il = envelop[vid];
 		var il = envelop[vid];
 		if( il == null )
 		if( il == null )
@@ -72,11 +72,11 @@ class Skin {
 	function sortInfluences( i1 : Influence, i2 : Influence ) {
 	function sortInfluences( i1 : Influence, i2 : Influence ) {
 		return i2.w > i1.w ? 1 : -1;
 		return i2.w > i1.w ? 1 : -1;
 	}
 	}
-	
+
 	public inline function isSplit() {
 	public inline function isSplit() {
 		return splitJoints != null;
 		return splitJoints != null;
 	}
 	}
-	
+
 	public function initWeights() {
 	public function initWeights() {
 		boundJoints = [];
 		boundJoints = [];
 		var pos = 0;
 		var pos = 0;
@@ -108,7 +108,7 @@ class Skin {
 		}
 		}
 		envelop = null;
 		envelop = null;
 	}
 	}
-	
+
 	public function split( maxBones : Int, index : Array<Int> ) {
 	public function split( maxBones : Int, index : Array<Int> ) {
 		if( isSplit() )
 		if( isSplit() )
 			return true;
 			return true;
@@ -117,7 +117,7 @@ class Skin {
 
 
 		splitJoints = [];
 		splitJoints = [];
 		triangleGroups = new haxe.ds.Vector(Std.int(index.length / 3));
 		triangleGroups = new haxe.ds.Vector(Std.int(index.length / 3));
-		
+
 		// collect joints groups used by triangles
 		// collect joints groups used by triangles
 		var curGroup = new Array<Joint>(), curJoints = [];
 		var curGroup = new Array<Joint>(), curJoints = [];
 		var ipos = 0, tpos = 0;
 		var ipos = 0, tpos = 0;
@@ -149,7 +149,7 @@ class Skin {
 				if( ipos == index.length ) break;
 				if( ipos == index.length ) break;
 			}
 			}
 		}
 		}
-		
+
 		// assign split indexes to joints
 		// assign split indexes to joints
 		var groups = [for( i in 0...splitJoints.length ) { id : i, reserved : [], joints : splitJoints[i] }];
 		var groups = [for( i in 0...splitJoints.length ) { id : i, reserved : [], joints : splitJoints[i] }];
 		var joints = [for( j in boundJoints ) { j : j, groups : [], index : -1 } ];
 		var joints = [for( j in boundJoints ) { j : j, groups : [], index : -1 } ];
@@ -189,13 +189,13 @@ class Skin {
 			}
 			}
 			splitJoints.push(jl);
 			splitJoints.push(jl);
 		}
 		}
-		
+
 		// rebind
 		// rebind
 		for( i in 0...vertexJoints.length )
 		for( i in 0...vertexJoints.length )
 			vertexJoints[i] = boundJoints[vertexJoints[i]].splitIndex;
 			vertexJoints[i] = boundJoints[vertexJoints[i]].splitIndex;
 
 
 		return true;
 		return true;
 	}
 	}
-	
-	
+
+
 }
 }

+ 8 - 8
h3d/anim/SmoothTransition.hx

@@ -12,17 +12,17 @@ class SmoothedObject extends Animation.AnimatedObject {
 }
 }
 
 
 class SmoothTransition extends Transition {
 class SmoothTransition extends Transition {
-	
+
 	static var MZERO = h3d.Matrix.L([
 	static var MZERO = h3d.Matrix.L([
 		1, 0, 0, 0,
 		1, 0, 0, 0,
 		0, 1, 1, 0,
 		0, 1, 1, 0,
 		0, 0, 1, 0,
 		0, 0, 1, 0,
 		0, 0, 0, 1,
 		0, 0, 0, 1,
 	]);
 	]);
-	
+
 	public var blendFactor : Float;
 	public var blendFactor : Float;
 	var tspeed : Float;
 	var tspeed : Float;
-	
+
 	public function new(current, target, speed) {
 	public function new(current, target, speed) {
 		super("smooth", current, target);
 		super("smooth", current, target);
 		blendFactor = 0.;
 		blendFactor = 0.;
@@ -32,7 +32,7 @@ class SmoothTransition extends Transition {
 		this.isInstance = true;
 		this.isInstance = true;
 		initObjects();
 		initObjects();
 	}
 	}
-	
+
 	function initObjects() {
 	function initObjects() {
 		var allObjects = new Map();
 		var allObjects = new Map();
 		var mzero = MZERO;
 		var mzero = MZERO;
@@ -59,13 +59,13 @@ class SmoothTransition extends Transition {
 			so.isAnim2 = true;
 			so.isAnim2 = true;
 		}
 		}
 	}
 	}
-	
+
 	override function bind( base ) {
 	override function bind( base ) {
 		super.bind(base);
 		super.bind(base);
 		this.objects = [];
 		this.objects = [];
 		initObjects();
 		initObjects();
 	}
 	}
-	
+
 	@:access(h3d.scene.Skin)
 	@:access(h3d.scene.Skin)
 	override function sync( decompose = false ) {
 	override function sync( decompose = false ) {
 		if( decompose ) throw "assert";
 		if( decompose ) throw "assert";
@@ -112,7 +112,7 @@ class SmoothTransition extends Transition {
 			if( o.targetSkin != null ) o.targetSkin.currentRelPose[o.targetJoint] = m else o.targetObject.defaultTransform = m;
 			if( o.targetSkin != null ) o.targetSkin.currentRelPose[o.targetJoint] = m else o.targetObject.defaultTransform = m;
 		}
 		}
 	}
 	}
-	
+
 	override function update( dt : Float ) : Float {
 	override function update( dt : Float ) : Float {
 		var rt = super.update(dt);
 		var rt = super.update(dt);
 		var st = dt - rt;
 		var st = dt - rt;
@@ -123,5 +123,5 @@ class SmoothTransition extends Transition {
 		}
 		}
 		return rt;
 		return rt;
 	}
 	}
-	
+
 }
 }

+ 8 - 8
h3d/anim/Transition.hx

@@ -1,10 +1,10 @@
 package h3d.anim;
 package h3d.anim;
 
 
 class Transition extends Animation {
 class Transition extends Animation {
-	
+
 	public var anim1 : Animation;
 	public var anim1 : Animation;
 	public var anim2 : Animation;
 	public var anim2 : Animation;
-	
+
 	public function new( transitionName : String, anim1 : Animation, anim2 : Animation ) {
 	public function new( transitionName : String, anim1 : Animation, anim2 : Animation ) {
 		var r1 = 1, r2 = 1;
 		var r1 = 1, r2 = 1;
 		while( true ) {
 		while( true ) {
@@ -16,13 +16,13 @@ class Transition extends Animation {
 		this.anim1 = anim1;
 		this.anim1 = anim1;
 		this.anim2 = anim2;
 		this.anim2 = anim2;
 	}
 	}
-	
+
 	override function setFrame( f : Float ) {
 	override function setFrame( f : Float ) {
 		super.setFrame(f);
 		super.setFrame(f);
 		anim1.setFrame(frame % anim1.frameCount);
 		anim1.setFrame(frame % anim1.frameCount);
 		anim2.setFrame(frame % anim2.frameCount);
 		anim2.setFrame(frame % anim2.frameCount);
 	}
 	}
-	
+
 	override function clone(?a : Animation) : Animation {
 	override function clone(?a : Animation) : Animation {
 		var a : Transition = cast a;
 		var a : Transition = cast a;
 		if( a == null )
 		if( a == null )
@@ -32,19 +32,19 @@ class Transition extends Animation {
 		a.anim2 = anim2.clone();
 		a.anim2 = anim2.clone();
 		return a;
 		return a;
 	}
 	}
-	
+
 	override function sync( decompose : Bool = false ) {
 	override function sync( decompose : Bool = false ) {
 		if( decompose )
 		if( decompose )
 			throw "Decompose not supported on transition";
 			throw "Decompose not supported on transition";
 		anim1.sync();
 		anim1.sync();
 		anim2.sync();
 		anim2.sync();
 	}
 	}
-	
+
 	override function bind(base) {
 	override function bind(base) {
 		anim1.bind(base);
 		anim1.bind(base);
 		anim2.bind(base);
 		anim2.bind(base);
 	}
 	}
-	
+
 	override function update(dt:Float) {
 	override function update(dt:Float) {
 		var rt = super.update(dt);
 		var rt = super.update(dt);
 		var st = dt - rt;
 		var st = dt - rt;
@@ -56,5 +56,5 @@ class Transition extends Animation {
 			tmp = anim2.update(tmp);
 			tmp = anim2.update(tmp);
 		return rt;
 		return rt;
 	}
 	}
-	
+
 }
 }

+ 26 - 26
h3d/col/Bounds.hx

@@ -2,18 +2,18 @@ package h3d.col;
 import hxd.Math;
 import hxd.Math;
 
 
 class Bounds {
 class Bounds {
-	
+
 	public var xMin : Float;
 	public var xMin : Float;
 	public var xMax : Float;
 	public var xMax : Float;
 	public var yMin : Float;
 	public var yMin : Float;
 	public var yMax : Float;
 	public var yMax : Float;
 	public var zMin : Float;
 	public var zMin : Float;
 	public var zMax : Float;
 	public var zMax : Float;
-	
+
 	public inline function new() {
 	public inline function new() {
 		empty();
 		empty();
 	}
 	}
-	
+
 	public function inFrustum( mvp : Matrix ) {
 	public function inFrustum( mvp : Matrix ) {
 		if( testPlane(Plane.frustumLeft(mvp)) < 0 )
 		if( testPlane(Plane.frustumLeft(mvp)) < 0 )
 			return false;
 			return false;
@@ -29,7 +29,7 @@ class Bounds {
 			return false;
 			return false;
 		return true;
 		return true;
 	}
 	}
-	
+
 	inline function testPlane( p : Plane ) {
 	inline function testPlane( p : Plane ) {
 		var a = p.nx;
 		var a = p.nx;
 		var b = p.ny;
 		var b = p.ny;
@@ -41,7 +41,7 @@ class Bounds {
 		var rr = a * (xMax - xMin) + b * (yMax - yMin) + c * (zMax - zMin);
 		var rr = a * (xMax - xMin) + b * (yMax - yMin) + c * (zMax - zMin);
 		return dd + rr - p.d*2;
 		return dd + rr - p.d*2;
 	}
 	}
-	
+
 	/**
 	/**
 	 * Check if the camera model-view-projection Matrix intersects with the Bounds. Returns -1 if outside, 0 if interests and 1 if fully inside.
 	 * Check if the camera model-view-projection Matrix intersects with the Bounds. Returns -1 if outside, 0 if interests and 1 if fully inside.
 	 * @param	mvp : the model-view-projection matrix to test against
 	 * @param	mvp : the model-view-projection matrix to test against
@@ -49,7 +49,7 @@ class Bounds {
 	 */
 	 */
 	public function inFrustumDetails( mvp : Matrix, checkZ = true ) {
 	public function inFrustumDetails( mvp : Matrix, checkZ = true ) {
 		var ret = 1;
 		var ret = 1;
-		
+
 		// left
 		// left
 		var p = new Plane(mvp._14 + mvp._11, mvp._24 + mvp._21 , mvp._34 + mvp._31, mvp._44 + mvp._41);
 		var p = new Plane(mvp._14 + mvp._11, mvp._24 + mvp._21 , mvp._34 + mvp._31, mvp._44 + mvp._41);
 		var m = p.nx * (p.nx > 0 ? xMax : xMin) + p.ny * (p.ny > 0 ? yMax : yMin) + p.nz * (p.nz > 0 ? zMax : zMin);
 		var m = p.nx * (p.nx > 0 ? xMax : xMin) + p.ny * (p.ny > 0 ? yMax : yMin) + p.nz * (p.nz > 0 ? zMax : zMin);
@@ -71,7 +71,7 @@ class Bounds {
 			return -1;
 			return -1;
 		var n = p.nx * (p.nx > 0 ? xMin : xMax) + p.ny * (p.ny > 0 ? yMin : yMax) + p.nz * (p.nz > 0 ? zMin : zMax);
 		var n = p.nx * (p.nx > 0 ? xMin : xMax) + p.ny * (p.ny > 0 ? yMin : yMax) + p.nz * (p.nz > 0 ? zMin : zMax);
 		if( n + p.d < 0 ) ret = 0;
 		if( n + p.d < 0 ) ret = 0;
-		
+
 		// top
 		// top
 		var p = new Plane(mvp._14 - mvp._12, mvp._24 - mvp._22 , mvp._34 - mvp._32, mvp._44 - mvp._42);
 		var p = new Plane(mvp._14 - mvp._12, mvp._24 - mvp._22 , mvp._34 - mvp._32, mvp._44 - mvp._42);
 		var m = p.nx * (p.nx > 0 ? xMax : xMin) + p.ny * (p.ny > 0 ? yMax : yMin) + p.nz * (p.nz > 0 ? zMax : zMin);
 		var m = p.nx * (p.nx > 0 ? xMax : xMin) + p.ny * (p.ny > 0 ? yMax : yMin) + p.nz * (p.nz > 0 ? zMax : zMin);
@@ -79,7 +79,7 @@ class Bounds {
 			return -1;
 			return -1;
 		var n = p.nx * (p.nx > 0 ? xMin : xMax) + p.ny * (p.ny > 0 ? yMin : yMax) + p.nz * (p.nz > 0 ? zMin : zMax);
 		var n = p.nx * (p.nx > 0 ? xMin : xMax) + p.ny * (p.ny > 0 ? yMin : yMax) + p.nz * (p.nz > 0 ? zMin : zMax);
 		if( n + p.d < 0 ) ret = 0;
 		if( n + p.d < 0 ) ret = 0;
-				
+
 		if( checkZ ) {
 		if( checkZ ) {
 			// nea
 			// nea
 			var p = new Plane(mvp._13, mvp._23, mvp._33, mvp._43);
 			var p = new Plane(mvp._13, mvp._23, mvp._33, mvp._43);
@@ -96,10 +96,10 @@ class Bounds {
 			var n = p.nx * (p.nx > 0 ? xMin : xMax) + p.ny * (p.ny > 0 ? yMin : yMax) + p.nz * (p.nz > 0 ? zMin : zMax);
 			var n = p.nx * (p.nx > 0 ? xMin : xMax) + p.ny * (p.ny > 0 ? yMin : yMax) + p.nz * (p.nz > 0 ? zMin : zMax);
 			if( n + p.d < 0 ) ret = 0;
 			if( n + p.d < 0 ) ret = 0;
 		}
 		}
-		
+
 		return ret;
 		return ret;
 	}
 	}
-	
+
 	public function transform3x4( m : Matrix ) {
 	public function transform3x4( m : Matrix ) {
 		var xMin = xMin, yMin = yMin, zMin = zMin, xMax = xMax, yMax = yMax, zMax = zMax;
 		var xMin = xMin, yMin = yMin, zMin = zMin, xMax = xMax, yMax = yMax, zMax = zMax;
 		empty();
 		empty();
@@ -129,15 +129,15 @@ class Bounds {
 		v.transform(m);
 		v.transform(m);
 		addPoint(v);
 		addPoint(v);
 	}
 	}
-	
+
 	public inline function collide( b : Bounds ) {
 	public inline function collide( b : Bounds ) {
 		return !(xMin > b.xMax || yMin > b.yMax || zMin > b.zMax || xMax < b.xMin || yMax < b.yMin || zMax < b.zMin);
 		return !(xMin > b.xMax || yMin > b.yMax || zMin > b.zMax || xMax < b.xMin || yMax < b.yMin || zMax < b.zMin);
 	}
 	}
-	
+
 	public inline function include( p : Point ) {
 	public inline function include( p : Point ) {
 		return p.x >= xMin && p.x < xMax && p.y >= yMin && p.y < yMax && p.z >= zMin && p.z < zMax;
 		return p.x >= xMin && p.x < xMax && p.y >= yMin && p.y < yMax && p.z >= zMin && p.z < zMax;
 	}
 	}
-	
+
 	public inline function add( b : Bounds ) {
 	public inline function add( b : Bounds ) {
 		if( b.xMin < xMin ) xMin = b.xMin;
 		if( b.xMin < xMin ) xMin = b.xMin;
 		if( b.xMax > xMax ) xMax = b.xMax;
 		if( b.xMax > xMax ) xMax = b.xMax;
@@ -164,7 +164,7 @@ class Bounds {
 		if( z < zMin ) zMin = z;
 		if( z < zMin ) zMin = z;
 		if( z > zMax ) zMax = z;
 		if( z > zMax ) zMax = z;
 	}
 	}
-	
+
 	public function intersection( a : Bounds, b : Bounds ) {
 	public function intersection( a : Bounds, b : Bounds ) {
 		var xMin = Math.max(a.xMin, b.xMin);
 		var xMin = Math.max(a.xMin, b.xMin);
 		var yMin = Math.max(a.yMin, b.yMin);
 		var yMin = Math.max(a.yMin, b.yMin);
@@ -179,7 +179,7 @@ class Bounds {
 		this.zMin = zMin;
 		this.zMin = zMin;
 		this.zMax = zMax;
 		this.zMax = zMax;
 	}
 	}
-	
+
 	public inline function offset( dx : Float, dy : Float, dz : Float ) {
 	public inline function offset( dx : Float, dy : Float, dz : Float ) {
 		xMin += dx;
 		xMin += dx;
 		xMax += dx;
 		xMax += dx;
@@ -188,7 +188,7 @@ class Bounds {
 		zMin += dz;
 		zMin += dz;
 		zMax += dz;
 		zMax += dz;
 	}
 	}
-	
+
 	public inline function setMin( p : Point ) {
 	public inline function setMin( p : Point ) {
 		xMin = p.x;
 		xMin = p.x;
 		yMin = p.y;
 		yMin = p.y;
@@ -200,7 +200,7 @@ class Bounds {
 		yMax = p.y;
 		yMax = p.y;
 		zMax = p.z;
 		zMax = p.z;
 	}
 	}
-	
+
 	public function load( b : Bounds ) {
 	public function load( b : Bounds ) {
 		xMin = b.xMin;
 		xMin = b.xMin;
 		xMax = b.xMax;
 		xMax = b.xMax;
@@ -209,7 +209,7 @@ class Bounds {
 		zMin = b.zMin;
 		zMin = b.zMin;
 		zMax = b.zMax;
 		zMax = b.zMax;
 	}
 	}
-	
+
 	public function scaleCenter( v : Float ) {
 	public function scaleCenter( v : Float ) {
 		var dx = (xMax - xMin) * 0.5 * v;
 		var dx = (xMax - xMin) * 0.5 * v;
 		var dy = (yMax - yMin) * 0.5 * v;
 		var dy = (yMax - yMin) * 0.5 * v;
@@ -224,11 +224,11 @@ class Bounds {
 		yMax = my + dy;
 		yMax = my + dy;
 		zMax = mz + dz;
 		zMax = mz + dz;
 	}
 	}
-	
+
 	public inline function getMin() {
 	public inline function getMin() {
 		return new Point(xMin, yMin, zMin);
 		return new Point(xMin, yMin, zMin);
 	}
 	}
-	
+
 	public inline function getCenter() {
 	public inline function getCenter() {
 		return new Point((xMin + xMax) * 0.5, (yMin + yMax) * 0.5, (zMin + zMax) * 0.5);
 		return new Point((xMin + xMax) * 0.5, (yMin + yMax) * 0.5, (zMin + zMax) * 0.5);
 	}
 	}
@@ -236,11 +236,11 @@ class Bounds {
 	public inline function getSize() {
 	public inline function getSize() {
 		return new Point(xMax - xMin, yMax - yMin, zMax - zMin);
 		return new Point(xMax - xMin, yMax - yMin, zMax - zMin);
 	}
 	}
-	
+
 	public inline function getMax() {
 	public inline function getMax() {
 		return new Point(xMax, yMax, zMax);
 		return new Point(xMax, yMax, zMax);
 	}
 	}
-	
+
 	public inline function empty() {
 	public inline function empty() {
 		xMin = 1e20;
 		xMin = 1e20;
 		xMax = -1e20;
 		xMax = -1e20;
@@ -258,7 +258,7 @@ class Bounds {
 		zMin = -1e20;
 		zMin = -1e20;
 		zMax = 1e20;
 		zMax = 1e20;
 	}
 	}
-	
+
 	public inline function clone() {
 	public inline function clone() {
 		var b = new Bounds();
 		var b = new Bounds();
 		b.xMin = xMin;
 		b.xMin = xMin;
@@ -269,11 +269,11 @@ class Bounds {
 		b.zMax = zMax;
 		b.zMax = zMax;
 		return b;
 		return b;
 	}
 	}
-	
+
 	public function toString() {
 	public function toString() {
 		return "{" + getMin() + "," + getMax() + "}";
 		return "{" + getMin() + "," + getMax() + "}";
 	}
 	}
-	
+
 	public static inline function fromPoints( min : Point, max : Point ) {
 	public static inline function fromPoints( min : Point, max : Point ) {
 		var b = new Bounds();
 		var b = new Bounds();
 		b.setMin(min);
 		b.setMin(min);
@@ -291,5 +291,5 @@ class Bounds {
 		b.zMax = z + dz;
 		b.zMax = z + dz;
 		return b;
 		return b;
 	}
 	}
-	
+
 }
 }

+ 17 - 17
h3d/col/Plane.hx

@@ -3,31 +3,31 @@ import hxd.Math;
 
 
 @:allow(h3d.col)
 @:allow(h3d.col)
 class Plane {
 class Plane {
-	
+
 	// Place equation :  nx.X + ny.Y + nz.Z - d = 0
 	// Place equation :  nx.X + ny.Y + nz.Z - d = 0
 	var nx : Float;
 	var nx : Float;
 	var ny : Float;
 	var ny : Float;
 	var nz : Float;
 	var nz : Float;
 	var d : Float;
 	var d : Float;
-	
+
 	inline function new(nx, ny, nz, d) {
 	inline function new(nx, ny, nz, d) {
 		this.nx = nx;
 		this.nx = nx;
 		this.ny = ny;
 		this.ny = ny;
 		this.nz = nz;
 		this.nz = nz;
 		this.d = d;
 		this.d = d;
 	}
 	}
-	
+
 	/**
 	/**
 		Returns the plan normal
 		Returns the plan normal
 	**/
 	**/
 	public inline function getNormal() {
 	public inline function getNormal() {
 		return new Point(nx, ny, nz);
 		return new Point(nx, ny, nz);
 	}
 	}
-	
+
 	public inline function getNormalDistance() {
 	public inline function getNormalDistance() {
 		return d;
 		return d;
 	}
 	}
-	
+
 	/**
 	/**
 		Normalize the plan, so we can use distance().
 		Normalize the plan, so we can use distance().
 	**/
 	**/
@@ -38,22 +38,22 @@ class Plane {
 		nz *= len;
 		nz *= len;
 		d *= len;
 		d *= len;
 	}
 	}
-	
+
 	public function toString() {
 	public function toString() {
 		return "{" + getNormal()+","+ d + "}";
 		return "{" + getNormal()+","+ d + "}";
 	}
 	}
-	
+
 	/**
 	/**
 		Returns the signed distance between a point an the plane. This requires the plan to be normalized. If the distance is negative it means that we are "under" the plan.
 		Returns the signed distance between a point an the plane. This requires the plan to be normalized. If the distance is negative it means that we are "under" the plan.
 	**/
 	**/
 	public inline function distance( p : Point ) {
 	public inline function distance( p : Point ) {
 		return nx * p.x + ny * p.y + nz * p.z - d;
 		return nx * p.x + ny * p.y + nz * p.z - d;
 	}
 	}
-	
+
 	public inline function side( p : Point ) {
 	public inline function side( p : Point ) {
 		return distance(p) >= 0;
 		return distance(p) >= 0;
 	}
 	}
-	
+
 	public inline function project( p : Point ) : Point {
 	public inline function project( p : Point ) : Point {
 		var d = distance(p);
 		var d = distance(p);
 		return new Point(p.x - d * nx, p.y - d * ny, p.z - d * nz);
 		return new Point(p.x - d * nx, p.y - d * ny, p.z - d * nz);
@@ -65,22 +65,22 @@ class Plane {
 		out.y = p.y - d * ny;
 		out.y = p.y - d * ny;
 		out.z = p.z - d * nz;
 		out.z = p.z - d * nz;
 	}
 	}
-	
+
 	public static inline function fromPoints( p0 : Point, p1 : Point, p2 : Point ) {
 	public static inline function fromPoints( p0 : Point, p1 : Point, p2 : Point ) {
 		var d1 = p1.sub(p0);
 		var d1 = p1.sub(p0);
 		var d2 = p2.sub(p0);
 		var d2 = p2.sub(p0);
 		var n = d1.cross(d2);
 		var n = d1.cross(d2);
 		return new Plane(n.x,n.y,n.z,n.dot(p0));
 		return new Plane(n.x,n.y,n.z,n.dot(p0));
 	}
 	}
-	
+
 	public static inline function fromNormalPoint( n : Point, p : Point ) {
 	public static inline function fromNormalPoint( n : Point, p : Point ) {
 		return new Plane(n.x,n.y,n.z,n.dot(p));
 		return new Plane(n.x,n.y,n.z,n.dot(p));
 	}
 	}
-	
+
 	public static inline function X(v:Float) {
 	public static inline function X(v:Float) {
 		return new Plane( 1, 0, 0, v );
 		return new Plane( 1, 0, 0, v );
 	}
 	}
-	
+
 	public static inline function Y(v:Float) {
 	public static inline function Y(v:Float) {
 		return new Plane( 0, 1, 0, v );
 		return new Plane( 0, 1, 0, v );
 	}
 	}
@@ -88,7 +88,7 @@ class Plane {
 	public static inline function Z(v:Float) {
 	public static inline function Z(v:Float) {
 		return new Plane( 0, 0, 1, v );
 		return new Plane( 0, 0, 1, v );
 	}
 	}
-	
+
 	public static inline function frustumLeft( mvp : Matrix ) {
 	public static inline function frustumLeft( mvp : Matrix ) {
 		return new Plane(mvp._14 + mvp._11, mvp._24 + mvp._21 , mvp._34 + mvp._31, -(mvp._44 + mvp._41));
 		return new Plane(mvp._14 + mvp._11, mvp._24 + mvp._21 , mvp._34 + mvp._31, -(mvp._44 + mvp._41));
 	}
 	}
@@ -96,7 +96,7 @@ class Plane {
 	public static inline function frustumRight( mvp : Matrix ) {
 	public static inline function frustumRight( mvp : Matrix ) {
 		return new Plane(mvp._14 - mvp._11, mvp._24 - mvp._21 , mvp._34 - mvp._31, mvp._41 - mvp._44);
 		return new Plane(mvp._14 - mvp._11, mvp._24 - mvp._21 , mvp._34 - mvp._31, mvp._41 - mvp._44);
 	}
 	}
-	
+
 	public static inline function frustumBottom( mvp : Matrix ) {
 	public static inline function frustumBottom( mvp : Matrix ) {
 		return new Plane(mvp._14 + mvp._12, mvp._24 + mvp._22 , mvp._34 + mvp._32, -(mvp._44 + mvp._42));
 		return new Plane(mvp._14 + mvp._12, mvp._24 + mvp._22 , mvp._34 + mvp._32, -(mvp._44 + mvp._42));
 	}
 	}
@@ -104,7 +104,7 @@ class Plane {
 	public static inline function frustumTop( mvp : Matrix ) {
 	public static inline function frustumTop( mvp : Matrix ) {
 		return new Plane(mvp._14 - mvp._12, mvp._24 - mvp._22 , mvp._34 - mvp._32, mvp._42 - mvp._44);
 		return new Plane(mvp._14 - mvp._12, mvp._24 - mvp._22 , mvp._34 - mvp._32, mvp._42 - mvp._44);
 	}
 	}
-	
+
 	public static inline function frustumNear( mvp : Matrix ) {
 	public static inline function frustumNear( mvp : Matrix ) {
 		return new Plane(mvp._13, mvp._23, mvp._33, -mvp._43);
 		return new Plane(mvp._13, mvp._23, mvp._33, -mvp._43);
 	}
 	}
@@ -112,5 +112,5 @@ class Plane {
 	public static inline function frustumFar( mvp : Matrix ) {
 	public static inline function frustumFar( mvp : Matrix ) {
 		return new Plane(mvp._14 - mvp._13, mvp._24 - mvp._23, mvp._34 - mvp._33, mvp._43 - mvp._44);
 		return new Plane(mvp._14 - mvp._13, mvp._24 - mvp._23, mvp._34 - mvp._33, mvp._43 - mvp._44);
 	}
 	}
-	
+
 }
 }

+ 12 - 12
h3d/col/Point.hx

@@ -6,13 +6,13 @@ class Point {
 	public var x : Float;
 	public var x : Float;
 	public var y : Float;
 	public var y : Float;
 	public var z : Float;
 	public var z : Float;
-	
+
 	public inline function new(x=0.,y=0.,z=0.) {
 	public inline function new(x=0.,y=0.,z=0.) {
 		this.x = x;
 		this.x = x;
 		this.y = y;
 		this.y = y;
 		this.z = z;
 		this.z = z;
 	}
 	}
-	
+
 	public function inFrustum( mvp : Matrix ) {
 	public function inFrustum( mvp : Matrix ) {
 		if( !Plane.frustumLeft(mvp).side(this) )
 		if( !Plane.frustumLeft(mvp).side(this) )
 			return false;
 			return false;
@@ -28,13 +28,13 @@ class Point {
 			return false;
 			return false;
 		return true;
 		return true;
 	}
 	}
-	
+
 	public inline function set(x, y, z) {
 	public inline function set(x, y, z) {
 		this.x = x;
 		this.x = x;
 		this.y = y;
 		this.y = y;
 		this.z = z;
 		this.z = z;
 	}
 	}
-	
+
 	public inline function sub( p : Point ) {
 	public inline function sub( p : Point ) {
 		return new Point(x - p.x, y - p.y, z - p.z);
 		return new Point(x - p.x, y - p.y, z - p.z);
 	}
 	}
@@ -42,15 +42,15 @@ class Point {
 	public inline function add( p : Point ) {
 	public inline function add( p : Point ) {
 		return new Point(x + p.x, y + p.y, z + p.z);
 		return new Point(x + p.x, y + p.y, z + p.z);
 	}
 	}
-	
+
 	public inline function cross( p : Point ) {
 	public inline function cross( p : Point ) {
 		return new Point(y * p.z - z * p.y, z * p.x - x * p.z,  x * p.y - y * p.x);
 		return new Point(y * p.z - z * p.y, z * p.x - x * p.z,  x * p.y - y * p.x);
 	}
 	}
-	
+
 	public inline function lengthSq() {
 	public inline function lengthSq() {
 		return x * x + y * y + z * z;
 		return x * x + y * y + z * z;
 	}
 	}
-	
+
 	public inline function length() {
 	public inline function length() {
 		return lengthSq().sqrt();
 		return lengthSq().sqrt();
 	}
 	}
@@ -58,7 +58,7 @@ class Point {
 	public inline function dot( p : Point ) {
 	public inline function dot( p : Point ) {
 		return x * p.x + y * p.y + z * p.z;
 		return x * p.x + y * p.y + z * p.z;
 	}
 	}
-	
+
 	public inline function distanceSq( p : Point ) {
 	public inline function distanceSq( p : Point ) {
 		var dx = p.x - x;
 		var dx = p.x - x;
 		var dy = p.y - y;
 		var dy = p.y - y;
@@ -70,7 +70,7 @@ class Point {
 		return distanceSq(p).sqrt();
 		return distanceSq(p).sqrt();
 	}
 	}
 
 
-	
+
 	public function normalize() {
 	public function normalize() {
 		var k = x * x + y * y + z * z;
 		var k = x * x + y * y + z * z;
 		if( k < hxd.Math.EPSILON ) k = 0 else k = k.invSqrt();
 		if( k < hxd.Math.EPSILON ) k = 0 else k = k.invSqrt();
@@ -78,7 +78,7 @@ class Point {
 		y *= k;
 		y *= k;
 		z *= k;
 		z *= k;
 	}
 	}
-	
+
 	public inline function transform( m : Matrix ) {
 	public inline function transform( m : Matrix ) {
 		var px = x * m._11 + y * m._21 + z * m._31 + m._41;
 		var px = x * m._11 + y * m._21 + z * m._31 + m._41;
 		var py = x * m._12 + y * m._22 + z * m._32 + m._42;
 		var py = x * m._12 + y * m._22 + z * m._32 + m._42;
@@ -87,7 +87,7 @@ class Point {
 		y = py;
 		y = py;
 		z = pz;
 		z = pz;
 	}
 	}
-	
+
 	public inline function toVector() {
 	public inline function toVector() {
 		return new Vector(x, y, z);
 		return new Vector(x, y, z);
 	}
 	}
@@ -99,5 +99,5 @@ class Point {
 	public function toString() {
 	public function toString() {
 		return '{${x.fmt()},${y.fmt()},${z.fmt()}}';
 		return '{${x.fmt()},${y.fmt()},${z.fmt()}}';
 	}
 	}
-	
+
 }
 }

+ 10 - 10
h3d/col/Ray.hx

@@ -3,17 +3,17 @@ import hxd.Math;
 
 
 @:allow(h3d.col)
 @:allow(h3d.col)
 class Ray {
 class Ray {
-	
+
 	var px : Float;
 	var px : Float;
 	var py : Float;
 	var py : Float;
 	var pz : Float;
 	var pz : Float;
 	var lx : Float;
 	var lx : Float;
 	var ly : Float;
 	var ly : Float;
 	var lz : Float;
 	var lz : Float;
-	
+
 	inline function new() {
 	inline function new() {
 	}
 	}
-	
+
 	public function normalize() {
 	public function normalize() {
 		var l = lx * lx + ly * ly + lz * lz;
 		var l = lx * lx + ly * ly + lz * lz;
 		if( l < Math.EPSILON ) l = 0 else l = Math.invSqrt(l);
 		if( l < Math.EPSILON ) l = 0 else l = Math.invSqrt(l);
@@ -21,7 +21,7 @@ class Ray {
 		ly *= l;
 		ly *= l;
 		lz *= l;
 		lz *= l;
 	}
 	}
-	
+
 	public inline function getPos() {
 	public inline function getPos() {
 		return new Point(px, py, pz);
 		return new Point(px, py, pz);
 	}
 	}
@@ -29,11 +29,11 @@ class Ray {
 	public inline function getDir() {
 	public inline function getDir() {
 		return new Point(lx, ly, lz);
 		return new Point(lx, ly, lz);
 	}
 	}
-	
+
 	public function toString() {
 	public function toString() {
 		return "{" + getPos() + "," + getDir() + "}";
 		return "{" + getPos() + "," + getDir() + "}";
 	}
 	}
-	
+
 	public inline function intersect( p : Plane ) : Null<Point> {
 	public inline function intersect( p : Plane ) : Null<Point> {
 		var d = lx * p.nx + ly * p.ny + lz * p.nz;
 		var d = lx * p.nx + ly * p.ny + lz * p.nz;
 		var nd = p.d - (px * p.nx + py * p.ny + pz * p.nz);
 		var nd = p.d - (px * p.nx + py * p.ny + pz * p.nz);
@@ -45,7 +45,7 @@ class Ray {
 			return new Point(px + lx * k, py + ly * k, pz + lz * k);
 			return new Point(px + lx * k, py + ly * k, pz + lz * k);
 		}
 		}
 	}
 	}
-	
+
 	public inline function collideFrustum( mvp : Matrix ) {
 	public inline function collideFrustum( mvp : Matrix ) {
 		// transform the two ray points into the normalized frustum box
 		// transform the two ray points into the normalized frustum box
 		var a = new h3d.Vector(px, py, pz);
 		var a = new h3d.Vector(px, py, pz);
@@ -56,7 +56,7 @@ class Ray {
 		var lx = b.x - a.x;
 		var lx = b.x - a.x;
 		var ly = b.y - a.y;
 		var ly = b.y - a.y;
 		var lz = b.z - a.z;
 		var lz = b.z - a.z;
-		
+
 		var dx = 1 / lx;
 		var dx = 1 / lx;
 		var dy = 1 / ly;
 		var dy = 1 / ly;
 		var dz = 1 / lz;
 		var dz = 1 / lz;
@@ -94,7 +94,7 @@ class Ray {
 			return true;
 			return true;
 		}
 		}
 	}
 	}
-	
+
 	public static inline function fromPoints( p1 : Point, p2 : Point ) {
 	public static inline function fromPoints( p1 : Point, p2 : Point ) {
 		var r = new Ray();
 		var r = new Ray();
 		r.px = p1.x;
 		r.px = p1.x;
@@ -116,5 +116,5 @@ class Ray {
 		r.lz = dz;
 		r.lz = dz;
 		return r;
 		return r;
 	}
 	}
-	
+
 }
 }

+ 5 - 5
h3d/col/Seg.hx

@@ -2,17 +2,17 @@ package h3d.col;
 import hxd.Math;
 import hxd.Math;
 
 
 class Seg {
 class Seg {
-	
+
 	public var p1 : Point;
 	public var p1 : Point;
 	public var p2 : Point;
 	public var p2 : Point;
 	public var lenSq : Float;
 	public var lenSq : Float;
-	
+
 	public inline function new( p1 : Point, p2 : Point ) {
 	public inline function new( p1 : Point, p2 : Point ) {
 		this.p1 = p1;
 		this.p1 = p1;
 		this.p2 = p2;
 		this.p2 = p2;
 		lenSq = p1.distanceSq(p2);
 		lenSq = p1.distanceSq(p2);
 	}
 	}
-	
+
 	public inline function distanceSq( p : Point ) {
 	public inline function distanceSq( p : Point ) {
 		var t = p.sub(p1).dot(p2.sub(p1)) / lenSq;
 		var t = p.sub(p1).dot(p2.sub(p1)) / lenSq;
 		return if( t < 0 )
 		return if( t < 0 )
@@ -22,9 +22,9 @@ class Seg {
 		} else
 		} else
 			p.distanceSq(new Point(p1.x + t * (p2.x - p1.x), p1.y + t * (p2.y - p1.y)));
 			p.distanceSq(new Point(p1.x + t * (p2.x - p1.x), p1.y + t * (p2.y - p1.y)));
 	}
 	}
-	
+
 	public inline function distance( p : Point ) {
 	public inline function distance( p : Point ) {
 		return Math.sqrt(distanceSq(p));
 		return Math.sqrt(distanceSq(p));
 	}
 	}
-	
+
 }
 }

+ 77 - 69
h3d/impl/Driver.hx

@@ -1,107 +1,115 @@
 package h3d.impl;
 package h3d.impl;
 
 
-#if (flash&&!cpp&&!js)
-	typedef IndexBuffer = flash.display3D.IndexBuffer3D;
-	typedef VertexBuffer = Stage3dDriver.VertexWrapper;
-	typedef Texture = flash.display3D.textures.TextureBase;
+#if flash
+typedef IndexBuffer = flash.display3D.IndexBuffer3D;
+typedef VertexBuffer = Stage3dDriver.VertexWrapper;
+typedef Texture = flash.display3D.textures.TextureBase;
 #elseif js
 #elseif js
-	typedef IndexBuffer = js.html.webgl.Buffer;
-	@:publicFields
-	class GLVB {
-		var b : js.html.webgl.Buffer;
-		var stride : Int;
-		public function new(b = null, s = 0) { this.b = b; this.stride = s; };
-	}
-	typedef VertexBuffer = GLVB;
-	typedef Texture = js.html.webgl.Texture;
+typedef IndexBuffer = js.html.webgl.Buffer;
+typedef VertexBuffer = { b : js.html.webgl.Buffer, stride : Int };
+typedef Texture = { t : js.html.webgl.Texture, width : Int, height : Int, fmt : Int, ?fb : js.html.webgl.Framebuffer, ?rb : js.html.webgl.Renderbuffer };
 #elseif cpp
 #elseif cpp
-	typedef IndexBuffer = openfl.gl.GLBuffer;
-	@:publicFields
-	class GLVB {
-		var b : openfl.gl.GLBuffer;
-		var stride : Int;
-		public function new(b = null, s = 0) { this.b = b; this.stride = s; };
-	}
-	typedef VertexBuffer = GLVB;
-	typedef Texture = openfl.gl.GLTexture;
+typedef IndexBuffer = openfl.gl.GLBuffer;
+typedef VertexBuffer = { b : openfl.gl.GLBuffer, stride : Int };
+typedef Texture = { t : openfl.gl.GLTexture };
 #else
 #else
-	typedef IndexBuffer = Int;
-	typedef VertexBuffer = Int;
-	typedef Texture = Int;
+typedef IndexBuffer = Int;
+typedef VertexBuffer = Int;
+typedef Texture = Int;
 #end
 #end
 
 
+enum Feature {
+	HardwareAccelerated;
+	StandardDerivatives;
+	FloatTextures;
+	TargetDepthBuffer;
+}
+
 class Driver {
 class Driver {
-	
+
+	public var logEnable : Bool;
+
+	public function hasFeature( f : Feature ) {
+		return false;
+	}
+
 	public function isDisposed() {
 	public function isDisposed() {
 		return true;
 		return true;
 	}
 	}
-	
+
 	public function dispose() {
 	public function dispose() {
 	}
 	}
-	
+
 	public function begin( frame : Int ) {
 	public function begin( frame : Int ) {
 	}
 	}
-	
-	public function clear( r : Float, g : Float, b : Float, a : Float ) {
+
+	public inline function log( str : String ) {
+		#if debug
+		if( logEnable ) logImpl(str);
+		#end
+	}
+
+	public function getNativeShaderCode( shader : hxsl.RuntimeShader ) : String {
+		return null;
+	}
+
+	function logImpl( str : String ) {
+	}
+
+	public function clear( ?color : h3d.Vector, ?depth : Float, ?stencil : Int ) {
 	}
 	}
-	
+
 	public function setCapture( bmp : hxd.BitmapData, callb : Void -> Void ) {
 	public function setCapture( bmp : hxd.BitmapData, callb : Void -> Void ) {
 	}
 	}
-	
+
 	public function reset() {
 	public function reset() {
 	}
 	}
-	
+
 	public function getDriverName( details : Bool ) {
 	public function getDriverName( details : Bool ) {
 		return "Not available";
 		return "Not available";
 	}
 	}
-	
+
 	public function init( onCreate : Bool -> Void, forceSoftware = false ) {
 	public function init( onCreate : Bool -> Void, forceSoftware = false ) {
 	}
 	}
-	
+
 	public function resize( width : Int, height : Int ) {
 	public function resize( width : Int, height : Int ) {
 	}
 	}
-	
-	public function selectMaterial( mbits : Int ) {
-	}
-	
-	/** return value tells if we have shader shader **/
-	public function selectShader( shader : Shader ) : Bool {
+
+	public function selectShader( shader : hxsl.RuntimeShader ) {
 		return false;
 		return false;
 	}
 	}
-	
-	public function deleteShader(shader : Shader) {
-		
+
+	public function selectMaterial( pass : h3d.mat.Pass ) {
+	}
+
+	public function uploadShaderBuffers( buffers : h3d.shader.Buffers, which : h3d.shader.Buffers.BufferKind ) {
 	}
 	}
 
 
 	public function getShaderInputNames() : Array<String> {
 	public function getShaderInputNames() : Array<String> {
 		return null;
 		return null;
 	}
 	}
-	
-	public function selectBuffer( buffer : VertexBuffer ) {
+
+	public function selectBuffer( buffer : Buffer ) {
 	}
 	}
-	
+
 	public function selectMultiBuffers( buffers : Buffer.BufferOffset ) {
 	public function selectMultiBuffers( buffers : Buffer.BufferOffset ) {
 	}
 	}
-	
+
 	public function draw( ibuf : IndexBuffer, startIndex : Int, ntriangles : Int ) {
 	public function draw( ibuf : IndexBuffer, startIndex : Int, ntriangles : Int ) {
 	}
 	}
-	
+
 	public function setRenderZone( x : Int, y : Int, width : Int, height : Int ) {
 	public function setRenderZone( x : Int, y : Int, width : Int, height : Int ) {
 	}
 	}
-	
-	public function setRenderTarget( tex : Null<h3d.mat.Texture>, clearColor : Int ) {
+
+	public function setRenderTarget( tex : Null<h3d.mat.Texture> ) {
 	}
 	}
-	
+
 	public function present() {
 	public function present() {
 	}
 	}
-	
-	public function isHardware() {
-		return true;
-	}
-	
+
 	public function setDebug( b : Bool ) {
 	public function setDebug( b : Bool ) {
 	}
 	}
-	
+
 	public function allocTexture( t : h3d.mat.Texture ) : Texture {
 	public function allocTexture( t : h3d.mat.Texture ) : Texture {
 		return null;
 		return null;
 	}
 	}
@@ -110,35 +118,35 @@ class Driver {
 		return null;
 		return null;
 	}
 	}
 
 
-	public function allocVertex( m : ManagedBuffer ) : VertexBuffer {
+	public function allocVertexes( m : ManagedBuffer ) : VertexBuffer {
 		return null;
 		return null;
 	}
 	}
-	
+
 	public function disposeTexture( t : Texture ) {
 	public function disposeTexture( t : Texture ) {
 	}
 	}
-	
+
 	public function disposeIndexes( i : IndexBuffer ) {
 	public function disposeIndexes( i : IndexBuffer ) {
 	}
 	}
-	
-	public function disposeVertex( v : VertexBuffer ) {
+
+	public function disposeVertexes( v : VertexBuffer ) {
 	}
 	}
-	
-	public function uploadIndexesBuffer( i : IndexBuffer, startIndice : Int, indiceCount : Int, buf : hxd.IndexBuffer, bufPos : Int ) {
+
+	public function uploadIndexBuffer( i : IndexBuffer, startIndice : Int, indiceCount : Int, buf : hxd.IndexBuffer, bufPos : Int ) {
 	}
 	}
 
 
-	public function uploadIndexesBytes( i : IndexBuffer, startIndice : Int, indiceCount : Int, buf : haxe.io.Bytes , bufPos : Int ) {
+	public function uploadIndexBytes( i : IndexBuffer, startIndice : Int, indiceCount : Int, buf : haxe.io.Bytes , bufPos : Int ) {
 	}
 	}
-	
+
 	public function uploadVertexBuffer( v : VertexBuffer, startVertex : Int, vertexCount : Int, buf : hxd.FloatBuffer, bufPos : Int ) {
 	public function uploadVertexBuffer( v : VertexBuffer, startVertex : Int, vertexCount : Int, buf : hxd.FloatBuffer, bufPos : Int ) {
 	}
 	}
 
 
 	public function uploadVertexBytes( v : VertexBuffer, startVertex : Int, vertexCount : Int, buf : haxe.io.Bytes, bufPos : Int ) {
 	public function uploadVertexBytes( v : VertexBuffer, startVertex : Int, vertexCount : Int, buf : haxe.io.Bytes, bufPos : Int ) {
 	}
 	}
-	
+
 	public function uploadTextureBitmap( t : h3d.mat.Texture, bmp : hxd.BitmapData, mipLevel : Int, side : Int ) {
 	public function uploadTextureBitmap( t : h3d.mat.Texture, bmp : hxd.BitmapData, mipLevel : Int, side : Int ) {
 	}
 	}
 
 
 	public function uploadTexturePixels( t : h3d.mat.Texture, pixels : hxd.Pixels, mipLevel : Int, side : Int ) {
 	public function uploadTexturePixels( t : h3d.mat.Texture, pixels : hxd.Pixels, mipLevel : Int, side : Int ) {
 	}
 	}
-	
+
 }
 }

File diff suppressed because it is too large
+ 338 - 1114
h3d/impl/GlDriver.hx


+ 303 - 0
h3d/impl/LogDriver.hx

@@ -0,0 +1,303 @@
+package h3d.impl;
+import h3d.impl.Driver;
+
+class LogDriver extends Driver {
+
+	var d : Driver;
+	var loggedShaders = new Map<Int,Bool>();
+	var currentShader : hxsl.RuntimeShader;
+
+	public function new( driver : Driver ) {
+		this.d = driver;
+		logEnable = true;
+		driver.logEnable = true;
+	}
+
+	override function logImpl( str : String ) {
+		d.logImpl(str);
+	}
+
+	override function hasFeature( f : Feature ) {
+		return d.hasFeature(f);
+	}
+
+	override function isDisposed() {
+		return d.isDisposed();
+	}
+
+	override function dispose() {
+		log('Dispose');
+		d.dispose();
+	}
+
+	override function begin( frame : Int ) {
+		log('Begin $frame');
+		d.begin(frame);
+	}
+
+	override function clear( ?color : h3d.Vector, ?depth : Float, ?stencil : Int ) {
+		log('Clear color=$color depth=$depth stencil=$stencil');
+		d.clear(color, depth, stencil);
+	}
+
+	override function setCapture( bmp : hxd.BitmapData, callb : Void -> Void ) {
+		log('SetCapture ${bmp.width}x${bmp.height}');
+		d.setCapture(bmp, callb);
+	}
+
+	override function reset() {
+		log('Reset');
+		d.reset();
+	}
+
+	override function getDriverName( details : Bool ) {
+		return d.getDriverName(details);
+	}
+
+	override function init( onCreate : Bool -> Void, forceSoftware = false ) {
+		log('Init');
+		d.init(function(b) {
+			log('OnCreate $b');
+			onCreate(b);
+		},forceSoftware);
+	}
+
+	override function resize( width : Int, height : Int ) {
+		log('Resize $width x $height');
+		d.resize(width, height);
+	}
+
+	override function selectShader( shader : hxsl.RuntimeShader ) {
+		log('Select shader #${shader.id}');
+		currentShader = shader;
+		var ret = d.selectShader(shader);
+		if( !loggedShaders.get(shader.id) ) {
+			function fmt( shader : hxsl.RuntimeShader.RuntimeShaderData ) {
+				var str = hxsl.Printer.shaderToString(shader.data);
+				str = ~/((fragment)|(vertex))Globals\[([0-9]+)\](.[xyz]+)?/g.map(str, function(r) {
+					var name = null;
+					var cid = Std.parseInt(r.matched(4)) << 2;
+					var swiz = r.matched(5);
+					if( swiz != null ) {
+						var d = swiz.charCodeAt(1) - 'x'.code;
+						cid += d;
+						swiz = "." + [for( i in 1...swiz.length ) String.fromCharCode(swiz.charCodeAt(i) - d)].join("");
+					}
+					for( g in shader.globals ) {
+						if( g.path == "__consts__" && cid >= g.pos && cid < g.pos + (switch(g.type) { case TArray(TFloat, SConst(n)): n; default: 0; } ) && swiz == ".x" ) {
+							swiz = null;
+							name = "" + shader.consts[cid - g.pos];
+							break;
+						}
+						if( g.pos == cid ) {
+							name = g.path;
+							break;
+						}
+					}
+					if( name == null )
+						return r.matched(0);
+					if( swiz != null ) name += swiz;
+					return name;
+				});
+				str = ~/((fragment)|(vertex))Params\[([0-9]+)\](.[xyz]+)?/g.map(str, function(r) {
+					var name = null;
+					var cid = Std.parseInt(r.matched(4)) << 2;
+					var swiz = r.matched(5);
+					if( swiz != null ) {
+						var d = swiz.charCodeAt(1) - 'x'.code;
+						cid += d;
+						swiz = "." + [for( i in 1...swiz.length ) String.fromCharCode(swiz.charCodeAt(i) - d)].join("");
+					}
+					for( p in shader.params )
+						if( p.pos == cid ) {
+							name = p.name;
+							break;
+						}
+					if( name == null )
+						return r.matched(0);
+					if( swiz != null ) name += swiz;
+					return name;
+				});
+				str = ~/((fragment)|(vertex))Textures\[([0-9]+)\]/g.map(str, function(r) {
+					var name = null;
+					var cid = Std.parseInt(r.matched(4));
+					for( p in shader.textures )
+						if( p.pos == cid )
+							return p.name;
+					return r.matched(0);
+				});
+				return str;
+			}
+			var str = fmt(shader.vertex) + "\n" + fmt(shader.fragment);
+			log('');
+			log('HXSL=');
+			log("\t" + str.split("\n").join("\n\t"));
+			var str = getNativeShaderCode(shader);
+			if( str != null ) {
+				log('NATIVE=');
+				log("\t" + str.split("\n").join("\n\t"));
+			}
+			log('');
+			loggedShaders.set(shader.id, true);
+		}
+		return ret;
+	}
+
+	override function getNativeShaderCode( shader ) {
+		return d.getNativeShaderCode(shader);
+	}
+
+	override function selectMaterial( pass : h3d.mat.Pass ) {
+		log('Select Material Cull=${pass.culling} depth=${pass.depthTest}${pass.depthWrite ? "" : " nowrite"} blend=${pass.blendSrc},${pass.blendDst} color=${pass.colorMask}');
+		d.selectMaterial(pass);
+	}
+
+	function sizeOf( t : hxsl.Ast.Type ) {
+		return switch( t ) {
+		case TVoid: 0;
+		case TInt, TFloat: 1;
+		case TVec(n, _): n;
+		case TMat4: 16;
+		case TMat3: 9;
+		case TMat3x4: 12;
+		case TArray(t, SConst(n)): sizeOf(t) * n;
+		default: throw "assert " + t;
+		}
+	}
+
+	override function uploadShaderBuffers( buffers : h3d.shader.Buffers, which : h3d.shader.Buffers.BufferKind ) {
+		switch( which ) {
+		case Globals:
+			inline function logVars( s : hxsl.RuntimeShader.RuntimeShaderData, buf : h3d.shader.Buffers.ShaderBuffers ) {
+				if( s.globalsSize == 0 ) return;
+				log('Upload ' + (s.vertex?"vertex":"fragment")+" globals");
+				for( g in s.globals )
+					log('\t@${g.pos} ' + g.path + '=' + [for( i in 0...sizeOf(g.type) ) hxd.Math.fmt(buf.globals.toData()[g.pos + i])]);
+			}
+			logVars(currentShader.vertex, buffers.vertex);
+			logVars(currentShader.fragment, buffers.fragment);
+		case Params:
+			inline function logVars( s : hxsl.RuntimeShader.RuntimeShaderData, buf : h3d.shader.Buffers.ShaderBuffers ) {
+				if( s.paramsSize == 0 ) return;
+				log('Upload ' + (s.vertex?"vertex":"fragment")+" params");
+				for( p in s.params ) {
+					var pos = p.pos;
+					#if flash
+					pos += s.globalsSize * 4;
+					#end
+					log('\t@$pos ' + p.name + '=' + [for( i in 0...sizeOf(p.type) ) hxd.Math.fmt(buf.params.toData()[p.pos + i])]);
+				}
+			}
+			logVars(currentShader.vertex, buffers.vertex);
+			logVars(currentShader.fragment, buffers.fragment);
+		case Textures:
+			inline function logVars( s : hxsl.RuntimeShader.RuntimeShaderData, buf : h3d.shader.Buffers.ShaderBuffers ) {
+				for( t in s.textures )
+					log('Set ${s.vertex ? "Vertex" : "Fragment"} Texture@${t.pos} '+t.name+"="+(buf.tex.length <= t.pos ? 'OUT OF BOUNDS' : ''+buf.tex[t.pos]));
+			}
+			logVars(currentShader.vertex, buffers.vertex);
+			logVars(currentShader.fragment, buffers.fragment);
+		}
+		d.uploadShaderBuffers(buffers, which);
+	}
+
+	override function getShaderInputNames() : Array<String> {
+		return d.getShaderInputNames();
+	}
+
+	override function selectBuffer( buffer : Buffer ) {
+		log('SelectBuffer');
+		d.selectBuffer(buffer);
+	}
+
+	override function selectMultiBuffers( buffers : Buffer.BufferOffset ) {
+		log('SelectMultiBuffers');
+		d.selectMultiBuffers(buffers);
+	}
+
+	override function draw( ibuf : IndexBuffer, startIndex : Int, ntriangles : Int ) {
+		log('Draw $ntriangles');
+		d.draw(ibuf, startIndex, ntriangles);
+	}
+
+	override function setRenderZone( x : Int, y : Int, width : Int, height : Int ) {
+		log('SetRenderZone [$x $y $width $height]');
+		d.setRenderZone(x, y, width, height);
+	}
+
+	override function setRenderTarget( tex : Null<h3d.mat.Texture> ) {
+		log('SetRenderTarget $tex');
+		d.setRenderTarget(tex);
+	}
+
+	override function present() {
+		log('Present');
+		d.present();
+	}
+
+	override function setDebug( b : Bool ) {
+		log('SetDebug $b');
+		d.setDebug(b);
+	}
+
+	override function allocTexture( t : h3d.mat.Texture ) : Texture {
+		log('AllocTexture $t');
+		return d.allocTexture(t);
+	}
+
+	override function allocIndexes( count : Int ) : IndexBuffer {
+		log('AllocIndexes $count');
+		return d.allocIndexes(count);
+	}
+
+	override function allocVertexes( m : ManagedBuffer ) : VertexBuffer {
+		log('AllocVertexes size=${m.size} stride=${m.stride}');
+		return d.allocVertexes(m);
+	}
+
+	override function disposeTexture( t : Texture ) {
+		log('Dispose texture');
+		d.disposeTexture(t);
+	}
+
+	override function disposeIndexes( i : IndexBuffer ) {
+		log('DisposeIndexes');
+		d.disposeIndexes(i);
+	}
+
+	override function disposeVertexes( v : VertexBuffer ) {
+		log('DisposeIndexes');
+		d.disposeVertexes(v);
+	}
+
+	override function uploadIndexBuffer( i : IndexBuffer, startIndice : Int, indiceCount : Int, buf : hxd.IndexBuffer, bufPos : Int ) {
+		log('UploadIndexBuffer');
+		d.uploadIndexBuffer(i, startIndice, indiceCount, buf, bufPos);
+	}
+
+	override function uploadIndexBytes( i : IndexBuffer, startIndice : Int, indiceCount : Int, buf : haxe.io.Bytes , bufPos : Int ) {
+		log('UploadIndexBytes');
+		d.uploadIndexBytes(i, startIndice, indiceCount, buf, bufPos);
+	}
+
+	override function uploadVertexBuffer( v : VertexBuffer, startVertex : Int, vertexCount : Int, buf : hxd.FloatBuffer, bufPos : Int ) {
+		log('UploadVertexBuffer');
+		d.uploadVertexBuffer(v, startVertex, vertexCount, buf, bufPos);
+	}
+
+	override function uploadVertexBytes( v : VertexBuffer, startVertex : Int, vertexCount : Int, buf : haxe.io.Bytes, bufPos : Int ) {
+		log('UploadVertexBytes');
+		d.uploadVertexBytes(v, startVertex, vertexCount, buf, bufPos);
+	}
+
+	override function uploadTextureBitmap( t : h3d.mat.Texture, bmp : hxd.BitmapData, mipLevel : Int, side : Int ) {
+		log('UploadTextureBitmap $t mip=$mipLevel side=$side');
+		d.uploadTextureBitmap(t, bmp, mipLevel, side);
+	}
+
+	override function uploadTexturePixels( t : h3d.mat.Texture, pixels : hxd.Pixels, mipLevel : Int, side : Int ) {
+		log('UploadTexturePixels $t mip=$mipLevel side=$side');
+		d.uploadTexturePixels(t, pixels, mipLevel, side);
+	}
+
+}

+ 8 - 8
h3d/impl/ManagedBuffer.hx

@@ -19,11 +19,11 @@ class ManagedBuffer {
 	public var stride(default,null) : Int;
 	public var stride(default,null) : Int;
 	public var size(default,null) : Int;
 	public var size(default,null) : Int;
 	public var flags(default, null) : haxe.EnumFlags<Buffer.BufferFlag>;
 	public var flags(default, null) : haxe.EnumFlags<Buffer.BufferFlag>;
-	
+
 	var vbuf : Driver.VertexBuffer;
 	var vbuf : Driver.VertexBuffer;
 	var freeList : FreeCell;
 	var freeList : FreeCell;
 	var next : ManagedBuffer;
 	var next : ManagedBuffer;
-	
+
 	public function new( stride, size, ?flags : Array<Buffer.BufferFlag> ) {
 	public function new( stride, size, ?flags : Array<Buffer.BufferFlag> ) {
 		this.flags = new haxe.EnumFlags();
 		this.flags = new haxe.EnumFlags();
 		if( flags != null )
 		if( flags != null )
@@ -43,7 +43,7 @@ class ManagedBuffer {
 	public function uploadVertexBytes( start : Int, vertices : Int, data : haxe.io.Bytes, dataPos = 0 ) {
 	public function uploadVertexBytes( start : Int, vertices : Int, data : haxe.io.Bytes, dataPos = 0 ) {
 		mem.driver.uploadVertexBytes(vbuf, start, vertices, data, dataPos);
 		mem.driver.uploadVertexBytes(vbuf, start, vertices, data, dataPos);
 	}
 	}
-	
+
 	public function alloc(vertices,align) {
 	public function alloc(vertices,align) {
 		var p = allocPosition(vertices, align);
 		var p = allocPosition(vertices, align);
 		if( p < 0 )
 		if( p < 0 )
@@ -55,7 +55,7 @@ class ManagedBuffer {
 		};
 		};
 		return b;
 		return b;
 	}
 	}
-	
+
 	public function getFreeVertices() {
 	public function getFreeVertices() {
 		var m = 0;
 		var m = 0;
 		var l = freeList;
 		var l = freeList;
@@ -65,7 +65,7 @@ class ManagedBuffer {
 		}
 		}
 		return m;
 		return m;
 	}
 	}
-	
+
 	function allocPosition( nvert : Int, align : Int ) {
 	function allocPosition( nvert : Int, align : Int ) {
 		var free = freeList;
 		var free = freeList;
 		while( free != null ) {
 		while( free != null ) {
@@ -90,7 +90,7 @@ class ManagedBuffer {
 		free.count -= nvert;
 		free.count -= nvert;
 		return pos;
 		return pos;
 	}
 	}
-	
+
 	function allocBuffer( b : Buffer ) {
 	function allocBuffer( b : Buffer ) {
 		var align = b.flags.has(Quads) ? 4 : (b.flags.has(Triangles) ? 3 : 1);
 		var align = b.flags.has(Quads) ? 4 : (b.flags.has(Triangles) ? 3 : 1);
 		var p = allocPosition(b.vertices, align);
 		var p = allocPosition(b.vertices, align);
@@ -101,7 +101,7 @@ class ManagedBuffer {
 		};
 		};
 		return true;
 		return true;
 	}
 	}
-	
+
 	@:allow(h3d.Buffer.dispose)
 	@:allow(h3d.Buffer.dispose)
 	function freeBuffer( b : Buffer ) {
 	function freeBuffer( b : Buffer ) {
 		var prev : FreeCell = null;
 		var prev : FreeCell = null;
@@ -141,7 +141,7 @@ class ManagedBuffer {
 	public function dispose() {
 	public function dispose() {
 		mem.freeManaged(this);
 		mem.freeManaged(this);
 	}
 	}
-	
+
 	public inline function isDisposed() {
 	public inline function isDisposed() {
 		return vbuf == null;
 		return vbuf == null;
 	}
 	}

+ 2 - 2
h3d/impl/MemoryManager.hx

@@ -84,7 +84,7 @@ class MemoryManager {
 		if( m.vbuf != null ) return;
 		if( m.vbuf != null ) return;
 
 
 		var mem = m.size * m.stride * 4;
 		var mem = m.size * m.stride * 4;
-		while( usedMemory + mem > MAX_MEMORY || bufferCount >= MAX_BUFFERS || (m.vbuf = driver.allocVertex(m)) == null ) {
+		while( usedMemory + mem > MAX_MEMORY || bufferCount >= MAX_BUFFERS || (m.vbuf = driver.allocVertexes(m)) == null ) {
 			var size = usedMemory - freeMemorySize();
 			var size = usedMemory - freeMemorySize();
 			garbage();
 			garbage();
 			cleanManagedBuffers();
 			cleanManagedBuffers();
@@ -101,7 +101,7 @@ class MemoryManager {
 	@:allow(h3d.impl.ManagedBuffer)
 	@:allow(h3d.impl.ManagedBuffer)
 	function freeManaged( m : ManagedBuffer ) {
 	function freeManaged( m : ManagedBuffer ) {
 		if( m.vbuf == null ) return;
 		if( m.vbuf == null ) return;
-		driver.disposeVertex(m.vbuf);
+		driver.disposeVertexes(m.vbuf);
 		m.vbuf = null;
 		m.vbuf = null;
 		usedMemory -= m.size * m.stride * 4;
 		usedMemory -= m.size * m.stride * 4;
 		bufferCount--;
 		bufferCount--;

+ 0 - 188
h3d/impl/Shader.hx

@@ -1,188 +0,0 @@
-package h3d.impl;
-
-
-#if macro
-import haxe.macro.Context;
-import haxe.macro.Type.Ref;
-#end
-
-#if flash
-typedef Shader = hxsl.Shader;
-#elseif (js || cpp)
-
-typedef ShaderLocation = #if js js.html.webgl.UniformLocation #else openfl.gl.GLUniformLocation #end;
-enum ShaderType {
-	Float;
-	Vec2;
-	Vec3;
-	Vec4;
-	Mat2;
-	Mat3;
-	Mat4;
-	Tex2d;
-	TexCube;
-	Byte3;
-	Byte4;
-	Struct( field : String, t : ShaderType );
-	Index( index : Int, t : ShaderType );
-	Elements( field : String, size:Null<Int>, t : ShaderType);//null means size in indefinite and will be context relative
-}
-
-@:publicFields
-class Uniform { 
-	var name : String;
-	var loc : Null<ShaderLocation>;
-	var type : ShaderType;
-	var index : Int;
-	
-	inline function new(n:String, l:ShaderLocation, t:ShaderType, i) {
-		if ( l == null) throw "assert";
-		name = n;
-		loc = l;
-		type = t;
-		index = i;
-	}
-}
-
-@:publicFields
-class Attribute {
-	var etype : Int;
-	var offset : Int; 
-	var index : Int;
-	var size : Int;
-	
-	var name : String;
-	var type : ShaderType;
-	
-	function new(n:String,t:ShaderType,e,o,i,s) {
-		name = n;
-		type = t;
-		etype = e;
-		offset = o;
-		index = i;
-		size = s;
-	}
-	
-	public function toString() {
-		return 'etype:$etype offset::$offset index:$index size:$size name:$name type:$type';
-	}
-}
-
-class ShaderInstance {
-
-	public var program : #if js js.html.webgl.Program #else openfl.gl.GLProgram #end;
-	public var attribs : Array<Attribute>;
-	public var uniforms : Array<Uniform>;
-	public var stride : Int;
-	public function new() {
-	}
-
-}
-
-@:autoBuild(h3d.impl.Shader.ShaderMacros.buildGLShader())
-class Shader {
-	
-	var instance : ShaderInstance;
-	
-	public function new() {
-	}
-	
-	function customSetup( driver : h3d.impl.GlDriver ) {
-	}
-	
-	function getConstants( vertex : Bool ) {
-		return "";
-	}
-
-	public function delete() {
-		#if !macro
-			if( instance!=null)
-				h3d.Engine.getCurrent().driver.deleteShader(this);
-		#end
-	}
-}
-
-#else
-
-class Shader implements Dynamic {
-	public function new() {
-	}
-}
-
-#end
-
-#if macro
-class ShaderMacros {
-	
-	public static function buildGLShader() {
-		var pos = Context.getLocalClass().get().pos;
-		var fields = Context.getBuildFields();
-		var hasVertex = false, hasFragment = false;
-		var r_uni = ~/uniform[ \t]+((lowp|mediump|highp)[ \t]+)?([A-Za-z0-9_]+)[ \t]+([A-Za-z0-9_]+)[ \t]*(\/\*([A-Za-z0-9_]+)\*\/)?/;
-		
-		var cl = Std.string(Context.getLocalClass());
-		//var allFields = Lambda.map( fields, function(t) return t.name).join(' ');
-		
-		function classHasField( c : haxe.macro.Type.Ref< haxe.macro.Type.ClassType> , name)
-		{
-			if ( c == null ) return false;
-			var o = c.get();
-			
-			return
-			if ( o.fields!=null && Lambda.exists( o.fields.get() , function(o) return o.name == name ))
-				true;
-			else if ( o.superClass == null ) false;
-			else classHasField( o.superClass.t , name);
-		}
-		
-		function addUniforms( code : String ) {
-			while( r_uni.match(code) ) {
-				var name = r_uni.matched(4);
-				var type = r_uni.matched(3);
-				var hint = r_uni.matched(6);
-				code = r_uni.matchedRight();
-				var t = switch( type ) {
-				case "float": macro : Float;
-				case "vec4", "vec3" if( hint == "byte4" ): macro : Int;
-				case "vec2", "vec3", "vec4": macro : h3d.Vector;
-				case "mat3", "mat4": macro : h3d.Matrix;
-				case "sampler2D", "samplerCube": macro : h3d.mat.Texture;
-				default:
-					// most likely a struct, handle it manually
-					if( type.charCodeAt(0) >= 'A'.code && type.charCodeAt(0) <= 'Z'.code )
-						continue;
-					throw "Unsupported type " + type;
-				}
-								
-				if ( code.charCodeAt(0) == '['.code ) t = macro : Array<$t>;
-				if ( classHasField( Context.getLocalClass(), name ) )  continue;
-				
-				fields.push( {
-						name : name,
-						kind : FVar(t),
-						pos : pos,
-						access : [APublic],
-						meta:[{name:":keep",params:[],pos:pos}]
-					});
-			}
-		}
-		for( f in fields )
-			switch( [f.name, f.kind] ) {
-				case ["VERTEX", FVar(_,{ expr : EConst(CString(code)) }) ]:
-					hasVertex = true;
-					addUniforms(code);
-				case ["FRAGMENT", FVar(_,{ expr : EConst(CString(code)) })]:
-					hasFragment = true;
-					addUniforms(code);
-				default:
-			}
-		if( !hasVertex )
-			haxe.macro.Context.error("Missing VERTEX shader", pos);
-		if( !hasFragment )
-			haxe.macro.Context.error("Missing FRAGMENT shader", pos);
-			
-		return fields;
-	}
-	
-}
-#end

+ 0 - 88
h3d/impl/Shaders.hx

@@ -1,88 +0,0 @@
-package h3d.impl;
-
-class PointShader extends h3d.impl.Shader {
-
-#if flash
-	static var SRC = {
-		var input : {
-			pos : Float2,
-		};
-		var tuv : Float2;
-		function vertex( mproj : Matrix, delta : Float4, size : Float2 ) {
-			var p = delta * mproj;
-			p.xy += input.pos.xy * size * p.z;
-			out = p;
-			tuv = input.pos;
-		}
-		function fragment( color : Color ) {
-			kill( 1 - (tuv.x * tuv.x + tuv.y * tuv.y) );
-			out = color;
-		}
-	}
-#elseif (js || cpp)
-
-	static var VERTEX = "
-		attribute vec2 pos;
-		varying mediump tuv;
-		uniform mat4 mproj;
-		uniform vec4 delta;
-		uniform vec2 size;
-		
-		void main(void) {
-			vec4 p = mproj * delta;
-			p.xy += pos.xy * size * p.z;
-			gl_Position = p;
-			tuv = pos;
-		}
-	";
-	static var FRAGMENT = "
-		varying mediump tuv;
-		uniform vec4 color /*byte4*/;
-		
-		void main(void) {
-			if( 1 - dot(tuv, tuv) < 0 ) discard;
-			gl_FragColor = color;
-		}
-	";
-
-#end
-	
-}
-
-class LineShader extends h3d.impl.Shader {
-
-#if flash
-	static var SRC = {
-		var input : {
-			pos : Float2,
-		};
-
-		function vertex( mproj : Matrix, start : Float4, end : Float4 ) {
-			var spos = start * mproj;
-			var epos = end * mproj;
-			var delta = epos.xy  - spos.xy;
-			delta.xy *= 1 / sqrt(delta.x * delta.x + delta.y * delta.y);
-			
-			
-			var p = (epos - spos) * (input.pos.x + 1) * 0.5 + spos;
-			p.xy += delta.yx * input.pos.y * p.z / 400;
-			out = p;
-		}
-		function fragment( color : Color ) {
-			out = color;
-		}
-	}
-	
-#elseif (js || cpp)
-
-	public var mproj : Matrix;
-	public var start : Vector;
-	public var end : Vector;
-	public var color : Int;
-	
-	static var VERTEX = "TODO";
-	static var FRAGMENT = "TODO";
-	
-#end
-
-}

+ 249 - 63
h3d/impl/Stage3dDriver.hx

@@ -1,5 +1,6 @@
 package h3d.impl;
 package h3d.impl;
 import h3d.impl.Driver;
 import h3d.impl.Driver;
+import h3d.mat.Pass;
 
 
 #if flash
 #if flash
 
 
@@ -31,17 +32,33 @@ class VertexWrapper {
 
 
 }
 }
 
 
+private class CompiledShader {
+	public var p : flash.display3D.Program3D;
+	public var s : hxsl.RuntimeShader;
+	public var stride : Int;
+	public var bufferFormat : Int;
+	public var inputNames : Array<String>;
+	public var usedTextures : Array<Bool>;
+	public function new(s) {
+		this.s = s;
+		stride = 0;
+		bufferFormat = 0;
+		inputNames = [];
+		usedTextures = [];
+	}
+}
+
 class Stage3dDriver extends Driver {
 class Stage3dDriver extends Driver {
 
 
-	public static var PROFILE = flash.display3D.Context3DProfile.BASELINE;
+	public static var PROFILE = #if flash14 cast "standard" #else flash.display3D.Context3DProfile.BASELINE #end;
 
 
 	var s3d : flash.display.Stage3D;
 	var s3d : flash.display.Stage3D;
 	var ctx : flash.display3D.Context3D;
 	var ctx : flash.display3D.Context3D;
 	var onCreateCallback : Bool -> Void;
 	var onCreateCallback : Bool -> Void;
 
 
 	var curMatBits : Int;
 	var curMatBits : Int;
-	var curShader : hxsl.Shader.ShaderInstance;
-	var curBuffer : VertexBuffer;
+	var curShader : CompiledShader;
+	var curBuffer : Buffer;
 	var curMultiBuffer : Array<Int>;
 	var curMultiBuffer : Array<Int>;
 	var curAttributes : Int;
 	var curAttributes : Int;
 	var curTextures : Array<h3d.mat.Texture>;
 	var curTextures : Array<h3d.mat.Texture>;
@@ -53,6 +70,8 @@ class Stage3dDriver extends Driver {
 	var enableDraw : Bool;
 	var enableDraw : Bool;
 	var capture : { bmp : hxd.BitmapData, callb : Void -> Void };
 	var capture : { bmp : hxd.BitmapData, callb : Void -> Void };
 	var frame : Int;
 	var frame : Int;
+	var programs : Map<Int, CompiledShader>;
+	var isStandardMode : Bool;
 
 
 	@:allow(h3d.impl.VertexWrapper)
 	@:allow(h3d.impl.VertexWrapper)
 	var empty : flash.utils.ByteArray;
 	var empty : flash.utils.ByteArray;
@@ -60,10 +79,15 @@ class Stage3dDriver extends Driver {
 	public function new() {
 	public function new() {
 		empty = new flash.utils.ByteArray();
 		empty = new flash.utils.ByteArray();
 		s3d = flash.Lib.current.stage.stage3Ds[0];
 		s3d = flash.Lib.current.stage.stage3Ds[0];
+		programs = new Map();
 		curTextures = [];
 		curTextures = [];
 		curMultiBuffer = [];
 		curMultiBuffer = [];
 	}
 	}
 
 
+	override function logImpl( str : String ) {
+		flash.Lib.trace(str);
+	}
+
 	override function getDriverName(details:Bool) {
 	override function getDriverName(details:Bool) {
 		return ctx == null ? "None" : (details ? ctx.driverInfo : ctx.driverInfo.split(" ")[0]);
 		return ctx == null ? "None" : (details ? ctx.driverInfo : ctx.driverInfo.split(" ")[0]);
 	}
 	}
@@ -92,14 +116,17 @@ class Stage3dDriver extends Driver {
 		this.onCreateCallback = onCreate;
 		this.onCreateCallback = onCreate;
 		s3d.addEventListener(flash.events.Event.CONTEXT3D_CREATE, this.onCreate);
 		s3d.addEventListener(flash.events.Event.CONTEXT3D_CREATE, this.onCreate);
 		s3d.requestContext3D( forceSoftware ? "software" : "auto", PROFILE );
 		s3d.requestContext3D( forceSoftware ? "software" : "auto", PROFILE );
+		isStandardMode = Std.string(PROFILE) == "standard";
 	}
 	}
 
 
 	function onCreate(_) {
 	function onCreate(_) {
 		var old = ctx;
 		var old = ctx;
+		for( p in programs )
+			p.p.dispose();
+		programs = new Map();
 		if( old != null ) {
 		if( old != null ) {
 			if( old.driverInfo != "Disposed" ) throw "Duplicate onCreate()";
 			if( old.driverInfo != "Disposed" ) throw "Duplicate onCreate()";
 			old.dispose();
 			old.dispose();
-			hxsl.Shader.ShaderGlobals.disposeAll();
 			ctx = s3d.context3D;
 			ctx = s3d.context3D;
 			onCreateCallback(true);
 			onCreateCallback(true);
 		} else {
 		} else {
@@ -108,8 +135,12 @@ class Stage3dDriver extends Driver {
 		}
 		}
 	}
 	}
 
 
-	override function isHardware() {
-		return ctx != null && ctx.driverInfo.toLowerCase().indexOf("software") == -1;
+	override function hasFeature( f : Feature ) : Bool {
+		return switch( f ) {
+		case HardwareAccelerated: ctx != null && ctx.driverInfo.toLowerCase().indexOf("software") == -1;
+		case StandardDerivatives, FloatTextures: isStandardMode;
+		case TargetDepthBuffer: false;
+		}
 	}
 	}
 
 
 	override function resize(width, height) {
 	override function resize(width, height) {
@@ -118,8 +149,12 @@ class Stage3dDriver extends Driver {
 		this.height = height;
 		this.height = height;
 	}
 	}
 
 
-	override function clear(r, g, b, a) {
-		ctx.clear(r, g, b, a);
+	override function clear( ?color : h3d.Vector, ?depth : Float, ?stencil : Int ) {
+		var mask = 0;
+		if( color != null ) mask |= flash.display3D.Context3DClearMask.COLOR;
+		if( depth != null ) mask |= flash.display3D.Context3DClearMask.DEPTH;
+		if( stencil != null ) mask |= flash.display3D.Context3DClearMask.STENCIL;
+		ctx.clear( color == null ? 0 : color.r, color == null ? 0 : color.g, color == null ? 0 : color.b, color == null ? 1 : color.a, depth == null ? 1 : depth, stencil == null ? 0 : stencil, mask);
 	}
 	}
 
 
 	override function setCapture( bmp : hxd.BitmapData, onCapture : Void -> Void ) {
 	override function setCapture( bmp : hxd.BitmapData, onCapture : Void -> Void ) {
@@ -152,7 +187,7 @@ class Stage3dDriver extends Driver {
 		t.dispose();
 		t.dispose();
 	}
 	}
 
 
-	override function allocVertex( buf : ManagedBuffer ) : VertexBuffer {
+	override function allocVertexes( buf : ManagedBuffer ) : VertexBuffer {
 		var v;
 		var v;
 		try {
 		try {
 			v = ctx.createVertexBuffer(buf.size, buf.stride);
 			v = ctx.createVertexBuffer(buf.size, buf.stride);
@@ -181,10 +216,11 @@ class Stage3dDriver extends Driver {
 	override function allocTexture( t : h3d.mat.Texture ) : Texture {
 	override function allocTexture( t : h3d.mat.Texture ) : Texture {
 		var fmt = flash.display3D.Context3DTextureFormat.BGRA;
 		var fmt = flash.display3D.Context3DTextureFormat.BGRA;
 		t.lastFrame = frame;
 		t.lastFrame = frame;
+		t.flags.unset(WasCleared);
 		if( t.flags.has(TargetDepth) )
 		if( t.flags.has(TargetDepth) )
 			throw "Unsupported texture flag";
 			throw "Unsupported texture flag";
 		try {
 		try {
-			if( t.flags.has(IsRectangle) ) {
+			if( t.flags.has(IsNPOT) ) {
 				if( t.flags.has(Cubic) || t.flags.has(MipMapped) )
 				if( t.flags.has(Cubic) || t.flags.has(MipMapped) )
 					throw "Not power of two texture is not supported with these flags";
 					throw "Not power of two texture is not supported with these flags";
 				#if !flash11_8
 				#if !flash11_8
@@ -207,7 +243,7 @@ class Stage3dDriver extends Driver {
 		if( t.flags.has(Cubic) ) {
 		if( t.flags.has(Cubic) ) {
 			var t = flash.Lib.as(t.t, flash.display3D.textures.CubeTexture);
 			var t = flash.Lib.as(t.t, flash.display3D.textures.CubeTexture);
 			t.uploadFromBitmapData(bmp.toNative(), side, mipLevel);
 			t.uploadFromBitmapData(bmp.toNative(), side, mipLevel);
-		} else if( t.flags.has(IsRectangle) ) {
+		} else if( t.flags.has(IsNPOT) ) {
 			#if flash11_8
 			#if flash11_8
 			var t = flash.Lib.as(t.t, flash.display3D.textures.RectangleTexture);
 			var t = flash.Lib.as(t.t, flash.display3D.textures.RectangleTexture);
 			t.uploadFromBitmapData(bmp.toNative());
 			t.uploadFromBitmapData(bmp.toNative());
@@ -224,7 +260,7 @@ class Stage3dDriver extends Driver {
 		if( t.flags.has(Cubic) ) {
 		if( t.flags.has(Cubic) ) {
 			var t = flash.Lib.as(t.t, flash.display3D.textures.CubeTexture);
 			var t = flash.Lib.as(t.t, flash.display3D.textures.CubeTexture);
 			t.uploadFromByteArray(data, 0, side, mipLevel);
 			t.uploadFromByteArray(data, 0, side, mipLevel);
-		} else if( t.flags.has(IsRectangle) ) {
+		} else if( t.flags.has(IsNPOT) ) {
 			#if flash11_8
 			#if flash11_8
 			var t = flash.Lib.as(t.t, flash.display3D.textures.RectangleTexture);
 			var t = flash.Lib.as(t.t, flash.display3D.textures.RectangleTexture);
 			t.uploadFromByteArray(data, 0);
 			t.uploadFromByteArray(data, 0);
@@ -235,7 +271,7 @@ class Stage3dDriver extends Driver {
 		}
 		}
 	}
 	}
 
 
-	override function disposeVertex( v : VertexBuffer ) {
+	override function disposeVertexes( v : VertexBuffer ) {
 		v.vbuf.dispose();
 		v.vbuf.dispose();
 		v.b = null;
 		v.b = null;
 	}
 	}
@@ -245,7 +281,7 @@ class Stage3dDriver extends Driver {
 	}
 	}
 
 
 	override function setDebug( d : Bool ) {
 	override function setDebug( d : Bool ) {
-		if( ctx != null ) ctx.enableErrorChecking = d && isHardware();
+		if( ctx != null ) ctx.enableErrorChecking = d && hasFeature(HardwareAccelerated);
 	}
 	}
 
 
 	override function uploadVertexBuffer( v : VertexBuffer, startVertex : Int, vertexCount : Int, buf : hxd.FloatBuffer, bufPos : Int ) {
 	override function uploadVertexBuffer( v : VertexBuffer, startVertex : Int, vertexCount : Int, buf : hxd.FloatBuffer, bufPos : Int ) {
@@ -257,48 +293,149 @@ class Stage3dDriver extends Driver {
 		v.vbuf.uploadFromByteArray( bytes.getData(), bufPos, startVertex, vertexCount );
 		v.vbuf.uploadFromByteArray( bytes.getData(), bufPos, startVertex, vertexCount );
 	}
 	}
 
 
-	override function uploadIndexesBuffer( i : IndexBuffer, startIndice : Int, indiceCount : Int, buf : hxd.IndexBuffer, bufPos : Int ) {
+	override function uploadIndexBuffer( i : IndexBuffer, startIndice : Int, indiceCount : Int, buf : hxd.IndexBuffer, bufPos : Int ) {
 		var data = buf.getNative();
 		var data = buf.getNative();
 		i.uploadFromVector( bufPos == 0 ? data : data.slice(bufPos, indiceCount + bufPos), startIndice, indiceCount );
 		i.uploadFromVector( bufPos == 0 ? data : data.slice(bufPos, indiceCount + bufPos), startIndice, indiceCount );
 	}
 	}
 
 
-	override function uploadIndexesBytes( i : IndexBuffer, startIndice : Int, indiceCount : Int, buf : haxe.io.Bytes, bufPos : Int ) {
+	override function uploadIndexBytes( i : IndexBuffer, startIndice : Int, indiceCount : Int, buf : haxe.io.Bytes, bufPos : Int ) {
 		i.uploadFromByteArray(buf.getData(), bufPos, startIndice, indiceCount );
 		i.uploadFromByteArray(buf.getData(), bufPos, startIndice, indiceCount );
 	}
 	}
 
 
-	override function selectMaterial( mbits : Int ) {
-		var diff = curMatBits ^ mbits;
-		if( diff != 0 ) {
-			if( curMatBits < 0 || diff&3 != 0 )
-				ctx.setCulling(FACE[mbits&3]);
-			if( curMatBits < 0 || diff & (0xFF << 6) != 0 )
-				ctx.setBlendFactors(BLEND[(mbits>>6)&15], BLEND[(mbits>>10)&15]);
-			if( curMatBits < 0 || diff & (15 << 2) != 0 )
-				ctx.setDepthTest((mbits >> 2) & 1 == 1, COMPARE[(mbits>>3)&7]);
-			if( curMatBits < 0 || diff & (15 << 14) != 0 )
-				ctx.setColorMask((mbits >> 14) & 1 != 0, (mbits >> 14) & 2 != 0, (mbits >> 14) & 4 != 0, (mbits >> 14) & 8 != 0);
-			curMatBits = mbits;
+	override function selectMaterial( pass : Pass ) {
+		selectMaterialBits(@:privateAccess pass.bits);
+	}
+
+	function selectMaterialBits( bits : Int ) {
+		var diff = bits ^ curMatBits;
+		if( curMatBits < 0 ) diff = -1;
+		if( diff == 0 )
+			return;
+		if( diff & Pass.culling_mask != 0 )
+			ctx.setCulling(FACE[Pass.getCulling(bits)]);
+		if( diff & (Pass.blendSrc_mask | Pass.blendDst_mask | Pass.blendAlphaSrc_mask | Pass.blendAlphaDst_mask) != 0 ) {
+			var csrc = Pass.getBlendSrc(bits);
+			var cdst = Pass.getBlendDst(bits);
+			var asrc = Pass.getBlendAlphaSrc(bits);
+			var adst = Pass.getBlendAlphaDst(bits);
+			if( csrc == asrc && cdst == adst ) {
+				if( (csrc | cdst) > BLEND.length ) throw "Blend operation not supported on flash";
+				ctx.setBlendFactors(BLEND[csrc], BLEND[cdst]);
+			} else {
+				throw "Alpha blend functions not supported on flash";
+			}
+		}
+		if( diff & (Pass.blendOp_mask | Pass.blendAlphaOp_mask) != 0 ) {
+			var cop = Pass.getBlendOp(bits);
+			var aop = Pass.getBlendAlphaOp(bits);
+			if( cop != 0 || aop != 0 )
+				throw "Custom blend operation not supported on flash";
+		}
+		if( diff & (Pass.depthWrite_mask | Pass.depthTest_mask) != 0 ) {
+			var write = Pass.getDepthWrite(bits) != 0;
+			var cmp = Pass.getDepthTest(bits);
+			ctx.setDepthTest(write, COMPARE[cmp]);
 		}
 		}
+		if( diff & Pass.colorMask_mask != 0 ) {
+			var m = Pass.getColorMask(bits);
+			ctx.setColorMask(m & 1 != 0, m & 2 != 0, m & 4 != 0, m & 8 != 0);
+		}
+		curMatBits = bits;
+	}
+
+	function compileShader( s : hxsl.RuntimeShader.RuntimeShaderData, usedTextures : Array<Bool> ) {
+		//trace(hxsl.Printer.shaderToString(s.data));
+		var agal = hxsl.AgalOut.toAgal(s, isStandardMode ? 2 : 1);
+		//var old = format.agal.Tools.toString(agal);
+		agal = new hxsl.AgalOptim().optimize(agal);
+		//var opt = format.agal.Tools.toString(agal);
+		for( op in agal.code )
+			switch( op ) {
+			case OTex(_, _, t): usedTextures[t.index] = true;
+			default:
+			}
+		var o = new haxe.io.BytesOutput();
+		new format.agal.Writer(o).write(agal);
+		return { agal : agal, bytes : o.getBytes() };
+	}
+
+	override function getNativeShaderCode( shader : hxsl.RuntimeShader ) {
+		var vertex = compileShader(shader.vertex, []).agal;
+		var fragment = compileShader(shader.fragment, []).agal;
+		function fmt( agal, data : hxsl.RuntimeShader.RuntimeShaderData ) {
+			var str = format.agal.Tools.toString(agal);
+			return ~/c([0-9]+)(.[xyz]+)?/g.map(str, function(r) {
+				var cid = Std.parseInt(r.matched(1)) << 2;
+				var swiz = r.matched(2);
+				if( swiz != null ) {
+					var d = swiz.charCodeAt(1) - 'x'.code;
+					cid += d;
+					swiz = "." + [for( i in 1...swiz.length ) String.fromCharCode(swiz.charCodeAt(i) - d)].join("");
+				}
+				var name = "C" + cid;
+				for( g in data.globals ) {
+					if( g.path == "__consts__" && cid >= g.pos && cid < g.pos + (switch(g.type) { case TArray(TFloat, SConst(n)): n; default: 0; } ) && swiz == ".x" ) {
+						swiz = null;
+						name = "" + data.consts[cid - g.pos];
+						break;
+					}
+					if( g.pos == cid ) {
+						name = g.path;
+						break;
+					}
+				}
+				for( p in data.params )
+					if( p.pos + (data.globalsSize << 2) == cid ) {
+						name = p.name;
+						break;
+					}
+				return swiz == null ? name : name+swiz;
+			});
+		}
+		return fmt(vertex, shader.vertex) + "\n" + fmt(fragment, shader.fragment);
 	}
 	}
 
 
-	override function selectShader( shader : Shader ) {
+	override function selectShader( shader : hxsl.RuntimeShader ) {
 		var shaderChanged = false;
 		var shaderChanged = false;
-		var s = shader.getInstance();
-		if( s.program == null ) {
-			s.program = ctx.createProgram();
-			var vdata = s.vertexBytes.getData();
-			var fdata = s.fragmentBytes.getData();
+		var p = programs.get(shader.id);
+		if( p == null ) {
+			p = new CompiledShader(shader);
+			p.p = ctx.createProgram();
+			var vdata = compileShader(shader.vertex,[]).bytes.getData();
+			var fdata = compileShader(shader.fragment, p.usedTextures).bytes.getData();
 			vdata.endian = flash.utils.Endian.LITTLE_ENDIAN;
 			vdata.endian = flash.utils.Endian.LITTLE_ENDIAN;
 			fdata.endian = flash.utils.Endian.LITTLE_ENDIAN;
 			fdata.endian = flash.utils.Endian.LITTLE_ENDIAN;
-			s.program.upload(vdata, fdata);
-			curShader = null; // in case we had the same shader and it was disposed
+
+			var pos = 0;
+			for( v in shader.vertex.data.vars )
+				if( v.kind == Input ) {
+					var size;
+					var fmt = switch( v.type ) {
+					case TBytes(4): size = 1; flash.display3D.Context3DVertexBufferFormat.BYTES_4;
+					case TFloat: size = 1; flash.display3D.Context3DVertexBufferFormat.FLOAT_1;
+					case TVec(2, VFloat): size = 2; flash.display3D.Context3DVertexBufferFormat.FLOAT_2;
+					case TVec(3, VFloat): size = 3; flash.display3D.Context3DVertexBufferFormat.FLOAT_3;
+					case TVec(4, VFloat): size = 4; flash.display3D.Context3DVertexBufferFormat.FLOAT_4;
+					default: throw "unsupported input " + v.type;
+					}
+					var idx = FORMAT.indexOf(fmt);
+					if( idx < 0 ) throw "assert " + fmt;
+					p.bufferFormat |= idx << (pos * 3);
+					p.inputNames.push(v.name);
+					p.stride += size;
+					pos++;
+				}
+
+			p.p.upload(vdata, fdata);
+			programs.set(shader.id, p);
+			curShader = null;
 		}
 		}
-		if( s != curShader ) {
-			ctx.setProgram(s.program);
+		if( p != curShader ) {
+			ctx.setProgram(p.p);
 			shaderChanged = true;
 			shaderChanged = true;
-			s.varsChanged = true;
+			curShader = p;
 			// unbind extra textures
 			// unbind extra textures
-			var tcount : Int = s.textures.length;
+			var tcount : Int = shader.fragment.textures.length + shader.vertex.textures.length;
 			while( curTextures.length > tcount ) {
 			while( curTextures.length > tcount ) {
 				curTextures.pop();
 				curTextures.pop();
 				ctx.setTextureAt(curTextures.length, null);
 				ctx.setTextureAt(curTextures.length, null);
@@ -306,28 +443,37 @@ class Stage3dDriver extends Driver {
 			// force remapping of vertex buffer
 			// force remapping of vertex buffer
 			curBuffer = null;
 			curBuffer = null;
 			curMultiBuffer[0] = -1;
 			curMultiBuffer[0] = -1;
-			curShader = s;
 		}
 		}
-		if( s.varsChanged ) {
-			s.varsChanged = false;
-			ctx.setProgramConstantsFromVector(flash.display3D.Context3DProgramType.VERTEX, 0, s.vertexVars.toData());
-			ctx.setProgramConstantsFromVector(flash.display3D.Context3DProgramType.FRAGMENT, 0, s.fragmentVars.toData());
-			for( i in 0...s.textures.length ) {
-				var t = s.textures[i];
+		return shaderChanged;
+	}
+
+	override function uploadShaderBuffers( buffers : h3d.shader.Buffers, which : h3d.shader.Buffers.BufferKind ) {
+		switch( which ) {
+		case Textures:
+			for( i in 0...curShader.s.fragment.textures.length ) {
+				var t = buffers.fragment.tex[i];
 				if( t == null || t.isDisposed() )
 				if( t == null || t.isDisposed() )
 					t = h3d.mat.Texture.fromColor(0xFFFF00FF);
 					t = h3d.mat.Texture.fromColor(0xFFFF00FF);
 				if( t != null && t.t == null && t.realloc != null ) {
 				if( t != null && t.t == null && t.realloc != null ) {
 					t.alloc();
 					t.alloc();
 					t.realloc();
 					t.realloc();
 				}
 				}
+				t.lastFrame = frame;
+				if( !curShader.usedTextures[i] ) {
+					if( curTextures[i] != null ) {
+						ctx.setTextureAt(i, null);
+						curTextures[i] = null;
+						curSamplerBits[i] = -1;
+					}
+					continue;
+				}
 				var cur = curTextures[i];
 				var cur = curTextures[i];
 				if( t != cur ) {
 				if( t != cur ) {
 					ctx.setTextureAt(i, t.t);
 					ctx.setTextureAt(i, t.t);
 					curTextures[i] = t;
 					curTextures[i] = t;
 				}
 				}
-				t.lastFrame = frame;
 				// if we have set one of the texture flag manually or if the shader does not configure the texture flags
 				// if we have set one of the texture flag manually or if the shader does not configure the texture flags
-				if( !t.hasDefaultFlags() || !s.texHasConfig[s.textureMap[i]] ) {
+				if( true /*!t.hasDefaultFlags() || !s.texHasConfig[s.textureMap[i]]*/ ) {
 					if( cur == null || t.bits != curSamplerBits[i] ) {
 					if( cur == null || t.bits != curSamplerBits[i] ) {
 						ctx.setSamplerStateAt(i, WRAP[t.wrap.getIndex()], FILTER[t.filter.getIndex()], MIP[t.mipMap.getIndex()]);
 						ctx.setSamplerStateAt(i, WRAP[t.wrap.getIndex()], FILTER[t.filter.getIndex()], MIP[t.mipMap.getIndex()]);
 						curSamplerBits[i] = t.bits;
 						curSamplerBits[i] = t.bits;
@@ -337,26 +483,63 @@ class Stage3dDriver extends Driver {
 					curSamplerBits[i] = -1;
 					curSamplerBits[i] = -1;
 				}
 				}
 			}
 			}
+		case Params:
+			if( curShader.s.vertex.paramsSize > 0 ) ctx.setProgramConstantsFromVector(flash.display3D.Context3DProgramType.VERTEX, curShader.s.vertex.globalsSize, buffers.vertex.params.toData(), curShader.s.vertex.paramsSize);
+			if( curShader.s.fragment.paramsSize > 0 ) ctx.setProgramConstantsFromVector(flash.display3D.Context3DProgramType.FRAGMENT, curShader.s.fragment.globalsSize, buffers.fragment.params.toData(), curShader.s.fragment.paramsSize);
+		case Globals:
+			if( curShader.s.vertex.globalsSize > 0 ) ctx.setProgramConstantsFromVector(flash.display3D.Context3DProgramType.VERTEX, 0, buffers.vertex.globals.toData(), curShader.s.vertex.globalsSize);
+			if( curShader.s.fragment.globalsSize > 0 ) ctx.setProgramConstantsFromVector(flash.display3D.Context3DProgramType.FRAGMENT, 0, buffers.fragment.globals.toData(), curShader.s.fragment.globalsSize);
 		}
 		}
-		return shaderChanged;
 	}
 	}
 
 
-	override function selectBuffer( v : VertexBuffer ) {
+	@:access(h3d.impl.ManagedBuffer)
+	override function selectBuffer( v : Buffer ) {
 		if( v == curBuffer )
 		if( v == curBuffer )
 			return;
 			return;
+		if( curBuffer != null && v.buffer == curBuffer.buffer && v.buffer.flags.has(RawFormat) == curBuffer.flags.has(RawFormat) ) {
+			curBuffer = v;
+			return;
+		}
+		if( curShader == null )
+			throw "No shader selected";
 		curBuffer = v;
 		curBuffer = v;
 		curMultiBuffer[0] = -1;
 		curMultiBuffer[0] = -1;
-		if( v.b.stride < curShader.stride )
-			throw "Buffer stride (" + v.b.stride + ") and shader stride (" + curShader.stride + ") mismatch";
-		if( !v.written )
-			v.finalize(this);
+
+		var m = v.buffer.vbuf;
+		if( m.b.stride < curShader.stride )
+			throw "Buffer stride (" + m.b.stride + ") and shader stride (" + curShader.stride + ") mismatch";
+		if( !m.written )
+			m.finalize(this);
 		var pos = 0, offset = 0;
 		var pos = 0, offset = 0;
 		var bits = curShader.bufferFormat;
 		var bits = curShader.bufferFormat;
-		while( offset < curShader.stride ) {
-			var size = bits & 7;
-			ctx.setVertexBufferAt(pos++, v.vbuf, offset, FORMAT[size]);
-			offset += size == 0 ? 1 : size;
-			bits >>= 3;
+		if( v.flags.has(RawFormat) ) {
+			while( offset < curShader.stride ) {
+				var size = bits & 7;
+				ctx.setVertexBufferAt(pos++, m.vbuf, offset, FORMAT[size]);
+				offset += size == 0 ? 1 : size;
+				bits >>= 3;
+			}
+		} else {
+			offset = 8; // custom data starts after [position, normal, uv]
+			for( s in curShader.inputNames ) {
+				switch( s ) {
+				case "position":
+					ctx.setVertexBufferAt(pos++, m.vbuf, 0, FORMAT[3]);
+				case "normal":
+					if( m.b.stride < 6 ) throw "Buffer is missing NORMAL data, set it to RAW format ?" #if debug + @:privateAccess v.allocPos #end;
+					ctx.setVertexBufferAt(pos++, m.vbuf, 3, FORMAT[3]);
+				case "uv":
+					if( m.b.stride < 8 ) throw "Buffer is missing UV data, set it to RAW format ?" #if debug + @:privateAccess v.allocPos #end;
+					ctx.setVertexBufferAt(pos++, m.vbuf, 6, FORMAT[2]);
+				default:
+					var size = bits & 7;
+					ctx.setVertexBufferAt(pos++, m.vbuf, offset, FORMAT[size]);
+					offset += size == 0 ? 1 : size;
+					if( offset > m.b.stride ) throw "Buffer is missing '"+s+"' data, set it to RAW format ?" #if debug + @:privateAccess v.allocPos #end;
+					bits >>= 3;
+				}
+				bits >>= 3;
+			}
 		}
 		}
 		for( i in pos...curAttributes )
 		for( i in pos...curAttributes )
 			ctx.setVertexBufferAt(i, null);
 			ctx.setVertexBufferAt(i, null);
@@ -364,7 +547,7 @@ class Stage3dDriver extends Driver {
 	}
 	}
 
 
 	override function getShaderInputNames() {
 	override function getShaderInputNames() {
-		return curShader.bufferNames;
+		return curShader.inputNames;
 	}
 	}
 
 
 	override function selectMultiBuffers( buffers : Buffer.BufferOffset ) {
 	override function selectMultiBuffers( buffers : Buffer.BufferOffset ) {
@@ -446,7 +629,7 @@ class Stage3dDriver extends Driver {
 		}
 		}
 	}
 	}
 
 
-	override function setRenderTarget( t : Null<h3d.mat.Texture>, clearColor : Int ) {
+	override function setRenderTarget( t : Null<h3d.mat.Texture>) {
 		if( t == null ) {
 		if( t == null ) {
 			ctx.setRenderToBackBuffer();
 			ctx.setRenderToBackBuffer();
 			inTarget = null;
 			inTarget = null;
@@ -458,8 +641,11 @@ class Stage3dDriver extends Driver {
 			ctx.setRenderToTexture(t.t, t.flags.has(TargetUseDefaultDepth));
 			ctx.setRenderToTexture(t.t, t.flags.has(TargetUseDefaultDepth));
 			inTarget = t;
 			inTarget = t;
 			t.lastFrame = frame;
 			t.lastFrame = frame;
+			if( !t.flags.has(WasCleared) ) {
+				t.flags.set(WasCleared);
+				ctx.clear(0, 0, 0, 1, 1, 0, flash.display3D.Context3DClearMask.COLOR);
+			}
 			reset();
 			reset();
-			ctx.clear( ((clearColor>>16)&0xFF)/255 , ((clearColor>>8)&0xFF)/255, (clearColor&0xFF)/255, ((clearColor>>>24)&0xFF)/255);
 		}
 		}
 	}
 	}
 
 

+ 0 - 15
h3d/mat/Bitmap.hx

@@ -1,15 +0,0 @@
-package h3d.mat;
-
-class Bitmap {
-
-	public var bytes : haxe.io.Bytes;
-	public var width : Int;
-	public var height : Int;
-	
-	public function new(w,h,b) {
-		this.width = w;
-		this.height = h;
-		this.bytes = b;
-	}
-	
-}

+ 9 - 0
h3d/mat/BlendMode.hx

@@ -0,0 +1,9 @@
+package h3d.mat;
+
+@:enum
+abstract BlendMode(Int) {
+	public var Normal = 0;
+	public var Alpha = 1;
+	public var Add = 2;
+	public var SoftAdd = 3;
+}

+ 22 - 1
h3d/mat/Data.hx

@@ -88,7 +88,7 @@ enum TextureFlags {
 	/**
 	/**
 		This is a not power of two texture. Automatically set when having width or height being not power of two.
 		This is a not power of two texture. Automatically set when having width or height being not power of two.
 	**/
 	**/
-	IsRectangle;
+	IsNPOT;
 	/**
 	/**
 		Don't initialy allocate the texture memory.
 		Don't initialy allocate the texture memory.
 	**/
 	**/
@@ -97,9 +97,30 @@ enum TextureFlags {
 		Inform that we will often perform upload operations on this texture
 		Inform that we will often perform upload operations on this texture
 	**/
 	**/
 	Dynamic;
 	Dynamic;
+	/**
+		The texture format will contain Float values
+	**/
+	FmtFloat;
+	/**
+		16-bit RGB format
+	**/
+	Fmt5_6_5;
+	/**
+		16-bit RGBA format
+	**/
+	Fmt4_4_4_4;
+	/**
+		16-bit RGBA format (1 bit of alpha)
+	**/
+	Fmt5_5_5_1;
 	/**
 	/**
 		Assumes that the color value of the texture is premultiplied by the alpha component.
 		Assumes that the color value of the texture is premultiplied by the alpha component.
 	**/
 	**/
 	AlphaPremultiplied;
 	AlphaPremultiplied;
+	/**
+		Tells if the target texture has been cleared (reserved for internal engine usage).
+	**/
+	WasCleared;
 }
 }
 
 
+

+ 95 - 74
h3d/mat/Material.hx

@@ -1,93 +1,114 @@
 package h3d.mat;
 package h3d.mat;
 import h3d.mat.Data;
 import h3d.mat.Data;
+import h3d.mat.Pass;
 
 
 class Material {
 class Material {
-	
-	var bits : Int;
-	public var culling(default,set) : Face;
-	public var depthWrite(default,set) : Bool;
-	public var depthTest(default,set) : Compare;
-	public var blendSrc(default,set) : Blend;
-	public var blendDst(default,set) : Blend;
-	public var colorMask(default,set) : Int;
-	public var shader : h3d.impl.Shader;
-	public var renderPass : Int;
-	
-	public function new(shader) {
-		bits = 0;
-		renderPass = 0;
-		this.shader = shader;
-		this.culling = Face.Back;
-		this.depthWrite = true;
-		this.depthTest = Compare.Less;
-		this.blendSrc = Blend.One;
-		this.blendDst = Blend.Zero;
-		this.colorMask = 15;
-	}
-	
-	public function setup( ctx : h3d.scene.RenderContext ) {
+
+	var passes : Pass;
+	public var mainPass(get, never) : Pass;
+	public var shadows(get, set) : Bool;
+	public var castShadows(default, set) : Bool;
+	public var receiveShadows(default, set) : Bool;
+
+	public function new(?shader:hxsl.Shader) {
+		if( shader != null )
+			addPass(new Pass("default",null)).addShader(shader);
 	}
 	}
-	
-	public function blend(src, dst) {
-		blendSrc = src;
-		blendDst = dst;
+
+	public function addPass<T:Pass>( p : T ) : T {
+		var prev = null, cur = passes;
+		while( cur != null ) {
+			prev = cur;
+			cur = cur.nextPass;
+		}
+		if( prev == null )
+			passes = p;
+		else
+			prev.nextPass = p;
+		p.nextPass = null;
+		return p;
 	}
 	}
-	
-	public function clone( ?m : Material ) {
-		if( m == null ) m = new Material(null);
-		m.culling = culling;
-		m.depthWrite = depthWrite;
-		m.depthTest = depthTest;
-		m.blendSrc = blendSrc;
-		m.blendDst = blendDst;
-		m.colorMask = colorMask;
-		return m;
+
+	public function removePass( p : Pass ) {
+		var prev : Pass = null, cur = passes;
+		while( cur != null ) {
+			if( cur == p ) {
+				if( prev == null )
+					passes = p.nextPass;
+				else
+					prev.nextPass = p.nextPass;
+				p.nextPass = null;
+				return true;
+			}
+			prev = cur;
+			cur = cur.nextPass;
+		}
+		return false;
 	}
 	}
-	
-	public function depth( write, test ) {
-		this.depthWrite = write;
-		this.depthTest = test;
+
+	inline function get_mainPass() {
+		return passes;
 	}
 	}
-	
-	public function setColorMask(r, g, b, a) {
-		this.colorMask = (r?1:0) | (g?2:0) | (b?4:0) | (a?8:0);
+
+	public function getPass( name : String ) : Pass {
+		var p = passes;
+		while( p != null ) {
+			if( p.name == name )
+				return p;
+			p = p.nextPass;
+		}
+		return null;
 	}
 	}
 
 
-	function set_culling(f) {
-		culling = f;
-		bits = (bits & ~(3 << 0)) | (Type.enumIndex(f) << 0);
-		return f;
+	public function allocPass< T:(Pass, { function new(?parent:Pass) : Void; }) >( name : String, ?c : Class<T> ) : T {
+		var p = getPass(name);
+		if( p != null ) return cast p;
+		if( c == null ) return null;
+		var p = Type.createInstance(c, [passes]);
+		addPass(p);
+		return p;
 	}
 	}
-	
-	function set_depthWrite(b) {
-		depthWrite = b;
-		bits = (bits & ~(1 << 2)) | ((b ? 1 : 0) << 2);
-		return b;
+
+	public function clone( ?m : Material ) : Material {
+		if( m == null ) m = new Material();
+		#if debug
+		if( Type.getClass(m) != Type.getClass(this) ) throw this + " is missing clone()";
+		#end
+		// DO NOT clone passes (it's up to the superclass to recreate the shaders)
+		m.castShadows = castShadows;
+		m.receiveShadows = receiveShadows;
+		return m;
 	}
 	}
-	
-	function set_depthTest(c) {
-		depthTest = c;
-		bits = (bits & ~(7 << 3)) | (Type.enumIndex(c) << 3);
-		return c;
+
+	inline function get_shadows() {
+		return castShadows && receiveShadows;
 	}
 	}
-	
-	function set_blendSrc(b) {
-		blendSrc = b;
-		bits = (bits & ~(15 << 6)) | (Type.enumIndex(b) << 6);
-		return b;
+
+	inline function set_shadows(v) {
+		castShadows = v;
+		receiveShadows = v;
+		return v;
 	}
 	}
 
 
-	function set_blendDst(b) {
-		blendDst = b;
-		bits = (bits & ~(15 << 10)) | (Type.enumIndex(b) << 10);
-		return b;
+	function set_castShadows(v) {
+		if( castShadows == v )
+			return v;
+		if( v )
+			addPass(new Pass("shadow", null, mainPass));
+		else
+			removePass(getPass("shadow"));
+		return castShadows = v;
 	}
 	}
-	
-	function set_colorMask(m) {
-		m &= 15;
-		colorMask = m;
-		bits = (bits & ~(15 << 14)) | (m << 14);
-		return m;
+
+	function set_receiveShadows(v) {
+		if( v == receiveShadows )
+			return v;
+		var shadows = h3d.pass.Params.shadowShader;
+		if( v )
+			mainPass.addShader(shadows);
+		else
+			mainPass.removeShader(shadows);
+		return receiveShadows = v;
 	}
 	}
 
 
 }
 }

+ 53 - 835
h3d/mat/MeshMaterial.hx

@@ -1,858 +1,76 @@
 package h3d.mat;
 package h3d.mat;
 
 
-typedef LightSystem = {
-	var ambient : h3d.Vector;
-	var dirs : Array<{ dir : h3d.Vector, color : h3d.Vector }>;
-	var points : Array<{ pos : h3d.Vector, color : h3d.Vector, att : h3d.Vector }>;
-}
-
-typedef ShadowMap = {
-	var lightProj : h3d.Matrix;
-	var lightCenter : h3d.Matrix;
-	var color : h3d.Vector;
-	var texture : Texture;
-}
-
-typedef DecalInfos = {
-	var depthTexture : Texture;
-	var uvScaleRatio : h3d.Vector;
-	var screenToLocal : h3d.Matrix;
-}
-
-private class MeshShader extends h3d.impl.Shader {
-	
-#if flash
-	static var SRC = {
-
-		var input : {
-			pos : Float3,
-			uv : Float2,
-			normal : Float3,
-			color : Float3,
-			colorAdd : Float3,
-			blending : Float,
-			weights : Float3,
-			indexes : Int,
-		};
-		
-		var tuv : Float2;
-		
-		var uvScale : Float2;
-		var uvDelta : Float2;
-		var hasSkin : Bool;
-		var hasVertexColor : Bool;
-		var hasVertexColorAdd : Bool;
-		var skinMatrixes : M34<34>;
-
-		var tcolor : Float3;
-		var acolor : Float3;
-		var talpha : Float;
-		
-		var zBias : Float;
-		var hasZBias : Bool;
-		
-		var alphaMap : Texture;
-		var alphaMapScroll : Float2;
-		var hasAlphaMap : Bool;
-		
-		var lightSystem : Param < {
-			var ambient : Float3;
-			var dirs : Array<{ dir : Float3, color : Float3 }>;
-			var points : Array<{ pos : Float3, color : Float3, att : Float3 }>;
-		}>;
-		
-		var fog : Float4;
-		
-		var glowTexture : Texture;
-		var glowAmount : Float3;
-		var hasGlow : Bool;
-		
-		var blendTexture : Texture;
-		var hasBlend : Bool;
-		var tblend : Float;
-
-		var hasShadowMap : Bool;
-		var shadowLightProj : Matrix;
-		var shadowLightCenter : Matrix;
-		var shadowColor : Float4;
-		var shadowTexture : Texture;
-		var tshadowPos : Float4;
-
-		var isOutline : Bool;
-		var outlineColor : Int;
-		var outlineSize : Float;
-		var outlinePower : Float;
-		var outlineProj : Float3;
-		
-		var cameraPos : Float3;
-		var worldNormal : Float3;
-		var worldView : Float3;
-
-		// the decal volume should have its pivot at the center of the box
-		// uvScaleRatio is the size of the box primitive
-		var isDecal : Bool;
-		var depthTexture : Texture;
-		var uvScaleRatio : Float2;
-		var screenToLocal : Matrix;
-		var outProjPos : Float4; // varying
-		
-		var smoothEdges : Bool;
-		var smoothFactor : Float;
-		
-		var writeDistance : Bool;
-		var projCenter : Float3;
-		var distance : Float3;
-		
-		
-		var colorMap : Texture;
-		var colorMapMatrix : Matrix;
-		var hasColorMap : Bool;
-
-		function vertex( mpos : Matrix, mproj : Matrix ) {
-			var tpos = input.pos.xyzw;
-			var tnorm : Float3 = [0, 0, 0];
-			
-			if( lightSystem != null || isOutline ) {
-				var n = input.normal;
-				if( hasSkin )
-					n = n * input.weights.x * skinMatrixes[input.indexes.x * (255 * 3)].m33 + n * input.weights.y * skinMatrixes[input.indexes.y * (255 * 3)].m33 + n * input.weights.z * skinMatrixes[input.indexes.z * (255 * 3)].m33;
-				else if( mpos != null )
-					n *= mpos.m33;
-				tnorm = n.normalize();
-			}
-			
-			if( hasSkin )
-				tpos.xyz = tpos * input.weights.x * skinMatrixes[input.indexes.x * (255 * 3)] + tpos * input.weights.y * skinMatrixes[input.indexes.y * (255 * 3)] + tpos * input.weights.z * skinMatrixes[input.indexes.z * (255 * 3)];
-			else if( mpos != null )
-				tpos *= mpos;
-				
-			if( isOutline ) {
-				tpos.xy += tnorm.xy * outlineProj.xy * outlineSize;
-				worldNormal = tnorm;
-				worldView = (cameraPos - tpos.xyz).normalize();
-			}
-			
-			var ppos = tpos * mproj;
-			if( hasZBias ) ppos.z += zBias;
-			
-			if( writeDistance ) {
-				var tmp = projCenter - (ppos.xyz / ppos.w);
-				tmp.y *= -1;
-				distance = tmp;
-			}
-			
-			out = ppos;
-			var t = input.uv;
-			if( uvScale != null ) t *= uvScale;
-			if( uvDelta != null ) t += uvDelta;
-			if( isDecal || smoothEdges ) outProjPos = ppos;
-			tuv = t;
-			if( lightSystem != null ) {
-				// calculate normal
-				var n = tnorm.normalize();
-				var col = lightSystem.ambient;
-				for( d in lightSystem.dirs )
-					col += d.color * n.dot(-d.dir).max(0);
-				for( p in lightSystem.points ) {
-					var d = p.pos - tpos.xyz;
-					var dlen = d.dot(d);
-					var qlen = dlen.sqt();
-					var dist : Float3;
-					dist.x = qlen;
-					dist.y = dlen;
-					dist.z = dlen * qlen;
-					col += p.color * (n.dot(d).max(0) / p.att.dot(dist));
-				}
-				if( hasVertexColor )
-					tcolor = col * input.color;
-				else
-					tcolor = col;
-			} else if( hasVertexColor )
-				tcolor = input.color;
-			if( hasVertexColorAdd )
-				acolor = input.colorAdd;
-			if( fog != null ) {
-				var dist = tpos.xyz - fog.xyz;
-				talpha = (fog.w * dist.dot(dist).rsqrt()).min(1);
-			}
-			if( hasBlend ) tblend = input.blending;
-			if( hasShadowMap )
-				tshadowPos = tpos * shadowLightProj * shadowLightCenter;
-		}
-		
-		var killAlpha : Bool;
-		var killAlphaThreshold : Float;
-		var isDXT1 : Bool;
-		var isDXT5 : Bool;
-		
-		function fragment( tex : Texture, colorAdd : Float4, colorMul : Float4, colorMatrix : M44 ) {
-			if( isOutline ) {
-				var c = outlineColor;
-				var e = 1 - worldNormal.normalize().dot(worldView.normalize());
-				out = c * e.pow(outlinePower);
-			} else if( isDecal ) {
-				var screenPos = outProjPos.xy / outProjPos.w;
-				var tuv = screenPos * [0.5,-0.5] + [0.5,0.5];
-				var ruv : Float4 = [0,0,0,0];
-				ruv.xy = screenPos;
-				ruv.z = depthTexture.get(tuv).rgb.dot([1,1/255,1/(255*255)]);
-				ruv.w = 1;
-				var wpos = ruv * screenToLocal;
-				var coord = uvScaleRatio * (wpos.xy / wpos.w) + 0.5;
-				kill( min(min(coord.x, coord.y), min(1 - coord.x, 1 - coord.y)) );
-				var c = tex.get(coord.xy);
-				if( killAlpha ) kill(c.a - killAlphaThreshold);
-				if( colorAdd != null ) c += colorAdd;
-				if( colorMul != null ) c = c * colorMul;
-				if( colorMatrix != null ) c = c * colorMatrix;
-				out = c;
-			} else {
-				var c = tex.get(tuv.xy, type = isDXT1 ? 1 : isDXT5 ? 2 : 0);
-				if( hasColorMap )
-					c.rgb += (colorMap.get(tuv.xy) * colorMapMatrix).rgb;
-				if( fog != null ) c.a *= talpha;
-				if( hasAlphaMap ) c.a *= alphaMap.get(alphaMapScroll != null ? tuv + alphaMapScroll : tuv.xy,type=isDXT1 ? 1 : isDXT5 ? 2 : 0).b;
-				if( smoothEdges ) {
-					var screenPos = outProjPos.xyz / outProjPos.w;
-					var tuv = screenPos.xy * [0.5,-0.5] + [0.5,0.5];
-					c.a *= ((depthTexture.get(tuv).rgb.dot([1, 1 / 255, 1 / (255*255)]) - screenPos.z) * smoothFactor).sat();
-				}
-				if( killAlpha ) kill(c.a - killAlphaThreshold);
-				if( hasBlend ) c.rgb = c.rgb * (1 - tblend) + tblend * blendTexture.get(tuv.xy,type=isDXT1 ? 1 : isDXT5 ? 2 : 0).rgb;
-				if( colorAdd != null ) c += colorAdd;
-				if( colorMul != null ) c = c * colorMul;
-				if( colorMatrix != null ) c = c * colorMatrix;
-				if( hasVertexColorAdd )
-					c.rgb += acolor;
-				if( lightSystem != null || hasVertexColor )
-					c.rgb *= tcolor;
-				if( hasShadowMap ) {
-					// ESM filtering
-					var shadow = exp( shadowColor.w * (tshadowPos.z - shadowTexture.get(tshadowPos.xy).dot([1, 1 / 255, 1 / (255 * 255), 1 / (255 * 255 * 255)]))).sat();
-					c.rgb *= (1 - shadow) * shadowColor.rgb + shadow.xxx;
-				}
-				if( hasGlow ) c.rgb += glowTexture.get(tuv.xy).rgb * glowAmount;
-				if( writeDistance ) c.rgb *= distance + [0.5,0.5,0];
-				out = c;
-			}
-		}
-		
-	}
-#else
-
-	public var maxSkinMatrixes : Int = 34;
-	public var hasVertexColor : Bool;
-	public var hasVertexColorAdd : Bool;
-	public var lightSystem(default, set) : LightSystem;
-	public var hasSkin : Bool;
-	public var hasZBias : Bool;
-	public var hasShadowMap : Bool;
-	public var killAlpha : Bool;
-	public var hasAlphaMap : Bool;
-	public var hasBlend : Bool;
-	public var hasGlow : Bool;
-	
-	var lights : {
-		ambient : h3d.Vector,
-		dirsDir : Array<h3d.Vector>,
-		dirsColor : Array<h3d.Vector>,
-		pointsPos : Array<h3d.Vector>,
-		pointsColor : Array<h3d.Vector>,
-		pointsAtt : Array<h3d.Vector>,
-	};
-	
-	function set_lightSystem(l) {
-		this.lightSystem = l;
-		lights = {
-			ambient : l.ambient,
-			dirsDir : [for( l in l.dirs ) l.dir],
-			dirsColor : [for( l in l.dirs ) l.color],
-			pointsPos : [for( p in l.points ) p.pos],
-			pointsColor : [for( p in l.points ) p.color],
-			pointsAtt : [for( p in l.points ) p.att],
-		};
-		return l;
-	}
-	
-	override function getConstants(vertex) {
-		var cst = [];
-		if( hasVertexColor ) cst.push("#define hasVertexColor");
-		if( hasVertexColorAdd ) cst.push("#define hasVertexColorAdd");
-		if( fog != null ) cst.push("#define hasFog");
-		if( hasBlend ) cst.push("#define hasBlend");
-		if( hasShadowMap ) cst.push("#define hasShadowMap");
-		if( lightSystem != null ) {
-			cst.push("#define hasLightSystem");
-			cst.push("const int numDirLights = " + lightSystem.dirs.length+";");
-			cst.push("const int numPointLights = " + lightSystem.points.length+";");
-		}
-		if( vertex ) {
-			if( mpos != null ) cst.push("#define hasPos");
-			if( hasSkin ) {
-				cst.push("#define hasSkin");
-				cst.push("const int maxSkinMatrixes = " + maxSkinMatrixes+";");
-			}
-			if( uvScale != null ) cst.push("#define hasUVScale");
-			if( uvDelta != null ) cst.push("#define hasUVDelta");
-			if( hasZBias ) cst.push("#define hasZBias");
-		} else {
-			if( killAlpha ) cst.push("#define killAlpha");
-			if( colorAdd != null ) cst.push("#define hasColorAdd");
-			if( colorMul != null ) cst.push("#define hasColorMul");
-			if( colorMatrix != null ) cst.push("#define hasColorMatrix");
-			if( hasAlphaMap ) cst.push("#define hasAlphaMap");
-			if( hasGlow ) cst.push("#define hasGlow");
-			if( hasVertexColorAdd || lightSystem != null ) cst.push("#define hasFragColor");
-		}
-		return cst.join("\n");
-	}
-
-	static var VERTEX = "
-	
-		attribute vec3 pos;
-		attribute vec2 uv;
-		#if hasLightSystem
-		attribute vec3 normal;
-		#end
-		#if hasVertexColor
-		attribute vec3 color;
-		#end
-		#if hasVertexColorAdd
-		attribute vec3 colorAdd;
-		#end
-		#if hasBlend
-		attribute float blending;
-		#end
-		#if hasSkin
-		uniform mat4 skinMatrixes[maxSkinMatrixes];
-		#end
-
-		uniform mat4 mpos;
-		uniform mat4 mproj;
-		uniform float zBias;
-		uniform vec2 uvScale;
-		uniform vec2 uvDelta;
-		
-		// we can't use Array of structures in GLSL
-		struct LightSystem {
-			vec3 ambient;
-			vec3 dirsDir[numDirLights];
-			vec3 dirsColor[numDirLights];
-			vec3 pointsPos[numPointLights];
-			vec3 pointsColor[numPointLights];
-			vec3 pointsAtt[numPointLights];
-		};
-		uniform LightSystem lights;
-			
-		uniform mat4 shadowLightProj;
-		uniform mat4 shadowLightCenter;
-
-		uniform vec4 fog;
-		
-		varying lowp vec2 tuv;
-		varying lowp vec3 tcolor;
-		varying lowp vec3 acolor;
-		varying mediump float talpha;
-		varying mediump float tblend;
-		varying mediump vec4 tshadowPos;
-		
-		uniform mat3 mposInv;
-
-		void main(void) {
-			vec4 tpos = vec4(pos, 1.0);
-			#if hasSkin
-//				tpos.xyz = tpos * input.weights.x * skinMatrixes[input.indexes.x * (255 * 3)] + tpos * input.weights.y * skinMatrixes[input.indexes.y * (255 * 3)] + tpos * input.weights.z * skinMatrixes[input.indexes.z * (255 * 3)];
-			#elseif hasPos
-				tpos = mpos * tpos;
-			#end
-			vec4 ppos = mproj * tpos;
-			#if hasZBias
-				ppos.z += zBias;
-			#end
-			gl_Position = ppos;
-			vec2 t = uv;
-			#if hasUVScale
-				t *= uvScale;
-			#end
-			#if hasUVDelta
-				t += uvDelta;
-			#end
-			tuv = t;
-			#if hasLightSystem
-				vec3 n = normal;
-				#if hasPos
-					n = mat3(mpos) * n;
-				#elseif hasSkin
-					//n = n * input.weights.x * skinMatrixes[input.indexes.x * (255 * 3)] + n * input.weights.y * skinMatrixes[input.indexes.y * (255 * 3)] + n * input.weights.z * skinMatrixes[input.indexes.z * (255 * 3)];
-					#if hasPos
-						n = mposInv * n;
-					#end
-				#end
-				n = normalize(n);
-				vec3 col = lights.ambient;
-				for(int i = 0; i < numDirLights; i++ )
-					col += lights.dirsColor[i] * max(dot(n,-lights.dirsDir[i]),0.);
-				for(int i = 0; i < numPointLights; i++ ) {
-					vec3 d = tpos.xyz - lights.pointsPos[i];
-					float dist2 = dot(d,d);
-					float dist = sqrt(dist2);
-					col += lights.pointsColor[i] * (max(dot(n,d),0.) / dot(lights.pointsAtt[i],vec3(dist,dist2,dist2*dist)));
-				}
-				#if hasVertexColor
-					tcolor = col * color;
-				#else
-					tcolor = col;
-				#end
-			#elseif hasVertexColor
-				tcolor = color;
-			#end
-			#if hasVertexColorAdd
-				acolor = colorAdd;
-			#end
-			#if hasFog
-				vec3 dist = tpos.xyz - fog.xyz;
-				talpha = (fog.w * dist.dot(dist).rsqrt()).min(1);
-			#end
-			#if hasBlend
-				tblend = blending;
-			#end
-			#if hasShadowMap
-				tshadowPos = shadowLightCenter * shadowLightProj * tpos;
-			#end
-		}
-
-	";
-	
-	static var FRAGMENT = "
-	
-		varying lowp vec2 tuv;
-		varying lowp vec3 tcolor;
-		varying lowp vec3 acolor;
-		varying mediump float talpha;
-		varying mediump float tblend;
-		varying mediump vec4 tshadowPos;
-
-		uniform sampler2D tex;
-		uniform lowp vec4 colorAdd;
-		uniform lowp vec4 colorMul;
-		uniform mediump mat4 colorMatrix;
-		
-		uniform lowp float killAlphaThreshold;
-
-		#if hasAlphaMap
-		uniform sampler2D alphaMap;
-		#end
-		
-		#if hasBlend
-		uniform sampler2D blendTexture;
-		#end
-
-		#if hasGlow
-		uniform sampler2D glowTexture;
-		uniform float glowAmount;
-		#end
-
-		#if hasShadowMap
-		uniform sampler2D shadowTexture;
-		uniform vec4 shadowColor;
-		#end
-
-		void main(void) {
-			lowp vec4 c = texture2D(tex, tuv);
-			#if hasFog
-				c.a *= talpha;
-			#end
-			#if hasAlphaMap
-				c.a *= texture2D(alphaMap, tuv).b;
-			#end
-			#if killAlpha
-				if( c.a - killAlphaThreshold ) discard;
-			#end
-			#if hasBlend
-				c.rgb = c.rgb * (1 - tblend) + tblend * texture2D(blendTexture, tuv).rgb;
-			#end
-			#if hasColorAdd
-				c += colorAdd;
-			#end
-			#if hasColorMul
-				c *= colorMul;
-			#end
-			#if hasColorMatrix
-				c = colorMatrix * c;
-			#end
-			#if hasVertexColorAdd
-				c.rgb += acolor;
-			#end
-			#if hasFragColor
-				c.rgb *= tcolor;
-			#end
-			#if hasShadowMap
-				// ESM filtering
-				mediump float shadow = exp( shadowColor.w * (tshadowPos.z - shadowTexture.get(tshadowPos.xy).dot([1, 1 / 255, 1 / (255 * 255), 1 / (255 * 255 * 255)]))).sat();
-				c.rgb *= (1 - shadow) * shadowColor.rgb + shadow.xxx;
-			#end
-			#if hasGlow
-				c.rgb += texture2D(glowTexture,tuv).rgb * glowAmount;
-			#end
-			gl_FragColor = c;
-		}
-
-	";
-
-
-#end
-	
-}
-
 class MeshMaterial extends Material {
 class MeshMaterial extends Material {
 
 
-	var mshader : MeshShader;
-	
-	public var texture : Texture;
-	
-	#if  flash
-	public var glowTexture(get, set) : Texture;
-	public var glowAmount(get, set) : Float;
-	public var glowColor(get, set) : h3d.Vector;
-	#end
-
-	public var useMatrixPos : Bool;
-	public var uvScale(get,set) : Null<h3d.Vector>;
-	public var uvDelta(get,set) : Null<h3d.Vector>;
+	var mshader : h3d.shader.BaseMesh;
+	var textureShader : h3d.shader.Texture;
+	public var texture(get,set) : h3d.mat.Texture;
 
 
-	public var killAlpha(get,set) : Bool;
+	public var color(get, set) : Vector;
+	public var blendMode(default, set) : BlendMode;
 
 
-	public var hasVertexColor(get, set) : Bool;
-	public var hasVertexColorAdd(get,set) : Bool;
-	
-	public var colorAdd(get,set) : Null<h3d.Vector>;
-	public var colorMul(get,set) : Null<h3d.Vector>;
-	public var colorMatrix(get,set) : Null<h3d.Matrix>;
-	
-	public var hasSkin(get,set) : Bool;
-	public var skinMatrixes(get,set) : Array<h3d.Matrix>;
-	
-	public var lightSystem(get, set) : LightSystem;
-	
-	public var alphaMap(get, set): Texture;
-	
-	public var fog(get, set) : h3d.Vector;
-	public var zBias(get, set) : Null<Float>;
-	
-	public var blendTexture(get, set) : Texture;
-	
-	public var killAlphaThreshold(get, set) : Float;
-	
-	
-	public var shadowMap(null, set) : ShadowMap;
-	
-	#if !openfl
-	public var volumeDecal(default, set) : DecalInfos;
-	#end
-	
-	public function new(texture) {
-		mshader = new MeshShader();
+	public function new(?texture) {
+		mshader = new h3d.shader.BaseMesh();
+		blendMode = Normal;
 		super(mshader);
 		super(mshader);
 		this.texture = texture;
 		this.texture = texture;
-		useMatrixPos = true;
-		killAlphaThreshold = 0.001;
-	}
-	
-	override function clone( ?m : Material ) {
-		var m = m == null ? new MeshMaterial(texture) : cast m;
-		super.clone(m);
-		m.useMatrixPos = useMatrixPos;
-		m.uvScale = uvScale;
-		m.uvDelta = uvDelta;
-		m.killAlpha = killAlpha;
-		m.hasVertexColor = hasVertexColor;
-		m.hasVertexColorAdd = hasVertexColorAdd;
-		m.colorAdd = colorAdd;
-		m.colorMul = colorMul;
-		m.colorMatrix = colorMatrix;
-		m.hasSkin = hasSkin;
-		m.skinMatrixes = skinMatrixes;
-		m.lightSystem = lightSystem;
-		m.alphaMap = alphaMap;
-		m.fog = fog;
-		m.zBias = zBias;
-		m.blendTexture = blendTexture;
-		m.killAlphaThreshold = killAlphaThreshold;
-		return m;
-	}
-	
-	override function setup( ctx : h3d.scene.RenderContext ) {
-		mshader.mpos = useMatrixPos ? ctx.localPos : null;
-		mshader.mproj = ctx.camera.m;
-		mshader.tex = texture;
-		#if flash
-		if( mshader.isOutline ) {
-			mshader.outlineProj = new h3d.Vector(ctx.camera.mproj._11, ctx.camera.mproj._22);
-			mshader.cameraPos = ctx.camera.pos;
-		}
-		#end
-	}
-	
-	/**
-		Set the DXT compression access mode for all textures of this material.
-	**/
-	public function setDXTSupport( enable : Bool, alpha = false ) {
-		#if flash
-		if( !enable ) {
-			mshader.isDXT1 = false;
-			mshader.isDXT5 = false;
-		} else {
-			mshader.isDXT1 = !alpha;
-			mshader.isDXT5 = alpha;
-		}
-		#else
-		throw "Not implemented";
-		#end
-	}
-	
-	inline function get_uvScale() {
-		return mshader.uvScale;
 	}
 	}
 
 
-	inline function set_uvScale(v) {
-		return mshader.uvScale = v;
+	inline function get_color() {
+		return mshader.color;
 	}
 	}
 
 
-	inline function get_uvDelta() {
-		return mshader.uvDelta;
+	inline function set_color(v) {
+		return mshader.color = v;
 	}
 	}
 
 
-	inline function set_uvDelta(v) {
-		return mshader.uvDelta = v;
-	}
-
-	inline function get_killAlpha() {
-		return mshader.killAlpha;
-	}
-
-	inline function set_killAlpha(v) {
-		return mshader.killAlpha = v;
-	}
-
-	inline function get_colorAdd() {
-		return mshader.colorAdd;
-	}
-
-	inline function set_colorAdd(v) {
-		return mshader.colorAdd = v;
-	}
-
-	inline function get_colorMul() {
-		return mshader.colorMul;
-	}
-
-	inline function set_colorMul(v) {
-		return mshader.colorMul = v;
-	}
-
-	inline function get_colorMatrix() {
-		return mshader.colorMatrix;
-	}
-
-	inline function set_colorMatrix(v) {
-		return mshader.colorMatrix = v;
-	}
-	
-	inline function get_hasSkin() {
-		return mshader.hasSkin;
-	}
-	
-	inline function set_hasSkin(v) {
-		return mshader.hasSkin = v;
-	}
-
-	inline function get_hasVertexColor() {
-		return mshader.hasVertexColor;
-	}
-	
-	inline function set_hasVertexColor(v) {
-		return mshader.hasVertexColor = v;
-	}
-	
-	inline function get_hasVertexColorAdd() {
-		return mshader.hasVertexColorAdd;
-	}
-	
-	inline function set_hasVertexColorAdd(v) {
-		return mshader.hasVertexColorAdd = v;
-	}
-	
-	inline function get_skinMatrixes() {
-		return mshader.skinMatrixes;
-	}
-	
-	inline function set_skinMatrixes( v : Array<h3d.Matrix> ) {
-		if( v != null && v.length > 35 )
-			throw "Maximum 35 bones are allowed for skinning (has "+v.length+")";
-		return mshader.skinMatrixes = v;
-	}
-	
-	inline function get_lightSystem() : LightSystem {
-		return mshader.lightSystem;
-	}
-
-	inline function set_lightSystem(v:LightSystem) {
-		if( v != null && hasSkin && v.dirs.length + v.points.length > 6 )
-			throw "Maximum 6 lights are allowed with skinning ("+(v.dirs.length+v.points.length)+" set)";
-		return mshader.lightSystem = v;
-	}
-	
-	inline function get_alphaMap() {
-		return mshader.alphaMap;
-	}
-	
-	inline function set_alphaMap(m) {
-		mshader.hasAlphaMap = m != null;
-		return mshader.alphaMap = m;
-	}
-	
-	inline function get_zBias() {
-		return mshader.hasZBias ? mshader.zBias : null;
-	}
-
-	inline function set_zBias(v : Null<Float>) {
-		mshader.hasZBias = v != null;
-		mshader.zBias = v;
-		return v;
-	}
-	
-	inline function get_glowTexture() {
-		return mshader.glowTexture;
-	}
-
-	#if flash
-	inline function set_glowTexture(t) {
-		mshader.hasGlow = t != null;
-		if( t != null && mshader.glowAmount == null ) mshader.glowAmount = new h3d.Vector(1, 1, 1);
-		return mshader.glowTexture = t;
-	}
-	
-	inline function get_glowAmount() {
-		if( mshader.glowAmount == null ) mshader.glowAmount = new h3d.Vector(1, 1, 1);
-		return mshader.glowAmount.x;
-	}
-
-	inline function set_glowAmount(v) {
-		if( mshader.glowAmount == null ) mshader.glowAmount = new h3d.Vector(1, 1, 1);
-		mshader.glowAmount.set(v, v, v);
-		return v;
-	}
-	
-	inline function get_glowColor() {
-		if( mshader.glowAmount == null ) mshader.glowAmount = new h3d.Vector(1, 1, 1);
-		return mshader.glowAmount;
-	}
-
-	inline function set_glowColor(v) {
-		return mshader.glowAmount = v;
-	}
-	#end
-
-	inline function get_fog() {
-		return mshader.fog;
-	}
-
-	inline function set_fog(v) {
-		return mshader.fog = v;
-	}
-	
-	inline function get_blendTexture() {
-		return mshader.blendTexture;
-	}
-	
-	inline function set_blendTexture(v) {
-		mshader.hasBlend = v != null;
-		return mshader.blendTexture = v;
-	}
-	
-	inline function get_killAlphaThreshold() {
-		return mshader.killAlphaThreshold;
-	}
-	
-	inline function set_killAlphaThreshold(v) {
-		return mshader.killAlphaThreshold = v;
-	}
-	
-	inline function set_shadowMap(v:ShadowMap) {
-		if( v != null ) {
-			mshader.hasShadowMap = true;
-			mshader.shadowColor = v.color;
-			mshader.shadowTexture = v.texture;
-			mshader.shadowLightProj = v.lightProj;
-			mshader.shadowLightCenter = v.lightCenter;
-		} else
-			mshader.hasShadowMap = false;
-		return v;
-	}
-	
-	#if !openfl
-	inline function set_volumeDecal( d : DecalInfos ) {
-		if( d != null ) {
-			mshader.isDecal = true;
-			mshader.depthTexture = d.depthTexture;
-			mshader.uvScaleRatio = d.uvScaleRatio;
-			mshader.screenToLocal = d.screenToLocal;
-		} else
-			mshader.isDecal = false;
-		return volumeDecal = d;
+	override function clone( ?m : Material ) : Material {
+		var m = m == null ? new MeshMaterial() : cast m;
+		super.clone(m);
+		m.texture = texture;
+		m.color = color;
+		m.blendMode = blendMode;
+		return m;
 	}
 	}
-	#end
-	
-	#if flash
 
 
-	public var isOutline(get, set) : Bool;
-	public var outlineColor(get, set) : Int;
-	public var outlineSize(get, set) : Float;
-	public var outlinePower(get, set) : Float;
-	
-	inline function get_isOutline() {
-		return mshader.isOutline;
-	}
-	
-	inline function set_isOutline(v) {
-		return mshader.isOutline = v;
+	function set_blendMode(v:BlendMode) {
+		if( mainPass != null ) {
+			switch( v ) {
+			case Normal:
+				mainPass.blend(One, Zero);
+				mainPass.setPassName("default");
+			case Alpha:
+				mainPass.blend(SrcAlpha, OneMinusSrcAlpha);
+				mainPass.setPassName("alpha");
+			case Add:
+				mainPass.blend(SrcAlpha, One);
+				mainPass.setPassName("additive");
+			case SoftAdd:
+				mainPass.blend(OneMinusDstColor, One);
+				mainPass.setPassName("additive");
+			}
+		}
+		return blendMode = v;
 	}
 	}
 
 
-	inline function get_outlineColor() {
-		return mshader.outlineColor;
-	}
-	
-	inline function set_outlineColor(v) {
-		return mshader.outlineColor = v;
+	function get_texture() {
+		return textureShader == null ? null : textureShader.texture;
 	}
 	}
 
 
-	inline function get_outlineSize() {
-		return mshader.outlineSize;
-	}
-	
-	inline function set_outlineSize(v) {
-		return mshader.outlineSize = v;
+	function set_texture(t) {
+		if( t == null ) {
+			if( textureShader != null ) {
+				mainPass.removeShader(textureShader);
+				textureShader = null;
+			}
+		} else {
+			if( textureShader == null ) {
+				textureShader = new h3d.shader.Texture();
+				mainPass.addShader(textureShader);
+			}
+			textureShader.texture = t;
+		}
+		return t;
 	}
 	}
 
 
-	inline function get_outlinePower() {
-		return mshader.outlinePower;
-	}
-	
-	inline function set_outlinePower(v) {
-		return mshader.outlinePower = v;
-	}
-	
-	public function setColorMap( texture, ?matrix ) {
-		mshader.hasColorMap = texture != null;
-		mshader.colorMap = texture;
-		mshader.colorMapMatrix = matrix;
-	}
-	
-	public function enableSmoothEdges( factor : Float, depthTexture ) {
-		mshader.smoothEdges = true;
-		mshader.smoothFactor = factor;
-		mshader.depthTexture = depthTexture;
-	}
-	
-	#end
 }
 }

+ 0 - 168
h3d/mat/PartMaterial.hx

@@ -1,168 +0,0 @@
-package h3d.mat;
-
-private class PartShader extends h3d.impl.Shader {
-
-#if flash
-	static var SRC = {
-
-		var input : {
-			pos : Float3,
-			uv : Float2,
-			alpha : Float,
-			frame : Float,
-			rotation : Float,
-			size : Float,
-		};
-		
-		var tuv : Float2;
-		var talpha : Float;
-		var partSize : Float2;
-		var frameCount : Float;
-		
-		var hasRotation : Bool;
-		var hasSize : Bool;
-
-		function vertex( mpos : M34, mproj : Matrix ) {
-			var tpos = input.pos.xyzw;
-			tpos.xyz = input.pos.xyzw * mpos;
-			var tmp = tpos * mproj;
-			var rpos = input.uv - 0.5;
-			if( hasRotation ) {
-				var cr = input.rotation.cos();
-				var sr = input.rotation.sin();
-				var tmp = rpos.x * cr + rpos.y * sr;
-				rpos.y = rpos.y * cr - rpos.x * sr;
-				rpos.x = tmp;
-			}
-			tmp.xy += rpos * (if( hasSize ) input.size * partSize else partSize);
-			out = tmp;
-			tuv = if( frameCount != null ) [input.uv.x*frameCount + input.frame,input.uv.y] else input.uv;
-			talpha = input.alpha;
-		}
-		
-		var killAlpha : Bool;
-		var killAlphaThreshold : Float;
-		
-		function fragment( tex : Texture, colorAdd : Float4, colorMul : Float4, colorMatrix : M44 ) {
-			var c = tex.get(tuv.xy);
-			if( killAlpha ) kill(c.a - killAlphaThreshold);
-			if( colorAdd != null ) c += colorAdd;
-			if( colorMul != null ) c = c * colorMul;
-			if( colorMatrix != null ) c = c * colorMatrix;
-			c.a *= talpha;
-			out = c;
-		}
-	
-	}
-
-#else
-
-	static var VERTEX = "TODO";
-	static var FRAGMENT = "TODO";
-	
-	
-	// TODO
-	public var killAlpha : Bool;
-	public var killAlphaThreshold : Float;
-	public var colorAdd : h3d.Vector;
-	public var colorMul : h3d.Vector;
-	public var colorMatrix : h3d.Matrix;
-	public var mpos : h3d.Matrix;
-	public var mproj : h3d.Matrix;
-	public var hasRotation : Bool;
-	public var hasSize : Bool;
-	public var partSize : h3d.Vector;
-	public var frameCount : Null<Float>;
-	public var tex : h3d.mat.Texture;
-
-#end
-
-}
-
-class PartMaterial extends Material {
-	
-	var pshader : PartShader;
-
-	public var texture : Texture;
-	public var killAlpha(get,set) : Bool;
-	public var killAlphaThreshold(get, set) : Float;
-
-	public var colorAdd(get,set) : Null<h3d.Vector>;
-	public var colorMul(get,set) : Null<h3d.Vector>;
-	public var colorMatrix(get,set) : Null<h3d.Matrix>;
-
-	public function new(texture) {
-		pshader = new PartShader();
-		super(pshader);
-		this.texture = texture;
-		blend(SrcAlpha, One);
-		culling = None;
-		depthWrite = false;
-		renderPass = 1;
-	}
-	
-	override function clone( ?m : Material ) {
-		var m = m == null ? new PartMaterial(texture) : cast m;
-		super.clone(m);
-		m.killAlpha = killAlpha;
-		m.colorAdd = colorAdd;
-		m.colorMul = colorMul;
-		m.colorMatrix = colorMatrix;
-		return m;
-	}
-
-	override function setup( ctx : h3d.scene.RenderContext ) {
-		pshader.mpos = ctx.localPos;
-		pshader.mproj = ctx.camera.m;
-		pshader.tex = texture;
-	}
-	
-	public function init( sizeX : Float, sizeY : Float, frameCount : Int, hasRotation, hasSize ) {
-		pshader.hasRotation = hasRotation;
-		pshader.hasSize = hasSize;
-		pshader.partSize.x = sizeX;
-		pshader.partSize.y = sizeY;
-		pshader.frameCount = frameCount <= 1 ? null : 1 / frameCount;
-	}
-		
-	inline function get_killAlpha() {
-		return pshader.killAlpha;
-	}
-
-	inline function set_killAlpha(v) {
-		return pshader.killAlpha = v;
-	}
-
-	inline function get_colorAdd() {
-		return pshader.colorAdd;
-	}
-
-	inline function set_colorAdd(v) {
-		return pshader.colorAdd = v;
-	}
-
-	inline function get_colorMul() {
-		return pshader.colorMul;
-	}
-
-	inline function set_colorMul(v) {
-		return pshader.colorMul = v;
-	}
-
-	inline function get_colorMatrix() {
-		return pshader.colorMatrix;
-	}
-
-	inline function set_colorMatrix(v) {
-		return pshader.colorMatrix = v;
-	}
-	
-	inline function get_killAlphaThreshold() {
-		return pshader.killAlphaThreshold;
-	}
-	
-	inline function set_killAlphaThreshold(v) {
-		return pshader.killAlphaThreshold = v;
-	}
-	
-}

+ 131 - 0
h3d/mat/Pass.hx

@@ -0,0 +1,131 @@
+package h3d.mat;
+import h3d.mat.Data;
+
+@:allow(h3d.mat.Material)
+@:build(hxd.impl.BitsBuilder.build())
+class Pass {
+
+	public var name(default, null) : String;
+	var passId : Int;
+	var bits : Int = 0;
+	var parentPass : Pass;
+	var parentShaders : hxsl.ShaderList;
+	var shaders : hxsl.ShaderList;
+	var nextPass : Pass;
+
+	public var enableLights : Bool;
+	/**
+		Inform the pass system that the parameters will be modified in object draw() command,
+		so they will be manually uploaded by calling RenderContext.uploadParams.
+	**/
+	public var dynamicParameters : Bool;
+
+	@:bits public var culling : Face;
+	@:bits public var depthWrite : Bool;
+	@:bits public var depthTest : Compare;
+	@:bits public var blendSrc : Blend;
+	@:bits public var blendDst : Blend;
+	@:bits public var blendAlphaSrc : Blend;
+	@:bits public var blendAlphaDst : Blend;
+	@:bits public var blendOp : Operation;
+	@:bits public var blendAlphaOp : Operation;
+	@:bits(4) public var colorMask : Int;
+
+	public function new(name, ?shaders, ?parent) {
+		this.parentPass = parent;
+		this.shaders = shaders;
+		setPassName(name);
+		culling = Back;
+		blend(One, Zero);
+		depth(true, Less);
+		blendOp = blendAlphaOp = Add;
+		colorMask = 15;
+	}
+
+	public function setPassName( name : String ) {
+		this.name = name;
+		passId = hxsl.Globals.allocID(name);
+	}
+
+	public inline function blend( src, dst ) {
+		this.blendSrc = src;
+		this.blendAlphaSrc = src;
+		this.blendDst = dst;
+		this.blendAlphaDst = dst;
+	}
+
+	public function depth( write, test ) {
+		this.depthWrite = write;
+		this.depthTest = test;
+	}
+
+	public function setColorMask(r, g, b, a) {
+		this.colorMask = (r?1:0) | (g?2:0) | (b?4:0) | (a?8:0);
+	}
+
+	public function addShader<T:hxsl.Shader>(s:T) : T {
+		shaders = new hxsl.ShaderList(s, shaders);
+		return s;
+	}
+
+	public function removeShader(s) {
+		var sl = shaders, prev = null;
+		while( sl != null ) {
+			if( sl.s == s ) {
+				if( prev == null )
+					shaders = sl.next;
+				else
+					prev.next = sl.next;
+				return true;
+			}
+			prev = sl;
+			sl = sl.next;
+		}
+		return false;
+	}
+
+	public function getShader< T:hxsl.Shader >(t:Class<T>) : T {
+		var s = shaders;
+		while( s != null ) {
+			if( Std.is(s.s, t) )
+				return cast s.s;
+			s = s.next;
+		}
+		return null;
+	}
+
+	public inline function getShaders() {
+		return shaders.iterator();
+	}
+
+	function getShadersRec() {
+		if( parentPass == null || parentShaders == parentPass.shaders )
+			return shaders;
+		// relink to our parent shader list
+		var s = shaders, prev = null;
+		while( s != null && s != parentShaders ) {
+			prev = s;
+			s = s.next;
+		}
+		parentShaders = parentPass.shaders;
+		if( prev == null )
+			shaders = parentShaders;
+		else
+			prev.next = parentShaders;
+		return shaders;
+	}
+
+	public function clone() {
+		var p = new Pass(name, shaders.clone());
+		p.bits = bits;
+		p.enableLights = enableLights;
+		return p;
+	}
+
+	public function getDebugShaderCode( scene : h3d.scene.Scene, toHxsl = true ) {
+		var shader = scene.getPass(name).compileShader(this);
+		var toString = toHxsl ? hxsl.Printer.shaderToString.bind(_, true) : hxsl.GlslOut.toGlsl;
+		return "VERTEX=\n" + toString(shader.vertex.data) + "\n\nFRAGMENT=\n" + toString(shader.fragment.data);
+	}
+
+}

+ 26 - 19
h3d/mat/Texture.hx

@@ -5,7 +5,7 @@ import h3d.mat.Data;
 class Texture {
 class Texture {
 
 
 	static var UID = 0;
 	static var UID = 0;
-	
+
 	var t : h3d.impl.Driver.Texture;
 	var t : h3d.impl.Driver.Texture;
 	var mem : h3d.impl.MemoryManager;
 	var mem : h3d.impl.MemoryManager;
 	#if debug
 	#if debug
@@ -28,7 +28,7 @@ class Texture {
 		it's been free because of lack of memory.
 		it's been free because of lack of memory.
 	**/
 	**/
 	public var realloc : Void -> Void;
 	public var realloc : Void -> Void;
-	
+
 	public function new(w, h, ?flags : Array<TextureFlags>, ?allocPos : h3d.impl.AllocPos ) {
 	public function new(w, h, ?flags : Array<TextureFlags>, ?allocPos : h3d.impl.AllocPos ) {
 		var engine = h3d.Engine.getCurrent();
 		var engine = h3d.Engine.getCurrent();
 		this.mem = engine.mem;
 		this.mem = engine.mem;
@@ -42,8 +42,8 @@ class Texture {
 		while( tw < w ) tw <<= 1;
 		while( tw < w ) tw <<= 1;
 		while( th < h) th <<= 1;
 		while( th < h) th <<= 1;
 		if( tw != w || th != h )
 		if( tw != w || th != h )
-			this.flags.set(IsRectangle);
-			
+			this.flags.set(IsNPOT);
+
 		// make the texture disposable if we're out of memory
 		// make the texture disposable if we're out of memory
 		// this can be disabled after allocation by reseting realloc
 		// this can be disabled after allocation by reseting realloc
 		if( this.flags.has(Target) ) realloc = function() { };
 		if( this.flags.has(Target) ) realloc = function() { };
@@ -59,16 +59,23 @@ class Texture {
 		#end
 		#end
 		alloc();
 		alloc();
 	}
 	}
-	
+
 	public function alloc() {
 	public function alloc() {
 		if( t == null )
 		if( t == null )
 			mem.allocTexture(this);
 			mem.allocTexture(this);
 	}
 	}
-	
+
 	function toString() {
 	function toString() {
-		return name+" "+width+"x"+height;
+		var str = name;
+		if( name == null ) {
+			str = "Texture_" + id;
+			#if debug
+			if( allocPos != null ) str += "(" + allocPos.className+":" + allocPos.lineNumber + ")";
+			#end
+		}
+		return str+"("+width+"x"+height+")";
 	}
 	}
-	
+
 	public function setName(n) {
 	public function setName(n) {
 		name = n;
 		name = n;
 	}
 	}
@@ -84,13 +91,13 @@ class Texture {
 		bits = (bits & ~(3 << 3)) | (Type.enumIndex(f) << 3);
 		bits = (bits & ~(3 << 3)) | (Type.enumIndex(f) << 3);
 		return filter = f;
 		return filter = f;
 	}
 	}
-	
+
 	function set_wrap(w:Wrap) {
 	function set_wrap(w:Wrap) {
 		bits |= 0x80000;
 		bits |= 0x80000;
 		bits = (bits & ~(3 << 6)) | (Type.enumIndex(w) << 6);
 		bits = (bits & ~(3 << 6)) | (Type.enumIndex(w) << 6);
 		return wrap = w;
 		return wrap = w;
 	}
 	}
-	
+
 	inline function hasDefaultFlags() {
 	inline function hasDefaultFlags() {
 		return bits & 0x80000 == 0;
 		return bits & 0x80000 == 0;
 	}
 	}
@@ -98,21 +105,21 @@ class Texture {
 	public inline function isDisposed() {
 	public inline function isDisposed() {
 		return t == null && realloc == null;
 		return t == null && realloc == null;
 	}
 	}
-	
+
 	public function resize(width, height) {
 	public function resize(width, height) {
 		dispose();
 		dispose();
-		
+
 		var tw = 1, th = 1;
 		var tw = 1, th = 1;
 		while( tw < width ) tw <<= 1;
 		while( tw < width ) tw <<= 1;
 		while( th < height ) th <<= 1;
 		while( th < height ) th <<= 1;
 		if( tw != width || th != height )
 		if( tw != width || th != height )
-			this.flags.set(IsRectangle);
+			this.flags.set(IsNPOT);
 		else
 		else
-			this.flags.unset(IsRectangle);
+			this.flags.unset(IsNPOT);
 
 
 		this.width = width;
 		this.width = width;
 		this.height = height;
 		this.height = height;
-		
+
 		if( !flags.has(NoAlloc) )
 		if( !flags.has(NoAlloc) )
 			alloc();
 			alloc();
 	}
 	}
@@ -131,7 +138,7 @@ class Texture {
 		uploadPixels(p);
 		uploadPixels(p);
 		p.dispose();
 		p.dispose();
 	}
 	}
-	
+
 	public function uploadBitmap( bmp : hxd.BitmapData, mipLevel = 0, side = 0 ) {
 	public function uploadBitmap( bmp : hxd.BitmapData, mipLevel = 0, side = 0 ) {
 		alloc();
 		alloc();
 		mem.driver.uploadTextureBitmap(this, bmp, mipLevel, side);
 		mem.driver.uploadTextureBitmap(this, bmp, mipLevel, side);
@@ -150,19 +157,19 @@ class Texture {
 			#end
 			#end
 		}
 		}
 	}
 	}
-	
+
 	public static function fromBitmap( bmp : hxd.BitmapData, ?allocPos : h3d.impl.AllocPos ) {
 	public static function fromBitmap( bmp : hxd.BitmapData, ?allocPos : h3d.impl.AllocPos ) {
 		var t = new Texture(bmp.width, bmp.height, allocPos);
 		var t = new Texture(bmp.width, bmp.height, allocPos);
 		t.uploadBitmap(bmp);
 		t.uploadBitmap(bmp);
 		return t;
 		return t;
 	}
 	}
-	
+
 	public static function fromPixels( pixels : hxd.Pixels, ?allocPos : h3d.impl.AllocPos ) {
 	public static function fromPixels( pixels : hxd.Pixels, ?allocPos : h3d.impl.AllocPos ) {
 		var t = new Texture(pixels.width, pixels.height, allocPos);
 		var t = new Texture(pixels.width, pixels.height, allocPos);
 		t.uploadPixels(pixels);
 		t.uploadPixels(pixels);
 		return t;
 		return t;
 	}
 	}
-	
+
 	static var COLOR_CACHE = new Map<Int,h3d.mat.Texture>();
 	static var COLOR_CACHE = new Map<Int,h3d.mat.Texture>();
 	/**
 	/**
 		Creates a 1x1 texture using the ARGB color passed as parameter.
 		Creates a 1x1 texture using the ARGB color passed as parameter.

+ 20 - 20
h3d/parts/Data.hx

@@ -26,34 +26,34 @@ enum Shape {
 }
 }
 
 
 class ValueXYZ {
 class ValueXYZ {
-	
+
 	public var vx : Value;
 	public var vx : Value;
 	public var vy : Value;
 	public var vy : Value;
 	public var vz : Value;
 	public var vz : Value;
-	
+
 	public function new(x, y, z) {
 	public function new(x, y, z) {
 		this.vx = x;
 		this.vx = x;
 		this.vy = y;
 		this.vy = y;
 		this.vz = z;
 		this.vz = z;
 	}
 	}
-	
+
 }
 }
 
 
 class ColorKey {
 class ColorKey {
-	
+
 	public var time : Float;
 	public var time : Float;
 	public var r : Float;
 	public var r : Float;
 	public var g : Float;
 	public var g : Float;
 	public var b : Float;
 	public var b : Float;
 	public var next : ColorKey;
 	public var next : ColorKey;
-	
+
 	public function new(time, r, g, b) {
 	public function new(time, r, g, b) {
 		this.time = time;
 		this.time = time;
 		this.r = r;
 		this.r = r;
 		this.g = g;
 		this.g = g;
 		this.b = b;
 		this.b = b;
 	}
 	}
-	
+
 }
 }
 
 
 enum BlendMode {
 enum BlendMode {
@@ -74,7 +74,7 @@ interface Randomized {
 }
 }
 
 
 class State {
 class State {
-	
+
 	// material
 	// material
 	public var textureName : String;
 	public var textureName : String;
 	public var frames : Array<h2d.Tile>;
 	public var frames : Array<h2d.Tile>;
@@ -82,7 +82,7 @@ class State {
 	public var sortMode : SortMode;
 	public var sortMode : SortMode;
 	public var is3D : Bool;
 	public var is3D : Bool;
 	public var isAlphaMap : Bool;
 	public var isAlphaMap : Bool;
-	
+
 	// emit
 	// emit
 	public var loop	: Bool;
 	public var loop	: Bool;
 	public var emitRate : Value;
 	public var emitRate : Value;
@@ -98,7 +98,7 @@ class State {
 	public var globalLife : Float;
 	public var globalLife : Float;
 	public var globalSpeed : Value;
 	public var globalSpeed : Value;
 	public var globalSize : Value;
 	public var globalSize : Value;
-	
+
 	// particle globals
 	// particle globals
 	public var life : Value;
 	public var life : Value;
 	public var size : Value;
 	public var size : Value;
@@ -106,28 +106,28 @@ class State {
 	public var rotation : Value;
 	public var rotation : Value;
 	public var speed : Value;
 	public var speed : Value;
 	public var gravity : Value;
 	public var gravity : Value;
-	
+
 	// effects
 	// effects
 	public var force : Null<ValueXYZ>;
 	public var force : Null<ValueXYZ>;
 	public var colors : Null<Array<{ time : Float, color : Int }>>;
 	public var colors : Null<Array<{ time : Float, color : Int }>>;
 	public var light : Value;
 	public var light : Value;
 	public var alpha : Value;
 	public var alpha : Value;
-	
+
 	// collide
 	// collide
 	public var collide : Bool;
 	public var collide : Bool;
 	public var collideKill : Bool;
 	public var collideKill : Bool;
 	public var bounce : Float;
 	public var bounce : Float;
-	
+
 	// animation
 	// animation
 	public var frame : Null<Value>;
 	public var frame : Null<Value>;
-	
+
 	// extra
 	// extra
 	public var delay : Float;
 	public var delay : Float;
 	public var update : Particle -> Void;
 	public var update : Particle -> Void;
-	
+
 	public function new() {
 	public function new() {
 	}
 	}
-	
+
 	public function setDefaults() {
 	public function setDefaults() {
 		// material
 		// material
 		textureName = null;
 		textureName = null;
@@ -168,7 +168,7 @@ class State {
 		// extra
 		// extra
 		delay = 0.;
 		delay = 0.;
 	}
 	}
-	
+
 	public function scale( val : Value, v : Float ) {
 	public function scale( val : Value, v : Float ) {
 		return switch( val ) {
 		return switch( val ) {
 		case VConst(c): VConst(c * v);
 		case VConst(c): VConst(c * v);
@@ -181,7 +181,7 @@ class State {
 		case VCustom(f): VCustom(function(p) return f(p) * v);
 		case VCustom(f): VCustom(function(p) return f(p) * v);
 		}
 		}
 	}
 	}
-	
+
 	public static inline function eval( v : Value, time : Float, r : Randomized, p : Particle ) : Float {
 	public static inline function eval( v : Value, time : Float, r : Randomized, p : Particle ) : Float {
 		return switch( v ) {
 		return switch( v ) {
 		case VConst(c): c;
 		case VConst(c): c;
@@ -204,7 +204,7 @@ class State {
 
 
 	public static var defPartAlpha = hxd.res.Embed.getResource("h3d/parts/defaultAlpha.png");
 	public static var defPartAlpha = hxd.res.Embed.getResource("h3d/parts/defaultAlpha.png");
 	public static var defPart = hxd.res.Embed.getResource("h3d/parts/default.png");
 	public static var defPart = hxd.res.Embed.getResource("h3d/parts/default.png");
-	
+
 	public function initFrames() {
 	public function initFrames() {
 		if( textureName == null ) {
 		if( textureName == null ) {
 			var t = switch( blendMode ) {
 			var t = switch( blendMode ) {
@@ -227,7 +227,7 @@ class State {
 			}
 			}
 		}
 		}
 	}
 	}
-	
+
 	public static function load( b : haxe.io.Bytes, loadTexture : String -> h2d.Tile ) {
 	public static function load( b : haxe.io.Bytes, loadTexture : String -> h2d.Tile ) {
 		var state : State = haxe.Unserializer.run(b.toString());
 		var state : State = haxe.Unserializer.run(b.toString());
 		if( state.textureName != null ) {
 		if( state.textureName != null ) {
@@ -238,5 +238,5 @@ class State {
 		state.initFrames();
 		state.initFrames();
 		return state;
 		return state;
 	}
 	}
-	
+
 }
 }

+ 71 - 71
h3d/parts/Editor.hx

@@ -25,7 +25,7 @@ private typedef Curve = {
 }
 }
 
 
 class Editor extends h2d.Sprite implements Randomized {
 class Editor extends h2d.Sprite implements Randomized {
-	
+
 	var emit : Emitter;
 	var emit : Emitter;
 	var state : State;
 	var state : State;
 	var curState : String;
 	var curState : String;
@@ -53,7 +53,7 @@ class Editor extends h2d.Sprite implements Randomized {
 	public var currentFilePath : String;
 	public var currentFilePath : String;
 	public var autoLoop : Bool = true;
 	public var autoLoop : Bool = true;
 	public var moveEmitter(default,set) : Bool = false;
 	public var moveEmitter(default,set) : Bool = false;
-	
+
 	static var CURVES : Array<{ name : String, f : Curve -> Data.Value }> = [
 	static var CURVES : Array<{ name : String, f : Curve -> Data.Value }> = [
 		{ name : "Const", f : function(c) return VConst(c.min) },
 		{ name : "Const", f : function(c) return VConst(c.min) },
 		{ name : "Linear", f : function(c) return VLinear(c.min, c.max - c.min) },
 		{ name : "Linear", f : function(c) return VLinear(c.min, c.max - c.min) },
@@ -64,12 +64,12 @@ class Editor extends h2d.Sprite implements Randomized {
 		{ name : "Random", f : function(c) return VRandom(c.min, c.max - c.min, c.converge) },
 		{ name : "Random", f : function(c) return VRandom(c.min, c.max - c.min, c.converge) },
 	];
 	];
 
 
-	
+
 	static function solvePoly( c : Curve ) {
 	static function solvePoly( c : Curve ) {
 
 
 		if( c.points == null )
 		if( c.points == null )
 			c.points = [new h2d.col.Point(0, c.min/c.max), new h2d.col.Point(1, 1)];
 			c.points = [new h2d.col.Point(0, c.min/c.max), new h2d.col.Point(1, 1)];
-		
+
 		var xvals = [for( p in c.points ) p.x];
 		var xvals = [for( p in c.points ) p.x];
 		var yvals = [for( p in c.points ) p.y * c.max];
 		var yvals = [for( p in c.points ) p.y * c.max];
 		var pts = [];
 		var pts = [];
@@ -83,14 +83,14 @@ class Editor extends h2d.Sprite implements Randomized {
 			beta.pop();
 			beta.pop();
 		return VPoly(beta,pts);
 		return VPoly(beta,pts);
 	}
 	}
-	
+
 	public function new(emiter, ?parent) {
 	public function new(emiter, ?parent) {
 		super(parent);
 		super(parent);
 		this.emit = emiter;
 		this.emit = emiter;
 		init();
 		init();
 		setState(emit.state);
 		setState(emit.state);
 	}
 	}
-	
+
 	public dynamic function onTextureSelect() {
 	public dynamic function onTextureSelect() {
 		hxd.File.browse(function(sel) {
 		hxd.File.browse(function(sel) {
 			sel.load(function(bytes) {
 			sel.load(function(bytes) {
@@ -102,20 +102,20 @@ class Editor extends h2d.Sprite implements Randomized {
 			fileTypes : [{ name : "Images", extensions : ["png","jpg","jpeg","gif"] }],
 			fileTypes : [{ name : "Images", extensions : ["png","jpg","jpeg","gif"] }],
 		});
 		});
 	}
 	}
-	
+
 	public function changeTexture( name : String, t : h2d.Tile ) {
 	public function changeTexture( name : String, t : h2d.Tile ) {
 		state.textureName = name;
 		state.textureName = name;
 		curState = null; // force reload (if texture was changed)
 		curState = null; // force reload (if texture was changed)
 		setTexture(t);
 		setTexture(t);
 		buildUI();
 		buildUI();
 	}
 	}
-	
+
 	function set_moveEmitter(v) {
 	function set_moveEmitter(v) {
 		this.moveEmitter = v;
 		this.moveEmitter = v;
 		buildUI();
 		buildUI();
 		return v;
 		return v;
 	}
 	}
-	
+
 	public dynamic function loadTexture( textureName : String ) : h2d.Tile {
 	public dynamic function loadTexture( textureName : String ) : h2d.Tile {
 		var bytes = null;
 		var bytes = null;
 		try {
 		try {
@@ -128,7 +128,7 @@ class Editor extends h2d.Sprite implements Randomized {
 		}
 		}
 		return bytes == null ? null : hxd.res.Any.fromBytes(textureName,bytes).toTile();
 		return bytes == null ? null : hxd.res.Any.fromBytes(textureName,bytes).toTile();
 	}
 	}
-	
+
 	public dynamic function onLoad() {
 	public dynamic function onLoad() {
 		hxd.File.browse(function(sel) {
 		hxd.File.browse(function(sel) {
 			currentFilePath = sel.fileName;
 			currentFilePath = sel.fileName;
@@ -151,7 +151,7 @@ class Editor extends h2d.Sprite implements Randomized {
 			fileTypes : [{ name : "Particle Effect", extensions : ["p"] }],
 			fileTypes : [{ name : "Particle Effect", extensions : ["p"] }],
 		});
 		});
 	}
 	}
-	
+
 	public dynamic function onSave( saveData ) {
 	public dynamic function onSave( saveData ) {
 		if( currentFilePath != null )
 		if( currentFilePath != null )
 			try {
 			try {
@@ -166,7 +166,7 @@ class Editor extends h2d.Sprite implements Randomized {
 			saveFileName : function(path) currentFilePath = path,
 			saveFileName : function(path) currentFilePath = path,
 		});
 		});
 	}
 	}
-	
+
 	public function setState(s) {
 	public function setState(s) {
 		undo = [];
 		undo = [];
 		redo = [];
 		redo = [];
@@ -184,7 +184,7 @@ class Editor extends h2d.Sprite implements Randomized {
 		buildUI();
 		buildUI();
 		emit.reset();
 		emit.reset();
 	}
 	}
-	
+
 	override function onAlloc() {
 	override function onAlloc() {
 		super.onAlloc();
 		super.onAlloc();
 		getScene().addEventListener(onEvent);
 		getScene().addEventListener(onEvent);
@@ -194,7 +194,7 @@ class Editor extends h2d.Sprite implements Randomized {
 		super.onDelete();
 		super.onDelete();
 		getScene().addEventListener(onEvent);
 		getScene().addEventListener(onEvent);
 	}
 	}
-	
+
 	var time : Float = 0.;
 	var time : Float = 0.;
 	public dynamic function onMoveEmitter(dt:Float) {
 	public dynamic function onMoveEmitter(dt:Float) {
 		time += dt * 0.03 * 60;
 		time += dt * 0.03 * 60;
@@ -203,7 +203,7 @@ class Editor extends h2d.Sprite implements Randomized {
 		emit.y = Math.sin(time * 0.5) * r;
 		emit.y = Math.sin(time * 0.5) * r;
 		emit.z = (Math.cos(time * 1.3) * Math.sin(time * 1.5) + 1) * r;
 		emit.z = (Math.cos(time * 1.3) * Math.sin(time * 1.5) + 1) * r;
 	}
 	}
-	
+
 	function onEvent( e : hxd.Event ) {
 	function onEvent( e : hxd.Event ) {
 		function loadHistory( h : History ) {
 		function loadHistory( h : History ) {
 			curState = h.state;
 			curState = h.state;
@@ -238,7 +238,7 @@ class Editor extends h2d.Sprite implements Randomized {
 		default:
 		default:
 		}
 		}
 	}
 	}
-	
+
 	function buildUI() {
 	function buildUI() {
 		if( ui != null ) ui.remove();
 		if( ui != null ) ui.remove();
 		ui = h2d.comp.Parser.fromHtml('
 		ui = h2d.comp.Parser.fromHtml('
@@ -247,7 +247,7 @@ class Editor extends h2d.Sprite implements Randomized {
 					* {
 					* {
 						font-size : 12px;
 						font-size : 12px;
 					}
 					}
-					
+
 					h1 {
 					h1 {
 						font-size : 10px;
 						font-size : 10px;
 						color : #BBB;
 						color : #BBB;
@@ -256,7 +256,7 @@ class Editor extends h2d.Sprite implements Randomized {
 					.body {
 					.body {
 						layout : dock;
 						layout : dock;
 					}
 					}
-					
+
 					span {
 					span {
 						padding-top : 2px;
 						padding-top : 2px;
 					}
 					}
@@ -273,7 +273,7 @@ class Editor extends h2d.Sprite implements Randomized {
 						layout : vertical;
 						layout : vertical;
 						margin-bottom : 10px;
 						margin-bottom : 10px;
 					}
 					}
-					
+
 					.sep {
 					.sep {
 						margin-top : -10px;
 						margin-top : -10px;
 						margin-bottom : -2px;
 						margin-bottom : -2px;
@@ -281,11 +281,11 @@ class Editor extends h2d.Sprite implements Randomized {
 						width : 200px;
 						width : 200px;
 						background-color : #555;
 						background-color : #555;
 					}
 					}
-					
+
 					span.label {
 					span.label {
 						width : 97px;
 						width : 97px;
 					}
 					}
-					
+
 					.buttons {
 					.buttons {
 						layout : inline;
 						layout : inline;
 					}
 					}
@@ -293,7 +293,7 @@ class Editor extends h2d.Sprite implements Randomized {
 					.line {
 					.line {
 						layout : horizontal;
 						layout : horizontal;
 					}
 					}
-					
+
 					.ic, .icol {
 					.ic, .icol {
 						icon : url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAAB3RJTUUH3QsHEDot9CONhQAAABd0RVh0U29mdHdhcmUAR0xEUE5HIHZlciAzLjRxhaThAAAACHRwTkdHTEQzAAAAAEqAKR8AAAAEZ0FNQQAAsY8L/GEFAAAABmJLR0QA/wD/AP+gvaeTAAAARklEQVR4nGP4z/CfJMRAmQYIIFbDfwwGJvpPHQ249PxHdtJ/LHKkaMBtBAN+80jRgCMY8GrAFjMMBGMKI+Jor4EU1eRoAADB1BsCKErgdwAAAABJRU5ErkJggg=");
 						icon : url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAAB3RJTUUH3QsHEDot9CONhQAAABd0RVh0U29mdHdhcmUAR0xEUE5HIHZlciAzLjRxhaThAAAACHRwTkdHTEQzAAAAAEqAKR8AAAAEZ0FNQQAAsY8L/GEFAAAABmJLR0QA/wD/AP+gvaeTAAAARklEQVR4nGP4z/CfJMRAmQYIIFbDfwwGJvpPHQ249PxHdtJ/LHKkaMBtBAN+80jRgCMY8GrAFjMMBGMKI+Jor4EU1eRoAADB1BsCKErgdwAAAABJRU5ErkJggg=");
 						icon-top : 1px;
 						icon-top : 1px;
@@ -301,27 +301,27 @@ class Editor extends h2d.Sprite implements Randomized {
 						icon-color : #888;
 						icon-color : #888;
 						padding-left : 20px;
 						padding-left : 20px;
 					}
 					}
-					
+
 					.ic:hover, .icol:hover {
 					.ic:hover, .icol:hover {
 						icon-top : 0px;
 						icon-top : 0px;
 					}
 					}
-					
+
 					.icol {
 					.icol {
 						icon-color : #AAA;
 						icon-color : #AAA;
 						icon : url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAAB3RJTUUH3QsICwAiCSUSqgAAABd0RVh0U29mdHdhcmUAR0xEUE5HIHZlciAzLjRxhaThAAAACHRwTkdHTEQzAAAAAEqAKR8AAAAEZ0FNQQAAsY8L/GEFAAAABmJLR0QA/wD/AP+gvaeTAAAAMklEQVR4nGMwIBEwAPFJWQVMlLHvLSYayRqcdmNBD8tFMNFI1kBa4vMnETD8Z/hPEgIAvqs9dJhBcSIAAAAASUVORK5CYII==");
 						icon : url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAAB3RJTUUH3QsICwAiCSUSqgAAABd0RVh0U29mdHdhcmUAR0xEUE5HIHZlciAzLjRxhaThAAAACHRwTkdHTEQzAAAAAEqAKR8AAAAEZ0FNQQAAsY8L/GEFAAAABmJLR0QA/wD/AP+gvaeTAAAAMklEQVR4nGMwIBEwAPFJWQVMlLHvLSYayRqcdmNBD8tFMNFI1kBa4vMnETD8Z/hPEgIAvqs9dJhBcSIAAAAASUVORK5CYII==");
 					}
 					}
-					
+
 					select, button, input {
 					select, button, input {
 						icon-top : 2px;
 						icon-top : 2px;
 						width : 70px;
 						width : 70px;
 						height : 11px;
 						height : 11px;
 						padding-top : 2px;
 						padding-top : 2px;
 					}
 					}
-					
+
 					.box {
 					.box {
 						width : 95px;
 						width : 95px;
 					}
 					}
-					
+
 					input {
 					input {
 						height : 13px;
 						height : 13px;
 						padding-top : 2px;
 						padding-top : 2px;
@@ -332,39 +332,39 @@ class Editor extends h2d.Sprite implements Randomized {
 						width : 310px;
 						width : 310px;
 						layout : dock;
 						layout : dock;
 					}
 					}
-					
+
 					.curve {
 					.curve {
 						dock : bottom;
 						dock : bottom;
 						layout : vertical;
 						layout : vertical;
 						padding : 5px;
 						padding : 5px;
 						height : 165px;
 						height : 165px;
 					}
 					}
-					
+
 					.curve .title {
 					.curve .title {
 						width : 180px;
 						width : 180px;
 						text-align : right;
 						text-align : right;
 						padding: 2px 10px;
 						padding: 2px 10px;
 						background-color : #202020;
 						background-color : #202020;
 					}
 					}
-					
+
 					.tname {
 					.tname {
 						width : 102px;
 						width : 102px;
 					}
 					}
-					
+
 					#curve {
 					#curve {
 						width : 300px;
 						width : 300px;
 						height : 110px;
 						height : 110px;
 						border : 1px solid #333;
 						border : 1px solid #333;
 					}
 					}
-					
+
 					button.file {
 					button.file {
 						width : 15px;
 						width : 15px;
 					}
 					}
-					
+
 					.curve .val {
 					.curve .val {
 						display : none;
 						display : none;
 					}
 					}
-					
+
 					.m_const .v_min, .m_linear .v_min, .m_pow .v_min, .m_random .v_min, .m_cos .v_min, .m_sin .v_min {
 					.m_const .v_min, .m_linear .v_min, .m_pow .v_min, .m_random .v_min, .m_cos .v_min, .m_sin .v_min {
 						display : block;
 						display : block;
 					}
 					}
@@ -372,23 +372,23 @@ class Editor extends h2d.Sprite implements Randomized {
 					.m_linear .v_max, .m_pow .v_max, .m_random .v_max, .m_cos .v_max, .m_sin .v_max, .m_curve .v_max {
 					.m_linear .v_max, .m_pow .v_max, .m_random .v_max, .m_cos .v_max, .m_sin .v_max, .m_curve .v_max {
 						display : block;
 						display : block;
 					}
 					}
-					
+
 					.m_pow .v_pow {
 					.m_pow .v_pow {
 						display : block;
 						display : block;
 					}
 					}
-					
+
 					.m_cos .v_freq, .m_sin .v_freq {
 					.m_cos .v_freq, .m_sin .v_freq {
 						display : block;
 						display : block;
 					}
 					}
-					
+
 					.m_curve .v_prec, .m_curve .v_clear {
 					.m_curve .v_prec, .m_curve .v_clear {
 						display : block;
 						display : block;
 					}
 					}
-					
+
 					.m_random .v_rnd {
 					.m_random .v_rnd {
 						display : block;
 						display : block;
 					}
 					}
-					
+
 					.v_rnd button {
 					.v_rnd button {
 						width : auto;
 						width : auto;
 					}
 					}
@@ -396,10 +396,10 @@ class Editor extends h2d.Sprite implements Randomized {
 					.v_rnd select {
 					.v_rnd select {
 						width : 40px;
 						width : 40px;
 					}
 					}
-					
+
 				</style>
 				</style>
 				<div class="main panel">
 				<div class="main panel">
-				
+
 					<h1>Global</h1>
 					<h1>Global</h1>
 					<div class="sep"></div>
 					<div class="sep"></div>
 					<div class="col">
 					<div class="col">
@@ -429,7 +429,7 @@ class Editor extends h2d.Sprite implements Randomized {
 							<button class="ic" value="Size" onclick="api.editCurve(\'globalSize\')"/>
 							<button class="ic" value="Size" onclick="api.editCurve(\'globalSize\')"/>
 						</div>
 						</div>
 					</div>
 					</div>
-					
+
 					<h1>Emit</h1>
 					<h1>Emit</h1>
 					<div class="sep"></div>
 					<div class="sep"></div>
 					<div class="col">
 					<div class="col">
@@ -473,7 +473,7 @@ class Editor extends h2d.Sprite implements Randomized {
 							<checkbox checked="${this.moveEmitter}" onchange="api.setMove(this.checked)"/> <span>Move Emitter</span>
 							<checkbox checked="${this.moveEmitter}" onchange="api.setMove(this.checked)"/> <span>Move Emitter</span>
 						</div>
 						</div>
 					</div>
 					</div>
-					
+
 					<h1>Particle</h1>
 					<h1>Particle</h1>
 					<div class="sep"></div>
 					<div class="sep"></div>
 					<div class="col">
 					<div class="col">
@@ -490,7 +490,7 @@ class Editor extends h2d.Sprite implements Randomized {
 							<button class="ic" value="Light" onclick="api.editCurve(\'light\')"/>
 							<button class="ic" value="Light" onclick="api.editCurve(\'light\')"/>
 						</div>
 						</div>
 					</div>
 					</div>
-					
+
 					<h1>Animation</h1>
 					<h1>Animation</h1>
 					<div class="sep"></div>
 					<div class="sep"></div>
 					<div class="col">
 					<div class="col">
@@ -502,7 +502,7 @@ class Editor extends h2d.Sprite implements Randomized {
 							<button disabled="${state.frames == null || state.frames.length <= 1}" class="ic" value="Frame" onclick="api.editCurve(\'frame\')"/>
 							<button disabled="${state.frames == null || state.frames.length <= 1}" class="ic" value="Frame" onclick="api.editCurve(\'frame\')"/>
 						</div>
 						</div>
 					</div>
 					</div>
-					
+
 					<h1>Collide</h1>
 					<h1>Collide</h1>
 					<div class="sep"></div>
 					<div class="sep"></div>
 					<div class="col">
 					<div class="col">
@@ -514,7 +514,7 @@ class Editor extends h2d.Sprite implements Randomized {
 							<checkbox checked="${state.collideKill}" onchange="api.s.collideKill = this.checked"/> <span>Kill</span>
 							<checkbox checked="${state.collideKill}" onchange="api.s.collideKill = this.checked"/> <span>Kill</span>
 						</div>
 						</div>
 					</div>
 					</div>
-					
+
 					<h1>Play</h1>
 					<h1>Play</h1>
 					<div class="sep"></div>
 					<div class="sep"></div>
 					<div style="layout:dock;width:200px">
 					<div style="layout:dock;width:200px">
@@ -620,7 +620,7 @@ class Editor extends h2d.Sprite implements Randomized {
 		cedit.onKeyDown = onCurveEvent;
 		cedit.onKeyDown = onCurveEvent;
 		setCurveMode(curve.mode);
 		setCurveMode(curve.mode);
 	}
 	}
-	
+
 	function toggleSplit() {
 	function toggleSplit() {
 		if( state.frames.length == 1 ) {
 		if( state.frames.length == 1 ) {
 			state.frame = VLinear(0,1);
 			state.frame = VLinear(0,1);
@@ -633,13 +633,13 @@ class Editor extends h2d.Sprite implements Randomized {
 		}
 		}
 		buildUI();
 		buildUI();
 	}
 	}
-	
+
 	function clearCurve() {
 	function clearCurve() {
 		curve.points = [new h2d.col.Point(0, curve.min/curve.max), new h2d.col.Point(1, 1)];
 		curve.points = [new h2d.col.Point(0, curve.min/curve.max), new h2d.col.Point(1, 1)];
 		curve.freq = 2;
 		curve.freq = 2;
 		buildUI();
 		buildUI();
 	}
 	}
-	
+
 	function onCurveEvent( e : hxd.Event ) {
 	function onCurveEvent( e : hxd.Event ) {
 		if( !curve.value.match(VPoly(_)) )
 		if( !curve.value.match(VPoly(_)) )
 			return;
 			return;
@@ -688,7 +688,7 @@ class Editor extends h2d.Sprite implements Randomized {
 		default:
 		default:
 		}
 		}
 	}
 	}
-	
+
 	function editColors() {
 	function editColors() {
 		if( grad != null ) {
 		if( grad != null ) {
 			grad.remove();
 			grad.remove();
@@ -710,7 +710,7 @@ class Editor extends h2d.Sprite implements Randomized {
 			if( !found ) state.colors = null;
 			if( !found ) state.colors = null;
 		};
 		};
 	}
 	}
-	
+
 	function editCurve( name : String, isShape : Bool = false ) {
 	function editCurve( name : String, isShape : Bool = false ) {
 		if( curve.name == name && curve.shape == isShape ) {
 		if( curve.name == name && curve.shape == isShape ) {
 			curve.name = null;
 			curve.name = null;
@@ -735,11 +735,11 @@ class Editor extends h2d.Sprite implements Randomized {
 		rebuildCurve();
 		rebuildCurve();
 		buildUI();
 		buildUI();
 	}
 	}
-	
+
 	public function rand() {
 	public function rand() {
 		return randomValue;
 		return randomValue;
 	}
 	}
-	
+
 	function init() {
 	function init() {
 		var bg = new hxd.BitmapData(300, 110);
 		var bg = new hxd.BitmapData(300, 110);
 		bg.clear(0xFF202020);
 		bg.clear(0xFF202020);
@@ -753,12 +753,12 @@ class Editor extends h2d.Sprite implements Randomized {
 		bg.dispose();
 		bg.dispose();
 		curveTexture = h2d.Tile.fromTexture(new h3d.mat.Texture(512, 512)).sub(0, 0, curveBG.width, curveBG.height);
 		curveTexture = h2d.Tile.fromTexture(new h3d.mat.Texture(512, 512)).sub(0, 0, curveBG.width, curveBG.height);
 	}
 	}
-	
+
 	function rebuildCurve() {
 	function rebuildCurve() {
 		var bmp = new hxd.BitmapData(512, 512);
 		var bmp = new hxd.BitmapData(512, 512);
 		var width = curveTexture.width, height = curveTexture.height;
 		var width = curveTexture.width, height = curveTexture.height;
 		var yMax;
 		var yMax;
-		
+
 		switch( curve.value ) {
 		switch( curve.value ) {
 		case VConst(v): yMax = Math.abs(v);
 		case VConst(v): yMax = Math.abs(v);
 		case VRandom(min, len,_), VLinear(min, len), VPow(min,len,_): yMax = Math.max(Math.abs(min), Math.abs(min + len));
 		case VRandom(min, len,_), VLinear(min, len), VPow(min,len,_): yMax = Math.max(Math.abs(min), Math.abs(min + len));
@@ -774,8 +774,8 @@ class Editor extends h2d.Sprite implements Randomized {
 		case VCustom(_):
 		case VCustom(_):
 			throw "assert";
 			throw "assert";
 		}
 		}
-		
-		
+
+
 		var sy = 1.;
 		var sy = 1.;
 		var k = 0;
 		var k = 0;
 		while( yMax > 100 * curve.incr ) {
 		while( yMax > 100 * curve.incr ) {
@@ -786,7 +786,7 @@ class Editor extends h2d.Sprite implements Randomized {
 		}
 		}
 		sy /= (100 * curve.incr);
 		sy /= (100 * curve.incr);
 		curve.scaleY = sy;
 		curve.scaleY = sy;
-		
+
 		inline function posX(x:Float) {
 		inline function posX(x:Float) {
 			return Std.int(x * (width - 1));
 			return Std.int(x * (width - 1));
 		}
 		}
@@ -809,7 +809,7 @@ class Editor extends h2d.Sprite implements Randomized {
 			}
 			}
 			bmp.setPixel(x, iy0, 0xFFFF0000);
 			bmp.setPixel(x, iy0, 0xFFFF0000);
 		}
 		}
-		
+
 		switch( curve.value ) {
 		switch( curve.value ) {
 		case VPoly(_):
 		case VPoly(_):
 			for( p in curve.points ) {
 			for( p in curve.points ) {
@@ -822,11 +822,11 @@ class Editor extends h2d.Sprite implements Randomized {
 			}
 			}
 		default:
 		default:
 		}
 		}
-		
+
 		curveTexture.getTexture().uploadBitmap(bmp);
 		curveTexture.getTexture().uploadBitmap(bmp);
 		bmp.dispose();
 		bmp.dispose();
 	}
 	}
-	
+
 	function initCurve( v : Value ) {
 	function initCurve( v : Value ) {
 		var c : Curve = {
 		var c : Curve = {
 			value : null,
 			value : null,
@@ -878,7 +878,7 @@ class Editor extends h2d.Sprite implements Randomized {
 		}
 		}
 		return c;
 		return c;
 	}
 	}
-	
+
 	function getShapeValue( value : String ) {
 	function getShapeValue( value : String ) {
 		return switch( [state.shape, value] ) {
 		return switch( [state.shape, value] ) {
 		case [(SLine(v) | SSphere(v) | SCone(v, _) | SDisc(v)), "size"]: v;
 		case [(SLine(v) | SSphere(v) | SCone(v, _) | SDisc(v)), "size"]: v;
@@ -886,7 +886,7 @@ class Editor extends h2d.Sprite implements Randomized {
 		default: VConst(0);
 		default: VConst(0);
 		}
 		}
 	}
 	}
-	
+
 	function rebuildShape( mode : Int, getValue ) {
 	function rebuildShape( mode : Int, getValue ) {
 		var size = getValue("size");
 		var size = getValue("size");
 		state.shape = switch( mode ) {
 		state.shape = switch( mode ) {
@@ -897,12 +897,12 @@ class Editor extends h2d.Sprite implements Randomized {
 		default: throw "Unknown shape #" + mode;
 		default: throw "Unknown shape #" + mode;
 		}
 		}
 	}
 	}
-	
+
 	function setCurShape( mode : Int ) {
 	function setCurShape( mode : Int ) {
 		rebuildShape(mode, getShapeValue);
 		rebuildShape(mode, getShapeValue);
 		buildUI();
 		buildUI();
 	}
 	}
-	
+
 	function setCurveMode( mode : Int ) {
 	function setCurveMode( mode : Int ) {
 		var cm = ui.getElementById("curve").getParent();
 		var cm = ui.getElementById("curve").getParent();
 		cm.removeClass("m_" + CURVES[curve.mode].name.toLowerCase());
 		cm.removeClass("m_" + CURVES[curve.mode].name.toLowerCase());
@@ -915,7 +915,7 @@ class Editor extends h2d.Sprite implements Randomized {
 		} else
 		} else
 			updateCurve();
 			updateCurve();
 	}
 	}
-	
+
 	function updateCurve() {
 	function updateCurve() {
 		curve.value = CURVES[curve.mode].f(curve);
 		curve.value = CURVES[curve.mode].f(curve);
 		if( curve.name != null ) {
 		if( curve.name != null ) {
@@ -932,8 +932,8 @@ class Editor extends h2d.Sprite implements Randomized {
 		curTile = t;
 		curTile = t;
 		state.initFrames();
 		state.initFrames();
 	}
 	}
-	
-	override function sync( ctx : h3d.scene.RenderContext ) {
+
+	override function sync( ctx : h2d.RenderContext ) {
 		// if resized, let's reflow our ui
 		// if resized, let's reflow our ui
 		if( ctx.engine.width != width || ctx.engine.height != height ) {
 		if( ctx.engine.width != width || ctx.engine.height != height ) {
 			ui.refresh();
 			ui.refresh();
@@ -983,15 +983,15 @@ class Editor extends h2d.Sprite implements Randomized {
 			}
 			}
 		} else
 		} else
 			lastPartSeen = null;
 			lastPartSeen = null;
-			
+
 		if( grad != null ) {
 		if( grad != null ) {
 			grad.x = width - 680;
 			grad.x = width - 680;
 			grad.y = height - 190;
 			grad.y = height - 190;
 			grad.colorPicker.x = grad.boxWidth - 180;
 			grad.colorPicker.x = grad.boxWidth - 180;
 			grad.colorPicker.y = -321;
 			grad.colorPicker.y = -321;
 		}
 		}
-			
+
 		super.sync(ctx);
 		super.sync(ctx);
 	}
 	}
-	
+
 }
 }

+ 43 - 40
h3d/parts/Emitter.hx

@@ -13,15 +13,15 @@ class Emitter extends h3d.scene.Object implements Randomized {
 	var rnd : Float;
 	var rnd : Float;
 	var emitCount : Float;
 	var emitCount : Float;
 	var colorMap : ColorKey;
 	var colorMap : ColorKey;
-		
+
 	var head : Particle;
 	var head : Particle;
 	var tail : Particle;
 	var tail : Particle;
 	var pool : Particle;
 	var pool : Particle;
-	
+
 	var tmp : h3d.Vector;
 	var tmp : h3d.Vector;
 	var tmpBuf : hxd.FloatBuffer;
 	var tmpBuf : hxd.FloatBuffer;
 	var curPart : Particle;
 	var curPart : Particle;
-	
+
 	public function new(?state,?parent) {
 	public function new(?state,?parent) {
 		super(parent);
 		super(parent);
 		material = new Material();
 		material = new Material();
@@ -35,7 +35,7 @@ class Emitter extends h3d.scene.Object implements Randomized {
 		}
 		}
 		setState(state);
 		setState(state);
 	}
 	}
-	
+
 	/**
 	/**
 		Offset all existing particles by the given values.
 		Offset all existing particles by the given values.
 	**/
 	**/
@@ -48,7 +48,7 @@ class Emitter extends h3d.scene.Object implements Randomized {
 			p = p.next;
 			p = p.next;
 		}
 		}
 	}
 	}
-	
+
 	public function reset() {
 	public function reset() {
 		while( head != null )
 		while( head != null )
 			kill(head);
 			kill(head);
@@ -56,17 +56,17 @@ class Emitter extends h3d.scene.Object implements Randomized {
 		emitCount = 0;
 		emitCount = 0;
 		rnd = Math.random();
 		rnd = Math.random();
 	}
 	}
-	
+
 	public function setState(s) {
 	public function setState(s) {
 		this.state = s;
 		this.state = s;
 		material.texture = s.frames == null || s.frames.length == 0 ? null : s.frames[0].getTexture();
 		material.texture = s.frames == null || s.frames.length == 0 ? null : s.frames[0].getTexture();
 		switch( s.blendMode ) {
 		switch( s.blendMode ) {
 		case Add:
 		case Add:
-			material.blend(SrcAlpha, One);
+			material.blendMode = Add;
 		case SoftAdd:
 		case SoftAdd:
-			material.blend(OneMinusDstColor, One);
+			material.blendMode = SoftAdd;
 		case Alpha:
 		case Alpha:
-			material.blend(SrcAlpha, OneMinusSrcAlpha);
+			material.blendMode = Alpha;
 		}
 		}
 		colorMap = null;
 		colorMap = null;
 		if( s.colors != null ) {
 		if( s.colors != null ) {
@@ -78,11 +78,11 @@ class Emitter extends h3d.scene.Object implements Randomized {
 			}
 			}
 		}
 		}
 	}
 	}
-	
+
 	inline function eval(v) {
 	inline function eval(v) {
 		return Data.State.eval(v,time, this, curPart);
 		return Data.State.eval(v,time, this, curPart);
 	}
 	}
-	
+
 	public function update(dt:Float) {
 	public function update(dt:Float) {
 		var s = state;
 		var s = state;
 		var old = time;
 		var old = time;
@@ -113,11 +113,11 @@ class Emitter extends h3d.scene.Object implements Randomized {
 		}
 		}
 		curPart = null;
 		curPart = null;
 	}
 	}
-	
+
 	public inline function rand() {
 	public inline function rand() {
 		return Math.random();
 		return Math.random();
 	}
 	}
-	
+
 	function initPosDir( p : Particle ) {
 	function initPosDir( p : Particle ) {
 		switch( state.shape ) {
 		switch( state.shape ) {
 		case SLine(size):
 		case SLine(size):
@@ -171,7 +171,7 @@ class Emitter extends h3d.scene.Object implements Randomized {
 			p.dz = Math.cos(phi);
 			p.dz = Math.cos(phi);
 		}
 		}
 	}
 	}
-	
+
 	function initPart(p:Particle) {
 	function initPart(p:Particle) {
 		initPosDir(p);
 		initPosDir(p);
 		if( !state.emitLocal ) {
 		if( !state.emitLocal ) {
@@ -190,12 +190,12 @@ class Emitter extends h3d.scene.Object implements Randomized {
 		p.time = 0;
 		p.time = 0;
 		p.lifeTimeFactor = 1 / eval(state.life);
 		p.lifeTimeFactor = 1 / eval(state.life);
 	}
 	}
-	
-	public function emit() {
+
+	public function emitPart() {
 		if( posChanged ) syncPos();
 		if( posChanged ) syncPos();
 		return emitParticle();
 		return emitParticle();
 	}
 	}
-	
+
 	function emitParticle() {
 	function emitParticle() {
 		var p;
 		var p;
 		if( pool == null )
 		if( pool == null )
@@ -229,7 +229,7 @@ class Emitter extends h3d.scene.Object implements Randomized {
 		}
 		}
 		return p;
 		return p;
 	}
 	}
-	
+
 	function kill(p:Particle) {
 	function kill(p:Particle) {
 		if( p.prev == null ) head = p.next else p.prev.next = p.next;
 		if( p.prev == null ) head = p.next else p.prev.next = p.next;
 		if( p.next == null ) tail = p.prev else p.next.prev = p.prev;
 		if( p.next == null ) tail = p.prev else p.next.prev = p.prev;
@@ -238,7 +238,7 @@ class Emitter extends h3d.scene.Object implements Randomized {
 		pool = p;
 		pool = p;
 		count--;
 		count--;
 	}
 	}
-	
+
 	function updateParticle( p : Particle, dt : Float ) {
 	function updateParticle( p : Particle, dt : Float ) {
 		p.time += dt * p.lifeTimeFactor;
 		p.time += dt * p.lifeTimeFactor;
 		if( p.time > 1 ) {
 		if( p.time > 1 ) {
@@ -246,7 +246,7 @@ class Emitter extends h3d.scene.Object implements Randomized {
 			return;
 			return;
 		}
 		}
 		p.randIndex = 0;
 		p.randIndex = 0;
-	
+
 		// apply forces
 		// apply forces
 		if( state.force != null ) {
 		if( state.force != null ) {
 			p.fx += p.eval(state.force.vx, time) * dt;
 			p.fx += p.eval(state.force.vx, time) * dt;
@@ -263,7 +263,7 @@ class Emitter extends h3d.scene.Object implements Randomized {
 		p.size = p.eval(state.size, p.time);
 		p.size = p.eval(state.size, p.time);
 		p.ratio = p.eval(state.ratio, p.time);
 		p.ratio = p.eval(state.ratio, p.time);
 		p.rotation = p.eval(state.rotation, p.time);
 		p.rotation = p.eval(state.rotation, p.time);
-		
+
 		// collide
 		// collide
 		if( state.collide && collider != null && collider.collidePart(p, tmp) ) {
 		if( state.collide && collider != null && collider.collidePart(p, tmp) ) {
 			if( state.collideKill ) {
 			if( state.collideKill ) {
@@ -276,8 +276,8 @@ class Emitter extends h3d.scene.Object implements Randomized {
 				p.dz = v.z * state.bounce;
 				p.dz = v.z * state.bounce;
 			}
 			}
 		}
 		}
-			
-		
+
+
 		// calc color
 		// calc color
 		var ck = colorMap;
 		var ck = colorMap;
 		var light = p.eval(state.light, p.time);
 		var light = p.eval(state.light, p.time);
@@ -314,27 +314,27 @@ class Emitter extends h3d.scene.Object implements Randomized {
 			p.cb = light;
 			p.cb = light;
 		}
 		}
 		p.ca = p.eval(state.alpha, p.time);
 		p.ca = p.eval(state.alpha, p.time);
-		
+
 		// frame
 		// frame
 		if( state.frame != null ) {
 		if( state.frame != null ) {
 			var f = p.eval(state.frame, p.time) % 1;
 			var f = p.eval(state.frame, p.time) % 1;
 			if( f < 0 ) f += 1;
 			if( f < 0 ) f += 1;
 			p.frame = Std.int(f * state.frames.length);
 			p.frame = Std.int(f * state.frames.length);
 		}
 		}
-		
+
 		if( state.update != null )
 		if( state.update != null )
 			state.update(p);
 			state.update(p);
 	}
 	}
-	
+
 	override function sync( ctx : h3d.scene.RenderContext ) {
 	override function sync( ctx : h3d.scene.RenderContext ) {
 		super.sync(ctx);
 		super.sync(ctx);
 		update(ctx.elapsedTime * speed);
 		update(ctx.elapsedTime * speed);
 	}
 	}
-	
+
 	public function isActive() {
 	public function isActive() {
 		return count != 0 || time < 1 || state.loop;
 		return count != 0 || time < 1 || state.loop;
 	}
 	}
-	
+
 	function sort( list : Particle ) {
 	function sort( list : Particle ) {
 		return haxe.ds.ListSort.sort(list, function(p1, p2) return p1.w < p2.w ? 1 : -1);
 		return haxe.ds.ListSort.sort(list, function(p1, p2) return p1.w < p2.w ? 1 : -1);
 	}
 	}
@@ -342,7 +342,7 @@ class Emitter extends h3d.scene.Object implements Randomized {
 	function sortInv( list : Particle ) {
 	function sortInv( list : Particle ) {
 		return haxe.ds.ListSort.sort(list, function(p1, p2) return p1.w < p2.w ? -1 : 1);
 		return haxe.ds.ListSort.sort(list, function(p1, p2) return p1.w < p2.w ? -1 : 1);
 	}
 	}
-	
+
 	@:access(h3d.parts.Material) @:access(h2d.Tile)
 	@:access(h3d.parts.Material) @:access(h2d.Tile)
 	override function draw( ctx : h3d.scene.RenderContext ) {
 	override function draw( ctx : h3d.scene.RenderContext ) {
 		if( head == null )
 		if( head == null )
@@ -382,7 +382,7 @@ class Emitter extends h3d.scene.Object implements Randomized {
 				var f = frames[p.frame];
 				var f = frames[p.frame];
 				if( f == null ) f = frames[0];
 				if( f == null ) f = frames[0];
 				var ratio = p.size * p.ratio * (f.height / f.width);
 				var ratio = p.size * p.ratio * (f.height / f.width);
-				
+
 				tmp[pos++] = prevX1;
 				tmp[pos++] = prevX1;
 				tmp[pos++] = prevY1;
 				tmp[pos++] = prevY1;
 				tmp[pos++] = prevZ1;
 				tmp[pos++] = prevZ1;
@@ -402,7 +402,7 @@ class Emitter extends h3d.scene.Object implements Randomized {
 					tmp[pos++] = p.cb;
 					tmp[pos++] = p.cb;
 					tmp[pos++] = p.ca;
 					tmp[pos++] = p.ca;
 				}
 				}
-				
+
 				tmp[pos++] = prevX2;
 				tmp[pos++] = prevX2;
 				tmp[pos++] = prevY2;
 				tmp[pos++] = prevY2;
 				tmp[pos++] = prevZ2;
 				tmp[pos++] = prevZ2;
@@ -431,11 +431,11 @@ class Emitter extends h3d.scene.Object implements Randomized {
 				dy *= d;
 				dy *= d;
 				dz *= d;
 				dz *= d;
 				var dir = new h3d.Vector(Math.sin(p.rotation), 0, Math.cos(p.rotation)).cross(new h3d.Vector(dx, dy, dz));
 				var dir = new h3d.Vector(Math.sin(p.rotation), 0, Math.cos(p.rotation)).cross(new h3d.Vector(dx, dy, dz));
-				
+
 				prevX1 = p.x + dir.x * p.size;
 				prevX1 = p.x + dir.x * p.size;
 				prevY1 = p.y + dir.y * p.size;
 				prevY1 = p.y + dir.y * p.size;
 				prevZ1 = p.z + dir.z * p.size;
 				prevZ1 = p.z + dir.z * p.size;
-				
+
 				prevX2 = p.x - dir.x * p.size;
 				prevX2 = p.x - dir.x * p.size;
 				prevY2 = p.y - dir.y * p.size;
 				prevY2 = p.y - dir.y * p.size;
 				prevZ2 = p.z - dir.z * p.size;
 				prevZ2 = p.z - dir.z * p.size;
@@ -473,7 +473,7 @@ class Emitter extends h3d.scene.Object implements Randomized {
 					tmp[pos++] = p.cb;
 					tmp[pos++] = p.cb;
 					tmp[pos++] = p.ca;
 					tmp[pos++] = p.ca;
 				}
 				}
-				
+
 				prev = p;
 				prev = p;
 				p = p.next;
 				p = p.next;
 			}
 			}
@@ -501,7 +501,7 @@ class Emitter extends h3d.scene.Object implements Randomized {
 					tmp[pos++] = p.cb;
 					tmp[pos++] = p.cb;
 					tmp[pos++] = p.ca;
 					tmp[pos++] = p.ca;
 				}
 				}
-				
+
 				tmp[pos++] = p.x;
 				tmp[pos++] = p.x;
 				tmp[pos++] = p.y;
 				tmp[pos++] = p.y;
 				tmp[pos++] = p.z;
 				tmp[pos++] = p.z;
@@ -552,15 +552,16 @@ class Emitter extends h3d.scene.Object implements Randomized {
 					tmp[pos++] = p.cb;
 					tmp[pos++] = p.cb;
 					tmp[pos++] = p.ca;
 					tmp[pos++] = p.ca;
 				}
 				}
-				
+
 				p = p.next;
 				p = p.next;
 			}
 			}
 		}
 		}
 		var stride = 10;
 		var stride = 10;
 		if( hasColor ) stride += 4;
 		if( hasColor ) stride += 4;
-		var buffer = h3d.Buffer.ofFloats(tmp, stride, [Quads, Dynamic], Std.int(pos/stride));
+		var buffer = h3d.Buffer.ofSubFloats(tmp, stride, Std.int(pos/stride), [Quads, Dynamic, RawFormat]);
 		var size = eval(state.globalSize);
 		var size = eval(state.globalSize);
-		
+
+		/*
 		material.pshader.mpos = state.emitLocal ? this.absPos : h3d.Matrix.I();
 		material.pshader.mpos = state.emitLocal ? this.absPos : h3d.Matrix.I();
 		material.pshader.mproj = ctx.camera.m;
 		material.pshader.mproj = ctx.camera.m;
 		if( state.is3D ) {
 		if( state.is3D ) {
@@ -572,10 +573,12 @@ class Emitter extends h3d.scene.Object implements Randomized {
 		}
 		}
 		material.pshader.hasColor = hasColor;
 		material.pshader.hasColor = hasColor;
 		material.pshader.isAlphaMap = state.isAlphaMap;
 		material.pshader.isAlphaMap = state.isAlphaMap;
-		
+
 		ctx.engine.selectMaterial(material);
 		ctx.engine.selectMaterial(material);
 		ctx.engine.renderQuadBuffer(buffer);
 		ctx.engine.renderQuadBuffer(buffer);
 		buffer.dispose();
 		buffer.dispose();
+		*/
+		throw "TODO";
 	}
 	}
-	
+
 }
 }

+ 12 - 26
h3d/parts/Material.hx

@@ -1,5 +1,5 @@
 package h3d.parts;
 package h3d.parts;
-
+/*
 private class PartShader extends h3d.impl.Shader {
 private class PartShader extends h3d.impl.Shader {
 
 
 #if flash
 #if flash
@@ -13,14 +13,14 @@ private class PartShader extends h3d.impl.Shader {
 			uv : Float2,
 			uv : Float2,
 			color : Float4,
 			color : Float4,
 		};
 		};
-		
+
 		var tuv : Float2;
 		var tuv : Float2;
 		var tcolor : Float4;
 		var tcolor : Float4;
 		var partSize : Float2;
 		var partSize : Float2;
-		
+
 		var hasColor : Bool;
 		var hasColor : Bool;
 		var is3D : Bool;
 		var is3D : Bool;
-		
+
 		var isAlphaMap : Bool;
 		var isAlphaMap : Bool;
 
 
 		function vertex( mpos : M34, mproj : Matrix ) {
 		function vertex( mpos : M34, mproj : Matrix ) {
@@ -45,7 +45,7 @@ private class PartShader extends h3d.impl.Shader {
 			tuv = input.uv;
 			tuv = input.uv;
 			if( hasColor ) tcolor = input.color;
 			if( hasColor ) tcolor = input.color;
 		}
 		}
-		
+
 		function fragment( tex : Texture ) {
 		function fragment( tex : Texture ) {
 			var c = tex.get(tuv.xy);
 			var c = tex.get(tuv.xy);
 			if( hasColor ) c *= tcolor;
 			if( hasColor ) c *= tcolor;
@@ -55,7 +55,7 @@ private class PartShader extends h3d.impl.Shader {
 			}
 			}
 			out = c;
 			out = c;
 		}
 		}
-	
+
 	}
 	}
 #else
 #else
 	static var VERTEX = "";
 	static var VERTEX = "";
@@ -63,29 +63,15 @@ private class PartShader extends h3d.impl.Shader {
 #end
 #end
 
 
 }
 }
+*/
 
 
-class Material extends h3d.mat.Material {
-	
-	var pshader : PartShader;
-	public var texture(default,set) : h3d.mat.Texture;
+class Material extends h3d.mat.MeshMaterial {
 
 
 	public function new(?texture) {
 	public function new(?texture) {
-		pshader = new PartShader();
-		super(pshader);
-		this.texture = texture;
-		blend(SrcAlpha, One);
-		culling = None;
-		depthWrite = false;
-	}
-	
-	override function clone( ?m : h3d.mat.Material ) {
-		var m = m == null ? new Material(texture) : cast m;
-		super.clone(m);
-		return m;
+		super(texture);
+		blendMode = Alpha;
+		mainPass.culling = None;
+		mainPass.depthWrite = false;
 	}
 	}
 
 
-	inline function set_texture(t) {
-		return pshader.tex = t;
-	}
-	
 }
 }

+ 9 - 9
h3d/parts/Particle.hx

@@ -1,12 +1,12 @@
 package h3d.parts;
 package h3d.parts;
 
 
 class Particle implements Data.Randomized {
 class Particle implements Data.Randomized {
-	
+
 	public var x : Float;
 	public var x : Float;
 	public var y : Float;
 	public var y : Float;
 	public var z : Float;
 	public var z : Float;
 	public var w : Float;
 	public var w : Float;
-	
+
 	public var time : Float;
 	public var time : Float;
 	public var lifeTimeFactor : Float;
 	public var lifeTimeFactor : Float;
 
 
@@ -22,16 +22,16 @@ class Particle implements Data.Randomized {
 	public var cg : Float;
 	public var cg : Float;
 	public var cb : Float;
 	public var cb : Float;
 	public var ca : Float;
 	public var ca : Float;
-	
+
 	public var frame : Int;
 	public var frame : Int;
-	
+
 	public var size : Float;
 	public var size : Float;
 	public var ratio : Float;
 	public var ratio : Float;
 	public var rotation : Float;
 	public var rotation : Float;
-	
+
 	public var prev : Particle;
 	public var prev : Particle;
 	public var next : Particle;
 	public var next : Particle;
-	
+
 	public var randIndex = 0;
 	public var randIndex = 0;
 	public var randValues : Array<Float>;
 	public var randValues : Array<Float>;
 
 
@@ -42,15 +42,15 @@ class Particle implements Data.Randomized {
 		ca = 1;
 		ca = 1;
 		frame = 0;
 		frame = 0;
 	}
 	}
-	
+
 	public inline function eval( v : Data.Value, time : Float ) {
 	public inline function eval( v : Data.Value, time : Float ) {
 		return Data.State.eval(v, time, this, this);
 		return Data.State.eval(v, time, this, this);
 	}
 	}
-	
+
 	public function rand() {
 	public function rand() {
 		if( randValues == null ) randValues = [];
 		if( randValues == null ) randValues = [];
 		if( randValues.length <= randIndex ) randValues.push(Math.random());
 		if( randValues.length <= randIndex ) randValues.push(Math.random());
 		return randValues[randIndex++];
 		return randValues[randIndex++];
 	}
 	}
-	
+
 }
 }

+ 29 - 0
h3d/pass/Base.hx

@@ -0,0 +1,29 @@
+package h3d.pass;
+
+class Base {
+
+	var ctx : h3d.scene.RenderContext;
+	public var priority : Int = 0;
+	public var forceProcessing : Bool = false;
+
+	public function new() {
+	}
+
+	public function compileShader( p : h3d.mat.Pass ) : hxsl.RuntimeShader {
+		throw "Not implemented for this pass";
+		return null;
+	}
+
+	public function setContext( ctx ) {
+		this.ctx = ctx;
+	}
+
+	public function draw( name : String, passes : Object ) {
+		return passes;
+	}
+
+	public function getLightSystem() : Null<LightSystem> {
+		return null;
+	}
+
+}

+ 84 - 0
h3d/pass/Blur.hx

@@ -0,0 +1,84 @@
+package h3d.pass;
+
+class Blur extends ScreenFx<h3d.shader.Blur> {
+
+	/**
+		Gives the blur quality : 0 for disable, 1 for 3x3, 2 for 5x5, etc.
+	**/
+	public var quality(default, set) : Int;
+
+	/**
+		The amount of blur (gaussian blur value).
+	**/
+	public var sigma(default, set) : Float;
+
+	var values : Array<Float>;
+
+	public function new(quality = 1, sigma = 1.) {
+		super(new h3d.shader.Blur());
+		this.quality = quality;
+		this.sigma = sigma;
+	}
+
+	function set_quality(q) {
+		values = null;
+		return quality = q;
+	}
+
+	function set_sigma(s) {
+		values = null;
+		return sigma = s;
+	}
+
+	function gauss( x:Int, s:Float ) : Float {
+		if( s <= 0 ) return x == 0 ? 1 : 0;
+		var sq = s * s;
+		var p = Math.pow(2.718281828459, -(x * x) / (2 * sq));
+		return p / Math.sqrt(2 * Math.PI * sq);
+	}
+
+	public function apply( src : h3d.mat.Texture, ?tmp : h3d.mat.Texture, ?output : h3d.mat.Texture, isDepth = false ) {
+
+		if( quality == 0 ) return;
+
+		if( output == null ) output = src;
+
+		var alloc = tmp == null;
+		if( alloc )
+			tmp = new h3d.mat.Texture(src.width, src.height, [Target, TargetNoFlipY]);
+
+		if( values == null ) {
+			values = [];
+			var tot = 0.;
+			for( i in 0...quality + 1 ) {
+				var g = gauss(i, sigma);
+				values[i] = g;
+				tot += g;
+				if( i > 0 ) tot += g;
+			}
+			for( i in 0...quality + 1 )
+				values[i] /= tot;
+		}
+
+
+		shader.Quality = quality + 1;
+		shader.texture = src;
+		shader.values = values;
+		shader.isDepth = isDepth;
+		shader.pixel.set(1 / src.width, 0);
+
+		engine.setTarget(tmp);
+		render();
+		engine.setTarget(null);
+
+		shader.texture = tmp;
+		shader.pixel.set(0, 1 / tmp.height);
+		engine.setTarget(output);
+		render();
+		engine.setTarget(null);
+
+		if( alloc )
+			tmp.dispose();
+	}
+
+}

+ 66 - 0
h3d/pass/Border.hx

@@ -0,0 +1,66 @@
+package h3d.pass;
+
+private class BorderShader extends hxsl.Shader {
+	static var SRC = {
+
+		@param var color : Vec4;
+
+		@input var input : {
+			var position : Vec2;
+		};
+
+		var output : {
+			var position : Vec4;
+			var color : Vec4;
+		};
+
+		function vertex() {
+			output.position = vec4(input.position, 0, 1);
+		}
+
+		function fragment() {
+			output.color = color;
+		}
+
+	}
+}
+
+class Border extends ScreenFx<BorderShader> {
+
+	public function new( size : Int ) {
+		super(new BorderShader());
+
+		var bbuf = new hxd.FloatBuffer();
+		inline function add(x, y) {
+			bbuf.push((x / size) * 2 - 1);
+			bbuf.push(1 - (y / size) * 2);
+		}
+		add(0, 0);
+		add(size, 0);
+		add(0, 1);
+		add(size, 1);
+
+		add(0, 0);
+		add(1, 0);
+		add(0, size);
+		add(1, size);
+
+		add(0, size-1);
+		add(size, size-1);
+		add(0, size);
+		add(size, size);
+
+		add(size-1, 0);
+		add(size, 0);
+		add(size-1, size);
+		add(size, size);
+
+		var plan = new h3d.prim.RawPrimitive(engine, bbuf, 2);
+		plan.buffer.flags.unset(Triangles);
+		plan.buffer.flags.set(Quads);
+		this.plan = plan;
+		shader.color.set(1,1,1,1);
+	}
+
+
+}

Some files were not shown because too many files changed in this diff