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
 *.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 {
 
 	public var frames : Array<Tile>;
-	public var currentFrame : Float;
+	public var currentFrame(get,set) : Float;
 	public var speed : Float;
 	public var loop : Bool = true;
+	var curFrame : Float;
 
 	public function new( ?frames, ?speed, ?parent ) {
 		super(parent);
 		this.frames = frames == null ? [] : frames;
-		this.currentFrame = 0;
+		this.curFrame = 0;
 		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() {
 	}
 
+	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 ) {
 		super.getBoundsRec(relativeTo, out);
 		var tile = getFrame();
@@ -30,28 +41,28 @@ class Anim extends Drawable {
 
 	override function sync( ctx : RenderContext ) {
 		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;
 		if( loop ) {
-			currentFrame %= frames.length;
+			curFrame %= frames.length;
 			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() {
-		var i = Std.int(currentFrame);
+		var i = Std.int(curFrame);
 		if( i == frames.length ) i--;
 		return frames[i];
 	}
 
 	override function draw( ctx : RenderContext ) {
 		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 ) {
-		drawTile(ctx.engine,tile);
+		emitTile(ctx,tile);
 	}
 
 	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 height(default, set) : Int;
 	public var freezed : Bool;
-	
+
 	var renderDone : Bool;
 	var tile : Tile;
-	
+
 	public function new( ?parent, width = -1, height = -1 ) {
 		super(parent);
 		this.width = width;
@@ -26,7 +26,7 @@ class CachedBitmap extends Drawable {
 		clean();
 		super.onDelete();
 	}
-	
+
 	function set_width(w) {
 		clean();
 		width = w;
@@ -38,7 +38,7 @@ class CachedBitmap extends Drawable {
 		height = h;
 		return h;
 	}
-	
+
 	public function getTile() {
 		if( tile == null ) {
 			var scene = getScene();
@@ -53,9 +53,9 @@ class CachedBitmap extends Drawable {
 	}
 
 	override function drawRec( ctx : RenderContext ) {
-		drawTile(ctx.engine, tile);
+		emitTile(ctx, tile);
 	}
-	
+
 	override function sync( ctx : RenderContext ) {
 		if( posChanged ) {
 			calcAbsPos();
@@ -69,7 +69,7 @@ class CachedBitmap extends Drawable {
 		var tile = getTile();
 		if( !freezed || !renderDone ) {
 			var oldA = matA, oldB = matB, oldC = matC, oldD = matD, oldX = absX, oldY = absY;
-			
+
 			// init matrix without rotation
 			matA = 1;
 			matB = 0;
@@ -77,7 +77,7 @@ class CachedBitmap extends Drawable {
 			matD = 1;
 			absX = 0;
 			absY = 0;
-			
+
 			// adds a pixels-to-viewport transform
 			var w = 2 / tile.width;
 			var h = -2 / tile.height;
@@ -94,11 +94,12 @@ class CachedBitmap extends Drawable {
 				c.sync(ctx);
 			}
 
+			throw "Should not draw in sync!";
 			ctx.engine.setTarget(tile.getTexture());
 			for( c in childs )
 				c.drawRec(ctx);
 			ctx.engine.setTarget(null);
-			
+
 			// restore
 			matA = oldA;
 			matB = oldB;
@@ -106,11 +107,11 @@ class CachedBitmap extends Drawable {
 			matD = oldD;
 			absX = oldX;
 			absY = oldY;
-			
+
 			renderDone = true;
 		}
 
 		super.sync(ctx);
 	}
-	
+
 }

+ 20 - 20
h2d/Console.hx

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

+ 120 - 489
h2d/Drawable.hx

@@ -1,525 +1,156 @@
 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 {
 
-	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;
-	#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) {
 		super(parent);
-		shader = new DrawableShader();
-		writeAlpha = true;
 		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 )
-			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 {
-	
+
 	public var t : h2d.Tile;
 	public var width : Int;
 	var kerning : Null<Kerning>;
-	
+
 	public function new(t,w) {
 		this.t = t;
 		this.width = w;
 	}
-	
+
 	public function addKerning( prevChar : Int, offset : Int ) {
 		var k = new Kerning(prevChar, offset);
 		k.next = kerning;
 		kerning = k;
 	}
-	
+
 	public function getKerningOffset( prevChar : Int ) {
 		var k = kerning;
 		while( k != null ) {
@@ -40,7 +40,7 @@ class FontChar {
 }
 
 class Font {
-	
+
 	public var name(default, null) : String;
 	public var size(default, null) : Int;
 	public var lineHeight(default, null) : Int;
@@ -48,7 +48,7 @@ class Font {
 	public var charset : hxd.Charset;
 	var glyphs : Map<Int,FontChar>;
 	var defaultChar : FontChar;
-	
+
 	function new(name,size) {
 		this.name = name;
 		this.size = size;
@@ -56,7 +56,7 @@ class Font {
 		defaultChar = new FontChar(new Tile(null, 0, 0, 0, 0),0);
 		charset = hxd.Charset.getDefault();
 	}
-	
+
 	public inline function getChar( code : Int ) {
 		var c = glyphs.get(code);
 		if( c == null ) {
@@ -65,7 +65,7 @@ class Font {
 		}
 		return c;
 	}
-	
+
 	/**
 		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);
 		this.size = size;
 	}
-	
+
 	public function hasChar( code : Int ) {
 		return glyphs.get(code) != null;
 	}
-	
+
 	public function 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 ) {
 		if (index.length <= 0) return ;
-		buffer = h3d.Buffer.ofFloats(tmp, 8);
+		buffer = h3d.Buffer.ofFloats(tmp, 8, [RawFormat]);
 		indexes = h3d.Indexes.alloc(index);
 		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);
 		}
 	}
@@ -123,7 +123,6 @@ class Graphics extends Drawable {
 	public function new(?parent) {
 		super(parent);
 		content = new GraphicsContent();
-		shader.hasVertexColor = true;
 		tile = h2d.Tile.fromColor(0xFFFFFFFF);
 		clear();
 	}
@@ -315,7 +314,7 @@ class Graphics extends Drawable {
 
 	override function draw(ctx:RenderContext) {
 		flush();
-		setupShader(ctx.engine, tile, 0);
+		ctx.beginDrawObject(this, tile.getTexture());
 		content.render(ctx.engine);
 	}
 

+ 3 - 50
h2d/HtmlText.hx

@@ -1,39 +1,8 @@
 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();
 		glyphs.setDefaultColor(textColor);
 		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);
 		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 ) {
-		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 ) {

+ 9 - 9
h2d/Layers.hx

@@ -1,25 +1,25 @@
 package h2d;
 
 class Layers extends Sprite {
-	
+
 	// the per-layer insert position
 	var layers : Array<Int>;
 	var layerCount : Int;
-	
+
 	public function new(?parent) {
 		super(parent);
 		layers = [];
 		layerCount = 0;
 	}
-	
+
 	override function addChild(s) {
 		addChildAt(s, 0);
 	}
-	
+
 	public inline function add(s, layer) {
 		return addChildAt(s, layer);
 	}
-	
+
 	override function addChildAt( s : Sprite, layer : Int ) {
 		if( s.parent == this ) {
 			var old = s.allocated;
@@ -34,7 +34,7 @@ class Layers extends Sprite {
 		for( i in layer...layerCount )
 			layers[i]++;
 	}
-	
+
 	override function removeChild( s : Sprite ) {
 		for( i in 0...childs.length ) {
 			if( childs[i] == s ) {
@@ -50,7 +50,7 @@ class Layers extends Sprite {
 			}
 		}
 	}
-	
+
 	public function under( s : Sprite ) {
 		for( i in 0...childs.length )
 			if( childs[i] == s ) {
@@ -83,7 +83,7 @@ class Layers extends Sprite {
 				break;
 			}
 	}
-	
+
 	public function ysort( layer : Int ) {
 		if( layer >= layerCount ) return;
 		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;
 
-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;
 
 class ScaleGrid extends h2d.TileGroup {
-	
+
 
 	public var borderWidth : Int;
 	public var borderHeight : Int;
-	
+
 	public var width(default,set) : Int;
 	public var height(default,set) : Int;
-	
+
 	public var tileBorders(default,set) : Bool;
-	
+
 	public function new( tile, borderW, borderH, ?parent ) {
 		super(tile,parent);
 		borderWidth = borderW;
@@ -24,7 +24,7 @@ class ScaleGrid extends h2d.TileGroup {
 		reset();
 		return b;
 	}
-	
+
 	function set_width(w) {
 		this.width = w;
 		reset();
@@ -36,71 +36,71 @@ class ScaleGrid extends h2d.TileGroup {
 		reset();
 		return h;
 	}
-	
+
 	override function draw( ctx : RenderContext ) {
 		if( content.isEmpty() ) {
 			var bw = borderWidth, bh = borderHeight;
-			
+
 			// 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 sizeY = tile.height - bh * 2;
-			
+
 			if( !tileBorders ) {
-				
+
 				var w = width - bw * 2;
 				var h = height - bh * 2;
-				
+
 				var t = tile.sub(bw, 0, sizeX, 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);
 				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);
 				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);
 				t.scaleToSize(bw, h);
-				content.add(w + bw, bh, t);
-				
+				content.addColor(w + bw, bh, curColor, t);
+
 			} else {
-				
+
 				var rw = Std.int((width - bw * 2) / sizeX);
 				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;
 				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);
 				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;
 				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);
 			t.scaleToSize(width - bw * 2,height - bh * 2);
-			content.add(bw, bh, t);
+			content.addColor(bw, bh, curColor, t);
 		}
 		super.draw(ctx);
 	}
-	
+
 }

+ 13 - 2
h2d/Scene.hx

@@ -382,6 +382,16 @@ class Scene extends Layers implements h3d.IDrawable {
 		var h = -2 / height;
 		absX = absX * w - 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;
 		matB *= h;
 		matC *= w;
@@ -419,9 +429,11 @@ class Scene extends Layers implements h3d.IDrawable {
 		ctx.engine = engine;
 		ctx.frame++;
 		ctx.time += ctx.elapsedTime;
-		ctx.currentPass = 0;
 		sync(ctx);
+		if( childs.length == 0 ) return;
+		ctx.begin();
 		drawRec(ctx);
+		ctx.end();
 	}
 
 	override function sync( ctx : RenderContext ) {
@@ -432,7 +444,6 @@ class Scene extends Layers implements h3d.IDrawable {
 			height = ctx.engine.height;
 			posChanged = true;
 		}
-		Tools.checkCoreObjects();
 		super.sync(ctx);
 	}
 

+ 4 - 4
h2d/Scene3D.hx

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

+ 49 - 14
h2d/SpriteBatch.hx

@@ -21,19 +21,31 @@ class BatchElement {
 	public var y : Float;
 	public var scale : 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 alpha(get,set) : Float;
 	public var batch(default, null) : SpriteBatch;
 
 	var prev : BatchElement;
 	var next : BatchElement;
 
 	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;
 		this.t = t;
 	}
 
+	inline function get_alpha() {
+		return a;
+	}
+
+	inline function set_alpha(v) {
+		return a = v;
+	}
+
 	function update(et:Float) {
 		return true;
 	}
@@ -56,7 +68,6 @@ class SpriteBatch extends Drawable {
 	public function new(t,?parent) {
 		super(parent);
 		tile = t;
-		shader.hasVertexAlpha = true;
 	}
 
 	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++] = t.u;
 				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;
 				tmp[pos++] = (px * ca - py * sa) * e.scale + e.x;
 				tmp[pos++] = (py * ca + px * sa) * e.scale + e.y;
 				tmp[pos++] = t.u2;
 				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;
 				tmp[pos++] = (px * ca - py * sa) * e.scale + e.x;
 				tmp[pos++] = (py * ca + px * sa) * e.scale + e.y;
 				tmp[pos++] = t.u;
 				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;
 				tmp[pos++] = (px * ca - py * sa) * e.scale + e.x;
 				tmp[pos++] = (py * ca + px * sa) * e.scale + e.y;
 				tmp[pos++] = t.u2;
 				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 {
 				var sx = e.x + t.dx;
 				var sy = e.y + t.dy;
@@ -179,27 +202,39 @@ class SpriteBatch extends Drawable {
 				tmp[pos++] = sy;
 				tmp[pos++] = t.u;
 				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++] = sy;
 				tmp[pos++] = t.u2;
 				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++] = sy + t.height + 0.1;
 				tmp[pos++] = t.u;
 				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++] = sy + t.height + 0.1;
 				tmp[pos++] = t.u2;
 				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;
 		}
-		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);
 		buffer.dispose();
 	}
@@ -207,7 +242,7 @@ class SpriteBatch extends Drawable {
 	public inline function isEmpty() {
 		return first == null;
 	}
-	
+
 	public inline function getElements() {
 		return new ElementsIterator(first);
 	}

+ 19 - 15
h2d/Text.hx

@@ -35,7 +35,7 @@ class Text extends Drawable {
 		this.font = font;
 		if( glyphs != null ) glyphs.remove();
 		glyphs = new TileGroup(font == null ? null : font.tile, this);
-		shader = glyphs.shader;
+		glyphs.visible = false;
 		rebuild();
 		return font;
 	}
@@ -64,20 +64,23 @@ class Text extends Drawable {
 	}
 
 	override function draw(ctx:RenderContext) {
-		glyphs.blendMode = blendMode;
 		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) {
@@ -176,8 +179,9 @@ class Text extends Drawable {
 
 	function set_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;
 	}
 

+ 36 - 58
h2d/Tile.hx

@@ -3,7 +3,15 @@ package h2d;
 @:allow(h2d)
 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;
 
@@ -30,7 +38,7 @@ class Tile {
 		if( tex != null ) setTexture(tex);
 	}
 
-	public function getTexture() : h3d.mat.Texture {
+	public inline function getTexture() {
 		return innerTex;
 	}
 
@@ -41,10 +49,10 @@ class Tile {
 	function setTexture(tex) {
 		this.innerTex = tex;
 		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);
 	}
 
+	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) {
 		this.x = x;
 		this.y = y;
 		var tex = innerTex;
 		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;
 		var tex = innerTex;
 		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);
 	}
 
-	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() {
 		if( innerTex != null ) innerTex.dispose();
 		innerTex = null;
@@ -192,6 +200,9 @@ class Tile {
 	}
 
 	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;
 		var colorBG = bmp.getPixel(bmp.width - 1, bmp.height - 1);
 		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));
 			}
 		}
+		#if js
+		bmp.unlock();
+		#end
 		var main = new Tile(tex, 0, 0, bmp.width, bmp.height);
 		main.upload(bmp);
 		return { main : main, tiles : tl };
@@ -227,42 +241,6 @@ class Tile {
 		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 ) {
 		var empty = true;
 		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 yMax : Float;
 
-
 	public function new() {
 		reset();
 	}
 
-	public function isEmpty() {
-		return buffer == null;
-	}
-
 	public function reset() {
 		tmp = new hxd.FloatBuffer();
 		if( buffer != null ) buffer.dispose();
@@ -27,40 +22,124 @@ private class TileLayerContent extends h3d.prim.Primitive {
 		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(sy);
 		tmp.push(t.u);
 		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(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(sy + t.height);
 		tmp.push(t.u);
 		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.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) {
 		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) {
@@ -73,16 +152,18 @@ private class TileLayerContent extends h3d.prim.Primitive {
 class TileGroup 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;
+		curColor = new h3d.Vector(1, 1, 1, 1);
 		content = new TileLayerContent();
-		super(parent);
 	}
 
 	override function getBoundsRec( relativeTo, out ) {
@@ -94,27 +175,44 @@ class TileGroup extends Drawable {
 		content.reset();
 	}
 
+	/**
+		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, 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) {
-		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 max = content.triCount();
 		if( rangeMax > 0 && rangeMax < max * 2 ) max = rangeMax * 2;
 		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 y : Float;
 	public var ray : Float;
-	
+
 	public inline function new( x : Float, y : Float, ray : Float ) {
 		this.x = x;
 		this.y = y;
 		this.ray = ray;
 	}
-	
+
 	public inline function distanceSq( p : Point ) {
 		var dx = p.x - x;
 		var dy = p.y - y;
@@ -25,7 +25,7 @@ class Circle {
 		var dy = p.y - y;
 		return ray * ray - (dx * dx + dy * dy);
 	}
-	
+
 	public inline function collideCircle( c : Circle ) {
 		var dx = x - c.x;
 		var dy = y - c.y;
@@ -35,5 +35,5 @@ class Circle {
 	public function toString() {
 		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.p2 = p2;
 	}
-	
+
 	public inline function side( p : Point ) {
 		return (p2.x - p1.x) * (p.y - p1.y) - (p2.y - p1.y) * (p.x - p1.x);
 	}
-	
+
 	public inline function project( p : Point ) {
 		var dx = p2.x - p1.x;
 		var dy = p2.y - p1.y;
 		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);
 	}
-	
+
 	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);
 		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;
 		return true;
 	}
-	
+
 	public inline function distanceSq( p : Point ) {
 		var dx = p2.x - p1.x;
 		var dy = p2.y - p1.y;
@@ -49,9 +49,9 @@ class Line {
 		var my = dy * k + p1.y - p.y;
 		return mx * mx + my * my;
 	}
-	
+
 	public inline function distance( p : Point ) {
 		return hxd.Math.sqrt(distanceSq(p));
 	}
-	
+
 }

+ 7 - 7
h2d/col/Point.hx

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

+ 8 - 8
h2d/col/Poly.hx

@@ -5,11 +5,11 @@ class Poly {
 
 	public var points : Array<Point>;
 	var segments : Array<Seg>;
-	
+
 	public function new( points ) {
 		this.points = points;
 	}
-		
+
 	public function isConvex() {
 		for( i in 0...points.length ) {
 			var p1 = points[i];
@@ -20,7 +20,7 @@ class Poly {
 		}
 		return true;
 	}
-	
+
 	public function calculateArea() {
 		var s = 0.;
 		for( i in 0...points.length ) {
@@ -41,14 +41,14 @@ class Poly {
 		}
 		return segments;
 	}
-	
+
 	public function hasPoint( p : Point ) {
 		for( s in getSegments() )
 			if( s.side(p) < 0 )
 				return false;
 		return true;
 	}
-	
+
 	public function project( p : Point ) : Point {
 		var dmin = 1e20, smin = null;
 		for( s in getSegments() ) {
@@ -60,7 +60,7 @@ class Poly {
 		}
 		return smin.project(p);
 	}
-	
+
 	public function distanceSq( p : Point ) {
 		var dmin = 1e20;
 		for( s in getSegments() ) {
@@ -69,9 +69,9 @@ class Poly {
 		}
 		return dmin;
 	}
-	
+
 	public inline function distance( p : Point ) {
 		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 m : Int;
 	public var n : Int;
-	
+
 	public function new(m, n) {
 		this.m = m;
 		this.n = n;
@@ -12,7 +12,7 @@ private class Matrix {
 		for( i in 0...m )
 			data[i] = new haxe.ds.Vector(n);
 	}
-	
+
 	public function clone() {
 		var m2 = new Matrix(m, n);
 		for( i in 0...m )
@@ -20,25 +20,25 @@ private class Matrix {
 				m2.data[i][j] = data[i][j];
 		return m2;
 	}
-	
+
 	function toString() {
 		return "[" + [for( k in data ) "\n" + Std.string(k)].join("") + "\n]";
 	}
 }
 
 private class QR {
-	
+
 	var qr : haxe.ds.Vector<haxe.ds.Vector<Float>>;
 	var rDiag : haxe.ds.Vector<Float>;
 	var m : Int;
 	var n : Int;
-	
+
 	public function new( mat : Matrix ) {
 		this.m = mat.m;
 		this.n = mat.n;
 		qr = mat.clone().data;
 		rDiag = new haxe.ds.Vector(n);
-		
+
 		for( k in 0...n ) {
 			var nrm = 0.;
 			for( i in k...m )
@@ -60,14 +60,14 @@ private class QR {
 			rDiag[k] = -nrm;
 		}
 	}
-	
+
 	function isFullRank() {
 		for( j in 0...n )
 			if( rDiag[j] == 0 )
 				return false;
 		return true;
 	}
-	
+
 	public function solve( b : Matrix ) {
 		if( b.m != m ) throw "Invalid matrix size";
 		if( !isFullRank() ) return null;
@@ -96,7 +96,7 @@ private class QR {
 			beta.push(X[i][0]);
 		return beta;
 	}
-	
+
 	function hypot( x : Float, y : Float ) {
 		if( x < 0 ) x = -x;
 		if( y < 0 ) y = -y;
@@ -109,7 +109,7 @@ private class QR {
 		t = t/x;
 		return x * Math.sqrt(1+t*t);
 	}
-	
+
 }
 
 class Polynomial {
@@ -129,11 +129,11 @@ class Polynomial {
 		for( i in 0...n )
 			for( j in 0...degree+1 )
 				x.data[i][j] = Math.pow(xVals[i], j);
-				
+
 		var y = new Matrix(yVals.length, n);
 		for( i in 0...yVals.length )
 			y.data[i][0] = yVals[i];
-		
+
 		var qr = new QR(x);
 		var beta = qr.solve(y);
 		if( beta == null ) {
@@ -142,5 +142,5 @@ class Polynomial {
 		}
 		return beta;
 	}
-	
+
 }

+ 3 - 3
h2d/col/RoundRect.hx

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

+ 5 - 5
h2d/col/Seg.hx

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

+ 7 - 7
h2d/col/Triangle.hx

@@ -1,26 +1,26 @@
 package h2d.col;
 
 class Triangle {
-	
+
 	static inline var UNDEF = 1.1315e-17;
-	
+
 	public var a : Point;
 	public var b : Point;
 	public var c : Point;
 	var area : Float;
 	var invArea : Float;
-	
+
 	public inline function new( a : Point, b : Point, c : Point ) {
 		this.a = a;
 		this.b = b;
 		this.c = c;
 		area = UNDEF;
 	}
-	
+
 	public inline function getCenter() {
 		return new Point((a.x + b.x + c.x) / 3, (a.y + b.y + c.y) / 3);
 	}
-	
+
 	public function getArea() {
 		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;
@@ -33,7 +33,7 @@ class Triangle {
 		getArea();
 		return invArea;
 	}
-	
+
 	/**
 		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);
 		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>> {
-	
+
 	public var root : T;
-	
+
 	public function new() {
 		this.root = null;
     }
@@ -320,17 +320,17 @@ private class RBNode<T:RBNode<T>> {
 }
 
 class Cell {
-	
+
 	public var id : Int;
 	public var point : Point;
 	public var halfedges : Array<Halfedge>;
-	
+
 	public function new(id, point) {
 		this.id = id;
 		this.point = point;
 		this.halfedges = [];
     }
-	
+
 	public function getCircle() {
 		// 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
@@ -371,7 +371,7 @@ class Cell {
 		halfedges.sort(sortByAngle);
 		return halfedges.length;
 	}
-	
+
 	static function sortByAngle(a:Halfedge, b:Halfedge) {
 		return b.angle > a.angle ? 1 : (b.angle < a.angle ? -1 : 0);
 	}
@@ -455,7 +455,7 @@ class Cell {
 			}
 		return 1;
 	}
-	
+
 }
 
 class Edge {
@@ -467,7 +467,7 @@ class Edge {
 	public var rCell : Null<Cell>;
 	public var va : Null<Point>;
 	public var vb : Null<Point>;
-	
+
 	public function new(lPoint, rPoint) {
 		this.lPoint = lPoint;
 		this.rPoint = rPoint;
@@ -477,11 +477,11 @@ class Edge {
 
 
 class Halfedge {
-	
+
 	public var point : Point;
 	public var edge : Edge;
 	public var angle : Float;
-	
+
 	public function new(edge, lPoint:Point, rPoint:Point) {
 		this.point = lPoint;
 		this.edge = edge;
@@ -504,7 +504,7 @@ class Halfedge {
 				: Math.atan2(va.x-vb.x, vb.y-va.y);
 		}
 	}
-	
+
 	public inline function getStartpoint() {
 		return this.edge.lPoint == this.point ? this.edge.va : this.edge.vb;
     }
@@ -512,7 +512,7 @@ class Halfedge {
 	public inline function getEndpoint() {
 		return this.edge.lPoint == this.point ? this.edge.vb : this.edge.va;
     }
-	
+
 	public inline function getTarget() {
 		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 {
-	
+
 	var epsilon : Float;
 	var beachline : RBTree<Beachsection>;
 	var vertices : Array<Point>;
@@ -646,7 +646,7 @@ class Voronoi {
 	function setEdgeEndpoint(edge, lPoint, rPoint, vertex) {
 		this.setEdgeStartpoint(edge, rPoint, lPoint, vertex);
     }
-	
+
 
 	// rhill 2011-06-02: A lot of Beachsection instanciations
 	// occur during the computation of the Voronoi diagram,
@@ -1406,7 +1406,7 @@ class Voronoi {
 		var r = b.y - a.y;
 		return r < 0 ? -1 : (r > 0 ? 1 : (b.x > a.x ? 1 : b.x < a.x ? -1 : 0));
 	}
-	
+
 	// rhill 2011-05-19:
 	//   Voronoi points are kept client-side now, to allow
 	//   user to freely modify content. At compute time,
@@ -1463,7 +1463,7 @@ class Voronoi {
 			// all done, quit
 			else
 				break;
-				
+
 		}
 
 		// wrapping-up:
@@ -1475,7 +1475,7 @@ class Voronoi {
 
 		//   add missing edges in order to close opened cells
 		this.closeCells(bbox);
-		
+
 		var eid = 0;
 		for( e in edges ) {
 			e.id = eid++;

+ 5 - 5
h2d/comp/Box.hx

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

+ 6 - 6
h2d/comp/Button.hx

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

+ 7 - 7
h2d/comp/Checkbox.hx

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

+ 7 - 7
h2d/comp/Color.hx

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

+ 61 - 61
h2d/comp/ColorPicker.hx

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

+ 9 - 9
h2d/comp/Context.hx

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

+ 76 - 76
h2d/comp/GradientEditor.hx

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

+ 8 - 8
h2d/comp/Interactive.hx

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

+ 7 - 7
h2d/comp/ItemList.hx

@@ -1,28 +1,28 @@
 package h2d.comp;
 
 class ItemList extends Box {
-	
+
 	public var selected(default,set) = -1;
 	var inputs : Array<h2d.Interactive>;
-	
+
 	public function new(?parent) {
 		super(Vertical, parent);
 		this.name = "itemlist";
 		inputs = [];
 	}
-	
+
 	function set_selected(v:Int) {
 		needRebuild = true;
 		return selected = v;
 	}
-	
+
 	function onWheel( e : hxd.Event ) {
 		scrollY -= e.wheelDelta * (components.length == 0 ? 0 : (components[0].height + style.verticalSpacing));
 		if( scrollY > 0 ) scrollY = 0;
 		e.propagate = false;
 		needRebuild = true;
 	}
-	
+
 	override function resizeRec( ctx : Context ) {
 		super.resizeRec(ctx);
 		if( !ctx.measure ) {
@@ -85,8 +85,8 @@ class ItemList extends Box {
 
 	public dynamic function onItemOver( current : 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)
 @:keep
 class JQuery {
-	
+
 	var root : Component;
 	var select : Array<Component>;
-	
+
 	public function new( root : Component, query : Dynamic ) {
 		while( root.parentComponent != null )
 			root = root.parentComponent;
 		this.root = root;
 		select = getSet(query);
 	}
-	
+
 	public function getComponents() {
 		return select;
 	}
-	
+
 	public function toggleClass( cl : String, ?flag : Bool ) {
 		for( s in select ) s.toggleClass(cl,flag);
 		return this;
 	}
-	
+
 	public function find( q : Dynamic ) {
 		if( Std.is(q, Component) )
 			return new JQuery(root, Lambda.has(select, q) ? null : q);
@@ -39,7 +39,7 @@ class JQuery {
 		throw "Invalid JQuery " + q;
 		return null;
 	}
-	
+
 	public function filter( q : Dynamic ) {
 		if( Std.is(q, Component) )
 			return new JQuery(root, Lambda.has(select, q) ? null : q);
@@ -69,7 +69,7 @@ class JQuery {
 		throw "Invalid JQuery " + q;
 		return null;
 	}
-	
+
 	public function click( f : JQuery -> Void ) {
 		for( c in select ) {
 			var int = Std.instance(c, Interactive);
@@ -78,7 +78,7 @@ class JQuery {
 		}
 		return this;
 	}
-	
+
 	public function show() {
 		for( s in select )
 			s.getStyle(true).display = true;
@@ -90,7 +90,7 @@ class JQuery {
 			s.getStyle(true).display = false;
 		return this;
 	}
-	
+
 	public function toggle() {
 		for( s in select ) {
 			var s = s.getStyle(true);
@@ -98,7 +98,7 @@ class JQuery {
 		}
 		return this;
 	}
-	
+
 	public function iterator() {
 		var it = select.iterator();
 		return {
@@ -161,7 +161,7 @@ class JQuery {
 			"";
 		}
 	}
-	
+
 	function _set_text(v:String) {
 		for( c in select )
 			switch( c.name ) {
@@ -173,7 +173,7 @@ class JQuery {
 			}
 		return this;
 	}
-	
+
 	function _set_style(v:String) {
 		var s = new h2d.css.Style();
 		new h2d.css.Parser().parse(v, s);
@@ -181,7 +181,7 @@ class JQuery {
 			c.addStyle(s);
 		return this;
 	}
-	
+
 	function getSet( query : Dynamic ) {
 		var set;
 		if( query == null )
@@ -198,29 +198,29 @@ class JQuery {
 			throw "Invalid JQuery " + query;
 		return set;
 	}
-	
+
 	function lookup( root : Component, query : String ) {
 		var set = [];
 		lookupRec(root, parseQuery(query), set);
 		return set;
 	}
-	
+
 	function parseQuery(q) : Query {
 		return new h2d.css.Parser().parseClasses(q);
 	}
-	
+
 	function matchQuery(q:Query, comp:Component) {
 		for( r in q )
 			if( h2d.css.Engine.ruleMatch(r, comp) )
 				return true;
 		return false;
 	}
-	
+
 	function lookupRec(comp:Component, q, set : Array<Component> ) {
 		if( matchQuery(q, comp) )
 			set.push(comp);
 		for( s in comp.components )
 			lookupRec(s, q, set);
 	}
-	
+
 }

+ 6 - 6
h2d/comp/Label.hx

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

+ 7 - 7
h2d/comp/Parser.hx

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

+ 12 - 12
h2d/comp/Select.hx

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

+ 6 - 6
h2d/comp/Slider.hx

@@ -1,20 +1,20 @@
 package h2d.comp;
 
 class Slider extends Component {
-	
+
 	var cursor : Button;
 	var input : h2d.Interactive;
 	public var minValue : Float = 0.;
 	public var maxValue : Float = 1.;
 	public var value(default, set) : Float;
-	
+
 	@:access(h2d.comp.Button)
 	public function new(?parent) {
 		super("slider", parent);
 		cursor = new Button("", this);
 		cursor.input.cancelEvents = true;
 		cursor.onMouseDown = function() {
-			
+
 		};
 		input = new h2d.Interactive(0, 0, this);
 		input.onPush = function(e) {
@@ -29,11 +29,11 @@ class Slider extends Component {
 		}
 		value = 0.;
 	}
-	
+
 	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;
 	}
-	
+
 	function gotoValue( v : Float ) {
 		if( v < minValue ) v = minValue;
 		if( v > maxValue ) v = maxValue;
@@ -51,7 +51,7 @@ class Slider extends Component {
 			value = v;
 		onChange(value);
 	}
-	
+
 	function set_value(v:Float) {
 		if( v < minValue ) v = minValue;
 		if( v > maxValue ) v = maxValue;

+ 3 - 3
h2d/css/Fill.hx

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

+ 5 - 5
h2d/css/Parser.hx

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

+ 6 - 6
h2d/css/Style.hx

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

+ 2 - 0
h2d/css/default.css

@@ -6,6 +6,8 @@
 	border : none;
 	background-color : transparent;
 	text-align : left;
+	padding : 0;
+	margin : 0;
 }
 
 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.
 	**/
 	Managed;
+	/**
+		Directly map the buffer content to the shader inputs, without assuming [pos:vec3,normal:vec3,uv:vec2] default prefix.
+	**/
+	RawFormat;
 	/**
 		Used internaly
 	**/
@@ -26,17 +30,23 @@ enum BufferFlag {
 class Buffer {
 	public static var GUID = 0;
 	public var id : Int;
+	#if debug
+	var allocPos : h3d.impl.AllocPos;
+	#end
 
 	public var buffer(default,null) : h3d.impl.ManagedBuffer;
 	public var position(default,null) : Int;
 	public var vertices(default,null) : Int;
 	public var next(default,null) : Buffer;
 	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++;
 		this.vertices = vertices;
 		this.flags = new haxe.EnumFlags();
+		#if debug
+		this.allocPos = allocPos;
+		#end
 		if( flags != null )
 			for( f in flags )
 				this.flags.set(f);
@@ -49,7 +59,7 @@ class Buffer {
 	public function isDisposed() {
 		return buffer == null || buffer.isDisposed();
 	}
-	
+
 	public function dispose() {
 		if( buffer != null ) {
 			buffer.freeBuffer(this);
@@ -57,7 +67,7 @@ class Buffer {
 			if( next != null ) next.dispose();
 		}
 	}
-	
+
 	/**
 		Returns the total number of vertices including the potential next buffers if it is split.
 	**/
@@ -70,7 +80,7 @@ class Buffer {
 		}
 		return count;
 	}
-	
+
 	public function uploadVector( buf : hxd.FloatBuffer, bufPos : Int, vertices : Int ) {
 		var cur = this;
 		while( vertices > 0 ) {
@@ -82,7 +92,7 @@ class Buffer {
 			cur = cur.next;
 		}
 	}
-	
+
 	public function uploadBytes( data : haxe.io.Bytes, dataPos : Int, vertices : Int ) {
 		var cur = this;
 		while( vertices > 0 ) {
@@ -94,28 +104,34 @@ class Buffer {
 			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);
 		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 {
 	public var id : Int;
 	public var buffer : Buffer;
 	public var offset : Int;
-	
+
 	/*
 		This is used to return a list of BufferOffset without allocating an array
 	*/
 	public var next : BufferOffset;
-	
+
 	static var UID = 0;
-	
+
 	public function new(buffer, offset) {
 		this.id = UID++;
 		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
 
 class Camera {
-	
+
 	public var zoom : Float;
-	
+
 	/**
 		The screenRatio represents the W/H screen ratio.
 	 **/
 	public var screenRatio : Float;
-	
+
 	/**
 		The horizontal FieldOfView, in degrees.
 	**/
 	public var fovX : Float;
 	public var zNear : Float;
 	public var zFar : Float;
-	
+
 	/**
 		Set orthographic bounds.
 	**/
 	public var orthoBounds : h3d.col.Bounds;
-	
+
 	public var rightHanded : Bool;
-	
+
 	public var mproj : Matrix;
 	public var mcam : Matrix;
 	public var m : Matrix;
-	
+
 	public var pos : Vector;
 	public var up : Vector;
 	public var target : Vector;
-	
+
 	public var viewX : Float = 0.;
 	public var viewY : Float = 0.;
-	
+
 	var minv : Matrix;
 	var needInv : Bool;
 
@@ -54,14 +54,14 @@ class Camera {
 		mproj = new Matrix();
 		update();
 	}
-	
+
 	/**
 		Update the fovX value based on the requested fovY value (in degrees) and current screenRatio.
 	**/
 	public function setFovY( value : Float ) {
 		fovX = Math.atan( Math.tan(value * Math.PI / 180) / screenRatio ) * 180 / Math.PI;
 	}
-	
+
 	public function clone() {
 		var c = new Camera(fovX, zoom, screenRatio, zNear, zFar, rightHanded);
 		c.pos = pos.clone();
@@ -95,20 +95,20 @@ class Camera {
 		p.project(getInverseViewProj());
 		return p;
 	}
-	
+
 	public function update() {
 		makeCameraMatrix(mcam);
 		makeFrustumMatrix(mproj);
 		m.multiply(mcam, mproj);
 		needInv = true;
 	}
-	
+
 	public function lostUp() {
 		var p2 = pos.clone();
 		p2.normalize();
 		return Math.abs(p2.dot3(up)) > 0.999;
 	}
-	
+
 	public function movePosAxis( dx : Float, dy : Float, dz = 0. ) {
 		var p = new Vector(dx, dy, dz);
 		p.project(mcam);
@@ -124,7 +124,7 @@ class Camera {
 		target.y += p.y;
 		target.z += p.z;
 	}
-	
+
 	function makeCameraMatrix( m : Matrix ) {
 		// 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
@@ -156,26 +156,26 @@ class Camera {
 		m._43 = -az.dot3(pos);
 		m._44 = 1;
 	}
-	
+
 	function makeFrustumMatrix( m : Matrix ) {
 		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
 		// Matrixes have to solve the following formulaes :
 		//
 		// transform P by Mproj and divide everything by
 		//    [x,y,-zNear,1] => [sx/zNear, sy/zNear, 0, 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
-		
+
 		var bounds = orthoBounds;
 		if( bounds != null ) {
-			
+
 			var w = 1 / (bounds.xMax - bounds.xMin);
 			var h = 1 / (bounds.yMax - bounds.yMin);
 			var d = 1 / (bounds.zMax - bounds.zMin);
-			
+
 			m._11 = 2 * w;
 			m._22 = 2 * h;
 			m._33 = d;
@@ -183,16 +183,16 @@ class Camera {
 			m._42 = -(bounds.yMin + bounds.yMax) * h;
 			m._43 = -bounds.zMin * d;
 			m._44 = 1;
-			
+
 		} else {
-		
+
 			var scale = zoom / Math.tan(fovX * Math.PI / 360.0);
 			m._11 = scale;
 			m._22 = scale * screenRatio;
 			m._33 = zFar / (zFar - zNear);
 			m._34 = 1;
 			m._43 = -(zNear * zFar) / (zFar - zNear);
-			
+
 		}
 
 		m._11 += viewX * m._14;
@@ -204,12 +204,12 @@ class Camera {
 		m._22 += viewY * m._24;
 		m._32 += viewY * m._34;
 		m._42 += viewY * m._44;
-		
+
 		// our z is negative in that case
 		if( rightHanded ) {
 			m._33 *= -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 {
 
 	public var driver(default,null) : h3d.impl.Driver;
-	
+
 	public var mem(default,null) : h3d.impl.MemoryManager;
 
 	public var hardware(default, null) : Bool;
@@ -16,23 +16,18 @@ class Engine {
 	public var drawCalls(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 fullScreen(default, set) : Bool;
-	
+
 	public var fps(get, never) : Float;
 	public var frameCount : Int = 0;
-	
-	public var forcedMatBits : Int = 0;
-	public var forcedMatMask : Int = 0xFFFFFF;
-	
+
 	var realFps : Float;
 	var lastTime : Float;
 	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)
 	var curProjMatrix : h3d.Matrix;
 
@@ -41,14 +36,14 @@ class Engine {
 		this.hardware = hardware;
 		this.antiAlias = aa;
 		this.autoResize = true;
-		
+
 		#if (!flash && openfl)
 			hxd.Stage.openFLBoot(start);
 		#else
 			start();
 		#end
 	}
-	
+
 	function start() {
 		fullScreen = !hxd.System.isWindowed;
 		var stage = hxd.Stage.getInstance();
@@ -65,20 +60,20 @@ class Engine {
 		if( CURRENT == null )
 			CURRENT = this;
 	}
-	
+
 	static var CURRENT : Engine = null;
-	
+
 	static inline function check() {
 		#if debug
 		if ( CURRENT == null ) throw "no current context, please do this operation after engine init/creation";
 		#end
 	}
-	
+
 	public static inline function getCurrent() {
 		check();
 		return CURRENT;
 	}
-	
+
 	public inline function setCurrent() {
 		CURRENT = this;
 	}
@@ -90,38 +85,39 @@ class Engine {
 	public function driverName(details=false) {
 		return driver.getDriverName(details);
 	}
-	
+
 	public function setCapture( bmp : hxd.BitmapData, callb : Void -> Void ) {
 		driver.setCapture(bmp,callb);
 	}
 
-	public function selectShader( shader : h3d.impl.Shader ) {
+	public function selectShader( shader : hxsl.RuntimeShader ) {
 		if( driver.selectShader(shader) )
 			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() )
 			return false;
-		driver.selectBuffer(@:privateAccess buf.vbuf);
+		driver.selectBuffer(buf);
 		return true;
 	}
 
 	public inline function renderTriBuffer( b : Buffer, start = 0, max = -1 ) {
 		return renderBuffer(b, mem.triIndexes, 3, start, max);
 	}
-	
+
 	public inline function renderQuadBuffer( b : Buffer, start = 0, max = -1 ) {
 		return renderBuffer(b, mem.quadIndexes, 2, start, max);
 	}
-	
+
 	// 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 ) {
 		if( indexes.isDisposed() )
@@ -147,7 +143,7 @@ class Engine {
 					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
 				driver.draw(indexes.ibuf, pos * 3, ntri);
 				drawTriangles += ntri;
@@ -156,7 +152,7 @@ class Engine {
 			b = b.next;
 		} while( b != null );
 	}
-	
+
 	// 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 ) {
 		if( b.next != null )
@@ -165,14 +161,14 @@ class Engine {
 			return;
 		var maxTri = Std.int(indexes.count / 3);
 		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
 			driver.draw(indexes.ibuf, startTri * 3, drawTri);
 			drawTriangles += drawTri;
 			drawCalls++;
 		}
 	}
-	
+
 	public function renderMultiBuffers( buffers : Buffer.BufferOffset, indexes : Indexes, startTri = 0, drawTri = -1 ) {
 		var maxTri = Std.int(indexes.count / 3);
 		if( maxTri <= 0 ) return;
@@ -196,8 +192,9 @@ class Engine {
 
 	function onCreate( disposed ) {
 		if( autoResize ) {
-			width = hxd.System.width;
-			height = hxd.System.height;
+			var stage = hxd.Stage.getInstance();
+			width = stage.width;
+			height = stage.height;
 		}
 		if( disposed )
 			mem.onContextLost();
@@ -205,7 +202,7 @@ class Engine {
 			mem = new h3d.impl.MemoryManager(driver);
 			mem.init();
 		}
-		hardware = driver.isHardware();
+		hardware = driver.hasFeature(HardwareAccelerated);
 		set_debug(debug);
 		set_fullScreen(fullScreen);
 		resize(width, height);
@@ -214,29 +211,30 @@ class Engine {
 		else
 			onReady();
 	}
-	
+
 	public dynamic function onContextLost() {
 	}
 
 	public dynamic function onReady() {
 	}
-	
+
 	function onStageResize() {
 		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 )
 				resize(w, h);
 			onResized();
 		}
 	}
-	
+
 	function set_fullScreen(v) {
 		fullScreen = v;
 		if( mem != null && hxd.System.isWindowed )
 			hxd.Stage.getInstance().setFullScreen(v);
 		return v;
 	}
-	
+
 	public dynamic function onResized() {
 	}
 
@@ -252,14 +250,15 @@ class Engine {
 	public function begin() {
 		if( driver.isDisposed() )
 			return false;
-		driver.clear( ((backgroundColor>>16)&0xFF)/255 , ((backgroundColor>>8)&0xFF)/255, (backgroundColor&0xFF)/255, ((backgroundColor>>>24)&0xFF)/255);
 		// init
 		frameCount++;
 		drawTriangles = 0;
 		shaderSwitches = 0;
 		drawCalls = 0;
 		curProjMatrix = null;
+		currentTarget = null;
 		driver.begin(frameCount);
+		if( backgroundColor != null ) clear(backgroundColor, 1, 0);
 		return true;
 	}
 
@@ -267,18 +266,35 @@ class Engine {
 		driver.reset();
 	}
 
+	public function hasFeature(f) {
+		return driver.hasFeature(f);
+	}
+
 	public function end() {
 		driver.present();
 		reset();
 		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
      * 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;
 		obj.render(this);
 		end();
-				
+
 		var delta = haxe.Timer.stamp() - lastTime;
 		lastTime += delta;
 		if( delta > 0 ) {
@@ -305,54 +321,14 @@ class Engine {
 		}
 		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() {
 		driver.dispose();
 		hxd.Stage.getInstance().removeResizeEvent(onStageResize);
 	}
-	
+
 	function get_fps() {
 		return Math.ceil(realFps * 100) / 100;
 	}
-	
+
 }

+ 6 - 6
h3d/Indexes.hx

@@ -7,26 +7,26 @@ class Indexes {
 	var mem : h3d.impl.MemoryManager;
 	var ibuf : h3d.impl.Driver.IndexBuffer;
 	public var count(default,null) : Int;
-	
+
 	public function new(count) {
 		this.mem = h3d.Engine.getCurrent().mem;
 		this.count = count;
 		mem.allocIndexes(this);
 	}
-	
+
 	public function isDisposed() {
 		return ibuf == null;
 	}
-	
+
 	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() {
 		if( ibuf != null )
 			mem.deleteIndexes(this);
 	}
-	
+
 	public static function alloc( i : hxd.IndexBuffer ) {
 		var idx = new Indexes( i.length );
 		idx.upload(i, 0, i.length);

+ 48 - 0
h3d/Matrix.hx

@@ -496,6 +496,54 @@ class Matrix {
 		_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
 
 	public static function I() {

+ 23 - 23
h3d/Quat.hx

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

+ 43 - 31
h3d/Vector.hx

@@ -17,7 +17,7 @@ class Vector {
 		this.z = z;
 		this.w = w;
 	}
-	
+
 	public inline function distance( v : Vector ) {
 		return Math.sqrt(distanceSq(v));
 	}
@@ -41,7 +41,7 @@ class 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);
 	}
-	
+
 	public inline function reflect( n : Vector ) {
 		var k = 2 * this.dot3(n);
 		return new Vector(x - k * n.x, y - k * n.y, z - k * n.z, 1);
@@ -70,20 +70,20 @@ class Vector {
 		y *= k;
 		z *= k;
 	}
-	
+
 	public inline function getNormalized() {
 		var k = lengthSq();
 		if( k < hxd.Math.EPSILON ) k = 0 else k = k.invSqrt();
 		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.y = y;
 		this.z = z;
 		this.w = w;
 	}
-	
+
 	public inline function load(v : Vector) {
 		this.x = v.x;
 		this.y = v.y;
@@ -96,7 +96,7 @@ class Vector {
 		y *= f;
 		z *= f;
 	}
-	
+
 	public inline function project( m : Matrix ) {
 		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;
@@ -107,7 +107,7 @@ class Vector {
 		z = pz * iw;
 		w = 1;
 	}
-	
+
 	public inline function lerp( v1 : Vector, v2 : Vector, k : Float ) {
 		var x = Math.lerp(v1.x, v2.x, k);
 		var y = Math.lerp(v1.y, v2.y, k);
@@ -118,7 +118,7 @@ class Vector {
 		this.z = z;
 		this.w = w;
 	}
-	
+
 	public inline function transform3x4( m : Matrix ) {
 		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;
@@ -136,7 +136,7 @@ class Vector {
 		y = py;
 		z = pz;
 	}
-	
+
 	public inline function transform( m : Matrix ) {
 		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;
@@ -147,38 +147,50 @@ class Vector {
 		z = pz;
 		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() {
 		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;
-		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 alphas : haxe.ds.Vector<Float>;
 	public var uvs : haxe.ds.Vector<Float>;
-	
+
 	override function clone() : AnimatedObject {
 		var o = new FrameObject(objectName);
 		o.frames = frames;
@@ -14,7 +14,7 @@ class FrameObject extends AnimatedObject {
 		return o;
 	}
 }
-	
+
 class FrameAnimation extends Animation {
 
 	var syncFrame : Int;
@@ -23,13 +23,13 @@ class FrameAnimation extends Animation {
 		super(name,frame,sampling);
 		syncFrame = -1;
 	}
-	
+
 	public function addCurve( objName, frames ) {
 		var f = new FrameObject(objName);
 		f.frames = frames;
 		objects.push(f);
 	}
-	
+
 	public function addAlphaCurve( objName, alphas ) {
 		var f = new FrameObject(objName);
 		f.alphas = alphas;
@@ -41,25 +41,25 @@ class FrameAnimation extends Animation {
 		f.uvs = uvs;
 		objects.push(f);
 	}
-	
+
 	inline function getFrames() : Array<FrameObject> {
 		return cast objects;
 	}
-	
+
 	override function initInstance() {
 		super.initInstance();
 		for( a in getFrames() )
 			if( a.alphas != null && (a.targetObject == null || !a.targetObject.isMesh()) )
 				throw a.objectName + " should be a mesh";
 	}
-	
+
 	override function clone(?a:Animation) {
 		if( a == null )
 			a = new FrameAnimation(name, frameCount, sampling);
 		super.clone(a);
 		return a;
 	}
-	
+
 	@:access(h3d.scene.Skin)
 	override function sync( decompose = false ) {
 		if( decompose ) throw "Decompose not supported on Frame Animation";
@@ -71,12 +71,8 @@ class FrameAnimation extends Animation {
 		for( o in getFrames() ) {
 			if( o.alphas != null ) {
 				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 ) {
 				o.targetSkin.currentRelPose[o.targetJoint] = o.frames[frame];
 				o.targetSkin.jointsUpdated = true;
@@ -84,5 +80,5 @@ class FrameAnimation extends Animation {
 				o.targetObject.defaultTransform = o.frames[frame];
 		}
 	}
-	
+
 }

+ 7 - 10
h3d/anim/LinearAnimation.hx

@@ -101,22 +101,19 @@ class LinearAnimation extends Animation {
 		for( o in getFrames() ) {
 			if( o.alphas != null ) {
 				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;
 			}
 			if( o.uvs != null ) {
 				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.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;
 			}
 			var f1 = o.frames[frame1], f2 = o.frames[frame2];

+ 5 - 5
h3d/anim/SimpleBlend.hx

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

+ 16 - 16
h3d/anim/Skin.hx

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

+ 8 - 8
h3d/anim/SmoothTransition.hx

@@ -12,17 +12,17 @@ class SmoothedObject extends Animation.AnimatedObject {
 }
 
 class SmoothTransition extends Transition {
-	
+
 	static var MZERO = h3d.Matrix.L([
 		1, 0, 0, 0,
 		0, 1, 1, 0,
 		0, 0, 1, 0,
 		0, 0, 0, 1,
 	]);
-	
+
 	public var blendFactor : Float;
 	var tspeed : Float;
-	
+
 	public function new(current, target, speed) {
 		super("smooth", current, target);
 		blendFactor = 0.;
@@ -32,7 +32,7 @@ class SmoothTransition extends Transition {
 		this.isInstance = true;
 		initObjects();
 	}
-	
+
 	function initObjects() {
 		var allObjects = new Map();
 		var mzero = MZERO;
@@ -59,13 +59,13 @@ class SmoothTransition extends Transition {
 			so.isAnim2 = true;
 		}
 	}
-	
+
 	override function bind( base ) {
 		super.bind(base);
 		this.objects = [];
 		initObjects();
 	}
-	
+
 	@:access(h3d.scene.Skin)
 	override function sync( decompose = false ) {
 		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;
 		}
 	}
-	
+
 	override function update( dt : Float ) : Float {
 		var rt = super.update(dt);
 		var st = dt - rt;
@@ -123,5 +123,5 @@ class SmoothTransition extends Transition {
 		}
 		return rt;
 	}
-	
+
 }

+ 8 - 8
h3d/anim/Transition.hx

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

+ 26 - 26
h3d/col/Bounds.hx

@@ -2,18 +2,18 @@ package h3d.col;
 import hxd.Math;
 
 class Bounds {
-	
+
 	public var xMin : Float;
 	public var xMax : Float;
 	public var yMin : Float;
 	public var yMax : Float;
 	public var zMin : Float;
 	public var zMax : Float;
-	
+
 	public inline function new() {
 		empty();
 	}
-	
+
 	public function inFrustum( mvp : Matrix ) {
 		if( testPlane(Plane.frustumLeft(mvp)) < 0 )
 			return false;
@@ -29,7 +29,7 @@ class Bounds {
 			return false;
 		return true;
 	}
-	
+
 	inline function testPlane( p : Plane ) {
 		var a = p.nx;
 		var b = p.ny;
@@ -41,7 +41,7 @@ class Bounds {
 		var rr = a * (xMax - xMin) + b * (yMax - yMin) + c * (zMax - zMin);
 		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.
 	 * @param	mvp : the model-view-projection matrix to test against
@@ -49,7 +49,7 @@ class Bounds {
 	 */
 	public function inFrustumDetails( mvp : Matrix, checkZ = true ) {
 		var ret = 1;
-		
+
 		// left
 		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);
@@ -71,7 +71,7 @@ class Bounds {
 			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);
 		if( n + p.d < 0 ) ret = 0;
-		
+
 		// top
 		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);
@@ -79,7 +79,7 @@ class Bounds {
 			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);
 		if( n + p.d < 0 ) ret = 0;
-				
+
 		if( checkZ ) {
 			// nea
 			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);
 			if( n + p.d < 0 ) ret = 0;
 		}
-		
+
 		return ret;
 	}
-	
+
 	public function transform3x4( m : Matrix ) {
 		var xMin = xMin, yMin = yMin, zMin = zMin, xMax = xMax, yMax = yMax, zMax = zMax;
 		empty();
@@ -129,15 +129,15 @@ class Bounds {
 		v.transform(m);
 		addPoint(v);
 	}
-	
+
 	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);
 	}
-	
+
 	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;
 	}
-	
+
 	public inline function add( b : Bounds ) {
 		if( b.xMin < xMin ) xMin = b.xMin;
 		if( b.xMax > xMax ) xMax = b.xMax;
@@ -164,7 +164,7 @@ class Bounds {
 		if( z < zMin ) zMin = z;
 		if( z > zMax ) zMax = z;
 	}
-	
+
 	public function intersection( a : Bounds, b : Bounds ) {
 		var xMin = Math.max(a.xMin, b.xMin);
 		var yMin = Math.max(a.yMin, b.yMin);
@@ -179,7 +179,7 @@ class Bounds {
 		this.zMin = zMin;
 		this.zMax = zMax;
 	}
-	
+
 	public inline function offset( dx : Float, dy : Float, dz : Float ) {
 		xMin += dx;
 		xMax += dx;
@@ -188,7 +188,7 @@ class Bounds {
 		zMin += dz;
 		zMax += dz;
 	}
-	
+
 	public inline function setMin( p : Point ) {
 		xMin = p.x;
 		yMin = p.y;
@@ -200,7 +200,7 @@ class Bounds {
 		yMax = p.y;
 		zMax = p.z;
 	}
-	
+
 	public function load( b : Bounds ) {
 		xMin = b.xMin;
 		xMax = b.xMax;
@@ -209,7 +209,7 @@ class Bounds {
 		zMin = b.zMin;
 		zMax = b.zMax;
 	}
-	
+
 	public function scaleCenter( v : Float ) {
 		var dx = (xMax - xMin) * 0.5 * v;
 		var dy = (yMax - yMin) * 0.5 * v;
@@ -224,11 +224,11 @@ class Bounds {
 		yMax = my + dy;
 		zMax = mz + dz;
 	}
-	
+
 	public inline function getMin() {
 		return new Point(xMin, yMin, zMin);
 	}
-	
+
 	public inline function getCenter() {
 		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() {
 		return new Point(xMax - xMin, yMax - yMin, zMax - zMin);
 	}
-	
+
 	public inline function getMax() {
 		return new Point(xMax, yMax, zMax);
 	}
-	
+
 	public inline function empty() {
 		xMin = 1e20;
 		xMax = -1e20;
@@ -258,7 +258,7 @@ class Bounds {
 		zMin = -1e20;
 		zMax = 1e20;
 	}
-	
+
 	public inline function clone() {
 		var b = new Bounds();
 		b.xMin = xMin;
@@ -269,11 +269,11 @@ class Bounds {
 		b.zMax = zMax;
 		return b;
 	}
-	
+
 	public function toString() {
 		return "{" + getMin() + "," + getMax() + "}";
 	}
-	
+
 	public static inline function fromPoints( min : Point, max : Point ) {
 		var b = new Bounds();
 		b.setMin(min);
@@ -291,5 +291,5 @@ class Bounds {
 		b.zMax = z + dz;
 		return b;
 	}
-	
+
 }

+ 17 - 17
h3d/col/Plane.hx

@@ -3,31 +3,31 @@ import hxd.Math;
 
 @:allow(h3d.col)
 class Plane {
-	
+
 	// Place equation :  nx.X + ny.Y + nz.Z - d = 0
 	var nx : Float;
 	var ny : Float;
 	var nz : Float;
 	var d : Float;
-	
+
 	inline function new(nx, ny, nz, d) {
 		this.nx = nx;
 		this.ny = ny;
 		this.nz = nz;
 		this.d = d;
 	}
-	
+
 	/**
 		Returns the plan normal
 	**/
 	public inline function getNormal() {
 		return new Point(nx, ny, nz);
 	}
-	
+
 	public inline function getNormalDistance() {
 		return d;
 	}
-	
+
 	/**
 		Normalize the plan, so we can use distance().
 	**/
@@ -38,22 +38,22 @@ class Plane {
 		nz *= len;
 		d *= len;
 	}
-	
+
 	public function toString() {
 		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.
 	**/
 	public inline function distance( p : Point ) {
 		return nx * p.x + ny * p.y + nz * p.z - d;
 	}
-	
+
 	public inline function side( p : Point ) {
 		return distance(p) >= 0;
 	}
-	
+
 	public inline function project( p : Point ) : Point {
 		var d = distance(p);
 		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.z = p.z - d * nz;
 	}
-	
+
 	public static inline function fromPoints( p0 : Point, p1 : Point, p2 : Point ) {
 		var d1 = p1.sub(p0);
 		var d2 = p2.sub(p0);
 		var n = d1.cross(d2);
 		return new Plane(n.x,n.y,n.z,n.dot(p0));
 	}
-	
+
 	public static inline function fromNormalPoint( n : Point, p : Point ) {
 		return new Plane(n.x,n.y,n.z,n.dot(p));
 	}
-	
+
 	public static inline function X(v:Float) {
 		return new Plane( 1, 0, 0, v );
 	}
-	
+
 	public static inline function Y(v:Float) {
 		return new Plane( 0, 1, 0, v );
 	}
@@ -88,7 +88,7 @@ class Plane {
 	public static inline function Z(v:Float) {
 		return new Plane( 0, 0, 1, v );
 	}
-	
+
 	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));
 	}
@@ -96,7 +96,7 @@ class Plane {
 	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);
 	}
-	
+
 	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));
 	}
@@ -104,7 +104,7 @@ class Plane {
 	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);
 	}
-	
+
 	public static inline function frustumNear( mvp : Matrix ) {
 		return new Plane(mvp._13, mvp._23, mvp._33, -mvp._43);
 	}
@@ -112,5 +112,5 @@ class Plane {
 	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);
 	}
-	
+
 }

+ 12 - 12
h3d/col/Point.hx

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

+ 10 - 10
h3d/col/Ray.hx

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

+ 5 - 5
h3d/col/Seg.hx

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

+ 77 - 69
h3d/impl/Driver.hx

@@ -1,107 +1,115 @@
 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
-	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
-	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
-	typedef IndexBuffer = Int;
-	typedef VertexBuffer = Int;
-	typedef Texture = Int;
+typedef IndexBuffer = Int;
+typedef VertexBuffer = Int;
+typedef Texture = Int;
 #end
 
+enum Feature {
+	HardwareAccelerated;
+	StandardDerivatives;
+	FloatTextures;
+	TargetDepthBuffer;
+}
+
 class Driver {
-	
+
+	public var logEnable : Bool;
+
+	public function hasFeature( f : Feature ) {
+		return false;
+	}
+
 	public function isDisposed() {
 		return true;
 	}
-	
+
 	public function dispose() {
 	}
-	
+
 	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 reset() {
 	}
-	
+
 	public function getDriverName( details : Bool ) {
 		return "Not available";
 	}
-	
+
 	public function init( onCreate : Bool -> Void, forceSoftware = false ) {
 	}
-	
+
 	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;
 	}
-	
-	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> {
 		return null;
 	}
-	
-	public function selectBuffer( buffer : VertexBuffer ) {
+
+	public function selectBuffer( buffer : Buffer ) {
 	}
-	
+
 	public function selectMultiBuffers( buffers : Buffer.BufferOffset ) {
 	}
-	
+
 	public function draw( ibuf : IndexBuffer, startIndex : Int, ntriangles : 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 isHardware() {
-		return true;
-	}
-	
+
 	public function setDebug( b : Bool ) {
 	}
-	
+
 	public function allocTexture( t : h3d.mat.Texture ) : Texture {
 		return null;
 	}
@@ -110,35 +118,35 @@ class Driver {
 		return null;
 	}
 
-	public function allocVertex( m : ManagedBuffer ) : VertexBuffer {
+	public function allocVertexes( m : ManagedBuffer ) : VertexBuffer {
 		return null;
 	}
-	
+
 	public function disposeTexture( t : Texture ) {
 	}
-	
+
 	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 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 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 size(default,null) : Int;
 	public var flags(default, null) : haxe.EnumFlags<Buffer.BufferFlag>;
-	
+
 	var vbuf : Driver.VertexBuffer;
 	var freeList : FreeCell;
 	var next : ManagedBuffer;
-	
+
 	public function new( stride, size, ?flags : Array<Buffer.BufferFlag> ) {
 		this.flags = new haxe.EnumFlags();
 		if( flags != null )
@@ -43,7 +43,7 @@ class ManagedBuffer {
 	public function uploadVertexBytes( start : Int, vertices : Int, data : haxe.io.Bytes, dataPos = 0 ) {
 		mem.driver.uploadVertexBytes(vbuf, start, vertices, data, dataPos);
 	}
-	
+
 	public function alloc(vertices,align) {
 		var p = allocPosition(vertices, align);
 		if( p < 0 )
@@ -55,7 +55,7 @@ class ManagedBuffer {
 		};
 		return b;
 	}
-	
+
 	public function getFreeVertices() {
 		var m = 0;
 		var l = freeList;
@@ -65,7 +65,7 @@ class ManagedBuffer {
 		}
 		return m;
 	}
-	
+
 	function allocPosition( nvert : Int, align : Int ) {
 		var free = freeList;
 		while( free != null ) {
@@ -90,7 +90,7 @@ class ManagedBuffer {
 		free.count -= nvert;
 		return pos;
 	}
-	
+
 	function allocBuffer( b : Buffer ) {
 		var align = b.flags.has(Quads) ? 4 : (b.flags.has(Triangles) ? 3 : 1);
 		var p = allocPosition(b.vertices, align);
@@ -101,7 +101,7 @@ class ManagedBuffer {
 		};
 		return true;
 	}
-	
+
 	@:allow(h3d.Buffer.dispose)
 	function freeBuffer( b : Buffer ) {
 		var prev : FreeCell = null;
@@ -141,7 +141,7 @@ class ManagedBuffer {
 	public function dispose() {
 		mem.freeManaged(this);
 	}
-	
+
 	public inline function isDisposed() {
 		return vbuf == null;
 	}

+ 2 - 2
h3d/impl/MemoryManager.hx

@@ -84,7 +84,7 @@ class MemoryManager {
 		if( m.vbuf != null ) return;
 
 		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();
 			garbage();
 			cleanManagedBuffers();
@@ -101,7 +101,7 @@ class MemoryManager {
 	@:allow(h3d.impl.ManagedBuffer)
 	function freeManaged( m : ManagedBuffer ) {
 		if( m.vbuf == null ) return;
-		driver.disposeVertex(m.vbuf);
+		driver.disposeVertexes(m.vbuf);
 		m.vbuf = null;
 		usedMemory -= m.size * m.stride * 4;
 		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;
 import h3d.impl.Driver;
+import h3d.mat.Pass;
 
 #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 {
 
-	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 ctx : flash.display3D.Context3D;
 	var onCreateCallback : Bool -> Void;
 
 	var curMatBits : Int;
-	var curShader : hxsl.Shader.ShaderInstance;
-	var curBuffer : VertexBuffer;
+	var curShader : CompiledShader;
+	var curBuffer : Buffer;
 	var curMultiBuffer : Array<Int>;
 	var curAttributes : Int;
 	var curTextures : Array<h3d.mat.Texture>;
@@ -53,6 +70,8 @@ class Stage3dDriver extends Driver {
 	var enableDraw : Bool;
 	var capture : { bmp : hxd.BitmapData, callb : Void -> Void };
 	var frame : Int;
+	var programs : Map<Int, CompiledShader>;
+	var isStandardMode : Bool;
 
 	@:allow(h3d.impl.VertexWrapper)
 	var empty : flash.utils.ByteArray;
@@ -60,10 +79,15 @@ class Stage3dDriver extends Driver {
 	public function new() {
 		empty = new flash.utils.ByteArray();
 		s3d = flash.Lib.current.stage.stage3Ds[0];
+		programs = new Map();
 		curTextures = [];
 		curMultiBuffer = [];
 	}
 
+	override function logImpl( str : String ) {
+		flash.Lib.trace(str);
+	}
+
 	override function getDriverName(details:Bool) {
 		return ctx == null ? "None" : (details ? ctx.driverInfo : ctx.driverInfo.split(" ")[0]);
 	}
@@ -92,14 +116,17 @@ class Stage3dDriver extends Driver {
 		this.onCreateCallback = onCreate;
 		s3d.addEventListener(flash.events.Event.CONTEXT3D_CREATE, this.onCreate);
 		s3d.requestContext3D( forceSoftware ? "software" : "auto", PROFILE );
+		isStandardMode = Std.string(PROFILE) == "standard";
 	}
 
 	function onCreate(_) {
 		var old = ctx;
+		for( p in programs )
+			p.p.dispose();
+		programs = new Map();
 		if( old != null ) {
 			if( old.driverInfo != "Disposed" ) throw "Duplicate onCreate()";
 			old.dispose();
-			hxsl.Shader.ShaderGlobals.disposeAll();
 			ctx = s3d.context3D;
 			onCreateCallback(true);
 		} 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) {
@@ -118,8 +149,12 @@ class Stage3dDriver extends Driver {
 		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 ) {
@@ -152,7 +187,7 @@ class Stage3dDriver extends Driver {
 		t.dispose();
 	}
 
-	override function allocVertex( buf : ManagedBuffer ) : VertexBuffer {
+	override function allocVertexes( buf : ManagedBuffer ) : VertexBuffer {
 		var v;
 		try {
 			v = ctx.createVertexBuffer(buf.size, buf.stride);
@@ -181,10 +216,11 @@ class Stage3dDriver extends Driver {
 	override function allocTexture( t : h3d.mat.Texture ) : Texture {
 		var fmt = flash.display3D.Context3DTextureFormat.BGRA;
 		t.lastFrame = frame;
+		t.flags.unset(WasCleared);
 		if( t.flags.has(TargetDepth) )
 			throw "Unsupported texture flag";
 		try {
-			if( t.flags.has(IsRectangle) ) {
+			if( t.flags.has(IsNPOT) ) {
 				if( t.flags.has(Cubic) || t.flags.has(MipMapped) )
 					throw "Not power of two texture is not supported with these flags";
 				#if !flash11_8
@@ -207,7 +243,7 @@ class Stage3dDriver extends Driver {
 		if( t.flags.has(Cubic) ) {
 			var t = flash.Lib.as(t.t, flash.display3D.textures.CubeTexture);
 			t.uploadFromBitmapData(bmp.toNative(), side, mipLevel);
-		} else if( t.flags.has(IsRectangle) ) {
+		} else if( t.flags.has(IsNPOT) ) {
 			#if flash11_8
 			var t = flash.Lib.as(t.t, flash.display3D.textures.RectangleTexture);
 			t.uploadFromBitmapData(bmp.toNative());
@@ -224,7 +260,7 @@ class Stage3dDriver extends Driver {
 		if( t.flags.has(Cubic) ) {
 			var t = flash.Lib.as(t.t, flash.display3D.textures.CubeTexture);
 			t.uploadFromByteArray(data, 0, side, mipLevel);
-		} else if( t.flags.has(IsRectangle) ) {
+		} else if( t.flags.has(IsNPOT) ) {
 			#if flash11_8
 			var t = flash.Lib.as(t.t, flash.display3D.textures.RectangleTexture);
 			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.b = null;
 	}
@@ -245,7 +281,7 @@ class Stage3dDriver extends Driver {
 	}
 
 	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 ) {
@@ -257,48 +293,149 @@ class Stage3dDriver extends Driver {
 		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();
 		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 );
 	}
 
-	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 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;
 			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;
-			s.varsChanged = true;
+			curShader = p;
 			// unbind extra textures
-			var tcount : Int = s.textures.length;
+			var tcount : Int = shader.fragment.textures.length + shader.vertex.textures.length;
 			while( curTextures.length > tcount ) {
 				curTextures.pop();
 				ctx.setTextureAt(curTextures.length, null);
@@ -306,28 +443,37 @@ class Stage3dDriver extends Driver {
 			// force remapping of vertex buffer
 			curBuffer = null;
 			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() )
 					t = h3d.mat.Texture.fromColor(0xFFFF00FF);
 				if( t != null && t.t == null && t.realloc != null ) {
 					t.alloc();
 					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];
 				if( t != cur ) {
 					ctx.setTextureAt(i, t.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( !t.hasDefaultFlags() || !s.texHasConfig[s.textureMap[i]] ) {
+				if( true /*!t.hasDefaultFlags() || !s.texHasConfig[s.textureMap[i]]*/ ) {
 					if( cur == null || t.bits != curSamplerBits[i] ) {
 						ctx.setSamplerStateAt(i, WRAP[t.wrap.getIndex()], FILTER[t.filter.getIndex()], MIP[t.mipMap.getIndex()]);
 						curSamplerBits[i] = t.bits;
@@ -337,26 +483,63 @@ class Stage3dDriver extends Driver {
 					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 )
 			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;
 		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 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 )
 			ctx.setVertexBufferAt(i, null);
@@ -364,7 +547,7 @@ class Stage3dDriver extends Driver {
 	}
 
 	override function getShaderInputNames() {
-		return curShader.bufferNames;
+		return curShader.inputNames;
 	}
 
 	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 ) {
 			ctx.setRenderToBackBuffer();
 			inTarget = null;
@@ -458,8 +641,11 @@ class Stage3dDriver extends Driver {
 			ctx.setRenderToTexture(t.t, t.flags.has(TargetUseDefaultDepth));
 			inTarget = t;
 			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();
-			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.
 	**/
-	IsRectangle;
+	IsNPOT;
 	/**
 		Don't initialy allocate the texture memory.
 	**/
@@ -97,9 +97,30 @@ enum TextureFlags {
 		Inform that we will often perform upload operations on this texture
 	**/
 	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.
 	**/
 	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;
 import h3d.mat.Data;
+import h3d.mat.Pass;
 
 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;
 
-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 {
 
-	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);
 		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 {
 
 	static var UID = 0;
-	
+
 	var t : h3d.impl.Driver.Texture;
 	var mem : h3d.impl.MemoryManager;
 	#if debug
@@ -28,7 +28,7 @@ class Texture {
 		it's been free because of lack of memory.
 	**/
 	public var realloc : Void -> Void;
-	
+
 	public function new(w, h, ?flags : Array<TextureFlags>, ?allocPos : h3d.impl.AllocPos ) {
 		var engine = h3d.Engine.getCurrent();
 		this.mem = engine.mem;
@@ -42,8 +42,8 @@ class Texture {
 		while( tw < w ) tw <<= 1;
 		while( th < h) th <<= 1;
 		if( tw != w || th != h )
-			this.flags.set(IsRectangle);
-			
+			this.flags.set(IsNPOT);
+
 		// make the texture disposable if we're out of memory
 		// this can be disabled after allocation by reseting realloc
 		if( this.flags.has(Target) ) realloc = function() { };
@@ -59,16 +59,23 @@ class Texture {
 		#end
 		alloc();
 	}
-	
+
 	public function alloc() {
 		if( t == null )
 			mem.allocTexture(this);
 	}
-	
+
 	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) {
 		name = n;
 	}
@@ -84,13 +91,13 @@ class Texture {
 		bits = (bits & ~(3 << 3)) | (Type.enumIndex(f) << 3);
 		return filter = f;
 	}
-	
+
 	function set_wrap(w:Wrap) {
 		bits |= 0x80000;
 		bits = (bits & ~(3 << 6)) | (Type.enumIndex(w) << 6);
 		return wrap = w;
 	}
-	
+
 	inline function hasDefaultFlags() {
 		return bits & 0x80000 == 0;
 	}
@@ -98,21 +105,21 @@ class Texture {
 	public inline function isDisposed() {
 		return t == null && realloc == null;
 	}
-	
+
 	public function resize(width, height) {
 		dispose();
-		
+
 		var tw = 1, th = 1;
 		while( tw < width ) tw <<= 1;
 		while( th < height ) th <<= 1;
 		if( tw != width || th != height )
-			this.flags.set(IsRectangle);
+			this.flags.set(IsNPOT);
 		else
-			this.flags.unset(IsRectangle);
+			this.flags.unset(IsNPOT);
 
 		this.width = width;
 		this.height = height;
-		
+
 		if( !flags.has(NoAlloc) )
 			alloc();
 	}
@@ -131,7 +138,7 @@ class Texture {
 		uploadPixels(p);
 		p.dispose();
 	}
-	
+
 	public function uploadBitmap( bmp : hxd.BitmapData, mipLevel = 0, side = 0 ) {
 		alloc();
 		mem.driver.uploadTextureBitmap(this, bmp, mipLevel, side);
@@ -150,19 +157,19 @@ class Texture {
 			#end
 		}
 	}
-	
+
 	public static function fromBitmap( bmp : hxd.BitmapData, ?allocPos : h3d.impl.AllocPos ) {
 		var t = new Texture(bmp.width, bmp.height, allocPos);
 		t.uploadBitmap(bmp);
 		return t;
 	}
-	
+
 	public static function fromPixels( pixels : hxd.Pixels, ?allocPos : h3d.impl.AllocPos ) {
 		var t = new Texture(pixels.width, pixels.height, allocPos);
 		t.uploadPixels(pixels);
 		return t;
 	}
-	
+
 	static var COLOR_CACHE = new Map<Int,h3d.mat.Texture>();
 	/**
 		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 {
-	
+
 	public var vx : Value;
 	public var vy : Value;
 	public var vz : Value;
-	
+
 	public function new(x, y, z) {
 		this.vx = x;
 		this.vy = y;
 		this.vz = z;
 	}
-	
+
 }
 
 class ColorKey {
-	
+
 	public var time : Float;
 	public var r : Float;
 	public var g : Float;
 	public var b : Float;
 	public var next : ColorKey;
-	
+
 	public function new(time, r, g, b) {
 		this.time = time;
 		this.r = r;
 		this.g = g;
 		this.b = b;
 	}
-	
+
 }
 
 enum BlendMode {
@@ -74,7 +74,7 @@ interface Randomized {
 }
 
 class State {
-	
+
 	// material
 	public var textureName : String;
 	public var frames : Array<h2d.Tile>;
@@ -82,7 +82,7 @@ class State {
 	public var sortMode : SortMode;
 	public var is3D : Bool;
 	public var isAlphaMap : Bool;
-	
+
 	// emit
 	public var loop	: Bool;
 	public var emitRate : Value;
@@ -98,7 +98,7 @@ class State {
 	public var globalLife : Float;
 	public var globalSpeed : Value;
 	public var globalSize : Value;
-	
+
 	// particle globals
 	public var life : Value;
 	public var size : Value;
@@ -106,28 +106,28 @@ class State {
 	public var rotation : Value;
 	public var speed : Value;
 	public var gravity : Value;
-	
+
 	// effects
 	public var force : Null<ValueXYZ>;
 	public var colors : Null<Array<{ time : Float, color : Int }>>;
 	public var light : Value;
 	public var alpha : Value;
-	
+
 	// collide
 	public var collide : Bool;
 	public var collideKill : Bool;
 	public var bounce : Float;
-	
+
 	// animation
 	public var frame : Null<Value>;
-	
+
 	// extra
 	public var delay : Float;
 	public var update : Particle -> Void;
-	
+
 	public function new() {
 	}
-	
+
 	public function setDefaults() {
 		// material
 		textureName = null;
@@ -168,7 +168,7 @@ class State {
 		// extra
 		delay = 0.;
 	}
-	
+
 	public function scale( val : Value, v : Float ) {
 		return switch( val ) {
 		case VConst(c): VConst(c * v);
@@ -181,7 +181,7 @@ class State {
 		case VCustom(f): VCustom(function(p) return f(p) * v);
 		}
 	}
-	
+
 	public static inline function eval( v : Value, time : Float, r : Randomized, p : Particle ) : Float {
 		return switch( v ) {
 		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 defPart = hxd.res.Embed.getResource("h3d/parts/default.png");
-	
+
 	public function initFrames() {
 		if( textureName == null ) {
 			var t = switch( blendMode ) {
@@ -227,7 +227,7 @@ class State {
 			}
 		}
 	}
-	
+
 	public static function load( b : haxe.io.Bytes, loadTexture : String -> h2d.Tile ) {
 		var state : State = haxe.Unserializer.run(b.toString());
 		if( state.textureName != null ) {
@@ -238,5 +238,5 @@ class State {
 		state.initFrames();
 		return state;
 	}
-	
+
 }

+ 71 - 71
h3d/parts/Editor.hx

@@ -25,7 +25,7 @@ private typedef Curve = {
 }
 
 class Editor extends h2d.Sprite implements Randomized {
-	
+
 	var emit : Emitter;
 	var state : State;
 	var curState : String;
@@ -53,7 +53,7 @@ class Editor extends h2d.Sprite implements Randomized {
 	public var currentFilePath : String;
 	public var autoLoop : Bool = true;
 	public var moveEmitter(default,set) : Bool = false;
-	
+
 	static var CURVES : Array<{ name : String, f : Curve -> Data.Value }> = [
 		{ name : "Const", f : function(c) return VConst(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) },
 	];
 
-	
+
 	static function solvePoly( c : Curve ) {
 
 		if( c.points == null )
 			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 yvals = [for( p in c.points ) p.y * c.max];
 		var pts = [];
@@ -83,14 +83,14 @@ class Editor extends h2d.Sprite implements Randomized {
 			beta.pop();
 		return VPoly(beta,pts);
 	}
-	
+
 	public function new(emiter, ?parent) {
 		super(parent);
 		this.emit = emiter;
 		init();
 		setState(emit.state);
 	}
-	
+
 	public dynamic function onTextureSelect() {
 		hxd.File.browse(function(sel) {
 			sel.load(function(bytes) {
@@ -102,20 +102,20 @@ class Editor extends h2d.Sprite implements Randomized {
 			fileTypes : [{ name : "Images", extensions : ["png","jpg","jpeg","gif"] }],
 		});
 	}
-	
+
 	public function changeTexture( name : String, t : h2d.Tile ) {
 		state.textureName = name;
 		curState = null; // force reload (if texture was changed)
 		setTexture(t);
 		buildUI();
 	}
-	
+
 	function set_moveEmitter(v) {
 		this.moveEmitter = v;
 		buildUI();
 		return v;
 	}
-	
+
 	public dynamic function loadTexture( textureName : String ) : h2d.Tile {
 		var bytes = null;
 		try {
@@ -128,7 +128,7 @@ class Editor extends h2d.Sprite implements Randomized {
 		}
 		return bytes == null ? null : hxd.res.Any.fromBytes(textureName,bytes).toTile();
 	}
-	
+
 	public dynamic function onLoad() {
 		hxd.File.browse(function(sel) {
 			currentFilePath = sel.fileName;
@@ -151,7 +151,7 @@ class Editor extends h2d.Sprite implements Randomized {
 			fileTypes : [{ name : "Particle Effect", extensions : ["p"] }],
 		});
 	}
-	
+
 	public dynamic function onSave( saveData ) {
 		if( currentFilePath != null )
 			try {
@@ -166,7 +166,7 @@ class Editor extends h2d.Sprite implements Randomized {
 			saveFileName : function(path) currentFilePath = path,
 		});
 	}
-	
+
 	public function setState(s) {
 		undo = [];
 		redo = [];
@@ -184,7 +184,7 @@ class Editor extends h2d.Sprite implements Randomized {
 		buildUI();
 		emit.reset();
 	}
-	
+
 	override function onAlloc() {
 		super.onAlloc();
 		getScene().addEventListener(onEvent);
@@ -194,7 +194,7 @@ class Editor extends h2d.Sprite implements Randomized {
 		super.onDelete();
 		getScene().addEventListener(onEvent);
 	}
-	
+
 	var time : Float = 0.;
 	public dynamic function onMoveEmitter(dt:Float) {
 		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.z = (Math.cos(time * 1.3) * Math.sin(time * 1.5) + 1) * r;
 	}
-	
+
 	function onEvent( e : hxd.Event ) {
 		function loadHistory( h : History ) {
 			curState = h.state;
@@ -238,7 +238,7 @@ class Editor extends h2d.Sprite implements Randomized {
 		default:
 		}
 	}
-	
+
 	function buildUI() {
 		if( ui != null ) ui.remove();
 		ui = h2d.comp.Parser.fromHtml('
@@ -247,7 +247,7 @@ class Editor extends h2d.Sprite implements Randomized {
 					* {
 						font-size : 12px;
 					}
-					
+
 					h1 {
 						font-size : 10px;
 						color : #BBB;
@@ -256,7 +256,7 @@ class Editor extends h2d.Sprite implements Randomized {
 					.body {
 						layout : dock;
 					}
-					
+
 					span {
 						padding-top : 2px;
 					}
@@ -273,7 +273,7 @@ class Editor extends h2d.Sprite implements Randomized {
 						layout : vertical;
 						margin-bottom : 10px;
 					}
-					
+
 					.sep {
 						margin-top : -10px;
 						margin-bottom : -2px;
@@ -281,11 +281,11 @@ class Editor extends h2d.Sprite implements Randomized {
 						width : 200px;
 						background-color : #555;
 					}
-					
+
 					span.label {
 						width : 97px;
 					}
-					
+
 					.buttons {
 						layout : inline;
 					}
@@ -293,7 +293,7 @@ class Editor extends h2d.Sprite implements Randomized {
 					.line {
 						layout : horizontal;
 					}
-					
+
 					.ic, .icol {
 						icon : url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAAB3RJTUUH3QsHEDot9CONhQAAABd0RVh0U29mdHdhcmUAR0xEUE5HIHZlciAzLjRxhaThAAAACHRwTkdHTEQzAAAAAEqAKR8AAAAEZ0FNQQAAsY8L/GEFAAAABmJLR0QA/wD/AP+gvaeTAAAARklEQVR4nGP4z/CfJMRAmQYIIFbDfwwGJvpPHQ249PxHdtJ/LHKkaMBtBAN+80jRgCMY8GrAFjMMBGMKI+Jor4EU1eRoAADB1BsCKErgdwAAAABJRU5ErkJggg=");
 						icon-top : 1px;
@@ -301,27 +301,27 @@ class Editor extends h2d.Sprite implements Randomized {
 						icon-color : #888;
 						padding-left : 20px;
 					}
-					
+
 					.ic:hover, .icol:hover {
 						icon-top : 0px;
 					}
-					
+
 					.icol {
 						icon-color : #AAA;
 						icon : url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAAB3RJTUUH3QsICwAiCSUSqgAAABd0RVh0U29mdHdhcmUAR0xEUE5HIHZlciAzLjRxhaThAAAACHRwTkdHTEQzAAAAAEqAKR8AAAAEZ0FNQQAAsY8L/GEFAAAABmJLR0QA/wD/AP+gvaeTAAAAMklEQVR4nGMwIBEwAPFJWQVMlLHvLSYayRqcdmNBD8tFMNFI1kBa4vMnETD8Z/hPEgIAvqs9dJhBcSIAAAAASUVORK5CYII==");
 					}
-					
+
 					select, button, input {
 						icon-top : 2px;
 						width : 70px;
 						height : 11px;
 						padding-top : 2px;
 					}
-					
+
 					.box {
 						width : 95px;
 					}
-					
+
 					input {
 						height : 13px;
 						padding-top : 2px;
@@ -332,39 +332,39 @@ class Editor extends h2d.Sprite implements Randomized {
 						width : 310px;
 						layout : dock;
 					}
-					
+
 					.curve {
 						dock : bottom;
 						layout : vertical;
 						padding : 5px;
 						height : 165px;
 					}
-					
+
 					.curve .title {
 						width : 180px;
 						text-align : right;
 						padding: 2px 10px;
 						background-color : #202020;
 					}
-					
+
 					.tname {
 						width : 102px;
 					}
-					
+
 					#curve {
 						width : 300px;
 						height : 110px;
 						border : 1px solid #333;
 					}
-					
+
 					button.file {
 						width : 15px;
 					}
-					
+
 					.curve .val {
 						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 {
 						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 {
 						display : block;
 					}
-					
+
 					.m_pow .v_pow {
 						display : block;
 					}
-					
+
 					.m_cos .v_freq, .m_sin .v_freq {
 						display : block;
 					}
-					
+
 					.m_curve .v_prec, .m_curve .v_clear {
 						display : block;
 					}
-					
+
 					.m_random .v_rnd {
 						display : block;
 					}
-					
+
 					.v_rnd button {
 						width : auto;
 					}
@@ -396,10 +396,10 @@ class Editor extends h2d.Sprite implements Randomized {
 					.v_rnd select {
 						width : 40px;
 					}
-					
+
 				</style>
 				<div class="main panel">
-				
+
 					<h1>Global</h1>
 					<div class="sep"></div>
 					<div class="col">
@@ -429,7 +429,7 @@ class Editor extends h2d.Sprite implements Randomized {
 							<button class="ic" value="Size" onclick="api.editCurve(\'globalSize\')"/>
 						</div>
 					</div>
-					
+
 					<h1>Emit</h1>
 					<div class="sep"></div>
 					<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>
 						</div>
 					</div>
-					
+
 					<h1>Particle</h1>
 					<div class="sep"></div>
 					<div class="col">
@@ -490,7 +490,7 @@ class Editor extends h2d.Sprite implements Randomized {
 							<button class="ic" value="Light" onclick="api.editCurve(\'light\')"/>
 						</div>
 					</div>
-					
+
 					<h1>Animation</h1>
 					<div class="sep"></div>
 					<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\')"/>
 						</div>
 					</div>
-					
+
 					<h1>Collide</h1>
 					<div class="sep"></div>
 					<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>
 						</div>
 					</div>
-					
+
 					<h1>Play</h1>
 					<div class="sep"></div>
 					<div style="layout:dock;width:200px">
@@ -620,7 +620,7 @@ class Editor extends h2d.Sprite implements Randomized {
 		cedit.onKeyDown = onCurveEvent;
 		setCurveMode(curve.mode);
 	}
-	
+
 	function toggleSplit() {
 		if( state.frames.length == 1 ) {
 			state.frame = VLinear(0,1);
@@ -633,13 +633,13 @@ class Editor extends h2d.Sprite implements Randomized {
 		}
 		buildUI();
 	}
-	
+
 	function clearCurve() {
 		curve.points = [new h2d.col.Point(0, curve.min/curve.max), new h2d.col.Point(1, 1)];
 		curve.freq = 2;
 		buildUI();
 	}
-	
+
 	function onCurveEvent( e : hxd.Event ) {
 		if( !curve.value.match(VPoly(_)) )
 			return;
@@ -688,7 +688,7 @@ class Editor extends h2d.Sprite implements Randomized {
 		default:
 		}
 	}
-	
+
 	function editColors() {
 		if( grad != null ) {
 			grad.remove();
@@ -710,7 +710,7 @@ class Editor extends h2d.Sprite implements Randomized {
 			if( !found ) state.colors = null;
 		};
 	}
-	
+
 	function editCurve( name : String, isShape : Bool = false ) {
 		if( curve.name == name && curve.shape == isShape ) {
 			curve.name = null;
@@ -735,11 +735,11 @@ class Editor extends h2d.Sprite implements Randomized {
 		rebuildCurve();
 		buildUI();
 	}
-	
+
 	public function rand() {
 		return randomValue;
 	}
-	
+
 	function init() {
 		var bg = new hxd.BitmapData(300, 110);
 		bg.clear(0xFF202020);
@@ -753,12 +753,12 @@ class Editor extends h2d.Sprite implements Randomized {
 		bg.dispose();
 		curveTexture = h2d.Tile.fromTexture(new h3d.mat.Texture(512, 512)).sub(0, 0, curveBG.width, curveBG.height);
 	}
-	
+
 	function rebuildCurve() {
 		var bmp = new hxd.BitmapData(512, 512);
 		var width = curveTexture.width, height = curveTexture.height;
 		var yMax;
-		
+
 		switch( curve.value ) {
 		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));
@@ -774,8 +774,8 @@ class Editor extends h2d.Sprite implements Randomized {
 		case VCustom(_):
 			throw "assert";
 		}
-		
-		
+
+
 		var sy = 1.;
 		var k = 0;
 		while( yMax > 100 * curve.incr ) {
@@ -786,7 +786,7 @@ class Editor extends h2d.Sprite implements Randomized {
 		}
 		sy /= (100 * curve.incr);
 		curve.scaleY = sy;
-		
+
 		inline function posX(x:Float) {
 			return Std.int(x * (width - 1));
 		}
@@ -809,7 +809,7 @@ class Editor extends h2d.Sprite implements Randomized {
 			}
 			bmp.setPixel(x, iy0, 0xFFFF0000);
 		}
-		
+
 		switch( curve.value ) {
 		case VPoly(_):
 			for( p in curve.points ) {
@@ -822,11 +822,11 @@ class Editor extends h2d.Sprite implements Randomized {
 			}
 		default:
 		}
-		
+
 		curveTexture.getTexture().uploadBitmap(bmp);
 		bmp.dispose();
 	}
-	
+
 	function initCurve( v : Value ) {
 		var c : Curve = {
 			value : null,
@@ -878,7 +878,7 @@ class Editor extends h2d.Sprite implements Randomized {
 		}
 		return c;
 	}
-	
+
 	function getShapeValue( value : String ) {
 		return switch( [state.shape, value] ) {
 		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);
 		}
 	}
-	
+
 	function rebuildShape( mode : Int, getValue ) {
 		var size = getValue("size");
 		state.shape = switch( mode ) {
@@ -897,12 +897,12 @@ class Editor extends h2d.Sprite implements Randomized {
 		default: throw "Unknown shape #" + mode;
 		}
 	}
-	
+
 	function setCurShape( mode : Int ) {
 		rebuildShape(mode, getShapeValue);
 		buildUI();
 	}
-	
+
 	function setCurveMode( mode : Int ) {
 		var cm = ui.getElementById("curve").getParent();
 		cm.removeClass("m_" + CURVES[curve.mode].name.toLowerCase());
@@ -915,7 +915,7 @@ class Editor extends h2d.Sprite implements Randomized {
 		} else
 			updateCurve();
 	}
-	
+
 	function updateCurve() {
 		curve.value = CURVES[curve.mode].f(curve);
 		if( curve.name != null ) {
@@ -932,8 +932,8 @@ class Editor extends h2d.Sprite implements Randomized {
 		curTile = t;
 		state.initFrames();
 	}
-	
-	override function sync( ctx : h3d.scene.RenderContext ) {
+
+	override function sync( ctx : h2d.RenderContext ) {
 		// if resized, let's reflow our ui
 		if( ctx.engine.width != width || ctx.engine.height != height ) {
 			ui.refresh();
@@ -983,15 +983,15 @@ class Editor extends h2d.Sprite implements Randomized {
 			}
 		} else
 			lastPartSeen = null;
-			
+
 		if( grad != null ) {
 			grad.x = width - 680;
 			grad.y = height - 190;
 			grad.colorPicker.x = grad.boxWidth - 180;
 			grad.colorPicker.y = -321;
 		}
-			
+
 		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 emitCount : Float;
 	var colorMap : ColorKey;
-		
+
 	var head : Particle;
 	var tail : Particle;
 	var pool : Particle;
-	
+
 	var tmp : h3d.Vector;
 	var tmpBuf : hxd.FloatBuffer;
 	var curPart : Particle;
-	
+
 	public function new(?state,?parent) {
 		super(parent);
 		material = new Material();
@@ -35,7 +35,7 @@ class Emitter extends h3d.scene.Object implements Randomized {
 		}
 		setState(state);
 	}
-	
+
 	/**
 		Offset all existing particles by the given values.
 	**/
@@ -48,7 +48,7 @@ class Emitter extends h3d.scene.Object implements Randomized {
 			p = p.next;
 		}
 	}
-	
+
 	public function reset() {
 		while( head != null )
 			kill(head);
@@ -56,17 +56,17 @@ class Emitter extends h3d.scene.Object implements Randomized {
 		emitCount = 0;
 		rnd = Math.random();
 	}
-	
+
 	public function setState(s) {
 		this.state = s;
 		material.texture = s.frames == null || s.frames.length == 0 ? null : s.frames[0].getTexture();
 		switch( s.blendMode ) {
 		case Add:
-			material.blend(SrcAlpha, One);
+			material.blendMode = Add;
 		case SoftAdd:
-			material.blend(OneMinusDstColor, One);
+			material.blendMode = SoftAdd;
 		case Alpha:
-			material.blend(SrcAlpha, OneMinusSrcAlpha);
+			material.blendMode = Alpha;
 		}
 		colorMap = null;
 		if( s.colors != null ) {
@@ -78,11 +78,11 @@ class Emitter extends h3d.scene.Object implements Randomized {
 			}
 		}
 	}
-	
+
 	inline function eval(v) {
 		return Data.State.eval(v,time, this, curPart);
 	}
-	
+
 	public function update(dt:Float) {
 		var s = state;
 		var old = time;
@@ -113,11 +113,11 @@ class Emitter extends h3d.scene.Object implements Randomized {
 		}
 		curPart = null;
 	}
-	
+
 	public inline function rand() {
 		return Math.random();
 	}
-	
+
 	function initPosDir( p : Particle ) {
 		switch( state.shape ) {
 		case SLine(size):
@@ -171,7 +171,7 @@ class Emitter extends h3d.scene.Object implements Randomized {
 			p.dz = Math.cos(phi);
 		}
 	}
-	
+
 	function initPart(p:Particle) {
 		initPosDir(p);
 		if( !state.emitLocal ) {
@@ -190,12 +190,12 @@ class Emitter extends h3d.scene.Object implements Randomized {
 		p.time = 0;
 		p.lifeTimeFactor = 1 / eval(state.life);
 	}
-	
-	public function emit() {
+
+	public function emitPart() {
 		if( posChanged ) syncPos();
 		return emitParticle();
 	}
-	
+
 	function emitParticle() {
 		var p;
 		if( pool == null )
@@ -229,7 +229,7 @@ class Emitter extends h3d.scene.Object implements Randomized {
 		}
 		return p;
 	}
-	
+
 	function kill(p:Particle) {
 		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;
@@ -238,7 +238,7 @@ class Emitter extends h3d.scene.Object implements Randomized {
 		pool = p;
 		count--;
 	}
-	
+
 	function updateParticle( p : Particle, dt : Float ) {
 		p.time += dt * p.lifeTimeFactor;
 		if( p.time > 1 ) {
@@ -246,7 +246,7 @@ class Emitter extends h3d.scene.Object implements Randomized {
 			return;
 		}
 		p.randIndex = 0;
-	
+
 		// apply forces
 		if( state.force != null ) {
 			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.ratio = p.eval(state.ratio, p.time);
 		p.rotation = p.eval(state.rotation, p.time);
-		
+
 		// collide
 		if( state.collide && collider != null && collider.collidePart(p, tmp) ) {
 			if( state.collideKill ) {
@@ -276,8 +276,8 @@ class Emitter extends h3d.scene.Object implements Randomized {
 				p.dz = v.z * state.bounce;
 			}
 		}
-			
-		
+
+
 		// calc color
 		var ck = colorMap;
 		var light = p.eval(state.light, p.time);
@@ -314,27 +314,27 @@ class Emitter extends h3d.scene.Object implements Randomized {
 			p.cb = light;
 		}
 		p.ca = p.eval(state.alpha, p.time);
-		
+
 		// frame
 		if( state.frame != null ) {
 			var f = p.eval(state.frame, p.time) % 1;
 			if( f < 0 ) f += 1;
 			p.frame = Std.int(f * state.frames.length);
 		}
-		
+
 		if( state.update != null )
 			state.update(p);
 	}
-	
+
 	override function sync( ctx : h3d.scene.RenderContext ) {
 		super.sync(ctx);
 		update(ctx.elapsedTime * speed);
 	}
-	
+
 	public function isActive() {
 		return count != 0 || time < 1 || state.loop;
 	}
-	
+
 	function sort( list : Particle ) {
 		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 ) {
 		return haxe.ds.ListSort.sort(list, function(p1, p2) return p1.w < p2.w ? -1 : 1);
 	}
-	
+
 	@:access(h3d.parts.Material) @:access(h2d.Tile)
 	override function draw( ctx : h3d.scene.RenderContext ) {
 		if( head == null )
@@ -382,7 +382,7 @@ class Emitter extends h3d.scene.Object implements Randomized {
 				var f = frames[p.frame];
 				if( f == null ) f = frames[0];
 				var ratio = p.size * p.ratio * (f.height / f.width);
-				
+
 				tmp[pos++] = prevX1;
 				tmp[pos++] = prevY1;
 				tmp[pos++] = prevZ1;
@@ -402,7 +402,7 @@ class Emitter extends h3d.scene.Object implements Randomized {
 					tmp[pos++] = p.cb;
 					tmp[pos++] = p.ca;
 				}
-				
+
 				tmp[pos++] = prevX2;
 				tmp[pos++] = prevY2;
 				tmp[pos++] = prevZ2;
@@ -431,11 +431,11 @@ class Emitter extends h3d.scene.Object implements Randomized {
 				dy *= d;
 				dz *= d;
 				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;
 				prevY1 = p.y + dir.y * p.size;
 				prevZ1 = p.z + dir.z * p.size;
-				
+
 				prevX2 = p.x - dir.x * p.size;
 				prevY2 = p.y - dir.y * 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.ca;
 				}
-				
+
 				prev = p;
 				p = p.next;
 			}
@@ -501,7 +501,7 @@ class Emitter extends h3d.scene.Object implements Randomized {
 					tmp[pos++] = p.cb;
 					tmp[pos++] = p.ca;
 				}
-				
+
 				tmp[pos++] = p.x;
 				tmp[pos++] = p.y;
 				tmp[pos++] = p.z;
@@ -552,15 +552,16 @@ class Emitter extends h3d.scene.Object implements Randomized {
 					tmp[pos++] = p.cb;
 					tmp[pos++] = p.ca;
 				}
-				
+
 				p = p.next;
 			}
 		}
 		var stride = 10;
 		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);
-		
+
+		/*
 		material.pshader.mpos = state.emitLocal ? this.absPos : h3d.Matrix.I();
 		material.pshader.mproj = ctx.camera.m;
 		if( state.is3D ) {
@@ -572,10 +573,12 @@ class Emitter extends h3d.scene.Object implements Randomized {
 		}
 		material.pshader.hasColor = hasColor;
 		material.pshader.isAlphaMap = state.isAlphaMap;
-		
+
 		ctx.engine.selectMaterial(material);
 		ctx.engine.renderQuadBuffer(buffer);
 		buffer.dispose();
+		*/
+		throw "TODO";
 	}
-	
+
 }

+ 12 - 26
h3d/parts/Material.hx

@@ -1,5 +1,5 @@
 package h3d.parts;
-
+/*
 private class PartShader extends h3d.impl.Shader {
 
 #if flash
@@ -13,14 +13,14 @@ private class PartShader extends h3d.impl.Shader {
 			uv : Float2,
 			color : Float4,
 		};
-		
+
 		var tuv : Float2;
 		var tcolor : Float4;
 		var partSize : Float2;
-		
+
 		var hasColor : Bool;
 		var is3D : Bool;
-		
+
 		var isAlphaMap : Bool;
 
 		function vertex( mpos : M34, mproj : Matrix ) {
@@ -45,7 +45,7 @@ private class PartShader extends h3d.impl.Shader {
 			tuv = input.uv;
 			if( hasColor ) tcolor = input.color;
 		}
-		
+
 		function fragment( tex : Texture ) {
 			var c = tex.get(tuv.xy);
 			if( hasColor ) c *= tcolor;
@@ -55,7 +55,7 @@ private class PartShader extends h3d.impl.Shader {
 			}
 			out = c;
 		}
-	
+
 	}
 #else
 	static var VERTEX = "";
@@ -63,29 +63,15 @@ private class PartShader extends h3d.impl.Shader {
 #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) {
-		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;
 
 class Particle implements Data.Randomized {
-	
+
 	public var x : Float;
 	public var y : Float;
 	public var z : Float;
 	public var w : Float;
-	
+
 	public var time : Float;
 	public var lifeTimeFactor : Float;
 
@@ -22,16 +22,16 @@ class Particle implements Data.Randomized {
 	public var cg : Float;
 	public var cb : Float;
 	public var ca : Float;
-	
+
 	public var frame : Int;
-	
+
 	public var size : Float;
 	public var ratio : Float;
 	public var rotation : Float;
-	
+
 	public var prev : Particle;
 	public var next : Particle;
-	
+
 	public var randIndex = 0;
 	public var randValues : Array<Float>;
 
@@ -42,15 +42,15 @@ class Particle implements Data.Randomized {
 		ca = 1;
 		frame = 0;
 	}
-	
+
 	public inline function eval( v : Data.Value, time : Float ) {
 		return Data.State.eval(v, time, this, this);
 	}
-	
+
 	public function rand() {
 		if( randValues == null ) randValues = [];
 		if( randValues.length <= randIndex ) randValues.push(Math.random());
 		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