From dd0c0512d5490b9a02d5dbfce52a34b0bb42295d Mon Sep 17 00:00:00 2001 From: player-03 Date: Mon, 16 Mar 2015 19:41:50 -0700 Subject: [PATCH 001/150] Android needs precision highp. At least in my tests. I also tried iOS but didn't see any issues there. Maybe it's something to do with Android's implementation of OpenGL? The issue I'm seeing is, when I try to render objects far away from the origin (when the camera is also far from the origin), their position becomes unreliable, causing objects to appear to vibrate. Presumably, these large numbers are getting rounded thanks to the low precision. An alternative would be to make a static String variable ("AGLSLParser.glslHeader" or something), and add that to the header. Then if you find you need a specific precision, you can set it yourself. --- openfl/_internal/aglsl/AGLSLParser.hx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openfl/_internal/aglsl/AGLSLParser.hx b/openfl/_internal/aglsl/AGLSLParser.hx index ba1d3df4f5..d762ff5d9a 100755 --- a/openfl/_internal/aglsl/AGLSLParser.hx +++ b/openfl/_internal/aglsl/AGLSLParser.hx @@ -20,7 +20,7 @@ class AGLSLParser { var body:String = ""; var i:Int = 0; - #if html5 + #if (html5 || android) header += "precision highp float;\n"; #end @@ -395,4 +395,4 @@ class AGLSLParser { } -} \ No newline at end of file +} From a0b686cfa0bb4616c9cd70e2e29b695effa9af61 Mon Sep 17 00:00:00 2001 From: player-03 Date: Mon, 16 Mar 2015 23:04:18 -0700 Subject: [PATCH 002/150] Use high precision only for vertex shaders. It's not guaranteed to be available on fragment shaders, but the GLSL ES specification requires it in vertex shaders. Also, vertex shaders are the ones that are likely to need high precision. I added iOS because Apple (and others) recommend using high precision for vertex shaders. I'd add Blackberry too, but I've never compiled for it. --- openfl/_internal/aglsl/AGLSLParser.hx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/openfl/_internal/aglsl/AGLSLParser.hx b/openfl/_internal/aglsl/AGLSLParser.hx index d762ff5d9a..606ac62736 100755 --- a/openfl/_internal/aglsl/AGLSLParser.hx +++ b/openfl/_internal/aglsl/AGLSLParser.hx @@ -20,8 +20,14 @@ class AGLSLParser { var body:String = ""; var i:Int = 0; - #if (html5 || android) + #if html5 header += "precision highp float;\n"; + #elseif (android || ios) + if (desc.header.type == "vertex") { + + header += "precision highp float;\n"; + + } #end var tag = desc.header.type.charAt (0); //TODO From c17b5e679e5a51748191734db43a48d27cf78d66 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Tue, 14 Apr 2015 13:53:41 -0700 Subject: [PATCH 003/150] Enforce ARGB color format when working with pixels, handle #if disable_cffi to disable GL rendering --- openfl/display/BitmapData.hx | 35 +++++++++++++++++++++-------------- openfl/display/Stage.hx | 2 ++ 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/openfl/display/BitmapData.hx b/openfl/display/BitmapData.hx index f8d1c8ff35..d231241560 100644 --- a/openfl/display/BitmapData.hx +++ b/openfl/display/BitmapData.hx @@ -6,6 +6,7 @@ import lime.graphics.opengl.GLTexture; import lime.graphics.GLRenderContext; import lime.graphics.Image; import lime.graphics.ImageBuffer; +import lime.graphics.ImageChannel; import lime.graphics.utils.ImageCanvasUtil; import lime.math.ColorMatrix; import lime.utils.Float32Array; @@ -179,18 +180,21 @@ class BitmapData implements IBitmapDrawable { if (width > 0 && height > 0) { if (transparent) { - - if ((fillColor & 0xFF000000) == 0) { + + if ((fillColor & 0xFF000000) == 0) { + fillColor = 0; + } - - } - else { + + } else { fillColor = (0xFF << 24) | (fillColor & 0xFFFFFF); } + fillColor = (fillColor << 8) | ((fillColor >> 24) & 0xFF); + __image = new Image (null, 0, 0, width, height, fillColor); __image.transparent = transparent; __isValid = true; @@ -551,7 +555,10 @@ class BitmapData implements IBitmapDrawable { case DATA: - var renderSession = @:privateAccess Lib.current.stage.__renderer.renderSession; + var renderer = @:privateAccess Lib.current.stage.__renderer; + if (renderer == null) return; + + var renderSession = @:privateAccess renderer.renderSession; var gl:GLRenderContext = renderSession.gl; if (gl == null) return; @@ -678,7 +685,7 @@ class BitmapData implements IBitmapDrawable { public function fillRect (rect:Rectangle, color:Int):Void { if (!__isValid || rect == null) return; - __image.fillRect (rect.__toLimeRectangle (), color); + __image.fillRect (rect.__toLimeRectangle (), color, ARGB); } @@ -697,7 +704,7 @@ class BitmapData implements IBitmapDrawable { public function floodFill (x:Int, y:Int, color:Int):Void { if (!__isValid) return; - __image.floodFill (x, y, color); + __image.floodFill (x, y, color, ARGB); } @@ -878,7 +885,7 @@ class BitmapData implements IBitmapDrawable { public function getPixel (x:Int, y:Int):Int { if (!__isValid) return 0; - return __image.getPixel (x, y); + return __image.getPixel (x, y, ARGB); } @@ -908,7 +915,7 @@ class BitmapData implements IBitmapDrawable { public function getPixel32 (x:Int, y:Int):Int { if (!__isValid) return 0; - return __image.getPixel32 (x, y); + return __image.getPixel32 (x, y, ARGB); } @@ -926,7 +933,7 @@ class BitmapData implements IBitmapDrawable { if (!__isValid) return null; if (rect == null) rect = this.rect; - return __image.getPixels (rect.__toLimeRectangle ()); + return __image.getPixels (rect.__toLimeRectangle (), ARGB); } @@ -1230,7 +1237,7 @@ class BitmapData implements IBitmapDrawable { public function setPixel (x:Int, y:Int, color:Int):Void { if (!__isValid) return; - __image.setPixel (x, y, color); + __image.setPixel (x, y, color, ARGB); } @@ -1269,7 +1276,7 @@ class BitmapData implements IBitmapDrawable { public function setPixel32 (x:Int, y:Int, color:Int):Void { if (!__isValid) return; - __image.setPixel32 (x, y, color); + __image.setPixel32 (x, y, color, ARGB); } @@ -1296,7 +1303,7 @@ class BitmapData implements IBitmapDrawable { public function setPixels (rect:Rectangle, byteArray:ByteArray):Void { if (!__isValid || rect == null) return; - __image.setPixels (rect.__toLimeRectangle (), byteArray); + __image.setPixels (rect.__toLimeRectangle (), byteArray, ARGB); } diff --git a/openfl/display/Stage.hx b/openfl/display/Stage.hx index 6506d75b71..944dc9f280 100644 --- a/openfl/display/Stage.hx +++ b/openfl/display/Stage.hx @@ -604,7 +604,9 @@ class Stage extends DisplayObjectContainer implements IModule { case OPENGL (gl): + #if !disable_cffi __renderer = new GLRenderer (stageWidth, stageHeight, gl); + #end case CANVAS (context): From eb1d736bc25847c64f0e2faf99ab3dbc5b4d82b2 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Tue, 14 Apr 2015 13:53:51 -0700 Subject: [PATCH 004/150] Update test --- tests/test/openfl/display/BitmapDataTest.hx | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/test/openfl/display/BitmapDataTest.hx b/tests/test/openfl/display/BitmapDataTest.hx index 22a10da6ce..2cf6242949 100644 --- a/tests/test/openfl/display/BitmapDataTest.hx +++ b/tests/test/openfl/display/BitmapDataTest.hx @@ -250,6 +250,8 @@ class BitmapDataTest { var bitmapData = new BitmapData (100, 100, true, 0xFF000000); var bitmapData2 = new BitmapData (100, 100, true, 0xFFFF0000); + Assert.areEqual (hex (0xFF000000), hex (bitmapData.getPixel32 (0, 0))); + bitmapData.copyChannel (bitmapData2, bitmapData2.rect, new Point (), BitmapDataChannel.RED, BitmapDataChannel.RED); Assert.areEqual (hex (0xFFFF0000), hex (bitmapData.getPixel32 (0, 0))); @@ -596,6 +598,7 @@ class BitmapDataTest { var expectedColor = color; if (sourceAlpha) { + // TODO: Native behavior is different than the flash target here. // The flash target premultiplies RGB by the alpha value. // If the native behavior is changed, this test needs to be @@ -603,8 +606,8 @@ class BitmapDataTest { if ((expectedColor & 0xFF000000) == 0) { expectedColor = 0; } - } - else { + + } else { // Surfaces that don't support alpha return FF for the alpha value, so // set our expected alpha to FF no matter what the initial value was expectedColor |= 0xFF000000; @@ -667,7 +670,9 @@ class BitmapDataTest { // TODO: Native targets do not match the flash behavior here. // If the native target is changed to match flash, // testGetSetPixels() must be changed to match. + #if !neko testGetSetPixels(0x80112233, true, true); + #end } @Test public function testGetAndSetPixelsOpqaueARGBToARGB() { @@ -679,7 +684,10 @@ class BitmapDataTest { } @Test public function testGetAndSetPixelsSemiARGBToRGB() { + // TODO + #if !neko testGetSetPixels(0x80112233, true, false); + #end } @Test public function testGetAndSetPixelsOpqaueARGBToRGB() { From db4adbd1980eb9dabbfef694e615423e89d44062 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Tue, 14 Apr 2015 16:16:10 -0700 Subject: [PATCH 005/150] Add merge test --- tests/test/openfl/display/BitmapDataTest.hx | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/test/openfl/display/BitmapDataTest.hx b/tests/test/openfl/display/BitmapDataTest.hx index 2cf6242949..c8a0b9b1ea 100644 --- a/tests/test/openfl/display/BitmapDataTest.hx +++ b/tests/test/openfl/display/BitmapDataTest.hx @@ -476,6 +476,22 @@ class BitmapDataTest { } + @Test public function merge () { + + var color = 0xFF000000; + var color2 = 0xFFFF0000; + + var bitmapData = new BitmapData (100, 100, true, color); + var sourceBitmapData = new BitmapData (100, 100, true, color2); + + bitmapData.merge (sourceBitmapData, sourceBitmapData.rect, new Point (), 256, 256, 256, 256); + + var pixel = bitmapData.getPixel32 (1, 1); + Assert.areEqual (StringTools.hex (0xFFFF0000), StringTools.hex (pixel)); + + } + + @Test public function noise () { // TODO: Confirm functionality From c5c775ed90513b7bd25adab14afb4b622d8d0d4b Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Wed, 15 Apr 2015 06:59:16 -0700 Subject: [PATCH 006/150] Add disable-cffi test --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index bdcaa0db6f..e581ff8f30 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,6 +36,7 @@ before_script: script: - haxelib run lime test neko + - haxelib run lime test neko -Ddisable-cffi - haxelib run lime test neko -Dlegacy - haxelib run munit test -as3 -norun - haxelib run munit test -browser phantomjs From faca0412fb54b9d2a4722818bde60eab9a849314 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Wed, 15 Apr 2015 07:44:13 -0700 Subject: [PATCH 007/150] Update to 3.0.2 --- haxelib.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/haxelib.json b/haxelib.json index d5437ab771..bf5539fdfd 100644 --- a/haxelib.json +++ b/haxelib.json @@ -4,7 +4,7 @@ "license": "MIT", "tags": [], "description": "The \"Open Flash Library\" for fast 2D development", - "version": "3.0.1", - "releasenote": "Improved -Dhybrid support", + "version": "3.0.2", + "releasenote": "Improvements to keyboard, TextField, and other fixes", "contributors": [ "singmajesty" ] } From 58f878ad929d68545b0f86efc40c6f1e5e28206a Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Wed, 15 Apr 2015 07:44:19 -0700 Subject: [PATCH 008/150] Update CHANGELOG --- CHANGELOG.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ef6f3cb56..2f0a65fc30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ +3.0.2 (04/15/2015) +------------------ + +* Improved handling of keyCode/charCode in keyboard events +* Improved the frame timing when using hybrid mode +* Improved the font lookup behavior of GL TextField +* Added better auto-size left support to GL TextField +* Added basic text line metrics in TextField +* Added support for compilation with -Ddisable-cffi +* Added dynamic DisplayObject field support for MovieClip +* Fixed UVs when using drawTiles with bitmapData.draw (GL) +* Fixed blendMode setting when using bitmapData.draw (GL) + + 3.0.1 (04/09/2015) ------------------ From 5d4fa685e330b22c273ab1d1acafd0304de605fb Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Wed, 15 Apr 2015 12:12:33 -0700 Subject: [PATCH 009/150] Search for legacy --- templates/legacy/haxe/ApplicationMain.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/legacy/haxe/ApplicationMain.hx b/templates/legacy/haxe/ApplicationMain.hx index e74ed73d02..77e9b38515 100644 --- a/templates/legacy/haxe/ApplicationMain.hx +++ b/templates/legacy/haxe/ApplicationMain.hx @@ -74,7 +74,7 @@ class ApplicationMain { #elseif linux try { - if (!sys.FileSystem.exists (Sys.getCwd () + "/lime.ndll")) { + if (!sys.FileSystem.exists (Sys.getCwd () + "/lime-legacy.ndll")) { Sys.setCwd (haxe.io.Path.directory (Sys.executablePath ())); From 5f1ec716790b2b161d01e7eb9ec2e0b89238d5fd Mon Sep 17 00:00:00 2001 From: "Lars A. Doucet" Date: Wed, 15 Apr 2015 17:19:27 -0500 Subject: [PATCH 010/150] Working on TextMetrics / GLTextField rendering. Not quite there but making progress! --- .../_internal/renderer/opengl/GLTextField.hx | 32 +- openfl/text/TextField.hx | 435 ++++++++++++++++-- 2 files changed, 432 insertions(+), 35 deletions(-) diff --git a/openfl/_internal/renderer/opengl/GLTextField.hx b/openfl/_internal/renderer/opengl/GLTextField.hx index b61983d75b..4e47804a12 100644 --- a/openfl/_internal/renderer/opengl/GLTextField.hx +++ b/openfl/_internal/renderer/opengl/GLTextField.hx @@ -1,6 +1,7 @@ package openfl._internal.renderer.opengl; +import haxe.Utf8; import lime.graphics.Image; import lime.text.Glyph; import lime.text.TextLayout; @@ -10,6 +11,7 @@ import openfl._internal.renderer.RenderSession; import openfl.display.BitmapData; import openfl.display.Graphics; import openfl.display.Tilesheet; +import openfl.geom.Point; import openfl.geom.Rectangle; import openfl.text.Font; import openfl.text.TextField; @@ -79,6 +81,8 @@ class GLTextField { private static inline function renderText (textField:TextField, text:String, format:TextFormat, offsetX:Float, textWidth:Float):Void { + var dodebug = (textField.defaultTextFormat.font.toLowerCase().indexOf("liberation") != -1); + var font = textField.__getFontInstance (format); if (font != null && format.size != null) { @@ -154,7 +158,6 @@ class GLTextField { index = tilesheet.addTileRect (new Rectangle (image.offsetX, image.offsetY, image.width, image.height)); tileID.set (key, index); - } tileIDs.set (bitmapData, tileID); @@ -169,9 +172,14 @@ class GLTextField { var g = ((format.color >> 8) & 0xFF) / 0xFF; var b = ((format.color) & 0xFF) / 0xFF; + if (dodebug) + { + //trace("textField." + textField. + } + var image; var x:Float = offsetX; - var y:Float = size; + var y:Float = size - textField.getLineMetrics(0).descent / 2; if (format.align == TextFormatAlign.RIGHT) { @@ -207,7 +215,11 @@ class GLTextField { } - var textLayout = textField.__textLayout; + var textLayout:TextLayout = textField.__textLayout; + + var line_i:Int = 0; + + var oldx = x; for (line in lines) { @@ -234,11 +246,21 @@ class GLTextField { x += position.advance.x; y -= position.advance.y; + if (dodebug) + { + trace("y = " + y); + } } - x = 0; - y += size * 1.185; + x = oldx; + + var tlm = textField.getLineMetrics(line_i); + + y += tlm.height; + + //y += size + (textField.getLineMetrics(line_i).descent);// * 1.5; + line_i++; } } diff --git a/openfl/text/TextField.hx b/openfl/text/TextField.hx index 650162aee4..7784713cd1 100644 --- a/openfl/text/TextField.hx +++ b/openfl/text/TextField.hx @@ -2,6 +2,7 @@ package openfl.text; #if !flash #if !openfl_legacy import haxe.io.Path; +import haxe.Utf8; import haxe.xml.Fast; import haxe.Timer; import lime.graphics.opengl.GLTexture; @@ -577,6 +578,7 @@ class TextField extends InteractiveObject { @:noCompletion private var __tilesheets:Array; @:noCompletion private var __width:Float; + @:noCompletion private static var __utf8_endline_code:Int = 10; #if js private var __div:DivElement; @@ -717,7 +719,22 @@ class TextField extends InteractiveObject { var height = textHeight; - return new TextLineMetrics (0, textWidth, height, height, 0, 0); + var lineWidth = __getLineWidth(lineIndex); + var lineHeight = __getLineMetric(lineIndex, LINE_HEIGHT); + + var ascender = __getLineMetric(lineIndex, ASCENDER); + var descender = __getLineMetric(lineIndex, DESCENDER); + + var leading = __getLineMetric(lineIndex, LEADING); + + var margin = switch(__textFormat.align) + { + case LEFT, JUSTIFY: 2; + case RIGHT: (width - textWidth) - 2; + case CENTER: (width - textWidth) / 2; + } + + return new TextLineMetrics (margin, lineWidth, lineHeight, ascender, descender, leading); //return new TextLineMetrics (0, 0, 0, 0, 0, 0); @@ -1110,6 +1127,187 @@ class TextField extends InteractiveObject { } + @:noCompletion private function __getLineBreaks():Int { + + var lines:Int = 0; + for (i in 0...text.length) { + var char = Utf8.charCodeAt(text, i); + if (char == __utf8_endline_code) + { + lines++; + } + } + return lines; + } + + @:noCompletion private function __getLineBreakIndeces():Array { + + var breaks = []; + for (i in 0...text.length) { + var char = Utf8.charCodeAt(text, i); + if (char == __utf8_endline_code) + { + breaks.push(i); + } + } + return breaks; + } + + @:noCompletion private function __getLineBreaksInRange(i:Int):Int { + var lines:Int = 0; + if (__ranges.length > i && i >= 0) + { + var range = __ranges[i]; + if (range.start > 0 && range.end < text.length) + { + for (j in range.start...range.end + 1) + { + var char = Utf8.charCodeAt(text, i); + if (char == __utf8_endline_code) + { + lines++; + } + } + } + } + return lines; + } + + + + @:noCompletion private function __getLineIndeces(line:Int):Array { + //If you want a specific line, this tells you what the first and last (non-linebreak) character indeces are + + var breaks = __getLineBreakIndeces(); + var i:Int = 0; + var first_char = 0; + var last_char = text.length - 1; + + for (br in breaks) { + + //if this is the line we care about + if (i == line) + { + //the first actual character in our line is the index after this line break + first_char = br + 1; + + //if there's another line break left in the list + if (i != breaks.length-1) + { + //the last character is the index before the next line break + //(otherwise it's the last character in the text field) + last_char = breaks[i + 1] - 1; + } + } + i++; + } + return [first_char, last_char]; + } + + @:noCompletion private function __getLineWidth(line:Int):Float { + + var sizes = __measureText(false); + + var total:Float = 0; + var breakCode:Int = __utf8_endline_code; + + var currLine:Int = 0; + + trace("__getLineWidth(" + line+") text=(" + text + ")"); + trace("...sizes = " + sizes); + + for (i in 0...sizes.length) { + var size = sizes[i]; + var charCode = Utf8.charCodeAt(text, i); + + if (charCode == breakCode) + { + currLine++; + } + else if (currLine == line) + { + total += size; + } + else if (currLine > line) + { + break; + } + } + + return total; + } + + private static inline var ASCENDER:Int = 0; + private static inline var DESCENDER:Int = 1; + private static inline var LINE_HEIGHT:Int = 2; + private static inline var LEADING:Int = 3; + + @:noCompletion private function __getLineMetric(line:Int,metric:Int):Float { + + if (__ranges == null) + { + return __getLineMetricSubRangesNull(true, metric); + } + else + { + return __getLineMetricSubRangesNotNull(line, metric); + } + } + + @:noCompletion private function __getLineMetricSubRangesNull(singleLine:Bool=false, metric:Int):Float { + + var font = __getFontInstance (__textFormat); + + if (font != null) { + + return switch(metric) + { + case LINE_HEIGHT: font.height / font.unitsPerEM * __textFormat.size;// + __getLineMetricSubRangesNull(singleLine, DESCENDER) / 2; + case ASCENDER: font.ascender / font.unitsPerEM * __textFormat.size; + case DESCENDER: Math.abs(font.descender / font.unitsPerEM * __textFormat.size); + case LEADING: __textFormat.leading; + default: 0; + } + } + + return 0; + } + + @:noCompletion private function __getLineMetricSubRangesNotNull(specificLine:Int, metric:Int):Float { + + var lineChars = __getLineIndeces(specificLine); + + var m = 0.0; + var best_m = 0.0; + + for (range in __ranges) { + + if (range.start >= lineChars[0]) + { + var font = __getFontInstance (range.format); + + if (font != null) { + + m = switch(metric) + { + case LINE_HEIGHT: font.height / font.unitsPerEM * __textFormat.size;// + __getLineMetricSubRangesNotNull(specificLine, DESCENDER) / 2; + case ASCENDER: font.ascender / font.unitsPerEM * __textFormat.size; + case DESCENDER: Math.abs(font.descender / font.unitsPerEM * __textFormat.size); + case LEADING: __textFormat.leading; + default: 0; + } + } + } + + if (m > best_m) + { + best_m = m; + } + m = 0; + } + + return best_m; + } @:noCompletion private function __getPosition (x:Float, y:Float):Int { @@ -1139,7 +1337,6 @@ class TextField extends InteractiveObject { } - @:noCompletion private function __getTextWidth (text:String):Float { #if (js && html5) @@ -1188,7 +1385,7 @@ class TextField extends InteractiveObject { } - @:noCompletion private function __measureText ():Array { + @:noCompletion private function __measureText (condense:Bool=true):Array { #if js @@ -1221,6 +1418,44 @@ class TextField extends InteractiveObject { #elseif (cpp || neko) + var measurements = __measureTextSub(false); + + var currWidth = 0.0; + var biggestWidth = 0.0; + + for (i in 0...measurements.length) + { + var measure = measurements[i]; + var char = Utf8.charCodeAt(text, i); + if (char == __utf8_endline_code) + { + if (currWidth > biggestWidth) + { + biggestWidth = currWidth; + currWidth = 0; + } + } + else + { + currWidth += measurements[i]; + } + } + + return [biggestWidth]; + + #else + + return null; + + #end + + } + + + #if (cpp || neko) + + @:noCompletion private function __measureTextSub(condense:Bool):Array { + if (__textLayout == null) { __textLayout = new TextLayout (); @@ -1229,66 +1464,207 @@ class TextField extends InteractiveObject { if (__ranges == null) { - var font = __getFontInstance (__textFormat); - var width = 0.0; + return __measureTextSubRangesNull(condense); + + } else { + + return __measureTextSubRangesNotNull(condense); + } + + return null; + } + + @:noCompletion private function __measureTextSubRangesNull(condense:Bool):Array + { + var font = __getFontInstance (__textFormat); + var width = 0.0; + var widths = []; + + if (font != null && __textFormat.size != null) { + + __textLayout.text = null; + __textLayout.font = font; + __textLayout.size = Std.int (__textFormat.size); + __textLayout.text = __text; - if (font != null && __textFormat.size != null) { + for (position in __textLayout.positions) { + if (condense) + { + width += position.advance.x; + } + else + { + widths.push(position.advance.x); + } + + } + + } + + if (condense) + { + widths.push(width); + } + + return widths; + } + + @:noCompletion private function __measureTextSubRangesNotNull(condense:Bool):Array + { + var measurements = []; + + for (range in __ranges) { + + var font = __getFontInstance (range.format); + var width = 0.0; + + if (font != null && range.format.size != null) { + __textLayout.text = null; __textLayout.font = font; - __textLayout.size = Std.int (__textFormat.size); - __textLayout.text = __text; + __textLayout.size = Std.int (range.format.size); + __textLayout.text = text.substring (range.start, range.end); for (position in __textLayout.positions) { - width += position.advance.x; + if (condense) + { + width += position.advance.x; + } + else + { + measurements.push(position.advance.x); + } } } - return [ width ]; + if (condense) + { + measurements.push (width); + } - } else { + } + + return measurements; + } + + @:noCompletion private function __measureTextHeight():Float { + if (__ranges == null) { - var measurements = []; + return __measureTextHeightSubRangesNull(); + } + else { + + return __measureTextHeightSubRangesNotNull(); + } + } + + @:noCompletion private function __measureTextHeightSubRangesNull(singleLine:Bool=false):Float { + + var font = __getFontInstance (__textFormat); + var width = 0.0; + var widths = []; + + var descent = __getLineMetricSubRangesNull(singleLine, DESCENDER); + + if (font != null && __textFormat.size != null && __textLayout != null) { + + __textLayout.text = null; + __textLayout.font = font; + __textLayout.size = Std.int (__textFormat.size); + __textLayout.text = __text; + + if (!singleLine) + { + var lbs = (__getLineBreaks() + 1); + return (__textFormat.size + descent) * lbs - descent; + } + else + { + return (__textFormat.size + descent); + } + } + + return 0; + } + + @:noCompletion private function __measureTextHeightSubRangesNotNull(specificLine:Int=-1):Float { + + var measurements = []; + + var h:Float = 0; + + var descent = __getLineMetricSubRangesNotNull(specificLine, DESCENDER); + + if (specificLine != -1) + { + var lineChars = __getLineIndeces(specificLine); + + var best_h = 0.0; + for (range in __ranges) { + + if (range.start >= lineChars[0]) + { + var font = __getFontInstance (range.format); + + if (font != null && range.format.size != null) { + + __textLayout.text = null; + __textLayout.font = font; + __textLayout.size = Std.int (range.format.size); + __textLayout.text = text.substring (range.start, range.end); + + h += (__textFormat.size + descent); + } + } + + if (h > best_h) + { + best_h = h; + } + h = 0; + } + + return best_h; + } + else + { + //TODO: I could see there being errors here if you have multiple ranges spanning endlines but partially spanning lines. + var r:Int = 0; for (range in __ranges) { var font = __getFontInstance (range.format); var width = 0.0; if (font != null && range.format.size != null) { - + __textLayout.text = null; __textLayout.font = font; __textLayout.size = Std.int (range.format.size); __textLayout.text = text.substring (range.start, range.end); - for (position in __textLayout.positions) { - - width += position.advance.x; - + if (r == 0) + { + h += __textFormat.size + descent; } + var linebreaks = __getLineBreaksInRange(r); + h += (__textFormat.size + descent) * __getLineBreaks(); + } - measurements.push (width); - + r++; } - - return measurements; - } - #else - - return null; - - #end - + return h; } + #end @:noCompletion private function __measureTextWithDOM ():Void { @@ -1809,7 +2185,6 @@ class TextField extends InteractiveObject { } - @:noCompletion public function get_textWidth ():Float { #if js @@ -1884,7 +2259,7 @@ class TextField extends InteractiveObject { #else - return __textFormat.size * 1.185; + return __measureTextHeight(); #end From 370b6ad13d7506ec9812e765376e3f358004c3ff Mon Sep 17 00:00:00 2001 From: "Lars A. Doucet" Date: Wed, 15 Apr 2015 19:15:27 -0500 Subject: [PATCH 011/150] More text field rendering fixes --- openfl/_internal/renderer/opengl/GLTextField.hx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openfl/_internal/renderer/opengl/GLTextField.hx b/openfl/_internal/renderer/opengl/GLTextField.hx index 4e47804a12..00fd35bb06 100644 --- a/openfl/_internal/renderer/opengl/GLTextField.hx +++ b/openfl/_internal/renderer/opengl/GLTextField.hx @@ -258,6 +258,8 @@ class GLTextField { y += tlm.height; + y += tlm.leading; + //y += size + (textField.getLineMetrics(line_i).descent);// * 1.5; line_i++; From c3584123da342c6c269066bef5eef12a05e012db Mon Sep 17 00:00:00 2001 From: "Lars A. Doucet" Date: Wed, 15 Apr 2015 19:22:33 -0500 Subject: [PATCH 012/150] TextMetrics: Figured out that in flash LINE_HEIGHT always includes the value of leading --- openfl/_internal/renderer/opengl/GLTextField.hx | 4 ---- openfl/text/TextField.hx | 4 ++-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/openfl/_internal/renderer/opengl/GLTextField.hx b/openfl/_internal/renderer/opengl/GLTextField.hx index 00fd35bb06..1c0f915b62 100644 --- a/openfl/_internal/renderer/opengl/GLTextField.hx +++ b/openfl/_internal/renderer/opengl/GLTextField.hx @@ -258,10 +258,6 @@ class GLTextField { y += tlm.height; - y += tlm.leading; - - //y += size + (textField.getLineMetrics(line_i).descent);// * 1.5; - line_i++; } diff --git a/openfl/text/TextField.hx b/openfl/text/TextField.hx index 7784713cd1..6620bba60e 100644 --- a/openfl/text/TextField.hx +++ b/openfl/text/TextField.hx @@ -1262,7 +1262,7 @@ class TextField extends InteractiveObject { return switch(metric) { - case LINE_HEIGHT: font.height / font.unitsPerEM * __textFormat.size;// + __getLineMetricSubRangesNull(singleLine, DESCENDER) / 2; + case LINE_HEIGHT: font.height / font.unitsPerEM * __textFormat.size + __getLineMetricSubRangesNull(singleLine, LEADING); case ASCENDER: font.ascender / font.unitsPerEM * __textFormat.size; case DESCENDER: Math.abs(font.descender / font.unitsPerEM * __textFormat.size); case LEADING: __textFormat.leading; @@ -1290,7 +1290,7 @@ class TextField extends InteractiveObject { m = switch(metric) { - case LINE_HEIGHT: font.height / font.unitsPerEM * __textFormat.size;// + __getLineMetricSubRangesNotNull(specificLine, DESCENDER) / 2; + case LINE_HEIGHT: font.height / font.unitsPerEM * __textFormat.size + __getLineMetricSubRangesNotNull(specificLine, LEADING); case ASCENDER: font.ascender / font.unitsPerEM * __textFormat.size; case DESCENDER: Math.abs(font.descender / font.unitsPerEM * __textFormat.size); case LEADING: __textFormat.leading; From 69a2fa4dc60e8ab3c724087d0b2ed53302004685 Mon Sep 17 00:00:00 2001 From: "Lars A. Doucet" Date: Wed, 15 Apr 2015 19:47:13 -0500 Subject: [PATCH 013/150] TextMetrics: improved lineWidth to return the width of the specified line, not the entire text field --- openfl/text/TextField.hx | 61 ++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 36 deletions(-) diff --git a/openfl/text/TextField.hx b/openfl/text/TextField.hx index 6620bba60e..ba4f359d58 100644 --- a/openfl/text/TextField.hx +++ b/openfl/text/TextField.hx @@ -1206,35 +1206,8 @@ class TextField extends InteractiveObject { @:noCompletion private function __getLineWidth(line:Int):Float { - var sizes = __measureText(false); - - var total:Float = 0; - var breakCode:Int = __utf8_endline_code; - - var currLine:Int = 0; - - trace("__getLineWidth(" + line+") text=(" + text + ")"); - trace("...sizes = " + sizes); - - for (i in 0...sizes.length) { - var size = sizes[i]; - var charCode = Utf8.charCodeAt(text, i); - - if (charCode == breakCode) - { - currLine++; - } - else if (currLine == line) - { - total += size; - } - else if (currLine > line) - { - break; - } - } - - return total; + var sizes = __measureText(line); + return sizes[0]; } private static inline var ASCENDER:Int = 0; @@ -1385,7 +1358,7 @@ class TextField extends InteractiveObject { } - @:noCompletion private function __measureText (condense:Bool=true):Array { + @:noCompletion private function __measureText (specificLine:Int=-1):Array { #if js @@ -1421,19 +1394,26 @@ class TextField extends InteractiveObject { var measurements = __measureTextSub(false); var currWidth = 0.0; - var biggestWidth = 0.0; + var bestWidth = 0.0; + + var linebreaks = __getLineBreakIndeces(); + var currLine:Int = 0; for (i in 0...measurements.length) { var measure = measurements[i]; - var char = Utf8.charCodeAt(text, i); - if (char == __utf8_endline_code) + if (linebreaks.indexOf(i) != -1) { - if (currWidth > biggestWidth) + if (currLine == specificLine) { - biggestWidth = currWidth; + return [currWidth]; + } + else if (currWidth > bestWidth) + { + bestWidth = currWidth; currWidth = 0; } + currLine++; } else { @@ -1441,7 +1421,16 @@ class TextField extends InteractiveObject { } } - return [biggestWidth]; + if (currLine == specificLine) + { + return [currWidth]; + } + else if (currWidth > bestWidth) + { + bestWidth = currWidth; + } + + return [bestWidth]; #else From 2276b44b0cff5f8ea8ddb6d3d021b7cda61598fd Mon Sep 17 00:00:00 2001 From: "Lars A. Doucet" Date: Wed, 15 Apr 2015 20:01:46 -0500 Subject: [PATCH 014/150] TextMetrics: fixing alignment per line --- .../_internal/renderer/opengl/GLTextField.hx | 29 +++++++++---------- openfl/text/TextField.hx | 4 +-- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/openfl/_internal/renderer/opengl/GLTextField.hx b/openfl/_internal/renderer/opengl/GLTextField.hx index 1c0f915b62..c27b007b99 100644 --- a/openfl/_internal/renderer/opengl/GLTextField.hx +++ b/openfl/_internal/renderer/opengl/GLTextField.hx @@ -177,19 +177,11 @@ class GLTextField { //trace("textField." + textField. } + var tlm = textField.getLineMetrics(0); + var image; var x:Float = offsetX; - var y:Float = size - textField.getLineMetrics(0).descent / 2; - - if (format.align == TextFormatAlign.RIGHT) { - - x += textField.__width - textWidth; - - } else if (format.align == TextFormatAlign.CENTER) { - - x += (textField.__width - textWidth) / 2; - - } + var y:Float = size - tlm.descent / 2; var tileData; @@ -219,10 +211,19 @@ class GLTextField { var line_i:Int = 0; - var oldx = x; - for (line in lines) { + tlm = textField.getLineMetrics(line_i); + + x = offsetX; + + x += switch(format.align) + { + case LEFT, JUSTIFY: 0; + case RIGHT: (textField.__width - tlm.width) - 4; //not sure why -4 works, I expected -2 + case CENTER: (textField.__width - tlm.width) / 2; + } + textLayout.text = null; textLayout.font = font; textLayout.size = size; @@ -252,8 +253,6 @@ class GLTextField { } } - x = oldx; - var tlm = textField.getLineMetrics(line_i); y += tlm.height; diff --git a/openfl/text/TextField.hx b/openfl/text/TextField.hx index ba4f359d58..d25d15814d 100644 --- a/openfl/text/TextField.hx +++ b/openfl/text/TextField.hx @@ -730,8 +730,8 @@ class TextField extends InteractiveObject { var margin = switch(__textFormat.align) { case LEFT, JUSTIFY: 2; - case RIGHT: (width - textWidth) - 2; - case CENTER: (width - textWidth) / 2; + case RIGHT: (width - lineWidth) - 2; + case CENTER: (width - lineWidth) / 2; } return new TextLineMetrics (margin, lineWidth, lineHeight, ascender, descender, leading); From 6373e4718e4b67fb7febf3a2dedb1e41b3869dd9 Mon Sep 17 00:00:00 2001 From: "Lars A. Doucet" Date: Wed, 15 Apr 2015 20:29:50 -0500 Subject: [PATCH 015/150] TextMetrics: fix crash if text has multiple ranges, clarify __getLineWidth() --- openfl/text/TextField.hx | 85 ++++++++++++++++++++-------------------- 1 file changed, 42 insertions(+), 43 deletions(-) diff --git a/openfl/text/TextField.hx b/openfl/text/TextField.hx index d25d15814d..63b4898bc4 100644 --- a/openfl/text/TextField.hx +++ b/openfl/text/TextField.hx @@ -1206,8 +1206,46 @@ class TextField extends InteractiveObject { @:noCompletion private function __getLineWidth(line:Int):Float { - var sizes = __measureText(line); - return sizes[0]; + var measurements = __measureTextSub(false); + + var currWidth = 0.0; + var bestWidth = 0.0; + + var linebreaks = __getLineBreakIndeces(); + + var currLine:Int = 0; + for (i in 0...measurements.length) + { + var measure = measurements[i]; + if (linebreaks.indexOf(i) != -1) + { + if (currLine == line) + { + return currWidth; + } + else if (currWidth > bestWidth) + { + bestWidth = currWidth; + currWidth = 0; + } + currLine++; + } + else + { + currWidth += measurements[i]; + } + } + + if (currLine == line) + { + return currWidth; + } + else if (currWidth > bestWidth) + { + bestWidth = currWidth; + } + + return bestWidth; } private static inline var ASCENDER:Int = 0; @@ -1358,7 +1396,7 @@ class TextField extends InteractiveObject { } - @:noCompletion private function __measureText (specificLine:Int=-1):Array { + @:noCompletion private function __measureText (condense:Bool=true):Array { #if js @@ -1391,46 +1429,7 @@ class TextField extends InteractiveObject { #elseif (cpp || neko) - var measurements = __measureTextSub(false); - - var currWidth = 0.0; - var bestWidth = 0.0; - - var linebreaks = __getLineBreakIndeces(); - - var currLine:Int = 0; - for (i in 0...measurements.length) - { - var measure = measurements[i]; - if (linebreaks.indexOf(i) != -1) - { - if (currLine == specificLine) - { - return [currWidth]; - } - else if (currWidth > bestWidth) - { - bestWidth = currWidth; - currWidth = 0; - } - currLine++; - } - else - { - currWidth += measurements[i]; - } - } - - if (currLine == specificLine) - { - return [currWidth]; - } - else if (currWidth > bestWidth) - { - bestWidth = currWidth; - } - - return [bestWidth]; + return __measureTextSub(condense); #else From b3d9a17ede315378b47a294a25ca1fcd97d76476 Mon Sep 17 00:00:00 2001 From: "Lars A. Doucet" Date: Wed, 15 Apr 2015 21:10:45 -0500 Subject: [PATCH 016/150] TextMetrics: Text fields now render in nearly exactly the same positions they do in Flash! --- openfl/_internal/renderer/opengl/GLTextField.hx | 2 +- openfl/text/TextField.hx | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/openfl/_internal/renderer/opengl/GLTextField.hx b/openfl/_internal/renderer/opengl/GLTextField.hx index c27b007b99..4c8529cfa2 100644 --- a/openfl/_internal/renderer/opengl/GLTextField.hx +++ b/openfl/_internal/renderer/opengl/GLTextField.hx @@ -181,7 +181,7 @@ class GLTextField { var image; var x:Float = offsetX; - var y:Float = size - tlm.descent / 2; + var y:Float = size;// - tlm.descent / 2; var tileData; diff --git a/openfl/text/TextField.hx b/openfl/text/TextField.hx index 63b4898bc4..021d58d3b0 100644 --- a/openfl/text/TextField.hx +++ b/openfl/text/TextField.hx @@ -2247,7 +2247,13 @@ class TextField extends InteractiveObject { #else - return __measureTextHeight(); + var lines = __getLineBreaks() + 1; + var th = 0.0; + for (i in 0...lines) + { + th += __getLineMetric(i, LINE_HEIGHT); + } + return th; #end From c668fe5a2753577903eba2d9d8aaf5d838ecf9a1 Mon Sep 17 00:00:00 2001 From: "Lars A. Doucet" Date: Thu, 16 Apr 2015 11:01:48 -0500 Subject: [PATCH 017/150] TextMetrics: Finally figured out how to set the initial y value. If you draw "The quick brown fox" at y == 0, the bottom of the "T" will rest right on TOP of the text field. Therefore you need to push it down by the value of the ascender and the margin, which is (ascent+2). --- openfl/_internal/renderer/opengl/GLTextField.hx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/openfl/_internal/renderer/opengl/GLTextField.hx b/openfl/_internal/renderer/opengl/GLTextField.hx index 4c8529cfa2..6fe09d9c67 100644 --- a/openfl/_internal/renderer/opengl/GLTextField.hx +++ b/openfl/_internal/renderer/opengl/GLTextField.hx @@ -181,7 +181,7 @@ class GLTextField { var image; var x:Float = offsetX; - var y:Float = size;// - tlm.descent / 2; + var y:Float = 2 + tlm.ascent; var tileData; @@ -246,11 +246,6 @@ class GLTextField { x += position.advance.x; y -= position.advance.y; - - if (dodebug) - { - trace("y = " + y); - } } var tlm = textField.getLineMetrics(line_i); From 9a0c69ea2e94931fb1079045dc264d6fee8a7ac1 Mon Sep 17 00:00:00 2001 From: "Lars A. Doucet" Date: Thu, 16 Apr 2015 11:45:39 -0500 Subject: [PATCH 018/150] TextMetrics: Dialed in the remaining discrepancies. Flixel's Mode now has exactly the same text rendering! The key insight was that line height = ascent + descent + leading, EXACTLY. --- openfl/text/TextField.hx | 148 +++++---------------------------------- 1 file changed, 19 insertions(+), 129 deletions(-) diff --git a/openfl/text/TextField.hx b/openfl/text/TextField.hx index 021d58d3b0..73e27860ad 100644 --- a/openfl/text/TextField.hx +++ b/openfl/text/TextField.hx @@ -1206,6 +1206,8 @@ class TextField extends InteractiveObject { @:noCompletion private function __getLineWidth(line:Int):Float { + //Returns the width of a given line, or if -1 is supplied, the largest width + var measurements = __measureTextSub(false); var currWidth = 0.0; @@ -1223,7 +1225,7 @@ class TextField extends InteractiveObject { { return currWidth; } - else if (currWidth > bestWidth) + else if (line == -1 && currWidth > bestWidth) { bestWidth = currWidth; currWidth = 0; @@ -1240,7 +1242,7 @@ class TextField extends InteractiveObject { { return currWidth; } - else if (currWidth > bestWidth) + else if (line == -1 && currWidth > bestWidth) { bestWidth = currWidth; } @@ -1273,7 +1275,10 @@ class TextField extends InteractiveObject { return switch(metric) { - case LINE_HEIGHT: font.height / font.unitsPerEM * __textFormat.size + __getLineMetricSubRangesNull(singleLine, LEADING); + case LINE_HEIGHT: __getLineMetricSubRangesNull(singleLine, ASCENDER) + + __getLineMetricSubRangesNull(singleLine, DESCENDER) + + __getLineMetricSubRangesNull(singleLine, LEADING); + //font.height / font.unitsPerEM * __textFormat.size + __getLineMetricSubRangesNull(singleLine, LEADING); case ASCENDER: font.ascender / font.unitsPerEM * __textFormat.size; case DESCENDER: Math.abs(font.descender / font.unitsPerEM * __textFormat.size); case LEADING: __textFormat.leading; @@ -1301,7 +1306,10 @@ class TextField extends InteractiveObject { m = switch(metric) { - case LINE_HEIGHT: font.height / font.unitsPerEM * __textFormat.size + __getLineMetricSubRangesNotNull(specificLine, LEADING); + case LINE_HEIGHT: __getLineMetricSubRangesNotNull(specificLine, ASCENDER) + + __getLineMetricSubRangesNotNull(specificLine, DESCENDER) + + __getLineMetricSubRangesNotNull(specificLine, LEADING); + //font.height / font.unitsPerEM * __textFormat.size + __getLineMetricSubRangesNotNull(specificLine, LEADING); case ASCENDER: font.ascender / font.unitsPerEM * __textFormat.size; case DESCENDER: Math.abs(font.descender / font.unitsPerEM * __textFormat.size); case LEADING: __textFormat.leading; @@ -1539,119 +1547,6 @@ class TextField extends InteractiveObject { return measurements; } - @:noCompletion private function __measureTextHeight():Float { - if (__ranges == null) { - - return __measureTextHeightSubRangesNull(); - } - else { - - return __measureTextHeightSubRangesNotNull(); - } - } - - @:noCompletion private function __measureTextHeightSubRangesNull(singleLine:Bool=false):Float { - - var font = __getFontInstance (__textFormat); - var width = 0.0; - var widths = []; - - var descent = __getLineMetricSubRangesNull(singleLine, DESCENDER); - - if (font != null && __textFormat.size != null && __textLayout != null) { - - __textLayout.text = null; - __textLayout.font = font; - __textLayout.size = Std.int (__textFormat.size); - __textLayout.text = __text; - - if (!singleLine) - { - var lbs = (__getLineBreaks() + 1); - return (__textFormat.size + descent) * lbs - descent; - } - else - { - return (__textFormat.size + descent); - } - } - - return 0; - } - - @:noCompletion private function __measureTextHeightSubRangesNotNull(specificLine:Int=-1):Float { - - var measurements = []; - - var h:Float = 0; - - var descent = __getLineMetricSubRangesNotNull(specificLine, DESCENDER); - - if (specificLine != -1) - { - var lineChars = __getLineIndeces(specificLine); - - var best_h = 0.0; - - for (range in __ranges) { - - if (range.start >= lineChars[0]) - { - var font = __getFontInstance (range.format); - - if (font != null && range.format.size != null) { - - __textLayout.text = null; - __textLayout.font = font; - __textLayout.size = Std.int (range.format.size); - __textLayout.text = text.substring (range.start, range.end); - - h += (__textFormat.size + descent); - } - } - - if (h > best_h) - { - best_h = h; - } - h = 0; - } - - return best_h; - } - else - { - //TODO: I could see there being errors here if you have multiple ranges spanning endlines but partially spanning lines. - var r:Int = 0; - for (range in __ranges) { - - var font = __getFontInstance (range.format); - var width = 0.0; - - if (font != null && range.format.size != null) { - - __textLayout.text = null; - __textLayout.font = font; - __textLayout.size = Std.int (range.format.size); - __textLayout.text = text.substring (range.start, range.end); - - if (r == 0) - { - h += __textFormat.size + descent; - } - - var linebreaks = __getLineBreaksInRange(r); - h += (__textFormat.size + descent) * __getLineBreaks(); - - } - - r++; - } - } - - return h; - } - #end @:noCompletion private function __measureTextWithDOM ():Void { @@ -2203,16 +2098,7 @@ class TextField extends InteractiveObject { #elseif (cpp || neko) - var sizes = __measureText (); - var total:Float = 0; - - for (size in sizes) { - - total += size; - - } - - return total; + return __getLineWidth( -1); #else @@ -2247,11 +2133,15 @@ class TextField extends InteractiveObject { #else - var lines = __getLineBreaks() + 1; + //sum the heights of the lines, but don't count the leading of the last line var th = 0.0; - for (i in 0...lines) + for (i in 0...numLines) { th += __getLineMetric(i, LINE_HEIGHT); + if (i == numLines - 1) + { + th -= __getLineMetric(i, LEADING); + } } return th; From e272d392933249145e996ca59f5929031d02e9c3 Mon Sep 17 00:00:00 2001 From: "Lars A. Doucet" Date: Thu, 16 Apr 2015 12:00:23 -0500 Subject: [PATCH 019/150] TextMetrics: Cleanup/comments --- openfl/text/TextField.hx | 43 +++++++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/openfl/text/TextField.hx b/openfl/text/TextField.hx index 73e27860ad..a9e69bbad3 100644 --- a/openfl/text/TextField.hx +++ b/openfl/text/TextField.hx @@ -1129,6 +1129,8 @@ class TextField extends InteractiveObject { @:noCompletion private function __getLineBreaks():Int { + //returns the number of line breaks in the text + var lines:Int = 0; for (i in 0...text.length) { var char = Utf8.charCodeAt(text, i); @@ -1142,6 +1144,8 @@ class TextField extends InteractiveObject { @:noCompletion private function __getLineBreakIndeces():Array { + //returns the exact character indeces where the line breaks occur + var breaks = []; for (i in 0...text.length) { var char = Utf8.charCodeAt(text, i); @@ -1154,6 +1158,9 @@ class TextField extends InteractiveObject { } @:noCompletion private function __getLineBreaksInRange(i:Int):Int { + + //returns the number of line breaks that occur within a given format range + var lines:Int = 0; if (__ranges.length > i && i >= 0) { @@ -1176,7 +1183,8 @@ class TextField extends InteractiveObject { @:noCompletion private function __getLineIndeces(line:Int):Array { - //If you want a specific line, this tells you what the first and last (non-linebreak) character indeces are + + //tells you what the first and last (non-linebreak) character indeces are in a given line var breaks = __getLineBreakIndeces(); var i:Int = 0; @@ -1206,7 +1214,7 @@ class TextField extends InteractiveObject { @:noCompletion private function __getLineWidth(line:Int):Float { - //Returns the width of a given line, or if -1 is supplied, the largest width + //Returns the width of a given line, or if -1 is supplied, the largest width of any single line var measurements = __measureTextSub(false); @@ -1256,7 +1264,9 @@ class TextField extends InteractiveObject { private static inline var LEADING:Int = 3; @:noCompletion private function __getLineMetric(line:Int,metric:Int):Float { - + + //returns the specified line metric for the given line + if (__ranges == null) { return __getLineMetricSubRangesNull(true, metric); @@ -1269,6 +1279,8 @@ class TextField extends InteractiveObject { @:noCompletion private function __getLineMetricSubRangesNull(singleLine:Bool=false, metric:Int):Float { + //subroutine if ranges are null + var font = __getFontInstance (__textFormat); if (font != null) { @@ -1278,7 +1290,6 @@ class TextField extends InteractiveObject { case LINE_HEIGHT: __getLineMetricSubRangesNull(singleLine, ASCENDER) + __getLineMetricSubRangesNull(singleLine, DESCENDER) + __getLineMetricSubRangesNull(singleLine, LEADING); - //font.height / font.unitsPerEM * __textFormat.size + __getLineMetricSubRangesNull(singleLine, LEADING); case ASCENDER: font.ascender / font.unitsPerEM * __textFormat.size; case DESCENDER: Math.abs(font.descender / font.unitsPerEM * __textFormat.size); case LEADING: __textFormat.leading; @@ -1291,6 +1302,9 @@ class TextField extends InteractiveObject { @:noCompletion private function __getLineMetricSubRangesNotNull(specificLine:Int, metric:Int):Float { + //subroutine if ranges are not null + //TODO: test this more thoroughly + var lineChars = __getLineIndeces(specificLine); var m = 0.0; @@ -1309,7 +1323,6 @@ class TextField extends InteractiveObject { case LINE_HEIGHT: __getLineMetricSubRangesNotNull(specificLine, ASCENDER) + __getLineMetricSubRangesNotNull(specificLine, DESCENDER) + __getLineMetricSubRangesNotNull(specificLine, LEADING); - //font.height / font.unitsPerEM * __textFormat.size + __getLineMetricSubRangesNotNull(specificLine, LEADING); case ASCENDER: font.ascender / font.unitsPerEM * __textFormat.size; case DESCENDER: Math.abs(font.descender / font.unitsPerEM * __textFormat.size); case LEADING: __textFormat.leading; @@ -1403,7 +1416,6 @@ class TextField extends InteractiveObject { } - @:noCompletion private function __measureText (condense:Bool=true):Array { #if js @@ -1437,6 +1449,9 @@ class TextField extends InteractiveObject { #elseif (cpp || neko) + //the "condense" flag, if true, will return the widths of individual text format ranges, if false will return the widths of each character + //TODO: look into whether this method and others can replace the JS stuff yet or not + return __measureTextSub(condense); #else @@ -1447,11 +1462,10 @@ class TextField extends InteractiveObject { } - - #if (cpp || neko) - @:noCompletion private function __measureTextSub(condense:Bool):Array { + //subroutine for measuring text (width) + if (__textLayout == null) { __textLayout = new TextLayout (); @@ -1472,6 +1486,8 @@ class TextField extends InteractiveObject { @:noCompletion private function __measureTextSubRangesNull(condense:Bool):Array { + //subroutine if format ranges are null + var font = __getFontInstance (__textFormat); var width = 0.0; var widths = []; @@ -1508,6 +1524,8 @@ class TextField extends InteractiveObject { @:noCompletion private function __measureTextSubRangesNotNull(condense:Bool):Array { + //subroutine if format ranges are not null + var measurements = []; for (range in __ranges) { @@ -1547,8 +1565,6 @@ class TextField extends InteractiveObject { return measurements; } - #end - @:noCompletion private function __measureTextWithDOM ():Void { #if js @@ -2098,6 +2114,8 @@ class TextField extends InteractiveObject { #elseif (cpp || neko) + //return the largest width of any given single line + //TODO: need to check actual left/right bounding volume in case of pathological cases (multiple format ranges for instance) return __getLineWidth( -1); #else @@ -2133,7 +2151,8 @@ class TextField extends InteractiveObject { #else - //sum the heights of the lines, but don't count the leading of the last line + //sum the heights of all the lines, but don't count the leading of the last line + //TODO: might need robustness check for pathological cases (multiple format ranges) -- would need to change how line heights are calculated var th = 0.0; for (i in 0...numLines) { From 5736e8dfb90fd2381e88aa5d789b4e1d683a4bc0 Mon Sep 17 00:00:00 2001 From: "Lars A. Doucet" Date: Thu, 16 Apr 2015 12:04:54 -0500 Subject: [PATCH 020/150] TextMetrics: cleaning up and adding comments to GL renderer --- .../_internal/renderer/opengl/GLTextField.hx | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/openfl/_internal/renderer/opengl/GLTextField.hx b/openfl/_internal/renderer/opengl/GLTextField.hx index 6fe09d9c67..910a11edaa 100644 --- a/openfl/_internal/renderer/opengl/GLTextField.hx +++ b/openfl/_internal/renderer/opengl/GLTextField.hx @@ -81,8 +81,6 @@ class GLTextField { private static inline function renderText (textField:TextField, text:String, format:TextFormat, offsetX:Float, textWidth:Float):Void { - var dodebug = (textField.defaultTextFormat.font.toLowerCase().indexOf("liberation") != -1); - var font = textField.__getFontInstance (format); if (font != null && format.size != null) { @@ -172,17 +170,15 @@ class GLTextField { var g = ((format.color >> 8) & 0xFF) / 0xFF; var b = ((format.color) & 0xFF) / 0xFF; - if (dodebug) - { - //trace("textField." + textField. - } - var tlm = textField.getLineMetrics(0); var image; var x:Float = offsetX; var y:Float = 2 + tlm.ascent; + //If you render with y == 0, the bottom pixel of the "T" in "The Quick Brown Fox" will rest on TOP of your text field. + //Flash API text fields have a 2px margin on all sides, so (2 + ASCENT) puts your text right where it needs to be. + var tileData; if (textField.__tilesheets.length == 0 || textField.__tilesheets[textField.__tilesheets.length - 1] != tilesheet) { @@ -215,12 +211,12 @@ class GLTextField { tlm = textField.getLineMetrics(line_i); + //x position must be reset every line and recalculated x = offsetX; - x += switch(format.align) - { + x += switch(format.align) { case LEFT, JUSTIFY: 0; - case RIGHT: (textField.__width - tlm.width) - 4; //not sure why -4 works, I expected -2 + case RIGHT: (textField.__width - tlm.width) - 4; //not sure why -4 works, I expected -2, but it seems to be correct! case CENTER: (textField.__width - tlm.width) / 2; } @@ -248,9 +244,7 @@ class GLTextField { y -= position.advance.y; } - var tlm = textField.getLineMetrics(line_i); - - y += tlm.height; + y += tlm.height; //always add the line height at the end line_i++; } From f652fc2f7b7eb1fbc02f6e8a9a9e9cae7118a1e0 Mon Sep 17 00:00:00 2001 From: "Lars A. Doucet" Date: Thu, 16 Apr 2015 12:16:46 -0500 Subject: [PATCH 021/150] TextMetrics: fixed bug with right-alignment and line width measurements, added more comments --- .../_internal/renderer/opengl/GLTextField.hx | 4 +++- openfl/text/TextField.hx | 23 +++++++++---------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/openfl/_internal/renderer/opengl/GLTextField.hx b/openfl/_internal/renderer/opengl/GLTextField.hx index 910a11edaa..448109b859 100644 --- a/openfl/_internal/renderer/opengl/GLTextField.hx +++ b/openfl/_internal/renderer/opengl/GLTextField.hx @@ -207,12 +207,14 @@ class GLTextField { var line_i:Int = 0; + var oldX = x; + for (line in lines) { tlm = textField.getLineMetrics(line_i); //x position must be reset every line and recalculated - x = offsetX; + x = oldX; x += switch(format.align) { case LEFT, JUSTIFY: 0; diff --git a/openfl/text/TextField.hx b/openfl/text/TextField.hx index a9e69bbad3..218f370609 100644 --- a/openfl/text/TextField.hx +++ b/openfl/text/TextField.hx @@ -715,8 +715,6 @@ class TextField extends InteractiveObject { */ public function getLineMetrics (lineIndex:Int):TextLineMetrics { - //openfl.Lib.notImplemented ("TextField.getLineMetrics"); - var height = textHeight; var lineWidth = __getLineWidth(lineIndex); @@ -1227,30 +1225,31 @@ class TextField extends InteractiveObject { for (i in 0...measurements.length) { var measure = measurements[i]; - if (linebreaks.indexOf(i) != -1) + if (linebreaks.indexOf(i) != -1) //if this character is a line break { - if (currLine == line) + if (currLine == line) //if we're currently on the desired line { - return currWidth; + return currWidth; //return the built up width immediately } - else if (line == -1 && currWidth > bestWidth) + else if (line == -1 && currWidth > bestWidth) //if we are looking at ALL lines, and this width is bigger than the last one { - bestWidth = currWidth; - currWidth = 0; + bestWidth = currWidth; //this is the new best width } + + currWidth = 0; //reset current width currLine++; } else { - currWidth += measurements[i]; + currWidth += measurements[i]; //keep building up the width } } - if (currLine == line) + if (currLine == line) //we reached end of the loop & this is the line we want { - return currWidth; + bestWidth = currWidth; } - else if (line == -1 && currWidth > bestWidth) + else if (line == -1 && currWidth > bestWidth) //looking at ALL lines, and this one's bigger { bestWidth = currWidth; } From b55e429e4c220c9565e3d3f717b6360a7ff43a00 Mon Sep 17 00:00:00 2001 From: "Lars A. Doucet" Date: Thu, 16 Apr 2015 12:26:04 -0500 Subject: [PATCH 022/150] TextMetrics: more comments --- openfl/_internal/renderer/opengl/GLTextField.hx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/openfl/_internal/renderer/opengl/GLTextField.hx b/openfl/_internal/renderer/opengl/GLTextField.hx index 448109b859..7c480f0f60 100644 --- a/openfl/_internal/renderer/opengl/GLTextField.hx +++ b/openfl/_internal/renderer/opengl/GLTextField.hx @@ -217,9 +217,10 @@ class GLTextField { x = oldX; x += switch(format.align) { - case LEFT, JUSTIFY: 0; - case RIGHT: (textField.__width - tlm.width) - 4; //not sure why -4 works, I expected -2, but it seems to be correct! - case CENTER: (textField.__width - tlm.width) / 2; + case LEFT, JUSTIFY: 0; //the renderer has already positioned the text at the right spot past the 2px left margin + case CENTER: ((textField.__width - 4) - tlm.width) / 2; //subtract 4 from textfield.__width because __width includes the 2px margin on both sides, which doesn't count + case RIGHT: ((textField.__width - 4) - tlm.width); //same thing here + } textLayout.text = null; From ea82e082586fcabcc448edcba94299637e43a600 Mon Sep 17 00:00:00 2001 From: "Lars A. Doucet" Date: Thu, 16 Apr 2015 13:11:54 -0500 Subject: [PATCH 023/150] Style Update --- openfl/text/TextField.hx | 67 ++++++++++++++-------------------------- 1 file changed, 23 insertions(+), 44 deletions(-) diff --git a/openfl/text/TextField.hx b/openfl/text/TextField.hx index 218f370609..683a9f9355 100644 --- a/openfl/text/TextField.hx +++ b/openfl/text/TextField.hx @@ -1132,8 +1132,7 @@ class TextField extends InteractiveObject { var lines:Int = 0; for (i in 0...text.length) { var char = Utf8.charCodeAt(text, i); - if (char == __utf8_endline_code) - { + if (char == __utf8_endline_code) { lines++; } } @@ -1147,8 +1146,7 @@ class TextField extends InteractiveObject { var breaks = []; for (i in 0...text.length) { var char = Utf8.charCodeAt(text, i); - if (char == __utf8_endline_code) - { + if (char == __utf8_endline_code) { breaks.push(i); } } @@ -1160,16 +1158,13 @@ class TextField extends InteractiveObject { //returns the number of line breaks that occur within a given format range var lines:Int = 0; - if (__ranges.length > i && i >= 0) - { + if (__ranges.length > i && i >= 0) { var range = __ranges[i]; - if (range.start > 0 && range.end < text.length) - { - for (j in range.start...range.end + 1) - { + if (range.start > 0 && range.end < text.length) { + for (j in range.start...range.end + 1) { var char = Utf8.charCodeAt(text, i); - if (char == __utf8_endline_code) - { + if (char == __utf8_endline_code) { + lines++; } } @@ -1192,14 +1187,12 @@ class TextField extends InteractiveObject { for (br in breaks) { //if this is the line we care about - if (i == line) - { + if (i == line) { //the first actual character in our line is the index after this line break first_char = br + 1; //if there's another line break left in the list - if (i != breaks.length-1) - { + if (i != breaks.length-1) { //the last character is the index before the next line break //(otherwise it's the last character in the text field) last_char = breaks[i + 1] - 1; @@ -1225,32 +1218,26 @@ class TextField extends InteractiveObject { for (i in 0...measurements.length) { var measure = measurements[i]; - if (linebreaks.indexOf(i) != -1) //if this character is a line break - { - if (currLine == line) //if we're currently on the desired line - { + if (linebreaks.indexOf(i) != -1) { //if this character is a line break + if (currLine == line) { //if we're currently on the desired line return currWidth; //return the built up width immediately } - else if (line == -1 && currWidth > bestWidth) //if we are looking at ALL lines, and this width is bigger than the last one - { + else if (line == -1 && currWidth > bestWidth) { //if we are looking at ALL lines, and this width is bigger than the last one bestWidth = currWidth; //this is the new best width } currWidth = 0; //reset current width currLine++; } - else - { + else { currWidth += measurements[i]; //keep building up the width } } - if (currLine == line) //we reached end of the loop & this is the line we want - { + if (currLine == line) { //we reached end of the loop & this is the line we want bestWidth = currWidth; } - else if (line == -1 && currWidth > bestWidth) //looking at ALL lines, and this one's bigger - { + else if (line == -1 && currWidth > bestWidth) { //looking at ALL lines, and this one's bigger bestWidth = currWidth; } @@ -1266,12 +1253,10 @@ class TextField extends InteractiveObject { //returns the specified line metric for the given line - if (__ranges == null) - { + if (__ranges == null) { return __getLineMetricSubRangesNull(true, metric); } - else - { + else { return __getLineMetricSubRangesNotNull(line, metric); } } @@ -1284,8 +1269,7 @@ class TextField extends InteractiveObject { if (font != null) { - return switch(metric) - { + return switch(metric) { case LINE_HEIGHT: __getLineMetricSubRangesNull(singleLine, ASCENDER) + __getLineMetricSubRangesNull(singleLine, DESCENDER) + __getLineMetricSubRangesNull(singleLine, LEADING); @@ -1311,14 +1295,12 @@ class TextField extends InteractiveObject { for (range in __ranges) { - if (range.start >= lineChars[0]) - { + if (range.start >= lineChars[0]) { var font = __getFontInstance (range.format); if (font != null) { - m = switch(metric) - { + m = switch(metric) { case LINE_HEIGHT: __getLineMetricSubRangesNotNull(specificLine, ASCENDER) + __getLineMetricSubRangesNotNull(specificLine, DESCENDER) + __getLineMetricSubRangesNotNull(specificLine, LEADING); @@ -1330,8 +1312,7 @@ class TextField extends InteractiveObject { } } - if (m > best_m) - { + if (m > best_m) { best_m = m; } m = 0; @@ -2153,11 +2134,9 @@ class TextField extends InteractiveObject { //sum the heights of all the lines, but don't count the leading of the last line //TODO: might need robustness check for pathological cases (multiple format ranges) -- would need to change how line heights are calculated var th = 0.0; - for (i in 0...numLines) - { + for (i in 0...numLines) { th += __getLineMetric(i, LINE_HEIGHT); - if (i == numLines - 1) - { + if (i == numLines - 1) { th -= __getLineMetric(i, LEADING); } } From a1c0be63a7f41d70b8772f287cfed186fc6d3f46 Mon Sep 17 00:00:00 2001 From: "Lars A. Doucet" Date: Thu, 16 Apr 2015 13:14:49 -0500 Subject: [PATCH 024/150] style update --- openfl/text/TextField.hx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/openfl/text/TextField.hx b/openfl/text/TextField.hx index 683a9f9355..2aa0fd90a5 100644 --- a/openfl/text/TextField.hx +++ b/openfl/text/TextField.hx @@ -1164,7 +1164,6 @@ class TextField extends InteractiveObject { for (j in range.start...range.end + 1) { var char = Utf8.charCodeAt(text, i); if (char == __utf8_endline_code) { - lines++; } } @@ -1215,8 +1214,7 @@ class TextField extends InteractiveObject { var linebreaks = __getLineBreakIndeces(); var currLine:Int = 0; - for (i in 0...measurements.length) - { + for (i in 0...measurements.length) { var measure = measurements[i]; if (linebreaks.indexOf(i) != -1) { //if this character is a line break if (currLine == line) { //if we're currently on the desired line From ad6c8341be4f003c1b29801de84b5f9d7a57d8ab Mon Sep 17 00:00:00 2001 From: "Lars A. Doucet" Date: Thu, 16 Apr 2015 13:17:08 -0500 Subject: [PATCH 025/150] style update --- openfl/text/TextField.hx | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/openfl/text/TextField.hx b/openfl/text/TextField.hx index 2aa0fd90a5..46748d08dc 100644 --- a/openfl/text/TextField.hx +++ b/openfl/text/TextField.hx @@ -725,8 +725,7 @@ class TextField extends InteractiveObject { var leading = __getLineMetric(lineIndex, LEADING); - var margin = switch(__textFormat.align) - { + var margin = switch(__textFormat.align) { case LEFT, JUSTIFY: 2; case RIGHT: (width - lineWidth) - 2; case CENTER: (width - lineWidth) / 2; @@ -1462,8 +1461,8 @@ class TextField extends InteractiveObject { return null; } - @:noCompletion private function __measureTextSubRangesNull(condense:Bool):Array - { + @:noCompletion private function __measureTextSubRangesNull(condense:Bool):Array { + //subroutine if format ranges are null var font = __getFontInstance (__textFormat); @@ -1500,8 +1499,8 @@ class TextField extends InteractiveObject { return widths; } - @:noCompletion private function __measureTextSubRangesNotNull(condense:Bool):Array - { + @:noCompletion private function __measureTextSubRangesNotNull(condense:Bool):Array { + //subroutine if format ranges are not null var measurements = []; From 0e2a5a85a8d58ba6e32fb22fde8df9dd22b20088 Mon Sep 17 00:00:00 2001 From: "Lars A. Doucet" Date: Thu, 16 Apr 2015 13:18:32 -0500 Subject: [PATCH 026/150] TextMetrics: clean up old commented code --- openfl/text/TextField.hx | 2 -- 1 file changed, 2 deletions(-) diff --git a/openfl/text/TextField.hx b/openfl/text/TextField.hx index 46748d08dc..9ebe1ca2e9 100644 --- a/openfl/text/TextField.hx +++ b/openfl/text/TextField.hx @@ -733,8 +733,6 @@ class TextField extends InteractiveObject { return new TextLineMetrics (margin, lineWidth, lineHeight, ascender, descender, leading); - //return new TextLineMetrics (0, 0, 0, 0, 0, 0); - } From ceaaae37f84819d524bb62eaf1aaf1a0ef6d02d1 Mon Sep 17 00:00:00 2001 From: "Lars A. Doucet" Date: Thu, 16 Apr 2015 13:28:59 -0500 Subject: [PATCH 027/150] Style fixes (thanks @hasufel!) --- openfl/text/TextField.hx | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/openfl/text/TextField.hx b/openfl/text/TextField.hx index 9ebe1ca2e9..557a585d83 100644 --- a/openfl/text/TextField.hx +++ b/openfl/text/TextField.hx @@ -1476,12 +1476,10 @@ class TextField extends InteractiveObject { for (position in __textLayout.positions) { - if (condense) - { + if (condense) { width += position.advance.x; } - else - { + else { widths.push(position.advance.x); } @@ -1489,8 +1487,7 @@ class TextField extends InteractiveObject { } - if (condense) - { + if (condense) { widths.push(width); } @@ -1517,12 +1514,10 @@ class TextField extends InteractiveObject { for (position in __textLayout.positions) { - if (condense) - { + if (condense) { width += position.advance.x; } - else - { + else { measurements.push(position.advance.x); } @@ -1530,8 +1525,7 @@ class TextField extends InteractiveObject { } - if (condense) - { + if (condense) { measurements.push (width); } From 5559bfe563620d97c300ace02d7e3a673aad9ced Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Thu, 16 Apr 2015 15:59:35 -0700 Subject: [PATCH 028/150] Improve the mouse stack when interactive and non-interactive children pass a hit test, improve the behavior of enabling POINTER or TEXT cursors --- openfl/display/DisplayObject.hx | 10 ++++- openfl/display/DisplayObjectContainer.hx | 28 ++++++++++-- openfl/display/InteractiveObject.hx | 16 ++++--- openfl/display/SimpleButton.hx | 8 ++++ openfl/display/Sprite.hx | 8 ++++ openfl/display/Stage.hx | 57 ++++++++---------------- openfl/text/TextField.hx | 7 +++ 7 files changed, 85 insertions(+), 49 deletions(-) diff --git a/openfl/display/DisplayObject.hx b/openfl/display/DisplayObject.hx index 3dbb2b50b9..335bba73a8 100644 --- a/openfl/display/DisplayObject.hx +++ b/openfl/display/DisplayObject.hx @@ -1,6 +1,7 @@ package openfl.display; #if !flash #if !openfl_legacy +import lime.ui.MouseCursor; import openfl._internal.renderer.canvas.CanvasGraphics; import openfl._internal.renderer.canvas.CanvasShape; import openfl._internal.renderer.dom.DOMShape; @@ -1010,9 +1011,16 @@ class DisplayObject extends EventDispatcher implements IBitmapDrawable { } - @:noCompletion private function __getInteractive (stack:Array):Void { + @:noCompletion private function __getCursor ():MouseCursor { + return null; + + } + + + @:noCompletion private function __getInteractive (stack:Array):Bool { + return false; } diff --git a/openfl/display/DisplayObjectContainer.hx b/openfl/display/DisplayObjectContainer.hx index ce9eb13519..39944a61bb 100644 --- a/openfl/display/DisplayObjectContainer.hx +++ b/openfl/display/DisplayObjectContainer.hx @@ -726,18 +726,38 @@ class DisplayObjectContainer extends InteractiveObject { var length = stack.length; + var interactive = false; + var hitTest = false; + while (--i >= 0) { - if (__children[i].__hitTest (x, y, shapeFlag, stack, interactiveOnly)) { - - stack.insert (length, this); + interactive = __children[i].__getInteractive (null); + + if (interactive || !hitTest) { - return true; + if (__children[i].__hitTest (x, y, shapeFlag, stack, true)) { + + hitTest = true; + + if (interactive) { + + break; + + } + + } } } + if (hitTest) { + + stack.insert (length, this); + return true; + + } + } } else { diff --git a/openfl/display/InteractiveObject.hx b/openfl/display/InteractiveObject.hx index 855142b3cd..30089d4bbf 100644 --- a/openfl/display/InteractiveObject.hx +++ b/openfl/display/InteractiveObject.hx @@ -1161,16 +1161,22 @@ class InteractiveObject extends DisplayObject { } - @:noCompletion private override function __getInteractive (stack:Array):Void { + @:noCompletion private override function __getInteractive (stack:Array):Bool { - stack.push (this); - - if (parent != null) { + if (stack != null) { + + stack.push (this); - parent.__getInteractive (stack); + if (parent != null) { + + parent.__getInteractive (stack); + + } } + return true; + } diff --git a/openfl/display/SimpleButton.hx b/openfl/display/SimpleButton.hx index ea4d491cfe..ecd96a5f6b 100644 --- a/openfl/display/SimpleButton.hx +++ b/openfl/display/SimpleButton.hx @@ -1,6 +1,7 @@ package openfl.display; #if !flash #if !openfl_legacy +import lime.ui.MouseCursor; import openfl.display.DisplayObject; import openfl.display.InteractiveObject; import openfl.events.MouseEvent; @@ -163,6 +164,13 @@ class SimpleButton extends DisplayObjectContainer { } + @:noCompletion private override function __getCursor ():MouseCursor { + + return useHandCursor ? POINTER : null; + + } + + // Getters & Setters diff --git a/openfl/display/Sprite.hx b/openfl/display/Sprite.hx index d1e39f818b..da51ab9c74 100644 --- a/openfl/display/Sprite.hx +++ b/openfl/display/Sprite.hx @@ -1,6 +1,7 @@ package openfl.display; #if !flash #if !openfl_legacy +import lime.ui.MouseCursor; import openfl._internal.renderer.canvas.CanvasGraphics; import openfl._internal.renderer.canvas.CanvasShape; import openfl._internal.renderer.dom.DOMShape; @@ -159,6 +160,13 @@ class Sprite extends DisplayObjectContainer { } + @:noCompletion private override function __getCursor ():MouseCursor { + + return (buttonMode && useHandCursor) ? POINTER : null; + + } + + @:noCompletion private override function __hitTest (x:Float, y:Float, shapeFlag:Bool, stack:Array, interactiveOnly:Bool):Bool { if (!visible || (interactiveOnly && !mouseEnabled)) return false; diff --git a/openfl/display/Stage.hx b/openfl/display/Stage.hx index 944dc9f280..d39eb01655 100644 --- a/openfl/display/Stage.hx +++ b/openfl/display/Stage.hx @@ -1014,9 +1014,15 @@ class Stage extends DisplayObjectContainer implements IModule { } - @:noCompletion private override function __getInteractive (stack:Array):Void { + @:noCompletion private override function __getInteractive (stack:Array):Bool { - stack.push (this); + if (stack != null) { + + stack.push (this); + + } + + return true; } @@ -1138,49 +1144,22 @@ class Stage extends DisplayObjectContainer implements IModule { } - if (Std.is (target, Sprite)) { - - var targetSprite:Sprite = cast target; - - if (targetSprite.buttonMode && targetSprite.useHandCursor) { - - Mouse.cursor = POINTER; - - } else { - - Mouse.cursor = ARROW; - - } - - } else if (Std.is (target, SimpleButton)) { - - var targetButton:SimpleButton = cast target; - - if (targetButton.useHandCursor) { - - Mouse.cursor = POINTER; - - } else { - - Mouse.cursor = ARROW; - - } - - } else if (Std.is (target, TextField)) { + var cursor = null; + + for (target in stack) { - var targetTextField:TextField = cast target; + cursor = target.__getCursor (); - if (targetTextField.type == INPUT) { - - Mouse.cursor = TEXT; - - } else { + if (cursor != null) { - Mouse.cursor = ARROW; + Mouse.cursor = cursor; + break; } - } else { + } + + if (cursor == null) { Mouse.cursor = ARROW; diff --git a/openfl/text/TextField.hx b/openfl/text/TextField.hx index 650162aee4..76026e1f28 100644 --- a/openfl/text/TextField.hx +++ b/openfl/text/TextField.hx @@ -983,6 +983,13 @@ class TextField extends InteractiveObject { } + @:noCompletion private override function __getCursor ():MouseCursor { + + return type == INPUT ? TEXT : null; + + } + + @:noCompletion private function __getFont (format:TextFormat):String { var font = format.italic ? "italic " : "normal "; From 1013f2411bcd989bbd0f25f7fbaa30595a95cc70 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Thu, 16 Apr 2015 16:24:38 -0700 Subject: [PATCH 029/150] Crude wordWrap implementation for canvas TextField --- .../renderer/canvas/CanvasTextField.hx | 51 ++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/openfl/_internal/renderer/canvas/CanvasTextField.hx b/openfl/_internal/renderer/canvas/CanvasTextField.hx index df02edae74..88d94bc28a 100644 --- a/openfl/_internal/renderer/canvas/CanvasTextField.hx +++ b/openfl/_internal/renderer/canvas/CanvasTextField.hx @@ -74,7 +74,55 @@ class CanvasTextField { context.textBaseline = "top"; context.fillStyle = "#" + StringTools.hex (format.color, 6); - var lines = text.split("\n"); + var lines = []; + + if (textField.wordWrap) { + + var words = text.split (" "); + var line = ""; + + var word, newLineIndex, test; + + for (i in 0...words.length) { + + word = words[i]; + newLineIndex = word.indexOf ("\n"); + + if (newLineIndex > -1) { + + lines.push (line + word.substring (0, newLineIndex)); + word = word.substr (newLineIndex + 1); + if (word == "") continue; + + } + + test = line + words[i] + " "; + + if (context.measureText (test).width > textField.__width - 4 && i > 0) { + + lines.push (line); + line = words[i] + " "; + + } else { + + line = test; + + } + + } + + if (line != "") { + + lines.push (line); + + } + + } else { + + lines = text.split ("\n"); + + } + var yOffset:Float = 0; for (line in lines) { @@ -99,6 +147,7 @@ class CanvasTextField { } yOffset += textField.textHeight; + } #end From 9ae3f451edff4498f678fa7e9f8979360b974c3b Mon Sep 17 00:00:00 2001 From: Kane Wallmann Date: Fri, 17 Apr 2015 16:21:27 +1000 Subject: [PATCH 030/150] Updated getRGBAPixels implementation to use copyChannel which is much faster --- openfl/_legacy/display/BitmapData.hx | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/openfl/_legacy/display/BitmapData.hx b/openfl/_legacy/display/BitmapData.hx index 234dc8bbaf..0e287e8071 100644 --- a/openfl/_legacy/display/BitmapData.hx +++ b/openfl/_legacy/display/BitmapData.hx @@ -324,22 +324,17 @@ class BitmapData implements IBitmapDrawable { public inline static function getRGBAPixels (bitmapData:BitmapData):ByteArray { - var data = bitmapData.getPixels (new Rectangle (0, 0, bitmapData.width, bitmapData.height)); - var size = bitmapData.width * bitmapData.height; - var v; + var rgbaData = new BitmapData( bitmapData.width, bitmapData.height, bitmapData.transparent ); - data.position = 0; - - for (i in 0...size) { - - v = data.readInt (); - data.position = i << 2; - data.writeInt ((((v >>> 0) & 0xFF) << 8) | (((v >>> 8) & 0xFF) << 16) | (((v >>> 16) & 0xFF) << 24) | (((v >>> 24) & 0xFF) << 0)); - - } + var rect = new Rectangle( 0, 0, bitmapData.width, bitmapData.height ); + var point = new Point( 0, 0 ); - return data; + rgbaData.copyChannel( bitmapData, rect, point, BitmapDataChannel.GREEN, BitmapDataChannel.RED ); + rgbaData.copyChannel( bitmapData, rect, point, BitmapDataChannel.BLUE, BitmapDataChannel.GREEN ); + rgbaData.copyChannel( bitmapData, rect, point, BitmapDataChannel.ALPHA, BitmapDataChannel.BLUE ); + rgbaData.copyChannel( bitmapData, rect, point, BitmapDataChannel.RED, BitmapDataChannel.ALPHA ); + return rgbaData.getPixels( rect ); } From c2ec769377aa013dfc6dbf5be52c9c8f9e66a6b7 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Fri, 17 Apr 2015 08:35:00 -0700 Subject: [PATCH 031/150] Compile fix --- openfl/_legacy/display/BitmapData.hx | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/openfl/_legacy/display/BitmapData.hx b/openfl/_legacy/display/BitmapData.hx index 0e287e8071..b23496acfb 100644 --- a/openfl/_legacy/display/BitmapData.hx +++ b/openfl/_legacy/display/BitmapData.hx @@ -3,6 +3,7 @@ package openfl._legacy.display; #if openfl_legacy import haxe.io.Bytes; import openfl._legacy.Assets; +import openfl.display.BitmapDataChannel; import openfl.display.JPEGEncoderOptions; import openfl.display.PNGEncoderOptions; import openfl.filters.BitmapFilter; @@ -324,17 +325,18 @@ class BitmapData implements IBitmapDrawable { public inline static function getRGBAPixels (bitmapData:BitmapData):ByteArray { - var rgbaData = new BitmapData( bitmapData.width, bitmapData.height, bitmapData.transparent ); + var rgbaData = new BitmapData (bitmapData.width, bitmapData.height, bitmapData.transparent); - var rect = new Rectangle( 0, 0, bitmapData.width, bitmapData.height ); - var point = new Point( 0, 0 ); + var rect = bitmapData.rect; + var point = new Point (0, 0); - rgbaData.copyChannel( bitmapData, rect, point, BitmapDataChannel.GREEN, BitmapDataChannel.RED ); - rgbaData.copyChannel( bitmapData, rect, point, BitmapDataChannel.BLUE, BitmapDataChannel.GREEN ); - rgbaData.copyChannel( bitmapData, rect, point, BitmapDataChannel.ALPHA, BitmapDataChannel.BLUE ); - rgbaData.copyChannel( bitmapData, rect, point, BitmapDataChannel.RED, BitmapDataChannel.ALPHA ); + rgbaData.copyChannel (bitmapData, rect, point, BitmapDataChannel.GREEN, BitmapDataChannel.RED); + rgbaData.copyChannel (bitmapData, rect, point, BitmapDataChannel.BLUE, BitmapDataChannel.GREEN); + rgbaData.copyChannel (bitmapData, rect, point, BitmapDataChannel.ALPHA, BitmapDataChannel.BLUE); + rgbaData.copyChannel (bitmapData, rect, point, BitmapDataChannel.RED, BitmapDataChannel.ALPHA); + + return rgbaData.getPixels (rect); - return rgbaData.getPixels( rect ); } From 0cab5cd687637080abdb4a6c45b4c7679ae66aa9 Mon Sep 17 00:00:00 2001 From: "Lars A. Doucet" Date: Fri, 17 Apr 2015 11:43:02 -0500 Subject: [PATCH 032/150] TextField: Fixed UTF8 string length crash error --- openfl/text/TextField.hx | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/openfl/text/TextField.hx b/openfl/text/TextField.hx index f0c3f77d58..045e418e71 100644 --- a/openfl/text/TextField.hx +++ b/openfl/text/TextField.hx @@ -1134,7 +1134,7 @@ class TextField extends InteractiveObject { //returns the number of line breaks in the text var lines:Int = 0; - for (i in 0...text.length) { + for (i in 0...Utf8.length(text)) { var char = Utf8.charCodeAt(text, i); if (char == __utf8_endline_code) { lines++; @@ -1148,10 +1148,13 @@ class TextField extends InteractiveObject { //returns the exact character indeces where the line breaks occur var breaks = []; - for (i in 0...text.length) { - var char = Utf8.charCodeAt(text, i); - if (char == __utf8_endline_code) { - breaks.push(i); + + for (i in 0...Utf8.length(text)) { + try{ + var char = Utf8.charCodeAt(text, i); + if (char == __utf8_endline_code) { + breaks.push(i); + } } } return breaks; From 5ead09b0d9f19705899656d3c28ef0c3acdf424f Mon Sep 17 00:00:00 2001 From: Kane Wallmann Date: Fri, 17 Apr 2015 16:21:27 +1000 Subject: [PATCH 033/150] Updated getRGBAPixels implementation to use copyChannel which is much faster --- openfl/_legacy/display/BitmapData.hx | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/openfl/_legacy/display/BitmapData.hx b/openfl/_legacy/display/BitmapData.hx index 234dc8bbaf..0e287e8071 100644 --- a/openfl/_legacy/display/BitmapData.hx +++ b/openfl/_legacy/display/BitmapData.hx @@ -324,22 +324,17 @@ class BitmapData implements IBitmapDrawable { public inline static function getRGBAPixels (bitmapData:BitmapData):ByteArray { - var data = bitmapData.getPixels (new Rectangle (0, 0, bitmapData.width, bitmapData.height)); - var size = bitmapData.width * bitmapData.height; - var v; + var rgbaData = new BitmapData( bitmapData.width, bitmapData.height, bitmapData.transparent ); - data.position = 0; - - for (i in 0...size) { - - v = data.readInt (); - data.position = i << 2; - data.writeInt ((((v >>> 0) & 0xFF) << 8) | (((v >>> 8) & 0xFF) << 16) | (((v >>> 16) & 0xFF) << 24) | (((v >>> 24) & 0xFF) << 0)); - - } + var rect = new Rectangle( 0, 0, bitmapData.width, bitmapData.height ); + var point = new Point( 0, 0 ); - return data; + rgbaData.copyChannel( bitmapData, rect, point, BitmapDataChannel.GREEN, BitmapDataChannel.RED ); + rgbaData.copyChannel( bitmapData, rect, point, BitmapDataChannel.BLUE, BitmapDataChannel.GREEN ); + rgbaData.copyChannel( bitmapData, rect, point, BitmapDataChannel.ALPHA, BitmapDataChannel.BLUE ); + rgbaData.copyChannel( bitmapData, rect, point, BitmapDataChannel.RED, BitmapDataChannel.ALPHA ); + return rgbaData.getPixels( rect ); } From 22f632de99d99d8fbbdd3138e6f6da147fbb7eaa Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Fri, 17 Apr 2015 08:35:00 -0700 Subject: [PATCH 034/150] Compile fix --- openfl/_legacy/display/BitmapData.hx | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/openfl/_legacy/display/BitmapData.hx b/openfl/_legacy/display/BitmapData.hx index 0e287e8071..b23496acfb 100644 --- a/openfl/_legacy/display/BitmapData.hx +++ b/openfl/_legacy/display/BitmapData.hx @@ -3,6 +3,7 @@ package openfl._legacy.display; #if openfl_legacy import haxe.io.Bytes; import openfl._legacy.Assets; +import openfl.display.BitmapDataChannel; import openfl.display.JPEGEncoderOptions; import openfl.display.PNGEncoderOptions; import openfl.filters.BitmapFilter; @@ -324,17 +325,18 @@ class BitmapData implements IBitmapDrawable { public inline static function getRGBAPixels (bitmapData:BitmapData):ByteArray { - var rgbaData = new BitmapData( bitmapData.width, bitmapData.height, bitmapData.transparent ); + var rgbaData = new BitmapData (bitmapData.width, bitmapData.height, bitmapData.transparent); - var rect = new Rectangle( 0, 0, bitmapData.width, bitmapData.height ); - var point = new Point( 0, 0 ); + var rect = bitmapData.rect; + var point = new Point (0, 0); - rgbaData.copyChannel( bitmapData, rect, point, BitmapDataChannel.GREEN, BitmapDataChannel.RED ); - rgbaData.copyChannel( bitmapData, rect, point, BitmapDataChannel.BLUE, BitmapDataChannel.GREEN ); - rgbaData.copyChannel( bitmapData, rect, point, BitmapDataChannel.ALPHA, BitmapDataChannel.BLUE ); - rgbaData.copyChannel( bitmapData, rect, point, BitmapDataChannel.RED, BitmapDataChannel.ALPHA ); + rgbaData.copyChannel (bitmapData, rect, point, BitmapDataChannel.GREEN, BitmapDataChannel.RED); + rgbaData.copyChannel (bitmapData, rect, point, BitmapDataChannel.BLUE, BitmapDataChannel.GREEN); + rgbaData.copyChannel (bitmapData, rect, point, BitmapDataChannel.ALPHA, BitmapDataChannel.BLUE); + rgbaData.copyChannel (bitmapData, rect, point, BitmapDataChannel.RED, BitmapDataChannel.ALPHA); + + return rgbaData.getPixels (rect); - return rgbaData.getPixels( rect ); } From 2ac30d63c14547a6ab6668a6cdd360eb79fde27c Mon Sep 17 00:00:00 2001 From: "Lars A. Doucet" Date: Fri, 17 Apr 2015 11:47:19 -0500 Subject: [PATCH 035/150] TextField: TODO Notification in location that might be crash-prone --- openfl/text/TextField.hx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openfl/text/TextField.hx b/openfl/text/TextField.hx index 045e418e71..01c380c761 100644 --- a/openfl/text/TextField.hx +++ b/openfl/text/TextField.hx @@ -1167,6 +1167,8 @@ class TextField extends InteractiveObject { var lines:Int = 0; if (__ranges.length > i && i >= 0) { var range = __ranges[i]; + + //TODO: this could quite possibly cause crash errors if range indeces are not based on Utf8 character indeces if (range.start > 0 && range.end < text.length) { for (j in range.start...range.end + 1) { var char = Utf8.charCodeAt(text, i); From 9d8112db46f2b84be188bcccc65577cc2acc33c0 Mon Sep 17 00:00:00 2001 From: "Lars A. Doucet" Date: Fri, 17 Apr 2015 13:53:57 -0500 Subject: [PATCH 036/150] Undo y-flip for uv's, add matrix transformation. This ALMOST fixes it, but it's at least as good as what's already there. --- .../renderer/opengl/utils/SpriteBatch.hx | 15 ++---- openfl/display/BitmapData.hx | 52 +++++++++---------- 2 files changed, 30 insertions(+), 37 deletions(-) diff --git a/openfl/_internal/renderer/opengl/utils/SpriteBatch.hx b/openfl/_internal/renderer/opengl/utils/SpriteBatch.hx index 13730ded4c..2f8f08b760 100644 --- a/openfl/_internal/renderer/opengl/utils/SpriteBatch.hx +++ b/openfl/_internal/renderer/opengl/utils/SpriteBatch.hx @@ -321,17 +321,10 @@ class SpriteBatch { matrix.tx = tx * oMatrix.a + ty * oMatrix.c + oMatrix.tx; matrix.ty = tx * oMatrix.b + ty * oMatrix.d + oMatrix.ty; - if (sheet.__bitmap.__uvFlipped) { - uvs.x0 = tileUV.x; uvs.y0 = tileUV.height; - uvs.x1 = tileUV.width; uvs.y1 = tileUV.height; - uvs.x2 = tileUV.width; uvs.y2 = tileUV.y; - uvs.x3 = tileUV.x; uvs.y3 = tileUV.y; - } else { - uvs.x0 = tileUV.x; uvs.y0 = tileUV.y; - uvs.x1 = tileUV.width; uvs.y1 = tileUV.y; - uvs.x2 = tileUV.width; uvs.y2 = tileUV.height; - uvs.x3 = tileUV.x; uvs.y3 = tileUV.height; - } + uvs.x0 = tileUV.x; uvs.y0 = tileUV.y; + uvs.x1 = tileUV.width; uvs.y1 = tileUV.y; + uvs.x2 = tileUV.width; uvs.y2 = tileUV.height; + uvs.x3 = tileUV.x; uvs.y3 = tileUV.height; bIndex = batchedSprites * 4 * elementsPerVertex; diff --git a/openfl/display/BitmapData.hx b/openfl/display/BitmapData.hx index d231241560..87e234a68d 100644 --- a/openfl/display/BitmapData.hx +++ b/openfl/display/BitmapData.hx @@ -142,7 +142,6 @@ class BitmapData implements IBitmapDrawable { @:noCompletion private var __textureImage:Image; @:noCompletion private var __framebuffer:FilterTexture; @:noCompletion private var __uvData:TextureUvs; - @:noCompletion private var __uvFlipped:Bool = false; private var __spritebatch:SpriteBatch; @@ -611,7 +610,22 @@ class BitmapData implements IBitmapDrawable { var matrixCache = source.__worldTransform; var blendModeCache = source.blendMode; - source.__worldTransform = matrix != null ? matrix : new Matrix (); + if (matrix == null) { + matrix = new Matrix(); + } + + //GL has inverted y coordinate space, we need to flip, but we also have to preserve transformations + var tx = matrix.tx; + var ty = matrix.ty; + + matrix.tx = 0; + matrix.ty = 0; + matrix.scale(1, -1); + matrix.translate(0, height); + matrix.tx += tx; + matrix.ty -= ty; //this is negative because y has been flipped! + + source.__worldTransform = matrix; source.__worldColorTransform = colorTransform != null ? colorTransform : new ColorTransform(); source.blendMode = blendMode; source.__updateChildren (false); @@ -639,9 +653,8 @@ class BitmapData implements IBitmapDrawable { __texture = __framebuffer.texture; __image.dirty = false; - __createUVs(true); - + __createUVs(); default: @@ -1560,31 +1573,18 @@ class BitmapData implements IBitmapDrawable { } - @:noCompletion private function __createUVs (?verticalFlip:Bool = false):Void { + @:noCompletion private function __createUVs ():Void { if (__uvData == null) __uvData = new TextureUvs(); - __uvFlipped = verticalFlip; - - if (verticalFlip) { - __uvData.x0 = 0; - __uvData.y0 = 1; - __uvData.x1 = 1; - __uvData.y1 = 1; - __uvData.x2 = 1; - __uvData.y2 = 0; - __uvData.x3 = 0; - __uvData.y3 = 0; - } else { - __uvData.x0 = 0; - __uvData.y0 = 0; - __uvData.x1 = 1; - __uvData.y1 = 0; - __uvData.x2 = 1; - __uvData.y2 = 1; - __uvData.x3 = 0; - __uvData.y3 = 1; - } + __uvData.x0 = 0; + __uvData.y0 = 0; + __uvData.x1 = 1; + __uvData.y1 = 0; + __uvData.x2 = 1; + __uvData.y2 = 1; + __uvData.x3 = 0; + __uvData.y3 = 1; } From cdedae52739744f26dc25f3d53be0a4931139a53 Mon Sep 17 00:00:00 2001 From: "Lars A. Doucet" Date: Fri, 17 Apr 2015 14:42:17 -0500 Subject: [PATCH 037/150] BitmapData.draw(): the matrix has to be inverted before AND after the drawing is done! --- openfl/display/BitmapData.hx | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/openfl/display/BitmapData.hx b/openfl/display/BitmapData.hx index 87e234a68d..b97ef2a0db 100644 --- a/openfl/display/BitmapData.hx +++ b/openfl/display/BitmapData.hx @@ -614,16 +614,7 @@ class BitmapData implements IBitmapDrawable { matrix = new Matrix(); } - //GL has inverted y coordinate space, we need to flip, but we also have to preserve transformations - var tx = matrix.tx; - var ty = matrix.ty; - - matrix.tx = 0; - matrix.ty = 0; - matrix.scale(1, -1); - matrix.translate(0, height); - matrix.tx += tx; - matrix.ty -= ty; //this is negative because y has been flipped! + invertMatrix(matrix); source.__worldTransform = matrix; source.__worldColorTransform = colorTransform != null ? colorTransform : new ColorTransform(); @@ -656,6 +647,8 @@ class BitmapData implements IBitmapDrawable { __createUVs(); + invertMatrix(matrix); + default: // TODO @@ -665,6 +658,19 @@ class BitmapData implements IBitmapDrawable { } + private function invertMatrix(matrix:Matrix):Void + { + var tx = matrix.tx; + var ty = matrix.ty; + + matrix.tx = 0; + matrix.ty = 0; + matrix.scale(1, -1); + matrix.translate(0, height); + matrix.tx += tx; + matrix.ty -= ty; + } + public function encode (rect:Rectangle, compressor:Dynamic, byteArray:ByteArray = null):ByteArray { // TODO: Support rect From 7dd754297514d67e7b78fd9ace8683ab64e7ca18 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Fri, 17 Apr 2015 12:51:36 -0700 Subject: [PATCH 038/150] Fix start time for Sound --- openfl/media/Sound.hx | 4 +++- openfl/media/SoundChannel.hx | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/openfl/media/Sound.hx b/openfl/media/Sound.hx index bb8182ca0a..23bd0e9c70 100644 --- a/openfl/media/Sound.hx +++ b/openfl/media/Sound.hx @@ -431,11 +431,13 @@ class Sound extends EventDispatcher { #if !html5 var source = new AudioSource (__buffer); + source.offset = Std.int (startTime * 1000); + if (loops > 1) source.loops = loops - 1; return new SoundChannel (source); #else var instance = if (loops > 1) - SoundJS.play (__soundID, SoundJS.INTERRUPT_ANY, 0, Std.int (startTime), loops-1, sndTransform.volume, sndTransform.pan); + SoundJS.play (__soundID, SoundJS.INTERRUPT_ANY, 0, Std.int (startTime), loops - 1, sndTransform.volume, sndTransform.pan); else SoundJS.play (__soundID, SoundJS.INTERRUPT_ANY, 0, Std.int (startTime), 0, sndTransform.volume, sndTransform.pan); diff --git a/openfl/media/SoundChannel.hx b/openfl/media/SoundChannel.hx index 98953fb624..409b80d3eb 100644 --- a/openfl/media/SoundChannel.hx +++ b/openfl/media/SoundChannel.hx @@ -137,7 +137,7 @@ class SoundChannel extends EventDispatcher { if (!__isValid) return 0; #if !html5 - return __source.timeOffset / 1000; + return (__source.currentTime + __source.offset) / 1000; #else return __soundInstance.getPosition (); #end @@ -150,7 +150,7 @@ class SoundChannel extends EventDispatcher { if (!__isValid) return 0; #if !html5 - __source.timeOffset = Std.int (value * 1000); + __source.currentTime = Std.int (value * 1000) - __source.offset; return value; #else __soundInstance.setPosition (Std.int (value)); From fe1cd7d39345748384f8c38d642d1b2911505653 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Fri, 17 Apr 2015 13:02:05 -0700 Subject: [PATCH 039/150] Add stub for event.preventDefault --- openfl/events/Event.hx | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/openfl/events/Event.hx b/openfl/events/Event.hx index c87c5201f5..11eca7e27e 100644 --- a/openfl/events/Event.hx +++ b/openfl/events/Event.hx @@ -413,6 +413,19 @@ class Event { } + /** + * Cancels an event's default behavior if that behavior can be canceled. + * Many events have associated behaviors that are carried out by default. For example, if a user types a character into a text field, the default behavior is that the character is displayed in the text field. Because the TextEvent.TEXT_INPUT event's default behavior can be canceled, you can use the preventDefault() method to prevent the character from appearing. + * An example of a behavior that is not cancelable is the default behavior associated with the Event.REMOVED event, which is generated whenever Flash Player is about to remove a display object from the display list. The default behavior (removing the element) cannot be canceled, so the preventDefault() method has no effect on this default behavior. + * You can use the Event.cancelable property to check whether you can prevent the default behavior associated with a particular event. If the value of Event.cancelable is true, then preventDefault() can be used to cancel the event; otherwise, preventDefault() has no effect. + */ + public function preventDefault ():Void { + + __isCancelled = true; + + } + + /** * Prevents processing of any event listeners in the current node and any * subsequent nodes in the event flow. This method takes effect immediately, From 7730918adccebe53de91362832c9d70abe0984ed Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Fri, 17 Apr 2015 14:20:35 -0700 Subject: [PATCH 040/150] Improve caching for GLTextField --- .../_internal/renderer/opengl/GLTextField.hx | 47 ++++++++++++++----- openfl/text/TextField.hx | 1 + 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/openfl/_internal/renderer/opengl/GLTextField.hx b/openfl/_internal/renderer/opengl/GLTextField.hx index 7c480f0f60..d37c39585e 100644 --- a/openfl/_internal/renderer/opengl/GLTextField.hx +++ b/openfl/_internal/renderer/opengl/GLTextField.hx @@ -68,7 +68,7 @@ class GLTextField { for (i in 0...textField.__tilesheets.length) { - graphics.drawTiles (textField.__tilesheets[i], textField.__tileData[i], true, Tilesheet.TILE_RGB); + graphics.drawTiles (textField.__tilesheets[i], textField.__tileData[i], true, Tilesheet.TILE_RGB, textField.__tileDataLength[i]); } @@ -187,6 +187,7 @@ class GLTextField { textField.__tilesheets.push (tilesheet); textField.__tileData.push (tileData); + textField.__tileDataLength.push (0); } else { @@ -204,19 +205,20 @@ class GLTextField { } var textLayout:TextLayout = textField.__textLayout; + var length = 0; var line_i:Int = 0; - var oldX = x; for (line in lines) { - tlm = textField.getLineMetrics(line_i); + tlm = textField.getLineMetrics (line_i); //x position must be reset every line and recalculated x = oldX; - x += switch(format.align) { + x += switch (format.align) { + case LEFT, JUSTIFY: 0; //the renderer has already positioned the text at the right spot past the 2px left margin case CENTER: ((textField.__width - 4) - tlm.width) / 2; //subtract 4 from textfield.__width because __width includes the 2px margin on both sides, which doesn't count case RIGHT: ((textField.__width - 4) - tlm.width); //same thing here @@ -234,24 +236,42 @@ class GLTextField { if (image != null) { - tileData.push (x + position.offset.x + image.x); - tileData.push (y + position.offset.y - image.y); - tileData.push (tileID.get (position.glyph)); - tileData.push (r); - tileData.push (g); - tileData.push (b); + if (length >= tileData.length) { + + tileData.push (x + position.offset.x + image.x); + tileData.push (y + position.offset.y - image.y); + tileData.push (tileID.get (position.glyph)); + tileData.push (r); + tileData.push (g); + tileData.push (b); + + } else { + + tileData[length] = x + position.offset.x + image.x; + tileData[length + 1] = y + position.offset.y - image.y; + tileData[length + 2] = tileID.get (position.glyph); + tileData[length + 3] = r; + tileData[length + 4] = g; + tileData[length + 5] = b; + + } + + length += 6; } x += position.advance.x; y -= position.advance.y; + } y += tlm.height; //always add the line height at the end - line_i++; + } + textField.__tileDataLength[textField.__tileDataLength.length - 1] = length; + } } @@ -269,12 +289,13 @@ class GLTextField { } else { - //if (textField.__tilesheets == null) { + if (textField.__tilesheets == null) { textField.__tilesheets = new Array (); textField.__tileData = new Array (); + textField.__tileDataLength = new Array (); - //} + } if (textField.__text != null && textField.__text != "") { diff --git a/openfl/text/TextField.hx b/openfl/text/TextField.hx index 01c380c761..f9ac3cfea4 100644 --- a/openfl/text/TextField.hx +++ b/openfl/text/TextField.hx @@ -575,6 +575,7 @@ class TextField extends InteractiveObject { @:noCompletion private var __textLayout:TextLayout; @:noCompletion private var __texture:GLTexture; @:noCompletion private var __tileData:Array>; + @:noCompletion private var __tileDataLength:Array; @:noCompletion private var __tilesheets:Array; @:noCompletion private var __width:Float; From 37e9bc94dd376f370e2047fb9ab322960d6c5929 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Fri, 17 Apr 2015 14:59:56 -0700 Subject: [PATCH 041/150] Fix 'drawSelf' behavior in bitmapData.draw for now (in GL)? (fixes #608) --- openfl/display/BitmapData.hx | 1 + 1 file changed, 1 insertion(+) diff --git a/openfl/display/BitmapData.hx b/openfl/display/BitmapData.hx index b97ef2a0db..e591912c1a 100644 --- a/openfl/display/BitmapData.hx +++ b/openfl/display/BitmapData.hx @@ -629,6 +629,7 @@ class BitmapData implements IBitmapDrawable { source.__updateChildren (true); __spritebatch.finish(); + __spritebatch = null; gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, __image.buffer.data); From 1eed880f14b5245fd25ce7ac342faac15a73fac5 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Fri, 17 Apr 2015 15:01:14 -0700 Subject: [PATCH 042/150] Try it this way instead --- openfl/display/BitmapData.hx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openfl/display/BitmapData.hx b/openfl/display/BitmapData.hx index e591912c1a..1428bb194d 100644 --- a/openfl/display/BitmapData.hx +++ b/openfl/display/BitmapData.hx @@ -574,6 +574,7 @@ class BitmapData implements IBitmapDrawable { tmpRect.y = height - tmpRect.bottom; var drawSelf = false; + //var drawSelf = true; if (__spritebatch == null) { __spritebatch = new SpriteBatch(gl); drawSelf = true; @@ -629,7 +630,7 @@ class BitmapData implements IBitmapDrawable { source.__updateChildren (true); __spritebatch.finish(); - __spritebatch = null; + //__spritebatch = null; gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, __image.buffer.data); From 0de34ec9e5b440ba875a809188d3184c2319b7d4 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Fri, 17 Apr 2015 15:29:27 -0700 Subject: [PATCH 043/150] Quick fix for the GLTextField tileData cache for now --- .../_internal/renderer/opengl/GLTextField.hx | 45 ++++++++++++------- openfl/text/TextField.hx | 6 +-- 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/openfl/_internal/renderer/opengl/GLTextField.hx b/openfl/_internal/renderer/opengl/GLTextField.hx index d37c39585e..9820131bfb 100644 --- a/openfl/_internal/renderer/opengl/GLTextField.hx +++ b/openfl/_internal/renderer/opengl/GLTextField.hx @@ -64,11 +64,11 @@ class GLTextField { } - if (textField.__tilesheets != null) { + if (textField.__tileData != null) { - for (i in 0...textField.__tilesheets.length) { + for (tilesheet in textField.__tilesheets.keys ()) { - graphics.drawTiles (textField.__tilesheets[i], textField.__tileData[i], true, Tilesheet.TILE_RGB, textField.__tileDataLength[i]); + graphics.drawTiles (tilesheet, textField.__tileData.get (tilesheet), true, Tilesheet.TILE_RGB, textField.__tileDataLength.get (tilesheet)); } @@ -181,20 +181,18 @@ class GLTextField { var tileData; - if (textField.__tilesheets.length == 0 || textField.__tilesheets[textField.__tilesheets.length - 1] != tilesheet) { + textField.__tilesheets.set (tilesheet, true); + + if (!textField.__tileData.exists (tilesheet)) { tileData = new Array (); - - textField.__tilesheets.push (tilesheet); - textField.__tileData.push (tileData); - textField.__tileDataLength.push (0); - - } else { - - tileData = textField.__tileData[textField.__tileData.length - 1]; + textField.__tileData.set (tilesheet, tileData); + textField.__tileDataLength.set (tilesheet, 0); } + tileData = textField.__tileData.get (tilesheet); + var offsetY = 0; var lines = text.split ("\n"); @@ -270,7 +268,7 @@ class GLTextField { } - textField.__tileDataLength[textField.__tileDataLength.length - 1] = length; + textField.__tileDataLength.set (tilesheet, length); } @@ -285,15 +283,17 @@ class GLTextField { textField.__tilesheets = null; textField.__tileData = null; + textField.__tileDataLength = null; textField.__dirty = false; } else { - if (textField.__tilesheets == null) { + textField.__tilesheets = new Map (); + + if (textField.__tileData == null) { - textField.__tilesheets = new Array (); - textField.__tileData = new Array (); - textField.__tileDataLength = new Array (); + textField.__tileData = new Map (); + textField.__tileDataLength = new Map (); } @@ -364,6 +364,17 @@ class GLTextField { } + for (key in textField.__tileData.keys ()) { + + if (!textField.__tilesheets.exists (key)) { + + textField.__tileData.remove (key); + textField.__tileDataLength.remove (key); + + } + + } + textField.__dirty = false; return true; diff --git a/openfl/text/TextField.hx b/openfl/text/TextField.hx index f9ac3cfea4..d15ef2b596 100644 --- a/openfl/text/TextField.hx +++ b/openfl/text/TextField.hx @@ -574,9 +574,9 @@ class TextField extends InteractiveObject { @:noCompletion private var __textFormat:TextFormat; @:noCompletion private var __textLayout:TextLayout; @:noCompletion private var __texture:GLTexture; - @:noCompletion private var __tileData:Array>; - @:noCompletion private var __tileDataLength:Array; - @:noCompletion private var __tilesheets:Array; + @:noCompletion private var __tileData:Map>; + @:noCompletion private var __tileDataLength:Map; + @:noCompletion private var __tilesheets:Map; @:noCompletion private var __width:Float; @:noCompletion private static var __utf8_endline_code:Int = 10; From 727e0e1be3bf734999df103c31b787a94c6abea6 Mon Sep 17 00:00:00 2001 From: Fernando Serboncini Date: Sat, 18 Apr 2015 11:49:59 -0400 Subject: [PATCH 044/150] Add missing import --- openfl/display/BitmapData.hx | 1 + 1 file changed, 1 insertion(+) diff --git a/openfl/display/BitmapData.hx b/openfl/display/BitmapData.hx index d4c2faf9d0..c3ec9b661c 100644 --- a/openfl/display/BitmapData.hx +++ b/openfl/display/BitmapData.hx @@ -5,6 +5,7 @@ import lime.graphics.opengl.GLBuffer; import lime.graphics.opengl.GLTexture; import lime.graphics.GLRenderContext; import lime.graphics.Image; +import lime.graphics.ImageChannel; import lime.graphics.ImageBuffer; import lime.graphics.utils.ImageCanvasUtil; import lime.math.ColorMatrix; From 29c7a9705d0aafd9450a03d2aefeaa550aa6aad3 Mon Sep 17 00:00:00 2001 From: Nick Date: Sun, 19 Apr 2015 22:23:28 -0400 Subject: [PATCH 045/150] Recursive DisplayObjectContainer.contains() Original flash method is recursive. --- openfl/display/DisplayObjectContainer.hx | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/openfl/display/DisplayObjectContainer.hx b/openfl/display/DisplayObjectContainer.hx index 39944a61bb..281a521377 100644 --- a/openfl/display/DisplayObjectContainer.hx +++ b/openfl/display/DisplayObjectContainer.hx @@ -287,21 +287,13 @@ class DisplayObjectContainer extends InteractiveObject { */ public function contains (child:DisplayObject):Bool { - #if (haxe_ver > 3.100) - - return __children.indexOf (child) > -1; - - #else - - for (i in __children) { + while (child != this && child != null) { - if (i == child) return true; + child = child.parent; } - return false; - - #end + return child == this; } @@ -1015,4 +1007,4 @@ typedef DisplayObjectContainer = openfl._legacy.display.DisplayObjectContainer; #end #else typedef DisplayObjectContainer = flash.display.DisplayObjectContainer; -#end \ No newline at end of file +#end From 8971cad6c303c4682aca34bac8de480b066cda61 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Mon, 20 Apr 2015 06:25:10 -0700 Subject: [PATCH 046/150] Compile fix --- openfl/_legacy/utils/SystemPath.hx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openfl/_legacy/utils/SystemPath.hx b/openfl/_legacy/utils/SystemPath.hx index fa425da300..641a91a28d 100644 --- a/openfl/_legacy/utils/SystemPath.hx +++ b/openfl/_legacy/utils/SystemPath.hx @@ -58,7 +58,7 @@ class SystemPath { #if lime_hybrid - switch (which) { + switch (inWhich) { case APP: return System.applicationDirectory; case STORAGE: return System.applicationStorageDirectory; @@ -89,4 +89,4 @@ class SystemPath { } -#end \ No newline at end of file +#end From fc44ffdf06b64490ebd2428cfce5a97db5914c85 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Mon, 20 Apr 2015 06:51:45 -0700 Subject: [PATCH 047/150] Improve .contains test --- tests/test/openfl/display/DisplayObjectContainerTest.hx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/test/openfl/display/DisplayObjectContainerTest.hx b/tests/test/openfl/display/DisplayObjectContainerTest.hx index 75dd40ecb2..fb79f4a612 100644 --- a/tests/test/openfl/display/DisplayObjectContainerTest.hx +++ b/tests/test/openfl/display/DisplayObjectContainerTest.hx @@ -145,6 +145,7 @@ class DisplayObjectContainerTest { var sprite = new Sprite (); var sprite2 = new Sprite (); + Assert.isTrue (sprite.contains (sprite)); Assert.isFalse (sprite.contains (sprite2)); sprite.addChild (sprite2); @@ -152,16 +153,22 @@ class DisplayObjectContainerTest { Assert.isTrue (sprite.contains (sprite2)); var sprite3 = new Sprite (); + var sprite4 = new Sprite (); + sprite3.addChild (sprite4); sprite.addChild (sprite3); Assert.isTrue (sprite.contains (sprite3)); + Assert.isTrue (sprite.contains (sprite4)); + Assert.isFalse (sprite3.contains (sprite)); + Assert.isFalse (sprite4.contains (sprite)); sprite.removeChild (sprite3); sprite.removeChild (sprite2); Assert.isFalse (sprite.contains (sprite2)); Assert.isFalse (sprite.contains (sprite3)); + Assert.isFalse (sprite.contains (sprite4)); } From 8a404efbafc78bfc358048ac18d3b51fd55a94c3 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Tue, 21 Apr 2015 00:28:38 -0700 Subject: [PATCH 048/150] Improve consistency of leading --- openfl/text/TextField.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openfl/text/TextField.hx b/openfl/text/TextField.hx index d15ef2b596..361089fd11 100644 --- a/openfl/text/TextField.hx +++ b/openfl/text/TextField.hx @@ -1009,7 +1009,7 @@ class TextField extends InteractiveObject { font += "normal "; font += format.bold ? "bold " : "normal "; font += format.size + "px"; - font += "/" + (format.size + format.leading + 4) + "px "; + font += "/" + (format.size + format.leading) + "px "; font += "'" + switch (format.font) { From 5e8e398dc8d74319dfc3c179c95b4caf8b2ac1cd Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Tue, 21 Apr 2015 11:13:29 -0700 Subject: [PATCH 049/150] Set stage focus on MOUSE_DOWN, improve TextField input to use focus events better --- openfl/display/Stage.hx | 6 ++++ openfl/text/TextField.hx | 61 +++++++++++++++++++++++++--------------- 2 files changed, 45 insertions(+), 22 deletions(-) diff --git a/openfl/display/Stage.hx b/openfl/display/Stage.hx index d39eb01655..80f011f35d 100644 --- a/openfl/display/Stage.hx +++ b/openfl/display/Stage.hx @@ -1111,6 +1111,12 @@ class Stage extends DisplayObjectContainer implements IModule { } + if (type == MouseEvent.MOUSE_DOWN) { + + focus = target; + + } + __fireEvent (MouseEvent.__create (type, button, __mouseX, __mouseY, (target == this ? targetPoint : target.globalToLocal (targetPoint)), target), stack); var clickType = switch (type) { diff --git a/openfl/text/TextField.hx b/openfl/text/TextField.hx index 361089fd11..dd9c7bf0bf 100644 --- a/openfl/text/TextField.hx +++ b/openfl/text/TextField.hx @@ -1688,17 +1688,6 @@ class TextField extends InteractiveObject { } - @:noCompletion private function stage_onFocusOut (event:Event):Void { - - __cursorPosition = -1; - __hasFocus = false; - __stopCursorTimer (); - __hiddenInput.blur (); - __dirty = true; - - } - - @:noCompletion private function stage_onMouseMove (event:MouseEvent) { if (__hasFocus && __selectionStart >= 0) { @@ -1724,9 +1713,36 @@ class TextField extends InteractiveObject { __cursorPosition = rightPos; stage.removeEventListener (MouseEvent.MOUSE_MOVE, stage_onMouseMove); - stage.addEventListener (MouseEvent.MOUSE_UP, stage_onMouseUp); + stage.removeEventListener (MouseEvent.MOUSE_UP, stage_onMouseUp); + + //stage.focus = this; + if (stage.focus == this) + this_onFocusIn (null); - stage.focus = this; + } + + + @:noCompletion private function this_onAddedToStage (event:Event):Void { + + addEventListener (FocusEvent.FOCUS_IN, this_onFocusIn); + addEventListener (FocusEvent.FOCUS_OUT, this_onFocusOut); + + __hiddenInput.addEventListener ('keydown', input_onKeyDown); + __hiddenInput.addEventListener ('keyup', input_onKeyUp); + __hiddenInput.addEventListener ('input', input_onKeyUp); + + addEventListener (MouseEvent.MOUSE_DOWN, this_onMouseDown); + + if (stage.focus == this) { + + this_onFocusIn (null); + + } + + } + + + @:noCompletion private function this_onFocusIn (event:Event):Void { if (__cursorPosition < 0) { @@ -1745,18 +1761,18 @@ class TextField extends InteractiveObject { __hasFocus = true; __dirty = true; + stage.addEventListener (MouseEvent.MOUSE_UP, stage_onMouseUp); + } - @:noCompletion private function this_onAddedToStage (event:Event):Void { + @:noCompletion private function this_onFocusOut (event:Event):Void { - stage.addEventListener (FocusEvent.FOCUS_OUT, stage_onFocusOut); - - __hiddenInput.addEventListener ('keydown', input_onKeyDown); - __hiddenInput.addEventListener ('keyup', input_onKeyUp); - __hiddenInput.addEventListener ('input', input_onKeyUp); - - addEventListener (MouseEvent.MOUSE_DOWN, this_onMouseDown); + __cursorPosition = -1; + __hasFocus = false; + __stopCursorTimer (); + __hiddenInput.blur (); + __dirty = true; } @@ -1773,7 +1789,8 @@ class TextField extends InteractiveObject { @:noCompletion private function this_onRemovedFromStage (event:Event):Void { - if (stage != null) stage.removeEventListener (FocusEvent.FOCUS_OUT, stage_onFocusOut); + removeEventListener (FocusEvent.FOCUS_IN, this_onFocusIn); + removeEventListener (FocusEvent.FOCUS_OUT, this_onFocusOut); if (__hiddenInput != null) __hiddenInput.removeEventListener ('keydown', input_onKeyDown); if (__hiddenInput != null) __hiddenInput.removeEventListener ('keyup', input_onKeyUp); From c7336dca5617bcd763ccd50c802457c69ab775c4 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Tue, 21 Apr 2015 11:16:51 -0700 Subject: [PATCH 050/150] Minor change --- openfl/text/TextField.hx | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/openfl/text/TextField.hx b/openfl/text/TextField.hx index dd9c7bf0bf..6d60cfe760 100644 --- a/openfl/text/TextField.hx +++ b/openfl/text/TextField.hx @@ -1702,22 +1702,24 @@ class TextField extends InteractiveObject { @:noCompletion private function stage_onMouseUp (event:MouseEvent):Void { - var upPos:Int = __getPosition (event.localX, event.localY); - var leftPos:Int; - var rightPos:Int; - - leftPos = Std.int (Math.min (__selectionStart, upPos)); - rightPos = Std.int (Math.max (__selectionStart, upPos)); - - __selectionStart = leftPos; - __cursorPosition = rightPos; - stage.removeEventListener (MouseEvent.MOUSE_MOVE, stage_onMouseMove); stage.removeEventListener (MouseEvent.MOUSE_UP, stage_onMouseUp); - //stage.focus = this; - if (stage.focus == this) + if (stage.focus == this) { + + var upPos:Int = __getPosition (event.localX, event.localY); + var leftPos:Int; + var rightPos:Int; + + leftPos = Std.int (Math.min (__selectionStart, upPos)); + rightPos = Std.int (Math.max (__selectionStart, upPos)); + + __selectionStart = leftPos; + __cursorPosition = rightPos; + this_onFocusIn (null); + + } } From 56e998471ed495f3b78a57ee1ff154235b071a4c Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Tue, 21 Apr 2015 12:08:43 -0700 Subject: [PATCH 051/150] Fix newline + wordWrap in canvas textfield --- .../renderer/canvas/CanvasTextField.hx | 49 ++++++++++++++----- 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/openfl/_internal/renderer/canvas/CanvasTextField.hx b/openfl/_internal/renderer/canvas/CanvasTextField.hx index 88d94bc28a..fae569a22e 100644 --- a/openfl/_internal/renderer/canvas/CanvasTextField.hx +++ b/openfl/_internal/renderer/canvas/CanvasTextField.hx @@ -90,22 +90,47 @@ class CanvasTextField { if (newLineIndex > -1) { - lines.push (line + word.substring (0, newLineIndex)); - word = word.substr (newLineIndex + 1); - if (word == "") continue; - - } - - test = line + words[i] + " "; - - if (context.measureText (test).width > textField.__width - 4 && i > 0) { + while (newLineIndex > -1) { + + test = line + word.substring (0, newLineIndex) + " "; + + if (context.measureText (test).width > textField.__width - 4 && i > 0) { + + lines.push (line); + lines.push (word.substring (0, newLineIndex) + " "); + + } else { + + lines.push (line + word.substring (0, newLineIndex) + " "); + + } + + word = word.substr (newLineIndex + 1); + newLineIndex = word.indexOf ("\n"); + line = ""; + + } - lines.push (line); - line = words[i] + " "; + if (word != "") { + + line = word + " "; + + } } else { - line = test; + test = line + words[i] + " "; + + if (context.measureText (test).width > textField.__width - 4 && i > 0) { + + lines.push (line); + line = words[i] + " "; + + } else { + + line = test; + + } } From 4a80391086cbc3c137e96c5f38138e3145d25324 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Tue, 21 Apr 2015 12:32:54 -0700 Subject: [PATCH 052/150] Update to 3.0.3 --- haxelib.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/haxelib.json b/haxelib.json index bf5539fdfd..c2c927b83c 100644 --- a/haxelib.json +++ b/haxelib.json @@ -4,7 +4,7 @@ "license": "MIT", "tags": [], "description": "The \"Open Flash Library\" for fast 2D development", - "version": "3.0.2", - "releasenote": "Improvements to keyboard, TextField, and other fixes", + "version": "3.0.3", + "releasenote": "Improvements to text, sound, bitmapData.draw", "contributors": [ "singmajesty" ] } From 90e6d676e0ab6803d145cecfe4901baa6bc075dc Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Tue, 21 Apr 2015 12:33:00 -0700 Subject: [PATCH 053/150] Update CHANGELOG --- CHANGELOG.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f0a65fc30..2d0ef3891f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,18 @@ +3.0.3 (04/21/2015) +------------------ + +* Improved hit test when there are interactive and non-interactive matches +* Improved accuracy of text metrics +* Improved accuracy of GL TextField glyph positioning +* Added wordWrap support to canvas TextField +* Added handling of stage.focus on mouse down +* Fixed the start time and loop count for native sounds +* Fixed the behavior of sprite.contains to loop recursively +* Fixed upside-down BitmapData in some cases when using GL bitmapData.draw +* Fixed layering of GL bitmapData.draw over existing BitmapData contents +* Improved performance of getRGBAPixels (legacy) + + 3.0.2 (04/15/2015) ------------------ From 6674c0a6eca01d5d7b2b84287597759aedfbbf82 Mon Sep 17 00:00:00 2001 From: James Gray Date: Tue, 21 Apr 2015 16:04:36 -0500 Subject: [PATCH 054/150] pull out GLTextField to a shared class Allows other renderers to make use of the same TextField code. --- .../_internal/renderer/TextFieldGraphics.hx | 384 ++++++++++++++++++ .../_internal/renderer/opengl/GLTextField.hx | 371 +---------------- 2 files changed, 387 insertions(+), 368 deletions(-) create mode 100644 openfl/_internal/renderer/TextFieldGraphics.hx diff --git a/openfl/_internal/renderer/TextFieldGraphics.hx b/openfl/_internal/renderer/TextFieldGraphics.hx new file mode 100644 index 0000000000..8db323e6b5 --- /dev/null +++ b/openfl/_internal/renderer/TextFieldGraphics.hx @@ -0,0 +1,384 @@ +package openfl._internal.renderer; + + +//import haxe.Utf8; +import lime.graphics.Image; +import lime.text.Glyph; +import lime.text.TextLayout; +import openfl._internal.renderer.RenderSession; +import openfl.display.BitmapData; +import openfl.display.Graphics; +import openfl.display.Tilesheet; +import openfl.geom.Point; +import openfl.geom.Rectangle; +import openfl.text.Font; +import openfl.text.TextField; +import openfl.text.TextFieldAutoSize; +import openfl.text.TextFormat; +import openfl.text.TextFormatAlign; + +@:access(openfl.text.TextField) + + +class TextFieldGraphics { + + + private static var bitmapData = new Map> (); + private static var glyphs = new Map>> (); + private static var tilesheets = new Map (); + private static var tileIDs = new Map> (); + + + public static function render (textField:TextField, renderSession:RenderSession) { + + update (textField); + + if (textField.__graphics == null) { + + textField.__graphics = new Graphics (); + + } + + var graphics = textField.__graphics; + graphics.clear (); + + if (textField.border || textField.background) { + + if (textField.border) { + + graphics.lineStyle (1, textField.borderColor); + + } + + if (textField.background) { + + graphics.beginFill (textField.backgroundColor); + + } + + graphics.drawRect (0.5, 0.5, textField.__width - 1, textField.__height - 1); + + } + + if (textField.__tileData != null) { + + for (tilesheet in textField.__tilesheets.keys ()) { + + graphics.drawTiles (tilesheet, textField.__tileData.get (tilesheet), true, Tilesheet.TILE_RGB, textField.__tileDataLength.get (tilesheet)); + + } + + } + + } + + + private static inline function renderText (textField:TextField, text:String, format:TextFormat, offsetX:Float, textWidth:Float):Void { + + var font = textField.__getFontInstance (format); + + if (font != null && format.size != null) { + + if (!glyphs.exists (font)) { + + glyphs.set (font, new Map ()); + + } + + var size = Std.int (format.size); + var fontGlyphs = glyphs.get (font); + + if (!fontGlyphs.exists (size)) { + + fontGlyphs.set (size, font.renderGlyphs (font.getGlyphs (), size)); + + } + + var images = fontGlyphs.get (size); + + if (!bitmapData.exists (font)) { + + bitmapData.set (font, new Map ()); + + } + + var fontBitmapData = bitmapData.get (font); + + if (!fontBitmapData.exists (size)) { + + var width, height, data; + + for (image in images) { + + width = image.buffer.width; + height = image.buffer.height; + data = image.data; + break; + + } + + var bitmapData = new BitmapData (width, height); + + for (x in 0...width) { + + for (y in 0...height) { + + var alpha = data[(y * width) + x]; + var color = alpha << 24 | 0xFF << 16 | 0xFF << 8 | 0xFF; + bitmapData.setPixel32 (x, y, color); + + } + + } + + fontBitmapData.set (size, bitmapData); + + } + + var bitmapData = fontBitmapData.get (size); + + if (!tilesheets.exists (bitmapData)) { + + var tilesheet = new Tilesheet (bitmapData); + var tileID = new Map (); + + var image, index; + + for (key in images.keys ()) { + + image = images.get (key); + index = tilesheet.addTileRect (new Rectangle (image.offsetX, image.offsetY, image.width, image.height)); + + tileID.set (key, index); + } + + tileIDs.set (bitmapData, tileID); + tilesheets.set (bitmapData, tilesheet); + + } + + var tilesheet = tilesheets.get (bitmapData); + var tileID = tileIDs.get (bitmapData); + + var r = ((format.color >> 16) & 0xFF) / 0xFF; + var g = ((format.color >> 8) & 0xFF) / 0xFF; + var b = ((format.color) & 0xFF) / 0xFF; + + var tlm = textField.getLineMetrics(0); + + var image; + var x:Float = offsetX; + var y:Float = 2 + tlm.ascent; + + //If you render with y == 0, the bottom pixel of the "T" in "The Quick Brown Fox" will rest on TOP of your text field. + //Flash API text fields have a 2px margin on all sides, so (2 + ASCENT) puts your text right where it needs to be. + + var tileData; + + textField.__tilesheets.set (tilesheet, true); + + if (!textField.__tileData.exists (tilesheet)) { + + tileData = new Array (); + textField.__tileData.set (tilesheet, tileData); + textField.__tileDataLength.set (tilesheet, 0); + + } + + tileData = textField.__tileData.get (tilesheet); + + var offsetY = 0; + var lines = text.split ("\n"); + + if (textField.__textLayout == null) { + + textField.__textLayout = new TextLayout (); + + } + + var textLayout:TextLayout = textField.__textLayout; + var length = 0; + + var line_i:Int = 0; + var oldX = x; + + for (line in lines) { + + tlm = textField.getLineMetrics (line_i); + + //x position must be reset every line and recalculated + x = oldX; + + x += switch (format.align) { + + case LEFT, JUSTIFY: 0; //the renderer has already positioned the text at the right spot past the 2px left margin + case CENTER: ((textField.__width - 4) - tlm.width) / 2; //subtract 4 from textfield.__width because __width includes the 2px margin on both sides, which doesn't count + case RIGHT: ((textField.__width - 4) - tlm.width); //same thing here + + } + + textLayout.text = null; + textLayout.font = font; + textLayout.size = size; + textLayout.text = line; + + for (position in textLayout.positions) { + + image = images.get (position.glyph); + + if (image != null) { + + if (length >= tileData.length) { + + tileData.push (x + position.offset.x + image.x); + tileData.push (y + position.offset.y - image.y); + tileData.push (tileID.get (position.glyph)); + tileData.push (r); + tileData.push (g); + tileData.push (b); + + } else { + + tileData[length] = x + position.offset.x + image.x; + tileData[length + 1] = y + position.offset.y - image.y; + tileData[length + 2] = tileID.get (position.glyph); + tileData[length + 3] = r; + tileData[length + 4] = g; + tileData[length + 5] = b; + + } + + length += 6; + + } + + x += position.advance.x; + y -= position.advance.y; + + } + + y += tlm.height; //always add the line height at the end + line_i++; + + } + + textField.__tileDataLength.set (tilesheet, length); + + } + + } + + + public static function update (textField:TextField):Bool { + + if (textField.__dirty) { + + if (((textField.__text == null || textField.__text == "") && !textField.background && !textField.border) || ((textField.width <= 0 || textField.height <= 0) && textField.autoSize != TextFieldAutoSize.LEFT)) { + + textField.__tilesheets = null; + textField.__tileData = null; + textField.__tileDataLength = null; + textField.__dirty = false; + + } else { + + textField.__tilesheets = new Map (); + + if (textField.__tileData == null) { + + textField.__tileData = new Map (); + textField.__tileDataLength = new Map (); + + } + + if (textField.__text != null && textField.__text != "") { + + var text = textField.text; + + if (textField.displayAsPassword) { + + var length = text.length; + var mask = ""; + + for (i in 0...length) { + + mask += "*"; + + } + + text = mask; + + } + + var measurements = textField.__measureText (); + var textWidth = 0.0; + + for (measurement in measurements) { + + textWidth += measurement; + + } + + if (textField.autoSize == TextFieldAutoSize.LEFT) { + + textField.__width = textWidth + 4; + textField.__height = textField.textHeight + 4; + + } + + if (textField.__ranges == null) { + + renderText (textField, text, textField.__textFormat, 2, textWidth); + + } else { + + var currentIndex = 0; + var range; + var offsetX = 2.0; + + for (i in 0...textField.__ranges.length) { + + range = textField.__ranges[i]; + + renderText (textField, text.substring (range.start, range.end), range.format, offsetX, textWidth); + offsetX += measurements[i]; + + } + + } + + } else { + + if (textField.autoSize == TextFieldAutoSize.LEFT) { + + textField.__width = 4; + textField.__height = 4; + + } + + } + + for (key in textField.__tileData.keys ()) { + + if (!textField.__tilesheets.exists (key)) { + + textField.__tileData.remove (key); + textField.__tileDataLength.remove (key); + + } + + } + + textField.__dirty = false; + return true; + + } + + } + + return false; + + } + + +} diff --git a/openfl/_internal/renderer/opengl/GLTextField.hx b/openfl/_internal/renderer/opengl/GLTextField.hx index 9820131bfb..6f214c4c08 100644 --- a/openfl/_internal/renderer/opengl/GLTextField.hx +++ b/openfl/_internal/renderer/opengl/GLTextField.hx @@ -1,23 +1,9 @@ package openfl._internal.renderer.opengl; -import haxe.Utf8; -import lime.graphics.Image; -import lime.text.Glyph; -import lime.text.TextLayout; -import openfl._internal.renderer.canvas.CanvasTextField; import openfl._internal.renderer.opengl.utils.GraphicsRenderer; import openfl._internal.renderer.RenderSession; -import openfl.display.BitmapData; -import openfl.display.Graphics; -import openfl.display.Tilesheet; -import openfl.geom.Point; -import openfl.geom.Rectangle; -import openfl.text.Font; import openfl.text.TextField; -import openfl.text.TextFieldAutoSize; -import openfl.text.TextFormat; -import openfl.text.TextFormatAlign; @:access(openfl.text.TextField) @@ -25,366 +11,15 @@ import openfl.text.TextFormatAlign; class GLTextField { - private static var bitmapData = new Map> (); - private static var glyphs = new Map>> (); - private static var tilesheets = new Map (); - private static var tileIDs = new Map> (); - - public static function render (textField:TextField, renderSession:RenderSession) { if (!textField.__renderable || textField.__worldAlpha <= 0) return; - - update (textField); - - if (textField.__graphics == null) { - - textField.__graphics = new Graphics (); - - } - - var graphics = textField.__graphics; - graphics.clear (); - - if (textField.border || textField.background) { - - if (textField.border) { - - graphics.lineStyle (1, textField.borderColor); - - } - - if (textField.background) { - - graphics.beginFill (textField.backgroundColor); - - } - - graphics.drawRect (0.5, 0.5, textField.__width - 1, textField.__height - 1); - - } - - if (textField.__tileData != null) { - - for (tilesheet in textField.__tilesheets.keys ()) { - - graphics.drawTiles (tilesheet, textField.__tileData.get (tilesheet), true, Tilesheet.TILE_RGB, textField.__tileDataLength.get (tilesheet)); - - } - - } + + TextFieldGraphics.render (textField, renderSession); GraphicsRenderer.render (textField, renderSession); } - private static inline function renderText (textField:TextField, text:String, format:TextFormat, offsetX:Float, textWidth:Float):Void { - - var font = textField.__getFontInstance (format); - - if (font != null && format.size != null) { - - if (!glyphs.exists (font)) { - - glyphs.set (font, new Map ()); - - } - - var size = Std.int (format.size); - var fontGlyphs = glyphs.get (font); - - if (!fontGlyphs.exists (size)) { - - fontGlyphs.set (size, font.renderGlyphs (font.getGlyphs (), size)); - - } - - var images = fontGlyphs.get (size); - - if (!bitmapData.exists (font)) { - - bitmapData.set (font, new Map ()); - - } - - var fontBitmapData = bitmapData.get (font); - - if (!fontBitmapData.exists (size)) { - - var width, height, data; - - for (image in images) { - - width = image.buffer.width; - height = image.buffer.height; - data = image.data; - break; - - } - - var bitmapData = new BitmapData (width, height); - - for (x in 0...width) { - - for (y in 0...height) { - - var alpha = data[(y * width) + x]; - var color = alpha << 24 | 0xFF << 16 | 0xFF << 8 | 0xFF; - bitmapData.setPixel32 (x, y, color); - - } - - } - - fontBitmapData.set (size, bitmapData); - - } - - var bitmapData = fontBitmapData.get (size); - - if (!tilesheets.exists (bitmapData)) { - - var tilesheet = new Tilesheet (bitmapData); - var tileID = new Map (); - - var image, index; - - for (key in images.keys ()) { - - image = images.get (key); - index = tilesheet.addTileRect (new Rectangle (image.offsetX, image.offsetY, image.width, image.height)); - - tileID.set (key, index); - } - - tileIDs.set (bitmapData, tileID); - tilesheets.set (bitmapData, tilesheet); - - } - - var tilesheet = tilesheets.get (bitmapData); - var tileID = tileIDs.get (bitmapData); - - var r = ((format.color >> 16) & 0xFF) / 0xFF; - var g = ((format.color >> 8) & 0xFF) / 0xFF; - var b = ((format.color) & 0xFF) / 0xFF; - - var tlm = textField.getLineMetrics(0); - - var image; - var x:Float = offsetX; - var y:Float = 2 + tlm.ascent; - - //If you render with y == 0, the bottom pixel of the "T" in "The Quick Brown Fox" will rest on TOP of your text field. - //Flash API text fields have a 2px margin on all sides, so (2 + ASCENT) puts your text right where it needs to be. - - var tileData; - - textField.__tilesheets.set (tilesheet, true); - - if (!textField.__tileData.exists (tilesheet)) { - - tileData = new Array (); - textField.__tileData.set (tilesheet, tileData); - textField.__tileDataLength.set (tilesheet, 0); - - } - - tileData = textField.__tileData.get (tilesheet); - - var offsetY = 0; - var lines = text.split ("\n"); - - if (textField.__textLayout == null) { - - textField.__textLayout = new TextLayout (); - - } - - var textLayout:TextLayout = textField.__textLayout; - var length = 0; - - var line_i:Int = 0; - var oldX = x; - - for (line in lines) { - - tlm = textField.getLineMetrics (line_i); - - //x position must be reset every line and recalculated - x = oldX; - - x += switch (format.align) { - - case LEFT, JUSTIFY: 0; //the renderer has already positioned the text at the right spot past the 2px left margin - case CENTER: ((textField.__width - 4) - tlm.width) / 2; //subtract 4 from textfield.__width because __width includes the 2px margin on both sides, which doesn't count - case RIGHT: ((textField.__width - 4) - tlm.width); //same thing here - - } - - textLayout.text = null; - textLayout.font = font; - textLayout.size = size; - textLayout.text = line; - - for (position in textLayout.positions) { - - image = images.get (position.glyph); - - if (image != null) { - - if (length >= tileData.length) { - - tileData.push (x + position.offset.x + image.x); - tileData.push (y + position.offset.y - image.y); - tileData.push (tileID.get (position.glyph)); - tileData.push (r); - tileData.push (g); - tileData.push (b); - - } else { - - tileData[length] = x + position.offset.x + image.x; - tileData[length + 1] = y + position.offset.y - image.y; - tileData[length + 2] = tileID.get (position.glyph); - tileData[length + 3] = r; - tileData[length + 4] = g; - tileData[length + 5] = b; - - } - - length += 6; - - } - - x += position.advance.x; - y -= position.advance.y; - - } - - y += tlm.height; //always add the line height at the end - line_i++; - - } - - textField.__tileDataLength.set (tilesheet, length); - - } - - } - - - public static function update (textField:TextField):Bool { - - if (textField.__dirty) { - - if (((textField.__text == null || textField.__text == "") && !textField.background && !textField.border) || ((textField.width <= 0 || textField.height <= 0) && textField.autoSize != TextFieldAutoSize.LEFT)) { - - textField.__tilesheets = null; - textField.__tileData = null; - textField.__tileDataLength = null; - textField.__dirty = false; - - } else { - - textField.__tilesheets = new Map (); - - if (textField.__tileData == null) { - - textField.__tileData = new Map (); - textField.__tileDataLength = new Map (); - - } - - if (textField.__text != null && textField.__text != "") { - - var text = textField.text; - - if (textField.displayAsPassword) { - - var length = text.length; - var mask = ""; - - for (i in 0...length) { - - mask += "*"; - - } - - text = mask; - - } - - var measurements = textField.__measureText (); - var textWidth = 0.0; - - for (measurement in measurements) { - - textWidth += measurement; - - } - - if (textField.autoSize == TextFieldAutoSize.LEFT) { - - textField.__width = textWidth + 4; - textField.__height = textField.textHeight + 4; - - } - - if (textField.__ranges == null) { - - renderText (textField, text, textField.__textFormat, 2, textWidth); - - } else { - - var currentIndex = 0; - var range; - var offsetX = 2.0; - - for (i in 0...textField.__ranges.length) { - - range = textField.__ranges[i]; - - renderText (textField, text.substring (range.start, range.end), range.format, offsetX, textWidth); - offsetX += measurements[i]; - - } - - } - - } else { - - if (textField.autoSize == TextFieldAutoSize.LEFT) { - - textField.__width = 4; - textField.__height = 4; - - } - - } - - for (key in textField.__tileData.keys ()) { - - if (!textField.__tilesheets.exists (key)) { - - textField.__tileData.remove (key); - textField.__tileDataLength.remove (key); - - } - - } - - textField.__dirty = false; - return true; - - } - - } - - return false; - - } - - -} \ No newline at end of file +} From ab2000291b2f7c54cde7c87a37483dc9ca36e295 Mon Sep 17 00:00:00 2001 From: James Gray Date: Wed, 22 Apr 2015 00:08:03 -0500 Subject: [PATCH 055/150] remove comment --- openfl/_internal/renderer/TextFieldGraphics.hx | 1 - 1 file changed, 1 deletion(-) diff --git a/openfl/_internal/renderer/TextFieldGraphics.hx b/openfl/_internal/renderer/TextFieldGraphics.hx index 8db323e6b5..480020e60d 100644 --- a/openfl/_internal/renderer/TextFieldGraphics.hx +++ b/openfl/_internal/renderer/TextFieldGraphics.hx @@ -1,7 +1,6 @@ package openfl._internal.renderer; -//import haxe.Utf8; import lime.graphics.Image; import lime.text.Glyph; import lime.text.TextLayout; From ffd660b29f9f18c4ac41662956861bc8acddfbff Mon Sep 17 00:00:00 2001 From: James Gray Date: Wed, 22 Apr 2015 00:08:32 -0500 Subject: [PATCH 056/150] remove RenderSession param from TextFieldGraphics --- openfl/_internal/renderer/TextFieldGraphics.hx | 2 +- openfl/_internal/renderer/opengl/GLTextField.hx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openfl/_internal/renderer/TextFieldGraphics.hx b/openfl/_internal/renderer/TextFieldGraphics.hx index 480020e60d..f410c58584 100644 --- a/openfl/_internal/renderer/TextFieldGraphics.hx +++ b/openfl/_internal/renderer/TextFieldGraphics.hx @@ -28,7 +28,7 @@ class TextFieldGraphics { private static var tileIDs = new Map> (); - public static function render (textField:TextField, renderSession:RenderSession) { + public static function render (textField:TextField) { update (textField); diff --git a/openfl/_internal/renderer/opengl/GLTextField.hx b/openfl/_internal/renderer/opengl/GLTextField.hx index 6f214c4c08..c42b8d869e 100644 --- a/openfl/_internal/renderer/opengl/GLTextField.hx +++ b/openfl/_internal/renderer/opengl/GLTextField.hx @@ -15,7 +15,7 @@ class GLTextField { if (!textField.__renderable || textField.__worldAlpha <= 0) return; - TextFieldGraphics.render (textField, renderSession); + TextFieldGraphics.render (textField); GraphicsRenderer.render (textField, renderSession); From f8e4f4f3e9e08e530b4adcdef57d3f2f316268ad Mon Sep 17 00:00:00 2001 From: MrCdK Date: Thu, 23 Apr 2015 20:47:18 +0200 Subject: [PATCH 057/150] Don't use the framebuffer texture if there are software changes on it. Fixes #616 --- openfl/_internal/renderer/RenderSession.hx | 2 + .../_internal/renderer/opengl/GLRenderer.hx | 1 + openfl/display/BitmapData.hx | 290 ++++++++++-------- openfl/display/DisplayObject.hx | 1 + openfl/display/IBitmapDrawable.hx | 2 + 5 files changed, 174 insertions(+), 122 deletions(-) diff --git a/openfl/_internal/renderer/RenderSession.hx b/openfl/_internal/renderer/RenderSession.hx index cd52b47e1b..77f37dfa5f 100644 --- a/openfl/_internal/renderer/RenderSession.hx +++ b/openfl/_internal/renderer/RenderSession.hx @@ -4,6 +4,7 @@ package openfl._internal.renderer; #if !flash import lime.graphics.CanvasRenderContext; import lime.graphics.DOMRenderContext; import lime.graphics.GLRenderContext; +import lime.graphics.opengl.GLFramebuffer; import lime.math.Matrix4; import openfl._internal.renderer.opengl.utils.BlendModeManager; import openfl._internal.renderer.opengl.utils.FilterManager; @@ -45,6 +46,7 @@ class RenderSession { public var blendModeManager:BlendModeManager; public var spriteBatch:SpriteBatch; public var stencilManager:StencilManager; + public var defaultFramebuffer:GLFramebuffer; public function new () { diff --git a/openfl/_internal/renderer/opengl/GLRenderer.hx b/openfl/_internal/renderer/opengl/GLRenderer.hx index dfb1392488..7cc1e4dd2f 100644 --- a/openfl/_internal/renderer/opengl/GLRenderer.hx +++ b/openfl/_internal/renderer/opengl/GLRenderer.hx @@ -119,6 +119,7 @@ class GLRenderer extends AbstractRenderer { renderSession.spriteBatch = this.spriteBatch; renderSession.stencilManager = this.stencilManager; renderSession.renderer = this; + renderSession.defaultFramebuffer = this.defaultFramebuffer; renderSession.projection = projection; renderSession.offset = offset; diff --git a/openfl/display/BitmapData.hx b/openfl/display/BitmapData.hx index d7f648d40d..81240c37f3 100644 --- a/openfl/display/BitmapData.hx +++ b/openfl/display/BitmapData.hx @@ -1,13 +1,12 @@ package openfl.display; #if !flash #if !openfl_legacy +import lime.graphics.ImageChannel; import lime.graphics.opengl.GLBuffer; import lime.graphics.opengl.GLTexture; import lime.graphics.GLRenderContext; import lime.graphics.Image; -import lime.graphics.ImageChannel; import lime.graphics.ImageBuffer; -import lime.graphics.ImageChannel; import lime.graphics.utils.ImageCanvasUtil; import lime.math.ColorMatrix; import lime.utils.Float32Array; @@ -135,6 +134,7 @@ class BitmapData implements IBitmapDrawable { @:noCompletion @:dox(hide) public var blendMode:BlendMode; @:noCompletion @:dox(hide) public var __worldTransform:Matrix; @:noCompletion @:dox(hide) public var __worldColorTransform:ColorTransform; + @:noCompletion @:dox(hide) public var __cacheAsBitmap:Bool; @:noCompletion private var __buffer:GLBuffer; @:noCompletion private var __image:Image; @@ -143,8 +143,7 @@ class BitmapData implements IBitmapDrawable { @:noCompletion private var __textureImage:Image; @:noCompletion private var __framebuffer:FilterTexture; @:noCompletion private var __uvData:TextureUvs; - - private var __spritebatch:SpriteBatch; + @:noCompletion private var __usingFramebuffer:Bool = false; /** * Creates a BitmapData object with a specified width and height. If you specify a value for @@ -282,6 +281,7 @@ class BitmapData implements IBitmapDrawable { if (!__isValid) return; __image.colorTransform (rect.__toLimeRectangle (), colorTransform.__toLimeColorMatrix ()); + __usingFramebuffer = false; } @@ -354,6 +354,7 @@ class BitmapData implements IBitmapDrawable { } __image.copyChannel (sourceBitmapData.__image, sourceRect.__toLimeRectangle (), destPoint.__toLimeVector2 (), sourceChannel, destChannel); + __usingFramebuffer = false; } @@ -402,7 +403,7 @@ class BitmapData implements IBitmapDrawable { if (!__isValid || sourceBitmapData == null) return; __image.copyPixels (sourceBitmapData.__image, sourceRect.__toLimeRectangle (), destPoint.__toLimeVector2 (), alphaBitmapData != null ? alphaBitmapData.__image : null, alphaPoint != null ? alphaPoint.__toLimeVector2 () : null, mergeAlpha); - + __usingFramebuffer = false; } @@ -434,6 +435,24 @@ class BitmapData implements IBitmapDrawable { rect = null; __isValid = false; + if (__texture != null) { + var renderer = @:privateAccess Lib.current.stage.__renderer; + if(renderer != null) { + var renderSession = @:privateAccess renderer.renderSession; + var gl = renderSession.gl; + if (gl != null) { + gl.deleteTexture(__texture); + } + } + + } + + if (__framebuffer != null) { + + __framebuffer.destroy(); + + } + } @@ -555,102 +574,10 @@ class BitmapData implements IBitmapDrawable { case DATA: - var renderer = @:privateAccess Lib.current.stage.__renderer; - if (renderer == null) return; - - var renderSession = @:privateAccess renderer.renderSession; - var gl:GLRenderContext = renderSession.gl; - if (gl == null) return; - - - var mainSpritebatch = renderSession.spriteBatch; - var mainProjection = renderSession.projection; - var renderTransparent = renderSession.renderer.transparent; - - if (clipRect == null) { - clipRect = new Rectangle(0, 0, width, height); - } - var tmpRect = clipRect.clone(); - // Flip Y - tmpRect.y = height - tmpRect.bottom; - - var drawSelf = false; - //var drawSelf = true; - if (__spritebatch == null) { - __spritebatch = new SpriteBatch(gl); - drawSelf = true; - } - - renderSession.spriteBatch = __spritebatch; - renderSession.projection = new Point((width / 2), -(height / 2)); - renderSession.renderer.transparent = transparent; - - if (__framebuffer == null) { - __framebuffer = new FilterTexture(gl, width, height, smoothing); - } - __framebuffer.resize(width, height); - gl.bindFramebuffer(gl.FRAMEBUFFER, __framebuffer.frameBuffer); + var renderSession = @:privateAccess Lib.current.stage.__renderer.renderSession; + __drawGL(renderSession, width, height, source, matrix, colorTransform, blendMode, clipRect, smoothing, __framebuffer == null || !__usingFramebuffer, false, true); - gl.viewport (0, 0, width, height); - - __spritebatch.begin(renderSession, drawSelf ? null : tmpRect); - - // enable writing to all the colors and alpha - gl.colorMask(true, true, true, true); - renderSession.blendModeManager.setBlendMode(BlendMode.NORMAL); - - if (drawSelf) { - __framebuffer.clear(); - this.__renderGL(renderSession); - __spritebatch.stop(); - // TODO remove the bitmap texture from vram when done? - __spritebatch.start(tmpRect); - } - - var ctCache = source.__worldColorTransform; - var matrixCache = source.__worldTransform; - var blendModeCache = source.blendMode; - - if (matrix == null) { - matrix = new Matrix(); - } - - invertMatrix(matrix); - - source.__worldTransform = matrix; - source.__worldColorTransform = colorTransform != null ? colorTransform : new ColorTransform(); - source.blendMode = blendMode; - source.__updateChildren (false); - - source.__renderGL (renderSession); - - source.__worldColorTransform = ctCache; - source.__worldTransform = matrixCache; - source.blendMode = blendModeCache; - source.__updateChildren (true); - - __spritebatch.finish(); - //__spritebatch = null; - - gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, __image.buffer.data); - - gl.bindFramebuffer(gl.FRAMEBUFFER, null); - - gl.viewport(0, 0, renderSession.renderer.width, renderSession.renderer.height); - - renderSession.spriteBatch = mainSpritebatch; - renderSession.projection = mainProjection; - renderSession.renderer.transparent = renderTransparent; - - gl.colorMask(true, true, true, renderSession.renderer.transparent); - - __texture = __framebuffer.texture; - __image.dirty = false; - - __createUVs(); - - invertMatrix(matrix); default: @@ -661,19 +588,6 @@ class BitmapData implements IBitmapDrawable { } - private function invertMatrix(matrix:Matrix):Void - { - var tx = matrix.tx; - var ty = matrix.ty; - - matrix.tx = 0; - matrix.ty = 0; - matrix.scale(1, -1); - matrix.translate(0, height); - matrix.tx += tx; - matrix.ty -= ty; - } - public function encode (rect:Rectangle, compressor:Dynamic, byteArray:ByteArray = null):ByteArray { // TODO: Support rect @@ -708,6 +622,7 @@ class BitmapData implements IBitmapDrawable { if (!__isValid || rect == null) return; __image.fillRect (rect.__toLimeRectangle (), color, ARGB); + __usingFramebuffer = false; } @@ -727,6 +642,7 @@ class BitmapData implements IBitmapDrawable { if (!__isValid) return; __image.floodFill (x, y, color, ARGB); + __usingFramebuffer = false; } @@ -964,6 +880,10 @@ class BitmapData implements IBitmapDrawable { if (!__isValid) return null; + if (__usingFramebuffer && __framebuffer != null) { + return __framebuffer.texture; + } + if (__texture == null) { __texture = gl.createTexture (); @@ -976,7 +896,7 @@ class BitmapData implements IBitmapDrawable { } - if (__image.dirty) { + if (__image != null && __image.dirty) { var format = (__image.buffer.bitsPerPixel == 1 ? gl.ALPHA : gl.RGBA); gl.bindTexture (gl.TEXTURE_2D, __texture); @@ -1066,6 +986,7 @@ class BitmapData implements IBitmapDrawable { if (!__isValid || sourceBitmapData == null || !sourceBitmapData.__isValid || sourceRect == null || destPoint == null) return; __image.merge (sourceBitmapData.__image, sourceRect.__toLimeRectangle (), destPoint.__toLimeVector2 (), redMultiplier, greenMultiplier, blueMultiplier, alphaMultiplier); + __usingFramebuffer = false; } @@ -1260,6 +1181,7 @@ class BitmapData implements IBitmapDrawable { if (!__isValid) return; __image.setPixel (x, y, color, ARGB); + __usingFramebuffer = false; } @@ -1299,6 +1221,7 @@ class BitmapData implements IBitmapDrawable { if (!__isValid) return; __image.setPixel32 (x, y, color, ARGB); + __usingFramebuffer = false; } @@ -1326,6 +1249,7 @@ class BitmapData implements IBitmapDrawable { if (!__isValid || rect == null) return; __image.setPixels (rect.__toLimeRectangle (), byteArray, ARGB); + __usingFramebuffer = false; } @@ -1582,18 +1506,29 @@ class BitmapData implements IBitmapDrawable { } - @:noCompletion private function __createUVs ():Void { + @:noCompletion private function __createUVs (?verticalFlip:Bool = false):Void { if (__uvData == null) __uvData = new TextureUvs(); - __uvData.x0 = 0; - __uvData.y0 = 0; - __uvData.x1 = 1; - __uvData.y1 = 0; - __uvData.x2 = 1; - __uvData.y2 = 1; - __uvData.x3 = 0; - __uvData.y3 = 1; + if (verticalFlip) { + __uvData.x0 = 0; + __uvData.y0 = 1; + __uvData.x1 = 1; + __uvData.y1 = 1; + __uvData.x2 = 1; + __uvData.y2 = 0; + __uvData.x3 = 0; + __uvData.y3 = 0; + } else { + __uvData.x0 = 0; + __uvData.y0 = 0; + __uvData.x1 = 1; + __uvData.y1 = 0; + __uvData.x2 = 1; + __uvData.y2 = 1; + __uvData.x3 = 0; + __uvData.y3 = 1; + } } @@ -1726,6 +1661,117 @@ class BitmapData implements IBitmapDrawable { } + @:noCompletion @:dox(hide) public function __drawGL (renderSession:RenderSession, width:Int, height:Int, source:IBitmapDrawable, matrix:Matrix = null, colorTransform:ColorTransform = null, blendMode:BlendMode = null, clipRect:Rectangle = null, smoothing:Bool = false, drawSelf:Bool = false, clearBuffer:Bool = false, readPixels:Bool = false):Void { + + var renderer = @:privateAccess Lib.current.stage.__renderer; + if (renderer == null) return; + + var renderSession = @:privateAccess renderer.renderSession; + var gl:GLRenderContext = renderSession.gl; + if (gl == null) return; + + var spritebatch = renderSession.spriteBatch; + var mainProjection = renderSession.projection; + var renderTransparent = renderSession.renderer.transparent; + + var tmpRect = clipRect == null ? new Rectangle(0, 0, width, height) : clipRect.clone(); + + renderSession.projection = new Point((width / 2), -(height / 2)); + renderSession.renderer.transparent = transparent; + + if (__framebuffer == null) { + __framebuffer = new FilterTexture(gl, width, height, smoothing); + } + + __framebuffer.resize(width, height); + gl.bindFramebuffer(gl.FRAMEBUFFER, __framebuffer.frameBuffer); + + gl.viewport (0, 0, width, height); + + spritebatch.begin(renderSession, drawSelf ? null : tmpRect); + + // enable writing to all the colors and alpha + gl.colorMask(true, true, true, true); + renderSession.blendModeManager.setBlendMode(BlendMode.NORMAL); + + if (clearBuffer || drawSelf) { + __framebuffer.clear(); + } + + if (drawSelf) { + this.__renderGL(renderSession); + spritebatch.stop(); + gl.deleteTexture(__texture); + spritebatch.start(tmpRect); + } + + var ctCache = source.__worldColorTransform; + var matrixCache = source.__worldTransform; + var blendModeCache = source.blendMode; + var cached = source.__cacheAsBitmap; + + var m = matrix != null ? matrix.clone() : new Matrix (); + + var tx = m.tx; + var ty = m.ty; + m.tx = 0; + m.ty = 0; + m.scale(1, -1); + m.translate(0, height); + m.tx += tx; + m.ty -= ty; + + source.__worldTransform = m; + source.__worldColorTransform = colorTransform != null ? colorTransform : new ColorTransform(); + source.blendMode = blendMode; + source.__cacheAsBitmap = false; + + source.__updateChildren (false); + + source.__renderGL (renderSession); + + source.__worldColorTransform = ctCache; + source.__worldTransform = matrixCache; + source.blendMode = blendModeCache; + source.__cacheAsBitmap = cached; + + source.__updateChildren (true); + + spritebatch.finish(); + + if (readPixels) { + + // TODO is this possible? + if (__image.width != width || __image.height != height) { + + __image.resize(width, height); + + } + + gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, __image.buffer.data); + + } + + gl.bindFramebuffer(gl.FRAMEBUFFER, renderSession.defaultFramebuffer); + + gl.viewport(0, 0, renderSession.renderer.width, renderSession.renderer.height); + + renderSession.projection = mainProjection; + renderSession.renderer.transparent = renderTransparent; + + gl.colorMask(true, true, true, renderSession.renderer.transparent); + + __usingFramebuffer = true; + if(__image != null) { + __image.dirty = false; + __image.premultiplied = true; + } + __createUVs(false); + __isValid = true; + + } + + @:noCompletion @:dox(hide) public function __renderMask (renderSession:RenderSession):Void { diff --git a/openfl/display/DisplayObject.hx b/openfl/display/DisplayObject.hx index 335bba73a8..6821252007 100644 --- a/openfl/display/DisplayObject.hx +++ b/openfl/display/DisplayObject.hx @@ -741,6 +741,7 @@ class DisplayObject extends EventDispatcher implements IBitmapDrawable { @:noCompletion private var __worldZ:Int; @:noCompletion private var __x:Float; @:noCompletion private var __y:Float; + @:noCompletion private var __cacheAsBitmap:Bool = false; #if js @:noCompletion private var __canvas:CanvasElement; diff --git a/openfl/display/IBitmapDrawable.hx b/openfl/display/IBitmapDrawable.hx index a999882f5a..02bcd8f5f2 100644 --- a/openfl/display/IBitmapDrawable.hx +++ b/openfl/display/IBitmapDrawable.hx @@ -12,6 +12,8 @@ interface IBitmapDrawable { var __worldColorTransform:ColorTransform; var blendMode:BlendMode; + private var __cacheAsBitmap:Bool; + function __renderCanvas (renderSession:RenderSession):Void; function __renderGL (renderSession:RenderSession):Void; function __renderMask (renderSession:RenderSession):Void; From 155e67a1cc3955bb708b2ff39bad92de57642cff Mon Sep 17 00:00:00 2001 From: Ben Morris Date: Thu, 23 Apr 2015 22:50:08 -0700 Subject: [PATCH 058/150] Font embedding path fix. --- openfl/Assets.hx | 5 ++++- openfl/_legacy/Assets.hx | 6 +++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/openfl/Assets.hx b/openfl/Assets.hx index 009811e0b9..6228a3eded 100644 --- a/openfl/Assets.hx +++ b/openfl/Assets.hx @@ -1325,7 +1325,10 @@ class Assets { case EConst(CString(filePath)): - path = Context.resolvePath (filePath); + path = filePath; + if (!sys.FileSystem.exists(filePath)) { + path = Context.resolvePath (filePath); + } default: diff --git a/openfl/_legacy/Assets.hx b/openfl/_legacy/Assets.hx index 7ccc571d6c..eabd5214d7 100644 --- a/openfl/_legacy/Assets.hx +++ b/openfl/_legacy/Assets.hx @@ -1870,7 +1870,11 @@ class Assets { case EConst(CString(filePath)): - path = Context.resolvePath (filePath); + path = filePath; + if (!sys.FileSystem.exists(filePath)) { + path = Context.resolvePath (filePath); + } + default: From 4eccc6c133920bad04737902b53a590cf3cd0971 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Fri, 24 Apr 2015 00:14:53 -0700 Subject: [PATCH 059/150] Fix HTML5 scrollRect --- openfl/display/DisplayObjectContainer.hx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openfl/display/DisplayObjectContainer.hx b/openfl/display/DisplayObjectContainer.hx index 281a521377..488ba802f6 100644 --- a/openfl/display/DisplayObjectContainer.hx +++ b/openfl/display/DisplayObjectContainer.hx @@ -778,7 +778,7 @@ class DisplayObjectContainer extends InteractiveObject { if (scrollRect != null) { - //renderSession.maskManager.pushRect (scrollRect, __worldTransform); + renderSession.maskManager.pushRect (scrollRect, __worldTransform); } @@ -804,7 +804,7 @@ class DisplayObjectContainer extends InteractiveObject { if (scrollRect != null) { - //renderSession.maskManager.popMask (); + renderSession.maskManager.popMask (); } From bf1d69a42051dbc6d0292659c50b345951df8b71 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Fri, 24 Apr 2015 02:19:27 -0700 Subject: [PATCH 060/150] Handle window enter/leave events from Lime --- openfl/_legacy/display/HybridStage.hx | 15 +++++++++++++++ openfl/display/Stage.hx | 14 ++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/openfl/_legacy/display/HybridStage.hx b/openfl/_legacy/display/HybridStage.hx index d30318b194..68a9d7e9dc 100644 --- a/openfl/_legacy/display/HybridStage.hx +++ b/openfl/_legacy/display/HybridStage.hx @@ -9,6 +9,7 @@ import lime.ui.GamepadAxis; import lime.ui.GamepadButton; import lime.ui.KeyCode; import lime.ui.KeyModifier; +import openfl._legacy.events.Event; import openfl._legacy.Lib; import openfl.ui.Keyboard; @@ -237,6 +238,13 @@ class HybridStage extends ManagedStage implements IModule { } + public function onWindowEnter ():Void { + + + + } + + public function onWindowFocusIn ():Void { pumpEvent ( { type: ManagedStage.etGotInputFocus } ); @@ -258,6 +266,13 @@ class HybridStage extends ManagedStage implements IModule { } + public function onWindowLeave ():Void { + + dispatchEvent (new Event (Event.MOUSE_LEAVE)); + + } + + public function onWindowMinimize ():Void { diff --git a/openfl/display/Stage.hx b/openfl/display/Stage.hx index 80f011f35d..f3ff627585 100644 --- a/openfl/display/Stage.hx +++ b/openfl/display/Stage.hx @@ -817,6 +817,13 @@ class Stage extends DisplayObjectContainer implements IModule { } + public function onWindowEnter ():Void { + + + + } + + public function onWindowFocusIn ():Void { @@ -838,6 +845,13 @@ class Stage extends DisplayObjectContainer implements IModule { } + public function onWindowLeave ():Void { + + dispatchEvent (new Event (Event.MOUSE_LEAVE)); + + } + + public function onWindowMinimize ():Void { From 51e17e6d7729afe704c7ea4a1822911c77687a12 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Fri, 24 Apr 2015 02:20:09 -0700 Subject: [PATCH 061/150] Text line measurement tweaks, improve text input cursor --- .../_internal/renderer/canvas/CanvasTextField.hx | 14 +++++++------- openfl/text/TextField.hx | 3 ++- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/openfl/_internal/renderer/canvas/CanvasTextField.hx b/openfl/_internal/renderer/canvas/CanvasTextField.hx index fae569a22e..fc058957ea 100644 --- a/openfl/_internal/renderer/canvas/CanvasTextField.hx +++ b/openfl/_internal/renderer/canvas/CanvasTextField.hx @@ -97,11 +97,11 @@ class CanvasTextField { if (context.measureText (test).width > textField.__width - 4 && i > 0) { lines.push (line); - lines.push (word.substring (0, newLineIndex) + " "); + lines.push (word.substring (0, newLineIndex)); } else { - lines.push (line + word.substring (0, newLineIndex) + " "); + lines.push (line + word.substring (0, newLineIndex)); } @@ -171,7 +171,7 @@ class CanvasTextField { } - yOffset += textField.textHeight; + yOffset += textField.textHeight; // TODO: Handle format.leading } @@ -186,7 +186,7 @@ class CanvasTextField { if (textField.__dirty) { - if (((textField.__text == null || textField.__text == "") && !textField.background && !textField.border) || ((textField.width <= 0 || textField.height <= 0) && textField.autoSize != TextFieldAutoSize.LEFT)) { + if (((textField.__text == null || textField.__text == "") && !textField.background && !textField.border && !textField.__hasFocus) || ((textField.width <= 0 || textField.height <= 0) && textField.autoSize != TextFieldAutoSize.LEFT)) { textField.__canvas = null; textField.__context = null; @@ -203,7 +203,7 @@ class CanvasTextField { context = textField.__context; - if (textField.__text != null && textField.__text != "") { + if ((textField.__text != null && textField.__text != "") || textField.__hasFocus) { var text = textField.text; @@ -263,9 +263,9 @@ class CanvasTextField { if (textField.__hasFocus && (textField.__selectionStart == textField.__cursorPosition) && textField.__showCursor) { - var cursorOffset = textField.__getTextWidth (text.substring (0, textField.__cursorPosition)); + var cursorOffset = textField.__getTextWidth (text.substring (0, textField.__cursorPosition)) + 3; context.fillStyle = "#" + StringTools.hex (textField.__textFormat.color, 6); - context.fillRect (cursorOffset, 5, 1, textField.__textFormat.size - 5); + context.fillRect (cursorOffset, 5, 1, (textField.__textFormat.size * 1.185) - 5); } else if (textField.__hasFocus && (Math.abs (textField.__selectionStart - textField.__cursorPosition)) > 0 && !textField.__isKeyDown) { diff --git a/openfl/text/TextField.hx b/openfl/text/TextField.hx index 6d60cfe760..4501273ed0 100644 --- a/openfl/text/TextField.hx +++ b/openfl/text/TextField.hx @@ -1558,6 +1558,7 @@ class TextField extends InteractiveObject { div = cast Browser.document.createElement ("div"); div.innerHTML = new EReg ("\n", "g").replace (__text, "
"); div.style.setProperty ("font", __getFont (__textFormat), null); + div.style.setProperty ("pointer-events", "none"); div.style.position = "absolute"; div.style.top = "110%"; // position off-screen! Browser.document.body.appendChild (div); @@ -1570,7 +1571,7 @@ class TextField extends InteractiveObject { // function of the flow within the width bounds... if (__div == null) { - div.style.width = Std.string (__width) + "px"; + div.style.width = Std.string (__width - 4) + "px"; } From 3eba148499e48ef993432673d72a251e3d285f95 Mon Sep 17 00:00:00 2001 From: Kane Wallmann Date: Fri, 24 Apr 2015 19:18:33 +1000 Subject: [PATCH 062/150] Fixed crash on non-flash targets when double click is enabled on InteractiveObject --- openfl/display/Stage.hx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/openfl/display/Stage.hx b/openfl/display/Stage.hx index f3ff627585..429d210d96 100644 --- a/openfl/display/Stage.hx +++ b/openfl/display/Stage.hx @@ -529,9 +529,9 @@ class Stage extends DisplayObjectContainer implements IModule { @:noCompletion private var __fullscreen:Bool; @:noCompletion private var __invalidated:Bool; @:noCompletion private var __lastClickTime:Int; - @:noCompletion private var __mouseOutStack = []; - @:noCompletion private var __mouseX:Float = 0; - @:noCompletion private var __mouseY:Float = 0; + @:noCompletion private var __mouseOutStack:Array; + @:noCompletion private var __mouseX:Float; + @:noCompletion private var __mouseY:Float; @:noCompletion private var __originalWidth:Int; @:noCompletion private var __originalHeight:Int; @:noCompletion private var __renderer:AbstractRenderer; @@ -569,7 +569,8 @@ class Stage extends DisplayObjectContainer implements IModule { __displayState = NORMAL; __mouseX = 0; __mouseY = 0; - + __lastClickTime = 0; + stageWidth = width; stageHeight = height; @@ -584,6 +585,7 @@ class Stage extends DisplayObjectContainer implements IModule { __clearBeforeRender = true; __stack = []; + __mouseOutStack = []; stage3Ds = new Vector (); stage3Ds.push (new Stage3D ()); From f38c74467fa26bc65e2ab5c7b9634aa3a36358db Mon Sep 17 00:00:00 2001 From: Jay Sistar Date: Fri, 24 Apr 2015 12:43:16 -0400 Subject: [PATCH 063/150] Fixing texture uploads from BitmapData objects. --- openfl/display3D/textures/Texture.hx | 91 +++++++++++++++++++--------- 1 file changed, 61 insertions(+), 30 deletions(-) diff --git a/openfl/display3D/textures/Texture.hx b/openfl/display3D/textures/Texture.hx index db9e66ed03..eb92987c58 100755 --- a/openfl/display3D/textures/Texture.hx +++ b/openfl/display3D/textures/Texture.hx @@ -51,9 +51,9 @@ class Texture extends TextureBase { public function uploadFromBitmapData (bitmapData:BitmapData, miplevel:Int = 0):Void { - + // TODO: Support upload from UInt8Array directly - + #if openfl_legacy var p = BitmapData.getRGBAPixels (bitmapData); #elseif js @@ -61,53 +61,84 @@ class Texture extends TextureBase { #else var p = @:privateAccess (bitmapData.__image).data.buffer; #end - + width = bitmapData.width; height = bitmapData.height; - uploadFromByteArray (p, 0, miplevel); - + + var source = new UInt8Array (p.length); + var endian = p.endian; + p.endian = "littleEndian"; + p.position = 0; + + var i:Int = 0; + + while (p.position < p.length) { + + var c:Int = p.readUnsignedInt (); + var a:Int = ((c >>> 24) & 0xFF) + 1; + + var r = (((((c ) & 0xFF) + 1) * a) >>> 8) - 1; + var g = (((((c >>> 8) & 0xFF) + 1) * a) >>> 8) - 1; + var b = (((((c >>> 16) & 0xFF) + 1) * a) >>> 8) - 1; + + source[i++] = (r == -1) ? 0 : r; + source[i++] = (g == -1) ? 0 : g; + source[i++] = (b == -1) ? 0 : b; + source[i++] = a - 1; + + } + p.endian = endian; + + uploadFromUInt8Array(source, miplevel); + } - - + + public function uploadFromByteArray (data:ByteArray, byteArrayOffset:Int, miplevel:Int = 0):Void { - - GL.bindTexture (GL.TEXTURE_2D, glTexture); - - if (optimizeForRenderToTexture) { - - GL.pixelStorei (GL.UNPACK_FLIP_Y_WEBGL, 1); - GL.texParameteri (GL.TEXTURE_2D, GL.TEXTURE_MAG_FILTER, GL.NEAREST); - GL.texParameteri (GL.TEXTURE_2D, GL.TEXTURE_MIN_FILTER, GL.NEAREST); - GL.texParameteri (GL.TEXTURE_2D, GL.TEXTURE_WRAP_S, GL.CLAMP_TO_EDGE); - GL.texParameteri (GL.TEXTURE_2D, GL.TEXTURE_WRAP_T, GL.CLAMP_TO_EDGE); - - } - + #if js var source = new UInt8Array (data.length); data.position = byteArrayOffset; - + var i:Int = 0; - + while (data.position < data.length) { - + source[i] = data.readUnsignedByte (); i++; - + } #else var source = new UInt8Array (data); #end - - GL.texImage2D (GL.TEXTURE_2D, miplevel, GL.RGBA, width, height, 0, GL.RGBA, GL.UNSIGNED_BYTE, source); + + uploadFromUInt8Array(source, miplevel); + + } + + public function uploadFromUInt8Array (data:UInt8Array, miplevel:Int = 0):Void { + + GL.bindTexture (GL.TEXTURE_2D, glTexture); + + if (optimizeForRenderToTexture) { + + GL.pixelStorei (GL.UNPACK_FLIP_Y_WEBGL, 1); + GL.texParameteri (GL.TEXTURE_2D, GL.TEXTURE_MAG_FILTER, GL.NEAREST); + GL.texParameteri (GL.TEXTURE_2D, GL.TEXTURE_MIN_FILTER, GL.NEAREST); + GL.texParameteri (GL.TEXTURE_2D, GL.TEXTURE_WRAP_S, GL.CLAMP_TO_EDGE); + GL.texParameteri (GL.TEXTURE_2D, GL.TEXTURE_WRAP_T, GL.CLAMP_TO_EDGE); + + } + + GL.texImage2D (GL.TEXTURE_2D, miplevel, GL.RGBA, width, height, 0, GL.RGBA, GL.UNSIGNED_BYTE, data); GL.bindTexture (GL.TEXTURE_2D, null); - + } - - + + } #else typedef Texture = flash.display3D.textures.Texture; -#end \ No newline at end of file +#end From cccd7a84bb094b5a1d35b935d4c10f7c3d3aa3e8 Mon Sep 17 00:00:00 2001 From: Jay Sistar Date: Fri, 24 Apr 2015 12:44:24 -0400 Subject: [PATCH 064/150] Type error in TextFormat (legacy only... 3.0 doesn't have this problem). --- openfl/_legacy/text/TextFormat.hx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openfl/_legacy/text/TextFormat.hx b/openfl/_legacy/text/TextFormat.hx index bfe7679726..4f514580c7 100644 --- a/openfl/_legacy/text/TextFormat.hx +++ b/openfl/_legacy/text/TextFormat.hx @@ -13,7 +13,7 @@ package openfl._legacy.text; #if openfl_legacy public var font:String; public var indent:Null; public var italic:Null; - public var kerning:Null; + public var kerning:Null; public var leading:Null; public var leftMargin:Null; public var letterSpacing:Null; @@ -47,4 +47,4 @@ package openfl._legacy.text; #if openfl_legacy } -#end \ No newline at end of file +#end From 9a4d16d9f747ac7ed337ee59d7f7cd20d33ab058 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Fri, 24 Apr 2015 09:56:55 -0700 Subject: [PATCH 065/150] Compile fix --- openfl/text/TextField.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openfl/text/TextField.hx b/openfl/text/TextField.hx index 4501273ed0..95226b5c30 100644 --- a/openfl/text/TextField.hx +++ b/openfl/text/TextField.hx @@ -1558,7 +1558,7 @@ class TextField extends InteractiveObject { div = cast Browser.document.createElement ("div"); div.innerHTML = new EReg ("\n", "g").replace (__text, "
"); div.style.setProperty ("font", __getFont (__textFormat), null); - div.style.setProperty ("pointer-events", "none"); + div.style.setProperty ("pointer-events", "none", null); div.style.position = "absolute"; div.style.top = "110%"; // position off-screen! Browser.document.body.appendChild (div); From f5448c1de54cf5d665a10d017792cc912411c34a Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Fri, 24 Apr 2015 10:09:06 -0700 Subject: [PATCH 066/150] Try and fix uploadFromBitmapData for legacy --- openfl/display3D/textures/Texture.hx | 99 +++++++++++++--------------- 1 file changed, 44 insertions(+), 55 deletions(-) diff --git a/openfl/display3D/textures/Texture.hx b/openfl/display3D/textures/Texture.hx index eb92987c58..a758f5395c 100755 --- a/openfl/display3D/textures/Texture.hx +++ b/openfl/display3D/textures/Texture.hx @@ -51,91 +51,80 @@ class Texture extends TextureBase { public function uploadFromBitmapData (bitmapData:BitmapData, miplevel:Int = 0):Void { - - // TODO: Support upload from UInt8Array directly - + #if openfl_legacy - var p = BitmapData.getRGBAPixels (bitmapData); - #elseif js - var p = ByteArray.__ofBuffer (@:privateAccess (bitmapData.__image).data.buffer); - #else - var p = @:privateAccess (bitmapData.__image).data.buffer; - #end - + + var pixels = BitmapData.getRGBAPixels (bitmapData); + width = bitmapData.width; height = bitmapData.height; - - var source = new UInt8Array (p.length); - var endian = p.endian; - p.endian = "littleEndian"; - p.position = 0; - - var i:Int = 0; - - while (p.position < p.length) { - - var c:Int = p.readUnsignedInt (); - var a:Int = ((c >>> 24) & 0xFF) + 1; - - var r = (((((c ) & 0xFF) + 1) * a) >>> 8) - 1; - var g = (((((c >>> 8) & 0xFF) + 1) * a) >>> 8) - 1; - var b = (((((c >>> 16) & 0xFF) + 1) * a) >>> 8) - 1; - - source[i++] = (r == -1) ? 0 : r; - source[i++] = (g == -1) ? 0 : g; - source[i++] = (b == -1) ? 0 : b; - source[i++] = a - 1; - + + uploadFromByteArray (pixels, 0, miplevel); + + #else + + var image = @:privateAccess (bitmapData.__image); + + if (!image.premultiplied) { + + image = image.clone (); + image.premultiplied = true; + } - p.endian = endian; - - uploadFromUInt8Array(source, miplevel); - + + width = image.width; + height = image.height; + + uploadFromUInt8Array (image.data, miplevel); + + #end + } - - + + public function uploadFromByteArray (data:ByteArray, byteArrayOffset:Int, miplevel:Int = 0):Void { - + #if js var source = new UInt8Array (data.length); data.position = byteArrayOffset; - + var i:Int = 0; - + while (data.position < data.length) { - + source[i] = data.readUnsignedByte (); i++; - + } #else var source = new UInt8Array (data); #end - - uploadFromUInt8Array(source, miplevel); - + + uploadFromUInt8Array (source, miplevel); + } - + + public function uploadFromUInt8Array (data:UInt8Array, miplevel:Int = 0):Void { - + GL.bindTexture (GL.TEXTURE_2D, glTexture); - + if (optimizeForRenderToTexture) { - + GL.pixelStorei (GL.UNPACK_FLIP_Y_WEBGL, 1); GL.texParameteri (GL.TEXTURE_2D, GL.TEXTURE_MAG_FILTER, GL.NEAREST); GL.texParameteri (GL.TEXTURE_2D, GL.TEXTURE_MIN_FILTER, GL.NEAREST); GL.texParameteri (GL.TEXTURE_2D, GL.TEXTURE_WRAP_S, GL.CLAMP_TO_EDGE); GL.texParameteri (GL.TEXTURE_2D, GL.TEXTURE_WRAP_T, GL.CLAMP_TO_EDGE); - + } - + GL.texImage2D (GL.TEXTURE_2D, miplevel, GL.RGBA, width, height, 0, GL.RGBA, GL.UNSIGNED_BYTE, data); GL.bindTexture (GL.TEXTURE_2D, null); - + } - - + + } From 48f0944734a039afb882d35b76f853ae47fa406a Mon Sep 17 00:00:00 2001 From: Daniel Uranga Date: Fri, 24 Apr 2015 16:45:39 -0300 Subject: [PATCH 067/150] Non-blocking HTTPs proof of concept. --- openfl/_legacy/net/URLLoader.hx | 268 ++++++++++++++++++++++---------- 1 file changed, 182 insertions(+), 86 deletions(-) diff --git a/openfl/_legacy/net/URLLoader.hx b/openfl/_legacy/net/URLLoader.hx index da5a5e5311..9c1e90b0f8 100644 --- a/openfl/_legacy/net/URLLoader.hx +++ b/openfl/_legacy/net/URLLoader.hx @@ -13,7 +13,115 @@ import openfl.net.URLRequestHeader; import openfl.net.URLVariables; import openfl.utils.ByteArray; import openfl.Lib; +import cpp.vm.Thread; +class URLLoadersManager { + + static var instance : URLLoadersManager; + + var managersThread : Thread; + var activeLoaders : List; + var loadsQueue : Array<{loader : URLLoader, request : URLRequest}>; + + public static function getInstance() : URLLoadersManager { + if (instance==null) { + instance = new URLLoadersManager(); + } + return instance; + } + + function new() { + activeLoaders = new List(); + loadsQueue = []; + managersThread = Thread.create(mainLoop); + } + + function mainLoop() { + + while (true) { + + var loadCall = loadsQueue.shift(); + if (loadCall!=null) { + loadCall.loader.loadInCURLThread(loadCall.request); + } + + if (!activeLoaders.isEmpty()) { + lime_curl_process_loaders(); + var oldLoaders = activeLoaders; + activeLoaders = new List(); + for (loader in oldLoaders) { + loader.update(); + if (loader.state == URLLoader.urlLoading) { + activeLoaders.push(loader); + } + } + } + + Sys.sleep(0.05); + } + + } // mainLoop + + public function enqueueLoad(loader : URLLoader, request : URLRequest) { + loadsQueue.push({loader : loader, request : request}); + } + + public function activeLoadersIsEmpty() { + return activeLoaders.isEmpty(); + } + + public function getActiveLoaders() : List { + if (Thread.current()!=managersThread) throw "Wrong thread : getActiveLoaders"; + return activeLoaders; + } + + public function create(request : URLRequest) : Dynamic { + if (Thread.current()!=managersThread) throw "Wrong thread : create"; + return lime_curl_create(request); + } + + public function updateLoader(handle : Dynamic, loader : URLLoader) : Void { + if (Thread.current()!=managersThread) throw "Wrong thread : updateLoader"; + lime_curl_update_loader(handle, loader); + } + + public function getCode(handle : Dynamic) : Int { + if (Thread.current()!=managersThread) throw "Wrong thread : getCode"; + return lime_curl_get_code(handle); + } + + public function getErrorMessage(handle : Dynamic) : String { + if (Thread.current()!=managersThread) throw "Wrong thread : getErrorMessage"; + return lime_curl_get_error_message(handle); + } + + public function getData(handle : Dynamic) : ByteArray { + if (Thread.current()!=managersThread) throw "Wrong thread : getData"; + return lime_curl_get_data(handle); + } + + public function getCookies(handle : Dynamic) : Array { + if (Thread.current()!=managersThread) throw "Wrong thread : getCookies"; + return lime_curl_get_cookies(handle); + } + + public function getHeaders(handle : Dynamic) : Array { + if (Thread.current()!=managersThread) throw "Wrong thread : getHeaders"; + return lime_curl_get_headers(handle); + } + + // Native Methods + private static var lime_curl_create = Lib.load ("lime-legacy", "lime_legacy_curl_create", 1); + private static var lime_curl_process_loaders = Lib.load ("lime-legacy", "lime_legacy_curl_process_loaders", 0); + private static var lime_curl_update_loader = Lib.load ("lime-legacy", "lime_legacy_curl_update_loader", 2); + private static var lime_curl_get_code = Lib.load ("lime-legacy", "lime_legacy_curl_get_code", 1); + private static var lime_curl_get_error_message = Lib.load ("lime-legacy", "lime_legacy_curl_get_error_message", 1); + private static var lime_curl_get_data = Lib.load ("lime-legacy", "lime_legacy_curl_get_data", 1); + private static var lime_curl_get_cookies = Lib.load ("lime-legacy", "lime_legacy_curl_get_cookies", 1); + private static var lime_curl_get_headers = Lib.load ("lime-legacy", "lime_legacy_curl_get_headers", 1); + private static var lime_curl_initialize = Lib.load ("lime-legacy", "lime_legacy_curl_initialize", 1); + +} class URLLoader extends EventDispatcher { @@ -23,14 +131,19 @@ class URLLoader extends EventDispatcher { public var data:Dynamic; public var dataFormat:URLLoaderDataFormat; - @:noCompletion private static var activeLoaders = new List (); + //@:noCompletion private static var activeLoaders = new List (); @:noCompletion private static inline var urlInvalid = 0; @:noCompletion private static inline var urlInit = 1; + + @:allow(openfl._legacy.net.URLLoadersManager) @:noCompletion private static inline var urlLoading = 2; + @:noCompletion private static inline var urlComplete = 3; @:noCompletion private static inline var urlError = 4; + @:allow(openfl._legacy.net.URLLoadersManager) @:noCompletion private var state:Int; + @:noCompletion private var __handle:Dynamic; @:noCompletion public var __onComplete:Dynamic -> Bool; @@ -64,7 +177,8 @@ class URLLoader extends EventDispatcher { private function dispatchHTTPStatus (code:Int):Void { var event = new HTTPStatusEvent (HTTPStatusEvent.HTTP_STATUS, false, false, code); - var headers:Array = lime_curl_get_headers (__handle); + //var headers:Array = lime_curl_get_headers (__handle); + var headers = URLLoadersManager.getInstance().getHeaders(__handle); for (header in headers) { @@ -77,34 +191,46 @@ class URLLoader extends EventDispatcher { } - dispatchEvent (event); + //dispatchEvent (event); + enqueueEvent(this, event); } public function getCookies ():Array { - + trace("GET COOKIES"); + return []; + /* return lime_curl_get_cookies (__handle); - + */ } public static function hasActive ():Bool { - return !activeLoaders.isEmpty (); + return !URLLoadersManager.getInstance().activeLoadersIsEmpty(); } public static function initialize (caCertFilePath:String):Void { - + trace("INITIALIZE"); + /* lime_curl_initialize (caCertFilePath); + */ } public function load (request:URLRequest):Void { + URLLoadersManager.getInstance().enqueueLoad(this, request); + + } + + @:allow(openfl._legacy.net.URLLoadersManager) + function loadInCURLThread(request:URLRequest):Void { + state = urlInit; var pref = request.url.substr (0, 7); @@ -140,7 +266,9 @@ class URLLoader extends EventDispatcher { } else { request.__prepare (); - __handle = lime_curl_create (request); + + //__handle = lime_curl_create (request); + __handle = URLLoadersManager.getInstance().create(request); if (__handle == null) { @@ -148,80 +276,75 @@ class URLLoader extends EventDispatcher { } else { - activeLoaders.push (this); + URLLoadersManager.getInstance().getActiveLoaders().push (this); } } - + } private function onError (msg:String):Void { - activeLoaders.remove (this); - dispatchEvent (new IOErrorEvent (IOErrorEvent.IO_ERROR, true, false, msg)); + URLLoadersManager.getInstance().getActiveLoaders().remove (this); + //dispatchEvent (new IOErrorEvent (IOErrorEvent.IO_ERROR, true, false, msg)); + enqueueEvent(this, new IOErrorEvent (IOErrorEvent.IO_ERROR, true, false, msg)); } - - private function update ():Void { - + @:allow(openfl._legacy.net.URLLoadersManager) + private function update():Void { + if (__handle != null) { - + var old_loaded = bytesLoaded; var old_total = bytesTotal; - lime_curl_update_loader (__handle, this); - + //lime_curl_update_loader (__handle, this); + URLLoadersManager.getInstance().updateLoader(__handle, this); + if (old_total < 0 && bytesTotal > 0) { - - dispatchEvent (new Event (Event.OPEN)); - + //dispatchEvent (new Event (Event.OPEN)); + enqueueEvent(this, new Event (Event.OPEN)); } if (bytesTotal > 0 && bytesLoaded != old_loaded) { - - dispatchEvent (new ProgressEvent (ProgressEvent.PROGRESS, false, false, bytesLoaded, bytesTotal)); - + //dispatchEvent (new ProgressEvent (ProgressEvent.PROGRESS, false, false, bytesLoaded, bytesTotal)); + var evt = new ProgressEvent (ProgressEvent.PROGRESS, false, false, bytesLoaded, bytesTotal); + enqueueEvent(this, evt); } - var code:Int = lime_curl_get_code (__handle); + //var code:Int = lime_curl_get_code (__handle); + var code = URLLoadersManager.getInstance().getCode(__handle); if (state == urlComplete) { - + dispatchHTTPStatus (code); - - var bytes:ByteArray = lime_curl_get_data (__handle); - + //var bytes:ByteArray = lime_curl_get_data (__handle); + var bytes = URLLoadersManager.getInstance().getData(__handle); switch (dataFormat) { - case TEXT, VARIABLES: data = bytes == null ? "" : bytes.asString (); default: data = bytes; - } - + if (code < 400) { - - __dataComplete (); - + __dataComplete (); } else { - var event = new IOErrorEvent (IOErrorEvent.IO_ERROR, true, false, data, code); __handle = null; - dispatchEvent (event); - + //dispatchEvent (event); + enqueueEvent(this, event); } } else if (state == urlError) { - dispatchHTTPStatus (code); - - var event = new IOErrorEvent (IOErrorEvent.IO_ERROR, true, false, lime_curl_get_error_message (__handle), code); + var errorMessage = URLLoadersManager.getInstance().getErrorMessage(__handle); + var event = new IOErrorEvent (IOErrorEvent.IO_ERROR, true, false, errorMessage, code); __handle = null; - dispatchEvent (event); - + //dispatchEvent (event); + enqueueEvent(this, event); } } @@ -231,13 +354,14 @@ class URLLoader extends EventDispatcher { @:noCompletion private function __dataComplete ():Void { - activeLoaders.remove (this); + URLLoadersManager.getInstance().getActiveLoaders().remove (this); if (__onComplete != null) { if (__onComplete (data)) { - dispatchEvent (new Event (Event.COMPLETE)); + //dispatchEvent (new Event (Event.COMPLETE)); + enqueueEvent(this, new Event (Event.COMPLETE)); } else { @@ -247,7 +371,8 @@ class URLLoader extends EventDispatcher { } else { - dispatchEvent (new Event (Event.COMPLETE)); + //dispatchEvent (new Event (Event.COMPLETE)); + enqueueEvent(this, new Event (Event.COMPLETE)); } @@ -256,52 +381,23 @@ class URLLoader extends EventDispatcher { @:noCompletion public static function __loadPending ():Bool { - return !activeLoaders.isEmpty (); + return !URLLoadersManager.getInstance().activeLoadersIsEmpty(); } - + static var eventsQueue : Array<{loader : URLLoader, event : Event}> = []; + + static function enqueueEvent(loader : URLLoader, event : Event) { + eventsQueue.push({loader : loader, event : event}); + } + @:noCompletion public static function __pollData ():Void { - - if (!activeLoaders.isEmpty ()) { - - lime_curl_process_loaders (); - var oldLoaders = activeLoaders; - activeLoaders = new List (); - - for (loader in oldLoaders) { - - loader.update (); - if (loader.state == urlLoading) { - - activeLoaders.push (loader); - - } - - } - + var evt = eventsQueue.shift(); + if (evt!=null) { + evt.loader.dispatchEvent(evt.event); } - } - - - - - // Native Methods - - - - - private static var lime_curl_create = Lib.load ("lime-legacy", "lime_legacy_curl_create", 1); - private static var lime_curl_process_loaders = Lib.load ("lime-legacy", "lime_legacy_curl_process_loaders", 0); - private static var lime_curl_update_loader = Lib.load ("lime-legacy", "lime_legacy_curl_update_loader", 2); - private static var lime_curl_get_code = Lib.load ("lime-legacy", "lime_legacy_curl_get_code", 1); - private static var lime_curl_get_error_message = Lib.load ("lime-legacy", "lime_legacy_curl_get_error_message", 1); - private static var lime_curl_get_data = Lib.load ("lime-legacy", "lime_legacy_curl_get_data", 1); - private static var lime_curl_get_cookies = Lib.load ("lime-legacy", "lime_legacy_curl_get_cookies", 1); - private static var lime_curl_get_headers = Lib.load ("lime-legacy", "lime_legacy_curl_get_headers", 1); - private static var lime_curl_initialize = Lib.load ("lime-legacy", "lime_legacy_curl_initialize", 1); - + } From 3ae1f2fee5de87416035f8bd151defeebf423b7f Mon Sep 17 00:00:00 2001 From: MrCdK Date: Sat, 25 Apr 2015 02:46:50 +0200 Subject: [PATCH 068/150] The original BitmapData should be flipped too when using draw() Fixes #623 (and hopefully it won't break anything else) --- openfl/display/BitmapData.hx | 68 +++++++++++++++++------------------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/openfl/display/BitmapData.hx b/openfl/display/BitmapData.hx index 81240c37f3..f764b0b960 100644 --- a/openfl/display/BitmapData.hx +++ b/openfl/display/BitmapData.hx @@ -200,7 +200,10 @@ class BitmapData implements IBitmapDrawable { } - __createUVs (); + __createUVs (); + + __worldTransform = new Matrix(); + __worldColorTransform = new ColorTransform(); } @@ -576,7 +579,7 @@ class BitmapData implements IBitmapDrawable { var renderSession = @:privateAccess Lib.current.stage.__renderer.renderSession; - __drawGL(renderSession, width, height, source, matrix, colorTransform, blendMode, clipRect, smoothing, __framebuffer == null || !__usingFramebuffer, false, true); + __drawGL(renderSession, width, height, source, matrix, colorTransform, blendMode, clipRect, smoothing, !__usingFramebuffer, false, true); default: @@ -1506,29 +1509,18 @@ class BitmapData implements IBitmapDrawable { } - @:noCompletion private function __createUVs (?verticalFlip:Bool = false):Void { + @:noCompletion private function __createUVs ():Void { if (__uvData == null) __uvData = new TextureUvs(); - if (verticalFlip) { - __uvData.x0 = 0; - __uvData.y0 = 1; - __uvData.x1 = 1; - __uvData.y1 = 1; - __uvData.x2 = 1; - __uvData.y2 = 0; - __uvData.x3 = 0; - __uvData.y3 = 0; - } else { - __uvData.x0 = 0; - __uvData.y0 = 0; - __uvData.x1 = 1; - __uvData.y1 = 0; - __uvData.x2 = 1; - __uvData.y2 = 1; - __uvData.x3 = 0; - __uvData.y3 = 1; - } + __uvData.x0 = 0; + __uvData.y0 = 0; + __uvData.x1 = 1; + __uvData.y1 = 0; + __uvData.x2 = 1; + __uvData.y2 = 1; + __uvData.x3 = 0; + __uvData.y3 = 1; } @@ -1654,8 +1646,6 @@ class BitmapData implements IBitmapDrawable { @:noCompletion @:dox(hide) public function __renderGL (renderSession:RenderSession):Void { - if (__worldTransform == null) __worldTransform = new Matrix(); - if (__worldColorTransform == null) __worldColorTransform = new ColorTransform(); renderSession.spriteBatch.renderBitmapData(this, true, __worldTransform, __worldColorTransform, __worldColorTransform.alphaMultiplier, blendMode); } @@ -1697,8 +1687,10 @@ class BitmapData implements IBitmapDrawable { if (clearBuffer || drawSelf) { __framebuffer.clear(); } - + if (drawSelf) { + __worldTransform.identity(); + __flipMatrix(__worldTransform); this.__renderGL(renderSession); spritebatch.stop(); gl.deleteTexture(__texture); @@ -1711,15 +1703,8 @@ class BitmapData implements IBitmapDrawable { var cached = source.__cacheAsBitmap; var m = matrix != null ? matrix.clone() : new Matrix (); - - var tx = m.tx; - var ty = m.ty; - m.tx = 0; - m.ty = 0; - m.scale(1, -1); - m.translate(0, height); - m.tx += tx; - m.ty -= ty; + + __flipMatrix(m); source.__worldTransform = m; source.__worldColorTransform = colorTransform != null ? colorTransform : new ColorTransform(); @@ -1766,11 +1751,24 @@ class BitmapData implements IBitmapDrawable { __image.dirty = false; __image.premultiplied = true; } - __createUVs(false); + __createUVs(); __isValid = true; } + @:noCompletion @:dox(hide) private inline function __flipMatrix (m:Matrix):Void { + + var tx = m.tx; + var ty = m.ty; + m.tx = 0; + m.ty = 0; + m.scale(1, -1); + m.translate(0, height); + m.tx += tx; + m.ty -= ty; + + } + @:noCompletion @:dox(hide) public function __renderMask (renderSession:RenderSession):Void { From ab45837d939e912dc5eb94394badd5837112ad36 Mon Sep 17 00:00:00 2001 From: vroad Date: Sat, 25 Apr 2015 18:16:10 +0900 Subject: [PATCH 069/150] Fix conditional compilation problems on nodejs --- openfl/Assets.hx | 2 +- openfl/Lib.hx | 6 +++--- .../_internal/renderer/canvas/CanvasBitmap.hx | 2 +- .../renderer/canvas/CanvasGraphics.hx | 20 +++++++++---------- .../_internal/renderer/canvas/CanvasShape.hx | 2 +- .../renderer/canvas/CanvasTextField.hx | 10 +++++----- openfl/_internal/renderer/dom/DOMBitmap.hx | 8 ++++---- openfl/_internal/renderer/dom/DOMRenderer.hx | 8 ++++---- openfl/_internal/renderer/dom/DOMShape.hx | 4 ++-- openfl/_internal/renderer/dom/DOMTextField.hx | 4 ++-- .../renderer/opengl/utils/GraphicsRenderer.hx | 2 +- openfl/display/Bitmap.hx | 4 ++-- openfl/display/BitmapData.hx | 16 +++++++-------- openfl/display/DisplayObject.hx | 4 ++-- openfl/display/Graphics.hx | 8 ++++---- openfl/display/OpenGLView.hx | 4 ++-- openfl/display/Stage.hx | 6 +++--- openfl/display3D/Context3D.hx | 10 +++++----- openfl/display3D/textures/RectangleTexture.hx | 4 ++-- openfl/display3D/textures/Texture.hx | 2 +- openfl/events/TouchEvent.hx | 2 +- openfl/external/ExternalInterface.hx | 4 ++-- openfl/filters/BitmapFilter.hx | 4 ++-- openfl/filters/ColorMatrixFilter.hx | 4 ++-- openfl/media/Video.hx | 2 +- openfl/net/SharedObject.hx | 12 +++++------ openfl/net/Socket.hx | 12 +++++------ openfl/net/URLLoader.hx | 10 +++++----- openfl/net/XMLSocket.hx | 2 +- openfl/sensors/Accelerometer.hx | 2 +- openfl/system/Capabilities.hx | 8 ++++---- openfl/text/TextField.hx | 16 +++++++-------- openfl/ui/Multitouch.hx | 4 ++-- openfl/utils/Timer.hx | 6 +++--- 34 files changed, 107 insertions(+), 107 deletions(-) diff --git a/openfl/Assets.hx b/openfl/Assets.hx index 6228a3eded..0a383523cf 100644 --- a/openfl/Assets.hx +++ b/openfl/Assets.hx @@ -442,7 +442,7 @@ class Assets { private static function isValidSound (sound:Sound):Bool { #if (tools && !display) - #if (cpp || neko) + #if (cpp || neko || nodejs) return true; //return (sound.__handle != null && sound.__handle != 0); diff --git a/openfl/Lib.hx b/openfl/Lib.hx index 56c15f147f..1481e35d15 100644 --- a/openfl/Lib.hx +++ b/openfl/Lib.hx @@ -8,7 +8,7 @@ import openfl.display.MovieClip; import openfl.display.Stage; import openfl.net.URLRequest; -#if js +#if (js && html5) import js.Browser; #end @@ -96,7 +96,7 @@ import js.Browser; } - #if js + #if (js && html5) Browser.window.open (request.url, target); #elseif flash return flash.Lib.getURL (request, target); @@ -120,7 +120,7 @@ import js.Browser; public static function preventDefaultTouchMove ():Void { - #if js + #if (js && html5) Browser.document.addEventListener ("touchmove", function (evt:js.html.Event):Void { evt.preventDefault (); diff --git a/openfl/_internal/renderer/canvas/CanvasBitmap.hx b/openfl/_internal/renderer/canvas/CanvasBitmap.hx index 1f25291369..aab7d73315 100644 --- a/openfl/_internal/renderer/canvas/CanvasBitmap.hx +++ b/openfl/_internal/renderer/canvas/CanvasBitmap.hx @@ -13,7 +13,7 @@ class CanvasBitmap { public static inline function render (bitmap:Bitmap, renderSession:RenderSession):Void { - #if js + #if (js && html5) if (!bitmap.__renderable || bitmap.__worldAlpha <= 0) return; var context = renderSession.context; diff --git a/openfl/_internal/renderer/canvas/CanvasGraphics.hx b/openfl/_internal/renderer/canvas/CanvasGraphics.hx index 260c6aa894..ec5c76ca82 100644 --- a/openfl/_internal/renderer/canvas/CanvasGraphics.hx +++ b/openfl/_internal/renderer/canvas/CanvasGraphics.hx @@ -12,7 +12,7 @@ import openfl.geom.Rectangle; import openfl.Lib; import openfl.Vector; -#if js +#if (js && html5) import js.html.CanvasElement; import js.html.CanvasPattern; import js.html.CanvasRenderingContext2D; @@ -41,7 +41,7 @@ class CanvasGraphics { private static var positionY:Float; private static var setFill:Bool; - #if js + #if (js && html5) private static var context:CanvasRenderingContext2D; private static var pattern:CanvasPattern; #end @@ -49,7 +49,7 @@ class CanvasGraphics { private static function beginPath ():Void { - #if js + #if (js && html5) if (!inPath) { context.beginPath (); @@ -63,7 +63,7 @@ class CanvasGraphics { private static function beginPatternFill (bitmapFill:BitmapData, bitmapRepeat:Bool):Void { - #if js + #if (js && html5) if (setFill || bitmapFill == null) return; if (pattern == null) { @@ -81,7 +81,7 @@ class CanvasGraphics { private static function closePath (closeFill:Bool):Void { - #if js + #if (js && html5) if (inPath) { if (hasFill) { @@ -131,7 +131,7 @@ class CanvasGraphics { private static function drawRoundRect (x:Float, y:Float, width:Float, height:Float, rx:Float, ry:Float):Void { - #if js + #if (js && html5) if (ry == -1) ry = rx; rx *= 0.5; @@ -165,7 +165,7 @@ class CanvasGraphics { } - /*#if js + /*#if (js && html5) private static inline function setFillStyle(data:DrawPath, context:CanvasRenderingContext2D, worldAlpha:Float) { if (data.hasFill) { @@ -184,7 +184,7 @@ class CanvasGraphics { public static function renderObjectGraphics(object:DisplayObject, renderSession:RenderSession):Void { - #if js + #if (js && html5) var worldAlpha = object.__worldAlpha; var graphics = object.__graphics; @@ -358,7 +358,7 @@ class CanvasGraphics { public static function render (graphics:Graphics, renderSession:RenderSession):Void { - #if js + #if (js && html5) if (graphics.__dirty) { @@ -1012,7 +1012,7 @@ class CanvasGraphics { private static function createTempPatternCanvas(bitmap:BitmapData, repeat:Bool, width:Float, height:Float) { - #if js + #if (js && html5) var canvas:CanvasElement = cast Browser.document.createElement ("canvas"); var context:CanvasRenderingContext2D = canvas.getContext ("2d"); diff --git a/openfl/_internal/renderer/canvas/CanvasShape.hx b/openfl/_internal/renderer/canvas/CanvasShape.hx index 56bd3afcce..ccbeb39022 100644 --- a/openfl/_internal/renderer/canvas/CanvasShape.hx +++ b/openfl/_internal/renderer/canvas/CanvasShape.hx @@ -12,7 +12,7 @@ class CanvasShape { public static inline function render (shape:DisplayObject, renderSession:RenderSession):Void { - #if js + #if (js && html5) if (!shape.__renderable || shape.__worldAlpha <= 0) return; var graphics = shape.__graphics; diff --git a/openfl/_internal/renderer/canvas/CanvasTextField.hx b/openfl/_internal/renderer/canvas/CanvasTextField.hx index fc058957ea..ed51fac215 100644 --- a/openfl/_internal/renderer/canvas/CanvasTextField.hx +++ b/openfl/_internal/renderer/canvas/CanvasTextField.hx @@ -7,7 +7,7 @@ import openfl.text.TextFieldAutoSize; import openfl.text.TextFormat; import openfl.text.TextFormatAlign; -#if js +#if (js && html5) import js.html.CanvasRenderingContext2D; import js.Browser; #end @@ -18,14 +18,14 @@ import js.Browser; class CanvasTextField { - #if js + #if (js && html5) private static var context:CanvasRenderingContext2D; #end public static inline function render (textField:TextField, renderSession:RenderSession):Void { - #if js + #if (js && html5) if (!textField.__renderable || textField.__worldAlpha <= 0) return; @@ -68,7 +68,7 @@ class CanvasTextField { private static inline function renderText (textField:TextField, text:String, format:TextFormat, offsetX:Float):Void { - #if js + #if (js && html5) context.font = textField.__getFont (format); context.textBaseline = "top"; @@ -182,7 +182,7 @@ class CanvasTextField { public static function update (textField:TextField):Bool { - #if js + #if (js && html5) if (textField.__dirty) { diff --git a/openfl/_internal/renderer/dom/DOMBitmap.hx b/openfl/_internal/renderer/dom/DOMBitmap.hx index b54dc2cce6..0db98f664b 100644 --- a/openfl/_internal/renderer/dom/DOMBitmap.hx +++ b/openfl/_internal/renderer/dom/DOMBitmap.hx @@ -5,7 +5,7 @@ import lime.graphics.ImageBuffer; import openfl._internal.renderer.RenderSession; import openfl.display.Bitmap; -#if js +#if (js && html5) import js.Browser; #end @@ -19,7 +19,7 @@ class DOMBitmap { public static inline function render (bitmap:Bitmap, renderSession:RenderSession):Void { - #if js + #if (js && html5) if (bitmap.stage != null && bitmap.__worldVisible && bitmap.__renderable && bitmap.bitmapData != null && bitmap.bitmapData.__isValid) { if (bitmap.bitmapData.__image.buffer.__srcImage != null) { @@ -58,7 +58,7 @@ class DOMBitmap { private static function renderCanvas (bitmap:Bitmap, renderSession:RenderSession):Void { - #if js + #if (js && html5) if (bitmap.__image != null) { renderSession.element.removeChild (bitmap.__image); @@ -99,7 +99,7 @@ class DOMBitmap { private static function renderImage (bitmap:Bitmap, renderSession:RenderSession):Void { - #if js + #if (js && html5) if (bitmap.__canvas != null) { renderSession.element.removeChild (bitmap.__canvas); diff --git a/openfl/_internal/renderer/dom/DOMRenderer.hx b/openfl/_internal/renderer/dom/DOMRenderer.hx index 1f03fd92e4..59bcff6717 100644 --- a/openfl/_internal/renderer/dom/DOMRenderer.hx +++ b/openfl/_internal/renderer/dom/DOMRenderer.hx @@ -7,7 +7,7 @@ import openfl._internal.renderer.RenderSession; import openfl.display.DisplayObject; import openfl.display.Stage; -#if js +#if (js && html5) import js.html.Element; #end @@ -31,7 +31,7 @@ class DOMRenderer extends AbstractRenderer { renderSession.element = element; renderSession.roundPixels = true; - #if js + #if (js && html5) var prefix = untyped __js__ ("(function () { var styles = window.getComputedStyle(document.documentElement, ''), pre = (Array.prototype.slice @@ -60,7 +60,7 @@ class DOMRenderer extends AbstractRenderer { public static function applyStyle (displayObject:DisplayObject, renderSession:RenderSession, setTransform:Bool, setAlpha:Bool, setClip:Bool):Void { - #if js + #if (js && html5) var style = displayObject.__style; if (setTransform && displayObject.__worldTransformChanged) { @@ -109,7 +109,7 @@ class DOMRenderer extends AbstractRenderer { } - #if js + #if (js && html5) public static function initializeElement (displayObject:DisplayObject, element:Element, renderSession:RenderSession):Void { var style = displayObject.__style = element.style; diff --git a/openfl/_internal/renderer/dom/DOMShape.hx b/openfl/_internal/renderer/dom/DOMShape.hx index a20362a818..ce9bb5656e 100644 --- a/openfl/_internal/renderer/dom/DOMShape.hx +++ b/openfl/_internal/renderer/dom/DOMShape.hx @@ -5,7 +5,7 @@ import openfl._internal.renderer.canvas.CanvasGraphics; import openfl.display.DisplayObject; import openfl.geom.Matrix; -#if js +#if (js && html5) import js.Browser; #end @@ -18,7 +18,7 @@ class DOMShape { public static inline function render (shape:DisplayObject, renderSession:RenderSession):Void { - #if js + #if (js && html5) var graphics = shape.__graphics; if (shape.stage != null && shape.__worldVisible && shape.__renderable && graphics != null) { diff --git a/openfl/_internal/renderer/dom/DOMTextField.hx b/openfl/_internal/renderer/dom/DOMTextField.hx index 97c24f51fb..25a12fb080 100644 --- a/openfl/_internal/renderer/dom/DOMTextField.hx +++ b/openfl/_internal/renderer/dom/DOMTextField.hx @@ -6,7 +6,7 @@ import openfl.text.TextField; import openfl.text.TextFieldAutoSize; import openfl.text.TextFormatAlign; -#if js +#if (js && html5) import js.Browser; #end @@ -18,7 +18,7 @@ class DOMTextField { public static inline function render (textField:TextField, renderSession:RenderSession):Void { - #if js + #if (js && html5) if (textField.stage != null && textField.__worldVisible && textField.__renderable) { diff --git a/openfl/_internal/renderer/opengl/utils/GraphicsRenderer.hx b/openfl/_internal/renderer/opengl/utils/GraphicsRenderer.hx index 691e279726..c3e078b09a 100644 --- a/openfl/_internal/renderer/opengl/utils/GraphicsRenderer.hx +++ b/openfl/_internal/renderer/opengl/utils/GraphicsRenderer.hx @@ -1194,7 +1194,7 @@ class GraphicsRenderer { gl.bindTexture(gl.TEXTURE_2D, bucket.texture); // TODO Fix this: webgl can only repeat textures that are power of two - if (bucket.textureRepeat #if js && bucket.bitmap.__image.powerOfTwo #end) { + if (bucket.textureRepeat #if (js && html5) && bucket.bitmap.__image.powerOfTwo #end) { gl.texParameteri (gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); gl.texParameteri (gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); } else { diff --git a/openfl/display/Bitmap.hx b/openfl/display/Bitmap.hx index 74b64ea6c3..add1fecc6e 100644 --- a/openfl/display/Bitmap.hx +++ b/openfl/display/Bitmap.hx @@ -9,7 +9,7 @@ import openfl.geom.Matrix; import openfl.geom.Point; import openfl.geom.Rectangle; -#if js +#if (js && html5) import js.html.ImageElement; #end @@ -86,7 +86,7 @@ class Bitmap extends DisplayObjectContainer { */ public var smoothing:Bool; - #if js + #if (js && html5) @:noCompletion private var __image:ImageElement; #end diff --git a/openfl/display/BitmapData.hx b/openfl/display/BitmapData.hx index f764b0b960..64512259c2 100644 --- a/openfl/display/BitmapData.hx +++ b/openfl/display/BitmapData.hx @@ -23,7 +23,7 @@ import openfl.geom.Rectangle; import openfl.utils.ByteArray; import openfl.Vector; -#if js +#if (js && html5) import js.html.CanvasElement; import js.html.CanvasRenderingContext2D; import js.html.ImageData; @@ -237,14 +237,14 @@ class BitmapData implements IBitmapDrawable { if (!__isValid || sourceBitmapData == null || !sourceBitmapData.__isValid) return; - #if js + #if (js && html5) ImageCanvasUtil.convertToCanvas (__image); ImageCanvasUtil.createImageData (__image); ImageCanvasUtil.convertToCanvas (sourceBitmapData.__image); ImageCanvasUtil.createImageData (sourceBitmapData.__image); #end - #if js + #if (js && html5) filter.__applyFilter (__image.buffer.__srcImageData, sourceBitmapData.__image.buffer.__srcImageData, sourceRect, destPoint); #end @@ -542,7 +542,7 @@ class BitmapData implements IBitmapDrawable { ImageCanvasUtil.convertToCanvas (__image); ImageCanvasUtil.sync (__image); - #if js + #if (js && html5) var buffer = __image.buffer; var renderSession = new RenderSession (); @@ -668,7 +668,7 @@ class BitmapData implements IBitmapDrawable { } - #if js + #if (js && html5) public static function fromCanvas (canvas:CanvasElement, transparent:Bool = true):BitmapData { var bitmapData = new BitmapData (0, 0, transparent); @@ -1557,7 +1557,7 @@ class BitmapData implements IBitmapDrawable { if (rawAlpha != null) { - #if js + #if (js && html5) ImageCanvasUtil.convertToCanvas (__image); ImageCanvasUtil.createImageData (__image); #end @@ -1616,7 +1616,7 @@ class BitmapData implements IBitmapDrawable { @:noCompletion @:dox(hide) public function __renderCanvas (renderSession:RenderSession):Void { - #if js + #if (js && html5) if (!__isValid) return; ImageCanvasUtil.sync (__image); @@ -1786,7 +1786,7 @@ class BitmapData implements IBitmapDrawable { @:noCompletion private function __sync ():Void { - #if js + #if (js && html5) ImageCanvasUtil.sync (__image); #end diff --git a/openfl/display/DisplayObject.hx b/openfl/display/DisplayObject.hx index 6821252007..4dff88c653 100644 --- a/openfl/display/DisplayObject.hx +++ b/openfl/display/DisplayObject.hx @@ -20,7 +20,7 @@ import openfl.geom.Rectangle; import openfl.geom.Transform; import openfl.Lib; -#if js +#if (js && html5) import js.html.CanvasElement; import js.html.CanvasRenderingContext2D; import js.html.CSSStyleDeclaration; @@ -743,7 +743,7 @@ class DisplayObject extends EventDispatcher implements IBitmapDrawable { @:noCompletion private var __y:Float; @:noCompletion private var __cacheAsBitmap:Bool = false; - #if js + #if (js && html5) @:noCompletion private var __canvas:CanvasElement; @:noCompletion private var __context:CanvasRenderingContext2D; @:noCompletion private var __style:CSSStyleDeclaration; diff --git a/openfl/display/Graphics.hx b/openfl/display/Graphics.hx index f74fb86398..1baa54dfdc 100644 --- a/openfl/display/Graphics.hx +++ b/openfl/display/Graphics.hx @@ -12,7 +12,7 @@ import openfl.geom.Point; import openfl.geom.Rectangle; import openfl.Vector; -#if js +#if (js && html5) import js.html.CanvasElement; import js.html.CanvasRenderingContext2D; #end @@ -58,7 +58,7 @@ class Graphics { @:noCompletion private var __cachedTexture:FilterTexture; @:noCompletion private var __owner:DisplayObject; - #if js + #if (js && html5) @:noCompletion private var __canvas:CanvasElement; @:noCompletion private var __context:CanvasRenderingContext2D; #end @@ -71,7 +71,7 @@ class Graphics { __positionX = 0; __positionY = 0; - #if js + #if (js && html5) moveTo( 0, 0); #end } @@ -249,7 +249,7 @@ class Graphics { __visible = false; - #if js + #if (js && html5) moveTo( 0, 0); #end } diff --git a/openfl/display/OpenGLView.hx b/openfl/display/OpenGLView.hx index 31185ca587..44da04fc57 100644 --- a/openfl/display/OpenGLView.hx +++ b/openfl/display/OpenGLView.hx @@ -10,7 +10,7 @@ import openfl.geom.Rectangle; import openfl.gl.GL; import openfl.Lib; -#if js +#if (js && html5) import js.html.CanvasElement; import js.Browser; #end @@ -92,7 +92,7 @@ class OpenGLView extends DirectRenderer { #if !flash @:noCompletion public override function __renderDOM (renderSession:RenderSession):Void { - #if js + #if (js && html5) if (stage != null && __worldVisible && __renderable) { if (!__added) { diff --git a/openfl/display/Stage.hx b/openfl/display/Stage.hx index 429d210d96..01a14865b6 100644 --- a/openfl/display/Stage.hx +++ b/openfl/display/Stage.hx @@ -36,7 +36,7 @@ import openfl.text.TextField; import openfl.ui.Keyboard; import openfl.ui.KeyLocation; -#if js +#if (js && html5) import js.html.CanvasElement; import js.html.DivElement; import js.html.Element; @@ -540,7 +540,7 @@ class Stage extends DisplayObjectContainer implements IModule { @:noCompletion private var __transparent:Bool; @:noCompletion private var __wasDirty:Bool; - #if js + #if (js && html5) //@:noCompletion private var __div:DivElement; //@:noCompletion private var __element:HtmlElement; #if stats @@ -1512,7 +1512,7 @@ class Stage extends DisplayObjectContainer implements IModule { - #if js + #if (js && html5) @:noCompletion private function canvas_onContextLost (event:js.html.webgl.ContextEvent):Void { //__glContextLost = true; diff --git a/openfl/display3D/Context3D.hx b/openfl/display3D/Context3D.hx index fea746fbb8..74c75ac9e8 100755 --- a/openfl/display3D/Context3D.hx +++ b/openfl/display3D/Context3D.hx @@ -99,7 +99,7 @@ class Context3D { } - #if (cpp || neko) + #if (cpp || neko || nodejs) GL.depthMask (true); #end GL.clearColor (red, green, blue, alpha); @@ -489,7 +489,7 @@ class Context3D { GL.disableVertexAttribArray (location); - #if (cpp || neko) + #if (cpp || neko || nodejs) GL.bindBuffer (GL.ARRAY_BUFFER, null); #end @@ -777,7 +777,7 @@ class Context3D { if (Std.is (texture, Texture)) { - #if (cpp || neko) + #if (cpp || neko || nodejs) GL.bindTexture (GL.TEXTURE_2D, cast (texture, Texture).glTexture); #end @@ -854,7 +854,7 @@ class Context3D { } else if (Std.is (texture, RectangleTexture)) { - #if (cpp || neko) + #if (cpp || neko || nodejs) GL.bindTexture (GL.TEXTURE_2D, cast(texture, RectangleTexture).glTexture); #end @@ -901,7 +901,7 @@ class Context3D { } else if (Std.is (texture, CubeTexture)) { - #if (cpp || neko) + #if (cpp || neko || nodejs) GL.bindTexture (GL.TEXTURE_CUBE_MAP, cast (texture, CubeTexture).glTexture); #end diff --git a/openfl/display3D/textures/RectangleTexture.hx b/openfl/display3D/textures/RectangleTexture.hx index 13547f9097..60da190043 100755 --- a/openfl/display3D/textures/RectangleTexture.hx +++ b/openfl/display3D/textures/RectangleTexture.hx @@ -25,7 +25,7 @@ class RectangleTexture extends TextureBase { super (glTexture, width, height); - #if (cpp || neko) + #if (cpp || neko || nodejs) if (optimizeForRenderToTexture) GL.pixelStorei(GL.UNPACK_FLIP_Y_WEBGL, 1); @@ -67,7 +67,7 @@ class RectangleTexture extends TextureBase { GL.bindTexture (GL.TEXTURE_2D, glTexture); - #if js + #if (js && html5) if (optimizeForRenderToTexture) GL.pixelStorei(GL.UNPACK_FLIP_Y_WEBGL, 1); diff --git a/openfl/display3D/textures/Texture.hx b/openfl/display3D/textures/Texture.hx index a758f5395c..f25af8de0a 100755 --- a/openfl/display3D/textures/Texture.hx +++ b/openfl/display3D/textures/Texture.hx @@ -28,7 +28,7 @@ class Texture extends TextureBase { super (glTexture, width, height); - #if (cpp || neko) + #if (cpp || neko || nodejs) if (optimizeForRenderToTexture) { GL.pixelStorei (GL.UNPACK_FLIP_Y_WEBGL, 1); diff --git a/openfl/events/TouchEvent.hx b/openfl/events/TouchEvent.hx index a4059e58ca..fe5ff7f2d5 100644 --- a/openfl/events/TouchEvent.hx +++ b/openfl/events/TouchEvent.hx @@ -269,7 +269,7 @@ class TouchEvent extends Event { @:noCompletion public static function __create (type:String, /*event:lime.ui.TouchEvent,*/ touch:Dynamic /*js.html.Touch*/, stageX:Float, stageY:Float, local:Point, target:InteractiveObject):TouchEvent { - #if js + #if (js && html5) var evt = new TouchEvent (type, true, false, local.x, local.y, null, false, false, false/*event.ctrlKey, event.altKey, event.shiftKey*/, false /* note: buttonDown not supported on w3c spec */, 0, 0); evt.stageX = stageX; diff --git a/openfl/external/ExternalInterface.hx b/openfl/external/ExternalInterface.hx index fdbdfc0fa1..c0dcaf8f1c 100644 --- a/openfl/external/ExternalInterface.hx +++ b/openfl/external/ExternalInterface.hx @@ -167,7 +167,7 @@ class ExternalInterface { */ public static function addCallback (functionName:String, closure:Dynamic):Void { - #if js + #if (js && html5) if (Lib.application.window.backend.element != null) { untyped Lib.application.window.backend.element[functionName] = closure; @@ -251,7 +251,7 @@ class ExternalInterface { */ public static function call (functionName:String, ?p1:Dynamic, ?p2:Dynamic, ?p3:Dynamic, ?p4:Dynamic, ?p5:Dynamic):Dynamic { - #if js + #if (js && html5) var callResponse:Dynamic = null; var thisArg = functionName.split('.').slice(0, -1).join('.'); diff --git a/openfl/filters/BitmapFilter.hx b/openfl/filters/BitmapFilter.hx index 0485948993..53b8c1f69b 100644 --- a/openfl/filters/BitmapFilter.hx +++ b/openfl/filters/BitmapFilter.hx @@ -4,7 +4,7 @@ package openfl.filters; #if !flash #if !openfl_legacy import openfl.geom.Point; import openfl.geom.Rectangle; -#if js +#if (js && html5) import js.html.ImageData; #end @@ -42,7 +42,7 @@ class BitmapFilter { } - #if js + #if (js && html5) @:noCompletion public function __applyFilter (sourceData:ImageData, targetData:ImageData, sourceRect:Rectangle, destPoint:Point):Void { diff --git a/openfl/filters/ColorMatrixFilter.hx b/openfl/filters/ColorMatrixFilter.hx index b8397a8380..b96c382dab 100644 --- a/openfl/filters/ColorMatrixFilter.hx +++ b/openfl/filters/ColorMatrixFilter.hx @@ -4,7 +4,7 @@ package openfl.filters; #if !flash #if !openfl_legacy import openfl.geom.Point; import openfl.geom.Rectangle; -#if js +#if (js && html5) import js.html.ImageData; #end @@ -38,7 +38,7 @@ class ColorMatrixFilter extends BitmapFilter { } - #if js + #if (js && html5) @:noCompletion public override function __applyFilter (sourceData:ImageData, targetData:ImageData, sourceRect:Rectangle, destPoint:Point):Void { var source = sourceData.data; diff --git a/openfl/media/Video.hx b/openfl/media/Video.hx index ad2fe051e6..f2cfe52220 100644 --- a/openfl/media/Video.hx +++ b/openfl/media/Video.hx @@ -9,7 +9,7 @@ import openfl.geom.Point; import openfl.geom.Rectangle; import openfl.net.NetStream; -#if js +#if (js && html5) import openfl._internal.renderer.dom.DOMRenderer; import js.html.MediaElement; import js.Browser; diff --git a/openfl/net/SharedObject.hx b/openfl/net/SharedObject.hx index 90537b93db..274c3a5e16 100644 --- a/openfl/net/SharedObject.hx +++ b/openfl/net/SharedObject.hx @@ -9,7 +9,7 @@ import openfl.events.EventDispatcher; import openfl.net.SharedObjectFlushStatus; import openfl.Lib; -#if js +#if (js && html5) import js.html.Storage; import js.Browser; #end @@ -208,7 +208,7 @@ class SharedObject extends EventDispatcher { data = { }; - #if js + #if (js && html5) try { __getLocalStorage ().removeItem (__key); @@ -279,7 +279,7 @@ class SharedObject extends EventDispatcher { */ public function flush (minDiskSpace:Int = 0):SharedObjectFlushStatus { - #if js + #if (js && html5) var data = Serializer.run (data); try { @@ -452,7 +452,7 @@ class SharedObject extends EventDispatcher { */ public static function getLocal (name:String, localPath:String = null, secure:Bool = false /* note: unsupported */) { - #if js + #if (js && html5) if (localPath == null) { localPath = Browser.window.location.href; @@ -464,7 +464,7 @@ class SharedObject extends EventDispatcher { so.__key = localPath + ":" + name; var rawData = null; - #if js + #if (js && html5) try { // user may have privacy settings which prevent reading @@ -494,7 +494,7 @@ class SharedObject extends EventDispatcher { } - #if js + #if (js && html5) @:noCompletion private static function __getLocalStorage ():Storage { var res = Browser.getLocalStorage (); diff --git a/openfl/net/Socket.hx b/openfl/net/Socket.hx index cf085bab47..9c6c0ddd8e 100644 --- a/openfl/net/Socket.hx +++ b/openfl/net/Socket.hx @@ -86,7 +86,7 @@ class Socket extends EventDispatcher /*implements IDataInput implements IDataOut if( port < 0 || port > 65535 ) throw new SecurityError("Invalid socket port number specified."); - #if js + #if (js && html5) _stamp = haxe.Timer.stamp(); #else var h : Host = null; @@ -107,12 +107,12 @@ class Socket extends EventDispatcher /*implements IDataInput implements IDataOut _output.endian = endian; _input = new ByteArray(); _input.endian = endian; - #if js + #if (js && html5) _inputBuffer = new ByteArray(); _inputBuffer.endian = endian; #end - #if js + #if (js && html5) _socket = untyped __js__("new WebSocket(\"ws://\" + host + \":\" + port)"); _socket.onopen = onOpenHandler; @@ -134,7 +134,7 @@ class Socket extends EventDispatcher /*implements IDataInput implements IDataOut } @:noCompletion private function onFrame( _ ){ - #if js + #if (js && html5) if (_inputBuffer.bytesAvailable > 0) { var newInput = new ByteArray(); @@ -360,7 +360,7 @@ class Socket extends EventDispatcher /*implements IDataInput implements IDataOut } //public function writeObject( object:Dynamic ):Void { _output.writeObject(object); } - #if js + #if (js && html5) @:noCompletion private function onOpenHandler (_):Void { _connected = true; dispatchEvent (new Event (Event.CONNECT)); @@ -390,7 +390,7 @@ class Socket extends EventDispatcher /*implements IDataInput implements IDataOut throw new IOError("Operation attempted on invalid socket."); if( _output.length > 0 ){ try { - #if js + #if (js && html5) _socket.send( _output.__getBuffer() ); #else _socket.output.write( _output ); diff --git a/openfl/net/URLLoader.hx b/openfl/net/URLLoader.hx index b4a989bd0b..66138e9a80 100644 --- a/openfl/net/URLLoader.hx +++ b/openfl/net/URLLoader.hx @@ -10,7 +10,7 @@ import openfl.errors.IOError; import openfl.events.SecurityErrorEvent; import openfl.utils.ByteArray; -#if js +#if (js && html5) import js.html.EventTarget; import js.html.XMLHttpRequest; import js.Browser; @@ -297,14 +297,14 @@ class URLLoader extends EventDispatcher { */ public function load (request:URLRequest):Void { - #if js + #if (js && html5) requestUrl (request.url, request.method, request.data, request.formatRequestHeaders ()); #end } - #if js + #if (js && html5) @:noCompletion private function registerEvents (subject:EventTarget):Void { var self = this; @@ -478,7 +478,7 @@ class URLLoader extends EventDispatcher { @:noCompletion private function onData (_):Void { - #if js + #if (js && html5) var content:Dynamic = getData (); switch (dataFormat) { @@ -554,7 +554,7 @@ class URLLoader extends EventDispatcher { @:noCompletion private function set_dataFormat (inputVal:URLLoaderDataFormat):URLLoaderDataFormat { - #if js + #if (js && html5) // prevent inadvertently using typed arrays when they are unsupported // @todo move these sorts of tests somewhere common in the vein of Modernizr diff --git a/openfl/net/XMLSocket.hx b/openfl/net/XMLSocket.hx index bc08d986a4..68642470c6 100644 --- a/openfl/net/XMLSocket.hx +++ b/openfl/net/XMLSocket.hx @@ -45,7 +45,7 @@ class XMLSocket extends EventDispatcher { public function connectWithProto (host: String, port:Int, protocol:String):Void { - #if js + #if (js && html5) if (protocol == null) { _socket = untyped __js__("new WebSocket(\"ws://\" + host + \":\" + port)"); } diff --git a/openfl/sensors/Accelerometer.hx b/openfl/sensors/Accelerometer.hx index 0f09a4b55c..371e8fa9d1 100644 --- a/openfl/sensors/Accelerometer.hx +++ b/openfl/sensors/Accelerometer.hx @@ -7,7 +7,7 @@ import openfl.errors.ArgumentError; import openfl.events.AccelerometerEvent; import openfl.events.EventDispatcher; -#if js +#if (js && html5) import js.Browser; #end diff --git a/openfl/system/Capabilities.hx b/openfl/system/Capabilities.hx index bb83d8e5bb..c6c85631e3 100644 --- a/openfl/system/Capabilities.hx +++ b/openfl/system/Capabilities.hx @@ -3,7 +3,7 @@ package openfl.system; #if !flash #if !openfl_legacy import haxe.macro.Compiler; -#if js +#if (js && html5) import js.html.DivElement; import js.html.Element; import js.Browser; @@ -439,7 +439,7 @@ class Capabilities { @:noCompletion private static function get_screenResolutionX ():Float { - #if js + #if (js && html5) return Browser.window.screen.width; @@ -454,7 +454,7 @@ class Capabilities { @:noCompletion private static function get_screenResolutionY ():Float { - #if js + #if (js && html5) return Browser.window.screen.height; @@ -469,7 +469,7 @@ class Capabilities { @:noCompletion private static function get_language ():String { - #if js + #if (js && html5) return untyped navigator.language; diff --git a/openfl/text/TextField.hx b/openfl/text/TextField.hx index 95226b5c30..f0c47ce544 100644 --- a/openfl/text/TextField.hx +++ b/openfl/text/TextField.hx @@ -27,7 +27,7 @@ import openfl.geom.Rectangle; import openfl.text.Font; import openfl.text.TextFormatAlign; -#if js +#if (js && html5) import js.html.CanvasElement; import js.html.CanvasRenderingContext2D; import js.html.CSSStyleDeclaration; @@ -581,7 +581,7 @@ class TextField extends InteractiveObject { @:noCompletion private static var __utf8_endline_code:Int = 10; - #if js + #if (js && html5) private var __div:DivElement; private var __hiddenInput:InputElement; #end @@ -1406,7 +1406,7 @@ class TextField extends InteractiveObject { @:noCompletion private function __measureText (condense:Bool=true):Array { - #if js + #if (js && html5) if (__context == null) { @@ -1435,7 +1435,7 @@ class TextField extends InteractiveObject { } - #elseif (cpp || neko) + #elseif (cpp || neko || nodejs) //the "condense" flag, if true, will return the widths of individual text format ranges, if false will return the widths of each character //TODO: look into whether this method and others can replace the JS stuff yet or not @@ -1549,7 +1549,7 @@ class TextField extends InteractiveObject { @:noCompletion private function __measureTextWithDOM ():Void { - #if js + #if (js && html5) var div:Element = __div; @@ -2088,7 +2088,7 @@ class TextField extends InteractiveObject { @:noCompletion public function get_textWidth ():Float { - #if js + #if (js && html5) if (__canvas != null) { @@ -2114,7 +2114,7 @@ class TextField extends InteractiveObject { } - #elseif (cpp || neko) + #elseif (cpp || neko || nodejs) //return the largest width of any given single line //TODO: need to check actual left/right bounding volume in case of pathological cases (multiple format ranges for instance) @@ -2131,7 +2131,7 @@ class TextField extends InteractiveObject { @:noCompletion public function get_textHeight ():Float { - #if js + #if (js && html5) if (__canvas != null) { diff --git a/openfl/ui/Multitouch.hx b/openfl/ui/Multitouch.hx index 6f0515b541..210390903b 100644 --- a/openfl/ui/Multitouch.hx +++ b/openfl/ui/Multitouch.hx @@ -4,7 +4,7 @@ package openfl.ui; #if !flash #if !openfl_legacy import openfl.ui.MultitouchInputMode; import openfl.Lib; -#if js +#if (js && html5) import js.Browser; #end @@ -149,7 +149,7 @@ class Multitouch { @:noCompletion private static function get_supportsTouchEvents ():Bool { - #if js + #if (js && html5) if (untyped __js__ ("('ontouchstart' in document.documentElement) || (window.DocumentTouch && document instanceof DocumentTouch)")) { return true; diff --git a/openfl/utils/Timer.hx b/openfl/utils/Timer.hx index 2e56a4c6a6..6e6693b0a1 100644 --- a/openfl/utils/Timer.hx +++ b/openfl/utils/Timer.hx @@ -6,7 +6,7 @@ import openfl.errors.Error; import openfl.events.EventDispatcher; import openfl.events.TimerEvent; -#if js +#if (js && html5) import js.Browser; #end @@ -142,7 +142,7 @@ class Timer extends EventDispatcher { running = true; - #if js + #if (js && html5) __timerID = Browser.window.setInterval (timer_onTimer, Std.int (__delay)); #else __timer = new HaxeTimer (__delay); @@ -164,7 +164,7 @@ class Timer extends EventDispatcher { running = false; - #if js + #if (js && html5) if (__timerID != null) { Browser.window.clearInterval (__timerID); From 041edd75ac22d0beae1e0f13ca8dd1ef86e5bc6c Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Mon, 27 Apr 2015 11:40:08 -0700 Subject: [PATCH 070/150] Improve TextField input for mobile browsers, hack to make the rendering of text in Safari/Firefox more consistent --- .../renderer/canvas/CanvasTextField.hx | 14 +++++++-- openfl/text/TextField.hx | 30 ++++++++++++++----- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/openfl/_internal/renderer/canvas/CanvasTextField.hx b/openfl/_internal/renderer/canvas/CanvasTextField.hx index ed51fac215..55d4fd70b3 100644 --- a/openfl/_internal/renderer/canvas/CanvasTextField.hx +++ b/openfl/_internal/renderer/canvas/CanvasTextField.hx @@ -71,8 +71,18 @@ class CanvasTextField { #if (js && html5) context.font = textField.__getFont (format); - context.textBaseline = "top"; context.fillStyle = "#" + StringTools.hex (format.color, 6); + context.textBaseline = "top"; + + var yOffset = 0.0; + + // Hack, baseline "top" is not consistent across browsers + + if (~/(iPad|iPhone|iPod|Firefox)/g.match (Browser.window.navigator.userAgent)) { + + yOffset = format.size * 0.185; + + } var lines = []; @@ -148,8 +158,6 @@ class CanvasTextField { } - var yOffset:Float = 0; - for (line in lines) { switch (format.align) { diff --git a/openfl/text/TextField.hx b/openfl/text/TextField.hx index f0c47ce544..046e7a26ec 100644 --- a/openfl/text/TextField.hx +++ b/openfl/text/TextField.hx @@ -26,6 +26,7 @@ import openfl.geom.Point; import openfl.geom.Rectangle; import openfl.text.Font; import openfl.text.TextFormatAlign; +import openfl.Lib; #if (js && html5) import js.html.CanvasElement; @@ -920,16 +921,27 @@ class TextField extends InteractiveObject { __hiddenInput.type = 'text'; __hiddenInput.style.position = 'absolute'; __hiddenInput.style.opacity = "0"; + __hiddenInput.style.color = "transparent"; + + if (~/(iPad|iPhone|iPod)/g.match (Browser.window.navigator.userAgent)) { + + __hiddenInput.style.fontSize = "0px"; + + } + untyped (__hiddenInput.style).pointerEvents = 'none'; - __hiddenInput.style.left = (x + ((__canvas != null) ? __canvas.offsetLeft : 0)) + 'px'; - __hiddenInput.style.top = (y + ((__canvas != null) ? __canvas.offsetTop : 0)) + 'px'; - __hiddenInput.style.width = __width + 'px'; - __hiddenInput.style.height = __height + 'px'; - __hiddenInput.style.zIndex = "0"; - if (this.maxChars > 0) { + // TODO: Position for mobile browsers better + + __hiddenInput.style.left = "0px"; + __hiddenInput.style.top = "50%"; + __hiddenInput.style.width = '1px'; + __hiddenInput.style.height = '1px'; + __hiddenInput.style.zIndex = "-10000000"; + + if (maxChars > 0) { - __hiddenInput.maxLength = this.maxChars; + __hiddenInput.maxLength = maxChars; } @@ -1774,7 +1786,7 @@ class TextField extends InteractiveObject { __cursorPosition = -1; __hasFocus = false; __stopCursorTimer (); - __hiddenInput.blur (); + if (__hiddenInput != null) __hiddenInput.blur (); __dirty = true; } @@ -1795,6 +1807,8 @@ class TextField extends InteractiveObject { removeEventListener (FocusEvent.FOCUS_IN, this_onFocusIn); removeEventListener (FocusEvent.FOCUS_OUT, this_onFocusOut); + this_onFocusOut (null); + if (__hiddenInput != null) __hiddenInput.removeEventListener ('keydown', input_onKeyDown); if (__hiddenInput != null) __hiddenInput.removeEventListener ('keyup', input_onKeyUp); if (__hiddenInput != null) __hiddenInput.removeEventListener ('input', input_onKeyUp); From aa8af64583541319bd8b2e1cfba0050e06d018a2 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Mon, 27 Apr 2015 14:48:00 -0700 Subject: [PATCH 071/150] Hook up bitmapData getColorBoundsRect (thanks @larsiusprime, close #634) --- openfl/display/BitmapData.hx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openfl/display/BitmapData.hx b/openfl/display/BitmapData.hx index 64512259c2..7107de8d07 100644 --- a/openfl/display/BitmapData.hx +++ b/openfl/display/BitmapData.hx @@ -795,7 +795,9 @@ class BitmapData implements IBitmapDrawable { public function getColorBoundsRect (mask:Int, color:Int, findColor:Bool = true):Rectangle { if (!__isValid) return new Rectangle (0, 0, width, height); - return __image.rect.__toFlashRectangle (); + + var rect = __image.getColorBoundsRect (mask, color, findColor); + return rect.__toFlashRectangle (); } From 7c0b0236eb66c32d35c77ebf624440a39efefcee Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Mon, 27 Apr 2015 14:52:41 -0700 Subject: [PATCH 072/150] Improve internal isValidBitmapData check in Assets (fixes #632, closes #633) --- openfl/Assets.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openfl/Assets.hx b/openfl/Assets.hx index 0a383523cf..ade59e1d57 100644 --- a/openfl/Assets.hx +++ b/openfl/Assets.hx @@ -429,7 +429,7 @@ class Assets { #else - return (bitmapData != null); + return (bitmapData != null && bitmapData.__image != null); #end #end From 9908a4f113011c9a21f542e554dabe5af1d75dce Mon Sep 17 00:00:00 2001 From: Kane Wallmann Date: Sun, 26 Apr 2015 21:52:13 +1000 Subject: [PATCH 073/150] Made canvas renderer more consistent with Flash --- .../renderer/canvas/CanvasGraphics.hx | 1183 ++++++++--------- openfl/display/Graphics.hx | 2 +- 2 files changed, 532 insertions(+), 653 deletions(-) diff --git a/openfl/_internal/renderer/canvas/CanvasGraphics.hx b/openfl/_internal/renderer/canvas/CanvasGraphics.hx index ec5c76ca82..cc1d61ac51 100644 --- a/openfl/_internal/renderer/canvas/CanvasGraphics.hx +++ b/openfl/_internal/renderer/canvas/CanvasGraphics.hx @@ -32,59 +32,316 @@ class CanvasGraphics { private static var TAN22 = 0.4142135623730950488016887242097; private static var bounds:Rectangle; - private static var hasFill:Bool; - private static var hasStroke:Bool; - private static var inPath:Bool; private static var inversePendingMatrix:Matrix; private static var pendingMatrix:Matrix; - private static var positionX:Float; - private static var positionY:Float; - private static var setFill:Bool; + + private static var hasStroke : Bool; + private static var hasFill:Bool; + + private static var bitmapFill:BitmapData; + private static var bitmapRepeat:Bool; + + private static var graphics:Graphics; + + private static var fillCommands:Array; + private static var strokeCommands:Array; #if (js && html5) private static var context:CanvasRenderingContext2D; private static var pattern:CanvasPattern; #end - - - private static function beginPath ():Void { + private static function playCommands( commands : Array, stroke : Bool = false ) + { #if (js && html5) - if (!inPath) { - - context.beginPath (); - inPath = true; - - } - #end - } - - - private static function beginPatternFill (bitmapFill:BitmapData, bitmapRepeat:Bool):Void { + bounds = graphics.__bounds; - #if (js && html5) - if (setFill || bitmapFill == null) return; + var offsetX = bounds.x; + var offsetY = bounds.y; - if (pattern == null) { + var positionX : Float = 0; + var positionY : Float = 0; + + var closeGap : Bool = false; + var startX : Float = 0; + var startY : Float = 0; + + for (command in commands) { + + switch (command) { + + case CubicCurveTo (cx1, cy1, cx2, cy2, x, y): + context.bezierCurveTo (cx1 - offsetX, cy1 - offsetY, cx2 - offsetX, cy2 - offsetY, x - offsetX, y - offsetY); + + case CurveTo (cx, cy, x, y): + context.quadraticCurveTo (cx - offsetX, cy - offsetY, x - offsetX, y - offsetY); + + case DrawCircle (x, y, radius): + + context.moveTo (x - offsetX + radius, y - offsetY); + context.arc (x - offsetX, y - offsetY, radius, 0, Math.PI * 2, true); + + case DrawEllipse (x, y, width, height): + + x -= offsetX; + y -= offsetY; + + var kappa = .5522848, + ox = (width / 2) * kappa, // control point offset horizontal + oy = (height / 2) * kappa, // control point offset vertical + xe = x + width, // x-end + ye = y + height, // y-end + xm = x + width / 2, // x-middle + ym = y + height / 2; // y-middle + + context.moveTo (x, ym); + context.bezierCurveTo (x, ym - oy, xm - ox, y, xm, y); + context.bezierCurveTo (xm + ox, y, xe, ym - oy, xe, ym); + context.bezierCurveTo (xe, ym + oy, xm + ox, ye, xm, ye); + context.bezierCurveTo (xm - ox, ye, x, ym + oy, x, ym); + + + case DrawRoundRect (x, y, width, height, rx, ry): + drawRoundRect (x - offsetX, y - offsetY, width, height, rx, ry); + + case LineTo (x, y): + + context.lineTo (x - offsetX, y - offsetY); + + positionX = x; + positionY = y; + + case MoveTo (x, y): + + context.moveTo (x - offsetX, y - offsetY); + + positionX = x; + positionY = y; + + closeGap = true; + startX = x; + startY = y; + + case LineStyle (thickness, color, alpha, pixelHinting, scaleMode, caps, joints, miterLimit): + + if ( stroke && hasStroke ) + { + context.closePath(); + context.stroke(); + context.beginPath(); + } + + context.moveTo (positionX - offsetX, positionY - offsetY); + + if (thickness == null) { + + hasStroke = false; + + } else { + + context.lineWidth = thickness; + + context.lineJoin = (joints == null ? "round" : Std.string (joints).toLowerCase ()); + context.lineCap = (caps == null ? "round" : switch (caps) { + case CapsStyle.NONE: "butt"; + default: Std.string (caps).toLowerCase (); + }); + + context.miterLimit = (miterLimit == null ? 3 : miterLimit); + + if (alpha == 1 || alpha == null) { + + context.strokeStyle = (color == null ? "#000000" : "#" + StringTools.hex (color & 0x00FFFFFF, 6)); + + } else { + + var r = (color & 0xFF0000) >>> 16; + var g = (color & 0x00FF00) >>> 8; + var b = (color & 0x0000FF); + + context.strokeStyle = (color == null ? "#000000" : "rgba(" + r + ", " + g + ", " + b + ", " + alpha + ")"); + + } + + hasStroke = true; + + } + + case BeginBitmapFill (bitmap, matrix, repeat, smooth): + + if (bitmap != bitmapFill || repeat != bitmapRepeat) { + + bitmapFill = bitmap; + bitmapRepeat = repeat; + pattern = null; + hasFill = false; + + bitmap.__sync (); + + } + + if (matrix != null) { + + pendingMatrix = matrix; + inversePendingMatrix = matrix.clone (); + inversePendingMatrix.invert (); + + } else { + + pendingMatrix = null; + inversePendingMatrix = null; + + } + + case BeginFill (rgb, alpha): + + if ( alpha <= 0.07 ) + { + hasFill = false; + } + else + { + if (alpha == 1) { + + context.fillStyle = "#" + StringTools.hex (rgb, 6); + + } else { + + var r = (rgb & 0xFF0000) >>> 16; + var g = (rgb & 0x00FF00) >>> 8; + var b = (rgb & 0x0000FF); + + context.fillStyle = "rgba(" + r + ", " + g + ", " + b + ", " + alpha + ")"; + + } + + bitmapFill = null; + hasFill = true; + } + + case BeginGradientFill (type, colors, alphas, ratios, matrix, spreadMethod, interpolationMethod, focalPointRatio): + + var gradientFill = null; + + switch (type) { + + case RADIAL: + + if (matrix == null) matrix = new Matrix (); + var point = matrix.transformPoint (new Point (1638.4, 0)); + gradientFill = context.createRadialGradient (matrix.tx, matrix.ty, 0, matrix.tx, matrix.ty, (point.x - matrix.tx) / 2); + + case LINEAR: + + var matrix = matrix != null ? matrix.clone () : new Matrix (); + matrix.tx -= matrix.a * 1638.4 / 2; + matrix.ty -= matrix.d * 1638.4 / 2; + + var point1 = matrix.transformPoint (new Point (0, 0)); + var point2 = matrix.transformPoint (new Point (1638.4, 0)); + + gradientFill = context.createLinearGradient (point1.x, point1.y, point2.x, point2.y); + + } + + for (i in 0...colors.length) { + + var rgb = colors[i]; + var alpha = alphas[i]; + var r = (rgb & 0xFF0000) >>> 16; + var g = (rgb & 0x00FF00) >>> 8; + var b = (rgb & 0x0000FF); + + var ratio = ratios[i] / 0xFF; + if (ratio < 0) ratio = 0; + if (ratio > 1) ratio = 1; + + gradientFill.addColorStop (ratio, "rgba(" + r + ", " + g + ", " + b + ", " + alpha + ")"); + + } + + context.fillStyle = gradientFill; + + bitmapFill = null; + hasFill = true; + + case DrawRect (x, y, width, height): + + var optimizationUsed = false; + + if (bitmapFill != null) { + + var st:Float = 0; + var sr:Float = 0; + var sb:Float = 0; + var sl:Float = 0; + + var canOptimizeMatrix = true; + + if (pendingMatrix != null) { + + if (pendingMatrix.b != 0 || pendingMatrix.c != 0) { + + canOptimizeMatrix = false; + + } else { + + var stl = inversePendingMatrix.transformPoint(new Point(x, y)); + var sbr = inversePendingMatrix.transformPoint(new Point(x + width, y + height)); + + st = stl.y; + sl = stl.x; + sb = sbr.y; + sr = sbr.x; + + } + + } else { + + st = y; + sl = x; + sb = y + height; + sr = x + width; + + } + + if (canOptimizeMatrix && st >= 0 && sl >= 0 && sr <= bitmapFill.width && sb <= bitmapFill.height) { + + optimizationUsed = true; + context.drawImage (bitmapFill.__image.src, sl, st, sr - sl, sb - st, x - offsetX, y - offsetY, width, height); + } + } + + if (!optimizationUsed) { + + context.rect (x - offsetX, y - offsetY, width, height); + } - pattern = context.createPattern (bitmapFill.__image.src, bitmapRepeat ? "repeat" : "no-repeat"); + + + default: + + } + + } + + if ( stroke && hasStroke ) + { + if ( hasFill && closeGap ) + { + context.lineTo (startX - offsetX, startY - offsetY); + } + context.stroke(); } - context.fillStyle = pattern; - setFill = true; - #end - - } - - - private static function closePath (closeFill:Bool):Void { - - #if (js && html5) - if (inPath) { - - if (hasFill) { + if ( !stroke ) + { + if ( hasFill || bitmapFill != null ) + { + if( bitmapFill != null ) + beginPatternFill (bitmapFill, bitmapRepeat); context.translate( -bounds.x, -bounds.y); @@ -101,34 +358,50 @@ class CanvasGraphics { } context.translate (bounds.x, bounds.y); - - } - - context.closePath (); - - if (hasStroke) { - - context.stroke (); - + + context.closePath(); } - } - inPath = false; + #end + } + + private static function fillEnd() + { + #if (js && html5) + context.beginPath(); + playCommands( fillCommands, false ); + fillCommands = []; + #end + } + + private static function strokeEnd() + { + #if (js && html5) + context.beginPath(); + playCommands( strokeCommands, true ); + context.closePath(); + strokeCommands = []; + #end + } + + private static function beginPatternFill (bitmapFill:BitmapData, bitmapRepeat:Bool):Void { + + #if (js && html5) + if (hasFill || bitmapFill == null) return; - if (closeFill) { + if (pattern == null) { - hasFill = false; - hasStroke = false; - pendingMatrix = null; - inversePendingMatrix = null; + pattern = context.createPattern (bitmapFill.__image.src, bitmapRepeat ? "repeat" : "no-repeat"); } + + context.fillStyle = pattern; + hasFill = true; #end } - - + private static function drawRoundRect (x:Float, y:Float, width:Float, height:Float, rx:Float, ry:Float):Void { #if (js && html5) @@ -163,629 +436,116 @@ class CanvasGraphics { #end } - - - /*#if (js && html5) - private static inline function setFillStyle(data:DrawPath, context:CanvasRenderingContext2D, worldAlpha:Float) { - if (data.hasFill) { - - context.globalAlpha = data.fill.alpha * worldAlpha; - if (data.fill.bitmap != null) { - var bitmap = data.fill.bitmap; - var repeat = data.fill.repeat; - var pattern = context.createPattern (bitmap.__image.src, repeat ? "repeat" : "no-repeat"); - context.fillStyle = pattern; - } else { - context.fillStyle = '#' + StringTools.hex(data.fill.color, 6); - } - } - } - #end - - public static function renderObjectGraphics(object:DisplayObject, renderSession:RenderSession):Void { - - #if (js && html5) - - var worldAlpha = object.__worldAlpha; - var graphics = object.__graphics; - - bounds = graphics.__bounds; - - if(!graphics.__dirty) return; - - graphics.__dirty = false; - - if(bounds == null || bounds.width == 0 || bounds.height == 0) { - - graphics.__canvas = null; - graphics.__context = null; - - } else { - - if (graphics.__canvas == null) { - - graphics.__canvas = cast Browser.document.createElement ("canvas"); - graphics.__context = graphics.__canvas.getContext ("2d"); - //untyped (context).mozImageSmoothingEnabled = false; - //untyped (context).webkitImageSmoothingEnabled = false; - //context.imageSmoothingEnabled = false; - - } - - var context = graphics.__context; - - graphics.__canvas.width = Math.ceil (bounds.width); - graphics.__canvas.height = Math.ceil (bounds.height); - - var offsetX = bounds.x; - var offsetY = bounds.y; - - for (i in 0...graphics.__graphicsData.length) { - - var data = graphics.__graphicsData[i]; - var points = data.points; - - context.strokeStyle = '#' + StringTools.hex (data.line.color, 6); - context.lineWidth = data.line.width; - context.lineCap = Std.string(data.line.caps); - context.lineJoin = Std.string(data.line.joints); - context.miterLimit = data.line.miterLimit; - - setFillStyle(data, context, worldAlpha); - - switch(data.type) { - - case Polygon: - - context.beginPath(); - context.moveTo(points[0] - offsetX, points[1] - offsetY); - for(i in 1...Std.int(points.length/2)) { - context.lineTo(points[i * 2] - offsetX, points[i * 2 + 1] - offsetY); - } - context.closePath(); - - if(data.hasFill) { - context.fill(); - } - - if(data.line.width > 0) { - context.globalAlpha = data.line.alpha * worldAlpha; - context.stroke(); - } - - case Rectangle(round): - - var rx = points[0] - offsetX; - var ry = points[1] - offsetY; - var width = points[2]; - var height = points[3]; - - if(round) { - - var radius = points[4]; - var maxRadius = Math.min(width, height) / 2; - radius = (radius > maxRadius) ? maxRadius : radius; - - context.beginPath(); - context.moveTo(rx, ry + radius); - context.lineTo(rx, ry + height - radius); - context.quadraticCurveTo(rx, ry + height, rx + radius, ry + height); - context.lineTo(rx + width - radius, ry + height); - context.quadraticCurveTo(rx + width, ry + height, rx + width, ry + height - radius); - context.lineTo(rx + width, ry + radius); - context.quadraticCurveTo(rx + width, ry, rx + width - radius, ry); - context.lineTo(rx + radius, ry); - context.quadraticCurveTo(rx, ry, rx, ry + radius); - context.closePath(); - - } - - if (data.hasFill) { - if (round) { - context.fill(); - } else { - context.fillRect(rx, ry, width, height); - } - } - - if(data.line.width > 0) { - context.globalAlpha = data.line.alpha * worldAlpha; - if(round) { - context.stroke(); - } else { - context.strokeRect(rx, ry, width, height); - } - } - - case Circle: - - context.beginPath(); - context.arc(points[0] - offsetX, points[1] - offsetY, points[2], 0, 2 * Math.PI, true); - context.closePath(); - - if(data.hasFill) { - context.fill(); - } - - if(data.line.width > 0) { - context.globalAlpha = data.line.alpha * worldAlpha; - context.stroke(); - } - - case Ellipse: - - var w = points[2]; - var h = points[3]; - var x = (points[0] - offsetX); - var y = (points[1] - offsetY); - - context.beginPath(); - var kappa = 0.5522848, - ox = (w / 2) * kappa, // control point offset horizontal - oy = (h / 2) * kappa, // control point offset vertical - xe = x + w, // x-end - ye = y + h, // y-end - xm = x + w / 2, // x-middle - ym = y + h / 2; // y-middle - context.moveTo(x, ym); - context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); - context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); - context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); - context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); - context.closePath(); - - if(data.hasFill) { - context.fill(); - } - - if(data.line.width > 0) { - context.globalAlpha = data.line.alpha * worldAlpha; - context.stroke(); - } - - case _: - - } - - } - - } - - #end - - }*/ - - + public static function render (graphics:Graphics, renderSession:RenderSession):Void { #if (js && html5) - + if (graphics.__dirty) { - + + CanvasGraphics.graphics = graphics; bounds = graphics.__bounds; + strokeCommands = []; + fillCommands = []; + hasFill = false; hasStroke = false; - inPath = false; - positionX = 0; - positionY = 0; + + bitmapFill = null; + bitmapRepeat = false; if (!graphics.__visible || graphics.__commands.length == 0 || bounds == null || bounds.width == 0 || bounds.height == 0) { graphics.__canvas = null; graphics.__context = null; - } else { - - if (graphics.__canvas == null) { - - graphics.__canvas = cast Browser.document.createElement ("canvas"); - graphics.__context = graphics.__canvas.getContext ("2d"); - //untyped (context).mozImageSmoothingEnabled = false; - //untyped (context).webkitImageSmoothingEnabled = false; - //context.imageSmoothingEnabled = false; - - } - - context = graphics.__context; - - graphics.__canvas.width = Math.ceil (bounds.width); - graphics.__canvas.height = Math.ceil (bounds.height); - - var offsetX = bounds.x; - var offsetY = bounds.y; - - var bitmapFill:BitmapData = null; - var bitmapRepeat = false; - - for (command in graphics.__commands) { - - switch (command) { - - case BeginBitmapFill (bitmap, matrix, repeat, smooth): - - closePath (false); - - if (bitmap != bitmapFill || repeat != bitmapRepeat) { - - bitmapFill = bitmap; - bitmapRepeat = repeat; - pattern = null; - setFill = false; - - bitmap.__sync (); - - } - - if (matrix != null) { - - pendingMatrix = matrix; - inversePendingMatrix = matrix.clone (); - inversePendingMatrix.invert (); - - } else { - - pendingMatrix = null; - inversePendingMatrix = null; - - } - - hasFill = true; - - case BeginFill (rgb, alpha): - - closePath (false); - - if (alpha == 1) { - - context.fillStyle = "#" + StringTools.hex (rgb, 6); - - } else { - - var r = (rgb & 0xFF0000) >>> 16; - var g = (rgb & 0x00FF00) >>> 8; - var b = (rgb & 0x0000FF); - - context.fillStyle = "rgba(" + r + ", " + g + ", " + b + ", " + alpha + ")"; - - } - - bitmapFill = null; - setFill = true; - hasFill = true; - - case BeginGradientFill (type, colors, alphas, ratios, matrix, spreadMethod, interpolationMethod, focalPointRatio): - - closePath (false); - - var gradientFill = null; - - switch (type) { - - case RADIAL: - - if (matrix == null) matrix = new Matrix (); - var point = matrix.transformPoint (new Point (1638.4, 0)); - gradientFill = context.createRadialGradient (matrix.tx, matrix.ty, 0, matrix.tx, matrix.ty, (point.x - matrix.tx) / 2); - - case LINEAR: - - var matrix = matrix != null ? matrix.clone () : new Matrix (); - matrix.tx -= matrix.a * 1638.4 / 2; - matrix.ty -= matrix.d * 1638.4 / 2; - - var point1 = matrix.transformPoint (new Point (0, 0)); - var point2 = matrix.transformPoint (new Point (1638.4, 0)); - - gradientFill = context.createLinearGradient (point1.x, point1.y, point2.x, point2.y); - - } - - for (i in 0...colors.length) { - - var rgb = colors[i]; - var alpha = alphas[i]; - var r = (rgb & 0xFF0000) >>> 16; - var g = (rgb & 0x00FF00) >>> 8; - var b = (rgb & 0x0000FF); - - var ratio = ratios[i] / 0xFF; - if (ratio < 0) ratio = 0; - if (ratio > 1) ratio = 1; - - gradientFill.addColorStop (ratio, "rgba(" + r + ", " + g + ", " + b + ", " + alpha + ")"); - - } - - context.fillStyle = gradientFill; - - bitmapFill = null; - setFill = true; - hasFill = true; - - case CubicCurveTo (cx1, cy1, cx2, cy2, x, y): - - beginPatternFill (bitmapFill, bitmapRepeat); - beginPath (); - context.bezierCurveTo (cx1 - offsetX, cy1 - offsetY, cx2 - offsetX, cy2 - offsetY, x - offsetX, y - offsetY); - positionX = x; - positionY = y; - - case CurveTo (cx, cy, x, y): - - beginPatternFill (bitmapFill, bitmapRepeat); - beginPath (); - context.quadraticCurveTo (cx - offsetX, cy - offsetY, x - offsetX, y - offsetY); - positionX = x; - positionY = y; - - case DrawCircle (x, y, radius): - - beginPatternFill (bitmapFill, bitmapRepeat); - beginPath (); - context.moveTo (x - offsetX + radius, y - offsetY); - context.arc (x - offsetX, y - offsetY, radius, 0, Math.PI * 2, true); - - case DrawEllipse (x, y, width, height): - - x -= offsetX; - y -= offsetY; - - var kappa = .5522848, - ox = (width / 2) * kappa, // control point offset horizontal - oy = (height / 2) * kappa, // control point offset vertical - xe = x + width, // x-end - ye = y + height, // y-end - xm = x + width / 2, // x-middle - ym = y + height / 2; // y-middle - - beginPatternFill (bitmapFill, bitmapRepeat); - beginPath (); - context.moveTo (x, ym); - context.bezierCurveTo (x, ym - oy, xm - ox, y, xm, y); - context.bezierCurveTo (xm + ox, y, xe, ym - oy, xe, ym); - context.bezierCurveTo (xe, ym + oy, xm + ox, ye, xm, ye); - context.bezierCurveTo (xm - ox, ye, x, ym + oy, x, ym); - - case DrawRect (x, y, width, height): - - var optimizationUsed = false; - - if (bitmapFill != null) { - - var st:Float = 0; - var sr:Float = 0; - var sb:Float = 0; - var sl:Float = 0; - - var canOptimizeMatrix = true; - - if (pendingMatrix != null) { - - if (pendingMatrix.b != 0 || pendingMatrix.c != 0) { - - canOptimizeMatrix = false; - - } else { - - var stl = inversePendingMatrix.transformPoint(new Point(x, y)); - var sbr = inversePendingMatrix.transformPoint(new Point(x + width, y + height)); - - st = stl.y; - sl = stl.x; - sb = sbr.y; - sr = sbr.x; - - } - - } else { - - st = y; - sl = x; - sb = y + height; - sr = x + width; - - } - - if (canOptimizeMatrix && st >= 0 && sl >= 0 && sr <= bitmapFill.width && sb <= bitmapFill.height) { - - optimizationUsed = true; - context.drawImage (bitmapFill.__image.src, sl, st, sr - sl, sb - st, x - offsetX, y - offsetY, width, height); - - } - - } - - if (!optimizationUsed) { - - beginPatternFill (bitmapFill, bitmapRepeat); - beginPath (); - context.rect (x - offsetX, y - offsetY, width, height); - - } - - case DrawRoundRect (x, y, width, height, rx, ry): - - beginPatternFill (bitmapFill, bitmapRepeat); - beginPath (); - drawRoundRect (x - offsetX, y - offsetY, width, height, rx, ry); - - case DrawTiles (sheet, tileData, smooth, flags, count): - - closePath (false); - - var useScale = (flags & Graphics.TILE_SCALE) > 0; - var useRotation = (flags & Graphics.TILE_ROTATION) > 0; - var useTransform = (flags & Graphics.TILE_TRANS_2x2) > 0; - var useRGB = (flags & Graphics.TILE_RGB) > 0; - var useAlpha = (flags & Graphics.TILE_ALPHA) > 0; - var useRect = (flags & Graphics.TILE_RECT) > 0; - var useOrigin = (flags & Graphics.TILE_ORIGIN) > 0; - var useBlendAdd = (flags & Graphics.TILE_BLEND_ADD) > 0; - - if (useTransform) { useScale = false; useRotation = false; } - - var scaleIndex = 0; - var rotationIndex = 0; - var rgbIndex = 0; - var alphaIndex = 0; - var transformIndex = 0; - - var numValues = 3; - - if (useRect) { numValues = useOrigin ? 8 : 6; } - if (useScale) { scaleIndex = numValues; numValues ++; } - if (useRotation) { rotationIndex = numValues; numValues ++; } - if (useTransform) { transformIndex = numValues; numValues += 4; } - if (useRGB) { rgbIndex = numValues; numValues += 3; } - if (useAlpha) { alphaIndex = numValues; numValues ++; } - - var totalCount = tileData.length; - if (count >= 0 && totalCount > count) totalCount = count; - var itemCount = Std.int (totalCount / numValues); - var index = 0; + } else { + + if (graphics.__canvas == null) { + + graphics.__canvas = cast Browser.document.createElement ("canvas"); + graphics.__context = graphics.__canvas.getContext ("2d"); + //untyped (context).mozImageSmoothingEnabled = false; + //untyped (context).webkitImageSmoothingEnabled = false; + //context.imageSmoothingEnabled = false; + } + + context = graphics.__context; + + graphics.__canvas.width = Math.ceil (bounds.width); + graphics.__canvas.height = Math.ceil (bounds.height); + + var offsetX = bounds.x; + var offsetY = bounds.y; + + fillCommands = new Array(); + strokeCommands = new Array(); + + inline function endAndPush( command : DrawCommand ) + { + fillEnd(); + strokeEnd(); + + strokeCommands.push( command ); + fillCommands.push( command ); + } + + for (command in graphics.__commands) { + + switch (command) { + + case CubicCurveTo (cx1, cy1, cx2, cy2, x, y): + strokeCommands.push( command ); + fillCommands.push( command ); - var rect = null; - var center = null; - var previousTileID = -1; + case CurveTo (cx, cy, x, y): + strokeCommands.push( command ); + fillCommands.push( command ); - var surface:Dynamic; - sheet.__bitmap.__sync (); - surface = sheet.__bitmap.__image.src; - - if (useBlendAdd) - context.globalCompositeOperation = "lighter"; + case LineTo (x, y): + strokeCommands.push( command ); + fillCommands.push( command ); - while (index < totalCount) { - - var tileID = (!useRect) ? Std.int (tileData[index + 2]) : -1; - - if (!useRect && tileID != previousTileID) { - - rect = sheet.__tileRects[tileID]; - center = sheet.__centerPoints[tileID]; - - previousTileID = tileID; - - } - else if (useRect) - { - rect = sheet.__rectTile; - rect.setTo(tileData[index + 2], tileData[index + 3], tileData[index + 4], tileData[index + 5]); - center = sheet.__point; - if (useOrigin) - { - center.setTo(tileData[index + 6], tileData[index + 7]); - } - else - { - center.setTo(0, 0); - } - } - - if (rect != null && rect.width > 0 && rect.height > 0 && center != null) { - - context.save (); - context.translate (tileData[index], tileData[index + 1]); - - if (useRotation) { - - context.rotate (tileData[index + rotationIndex]); - - } - - var scale = 1.0; - - if (useScale) { - - scale = tileData[index + scaleIndex]; - - } - - if (useTransform) { - - context.transform (tileData[index + transformIndex], tileData[index + transformIndex + 1], tileData[index + transformIndex + 2], tileData[index + transformIndex + 3], 0, 0); - - } - - if (useAlpha) { - - context.globalAlpha = tileData[index + alphaIndex]; - - } - - context.drawImage (surface, rect.x, rect.y, rect.width, rect.height, -center.x * scale, -center.y * scale, rect.width * scale, rect.height * scale); - context.restore (); - - } - - index += numValues; - - } - - if (useBlendAdd) - context.globalCompositeOperation = "source-over"; - case EndFill: - closePath (true); + fillEnd(); + strokeEnd(); + + hasFill = false; case LineStyle (thickness, color, alpha, pixelHinting, scaleMode, caps, joints, miterLimit): + strokeCommands.push( command ); - closePath (false); + case BeginBitmapFill (bitmap, matrix, repeat, smooth): + endAndPush(command); + + case BeginFill (rgb, alpha): + endAndPush(command); + + case BeginGradientFill (type, colors, alphas, ratios, matrix, spreadMethod, interpolationMethod, focalPointRatio): + endAndPush(command); - if (thickness == null) { - - hasStroke = false; - - } else { - - context.lineWidth = thickness; - - context.lineJoin = (joints == null ? "round" : Std.string (joints).toLowerCase ()); - context.lineCap = (caps == null ? "round" : switch (caps) { - case CapsStyle.NONE: "butt"; - default: Std.string (caps).toLowerCase (); - }); - - context.miterLimit = (miterLimit == null ? 3 : miterLimit); - - if (alpha == 1 || alpha == null) { - - context.strokeStyle = (color == null ? "#000000" : "#" + StringTools.hex (color & 0x00FFFFFF, 6)); - - } else { - - var r = (color & 0xFF0000) >>> 16; - var g = (color & 0x00FF00) >>> 8; - var b = (color & 0x0000FF); - - context.strokeStyle = (color == null ? "#000000" : "rgba(" + r + ", " + g + ", " + b + ", " + alpha + ")"); - - } - - hasStroke = true; - - } - - case LineTo (x, y): + case DrawCircle (x, y, radius): + endAndPush(command); - beginPatternFill(bitmapFill, bitmapRepeat); - beginPath (); - context.lineTo (x - offsetX, y - offsetY); - positionX = x; - positionY = y; + case DrawEllipse (x, y, width, height): + endAndPush(command); + + case DrawRect (x, y, width, height): + endAndPush( command ); + + case DrawRoundRect (x, y, width, height, rx, ry): + endAndPush(command); case MoveTo (x, y): - - beginPath (); - context.moveTo (x - offsetX, y - offsetY); - positionX = x; - positionY = y; + strokeCommands.push( command ); + fillCommands.push( command ); case DrawTriangles (vertices, indices, uvtData, culling, _, _): - - closePath(false); + + fillEnd(); + strokeEnd(); var v = vertices; var ind = indices; @@ -905,7 +665,121 @@ class CanvasGraphics { i += 3; - } + } + + case DrawTiles (sheet, tileData, smooth, flags, count): + + var useScale = (flags & Graphics.TILE_SCALE) > 0; + var useRotation = (flags & Graphics.TILE_ROTATION) > 0; + var useTransform = (flags & Graphics.TILE_TRANS_2x2) > 0; + var useRGB = (flags & Graphics.TILE_RGB) > 0; + var useAlpha = (flags & Graphics.TILE_ALPHA) > 0; + var useRect = (flags & Graphics.TILE_RECT) > 0; + var useOrigin = (flags & Graphics.TILE_ORIGIN) > 0; + var useBlendAdd = (flags & Graphics.TILE_BLEND_ADD) > 0; + + if (useTransform) { useScale = false; useRotation = false; } + + var scaleIndex = 0; + var rotationIndex = 0; + var rgbIndex = 0; + var alphaIndex = 0; + var transformIndex = 0; + + var numValues = 3; + + if (useRect) { numValues = useOrigin ? 8 : 6; } + if (useScale) { scaleIndex = numValues; numValues ++; } + if (useRotation) { rotationIndex = numValues; numValues ++; } + if (useTransform) { transformIndex = numValues; numValues += 4; } + if (useRGB) { rgbIndex = numValues; numValues += 3; } + if (useAlpha) { alphaIndex = numValues; numValues ++; } + + var totalCount = tileData.length; + if (count >= 0 && totalCount > count) totalCount = count; + var itemCount = Std.int (totalCount / numValues); + var index = 0; + + var rect = null; + var center = null; + var previousTileID = -1; + + var surface:Dynamic; + sheet.__bitmap.__sync (); + surface = sheet.__bitmap.__image.src; + + if (useBlendAdd) + context.globalCompositeOperation = "lighter"; + + while (index < totalCount) { + + var tileID = (!useRect) ? Std.int (tileData[index + 2]) : -1; + + if (!useRect && tileID != previousTileID) { + + rect = sheet.__tileRects[tileID]; + center = sheet.__centerPoints[tileID]; + + previousTileID = tileID; + + } + else if (useRect) + { + rect = sheet.__rectTile; + rect.setTo(tileData[index + 2], tileData[index + 3], tileData[index + 4], tileData[index + 5]); + center = sheet.__point; + if (useOrigin) + { + center.setTo(tileData[index + 6], tileData[index + 7]); + } + else + { + center.setTo(0, 0); + } + } + + if (rect != null && rect.width > 0 && rect.height > 0 && center != null) { + + context.save (); + context.translate (tileData[index], tileData[index + 1]); + + if (useRotation) { + + context.rotate (tileData[index + rotationIndex]); + + } + + var scale = 1.0; + + if (useScale) { + + scale = tileData[index + scaleIndex]; + + } + + if (useTransform) { + + context.transform (tileData[index + transformIndex], tileData[index + transformIndex + 1], tileData[index + transformIndex + 2], tileData[index + transformIndex + 3], 0, 0); + + } + + if (useAlpha) { + + context.globalAlpha = tileData[index + alphaIndex]; + + } + + context.drawImage (surface, rect.x, rect.y, rect.width, rect.height, -center.x * scale, -center.y * scale, rect.width * scale, rect.height * scale); + context.restore (); + + } + + index += numValues; + + } + + if (useBlendAdd) + context.globalCompositeOperation = "source-over"; case _: openfl.Lib.notImplemented("CanvasGraphics"); @@ -917,7 +791,12 @@ class CanvasGraphics { } graphics.__dirty = false; - closePath (false); + + if( fillCommands.length > 0 ) + fillEnd(); + + if( strokeCommands.length > 0 ) + strokeEnd(); } diff --git a/openfl/display/Graphics.hx b/openfl/display/Graphics.hx index 1baa54dfdc..a0a5b96adf 100644 --- a/openfl/display/Graphics.hx +++ b/openfl/display/Graphics.hx @@ -911,7 +911,7 @@ class Graphics { */ public function lineStyle (thickness:Null = null, color:Null = null, alpha:Null = null, pixelHinting:Null = null, scaleMode:LineScaleMode = null, caps:CapsStyle = null, joints:JointStyle = null, miterLimit:Null = null):Void { - __halfStrokeWidth = (thickness != null) ? thickness / 2 : 0; + __halfStrokeWidth = thickness > __halfStrokeWidth ? thickness : __halfStrokeWidth; __commands.push (LineStyle (thickness, color, alpha, pixelHinting, scaleMode, caps, joints, miterLimit)); if (thickness != null) __visible = true; From b1da73d403425b3a249f3a58e6a8d8e40464435a Mon Sep 17 00:00:00 2001 From: "Lars A. Doucet" Date: Tue, 28 Apr 2015 13:22:47 -0500 Subject: [PATCH 074/150] BitmapData.hx getColorBoundsRect: __toFlashRectangle returns null on non-flash targets, better to directly return an openfl.geom.Rectangle right in the function (that's a flash.geom.Rectangle on flash anyway, functionally equivalent to __toFlashRectangle) --- openfl/display/BitmapData.hx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openfl/display/BitmapData.hx b/openfl/display/BitmapData.hx index 7107de8d07..66a862ee67 100644 --- a/openfl/display/BitmapData.hx +++ b/openfl/display/BitmapData.hx @@ -795,9 +795,8 @@ class BitmapData implements IBitmapDrawable { public function getColorBoundsRect (mask:Int, color:Int, findColor:Bool = true):Rectangle { if (!__isValid) return new Rectangle (0, 0, width, height); - var rect = __image.getColorBoundsRect (mask, color, findColor); - return rect.__toFlashRectangle (); + return new Rectangle(rect.x, rect.y, rect.width, rect.height); } From 7e3556648cb6c05a69a9d346b1bf3a670c706965 Mon Sep 17 00:00:00 2001 From: Kane Wallmann Date: Sun, 26 Apr 2015 21:52:13 +1000 Subject: [PATCH 075/150] Made canvas renderer more consistent with Flash --- .../renderer/canvas/CanvasGraphics.hx | 1183 ++++++++--------- openfl/display/Graphics.hx | 2 +- 2 files changed, 532 insertions(+), 653 deletions(-) diff --git a/openfl/_internal/renderer/canvas/CanvasGraphics.hx b/openfl/_internal/renderer/canvas/CanvasGraphics.hx index ec5c76ca82..cc1d61ac51 100644 --- a/openfl/_internal/renderer/canvas/CanvasGraphics.hx +++ b/openfl/_internal/renderer/canvas/CanvasGraphics.hx @@ -32,59 +32,316 @@ class CanvasGraphics { private static var TAN22 = 0.4142135623730950488016887242097; private static var bounds:Rectangle; - private static var hasFill:Bool; - private static var hasStroke:Bool; - private static var inPath:Bool; private static var inversePendingMatrix:Matrix; private static var pendingMatrix:Matrix; - private static var positionX:Float; - private static var positionY:Float; - private static var setFill:Bool; + + private static var hasStroke : Bool; + private static var hasFill:Bool; + + private static var bitmapFill:BitmapData; + private static var bitmapRepeat:Bool; + + private static var graphics:Graphics; + + private static var fillCommands:Array; + private static var strokeCommands:Array; #if (js && html5) private static var context:CanvasRenderingContext2D; private static var pattern:CanvasPattern; #end - - - private static function beginPath ():Void { + private static function playCommands( commands : Array, stroke : Bool = false ) + { #if (js && html5) - if (!inPath) { - - context.beginPath (); - inPath = true; - - } - #end - } - - - private static function beginPatternFill (bitmapFill:BitmapData, bitmapRepeat:Bool):Void { + bounds = graphics.__bounds; - #if (js && html5) - if (setFill || bitmapFill == null) return; + var offsetX = bounds.x; + var offsetY = bounds.y; - if (pattern == null) { + var positionX : Float = 0; + var positionY : Float = 0; + + var closeGap : Bool = false; + var startX : Float = 0; + var startY : Float = 0; + + for (command in commands) { + + switch (command) { + + case CubicCurveTo (cx1, cy1, cx2, cy2, x, y): + context.bezierCurveTo (cx1 - offsetX, cy1 - offsetY, cx2 - offsetX, cy2 - offsetY, x - offsetX, y - offsetY); + + case CurveTo (cx, cy, x, y): + context.quadraticCurveTo (cx - offsetX, cy - offsetY, x - offsetX, y - offsetY); + + case DrawCircle (x, y, radius): + + context.moveTo (x - offsetX + radius, y - offsetY); + context.arc (x - offsetX, y - offsetY, radius, 0, Math.PI * 2, true); + + case DrawEllipse (x, y, width, height): + + x -= offsetX; + y -= offsetY; + + var kappa = .5522848, + ox = (width / 2) * kappa, // control point offset horizontal + oy = (height / 2) * kappa, // control point offset vertical + xe = x + width, // x-end + ye = y + height, // y-end + xm = x + width / 2, // x-middle + ym = y + height / 2; // y-middle + + context.moveTo (x, ym); + context.bezierCurveTo (x, ym - oy, xm - ox, y, xm, y); + context.bezierCurveTo (xm + ox, y, xe, ym - oy, xe, ym); + context.bezierCurveTo (xe, ym + oy, xm + ox, ye, xm, ye); + context.bezierCurveTo (xm - ox, ye, x, ym + oy, x, ym); + + + case DrawRoundRect (x, y, width, height, rx, ry): + drawRoundRect (x - offsetX, y - offsetY, width, height, rx, ry); + + case LineTo (x, y): + + context.lineTo (x - offsetX, y - offsetY); + + positionX = x; + positionY = y; + + case MoveTo (x, y): + + context.moveTo (x - offsetX, y - offsetY); + + positionX = x; + positionY = y; + + closeGap = true; + startX = x; + startY = y; + + case LineStyle (thickness, color, alpha, pixelHinting, scaleMode, caps, joints, miterLimit): + + if ( stroke && hasStroke ) + { + context.closePath(); + context.stroke(); + context.beginPath(); + } + + context.moveTo (positionX - offsetX, positionY - offsetY); + + if (thickness == null) { + + hasStroke = false; + + } else { + + context.lineWidth = thickness; + + context.lineJoin = (joints == null ? "round" : Std.string (joints).toLowerCase ()); + context.lineCap = (caps == null ? "round" : switch (caps) { + case CapsStyle.NONE: "butt"; + default: Std.string (caps).toLowerCase (); + }); + + context.miterLimit = (miterLimit == null ? 3 : miterLimit); + + if (alpha == 1 || alpha == null) { + + context.strokeStyle = (color == null ? "#000000" : "#" + StringTools.hex (color & 0x00FFFFFF, 6)); + + } else { + + var r = (color & 0xFF0000) >>> 16; + var g = (color & 0x00FF00) >>> 8; + var b = (color & 0x0000FF); + + context.strokeStyle = (color == null ? "#000000" : "rgba(" + r + ", " + g + ", " + b + ", " + alpha + ")"); + + } + + hasStroke = true; + + } + + case BeginBitmapFill (bitmap, matrix, repeat, smooth): + + if (bitmap != bitmapFill || repeat != bitmapRepeat) { + + bitmapFill = bitmap; + bitmapRepeat = repeat; + pattern = null; + hasFill = false; + + bitmap.__sync (); + + } + + if (matrix != null) { + + pendingMatrix = matrix; + inversePendingMatrix = matrix.clone (); + inversePendingMatrix.invert (); + + } else { + + pendingMatrix = null; + inversePendingMatrix = null; + + } + + case BeginFill (rgb, alpha): + + if ( alpha <= 0.07 ) + { + hasFill = false; + } + else + { + if (alpha == 1) { + + context.fillStyle = "#" + StringTools.hex (rgb, 6); + + } else { + + var r = (rgb & 0xFF0000) >>> 16; + var g = (rgb & 0x00FF00) >>> 8; + var b = (rgb & 0x0000FF); + + context.fillStyle = "rgba(" + r + ", " + g + ", " + b + ", " + alpha + ")"; + + } + + bitmapFill = null; + hasFill = true; + } + + case BeginGradientFill (type, colors, alphas, ratios, matrix, spreadMethod, interpolationMethod, focalPointRatio): + + var gradientFill = null; + + switch (type) { + + case RADIAL: + + if (matrix == null) matrix = new Matrix (); + var point = matrix.transformPoint (new Point (1638.4, 0)); + gradientFill = context.createRadialGradient (matrix.tx, matrix.ty, 0, matrix.tx, matrix.ty, (point.x - matrix.tx) / 2); + + case LINEAR: + + var matrix = matrix != null ? matrix.clone () : new Matrix (); + matrix.tx -= matrix.a * 1638.4 / 2; + matrix.ty -= matrix.d * 1638.4 / 2; + + var point1 = matrix.transformPoint (new Point (0, 0)); + var point2 = matrix.transformPoint (new Point (1638.4, 0)); + + gradientFill = context.createLinearGradient (point1.x, point1.y, point2.x, point2.y); + + } + + for (i in 0...colors.length) { + + var rgb = colors[i]; + var alpha = alphas[i]; + var r = (rgb & 0xFF0000) >>> 16; + var g = (rgb & 0x00FF00) >>> 8; + var b = (rgb & 0x0000FF); + + var ratio = ratios[i] / 0xFF; + if (ratio < 0) ratio = 0; + if (ratio > 1) ratio = 1; + + gradientFill.addColorStop (ratio, "rgba(" + r + ", " + g + ", " + b + ", " + alpha + ")"); + + } + + context.fillStyle = gradientFill; + + bitmapFill = null; + hasFill = true; + + case DrawRect (x, y, width, height): + + var optimizationUsed = false; + + if (bitmapFill != null) { + + var st:Float = 0; + var sr:Float = 0; + var sb:Float = 0; + var sl:Float = 0; + + var canOptimizeMatrix = true; + + if (pendingMatrix != null) { + + if (pendingMatrix.b != 0 || pendingMatrix.c != 0) { + + canOptimizeMatrix = false; + + } else { + + var stl = inversePendingMatrix.transformPoint(new Point(x, y)); + var sbr = inversePendingMatrix.transformPoint(new Point(x + width, y + height)); + + st = stl.y; + sl = stl.x; + sb = sbr.y; + sr = sbr.x; + + } + + } else { + + st = y; + sl = x; + sb = y + height; + sr = x + width; + + } + + if (canOptimizeMatrix && st >= 0 && sl >= 0 && sr <= bitmapFill.width && sb <= bitmapFill.height) { + + optimizationUsed = true; + context.drawImage (bitmapFill.__image.src, sl, st, sr - sl, sb - st, x - offsetX, y - offsetY, width, height); + } + } + + if (!optimizationUsed) { + + context.rect (x - offsetX, y - offsetY, width, height); + } - pattern = context.createPattern (bitmapFill.__image.src, bitmapRepeat ? "repeat" : "no-repeat"); + + + default: + + } + + } + + if ( stroke && hasStroke ) + { + if ( hasFill && closeGap ) + { + context.lineTo (startX - offsetX, startY - offsetY); + } + context.stroke(); } - context.fillStyle = pattern; - setFill = true; - #end - - } - - - private static function closePath (closeFill:Bool):Void { - - #if (js && html5) - if (inPath) { - - if (hasFill) { + if ( !stroke ) + { + if ( hasFill || bitmapFill != null ) + { + if( bitmapFill != null ) + beginPatternFill (bitmapFill, bitmapRepeat); context.translate( -bounds.x, -bounds.y); @@ -101,34 +358,50 @@ class CanvasGraphics { } context.translate (bounds.x, bounds.y); - - } - - context.closePath (); - - if (hasStroke) { - - context.stroke (); - + + context.closePath(); } - } - inPath = false; + #end + } + + private static function fillEnd() + { + #if (js && html5) + context.beginPath(); + playCommands( fillCommands, false ); + fillCommands = []; + #end + } + + private static function strokeEnd() + { + #if (js && html5) + context.beginPath(); + playCommands( strokeCommands, true ); + context.closePath(); + strokeCommands = []; + #end + } + + private static function beginPatternFill (bitmapFill:BitmapData, bitmapRepeat:Bool):Void { + + #if (js && html5) + if (hasFill || bitmapFill == null) return; - if (closeFill) { + if (pattern == null) { - hasFill = false; - hasStroke = false; - pendingMatrix = null; - inversePendingMatrix = null; + pattern = context.createPattern (bitmapFill.__image.src, bitmapRepeat ? "repeat" : "no-repeat"); } + + context.fillStyle = pattern; + hasFill = true; #end } - - + private static function drawRoundRect (x:Float, y:Float, width:Float, height:Float, rx:Float, ry:Float):Void { #if (js && html5) @@ -163,629 +436,116 @@ class CanvasGraphics { #end } - - - /*#if (js && html5) - private static inline function setFillStyle(data:DrawPath, context:CanvasRenderingContext2D, worldAlpha:Float) { - if (data.hasFill) { - - context.globalAlpha = data.fill.alpha * worldAlpha; - if (data.fill.bitmap != null) { - var bitmap = data.fill.bitmap; - var repeat = data.fill.repeat; - var pattern = context.createPattern (bitmap.__image.src, repeat ? "repeat" : "no-repeat"); - context.fillStyle = pattern; - } else { - context.fillStyle = '#' + StringTools.hex(data.fill.color, 6); - } - } - } - #end - - public static function renderObjectGraphics(object:DisplayObject, renderSession:RenderSession):Void { - - #if (js && html5) - - var worldAlpha = object.__worldAlpha; - var graphics = object.__graphics; - - bounds = graphics.__bounds; - - if(!graphics.__dirty) return; - - graphics.__dirty = false; - - if(bounds == null || bounds.width == 0 || bounds.height == 0) { - - graphics.__canvas = null; - graphics.__context = null; - - } else { - - if (graphics.__canvas == null) { - - graphics.__canvas = cast Browser.document.createElement ("canvas"); - graphics.__context = graphics.__canvas.getContext ("2d"); - //untyped (context).mozImageSmoothingEnabled = false; - //untyped (context).webkitImageSmoothingEnabled = false; - //context.imageSmoothingEnabled = false; - - } - - var context = graphics.__context; - - graphics.__canvas.width = Math.ceil (bounds.width); - graphics.__canvas.height = Math.ceil (bounds.height); - - var offsetX = bounds.x; - var offsetY = bounds.y; - - for (i in 0...graphics.__graphicsData.length) { - - var data = graphics.__graphicsData[i]; - var points = data.points; - - context.strokeStyle = '#' + StringTools.hex (data.line.color, 6); - context.lineWidth = data.line.width; - context.lineCap = Std.string(data.line.caps); - context.lineJoin = Std.string(data.line.joints); - context.miterLimit = data.line.miterLimit; - - setFillStyle(data, context, worldAlpha); - - switch(data.type) { - - case Polygon: - - context.beginPath(); - context.moveTo(points[0] - offsetX, points[1] - offsetY); - for(i in 1...Std.int(points.length/2)) { - context.lineTo(points[i * 2] - offsetX, points[i * 2 + 1] - offsetY); - } - context.closePath(); - - if(data.hasFill) { - context.fill(); - } - - if(data.line.width > 0) { - context.globalAlpha = data.line.alpha * worldAlpha; - context.stroke(); - } - - case Rectangle(round): - - var rx = points[0] - offsetX; - var ry = points[1] - offsetY; - var width = points[2]; - var height = points[3]; - - if(round) { - - var radius = points[4]; - var maxRadius = Math.min(width, height) / 2; - radius = (radius > maxRadius) ? maxRadius : radius; - - context.beginPath(); - context.moveTo(rx, ry + radius); - context.lineTo(rx, ry + height - radius); - context.quadraticCurveTo(rx, ry + height, rx + radius, ry + height); - context.lineTo(rx + width - radius, ry + height); - context.quadraticCurveTo(rx + width, ry + height, rx + width, ry + height - radius); - context.lineTo(rx + width, ry + radius); - context.quadraticCurveTo(rx + width, ry, rx + width - radius, ry); - context.lineTo(rx + radius, ry); - context.quadraticCurveTo(rx, ry, rx, ry + radius); - context.closePath(); - - } - - if (data.hasFill) { - if (round) { - context.fill(); - } else { - context.fillRect(rx, ry, width, height); - } - } - - if(data.line.width > 0) { - context.globalAlpha = data.line.alpha * worldAlpha; - if(round) { - context.stroke(); - } else { - context.strokeRect(rx, ry, width, height); - } - } - - case Circle: - - context.beginPath(); - context.arc(points[0] - offsetX, points[1] - offsetY, points[2], 0, 2 * Math.PI, true); - context.closePath(); - - if(data.hasFill) { - context.fill(); - } - - if(data.line.width > 0) { - context.globalAlpha = data.line.alpha * worldAlpha; - context.stroke(); - } - - case Ellipse: - - var w = points[2]; - var h = points[3]; - var x = (points[0] - offsetX); - var y = (points[1] - offsetY); - - context.beginPath(); - var kappa = 0.5522848, - ox = (w / 2) * kappa, // control point offset horizontal - oy = (h / 2) * kappa, // control point offset vertical - xe = x + w, // x-end - ye = y + h, // y-end - xm = x + w / 2, // x-middle - ym = y + h / 2; // y-middle - context.moveTo(x, ym); - context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); - context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); - context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); - context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); - context.closePath(); - - if(data.hasFill) { - context.fill(); - } - - if(data.line.width > 0) { - context.globalAlpha = data.line.alpha * worldAlpha; - context.stroke(); - } - - case _: - - } - - } - - } - - #end - - }*/ - - + public static function render (graphics:Graphics, renderSession:RenderSession):Void { #if (js && html5) - + if (graphics.__dirty) { - + + CanvasGraphics.graphics = graphics; bounds = graphics.__bounds; + strokeCommands = []; + fillCommands = []; + hasFill = false; hasStroke = false; - inPath = false; - positionX = 0; - positionY = 0; + + bitmapFill = null; + bitmapRepeat = false; if (!graphics.__visible || graphics.__commands.length == 0 || bounds == null || bounds.width == 0 || bounds.height == 0) { graphics.__canvas = null; graphics.__context = null; - } else { - - if (graphics.__canvas == null) { - - graphics.__canvas = cast Browser.document.createElement ("canvas"); - graphics.__context = graphics.__canvas.getContext ("2d"); - //untyped (context).mozImageSmoothingEnabled = false; - //untyped (context).webkitImageSmoothingEnabled = false; - //context.imageSmoothingEnabled = false; - - } - - context = graphics.__context; - - graphics.__canvas.width = Math.ceil (bounds.width); - graphics.__canvas.height = Math.ceil (bounds.height); - - var offsetX = bounds.x; - var offsetY = bounds.y; - - var bitmapFill:BitmapData = null; - var bitmapRepeat = false; - - for (command in graphics.__commands) { - - switch (command) { - - case BeginBitmapFill (bitmap, matrix, repeat, smooth): - - closePath (false); - - if (bitmap != bitmapFill || repeat != bitmapRepeat) { - - bitmapFill = bitmap; - bitmapRepeat = repeat; - pattern = null; - setFill = false; - - bitmap.__sync (); - - } - - if (matrix != null) { - - pendingMatrix = matrix; - inversePendingMatrix = matrix.clone (); - inversePendingMatrix.invert (); - - } else { - - pendingMatrix = null; - inversePendingMatrix = null; - - } - - hasFill = true; - - case BeginFill (rgb, alpha): - - closePath (false); - - if (alpha == 1) { - - context.fillStyle = "#" + StringTools.hex (rgb, 6); - - } else { - - var r = (rgb & 0xFF0000) >>> 16; - var g = (rgb & 0x00FF00) >>> 8; - var b = (rgb & 0x0000FF); - - context.fillStyle = "rgba(" + r + ", " + g + ", " + b + ", " + alpha + ")"; - - } - - bitmapFill = null; - setFill = true; - hasFill = true; - - case BeginGradientFill (type, colors, alphas, ratios, matrix, spreadMethod, interpolationMethod, focalPointRatio): - - closePath (false); - - var gradientFill = null; - - switch (type) { - - case RADIAL: - - if (matrix == null) matrix = new Matrix (); - var point = matrix.transformPoint (new Point (1638.4, 0)); - gradientFill = context.createRadialGradient (matrix.tx, matrix.ty, 0, matrix.tx, matrix.ty, (point.x - matrix.tx) / 2); - - case LINEAR: - - var matrix = matrix != null ? matrix.clone () : new Matrix (); - matrix.tx -= matrix.a * 1638.4 / 2; - matrix.ty -= matrix.d * 1638.4 / 2; - - var point1 = matrix.transformPoint (new Point (0, 0)); - var point2 = matrix.transformPoint (new Point (1638.4, 0)); - - gradientFill = context.createLinearGradient (point1.x, point1.y, point2.x, point2.y); - - } - - for (i in 0...colors.length) { - - var rgb = colors[i]; - var alpha = alphas[i]; - var r = (rgb & 0xFF0000) >>> 16; - var g = (rgb & 0x00FF00) >>> 8; - var b = (rgb & 0x0000FF); - - var ratio = ratios[i] / 0xFF; - if (ratio < 0) ratio = 0; - if (ratio > 1) ratio = 1; - - gradientFill.addColorStop (ratio, "rgba(" + r + ", " + g + ", " + b + ", " + alpha + ")"); - - } - - context.fillStyle = gradientFill; - - bitmapFill = null; - setFill = true; - hasFill = true; - - case CubicCurveTo (cx1, cy1, cx2, cy2, x, y): - - beginPatternFill (bitmapFill, bitmapRepeat); - beginPath (); - context.bezierCurveTo (cx1 - offsetX, cy1 - offsetY, cx2 - offsetX, cy2 - offsetY, x - offsetX, y - offsetY); - positionX = x; - positionY = y; - - case CurveTo (cx, cy, x, y): - - beginPatternFill (bitmapFill, bitmapRepeat); - beginPath (); - context.quadraticCurveTo (cx - offsetX, cy - offsetY, x - offsetX, y - offsetY); - positionX = x; - positionY = y; - - case DrawCircle (x, y, radius): - - beginPatternFill (bitmapFill, bitmapRepeat); - beginPath (); - context.moveTo (x - offsetX + radius, y - offsetY); - context.arc (x - offsetX, y - offsetY, radius, 0, Math.PI * 2, true); - - case DrawEllipse (x, y, width, height): - - x -= offsetX; - y -= offsetY; - - var kappa = .5522848, - ox = (width / 2) * kappa, // control point offset horizontal - oy = (height / 2) * kappa, // control point offset vertical - xe = x + width, // x-end - ye = y + height, // y-end - xm = x + width / 2, // x-middle - ym = y + height / 2; // y-middle - - beginPatternFill (bitmapFill, bitmapRepeat); - beginPath (); - context.moveTo (x, ym); - context.bezierCurveTo (x, ym - oy, xm - ox, y, xm, y); - context.bezierCurveTo (xm + ox, y, xe, ym - oy, xe, ym); - context.bezierCurveTo (xe, ym + oy, xm + ox, ye, xm, ye); - context.bezierCurveTo (xm - ox, ye, x, ym + oy, x, ym); - - case DrawRect (x, y, width, height): - - var optimizationUsed = false; - - if (bitmapFill != null) { - - var st:Float = 0; - var sr:Float = 0; - var sb:Float = 0; - var sl:Float = 0; - - var canOptimizeMatrix = true; - - if (pendingMatrix != null) { - - if (pendingMatrix.b != 0 || pendingMatrix.c != 0) { - - canOptimizeMatrix = false; - - } else { - - var stl = inversePendingMatrix.transformPoint(new Point(x, y)); - var sbr = inversePendingMatrix.transformPoint(new Point(x + width, y + height)); - - st = stl.y; - sl = stl.x; - sb = sbr.y; - sr = sbr.x; - - } - - } else { - - st = y; - sl = x; - sb = y + height; - sr = x + width; - - } - - if (canOptimizeMatrix && st >= 0 && sl >= 0 && sr <= bitmapFill.width && sb <= bitmapFill.height) { - - optimizationUsed = true; - context.drawImage (bitmapFill.__image.src, sl, st, sr - sl, sb - st, x - offsetX, y - offsetY, width, height); - - } - - } - - if (!optimizationUsed) { - - beginPatternFill (bitmapFill, bitmapRepeat); - beginPath (); - context.rect (x - offsetX, y - offsetY, width, height); - - } - - case DrawRoundRect (x, y, width, height, rx, ry): - - beginPatternFill (bitmapFill, bitmapRepeat); - beginPath (); - drawRoundRect (x - offsetX, y - offsetY, width, height, rx, ry); - - case DrawTiles (sheet, tileData, smooth, flags, count): - - closePath (false); - - var useScale = (flags & Graphics.TILE_SCALE) > 0; - var useRotation = (flags & Graphics.TILE_ROTATION) > 0; - var useTransform = (flags & Graphics.TILE_TRANS_2x2) > 0; - var useRGB = (flags & Graphics.TILE_RGB) > 0; - var useAlpha = (flags & Graphics.TILE_ALPHA) > 0; - var useRect = (flags & Graphics.TILE_RECT) > 0; - var useOrigin = (flags & Graphics.TILE_ORIGIN) > 0; - var useBlendAdd = (flags & Graphics.TILE_BLEND_ADD) > 0; - - if (useTransform) { useScale = false; useRotation = false; } - - var scaleIndex = 0; - var rotationIndex = 0; - var rgbIndex = 0; - var alphaIndex = 0; - var transformIndex = 0; - - var numValues = 3; - - if (useRect) { numValues = useOrigin ? 8 : 6; } - if (useScale) { scaleIndex = numValues; numValues ++; } - if (useRotation) { rotationIndex = numValues; numValues ++; } - if (useTransform) { transformIndex = numValues; numValues += 4; } - if (useRGB) { rgbIndex = numValues; numValues += 3; } - if (useAlpha) { alphaIndex = numValues; numValues ++; } - - var totalCount = tileData.length; - if (count >= 0 && totalCount > count) totalCount = count; - var itemCount = Std.int (totalCount / numValues); - var index = 0; + } else { + + if (graphics.__canvas == null) { + + graphics.__canvas = cast Browser.document.createElement ("canvas"); + graphics.__context = graphics.__canvas.getContext ("2d"); + //untyped (context).mozImageSmoothingEnabled = false; + //untyped (context).webkitImageSmoothingEnabled = false; + //context.imageSmoothingEnabled = false; + } + + context = graphics.__context; + + graphics.__canvas.width = Math.ceil (bounds.width); + graphics.__canvas.height = Math.ceil (bounds.height); + + var offsetX = bounds.x; + var offsetY = bounds.y; + + fillCommands = new Array(); + strokeCommands = new Array(); + + inline function endAndPush( command : DrawCommand ) + { + fillEnd(); + strokeEnd(); + + strokeCommands.push( command ); + fillCommands.push( command ); + } + + for (command in graphics.__commands) { + + switch (command) { + + case CubicCurveTo (cx1, cy1, cx2, cy2, x, y): + strokeCommands.push( command ); + fillCommands.push( command ); - var rect = null; - var center = null; - var previousTileID = -1; + case CurveTo (cx, cy, x, y): + strokeCommands.push( command ); + fillCommands.push( command ); - var surface:Dynamic; - sheet.__bitmap.__sync (); - surface = sheet.__bitmap.__image.src; - - if (useBlendAdd) - context.globalCompositeOperation = "lighter"; + case LineTo (x, y): + strokeCommands.push( command ); + fillCommands.push( command ); - while (index < totalCount) { - - var tileID = (!useRect) ? Std.int (tileData[index + 2]) : -1; - - if (!useRect && tileID != previousTileID) { - - rect = sheet.__tileRects[tileID]; - center = sheet.__centerPoints[tileID]; - - previousTileID = tileID; - - } - else if (useRect) - { - rect = sheet.__rectTile; - rect.setTo(tileData[index + 2], tileData[index + 3], tileData[index + 4], tileData[index + 5]); - center = sheet.__point; - if (useOrigin) - { - center.setTo(tileData[index + 6], tileData[index + 7]); - } - else - { - center.setTo(0, 0); - } - } - - if (rect != null && rect.width > 0 && rect.height > 0 && center != null) { - - context.save (); - context.translate (tileData[index], tileData[index + 1]); - - if (useRotation) { - - context.rotate (tileData[index + rotationIndex]); - - } - - var scale = 1.0; - - if (useScale) { - - scale = tileData[index + scaleIndex]; - - } - - if (useTransform) { - - context.transform (tileData[index + transformIndex], tileData[index + transformIndex + 1], tileData[index + transformIndex + 2], tileData[index + transformIndex + 3], 0, 0); - - } - - if (useAlpha) { - - context.globalAlpha = tileData[index + alphaIndex]; - - } - - context.drawImage (surface, rect.x, rect.y, rect.width, rect.height, -center.x * scale, -center.y * scale, rect.width * scale, rect.height * scale); - context.restore (); - - } - - index += numValues; - - } - - if (useBlendAdd) - context.globalCompositeOperation = "source-over"; - case EndFill: - closePath (true); + fillEnd(); + strokeEnd(); + + hasFill = false; case LineStyle (thickness, color, alpha, pixelHinting, scaleMode, caps, joints, miterLimit): + strokeCommands.push( command ); - closePath (false); + case BeginBitmapFill (bitmap, matrix, repeat, smooth): + endAndPush(command); + + case BeginFill (rgb, alpha): + endAndPush(command); + + case BeginGradientFill (type, colors, alphas, ratios, matrix, spreadMethod, interpolationMethod, focalPointRatio): + endAndPush(command); - if (thickness == null) { - - hasStroke = false; - - } else { - - context.lineWidth = thickness; - - context.lineJoin = (joints == null ? "round" : Std.string (joints).toLowerCase ()); - context.lineCap = (caps == null ? "round" : switch (caps) { - case CapsStyle.NONE: "butt"; - default: Std.string (caps).toLowerCase (); - }); - - context.miterLimit = (miterLimit == null ? 3 : miterLimit); - - if (alpha == 1 || alpha == null) { - - context.strokeStyle = (color == null ? "#000000" : "#" + StringTools.hex (color & 0x00FFFFFF, 6)); - - } else { - - var r = (color & 0xFF0000) >>> 16; - var g = (color & 0x00FF00) >>> 8; - var b = (color & 0x0000FF); - - context.strokeStyle = (color == null ? "#000000" : "rgba(" + r + ", " + g + ", " + b + ", " + alpha + ")"); - - } - - hasStroke = true; - - } - - case LineTo (x, y): + case DrawCircle (x, y, radius): + endAndPush(command); - beginPatternFill(bitmapFill, bitmapRepeat); - beginPath (); - context.lineTo (x - offsetX, y - offsetY); - positionX = x; - positionY = y; + case DrawEllipse (x, y, width, height): + endAndPush(command); + + case DrawRect (x, y, width, height): + endAndPush( command ); + + case DrawRoundRect (x, y, width, height, rx, ry): + endAndPush(command); case MoveTo (x, y): - - beginPath (); - context.moveTo (x - offsetX, y - offsetY); - positionX = x; - positionY = y; + strokeCommands.push( command ); + fillCommands.push( command ); case DrawTriangles (vertices, indices, uvtData, culling, _, _): - - closePath(false); + + fillEnd(); + strokeEnd(); var v = vertices; var ind = indices; @@ -905,7 +665,121 @@ class CanvasGraphics { i += 3; - } + } + + case DrawTiles (sheet, tileData, smooth, flags, count): + + var useScale = (flags & Graphics.TILE_SCALE) > 0; + var useRotation = (flags & Graphics.TILE_ROTATION) > 0; + var useTransform = (flags & Graphics.TILE_TRANS_2x2) > 0; + var useRGB = (flags & Graphics.TILE_RGB) > 0; + var useAlpha = (flags & Graphics.TILE_ALPHA) > 0; + var useRect = (flags & Graphics.TILE_RECT) > 0; + var useOrigin = (flags & Graphics.TILE_ORIGIN) > 0; + var useBlendAdd = (flags & Graphics.TILE_BLEND_ADD) > 0; + + if (useTransform) { useScale = false; useRotation = false; } + + var scaleIndex = 0; + var rotationIndex = 0; + var rgbIndex = 0; + var alphaIndex = 0; + var transformIndex = 0; + + var numValues = 3; + + if (useRect) { numValues = useOrigin ? 8 : 6; } + if (useScale) { scaleIndex = numValues; numValues ++; } + if (useRotation) { rotationIndex = numValues; numValues ++; } + if (useTransform) { transformIndex = numValues; numValues += 4; } + if (useRGB) { rgbIndex = numValues; numValues += 3; } + if (useAlpha) { alphaIndex = numValues; numValues ++; } + + var totalCount = tileData.length; + if (count >= 0 && totalCount > count) totalCount = count; + var itemCount = Std.int (totalCount / numValues); + var index = 0; + + var rect = null; + var center = null; + var previousTileID = -1; + + var surface:Dynamic; + sheet.__bitmap.__sync (); + surface = sheet.__bitmap.__image.src; + + if (useBlendAdd) + context.globalCompositeOperation = "lighter"; + + while (index < totalCount) { + + var tileID = (!useRect) ? Std.int (tileData[index + 2]) : -1; + + if (!useRect && tileID != previousTileID) { + + rect = sheet.__tileRects[tileID]; + center = sheet.__centerPoints[tileID]; + + previousTileID = tileID; + + } + else if (useRect) + { + rect = sheet.__rectTile; + rect.setTo(tileData[index + 2], tileData[index + 3], tileData[index + 4], tileData[index + 5]); + center = sheet.__point; + if (useOrigin) + { + center.setTo(tileData[index + 6], tileData[index + 7]); + } + else + { + center.setTo(0, 0); + } + } + + if (rect != null && rect.width > 0 && rect.height > 0 && center != null) { + + context.save (); + context.translate (tileData[index], tileData[index + 1]); + + if (useRotation) { + + context.rotate (tileData[index + rotationIndex]); + + } + + var scale = 1.0; + + if (useScale) { + + scale = tileData[index + scaleIndex]; + + } + + if (useTransform) { + + context.transform (tileData[index + transformIndex], tileData[index + transformIndex + 1], tileData[index + transformIndex + 2], tileData[index + transformIndex + 3], 0, 0); + + } + + if (useAlpha) { + + context.globalAlpha = tileData[index + alphaIndex]; + + } + + context.drawImage (surface, rect.x, rect.y, rect.width, rect.height, -center.x * scale, -center.y * scale, rect.width * scale, rect.height * scale); + context.restore (); + + } + + index += numValues; + + } + + if (useBlendAdd) + context.globalCompositeOperation = "source-over"; case _: openfl.Lib.notImplemented("CanvasGraphics"); @@ -917,7 +791,12 @@ class CanvasGraphics { } graphics.__dirty = false; - closePath (false); + + if( fillCommands.length > 0 ) + fillEnd(); + + if( strokeCommands.length > 0 ) + strokeEnd(); } diff --git a/openfl/display/Graphics.hx b/openfl/display/Graphics.hx index 1baa54dfdc..a0a5b96adf 100644 --- a/openfl/display/Graphics.hx +++ b/openfl/display/Graphics.hx @@ -911,7 +911,7 @@ class Graphics { */ public function lineStyle (thickness:Null = null, color:Null = null, alpha:Null = null, pixelHinting:Null = null, scaleMode:LineScaleMode = null, caps:CapsStyle = null, joints:JointStyle = null, miterLimit:Null = null):Void { - __halfStrokeWidth = (thickness != null) ? thickness / 2 : 0; + __halfStrokeWidth = thickness > __halfStrokeWidth ? thickness : __halfStrokeWidth; __commands.push (LineStyle (thickness, color, alpha, pixelHinting, scaleMode, caps, joints, miterLimit)); if (thickness != null) __visible = true; From 819b30c66cd3d5c999ca01acadd9338ee5bcb34a Mon Sep 17 00:00:00 2001 From: MrCdK Date: Wed, 29 Apr 2015 01:08:50 +0200 Subject: [PATCH 076/150] Optimized shaders, now they use a projectionMatrix and not a vectors --- openfl/_internal/renderer/AbstractRenderer.hx | 7 ++++ openfl/_internal/renderer/RenderSession.hx | 11 +---- .../_internal/renderer/opengl/GLRenderer.hx | 41 +++++++++++++++---- .../renderer/opengl/shaders2/DefaultShader.hx | 13 ++---- .../opengl/shaders2/DrawTrianglesShader.hx | 14 ++----- .../renderer/opengl/shaders2/FillShader.hx | 13 ++---- .../opengl/shaders2/PatternFillShader.hx | 13 ++---- .../opengl/shaders2/PrimitiveShader.hx | 13 ++---- .../renderer/opengl/utils/FilterManager.hx | 7 ++-- .../renderer/opengl/utils/GraphicsRenderer.hx | 22 ++++------ .../renderer/opengl/utils/SpriteBatch.hx | 24 ++++++----- .../renderer/opengl/utils/StencilManager.hx | 12 +++--- openfl/display/BitmapData.hx | 7 +--- 13 files changed, 93 insertions(+), 104 deletions(-) diff --git a/openfl/_internal/renderer/AbstractRenderer.hx b/openfl/_internal/renderer/AbstractRenderer.hx index 5a3d769eec..00a4563e14 100644 --- a/openfl/_internal/renderer/AbstractRenderer.hx +++ b/openfl/_internal/renderer/AbstractRenderer.hx @@ -34,6 +34,13 @@ class AbstractRenderer { + } + + + public function setViewport (x:Int, y:Int, width:Int, height:Int):Void { + + + } diff --git a/openfl/_internal/renderer/RenderSession.hx b/openfl/_internal/renderer/RenderSession.hx index 77f37dfa5f..3814843ee1 100644 --- a/openfl/_internal/renderer/RenderSession.hx +++ b/openfl/_internal/renderer/RenderSession.hx @@ -5,7 +5,6 @@ import lime.graphics.CanvasRenderContext; import lime.graphics.DOMRenderContext; import lime.graphics.GLRenderContext; import lime.graphics.opengl.GLFramebuffer; -import lime.math.Matrix4; import openfl._internal.renderer.opengl.utils.BlendModeManager; import openfl._internal.renderer.opengl.utils.FilterManager; import openfl._internal.renderer.opengl.utils.MaskManager; @@ -13,6 +12,7 @@ import openfl._internal.renderer.opengl.utils.ShaderManager; import openfl._internal.renderer.opengl.utils.SpriteBatch; import openfl._internal.renderer.opengl.utils.StencilManager; import openfl.display.BlendMode; +import openfl.geom.Matrix; import openfl.geom.Point; @@ -22,23 +22,16 @@ class RenderSession { public var context:CanvasRenderContext; public var element:DOMRenderContext; public var gl:GLRenderContext; - //public var glProgram:ShaderProgram; - //public var mask:Bool; - //public var maskManager:MaskManager; - public var projectionMatrix:Matrix4; public var renderer:AbstractRenderer; - //public var scaleMode:ScaleMode; public var roundPixels:Bool; public var transformProperty:String; public var transformOriginProperty:String; public var vendorPrefix:String; public var z:Int; - //public var smoothProperty:Null = null; + public var projectionMatrix:Matrix; public var drawCount:Int; public var currentBlendMode:BlendMode; - public var projection:Point; - public var offset:Point; public var shaderManager:ShaderManager; public var maskManager:#if neko MaskManager #else Dynamic #end; diff --git a/openfl/_internal/renderer/opengl/GLRenderer.hx b/openfl/_internal/renderer/opengl/GLRenderer.hx index 7cc1e4dd2f..273452fdfa 100644 --- a/openfl/_internal/renderer/opengl/GLRenderer.hx +++ b/openfl/_internal/renderer/opengl/GLRenderer.hx @@ -11,6 +11,7 @@ import openfl.display.BlendMode; import openfl.display.DisplayObject; import openfl.display.Stage; import openfl.errors.Error; +import openfl.geom.Matrix; import openfl.geom.Point; @:access(lime.graphics.opengl.GL) @@ -39,9 +40,15 @@ class GLRenderer extends AbstractRenderer { public var spriteBatch:SpriteBatch; public var stencilManager:StencilManager; public var view:Dynamic; + public var projectionMatrix:Matrix; private var __stage:Dynamic; + private var vpX:Int = 0; + private var vpY:Int = 0; + private var vpWidth:Int = 0; + private var vpHeight:Int = 0; + public function new (width:Int = 800, height:Int = 600, gl:GLRenderContext /*view:Dynamic = null*/, transparent:Bool = false, antialias:Bool = false, preserveDrawingBuffer:Bool = false) { @@ -93,6 +100,8 @@ class GLRenderer extends AbstractRenderer { } + projectionMatrix = new Matrix(); + projection = new Point (); projection.x = this.width / 2; projection.y = -this.height / 2; @@ -120,9 +129,7 @@ class GLRenderer extends AbstractRenderer { renderSession.stencilManager = this.stencilManager; renderSession.renderer = this; renderSession.defaultFramebuffer = this.defaultFramebuffer; - - renderSession.projection = projection; - renderSession.offset = offset; + renderSession.projectionMatrix = this.projectionMatrix; shaderManager.setShader(shaderManager.defaultShader); @@ -161,6 +168,25 @@ class GLRenderer extends AbstractRenderer { } + public override function setViewport(x:Int, y:Int, width:Int, height:Int) { + if (!(vpX == x && vpY == y && vpWidth == width && vpHeight == height)) { + vpX = x; + vpY = y; + vpWidth = width; + vpHeight = height; + gl.viewport(x, y, width, height); + setOrtho(x, y, width, height); + } + } + + public function setOrtho(x:Float, y:Float, width:Float, height:Float) { + var o = projectionMatrix; + o.identity(); + o.a = 1 / width * 2; + o.d = -1 / height * 2; + o.tx = -1 - x * o.a; + o.ty = 1 - y * o.d; + } /*private static function destroyTexture (texture:BaseTexture):Void { @@ -236,7 +262,7 @@ class GLRenderer extends AbstractRenderer { gl.enable (gl.BLEND); gl.colorMask (true, true, true, transparent); - gl.viewport (0, 0, width, height); + setViewport (0, 0, width, height); /*for (key in Texture.TextureCache.keys ()) { @@ -257,7 +283,7 @@ class GLRenderer extends AbstractRenderer { //updateTextures (); var gl = this.gl; - gl.viewport (0, 0, width, height); + setViewport (0, 0, width, height); gl.bindFramebuffer (gl.FRAMEBUFFER, defaultFramebuffer); @@ -284,9 +310,6 @@ class GLRenderer extends AbstractRenderer { renderSession.drawCount = 0; renderSession.currentBlendMode = null; - renderSession.projection = projection; - renderSession.offset = offset; - spriteBatch.begin (renderSession); filterManager.begin (renderSession, buffer); displayObject.__renderGL (renderSession); @@ -303,7 +326,7 @@ class GLRenderer extends AbstractRenderer { super.resize (width, height); - gl.viewport (0, 0, width, height); + setViewport (0, 0, width, height); projection.x = width / 2; projection.y = -height / 2; diff --git a/openfl/_internal/renderer/opengl/shaders2/DefaultShader.hx b/openfl/_internal/renderer/opengl/shaders2/DefaultShader.hx index 4d3ffa0bce..4f1f815b22 100644 --- a/openfl/_internal/renderer/opengl/shaders2/DefaultShader.hx +++ b/openfl/_internal/renderer/opengl/shaders2/DefaultShader.hx @@ -13,16 +13,13 @@ class DefaultShader extends Shader { 'attribute vec2 ${Attrib.TexCoord};', 'attribute vec4 ${Attrib.Color};', - 'uniform vec2 ${Uniform.ProjectionVector};', - 'uniform vec2 ${Uniform.OffsetVector};', + 'uniform mat3 ${Uniform.ProjectionMatrix};', 'varying vec2 vTexCoord;', 'varying vec4 vColor;', - 'const vec2 center = vec2(-1.0, 1.0);', - 'void main(void) {', - ' gl_Position = vec4( ((${Attrib.Position} + ${Uniform.OffsetVector}) / ${Uniform.ProjectionVector}) + center , 0.0, 1.0);', + ' gl_Position = vec4((${Uniform.ProjectionMatrix} * vec3(${Attrib.Position}, 1.0)).xy, 0.0, 1.0);', ' vTexCoord = ${Attrib.TexCoord};', ' vColor = ${Attrib.Color};', '}' @@ -66,8 +63,7 @@ class DefaultShader extends Shader { getAttribLocation(Attrib.Position); getAttribLocation(Attrib.TexCoord); getAttribLocation(Attrib.Color); - getUniformLocation(Uniform.ProjectionVector); - getUniformLocation(Uniform.OffsetVector); + getUniformLocation(Uniform.ProjectionMatrix); getUniformLocation(Uniform.Sampler); getUniformLocation(Uniform.ColorMultiplier); getUniformLocation(Uniform.ColorOffset); @@ -84,8 +80,7 @@ class DefaultShader extends Shader { @:enum private abstract Uniform(String) from String to String { var Sampler = "uSampler0"; - var ProjectionVector = "uProjectionVector"; - var OffsetVector = "uOffsetVector"; + var ProjectionMatrix = "uProjectionMatrix"; var Color = "uColor"; var Alpha = "uAlpha"; var ColorMultiplier = "uColorMultiplier"; diff --git a/openfl/_internal/renderer/opengl/shaders2/DrawTrianglesShader.hx b/openfl/_internal/renderer/opengl/shaders2/DrawTrianglesShader.hx index c7ab789211..a775db9ce7 100644 --- a/openfl/_internal/renderer/opengl/shaders2/DrawTrianglesShader.hx +++ b/openfl/_internal/renderer/opengl/shaders2/DrawTrianglesShader.hx @@ -14,16 +14,13 @@ class DrawTrianglesShader extends Shader { 'attribute vec2 ${Attrib.Position};', 'attribute vec2 ${Attrib.TexCoord};', 'attribute vec4 ${Attrib.Color};', - 'uniform vec2 ${Uniform.ProjectionVector};', - 'uniform vec2 ${Uniform.OffsetVector};', + 'uniform mat3 ${Uniform.ProjectionMatrix};', 'varying vec2 vTexCoord;', 'varying vec4 vColor;', - - 'const vec2 center = vec2(-1.0, 1.0);', 'void main(void) {', - ' gl_Position = vec4( ((${Attrib.Position} + ${Uniform.OffsetVector}) / ${Uniform.ProjectionVector}) + center , 0.0, 1.0);', + ' gl_Position = vec4((${Uniform.ProjectionMatrix} * vec3(${Attrib.Position}, 1.0)).xy, 0.0, 1.0);', ' vTexCoord = ${Attrib.TexCoord};', // the passed color is ARGB format ' vColor = ${Attrib.Color}.bgra;', @@ -73,14 +70,12 @@ class DrawTrianglesShader extends Shader { override function init() { super.init(); - // TODO Modify graphicsrenderer to draw projection -y getAttribLocation(Attrib.Position); getAttribLocation(Attrib.TexCoord); getAttribLocation(Attrib.Color); getUniformLocation(Uniform.Sampler); - getUniformLocation(Uniform.ProjectionVector); - getUniformLocation(Uniform.OffsetVector); + getUniformLocation(Uniform.ProjectionMatrix); getUniformLocation(Uniform.Color); getUniformLocation(Uniform.Alpha); getUniformLocation(Uniform.UseTexture); @@ -100,8 +95,7 @@ class DrawTrianglesShader extends Shader { @:enum private abstract Uniform(String) from String to String { var UseTexture = "uUseTexture"; var Sampler = DefUniform.Sampler; - var ProjectionVector = DefUniform.ProjectionVector; - var OffsetVector = DefUniform.OffsetVector; + var ProjectionMatrix = DefUniform.ProjectionMatrix; var Color = DefUniform.Color; var Alpha = DefUniform.Alpha; var ColorMultiplier = DefUniform.ColorMultiplier; diff --git a/openfl/_internal/renderer/opengl/shaders2/FillShader.hx b/openfl/_internal/renderer/opengl/shaders2/FillShader.hx index ac16823b1b..7113939ceb 100644 --- a/openfl/_internal/renderer/opengl/shaders2/FillShader.hx +++ b/openfl/_internal/renderer/opengl/shaders2/FillShader.hx @@ -12,8 +12,7 @@ class FillShader extends Shader { vertexSrc = [ 'attribute vec2 ${Attrib.Position};', 'uniform mat3 ${Uniform.TranslationMatrix};', - 'uniform vec2 ${Uniform.ProjectionVector};', - 'uniform vec2 ${Uniform.OffsetVector};', + 'uniform mat3 ${Uniform.ProjectionMatrix};', 'uniform vec4 ${Uniform.Color};', 'uniform float ${Uniform.Alpha};', @@ -32,9 +31,7 @@ class FillShader extends Shader { '}', 'void main(void) {', - ' vec3 v = ${Uniform.TranslationMatrix} * vec3(${Attrib.Position}, 1.0);', - ' v -= ${Uniform.OffsetVector}.xyx;', - ' gl_Position = vec4( v.x / ${Uniform.ProjectionVector}.x -1.0, v.y / - ${Uniform.ProjectionVector}.y + 1.0 , 0.0, 1.0);', + ' gl_Position = vec4((${Uniform.ProjectionMatrix} * ${Uniform.TranslationMatrix} * vec3(${Attrib.Position}, 1.0)).xy, 0.0, 1.0);', ' vColor = colorTransform(${Uniform.Color}, ${Uniform.Alpha}, ${Uniform.ColorMultiplier}, ${Uniform.ColorOffset});', '}' @@ -60,8 +57,7 @@ class FillShader extends Shader { getAttribLocation(Attrib.Position); getUniformLocation(Uniform.TranslationMatrix); - getUniformLocation(Uniform.ProjectionVector); - getUniformLocation(Uniform.OffsetVector); + getUniformLocation(Uniform.ProjectionMatrix); getUniformLocation(Uniform.Color); getUniformLocation(Uniform.ColorMultiplier); getUniformLocation(Uniform.ColorOffset); @@ -75,8 +71,7 @@ class FillShader extends Shader { @:enum private abstract Uniform(String) from String to String { var TranslationMatrix = "uTranslationMatrix"; - var ProjectionVector = DefUniform.ProjectionVector; - var OffsetVector = DefUniform.OffsetVector; + var ProjectionMatrix = DefUniform.ProjectionMatrix; var Color = DefUniform.Color; var Alpha = DefUniform.Alpha; var ColorMultiplier = DefUniform.ColorMultiplier; diff --git a/openfl/_internal/renderer/opengl/shaders2/PatternFillShader.hx b/openfl/_internal/renderer/opengl/shaders2/PatternFillShader.hx index bfd069d076..2a3b8b7b43 100644 --- a/openfl/_internal/renderer/opengl/shaders2/PatternFillShader.hx +++ b/openfl/_internal/renderer/opengl/shaders2/PatternFillShader.hx @@ -12,16 +12,13 @@ class PatternFillShader extends Shader { vertexSrc = [ 'attribute vec2 ${Attrib.Position};', 'uniform mat3 ${Uniform.TranslationMatrix};', - 'uniform vec2 ${Uniform.ProjectionVector};', - 'uniform vec2 ${Uniform.OffsetVector};', + 'uniform mat3 ${Uniform.ProjectionMatrix};', 'uniform mat3 ${Uniform.PatternMatrix};', 'varying vec2 vPosition;', 'void main(void) {', - ' vec3 v = ${Uniform.TranslationMatrix} * vec3(${Attrib.Position} , 1.0);', - ' v -= ${Uniform.OffsetVector}.xyx;', - ' gl_Position = vec4( v.x / ${Uniform.ProjectionVector}.x -1.0, v.y / - ${Uniform.ProjectionVector}.y + 1.0 , 0.0, 1.0);', + ' gl_Position = vec4((${Uniform.ProjectionMatrix} * ${Uniform.TranslationMatrix} * vec3(${Attrib.Position}, 1.0)).xy, 0.0, 1.0);', ' vPosition = (${Uniform.PatternMatrix} * vec3(${Attrib.Position}, 1)).xy;', '}' @@ -70,8 +67,7 @@ class PatternFillShader extends Shader { getUniformLocation(Uniform.TranslationMatrix); getUniformLocation(Uniform.PatternMatrix); - getUniformLocation(Uniform.ProjectionVector); - getUniformLocation(Uniform.OffsetVector); + getUniformLocation(Uniform.ProjectionMatrix); getUniformLocation(Uniform.Sampler); getUniformLocation(Uniform.PatternTL); getUniformLocation(Uniform.PatternBR); @@ -92,8 +88,7 @@ class PatternFillShader extends Shader { var PatternTL = "uPatternTL"; var PatternBR = "uPatternBR"; var Sampler = DefUniform.Sampler; - var ProjectionVector = DefUniform.ProjectionVector; - var OffsetVector = DefUniform.OffsetVector; + var ProjectionMatrix = DefUniform.ProjectionMatrix; var Color = DefUniform.Color; var Alpha = DefUniform.Alpha; var ColorMultiplier = DefUniform.ColorMultiplier; diff --git a/openfl/_internal/renderer/opengl/shaders2/PrimitiveShader.hx b/openfl/_internal/renderer/opengl/shaders2/PrimitiveShader.hx index d87d9f9dce..0c46df20c5 100644 --- a/openfl/_internal/renderer/opengl/shaders2/PrimitiveShader.hx +++ b/openfl/_internal/renderer/opengl/shaders2/PrimitiveShader.hx @@ -14,8 +14,7 @@ class PrimitiveShader extends Shader { 'attribute vec4 ${Attrib.Color};', 'uniform mat3 ${Uniform.TranslationMatrix};', - 'uniform vec2 ${Uniform.ProjectionVector};', - 'uniform vec2 ${Uniform.OffsetVector};', + 'uniform mat3 ${Uniform.ProjectionMatrix};', 'uniform vec4 ${Uniform.ColorMultiplier};', 'uniform vec4 ${Uniform.ColorOffset};', 'uniform float ${Uniform.Alpha};', @@ -32,9 +31,7 @@ class PrimitiveShader extends Shader { '}', 'void main(void) {', - ' vec3 v = ${Uniform.TranslationMatrix} * vec3(${Attrib.Position} , 1.0);', - ' v -= ${Uniform.OffsetVector}.xyx;', - ' gl_Position = vec4( v.x / ${Uniform.ProjectionVector}.x -1.0, v.y / -${Uniform.ProjectionVector}.y + 1.0 , 0.0, 1.0);', + ' gl_Position = vec4((${Uniform.ProjectionMatrix} * ${Uniform.TranslationMatrix} * vec3(${Attrib.Position}, 1.0)).xy, 0.0, 1.0);', ' vColor = colorTransform(${Attrib.Color}, ${Uniform.Alpha}, ${Uniform.ColorMultiplier}, ${Uniform.ColorOffset});', '}' ]; @@ -61,8 +58,7 @@ class PrimitiveShader extends Shader { getAttribLocation(Attrib.Position); getAttribLocation(Attrib.Color); getUniformLocation(Uniform.TranslationMatrix); - getUniformLocation(Uniform.ProjectionVector); - getUniformLocation(Uniform.OffsetVector); + getUniformLocation(Uniform.ProjectionMatrix); getUniformLocation(Uniform.Alpha); getUniformLocation(Uniform.ColorMultiplier); getUniformLocation(Uniform.ColorOffset); @@ -77,8 +73,7 @@ class PrimitiveShader extends Shader { @:enum private abstract Uniform(String) from String to String { var TranslationMatrix = "uTranslationMatrix"; - var ProjectionVector = DefUniform.ProjectionVector; - var OffsetVector = DefUniform.OffsetVector; + var ProjectionMatrix = DefUniform.ProjectionMatrix; var Alpha = DefUniform.Alpha; var ColorMultiplier = DefUniform.ColorMultiplier; var ColorOffset = DefUniform.ColorOffset; diff --git a/openfl/_internal/renderer/opengl/utils/FilterManager.hx b/openfl/_internal/renderer/opengl/utils/FilterManager.hx index 29aba486db..5292ad5f77 100644 --- a/openfl/_internal/renderer/opengl/utils/FilterManager.hx +++ b/openfl/_internal/renderer/opengl/utils/FilterManager.hx @@ -104,10 +104,9 @@ class FilterManager { this.renderSession = renderSession; defaultShader = renderSession.shaderManager.defaultShader; - var projection = renderSession.projection; - - width = Std.int (projection.x * 2); - height = Std.int (-projection.y * 2); + // TODO + width = 0; + height = 0; this.buffer = buffer; } diff --git a/openfl/_internal/renderer/opengl/utils/GraphicsRenderer.hx b/openfl/_internal/renderer/opengl/utils/GraphicsRenderer.hx index c3e078b09a..e52c5d8f5d 100644 --- a/openfl/_internal/renderer/opengl/utils/GraphicsRenderer.hx +++ b/openfl/_internal/renderer/opengl/utils/GraphicsRenderer.hx @@ -859,14 +859,13 @@ class GraphicsRenderer { } */ - renderGraphics(object, renderSession, renderSession.projection, false); + renderGraphics(object, renderSession, false); } - public static function renderGraphics (object:DisplayObject, renderSession:RenderSession, projection:Point, ?localCoords:Bool = false):Void { + public static function renderGraphics (object:DisplayObject, renderSession:RenderSession, ?localCoords:Bool = false):Void { var graphics = object.__graphics; var gl = renderSession.gl; - var offset = renderSession.offset; var glStack = graphics.__glStack[GLRenderer.glContextId]; var bucket:GLBucket; @@ -891,15 +890,15 @@ class GraphicsRenderer { if (batchDrawing && !localCoords) { renderSession.spriteBatch.finish(); } - renderSession.stencilManager.pushBucket(bucket, renderSession, projection, translationMatrix.toArray(true)); - var shader = prepareShader(bucket, renderSession, object, projection, translationMatrix.toArray(true)); + renderSession.stencilManager.pushBucket(bucket, renderSession, translationMatrix.toArray(true)); + var shader = prepareShader(bucket, renderSession, object, translationMatrix.toArray(true)); renderFill(bucket, shader, renderSession); renderSession.stencilManager.popBucket(object, bucket, renderSession); case DrawTriangles: if (batchDrawing && !localCoords) { renderSession.spriteBatch.finish(); } - var shader = prepareShader(bucket, renderSession, object, projection, null); + var shader = prepareShader(bucket, renderSession, object, null); renderDrawTriangles(bucket, shader, renderSession); case DrawTiles: if (!batchDrawing) { @@ -922,8 +921,7 @@ class GraphicsRenderer { renderSession.shaderManager.setShader (shader); gl.uniformMatrix3fv (shader.getUniformLocation(PrimitiveUniform.TranslationMatrix), false, translationMatrix.toArray(true)); - gl.uniform2f (shader.getUniformLocation(PrimitiveUniform.ProjectionVector), projection.x, -projection.y); - gl.uniform2f (shader.getUniformLocation(PrimitiveUniform.OffsetVector), -offset.x, -offset.y); + gl.uniformMatrix3fv (shader.getUniformLocation(PrimitiveUniform.ProjectionMatrix), false, renderSession.projectionMatrix.toArray(true)); gl.uniform1f (shader.getUniformLocation(PrimitiveUniform.Alpha), 1); gl.uniform4f (shader.getUniformLocation(FillUniform.ColorMultiplier), ct.redMultiplier, ct.greenMultiplier, ct.blueMultiplier, ct.alphaMultiplier); @@ -1109,9 +1107,8 @@ class GraphicsRenderer { return bucket; } - private static function prepareShader(bucket:GLBucket, renderSession:RenderSession, object:DisplayObject, projection:Point, translationMatrix:Float32Array) { + private static function prepareShader(bucket:GLBucket, renderSession:RenderSession, object:DisplayObject, translationMatrix:Float32Array) { var gl = renderSession.gl; - var offset = renderSession.offset; var shader:Shader = null; shader = switch(bucket.mode) { @@ -1130,8 +1127,8 @@ class GraphicsRenderer { var newShader = renderSession.shaderManager.setShader(shader); // common uniforms - gl.uniform2f (shader.getUniformLocation(DefUniform.OffsetVector), -offset.x, -offset.y); gl.uniform1f (shader.getUniformLocation(DefUniform.Alpha), object.__worldAlpha); + gl.uniformMatrix3fv(shader.getUniformLocation(DefUniform.ProjectionMatrix), false, @:privateAccess renderSession.projectionMatrix.toArray(true)); var ct:ColorTransform = object.__worldColorTransform; gl.uniform4f (shader.getUniformLocation(FillUniform.ColorMultiplier), ct.redMultiplier, ct.greenMultiplier, ct.blueMultiplier, ct.alphaMultiplier); @@ -1140,17 +1137,14 @@ class GraphicsRenderer { // specific uniforms switch(bucket.mode) { case Fill: - gl.uniform2f (shader.getUniformLocation(DefUniform.ProjectionVector), projection.x, -projection.y); gl.uniformMatrix3fv (shader.getUniformLocation(FillUniform.TranslationMatrix), false, translationMatrix); gl.uniform4fv (shader.getUniformLocation(FillUniform.Color), new Float32Array (bucket.color)); case PatternFill: - gl.uniform2f (shader.getUniformLocation(PatternFillUniform.ProjectionVector), projection.x, -projection.y); gl.uniformMatrix3fv (shader.getUniformLocation(PatternFillUniform.TranslationMatrix), false, translationMatrix); gl.uniform2f(shader.getUniformLocation(PatternFillUniform.PatternTL), bucket.textureTL.x, bucket.textureTL.y); gl.uniform2f(shader.getUniformLocation(PatternFillUniform.PatternBR), bucket.textureBR.x, bucket.textureBR.y); gl.uniformMatrix3fv(shader.getUniformLocation(PatternFillUniform.PatternMatrix), false, bucket.textureMatrix.toArray(false)); case DrawTriangles: - gl.uniform2f (shader.getUniformLocation(DrawTrianglesUniform.ProjectionVector), projection.x, projection.y); if (bucket.texture != null) { gl.uniform1i(shader.getUniformLocation(DrawTrianglesUniform.UseTexture), 1); } else { diff --git a/openfl/_internal/renderer/opengl/utils/SpriteBatch.hx b/openfl/_internal/renderer/opengl/utils/SpriteBatch.hx index 2f8f08b760..5346a9b9a1 100644 --- a/openfl/_internal/renderer/opengl/utils/SpriteBatch.hx +++ b/openfl/_internal/renderer/opengl/utils/SpriteBatch.hx @@ -22,6 +22,7 @@ import lime.utils.*; @:access(openfl.display.Graphics) @:access(openfl.display.DisplayObject) @:access(openfl.display.Tilesheet) +@:access(openfl.geom.Matrix) class SpriteBatch { static inline var VERTS_PER_SPRITE:Int = 4; @@ -379,6 +380,7 @@ class SpriteBatch { var w0:Float, w1:Float, h0:Float, h1:Float; + if (pivot == null) { w0 = width; w1 = 0; h0 = height; h1 = 0; @@ -396,25 +398,26 @@ class SpriteBatch { var tx = matrix.tx; var ty = matrix.ty; var cOffsetIndex = 0; + var off = 0; - positions[index++] = (a * w1 + c * h1 + tx); - positions[index++] = (d * h1 + b * w1 + ty); + positions[index++] = (a * w1 + c * h1 + tx) + off; + positions[index++] = (d * h1 + b * w1 + ty) + off; positions[index++] = uvs.x0; positions[index++] = uvs.y0; if(enableColor) { colors[index++] = color; } - positions[index++] = (a * w0 + c * h1 + tx); - positions[index++] = (d * h1 + b * w0 + ty); + positions[index++] = (a * w0 + c * h1 + tx) + off; + positions[index++] = (d * h1 + b * w0 + ty) + off; positions[index++] = uvs.x1; positions[index++] = uvs.y1; if(enableColor) { colors[index++] = color; } - positions[index++] = (a * w0 + c * h0 + tx); - positions[index++] = (d * h0 + b * w0 + ty); + positions[index++] = (a * w0 + c * h0 + tx) + off; + positions[index++] = (d * h0 + b * w0 + ty) + off; positions[index++] = uvs.x2; positions[index++] = uvs.y2; if(enableColor) { @@ -422,8 +425,8 @@ class SpriteBatch { } - positions[index++] = (a * w1 + c * h0 + tx); - positions[index++] = (d * h0 + b * w1 + ty); + positions[index++] = (a * w1 + c * h0 + tx) + off; + positions[index++] = (d * h0 + b * w1 + ty) + off; positions[index++] = uvs.x3; positions[index++] = uvs.y3; if(enableColor) { @@ -526,8 +529,7 @@ class SpriteBatch { // TODO cache this somehow?, don't do each state change? shader.bindVertexArray(vertexArray); - var projection = renderSession.projection; - gl.uniform2f(shader.getUniformLocation(DefUniform.ProjectionVector), projection.x, projection.y); + gl.uniformMatrix3fv(shader.getUniformLocation(DefUniform.ProjectionMatrix), false, renderSession.projectionMatrix.toArray(true)); if (state.colorTransform != null) { var ct = state.colorTransform; @@ -544,6 +546,7 @@ class SpriteBatch { gl.bindTexture(gl.TEXTURE_2D, state.texture); if (state.textureSmooth) { + //if (false) { gl.texParameteri (gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); gl.texParameteri (gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); } else { @@ -590,6 +593,7 @@ class SpriteBatch { return r; } + } @:access(openfl.geom.ColorTransform) diff --git a/openfl/_internal/renderer/opengl/utils/StencilManager.hx b/openfl/_internal/renderer/opengl/utils/StencilManager.hx index 527f347d04..ccf457d3df 100644 --- a/openfl/_internal/renderer/opengl/utils/StencilManager.hx +++ b/openfl/_internal/renderer/opengl/utils/StencilManager.hx @@ -38,21 +38,19 @@ class StencilManager { } - public inline function prepareGraphics(fill:GLBucketData, renderSession:RenderSession, projection:Point, translationMatrix:Float32Array):Void { - var offset = renderSession.offset; + public inline function prepareGraphics(fill:GLBucketData, renderSession:RenderSession, translationMatrix:Float32Array):Void { var shader = renderSession.shaderManager.fillShader; renderSession.shaderManager.setShader (shader); gl.uniformMatrix3fv (shader.getUniformLocation(FillUniform.TranslationMatrix), false, translationMatrix); - gl.uniform2f (shader.getUniformLocation(FillUniform.ProjectionVector), projection.x, -projection.y); - gl.uniform2f (shader.getUniformLocation(FillUniform.OffsetVector), -offset.x, -offset.y); + gl.uniformMatrix3fv (shader.getUniformLocation(FillUniform.ProjectionMatrix), false, renderSession.projectionMatrix.toArray(true)); fill.vertexArray.bind(); shader.bindVertexArray(fill.vertexArray); gl.bindBuffer (gl.ELEMENT_ARRAY_BUFFER, fill.indexBuffer); } - public function pushBucket (bucket:GLBucket, renderSession:RenderSession, projection:Point, translationMatrix:Float32Array, ?isMask:Bool = false):Void { + public function pushBucket (bucket:GLBucket, renderSession:RenderSession, translationMatrix:Float32Array, ?isMask:Bool = false):Void { if(!isMask) { gl.enable(gl.STENCIL_TEST); @@ -68,7 +66,7 @@ class StencilManager { for (fill in bucket.fills) { if (fill.available) continue; - prepareGraphics(fill, renderSession, projection, translationMatrix); + prepareGraphics(fill, renderSession, translationMatrix); gl.drawElements (fill.drawMode, fill.glIndices.length, gl.UNSIGNED_SHORT, 0); } @@ -126,7 +124,7 @@ class StencilManager { switch(bucket.mode) { case Fill, PatternFill: - pushBucket(bucket, renderSession, renderSession.projection, translationMatrix.toArray(true), true); + pushBucket(bucket, renderSession, translationMatrix.toArray(true), true); case _: } } diff --git a/openfl/display/BitmapData.hx b/openfl/display/BitmapData.hx index 7107de8d07..9f963208e5 100644 --- a/openfl/display/BitmapData.hx +++ b/openfl/display/BitmapData.hx @@ -1663,12 +1663,10 @@ class BitmapData implements IBitmapDrawable { if (gl == null) return; var spritebatch = renderSession.spriteBatch; - var mainProjection = renderSession.projection; var renderTransparent = renderSession.renderer.transparent; var tmpRect = clipRect == null ? new Rectangle(0, 0, width, height) : clipRect.clone(); - renderSession.projection = new Point((width / 2), -(height / 2)); renderSession.renderer.transparent = transparent; if (__framebuffer == null) { @@ -1678,7 +1676,7 @@ class BitmapData implements IBitmapDrawable { __framebuffer.resize(width, height); gl.bindFramebuffer(gl.FRAMEBUFFER, __framebuffer.frameBuffer); - gl.viewport (0, 0, width, height); + renderer.setViewport (0, 0, width, height); spritebatch.begin(renderSession, drawSelf ? null : tmpRect); @@ -1741,9 +1739,8 @@ class BitmapData implements IBitmapDrawable { gl.bindFramebuffer(gl.FRAMEBUFFER, renderSession.defaultFramebuffer); - gl.viewport(0, 0, renderSession.renderer.width, renderSession.renderer.height); + renderer.setViewport (0, 0, renderSession.renderer.width, renderSession.renderer.height); - renderSession.projection = mainProjection; renderSession.renderer.transparent = renderTransparent; gl.colorMask(true, true, true, renderSession.renderer.transparent); From ea8d4f7f95a578e44573764cfe33e46d231f6692 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Tue, 28 Apr 2015 22:44:01 -0700 Subject: [PATCH 077/150] Improve TextField selectable=false --- openfl/text/TextField.hx | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/openfl/text/TextField.hx b/openfl/text/TextField.hx index 046e7a26ec..027658d9e7 100644 --- a/openfl/text/TextField.hx +++ b/openfl/text/TextField.hx @@ -478,7 +478,7 @@ class TextField extends InteractiveObject { * * @default true */ - public var selectable:Bool; + public var selectable (default, set):Bool; /** * The zero-based character index value of the first character in the current @@ -569,6 +569,7 @@ class TextField extends InteractiveObject { @:noCompletion private var __measuredHeight:Int; @:noCompletion private var __measuredWidth:Int; @:noCompletion private var __ranges:Array; + @:noCompletion private var __selectable:Bool; @:noCompletion private var __selectionStart:Int; @:noCompletion private var __showCursor:Bool; @:noCompletion private var __text:String; @@ -1010,7 +1011,7 @@ class TextField extends InteractiveObject { @:noCompletion private override function __getCursor ():MouseCursor { - return type == INPUT ? TEXT : null; + return (type == INPUT && selectable) ? TEXT : null; } @@ -1794,6 +1795,8 @@ class TextField extends InteractiveObject { @:noCompletion private function this_onMouseDown (event:MouseEvent):Void { + if (!selectable) return; + __selectionStart = __getPosition (event.localX, event.localY); stage.addEventListener (MouseEvent.MOUSE_MOVE, stage_onMouseMove); @@ -2051,7 +2054,20 @@ class TextField extends InteractiveObject { } - @:noCompletion public function get_text ():String { + @:noCompletion private function set_selectable (value:Bool):Bool { + + if (!value && selectable && type == TextFieldType.INPUT) { + + this_onRemovedFromStage (null); + + } + + return selectable = value; + + } + + + @:noCompletion private function get_text ():String { if (__isHTML) { @@ -2064,7 +2080,7 @@ class TextField extends InteractiveObject { } - @:noCompletion public function set_text (value:String):String { + @:noCompletion private function set_text (value:String):String { #if (js && html5) if (__text != value && __hiddenInput != null) __hiddenInput.value = value; #end if (__isHTML || __text != value) __dirty = true; From a244bd8f9577be4343d6b7118bef7bc670f45453 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Wed, 29 Apr 2015 03:22:23 -0700 Subject: [PATCH 078/150] Improve text input on iOS 6 and 7 --- openfl/text/TextField.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openfl/text/TextField.hx b/openfl/text/TextField.hx index 027658d9e7..7034fe44fb 100644 --- a/openfl/text/TextField.hx +++ b/openfl/text/TextField.hx @@ -924,7 +924,7 @@ class TextField extends InteractiveObject { __hiddenInput.style.opacity = "0"; __hiddenInput.style.color = "transparent"; - if (~/(iPad|iPhone|iPod)/g.match (Browser.window.navigator.userAgent)) { + if (~/(iPad|iPhone|iPod).*os 8_/g.match (Browser.window.navigator.userAgent)) { __hiddenInput.style.fontSize = "0px"; From 512f538de3f6de9636272d59903723342ef6c07d Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Wed, 29 Apr 2015 03:32:17 -0700 Subject: [PATCH 079/150] Compile fix --- openfl/text/TextField.hx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openfl/text/TextField.hx b/openfl/text/TextField.hx index 7034fe44fb..986c1644ca 100644 --- a/openfl/text/TextField.hx +++ b/openfl/text/TextField.hx @@ -2056,11 +2056,13 @@ class TextField extends InteractiveObject { @:noCompletion private function set_selectable (value:Bool):Bool { + #if (js && html5) if (!value && selectable && type == TextFieldType.INPUT) { this_onRemovedFromStage (null); } + #end return selectable = value; From a4021233c3d76acde3bd1f5b17a1ec4f165abcdc Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Wed, 29 Apr 2015 04:35:13 -0700 Subject: [PATCH 080/150] Fix render of default OpenFL preloader --- openfl/_internal/renderer/canvas/CanvasGraphics.hx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openfl/_internal/renderer/canvas/CanvasGraphics.hx b/openfl/_internal/renderer/canvas/CanvasGraphics.hx index cc1d61ac51..701606cd34 100644 --- a/openfl/_internal/renderer/canvas/CanvasGraphics.hx +++ b/openfl/_internal/renderer/canvas/CanvasGraphics.hx @@ -193,10 +193,10 @@ class CanvasGraphics { inversePendingMatrix = null; } - + case BeginFill (rgb, alpha): - if ( alpha <= 0.07 ) + if ( alpha < 0.005 ) { hasFill = false; } From 9fae3ddd6504f4228255c8cbd0ebe6b5709b6033 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Wed, 29 Apr 2015 04:35:30 -0700 Subject: [PATCH 081/150] Fix blinking cursor in text input --- openfl/text/TextField.hx | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/openfl/text/TextField.hx b/openfl/text/TextField.hx index 986c1644ca..d11dace9d1 100644 --- a/openfl/text/TextField.hx +++ b/openfl/text/TextField.hx @@ -924,20 +924,25 @@ class TextField extends InteractiveObject { __hiddenInput.style.opacity = "0"; __hiddenInput.style.color = "transparent"; - if (~/(iPad|iPhone|iPod).*os 8_/g.match (Browser.window.navigator.userAgent)) { + // TODO: Position for mobile browsers better + + __hiddenInput.style.left = "0px"; + __hiddenInput.style.top = "50%"; + + if (~/(iPad|iPhone|iPod).*OS 8_/gi.match (Browser.window.navigator.userAgent)) { __hiddenInput.style.fontSize = "0px"; + __hiddenInput.style.width = '0px'; + __hiddenInput.style.height = '0px'; + + } else { + + __hiddenInput.style.width = '1px'; + __hiddenInput.style.height = '1px'; } untyped (__hiddenInput.style).pointerEvents = 'none'; - - // TODO: Position for mobile browsers better - - __hiddenInput.style.left = "0px"; - __hiddenInput.style.top = "50%"; - __hiddenInput.style.width = '1px'; - __hiddenInput.style.height = '1px'; __hiddenInput.style.zIndex = "-10000000"; if (maxChars > 0) { From 8f1358da39f7ac5d55ce76813ea50147930c810b Mon Sep 17 00:00:00 2001 From: MrCdK Date: Wed, 29 Apr 2015 19:33:18 +0200 Subject: [PATCH 082/150] Implemented pixelSnapping (kind of) It will snap when the bitmap.pixelSnapping is set to AUTO or ALWAYS Tilesheet.drawTiles() is always NEVER --- openfl/_internal/renderer/opengl/GLBitmap.hx | 2 +- .../renderer/opengl/utils/SpriteBatch.hx | 52 ++++++++++++++----- 2 files changed, 39 insertions(+), 15 deletions(-) diff --git a/openfl/_internal/renderer/opengl/GLBitmap.hx b/openfl/_internal/renderer/opengl/GLBitmap.hx index a24726d95a..cebb81b10a 100644 --- a/openfl/_internal/renderer/opengl/GLBitmap.hx +++ b/openfl/_internal/renderer/opengl/GLBitmap.hx @@ -15,7 +15,7 @@ class GLBitmap { if (!bitmap.__renderable || bitmap.__worldAlpha <= 0 || bitmap.bitmapData == null || !bitmap.bitmapData.__isValid) return; - renderSession.spriteBatch.renderBitmapData(bitmap.bitmapData, bitmap.smoothing, bitmap.__worldTransform, bitmap.__worldColorTransform, bitmap.__worldAlpha, bitmap.blendMode); + renderSession.spriteBatch.renderBitmapData(bitmap.bitmapData, bitmap.smoothing, bitmap.__worldTransform, bitmap.__worldColorTransform, bitmap.__worldAlpha, bitmap.blendMode, bitmap.pixelSnapping); } diff --git a/openfl/_internal/renderer/opengl/utils/SpriteBatch.hx b/openfl/_internal/renderer/opengl/utils/SpriteBatch.hx index 5346a9b9a1..d788c35ac8 100644 --- a/openfl/_internal/renderer/opengl/utils/SpriteBatch.hx +++ b/openfl/_internal/renderer/opengl/utils/SpriteBatch.hx @@ -8,6 +8,7 @@ import openfl._internal.renderer.opengl.utils.VertexAttribute; import openfl._internal.renderer.RenderSession; import openfl.display.BitmapData; import openfl.display.DisplayObject; +import openfl.display.PixelSnapping; import openfl.display.Tilesheet; import openfl.geom.ColorTransform; import openfl.geom.Matrix; @@ -149,7 +150,7 @@ class SpriteBatch { flush(); } - public function renderBitmapData(bitmapData:BitmapData, smoothing:Bool, matrix:Matrix, ct:ColorTransform, ?alpha:Float = 1, ?blendMode:BlendMode) { + public function renderBitmapData(bitmapData:BitmapData, smoothing:Bool, matrix:Matrix, ct:ColorTransform, ?alpha:Float = 1, ?blendMode:BlendMode, ?pixelSnapping:PixelSnapping) { if (bitmapData == null) return; var texture = bitmapData.getTexture(gl); @@ -166,7 +167,7 @@ class SpriteBatch { enableAttributes(0); var index = batchedSprites * 4 * elementsPerVertex; - fillVertices(index, bitmapData.width, bitmapData.height, matrix, uvs, null, color); + fillVertices(index, bitmapData.width, bitmapData.height, matrix, uvs, null, color, pixelSnapping); setState(batchedSprites, texture, smoothing, blendMode, ct, true); @@ -331,7 +332,7 @@ class SpriteBatch { color = ((Std.int(alpha * 255)) & 0xFF) << 24 | (tint & 0xFF) << 16 | ((tint >> 8) & 0xFF) << 8 | ((tint >> 16) & 0xFF); - fillVertices(bIndex, rect.width, rect.height, matrix, uvs, null, color); + fillVertices(bIndex, rect.width, rect.height, matrix, uvs, null, color, NEVER); setState(batchedSprites, texture, smooth, blendMode, object.__worldColorTransform, false); @@ -376,7 +377,7 @@ class SpriteBatch { } inline function fillVertices(index:Int, width:Float, height:Float, matrix:Matrix, uvs:TextureUvs, ?pivot:Point, - ?color:Int = 0xFFFFFFFF) { + ?color:Int = 0xFFFFFFFF, ?pixelSnapping:PixelSnapping) { var w0:Float, w1:Float, h0:Float, h1:Float; @@ -391,6 +392,11 @@ class SpriteBatch { h1 = height * -pivot.y; } + if (pixelSnapping == null) { + pixelSnapping = PixelSnapping.NEVER; + } + + var snap = pixelSnapping != NEVER; var a = matrix.a; var b = matrix.b; var c = matrix.c; @@ -398,35 +404,53 @@ class SpriteBatch { var tx = matrix.tx; var ty = matrix.ty; var cOffsetIndex = 0; - var off = 0; - positions[index++] = (a * w1 + c * h1 + tx) + off; - positions[index++] = (d * h1 + b * w1 + ty) + off; + if(!snap) { + positions[index++] = (a * w1 + c * h1 + tx); + positions[index++] = (d * h1 + b * w1 + ty); + } else { + positions[index++] = Math.fround(a * w1 + c * h1 + tx); + positions[index++] = Math.fround(d * h1 + b * w1 + ty); + } positions[index++] = uvs.x0; positions[index++] = uvs.y0; if(enableColor) { colors[index++] = color; } - positions[index++] = (a * w0 + c * h1 + tx) + off; - positions[index++] = (d * h1 + b * w0 + ty) + off; + if(!snap) { + positions[index++] = (a * w0 + c * h1 + tx); + positions[index++] = (d * h1 + b * w0 + ty); + } else { + positions[index++] = Math.fround(a * w0 + c * h1 + tx); + positions[index++] = Math.fround(d * h1 + b * w0 + ty); + } positions[index++] = uvs.x1; positions[index++] = uvs.y1; if(enableColor) { colors[index++] = color; } - positions[index++] = (a * w0 + c * h0 + tx) + off; - positions[index++] = (d * h0 + b * w0 + ty) + off; + if(!snap) { + positions[index++] = (a * w0 + c * h0 + tx); + positions[index++] = (d * h0 + b * w0 + ty); + } else { + positions[index++] = Math.fround(a * w0 + c * h0 + tx); + positions[index++] = Math.fround(d * h0 + b * w0 + ty); + } positions[index++] = uvs.x2; positions[index++] = uvs.y2; if(enableColor) { colors[index++] = color; } - - positions[index++] = (a * w1 + c * h0 + tx) + off; - positions[index++] = (d * h0 + b * w1 + ty) + off; + if(!snap) { + positions[index++] = (a * w1 + c * h0 + tx); + positions[index++] = (d * h0 + b * w1 + ty); + } else { + positions[index++] = Math.fround(a * w1 + c * h0 + tx); + positions[index++] = Math.fround(d * h0 + b * w1 + ty); + } positions[index++] = uvs.x3; positions[index++] = uvs.y3; if(enableColor) { From fefcb3ef871c8db11ba61ef8839fc03876f845d4 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Wed, 29 Apr 2015 13:26:27 -0700 Subject: [PATCH 083/150] Fix support for hybrid --- openfl/Assets.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openfl/Assets.hx b/openfl/Assets.hx index ade59e1d57..078e48e4ab 100644 --- a/openfl/Assets.hx +++ b/openfl/Assets.hx @@ -429,7 +429,7 @@ class Assets { #else - return (bitmapData != null && bitmapData.__image != null); + return (bitmapData != null && #if !lime_hybrid bitmapData.__image != null #else bitmapData.__handle != null #end); #end #end From 81979c4d0563a4f9262b72b0277b34a1ccb0aaa7 Mon Sep 17 00:00:00 2001 From: MrCdK Date: Wed, 29 Apr 2015 23:07:01 +0200 Subject: [PATCH 084/150] Fix wrong pattern matrix calculations on Graphics.beginBitmapFill() --- .../renderer/opengl/utils/GraphicsRenderer.hx | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/openfl/_internal/renderer/opengl/utils/GraphicsRenderer.hx b/openfl/_internal/renderer/opengl/utils/GraphicsRenderer.hx index c3e078b09a..4c5ea39c22 100644 --- a/openfl/_internal/renderer/opengl/utils/GraphicsRenderer.hx +++ b/openfl/_internal/renderer/opengl/utils/GraphicsRenderer.hx @@ -1035,8 +1035,6 @@ class GraphicsRenderer { bucket.uploadTileBuffer = true; //prepare the matrix - var tMatrix = bucket.textureMatrix; - tMatrix.identity(); var pMatrix:Matrix; if (m == null) { pMatrix = new Matrix(); @@ -1044,19 +1042,19 @@ class GraphicsRenderer { pMatrix = m.clone(); } - tMatrix.concat(pMatrix); - pMatrix = pMatrix.invert(); - var tx = (pMatrix.tx) / (b.width); - var ty = (pMatrix.ty) / (b.height); + pMatrix.invert(); + pMatrix.scale(1 / b.width, 1 / b.height); + var tx = pMatrix.tx; + var ty = pMatrix.ty; + pMatrix.tx = 0; + pMatrix.ty = 0; bucket.textureTL.x = tx; bucket.textureTL.y = ty; bucket.textureBR.x = tx + 1; bucket.textureBR.y = ty + 1; - - tMatrix.scale(1 / b.width, 1 / b.height); - - bucket.textureMatrix = tMatrix; + + bucket.textureMatrix = pMatrix; case _: bucket = switchBucket(path.fillIndex, glStack, Line); bucket.uploadTileBuffer = false; @@ -1148,7 +1146,7 @@ class GraphicsRenderer { gl.uniformMatrix3fv (shader.getUniformLocation(PatternFillUniform.TranslationMatrix), false, translationMatrix); gl.uniform2f(shader.getUniformLocation(PatternFillUniform.PatternTL), bucket.textureTL.x, bucket.textureTL.y); gl.uniform2f(shader.getUniformLocation(PatternFillUniform.PatternBR), bucket.textureBR.x, bucket.textureBR.y); - gl.uniformMatrix3fv(shader.getUniformLocation(PatternFillUniform.PatternMatrix), false, bucket.textureMatrix.toArray(false)); + gl.uniformMatrix3fv(shader.getUniformLocation(PatternFillUniform.PatternMatrix), false, bucket.textureMatrix.toArray(true)); case DrawTriangles: gl.uniform2f (shader.getUniformLocation(DrawTrianglesUniform.ProjectionVector), projection.x, projection.y); if (bucket.texture != null) { From 2400e4a6ae2702ca91ef7e612cd5a56671526847 Mon Sep 17 00:00:00 2001 From: MrCdK Date: Wed, 29 Apr 2015 23:49:35 +0200 Subject: [PATCH 085/150] BitmapData should default to nearest filtering. Bitmap is the one enabling or disabling smoothing. --- openfl/display/BitmapData.hx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openfl/display/BitmapData.hx b/openfl/display/BitmapData.hx index 9f963208e5..b1ad4588ef 100644 --- a/openfl/display/BitmapData.hx +++ b/openfl/display/BitmapData.hx @@ -895,8 +895,8 @@ class BitmapData implements IBitmapDrawable { gl.bindTexture (gl.TEXTURE_2D, __texture); gl.texParameteri (gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri (gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - gl.texParameteri (gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); - gl.texParameteri (gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + gl.texParameteri (gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texParameteri (gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); __image.dirty = true; } @@ -1648,7 +1648,7 @@ class BitmapData implements IBitmapDrawable { @:noCompletion @:dox(hide) public function __renderGL (renderSession:RenderSession):Void { - renderSession.spriteBatch.renderBitmapData(this, true, __worldTransform, __worldColorTransform, __worldColorTransform.alphaMultiplier, blendMode); + renderSession.spriteBatch.renderBitmapData(this, false, __worldTransform, __worldColorTransform, __worldColorTransform.alphaMultiplier, blendMode); } From 1db26e057d320f50c5ad57358fde67fc921a515f Mon Sep 17 00:00:00 2001 From: Jay Sistar Date: Wed, 29 Apr 2015 17:58:23 -0400 Subject: [PATCH 086/150] Put the BlendModeManager and ShaderManager in a sane state after OpenGLView renders. --- .../renderer/opengl/utils/BlendModeManager.hx | 14 ++++++++++---- .../renderer/opengl/utils/ShaderManager.hx | 13 +++++++++++-- openfl/display/OpenGLView.hx | 4 +++- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/openfl/_internal/renderer/opengl/utils/BlendModeManager.hx b/openfl/_internal/renderer/opengl/utils/BlendModeManager.hx index d7bee6d554..f5f85515aa 100644 --- a/openfl/_internal/renderer/opengl/utils/BlendModeManager.hx +++ b/openfl/_internal/renderer/opengl/utils/BlendModeManager.hx @@ -27,10 +27,16 @@ class BlendModeManager { } - public function setBlendMode (blendMode:BlendMode):Bool { + public function setBlendMode (blendMode:BlendMode, ?force:Bool = false):Bool { - if (blendMode == null) blendMode = BlendMode.NORMAL; - if (currentBlendMode == blendMode) { + if (blendMode == null) { + + blendMode = BlendMode.NORMAL; + force = true; + + } + + if (!force && currentBlendMode == blendMode) { return false; @@ -46,4 +52,4 @@ class BlendModeManager { } -} \ No newline at end of file +} diff --git a/openfl/_internal/renderer/opengl/utils/ShaderManager.hx b/openfl/_internal/renderer/opengl/utils/ShaderManager.hx index 65fa350167..1910e1da5b 100644 --- a/openfl/_internal/renderer/opengl/utils/ShaderManager.hx +++ b/openfl/_internal/renderer/opengl/utils/ShaderManager.hx @@ -44,11 +44,20 @@ class ShaderManager { } public function setShader(shader:Shader, ?force:Bool = false) { - if (!force && currentShader.ID == shader.ID) return false; + if (shader == null) { + // Assume we want to force, if we get called with null. + currentShader = null; + gl.useProgram(null); + return true; + } + + if (currentShader != null && !force && currentShader.ID == shader.ID) { + return false; + } currentShader = shader; gl.useProgram(shader.program); return true; } -} \ No newline at end of file +} diff --git a/openfl/display/OpenGLView.hx b/openfl/display/OpenGLView.hx index 31185ca587..a253fd3730 100644 --- a/openfl/display/OpenGLView.hx +++ b/openfl/display/OpenGLView.hx @@ -184,6 +184,8 @@ class OpenGLView extends DirectRenderer { if (__render != null) __render (rect); + renderSession.shaderManager.setShader(null); + renderSession.blendModeManager.setBlendMode(null); } } @@ -240,4 +242,4 @@ class OpenGLView extends DirectRenderer { #else typedef OpenGLView = openfl._legacy.display.OpenGLView; -#end \ No newline at end of file +#end From cb8084ffa6fc311230216d01c39c7289169e7c09 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Wed, 29 Apr 2015 15:30:05 -0700 Subject: [PATCH 087/150] Improve text input --- .../renderer/canvas/CanvasTextField.hx | 10 ++-- openfl/text/TextField.hx | 53 ++++++++++++++++--- 2 files changed, 51 insertions(+), 12 deletions(-) diff --git a/openfl/_internal/renderer/canvas/CanvasTextField.hx b/openfl/_internal/renderer/canvas/CanvasTextField.hx index 55d4fd70b3..9d35e29b95 100644 --- a/openfl/_internal/renderer/canvas/CanvasTextField.hx +++ b/openfl/_internal/renderer/canvas/CanvasTextField.hx @@ -273,17 +273,19 @@ class CanvasTextField { var cursorOffset = textField.__getTextWidth (text.substring (0, textField.__cursorPosition)) + 3; context.fillStyle = "#" + StringTools.hex (textField.__textFormat.color, 6); - context.fillRect (cursorOffset, 5, 1, (textField.__textFormat.size * 1.185) - 5); + context.fillRect (cursorOffset, 5, 1, (textField.__textFormat.size * 1.185) - 4); } else if (textField.__hasFocus && (Math.abs (textField.__selectionStart - textField.__cursorPosition)) > 0 && !textField.__isKeyDown) { var lowPos = Std.int (Math.min (textField.__selectionStart, textField.__cursorPosition)); var highPos = Std.int (Math.max (textField.__selectionStart, textField.__cursorPosition)); - var xPos = textField.__getTextWidth (text.substring (0, lowPos)); + var xPos = textField.__getTextWidth (text.substring (0, lowPos)) + 2; var widthPos = textField.__getTextWidth (text.substring (lowPos, highPos)); - context.fillStyle = "#" + StringTools.hex (textField.__textFormat.color, 6); - context.fillRect (xPos, 5, widthPos, textField.__textFormat.size - 5); + // TODO: White text + + context.fillStyle = "#000000"; + context.fillRect (xPos, 5, widthPos, (textField.__textFormat.size * 1.185) - 4); } diff --git a/openfl/text/TextField.hx b/openfl/text/TextField.hx index d11dace9d1..378a43b334 100644 --- a/openfl/text/TextField.hx +++ b/openfl/text/TextField.hx @@ -1349,12 +1349,14 @@ class TextField extends InteractiveObject { @:noCompletion private function __getPosition (x:Float, y:Float):Int { + if (x <= 2) return 0; + var value:String = text; var text:String = value; - var totalW:Float = 0; + var totalW:Float = 2; var pos = text.length; - if (x < __getTextWidth (text)) { + if (x < __getTextWidth (text) + 2) { for (i in 0...text.length) { @@ -1711,7 +1713,8 @@ class TextField extends InteractiveObject { if (__hasFocus && __selectionStart >= 0) { - __cursorPosition = __getPosition (event.localX, event.localY); + var localPoint = globalToLocal (new Point (event.stageX, event.stageY)); + __cursorPosition = __getPosition (localPoint.x, localPoint.y); __dirty = true; } @@ -1726,7 +1729,8 @@ class TextField extends InteractiveObject { if (stage.focus == this) { - var upPos:Int = __getPosition (event.localX, event.localY); + var localPoint = globalToLocal (new Point (event.stageX, event.stageY)); + var upPos:Int = __getPosition (localPoint.x, localPoint.y); var leftPos:Int; var rightPos:Int; @@ -1802,7 +1806,9 @@ class TextField extends InteractiveObject { if (!selectable) return; - __selectionStart = __getPosition (event.localX, event.localY); + var localPoint = globalToLocal (new Point (event.stageX, event.stageY)); + __selectionStart = __getPosition (localPoint.x, localPoint.y); + __cursorPosition = __selectionStart; stage.addEventListener (MouseEvent.MOUSE_MOVE, stage_onMouseMove); stage.addEventListener (MouseEvent.MOUSE_UP, stage_onMouseUp); @@ -1957,7 +1963,17 @@ class TextField extends InteractiveObject { if (segments.length == 1) { value = new EReg ("<.*?>", "g").replace (value, ""); - #if (js && html5) if (__hiddenInput != null) __hiddenInput.value = value; #end + #if (js && html5) + if (__text != value && __hiddenInput != null) { + + var selectionStart = __hiddenInput.selectionStart; + var selectionEnd = __hiddenInput.selectionEnd; + __hiddenInput.value = value; + __hiddenInput.selectionStart = selectionStart; + __hiddenInput.selectionEnd = selectionEnd; + + } + #end return __text = value; } else { @@ -2028,7 +2044,17 @@ class TextField extends InteractiveObject { } - #if (js && html5) if (__hiddenInput != null) __hiddenInput.value = value; #end + #if (js && html5) + if (__text != value && __hiddenInput != null) { + + var selectionStart = __hiddenInput.selectionStart; + var selectionEnd = __hiddenInput.selectionEnd; + __hiddenInput.value = value; + __hiddenInput.selectionStart = selectionStart; + __hiddenInput.selectionEnd = selectionEnd; + + } + #end return __text = value; } @@ -2089,7 +2115,18 @@ class TextField extends InteractiveObject { @:noCompletion private function set_text (value:String):String { - #if (js && html5) if (__text != value && __hiddenInput != null) __hiddenInput.value = value; #end + #if (js && html5) + if (__text != value && __hiddenInput != null) { + + var selectionStart = __hiddenInput.selectionStart; + var selectionEnd = __hiddenInput.selectionEnd; + __hiddenInput.value = value; + __hiddenInput.selectionStart = selectionStart; + __hiddenInput.selectionEnd = selectionEnd; + + } + #end + if (__isHTML || __text != value) __dirty = true; __ranges = null; __isHTML = false; From dbed1a0470a1685380e136617b52145bc3d4ffae Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Wed, 29 Apr 2015 15:53:26 -0700 Subject: [PATCH 088/150] Improve text selection --- .../renderer/canvas/CanvasTextField.hx | 2 +- openfl/text/TextField.hx | 67 ++++++++++++------- 2 files changed, 45 insertions(+), 24 deletions(-) diff --git a/openfl/_internal/renderer/canvas/CanvasTextField.hx b/openfl/_internal/renderer/canvas/CanvasTextField.hx index 9d35e29b95..8d208c8100 100644 --- a/openfl/_internal/renderer/canvas/CanvasTextField.hx +++ b/openfl/_internal/renderer/canvas/CanvasTextField.hx @@ -275,7 +275,7 @@ class CanvasTextField { context.fillStyle = "#" + StringTools.hex (textField.__textFormat.color, 6); context.fillRect (cursorOffset, 5, 1, (textField.__textFormat.size * 1.185) - 4); - } else if (textField.__hasFocus && (Math.abs (textField.__selectionStart - textField.__cursorPosition)) > 0 && !textField.__isKeyDown) { + } else if (textField.__hasFocus && (Math.abs (textField.__selectionStart - textField.__cursorPosition)) > 0) { var lowPos = Std.int (Math.min (textField.__selectionStart, textField.__cursorPosition)); var highPos = Std.int (Math.max (textField.__selectionStart, textField.__cursorPosition)); diff --git a/openfl/text/TextField.hx b/openfl/text/TextField.hx index 378a43b334..2ffcbaab24 100644 --- a/openfl/text/TextField.hx +++ b/openfl/text/TextField.hx @@ -1666,8 +1666,18 @@ class TextField extends InteractiveObject { __ranges = null; __isHTML = false; - __cursorPosition = __hiddenInput.selectionStart; - __selectionStart = __cursorPosition; + if (__hiddenInput.selectionDirection == "backward") { + + __cursorPosition = __hiddenInput.selectionStart; + __selectionStart = __hiddenInput.selectionEnd; + + } else { + + __cursorPosition = __hiddenInput.selectionEnd; + __selectionStart = __hiddenInput.selectionStart; + + } + __dirty = true; dispatchEvent (new Event (Event.CHANGE, true)); @@ -1683,27 +1693,38 @@ class TextField extends InteractiveObject { var keyCode = event.which; var isShift = event.shiftKey; - if (keyCode == 65 && (event.ctrlKey || event.metaKey)) { // Command/Ctrl + A + //if (keyCode == 65 && (event.ctrlKey || event.metaKey)) { // Command/Ctrl + A + // + //__hiddenInput.selectionStart = 0; + //__hiddenInput.selectionEnd = text.length; + //event.preventDefault (); + //__dirty = true; + //return; + // + //} + // + //if (keyCode == 17 || event.metaKey || event.ctrlKey) { + // + //return; + // + //} + + __text = __hiddenInput.value; + __ranges = null; + __isHTML = false; + + if (__hiddenInput.selectionDirection == "backward") { - __hiddenInput.selectionStart = 0; - __hiddenInput.selectionEnd = text.length; - event.preventDefault (); - __dirty = true; - return; + __cursorPosition = __hiddenInput.selectionStart; + __selectionStart = __hiddenInput.selectionEnd; - } - - if (keyCode == 17 || event.metaKey || event.ctrlKey) { + } else { - return; + __cursorPosition = __hiddenInput.selectionEnd; + __selectionStart = __hiddenInput.selectionStart; } - __text = __hiddenInput.value; - __ranges = null; - __isHTML = false; - - __selectionStart = __hiddenInput.selectionStart; __dirty = true; } @@ -1752,9 +1773,9 @@ class TextField extends InteractiveObject { addEventListener (FocusEvent.FOCUS_IN, this_onFocusIn); addEventListener (FocusEvent.FOCUS_OUT, this_onFocusOut); - __hiddenInput.addEventListener ('keydown', input_onKeyDown); - __hiddenInput.addEventListener ('keyup', input_onKeyUp); - __hiddenInput.addEventListener ('input', input_onKeyUp); + __hiddenInput.addEventListener ('keydown', input_onKeyDown, true); + __hiddenInput.addEventListener ('keyup', input_onKeyUp, true); + __hiddenInput.addEventListener ('input', input_onKeyUp, true); addEventListener (MouseEvent.MOUSE_DOWN, this_onMouseDown); @@ -1823,9 +1844,9 @@ class TextField extends InteractiveObject { this_onFocusOut (null); - if (__hiddenInput != null) __hiddenInput.removeEventListener ('keydown', input_onKeyDown); - if (__hiddenInput != null) __hiddenInput.removeEventListener ('keyup', input_onKeyUp); - if (__hiddenInput != null) __hiddenInput.removeEventListener ('input', input_onKeyUp); + if (__hiddenInput != null) __hiddenInput.removeEventListener ('keydown', input_onKeyDown, true); + if (__hiddenInput != null) __hiddenInput.removeEventListener ('keyup', input_onKeyUp, true); + if (__hiddenInput != null) __hiddenInput.removeEventListener ('input', input_onKeyUp, true); removeEventListener (MouseEvent.MOUSE_DOWN, this_onMouseDown); if (stage != null) stage.removeEventListener (MouseEvent.MOUSE_MOVE, stage_onMouseMove); From a241d6d30874cf533f7c0b0ef38e0b361cb32ed0 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Thu, 30 Apr 2015 09:55:25 -0700 Subject: [PATCH 089/150] __getBounds fix --- openfl/display/Bitmap.hx | 20 +++++++++++--------- openfl/display/DisplayObject.hx | 11 ++++++++--- openfl/display/DisplayObjectContainer.hx | 2 +- openfl/media/Video.hx | 2 +- openfl/text/TextField.hx | 2 +- 5 files changed, 22 insertions(+), 15 deletions(-) diff --git a/openfl/display/Bitmap.hx b/openfl/display/Bitmap.hx index add1fecc6e..b6977640de 100644 --- a/openfl/display/Bitmap.hx +++ b/openfl/display/Bitmap.hx @@ -113,7 +113,7 @@ class Bitmap extends DisplayObjectContainer { if (bitmapData != null) { var bounds = new Rectangle (0, 0, bitmapData.width, bitmapData.height); - bounds = bounds.transform (__worldTransform); + bounds = bounds.transform (matrix != null ? matrix : __worldTransform); rect.__expand (bounds.x, bounds.y, bounds.width, bounds.height); @@ -174,18 +174,20 @@ class Bitmap extends DisplayObjectContainer { @:noCompletion @:dox(hide) public override function __updateMask (maskGraphics:Graphics):Void { - - maskGraphics.__commands.push(OverrideMatrix(this.__worldTransform)); - maskGraphics.beginFill(0); - maskGraphics.drawRect(0, 0, bitmapData.width, bitmapData.height); - + + maskGraphics.__commands.push (OverrideMatrix (this.__worldTransform)); + maskGraphics.beginFill (0); + maskGraphics.drawRect (0, 0, bitmapData.width, bitmapData.height); + if (maskGraphics.__bounds == null) { - maskGraphics.__bounds = new Rectangle(); + + maskGraphics.__bounds = new Rectangle (); + } - __getBounds(maskGraphics.__bounds, @:privateAccess Matrix.__identity); + __getBounds (maskGraphics.__bounds, @:privateAccess Matrix.__identity); - super.__updateMask(maskGraphics); + super.__updateMask (maskGraphics); } diff --git a/openfl/display/DisplayObject.hx b/openfl/display/DisplayObject.hx index 4dff88c653..e11eaceb07 100644 --- a/openfl/display/DisplayObject.hx +++ b/openfl/display/DisplayObject.hx @@ -939,6 +939,8 @@ class DisplayObject extends EventDispatcher implements IBitmapDrawable { if (parent != null) { var bounds = new Rectangle (); + + __getTransform (); __getBounds (bounds, null); return bounds.containsPoint (new Point (x, y)); @@ -1403,15 +1405,18 @@ class DisplayObject extends EventDispatcher implements IBitmapDrawable { if (__graphics != null) { - maskGraphics.__commands.push(OverrideMatrix(this.__worldTransform)); - maskGraphics.__commands = maskGraphics.__commands.concat(__graphics.__commands); + maskGraphics.__commands.push (OverrideMatrix (this.__worldTransform)); + maskGraphics.__commands = maskGraphics.__commands.concat (__graphics.__commands); maskGraphics.__dirty = true; maskGraphics.__visible = true; + if (maskGraphics.__bounds == null) { + maskGraphics.__bounds = new Rectangle(); + } - __graphics.__getBounds(maskGraphics.__bounds, @:privateAccess Matrix.__identity); + __graphics.__getBounds (maskGraphics.__bounds, @:privateAccess Matrix.__identity); } diff --git a/openfl/display/DisplayObjectContainer.hx b/openfl/display/DisplayObjectContainer.hx index 488ba802f6..05b4cb864e 100644 --- a/openfl/display/DisplayObjectContainer.hx +++ b/openfl/display/DisplayObjectContainer.hx @@ -657,7 +657,7 @@ class DisplayObjectContainer extends InteractiveObject { @:noCompletion private override function __getBounds (rect:Rectangle, matrix:Matrix):Void { - super.__getBounds(rect, matrix); + super.__getBounds (rect, matrix); if (__children.length == 0) return; diff --git a/openfl/media/Video.hx b/openfl/media/Video.hx index f2cfe52220..bc3c0aa6c6 100644 --- a/openfl/media/Video.hx +++ b/openfl/media/Video.hx @@ -65,7 +65,7 @@ class Video extends DisplayObject { @:noCompletion private override function __getBounds (rect:Rectangle, matrix:Matrix):Void { var bounds = new Rectangle (0, 0, __width, __height); - bounds.transform (__worldTransform); + bounds.transform (matrix != null ? matrix : __worldTransform); rect.__expand (bounds.x, bounds.y, bounds.width, bounds.height); diff --git a/openfl/text/TextField.hx b/openfl/text/TextField.hx index 2ffcbaab24..3f3e97e63f 100644 --- a/openfl/text/TextField.hx +++ b/openfl/text/TextField.hx @@ -1007,7 +1007,7 @@ class TextField extends InteractiveObject { @:noCompletion private override function __getBounds (rect:Rectangle, matrix:Matrix):Void { var bounds = new Rectangle (0, 0, __width, __height); - bounds.transform (__worldTransform); + bounds.transform (matrix != null ? matrix : __worldTransform); rect.__expand (bounds.x, bounds.y, bounds.width, bounds.height); From 7ae424117fdd4f5309ad7e39b82c1886661146f9 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Thu, 30 Apr 2015 10:01:10 -0700 Subject: [PATCH 090/150] Always require a matrix --- openfl/display/Bitmap.hx | 2 +- openfl/display/DisplayObject.hx | 8 +++----- openfl/display/DisplayObjectContainer.hx | 2 +- openfl/display/Graphics.hx | 8 ++------ openfl/media/Video.hx | 2 +- openfl/text/TextField.hx | 2 +- 6 files changed, 9 insertions(+), 15 deletions(-) diff --git a/openfl/display/Bitmap.hx b/openfl/display/Bitmap.hx index b6977640de..03548f11d2 100644 --- a/openfl/display/Bitmap.hx +++ b/openfl/display/Bitmap.hx @@ -113,7 +113,7 @@ class Bitmap extends DisplayObjectContainer { if (bitmapData != null) { var bounds = new Rectangle (0, 0, bitmapData.width, bitmapData.height); - bounds = bounds.transform (matrix != null ? matrix : __worldTransform); + bounds = bounds.transform (matrix); rect.__expand (bounds.x, bounds.y, bounds.width, bounds.height); diff --git a/openfl/display/DisplayObject.hx b/openfl/display/DisplayObject.hx index e11eaceb07..1bf2839bc4 100644 --- a/openfl/display/DisplayObject.hx +++ b/openfl/display/DisplayObject.hx @@ -939,9 +939,7 @@ class DisplayObject extends EventDispatcher implements IBitmapDrawable { if (parent != null) { var bounds = new Rectangle (); - - __getTransform (); - __getBounds (bounds, null); + __getBounds (bounds, __getTransform ()); return bounds.containsPoint (new Point (x, y)); @@ -1005,9 +1003,9 @@ class DisplayObject extends EventDispatcher implements IBitmapDrawable { @:noCompletion private function __getBounds (rect:Rectangle, matrix:Matrix):Void { - if (__graphics != null) { + if (__graphics != null && matrix != null) { - __graphics.__getBounds (rect, matrix != null ? matrix : __worldTransform); + __graphics.__getBounds (rect, matrix); } diff --git a/openfl/display/DisplayObjectContainer.hx b/openfl/display/DisplayObjectContainer.hx index 05b4cb864e..01a1e1ac46 100644 --- a/openfl/display/DisplayObjectContainer.hx +++ b/openfl/display/DisplayObjectContainer.hx @@ -674,7 +674,7 @@ class DisplayObjectContainer extends InteractiveObject { for (child in __children) { if (!child.__renderable) continue; - child.__getBounds (rect, null); + child.__getBounds (rect, child.__worldTransform); } diff --git a/openfl/display/Graphics.hx b/openfl/display/Graphics.hx index a0a5b96adf..46866bfbda 100644 --- a/openfl/display/Graphics.hx +++ b/openfl/display/Graphics.hx @@ -977,9 +977,7 @@ class Graphics { @:noCompletion private function __getBounds (rect:Rectangle, matrix:Matrix):Void { - if (__bounds == null) return; - - var bounds = __bounds.clone ().transform (matrix); + var bounds = __bounds.transform (matrix); rect.__expand (bounds.x, bounds.y, bounds.width, bounds.height); } @@ -989,9 +987,7 @@ class Graphics { //TODO: Shape flag - if (__bounds == null) return false; - - var bounds = __bounds.clone ().transform (matrix); + var bounds = __bounds.transform (matrix); return (x > bounds.x && y > bounds.y && x <= bounds.right && y <= bounds.bottom); } diff --git a/openfl/media/Video.hx b/openfl/media/Video.hx index bc3c0aa6c6..703fdb37d0 100644 --- a/openfl/media/Video.hx +++ b/openfl/media/Video.hx @@ -65,7 +65,7 @@ class Video extends DisplayObject { @:noCompletion private override function __getBounds (rect:Rectangle, matrix:Matrix):Void { var bounds = new Rectangle (0, 0, __width, __height); - bounds.transform (matrix != null ? matrix : __worldTransform); + bounds.transform (matrix); rect.__expand (bounds.x, bounds.y, bounds.width, bounds.height); diff --git a/openfl/text/TextField.hx b/openfl/text/TextField.hx index 3f3e97e63f..d635171dfe 100644 --- a/openfl/text/TextField.hx +++ b/openfl/text/TextField.hx @@ -1007,7 +1007,7 @@ class TextField extends InteractiveObject { @:noCompletion private override function __getBounds (rect:Rectangle, matrix:Matrix):Void { var bounds = new Rectangle (0, 0, __width, __height); - bounds.transform (matrix != null ? matrix : __worldTransform); + bounds.transform (matrix); rect.__expand (bounds.x, bounds.y, bounds.width, bounds.height); From 4d616f03d2b3939cb357c75eae988e53faeadffc Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Thu, 30 Apr 2015 10:07:38 -0700 Subject: [PATCH 091/150] Bounds fix --- openfl/media/Video.hx | 2 +- openfl/text/TextField.hx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openfl/media/Video.hx b/openfl/media/Video.hx index 703fdb37d0..d568deef77 100644 --- a/openfl/media/Video.hx +++ b/openfl/media/Video.hx @@ -65,7 +65,7 @@ class Video extends DisplayObject { @:noCompletion private override function __getBounds (rect:Rectangle, matrix:Matrix):Void { var bounds = new Rectangle (0, 0, __width, __height); - bounds.transform (matrix); + bounds = bounds.transform (matrix); rect.__expand (bounds.x, bounds.y, bounds.width, bounds.height); diff --git a/openfl/text/TextField.hx b/openfl/text/TextField.hx index d635171dfe..2a7da60816 100644 --- a/openfl/text/TextField.hx +++ b/openfl/text/TextField.hx @@ -1007,7 +1007,7 @@ class TextField extends InteractiveObject { @:noCompletion private override function __getBounds (rect:Rectangle, matrix:Matrix):Void { var bounds = new Rectangle (0, 0, __width, __height); - bounds.transform (matrix); + bounds = bounds.transform (matrix); rect.__expand (bounds.x, bounds.y, bounds.width, bounds.height); From 10f036fa4105c16ec71d8519e49c7d2d828eb230 Mon Sep 17 00:00:00 2001 From: "Lars A. Doucet" Date: Thu, 30 Apr 2015 16:04:08 -0500 Subject: [PATCH 092/150] HTML5/CanvasGraphics: fixes linear gradients as far as I can tell. --- openfl/_internal/renderer/canvas/CanvasGraphics.hx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/openfl/_internal/renderer/canvas/CanvasGraphics.hx b/openfl/_internal/renderer/canvas/CanvasGraphics.hx index 701606cd34..ceb7dfdc1c 100644 --- a/openfl/_internal/renderer/canvas/CanvasGraphics.hx +++ b/openfl/_internal/renderer/canvas/CanvasGraphics.hx @@ -241,6 +241,12 @@ class CanvasGraphics { var point1 = matrix.transformPoint (new Point (0, 0)); var point2 = matrix.transformPoint (new Point (1638.4, 0)); + point1.x -= point2.x; + point1.y -= point2.y; + + point2.x -= point2.x; + point2.y -= point2.y; + gradientFill = context.createLinearGradient (point1.x, point1.y, point2.x, point2.y); } @@ -258,7 +264,6 @@ class CanvasGraphics { if (ratio > 1) ratio = 1; gradientFill.addColorStop (ratio, "rgba(" + r + ", " + g + ", " + b + ", " + alpha + ")"); - } context.fillStyle = gradientFill; From 7813c1b7b525720da578e3580092fac5b84db2c4 Mon Sep 17 00:00:00 2001 From: "Lars A. Doucet" Date: Thu, 30 Apr 2015 16:04:58 -0500 Subject: [PATCH 093/150] Style fix --- openfl/_internal/renderer/canvas/CanvasGraphics.hx | 1 + 1 file changed, 1 insertion(+) diff --git a/openfl/_internal/renderer/canvas/CanvasGraphics.hx b/openfl/_internal/renderer/canvas/CanvasGraphics.hx index ceb7dfdc1c..6a43037e9c 100644 --- a/openfl/_internal/renderer/canvas/CanvasGraphics.hx +++ b/openfl/_internal/renderer/canvas/CanvasGraphics.hx @@ -264,6 +264,7 @@ class CanvasGraphics { if (ratio > 1) ratio = 1; gradientFill.addColorStop (ratio, "rgba(" + r + ", " + g + ", " + b + ", " + alpha + ")"); + } context.fillStyle = gradientFill; From 827d7be91b3a0061e89aaf77792f439cb3dc29d7 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Thu, 30 Apr 2015 19:10:16 -0700 Subject: [PATCH 094/150] Fix linear gradient fill --- openfl/_internal/renderer/canvas/CanvasGraphics.hx | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/openfl/_internal/renderer/canvas/CanvasGraphics.hx b/openfl/_internal/renderer/canvas/CanvasGraphics.hx index 6a43037e9c..8ab04084a6 100644 --- a/openfl/_internal/renderer/canvas/CanvasGraphics.hx +++ b/openfl/_internal/renderer/canvas/CanvasGraphics.hx @@ -235,11 +235,8 @@ class CanvasGraphics { case LINEAR: var matrix = matrix != null ? matrix.clone () : new Matrix (); - matrix.tx -= matrix.a * 1638.4 / 2; - matrix.ty -= matrix.d * 1638.4 / 2; - - var point1 = matrix.transformPoint (new Point (0, 0)); - var point2 = matrix.transformPoint (new Point (1638.4, 0)); + var point1 = matrix.transformPoint (new Point (-819.2, 0)); + var point2 = matrix.transformPoint (new Point (819.2, 0)); point1.x -= point2.x; point1.y -= point2.y; From 4c6a271f3e47797fac0b37a97865b0a3085088b8 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Thu, 30 Apr 2015 19:11:01 -0700 Subject: [PATCH 095/150] Fix linear gradient --- openfl/_internal/renderer/canvas/CanvasGraphics.hx | 6 ------ 1 file changed, 6 deletions(-) diff --git a/openfl/_internal/renderer/canvas/CanvasGraphics.hx b/openfl/_internal/renderer/canvas/CanvasGraphics.hx index 8ab04084a6..d7c01c3b18 100644 --- a/openfl/_internal/renderer/canvas/CanvasGraphics.hx +++ b/openfl/_internal/renderer/canvas/CanvasGraphics.hx @@ -238,12 +238,6 @@ class CanvasGraphics { var point1 = matrix.transformPoint (new Point (-819.2, 0)); var point2 = matrix.transformPoint (new Point (819.2, 0)); - point1.x -= point2.x; - point1.y -= point2.y; - - point2.x -= point2.x; - point2.y -= point2.y; - gradientFill = context.createLinearGradient (point1.x, point1.y, point2.x, point2.y); } From b55ca866af4087393dd48c97717a64a754432088 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Fri, 1 May 2015 05:16:07 -0700 Subject: [PATCH 096/150] Fix bounds check --- openfl/display/DisplayObject.hx | 2 +- openfl/display/Graphics.hx | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/openfl/display/DisplayObject.hx b/openfl/display/DisplayObject.hx index 1bf2839bc4..569ef595ae 100644 --- a/openfl/display/DisplayObject.hx +++ b/openfl/display/DisplayObject.hx @@ -1003,7 +1003,7 @@ class DisplayObject extends EventDispatcher implements IBitmapDrawable { @:noCompletion private function __getBounds (rect:Rectangle, matrix:Matrix):Void { - if (__graphics != null && matrix != null) { + if (__graphics != null) { __graphics.__getBounds (rect, matrix); diff --git a/openfl/display/Graphics.hx b/openfl/display/Graphics.hx index 46866bfbda..370d0b1c8f 100644 --- a/openfl/display/Graphics.hx +++ b/openfl/display/Graphics.hx @@ -977,6 +977,8 @@ class Graphics { @:noCompletion private function __getBounds (rect:Rectangle, matrix:Matrix):Void { + if (__bounds == null) return; + var bounds = __bounds.transform (matrix); rect.__expand (bounds.x, bounds.y, bounds.width, bounds.height); @@ -987,6 +989,8 @@ class Graphics { //TODO: Shape flag + if (__bounds == null) return false; + var bounds = __bounds.transform (matrix); return (x > bounds.x && y > bounds.y && x <= bounds.right && y <= bounds.bottom); From d946ecd6f479d63229b98700788b4fca2b51bf7d Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Fri, 1 May 2015 18:14:12 -0700 Subject: [PATCH 097/150] Update template to handle hardware config --- templates/haxe/ApplicationMain.hx | 1 + 1 file changed, 1 insertion(+) diff --git a/templates/haxe/ApplicationMain.hx b/templates/haxe/ApplicationMain.hx index fdcf96fb64..68f4bd68b6 100644 --- a/templates/haxe/ApplicationMain.hx +++ b/templates/haxe/ApplicationMain.hx @@ -114,6 +114,7 @@ class ApplicationMain { file: "::APP_FILE::", fps: Std.int (::WIN_FPS::), fullscreen: ::WIN_FULLSCREEN::, + hardware: ::WIN_HARDWARE::, height: Std.int (::WIN_HEIGHT::), orientation: "::WIN_ORIENTATION::", packageName: "::META_PACKAGE_NAME::", From da6f35826ed1458cd0db9b5bf08d7a7146a2d35b Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Sat, 2 May 2015 16:08:11 -0700 Subject: [PATCH 098/150] Tidy CanvasGraphics class --- .../renderer/canvas/CanvasGraphics.hx | 656 ++++++++++-------- 1 file changed, 365 insertions(+), 291 deletions(-) diff --git a/openfl/_internal/renderer/canvas/CanvasGraphics.hx b/openfl/_internal/renderer/canvas/CanvasGraphics.hx index d7c01c3b18..dca2588959 100644 --- a/openfl/_internal/renderer/canvas/CanvasGraphics.hx +++ b/openfl/_internal/renderer/canvas/CanvasGraphics.hx @@ -31,50 +31,201 @@ class CanvasGraphics { private static var SIN45 = 0.70710678118654752440084436210485; private static var TAN22 = 0.4142135623730950488016887242097; - private static var bounds:Rectangle; - private static var inversePendingMatrix:Matrix; - private static var pendingMatrix:Matrix; - - private static var hasStroke : Bool; - private static var hasFill:Bool; - private static var bitmapFill:BitmapData; private static var bitmapRepeat:Bool; - - private static var graphics:Graphics; - + private static var bounds:Rectangle; private static var fillCommands:Array; + private static var graphics:Graphics; + private static var hasFill:Bool; + private static var hasStroke:Bool; + private static var inversePendingMatrix:Matrix; + private static var pendingMatrix:Matrix; private static var strokeCommands:Array; #if (js && html5) private static var context:CanvasRenderingContext2D; private static var pattern:CanvasPattern; #end + + + private static function beginPatternFill (bitmapFill:BitmapData, bitmapRepeat:Bool):Void { + + #if (js && html5) + if (hasFill || bitmapFill == null) return; + + if (pattern == null) { + + pattern = context.createPattern (bitmapFill.__image.src, bitmapRepeat ? "repeat" : "no-repeat"); + + } + + context.fillStyle = pattern; + hasFill = true; + #end + + } + + + private static function createTempPatternCanvas (bitmap:BitmapData, repeat:Bool, width:Int, height:Int) { + + // TODO: Don't create extra canvas elements like this - private static function playCommands( commands : Array, stroke : Bool = false ) - { #if (js && html5) + var canvas:CanvasElement = cast Browser.document.createElement ("canvas"); + var context = canvas.getContext ("2d"); + + canvas.width = width; + canvas.height = height; + + context.fillStyle = context.createPattern (bitmap.__image.src, repeat ? "repeat" : "no-repeat"); + context.beginPath (); + context.moveTo (0, 0); + context.lineTo (0, height); + context.lineTo (width, height); + context.lineTo (width, 0); + context.lineTo (0, 0); + context.closePath (); + context.fill (); + return canvas; + #end + + } + + + private static function endFill ():Void { + #if (js && html5) + context.beginPath (); + playCommands (fillCommands, false); + fillCommands = []; + #end + + } + + + private static function endStroke ():Void { + + #if (js && html5) + context.beginPath (); + playCommands (strokeCommands, true); + context.closePath (); + strokeCommands = []; + #end + + } + + + private static function drawRoundRect (x:Float, y:Float, width:Float, height:Float, rx:Float, ry:Float):Void { + + #if (js && html5) + if (ry == -1) ry = rx; + + rx *= 0.5; + ry *= 0.5; + + if (rx > width / 2) rx = width / 2; + if (ry > height / 2) ry = height / 2; + + var xe = x + width, + ye = y + height, + cx1 = -rx + (rx * SIN45), + cx2 = -rx + (rx * TAN22), + cy1 = -ry + (ry * SIN45), + cy2 = -ry + (ry * TAN22); + + context.moveTo (xe, ye - ry); + context.quadraticCurveTo (xe, ye + cy2, xe + cx1, ye + cy1); + context.quadraticCurveTo (xe + cx2, ye, xe - rx, ye); + context.lineTo (x + rx, ye); + context.quadraticCurveTo (x - cx2, ye, x - cx1, ye + cy1); + context.quadraticCurveTo (x, ye + cy2, x, ye - ry); + context.lineTo (x, y + ry); + context.quadraticCurveTo (x, y - cy2, x - cx1, y - cy1); + context.quadraticCurveTo (x - cx2, y, x + rx, y); + context.lineTo (xe - rx, y); + context.quadraticCurveTo (xe + cx2, y, xe + cx1, y - cy1); + context.quadraticCurveTo (xe, y - cy2, xe, y + ry); + context.lineTo (xe, ye - ry); + #end + + } + + + private static inline function isCCW (x1:Float, y1:Float, x2:Float, y2:Float, x3:Float, y3:Float) { + + return ((x2 - x1) * (y3 - y1) - (y2 - y1) * (x3 - x1)) < 0; + + } + + + private static function normalizeUVT (uvt:Vector, skipT:Bool = false): { max:Float, uvt:Vector } { + + var max:Float = Math.NEGATIVE_INFINITY; + var tmp = Math.NEGATIVE_INFINITY; + var len = uvt.length; + + for (t in 1...len + 1) { + + if (skipT && t % 3 == 0) { + + continue; + + } + + tmp = uvt[t - 1]; + + if (max < tmp) { + + max = tmp; + + } + + } + + var result = new Vector (); + + for (t in 1...len + 1) { + + if (skipT && t % 3 == 0) { + + continue; + + } + + result.push ((uvt[t - 1] / max)); + + } + + return { max: max, uvt: result }; + + } + + + private static function playCommands (commands:Array, stroke:Bool = false):Void { + + #if (js && html5) bounds = graphics.__bounds; var offsetX = bounds.x; var offsetY = bounds.y; - var positionX : Float = 0; - var positionY : Float = 0; + var positionX = 0.0; + var positionY = 0.0; + + var closeGap = false; + var startX = 0.0; + var startY = 0.0; - var closeGap : Bool = false; - var startX : Float = 0; - var startY : Float = 0; - for (command in commands) { - + switch (command) { - + case CubicCurveTo (cx1, cy1, cx2, cy2, x, y): + context.bezierCurveTo (cx1 - offsetX, cy1 - offsetY, cx2 - offsetX, cy2 - offsetY, x - offsetX, y - offsetY); case CurveTo (cx, cy, x, y): + context.quadraticCurveTo (cx - offsetX, cy - offsetY, x - offsetX, y - offsetY); case DrawCircle (x, y, radius): @@ -101,20 +252,20 @@ class CanvasGraphics { context.bezierCurveTo (xe, ym + oy, xm + ox, ye, xm, ye); context.bezierCurveTo (xm - ox, ye, x, ym + oy, x, ym); - case DrawRoundRect (x, y, width, height, rx, ry): + drawRoundRect (x - offsetX, y - offsetY, width, height, rx, ry); - + case LineTo (x, y): - context.lineTo (x - offsetX, y - offsetY); + context.lineTo (x - offsetX, y - offsetY); positionX = x; positionY = y; - + case MoveTo (x, y): - context.moveTo (x - offsetX, y - offsetY); + context.moveTo (x - offsetX, y - offsetY); positionX = x; positionY = y; @@ -122,14 +273,15 @@ class CanvasGraphics { closeGap = true; startX = x; startY = y; - + case LineStyle (thickness, color, alpha, pixelHinting, scaleMode, caps, joints, miterLimit): - if ( stroke && hasStroke ) - { - context.closePath(); - context.stroke(); - context.beginPath(); + if (stroke && hasStroke) { + + context.closePath (); + context.stroke (); + context.beginPath (); + } context.moveTo (positionX - offsetX, positionY - offsetY); @@ -151,9 +303,9 @@ class CanvasGraphics { context.miterLimit = (miterLimit == null ? 3 : miterLimit); if (alpha == 1 || alpha == null) { - + context.strokeStyle = (color == null ? "#000000" : "#" + StringTools.hex (color & 0x00FFFFFF, 6)); - + } else { var r = (color & 0xFF0000) >>> 16; @@ -167,9 +319,9 @@ class CanvasGraphics { hasStroke = true; } - + case BeginBitmapFill (bitmap, matrix, repeat, smooth): - + if (bitmap != bitmapFill || repeat != bitmapRepeat) { bitmapFill = bitmap; @@ -196,12 +348,12 @@ class CanvasGraphics { case BeginFill (rgb, alpha): - if ( alpha < 0.005 ) - { + if (alpha < 0.005) { + hasFill = false; - } - else - { + + } else { + if (alpha == 1) { context.fillStyle = "#" + StringTools.hex (rgb, 6); @@ -218,10 +370,11 @@ class CanvasGraphics { bitmapFill = null; hasFill = true; + } case BeginGradientFill (type, colors, alphas, ratios, matrix, spreadMethod, interpolationMethod, focalPointRatio): - + var gradientFill = null; switch (type) { @@ -314,33 +467,37 @@ class CanvasGraphics { context.rect (x - offsetX, y - offsetY, width, height); } - - - + + default: } - - } + + } - if ( stroke && hasStroke ) - { - if ( hasFill && closeGap ) - { - context.lineTo (startX - offsetX, startY - offsetY); + if (stroke && hasStroke) { + + if (hasFill && closeGap) { + + context.lineTo (startX - offsetX, startY - offsetY); + } - context.stroke(); + context.stroke (); + } - if ( !stroke ) - { - if ( hasFill || bitmapFill != null ) - { - if( bitmapFill != null ) + if (!stroke) { + + if (hasFill || bitmapFill != null) { + + if (bitmapFill != null) { + beginPatternFill (bitmapFill, bitmapRepeat); + + } - context.translate( -bounds.x, -bounds.y); + context.translate (-bounds.x, -bounds.y); if (pendingMatrix != null) { @@ -355,103 +512,25 @@ class CanvasGraphics { } context.translate (bounds.x, bounds.y); - - context.closePath(); + context.closePath (); + } - } - - #end - } - - private static function fillEnd() - { - #if (js && html5) - context.beginPath(); - playCommands( fillCommands, false ); - fillCommands = []; - #end - } - - private static function strokeEnd() - { - #if (js && html5) - context.beginPath(); - playCommands( strokeCommands, true ); - context.closePath(); - strokeCommands = []; - #end - } - - private static function beginPatternFill (bitmapFill:BitmapData, bitmapRepeat:Bool):Void { - - #if (js && html5) - if (hasFill || bitmapFill == null) return; - - if (pattern == null) { - - pattern = context.createPattern (bitmapFill.__image.src, bitmapRepeat ? "repeat" : "no-repeat"); } - - context.fillStyle = pattern; - hasFill = true; - #end - - } - - private static function drawRoundRect (x:Float, y:Float, width:Float, height:Float, rx:Float, ry:Float):Void { - - #if (js && html5) - if (ry == -1) ry = rx; - - rx *= 0.5; - ry *= 0.5; - - if (rx > width / 2) rx = width / 2; - if (ry > height / 2) ry = height / 2; - - var xe = x + width, - ye = y + height, - cx1 = -rx + (rx * SIN45), - cx2 = -rx + (rx * TAN22), - cy1 = -ry + (ry * SIN45), - cy2 = -ry + (ry * TAN22); - - context.moveTo (xe, ye - ry); - context.quadraticCurveTo (xe, ye + cy2, xe + cx1, ye + cy1); - context.quadraticCurveTo (xe + cx2, ye, xe - rx, ye); - context.lineTo (x + rx, ye); - context.quadraticCurveTo (x - cx2, ye, x - cx1, ye + cy1); - context.quadraticCurveTo (x, ye + cy2, x, ye - ry); - context.lineTo (x, y + ry); - context.quadraticCurveTo (x, y - cy2, x - cx1, y - cy1); - context.quadraticCurveTo (x - cx2, y, x + rx, y); - context.lineTo (xe - rx, y); - context.quadraticCurveTo (xe + cx2, y, xe + cx1, y - cy1); - context.quadraticCurveTo (xe, y - cy2, xe, y + ry); - context.lineTo (xe, ye - ry); #end } - + + public static function render (graphics:Graphics, renderSession:RenderSession):Void { #if (js && html5) - - if (graphics.__dirty) { + if (graphics.__dirty) { + CanvasGraphics.graphics = graphics; bounds = graphics.__bounds; - strokeCommands = []; - fillCommands = []; - - hasFill = false; - hasStroke = false; - - bitmapFill = null; - bitmapRepeat = false; - if (!graphics.__visible || graphics.__commands.length == 0 || bounds == null || bounds.width == 0 || bounds.height == 0) { graphics.__canvas = null; @@ -476,13 +555,18 @@ class CanvasGraphics { var offsetX = bounds.x; var offsetY = bounds.y; - fillCommands = new Array(); - strokeCommands = new Array(); + fillCommands = new Array (); + strokeCommands = new Array (); + + hasFill = false; + hasStroke = false; + bitmapFill = null; + bitmapRepeat = false; inline function endAndPush( command : DrawCommand ) { - fillEnd(); - strokeEnd(); + endFill(); + endStroke(); strokeCommands.push( command ); fillCommands.push( command ); @@ -492,57 +576,41 @@ class CanvasGraphics { switch (command) { - case CubicCurveTo (cx1, cy1, cx2, cy2, x, y): - strokeCommands.push( command ); - fillCommands.push( command ); - - case CurveTo (cx, cy, x, y): - strokeCommands.push( command ); - fillCommands.push( command ); - - case LineTo (x, y): - strokeCommands.push( command ); - fillCommands.push( command ); + case CubicCurveTo (_, _, _, _, _, _), CurveTo (_, _, _, _), LineTo (_, _), MoveTo (_, _): + fillCommands.push (command); + strokeCommands.push (command); + case EndFill: - fillEnd(); - strokeEnd(); - + endFill (); + endStroke (); hasFill = false; - case LineStyle (thickness, color, alpha, pixelHinting, scaleMode, caps, joints, miterLimit): - strokeCommands.push( command ); + case LineStyle (_, _, _, _, _, _, _, _): - case BeginBitmapFill (bitmap, matrix, repeat, smooth): - endAndPush(command); - - case BeginFill (rgb, alpha): - endAndPush(command); - - case BeginGradientFill (type, colors, alphas, ratios, matrix, spreadMethod, interpolationMethod, focalPointRatio): - endAndPush(command); + strokeCommands.push (command); + + case BeginBitmapFill (_, _, _, _), BeginFill (_, _), BeginGradientFill (_, _, _, _, _, _, _, _): - case DrawCircle (x, y, radius): - endAndPush(command); + endFill (); + endStroke (); - case DrawEllipse (x, y, width, height): - endAndPush(command); - - case DrawRect (x, y, width, height): - endAndPush( command ); + fillCommands.push (command); + strokeCommands.push (command); - case DrawRoundRect (x, y, width, height, rx, ry): - endAndPush(command); + case DrawCircle (_, _, _), DrawEllipse (_, _, _, _), DrawRect (_, _, _, _), DrawRoundRect (_, _, _, _, _, _): - case MoveTo (x, y): - strokeCommands.push( command ); - fillCommands.push( command ); + endFill (); + endStroke (); + fillCommands.push (command); + strokeCommands.push (command); + case DrawTriangles (vertices, indices, uvtData, culling, _, _): - fillEnd(); - strokeEnd(); + endFill (); + endStroke (); var v = vertices; var ind = indices; @@ -551,30 +619,44 @@ class CanvasGraphics { var colorFill = bitmapFill == null; if (colorFill && uvt != null) { + // Flash doesn't draw anything if the fill isn't a bitmap and there are uvt values break; + } - if(!colorFill) { + if (!colorFill) { + //TODO move this to Graphics? + if (uvtData == null) { - uvtData = new Vector(); - for (i in 0...(Std.int(v.length / 2))) { - uvtData.push(v[i * 2] / bitmapFill.width); - uvtData.push(v[i * 2 + 1] / bitmapFill.height); + + uvtData = new Vector (); + + for (i in 0...(Std.int (v.length / 2))) { + + uvtData.push (v[i * 2] / bitmapFill.width); + uvtData.push (v[i * 2 + 1] / bitmapFill.height); + } + } var skipT = uvtData.length != v.length; - var normalizedUvt = normalizeUvt(uvtData, skipT); - var maxUvt = normalizedUvt.max; - uvt = normalizedUvt.uvt; + var normalizedUVT = normalizeUVT (uvtData, skipT); + var maxUVT = normalizedUVT.max; + uvt = normalizedUVT.uvt; - if (maxUvt > 1) { - pattern = createTempPatternCanvas(bitmapFill, bitmapRepeat, bounds.width, bounds.height); + if (maxUVT > 1) { + + pattern = createTempPatternCanvas (bitmapFill, bitmapRepeat, Std.int (bounds.width), Std.int (bounds.height)); + } else { - pattern = createTempPatternCanvas(bitmapFill, bitmapRepeat, bitmapFill.width, bitmapFill.height); + + pattern = createTempPatternCanvas (bitmapFill, bitmapRepeat, bitmapFill.width, bitmapFill.height); + } + } var i = 0; @@ -587,53 +669,72 @@ class CanvasGraphics { var denom:Float; var t1:Float, t2:Float, t3:Float, t4:Float; var dx:Float, dy:Float; - // code from http://tulrich.com/geekstuff/canvas/perspective.html + while (i < l) { + a = i; b = i + 1; c = i + 2; - iax = ind[a] * 2; iay = ind[a] * 2 + 1; - ibx = ind[b] * 2; iby = ind[b] * 2 + 1; - icx = ind[c] * 2; icy = ind[c] * 2 + 1; + iax = ind[a] * 2; + iay = ind[a] * 2 + 1; + ibx = ind[b] * 2; + iby = ind[b] * 2 + 1; + icx = ind[c] * 2; + icy = ind[c] * 2 + 1; - x1 = v[iax]; y1 = v[iay]; - x2 = v[ibx]; y2 = v[iby]; - x3 = v[icx]; y3 = v[icy]; + x1 = v[iax]; + y1 = v[iay]; + x2 = v[ibx]; + y2 = v[iby]; + x3 = v[icx]; + y3 = v[icy]; - switch(culling) { + switch (culling) { + case POSITIVE: - if (!isCCW(x1, y1, x2, y2, x3, y3)) { + + if (!isCCW (x1, y1, x2, y2, x3, y3)) { + i += 3; continue; + } + case NEGATIVE: - if (isCCW(x1, y1, x2, y2, x3, y3)) { + + if (isCCW (x1, y1, x2, y2, x3, y3)) { + i += 3; continue; + } - case _: + + default: + } if (colorFill) { - context.beginPath(); - context.moveTo(x1, y1); - context.lineTo(x2, y2); - context.lineTo(x3, y3); - context.closePath(); - context.fill(); + + context.beginPath (); + context.moveTo (x1, y1); + context.lineTo (x2, y2); + context.lineTo (x3, y3); + context.closePath (); + context.fill (); i += 3; continue; + } - context.save(); - context.beginPath(); - context.moveTo(x1, y1); - context.lineTo(x2, y2); - context.lineTo(x3, y3); - context.closePath(); + context.save (); + context.beginPath (); + context.moveTo (x1, y1); + context.lineTo (x2, y2); + context.lineTo (x3, y3); + context.closePath (); - context.clip(); + context.clip (); uvx1 = uvt[iax] * pattern.width; uvx2 = uvt[ibx] * pattern.width; @@ -643,9 +744,12 @@ class CanvasGraphics { uvy3 = uvt[icy] * pattern.height; denom = uvx1 * (uvy3 - uvy2) - uvx2 * uvy3 + uvx3 * uvy2 + (uvx2 - uvx3) * uvy1; + if (denom == 0) { + i += 3; continue; + } t1 = - (uvy1 * (x3 - x2) - uvy2 * x3 + uvy3 * x2 + (uvy2 - uvy3) * x1) / denom; @@ -655,15 +759,14 @@ class CanvasGraphics { dx = (uvx1 * (uvy3 * x2 - uvy2 * x3) + uvy1 * (uvx2 * x3 - uvx3 * x2) + (uvx3 * uvy2 - uvx2 * uvy3) * x1) / denom; dy = (uvx1 * (uvy3 * y2 - uvy2 * y3) + uvy1 * (uvx2 * y3 - uvx3 * y2) + (uvx3 * uvy2 - uvx2 * uvy3) * y1) / denom; - context.transform(t1, t2, t3, t4, dx, dy); - context.drawImage(pattern, 0, 0); - - context.restore(); + context.transform (t1, t2, t3, t4, dx, dy); + context.drawImage (pattern, 0, 0); + context.restore (); i += 3; - } - + } + case DrawTiles (sheet, tileData, smooth, flags, count): var useScale = (flags & Graphics.TILE_SCALE) > 0; @@ -704,9 +807,12 @@ class CanvasGraphics { var surface:Dynamic; sheet.__bitmap.__sync (); surface = sheet.__bitmap.__image.src; - - if (useBlendAdd) + + if (useBlendAdd) { + context.globalCompositeOperation = "lighter"; + + } while (index < totalCount) { @@ -719,20 +825,22 @@ class CanvasGraphics { previousTileID = tileID; - } - else if (useRect) - { + } else if (useRect) { + rect = sheet.__rectTile; - rect.setTo(tileData[index + 2], tileData[index + 3], tileData[index + 4], tileData[index + 5]); + rect.setTo (tileData[index + 2], tileData[index + 3], tileData[index + 4], tileData[index + 5]); center = sheet.__point; - if (useOrigin) - { - center.setTo(tileData[index + 6], tileData[index + 7]); - } - else - { - center.setTo(0, 0); + + if (useOrigin) { + + center.setTo (tileData[index + 6], tileData[index + 7]); + + } else { + + center.setTo (0, 0); + } + } if (rect != null && rect.width > 0 && rect.height > 0 && center != null) { @@ -774,12 +882,16 @@ class CanvasGraphics { index += numValues; } - - if (useBlendAdd) + + if (useBlendAdd) { + context.globalCompositeOperation = "source-over"; + + } + + default: - case _: - openfl.Lib.notImplemented("CanvasGraphics"); + openfl.Lib.notImplemented ("CanvasGraphics"); } @@ -789,11 +901,17 @@ class CanvasGraphics { graphics.__dirty = false; - if( fillCommands.length > 0 ) - fillEnd(); + if (fillCommands.length > 0) { + + endFill (); + + } - if( strokeCommands.length > 0 ) - strokeEnd(); + if (strokeCommands.length > 0) { + + endStroke (); + + } } @@ -886,49 +1004,5 @@ class CanvasGraphics { } - private static function createTempPatternCanvas(bitmap:BitmapData, repeat:Bool, width:Float, height:Float) { - - #if (js && html5) - var canvas:CanvasElement = cast Browser.document.createElement ("canvas"); - var context:CanvasRenderingContext2D = canvas.getContext ("2d"); - - canvas.width = Math.ceil (width); - canvas.height = Math.ceil (height); - - context.fillStyle = context.createPattern(bitmap.__image.src, repeat ? "repeat" : "no-repeat"); - context.beginPath(); - context.moveTo(0, 0); - context.lineTo(0, height); - context.lineTo(width, height); - context.lineTo(width, 0); - context.lineTo(0, 0); - context.closePath(); - context.fill(); - return canvas; - #end - } - - private static inline function isCCW(x1:Float, y1:Float, x2:Float, y2:Float, x3:Float, y3:Float) { - return ((x2 - x1) * (y3 - y1) - (y2 - y1) * (x3 - x1)) < 0; - } - - private static function normalizeUvt(uvt:Vector, skipT:Bool = false):{max:Float, uvt:Vector } { - var max:Float = Math.NEGATIVE_INFINITY; - var tmp = Math.NEGATIVE_INFINITY; - var len = uvt.length; - for (t in 1...len+1) { - if (skipT && t % 3 == 0) continue; - tmp = uvt[t - 1]; - if (max < tmp) max = tmp; - } - - var result:Vector = new Vector(); - for (t in 1...len+1) { - if (skipT && t % 3 == 0) continue; - result.push((uvt[t - 1] / max)); - } - - return {max:max, uvt:result}; - } -} +} \ No newline at end of file From 7f8d03c47fbf4b206d6b4218fe31a894fbb32e68 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Sat, 2 May 2015 16:17:46 -0700 Subject: [PATCH 099/150] Start of Cairo renderer --- openfl/_internal/renderer/RenderSession.hx | 2 + .../_internal/renderer/cairo/CairoGraphics.hx | 1001 +++++++++++++++++ .../_internal/renderer/cairo/CairoRenderer.hx | 53 + openfl/_internal/renderer/cairo/CairoShape.hx | 76 ++ openfl/display/DisplayObject.hx | 12 + openfl/display/Stage.hx | 16 + 6 files changed, 1160 insertions(+) create mode 100644 openfl/_internal/renderer/cairo/CairoGraphics.hx create mode 100644 openfl/_internal/renderer/cairo/CairoRenderer.hx create mode 100644 openfl/_internal/renderer/cairo/CairoShape.hx diff --git a/openfl/_internal/renderer/RenderSession.hx b/openfl/_internal/renderer/RenderSession.hx index 3814843ee1..2e946ffbd2 100644 --- a/openfl/_internal/renderer/RenderSession.hx +++ b/openfl/_internal/renderer/RenderSession.hx @@ -1,6 +1,7 @@ package openfl._internal.renderer; #if !flash +import lime.graphics.CairoRenderContext; import lime.graphics.CanvasRenderContext; import lime.graphics.DOMRenderContext; import lime.graphics.GLRenderContext; @@ -19,6 +20,7 @@ import openfl.geom.Point; class RenderSession { + public var cairo:CairoRenderContext; public var context:CanvasRenderContext; public var element:DOMRenderContext; public var gl:GLRenderContext; diff --git a/openfl/_internal/renderer/cairo/CairoGraphics.hx b/openfl/_internal/renderer/cairo/CairoGraphics.hx new file mode 100644 index 0000000000..89f933850d --- /dev/null +++ b/openfl/_internal/renderer/cairo/CairoGraphics.hx @@ -0,0 +1,1001 @@ +package openfl._internal.renderer.cairo; + + +import openfl._internal.renderer.RenderSession; +import openfl.display.BitmapData; +import openfl.display.CapsStyle; +import openfl.display.DisplayObject; +import openfl.display.Graphics; +import openfl.geom.Matrix; +import openfl.geom.Point; +import openfl.geom.Rectangle; +import openfl.Lib; +import openfl.Vector; + +@:access(openfl.display.DisplayObject) +@:access(openfl.display.BitmapData) +@:access(openfl.display.Graphics) +@:access(openfl.display.Tilesheet) + + +class CairoGraphics { + + + private static var SIN45 = 0.70710678118654752440084436210485; + private static var TAN22 = 0.4142135623730950488016887242097; + + private static var bitmapFill:BitmapData; + private static var bitmapRepeat:Bool; + private static var bounds:Rectangle; + private static var fillCommands:Array; + private static var graphics:Graphics; + private static var hasFill:Bool; + private static var hasStroke:Bool; + private static var inversePendingMatrix:Matrix; + private static var pendingMatrix:Matrix; + private static var strokeCommands:Array; + + #if (js && html5) + private static var context:CanvasRenderingContext2D; + private static var pattern:CanvasPattern; + #end + + + private static function beginPatternFill (bitmapFill:BitmapData, bitmapRepeat:Bool):Void { + + //#if (js && html5) + //if (hasFill || bitmapFill == null) return; + // + //if (pattern == null) { + // + //pattern = context.createPattern (bitmapFill.__image.src, bitmapRepeat ? "repeat" : "no-repeat"); + // + //} + // + //context.fillStyle = pattern; + //hasFill = true; + //#end + + } + + + private static function createTempPatternCanvas (bitmap:BitmapData, repeat:Bool, width:Int, height:Int) { + + // TODO: Don't create extra canvas elements like this + + //#if (js && html5) + //var canvas:CanvasElement = cast Browser.document.createElement ("canvas"); + //var context = canvas.getContext ("2d"); + // + //canvas.width = width; + //canvas.height = height; + // + //context.fillStyle = context.createPattern (bitmap.__image.src, repeat ? "repeat" : "no-repeat"); + //context.beginPath (); + //context.moveTo (0, 0); + //context.lineTo (0, height); + //context.lineTo (width, height); + //context.lineTo (width, 0); + //context.lineTo (0, 0); + //context.closePath (); + //context.fill (); + //return canvas; + //#end + + } + + + private static function endFill ():Void { + + //#if (js && html5) + //context.beginPath (); + //playCommands (fillCommands, false); + //fillCommands = []; + //#end + + } + + + private static function endStroke ():Void { + + //#if (js && html5) + //context.beginPath (); + //playCommands (strokeCommands, true); + //context.closePath (); + //strokeCommands = []; + //#end + + } + + + private static function drawRoundRect (x:Float, y:Float, width:Float, height:Float, rx:Float, ry:Float):Void { + + //#if (js && html5) + //if (ry == -1) ry = rx; + // + //rx *= 0.5; + //ry *= 0.5; + // + //if (rx > width / 2) rx = width / 2; + //if (ry > height / 2) ry = height / 2; + // + //var xe = x + width, + //ye = y + height, + //cx1 = -rx + (rx * SIN45), + //cx2 = -rx + (rx * TAN22), + //cy1 = -ry + (ry * SIN45), + //cy2 = -ry + (ry * TAN22); + // + //context.moveTo (xe, ye - ry); + //context.quadraticCurveTo (xe, ye + cy2, xe + cx1, ye + cy1); + //context.quadraticCurveTo (xe + cx2, ye, xe - rx, ye); + //context.lineTo (x + rx, ye); + //context.quadraticCurveTo (x - cx2, ye, x - cx1, ye + cy1); + //context.quadraticCurveTo (x, ye + cy2, x, ye - ry); + //context.lineTo (x, y + ry); + //context.quadraticCurveTo (x, y - cy2, x - cx1, y - cy1); + //context.quadraticCurveTo (x - cx2, y, x + rx, y); + //context.lineTo (xe - rx, y); + //context.quadraticCurveTo (xe + cx2, y, xe + cx1, y - cy1); + //context.quadraticCurveTo (xe, y - cy2, xe, y + ry); + //context.lineTo (xe, ye - ry); + //#end + + } + + + private static inline function isCCW (x1:Float, y1:Float, x2:Float, y2:Float, x3:Float, y3:Float) { + + return ((x2 - x1) * (y3 - y1) - (y2 - y1) * (x3 - x1)) < 0; + + } + + + private static function normalizeUVT (uvt:Vector, skipT:Bool = false): { max:Float, uvt:Vector } { + + var max:Float = Math.NEGATIVE_INFINITY; + var tmp = Math.NEGATIVE_INFINITY; + var len = uvt.length; + + for (t in 1...len + 1) { + + if (skipT && t % 3 == 0) { + + continue; + + } + + tmp = uvt[t - 1]; + + if (max < tmp) { + + max = tmp; + + } + + } + + var result = new Vector (); + + for (t in 1...len + 1) { + + if (skipT && t % 3 == 0) { + + continue; + + } + + result.push ((uvt[t - 1] / max)); + + } + + return { max: max, uvt: result }; + + } + + + private static function playCommands (commands:Array, stroke:Bool = false):Void { + + //#if (js && html5) + //bounds = graphics.__bounds; + // + //var offsetX = bounds.x; + //var offsetY = bounds.y; + // + //var positionX = 0.0; + //var positionY = 0.0; + // + //var closeGap = false; + //var startX = 0.0; + //var startY = 0.0; + // + //for (command in commands) { + // + //switch (command) { + // + //case CubicCurveTo (cx1, cy1, cx2, cy2, x, y): + // + //context.bezierCurveTo (cx1 - offsetX, cy1 - offsetY, cx2 - offsetX, cy2 - offsetY, x - offsetX, y - offsetY); + // + //case CurveTo (cx, cy, x, y): + // + //context.quadraticCurveTo (cx - offsetX, cy - offsetY, x - offsetX, y - offsetY); + // + //case DrawCircle (x, y, radius): + // + //context.moveTo (x - offsetX + radius, y - offsetY); + //context.arc (x - offsetX, y - offsetY, radius, 0, Math.PI * 2, true); + // + //case DrawEllipse (x, y, width, height): + // + //x -= offsetX; + //y -= offsetY; + // + //var kappa = .5522848, + //ox = (width / 2) * kappa, // control point offset horizontal + //oy = (height / 2) * kappa, // control point offset vertical + //xe = x + width, // x-end + //ye = y + height, // y-end + //xm = x + width / 2, // x-middle + //ym = y + height / 2; // y-middle + // + //context.moveTo (x, ym); + //context.bezierCurveTo (x, ym - oy, xm - ox, y, xm, y); + //context.bezierCurveTo (xm + ox, y, xe, ym - oy, xe, ym); + //context.bezierCurveTo (xe, ym + oy, xm + ox, ye, xm, ye); + //context.bezierCurveTo (xm - ox, ye, x, ym + oy, x, ym); + // + //case DrawRoundRect (x, y, width, height, rx, ry): + // + //drawRoundRect (x - offsetX, y - offsetY, width, height, rx, ry); + // + //case LineTo (x, y): + // + //context.lineTo (x - offsetX, y - offsetY); + // + //positionX = x; + //positionY = y; + // + //case MoveTo (x, y): + // + //context.moveTo (x - offsetX, y - offsetY); + // + //positionX = x; + //positionY = y; + // + //closeGap = true; + //startX = x; + //startY = y; + // + //case LineStyle (thickness, color, alpha, pixelHinting, scaleMode, caps, joints, miterLimit): + // + //if (stroke && hasStroke) { + // + //context.closePath (); + //context.stroke (); + //context.beginPath (); + // + //} + // + //context.moveTo (positionX - offsetX, positionY - offsetY); + // + //if (thickness == null) { + // + //hasStroke = false; + // + //} else { + // + //context.lineWidth = thickness; + // + //context.lineJoin = (joints == null ? "round" : Std.string (joints).toLowerCase ()); + //context.lineCap = (caps == null ? "round" : switch (caps) { + //case CapsStyle.NONE: "butt"; + //default: Std.string (caps).toLowerCase (); + //}); + // + //context.miterLimit = (miterLimit == null ? 3 : miterLimit); + // + //if (alpha == 1 || alpha == null) { + // + //context.strokeStyle = (color == null ? "#000000" : "#" + StringTools.hex (color & 0x00FFFFFF, 6)); + // + //} else { + // + //var r = (color & 0xFF0000) >>> 16; + //var g = (color & 0x00FF00) >>> 8; + //var b = (color & 0x0000FF); + // + //context.strokeStyle = (color == null ? "#000000" : "rgba(" + r + ", " + g + ", " + b + ", " + alpha + ")"); + // + //} + // + //hasStroke = true; + // + //} + // + //case BeginBitmapFill (bitmap, matrix, repeat, smooth): + // + //if (bitmap != bitmapFill || repeat != bitmapRepeat) { + // + //bitmapFill = bitmap; + //bitmapRepeat = repeat; + //pattern = null; + //hasFill = false; + // + //bitmap.__sync (); + // + //} + // + //if (matrix != null) { + // + //pendingMatrix = matrix; + //inversePendingMatrix = matrix.clone (); + //inversePendingMatrix.invert (); + // + //} else { + // + //pendingMatrix = null; + //inversePendingMatrix = null; + // + //} + // + //case BeginFill (rgb, alpha): + // + //if (alpha < 0.005) { + // + //hasFill = false; + // + //} else { + // + //if (alpha == 1) { + // + //context.fillStyle = "#" + StringTools.hex (rgb, 6); + // + //} else { + // + //var r = (rgb & 0xFF0000) >>> 16; + //var g = (rgb & 0x00FF00) >>> 8; + //var b = (rgb & 0x0000FF); + // + //context.fillStyle = "rgba(" + r + ", " + g + ", " + b + ", " + alpha + ")"; + // + //} + // + //bitmapFill = null; + //hasFill = true; + // + //} + // + //case BeginGradientFill (type, colors, alphas, ratios, matrix, spreadMethod, interpolationMethod, focalPointRatio): + // + //var gradientFill = null; + // + //switch (type) { + // + //case RADIAL: + // + //if (matrix == null) matrix = new Matrix (); + //var point = matrix.transformPoint (new Point (1638.4, 0)); + //gradientFill = context.createRadialGradient (matrix.tx, matrix.ty, 0, matrix.tx, matrix.ty, (point.x - matrix.tx) / 2); + // + //case LINEAR: + // + //var matrix = matrix != null ? matrix.clone () : new Matrix (); + //var point1 = matrix.transformPoint (new Point (-819.2, 0)); + //var point2 = matrix.transformPoint (new Point (819.2, 0)); + // + //gradientFill = context.createLinearGradient (point1.x, point1.y, point2.x, point2.y); + // + //} + // + //for (i in 0...colors.length) { + // + //var rgb = colors[i]; + //var alpha = alphas[i]; + //var r = (rgb & 0xFF0000) >>> 16; + //var g = (rgb & 0x00FF00) >>> 8; + //var b = (rgb & 0x0000FF); + // + //var ratio = ratios[i] / 0xFF; + //if (ratio < 0) ratio = 0; + //if (ratio > 1) ratio = 1; + // + //gradientFill.addColorStop (ratio, "rgba(" + r + ", " + g + ", " + b + ", " + alpha + ")"); + // + //} + // + //context.fillStyle = gradientFill; + // + //bitmapFill = null; + //hasFill = true; + // + //case DrawRect (x, y, width, height): + // + //var optimizationUsed = false; + // + //if (bitmapFill != null) { + // + //var st:Float = 0; + //var sr:Float = 0; + //var sb:Float = 0; + //var sl:Float = 0; + // + //var canOptimizeMatrix = true; + // + //if (pendingMatrix != null) { + // + //if (pendingMatrix.b != 0 || pendingMatrix.c != 0) { + // + //canOptimizeMatrix = false; + // + //} else { + // + //var stl = inversePendingMatrix.transformPoint(new Point(x, y)); + //var sbr = inversePendingMatrix.transformPoint(new Point(x + width, y + height)); + // + //st = stl.y; + //sl = stl.x; + //sb = sbr.y; + //sr = sbr.x; + // + //} + // + //} else { + // + //st = y; + //sl = x; + //sb = y + height; + //sr = x + width; + // + //} + // + //if (canOptimizeMatrix && st >= 0 && sl >= 0 && sr <= bitmapFill.width && sb <= bitmapFill.height) { + // + //optimizationUsed = true; + //context.drawImage (bitmapFill.__image.src, sl, st, sr - sl, sb - st, x - offsetX, y - offsetY, width, height); + //} + //} + // + //if (!optimizationUsed) { + // + //context.rect (x - offsetX, y - offsetY, width, height); + //} + // + // + //default: + // + //} + // + //} + // + //if (stroke && hasStroke) { + // + //if (hasFill && closeGap) { + // + //context.lineTo (startX - offsetX, startY - offsetY); + // + //} + // + //context.stroke (); + // + //} + // + //if (!stroke) { + // + //if (hasFill || bitmapFill != null) { + // + //if (bitmapFill != null) { + // + //beginPatternFill (bitmapFill, bitmapRepeat); + // + //} + // + //context.translate (-bounds.x, -bounds.y); + // + //if (pendingMatrix != null) { + // + //context.transform (pendingMatrix.a, pendingMatrix.b, pendingMatrix.c, pendingMatrix.d, pendingMatrix.tx, pendingMatrix.ty); + //context.fill (); + //context.transform (inversePendingMatrix.a, inversePendingMatrix.b, inversePendingMatrix.c, inversePendingMatrix.d, inversePendingMatrix.tx, inversePendingMatrix.ty); + // + //} else { + // + //context.fill (); + // + //} + // + //context.translate (bounds.x, bounds.y); + //context.closePath (); + // + //} + // + //} + //#end + + } + + + public static function render (graphics:Graphics, renderSession:RenderSession):Void { + + //#if (js && html5) + // + //if (graphics.__dirty) { + // + //CanvasGraphics.graphics = graphics; + //bounds = graphics.__bounds; + // + //if (!graphics.__visible || graphics.__commands.length == 0 || bounds == null || bounds.width == 0 || bounds.height == 0) { + // + //graphics.__canvas = null; + //graphics.__context = null; + // + //} else { + // + //if (graphics.__canvas == null) { + // + //graphics.__canvas = cast Browser.document.createElement ("canvas"); + //graphics.__context = graphics.__canvas.getContext ("2d"); + ////untyped (context).mozImageSmoothingEnabled = false; + ////untyped (context).webkitImageSmoothingEnabled = false; + ////context.imageSmoothingEnabled = false; + //} + // + //context = graphics.__context; + // + //graphics.__canvas.width = Math.ceil (bounds.width); + //graphics.__canvas.height = Math.ceil (bounds.height); + // + //var offsetX = bounds.x; + //var offsetY = bounds.y; + // + //fillCommands = new Array (); + //strokeCommands = new Array (); + // + //hasFill = false; + //hasStroke = false; + //bitmapFill = null; + //bitmapRepeat = false; + // + //inline function endAndPush( command : DrawCommand ) + //{ + //endFill(); + //endStroke(); + // + //strokeCommands.push( command ); + //fillCommands.push( command ); + //} + // + //for (command in graphics.__commands) { + // + //switch (command) { + // + //case CubicCurveTo (_, _, _, _, _, _), CurveTo (_, _, _, _), LineTo (_, _), MoveTo (_, _): + // + //fillCommands.push (command); + //strokeCommands.push (command); + // + //case EndFill: + // + //endFill (); + //endStroke (); + //hasFill = false; + // + //case LineStyle (_, _, _, _, _, _, _, _): + // + //strokeCommands.push (command); + // + //case BeginBitmapFill (_, _, _, _), BeginFill (_, _), BeginGradientFill (_, _, _, _, _, _, _, _): + // + //endFill (); + //endStroke (); + // + //fillCommands.push (command); + //strokeCommands.push (command); + // + //case DrawCircle (_, _, _), DrawEllipse (_, _, _, _), DrawRect (_, _, _, _), DrawRoundRect (_, _, _, _, _, _): + // + //endFill (); + //endStroke (); + // + //fillCommands.push (command); + //strokeCommands.push (command); + // + //case DrawTriangles (vertices, indices, uvtData, culling, _, _): + // + //endFill (); + //endStroke (); + // + //var v = vertices; + //var ind = indices; + //var uvt = uvtData; + //var pattern:CanvasElement = null; + //var colorFill = bitmapFill == null; + // + //if (colorFill && uvt != null) { + // + //// Flash doesn't draw anything if the fill isn't a bitmap and there are uvt values + //break; + // + //} + // + //if (!colorFill) { + // + ////TODO move this to Graphics? + // + //if (uvtData == null) { + // + //uvtData = new Vector (); + // + //for (i in 0...(Std.int (v.length / 2))) { + // + //uvtData.push (v[i * 2] / bitmapFill.width); + //uvtData.push (v[i * 2 + 1] / bitmapFill.height); + // + //} + // + //} + // + //var skipT = uvtData.length != v.length; + //var normalizedUVT = normalizeUVT (uvtData, skipT); + //var maxUVT = normalizedUVT.max; + //uvt = normalizedUVT.uvt; + // + //if (maxUVT > 1) { + // + //pattern = createTempPatternCanvas (bitmapFill, bitmapRepeat, Std.int (bounds.width), Std.int (bounds.height)); + // + //} else { + // + //pattern = createTempPatternCanvas (bitmapFill, bitmapRepeat, bitmapFill.width, bitmapFill.height); + // + //} + // + //} + // + //var i = 0; + //var l = ind.length; + // + //var a:Int, b:Int, c:Int; + //var iax:Int, iay:Int, ibx:Int, iby:Int, icx:Int, icy:Int; + //var x1:Float, y1:Float, x2:Float, y2:Float, x3:Float, y3:Float; + //var uvx1:Float, uvy1:Float, uvx2:Float, uvy2:Float, uvx3:Float, uvy3:Float; + //var denom:Float; + //var t1:Float, t2:Float, t3:Float, t4:Float; + //var dx:Float, dy:Float; + // + //while (i < l) { + // + //a = i; + //b = i + 1; + //c = i + 2; + // + //iax = ind[a] * 2; + //iay = ind[a] * 2 + 1; + //ibx = ind[b] * 2; + //iby = ind[b] * 2 + 1; + //icx = ind[c] * 2; + //icy = ind[c] * 2 + 1; + // + //x1 = v[iax]; + //y1 = v[iay]; + //x2 = v[ibx]; + //y2 = v[iby]; + //x3 = v[icx]; + //y3 = v[icy]; + // + //switch (culling) { + // + //case POSITIVE: + // + //if (!isCCW (x1, y1, x2, y2, x3, y3)) { + // + //i += 3; + //continue; + // + //} + // + //case NEGATIVE: + // + //if (isCCW (x1, y1, x2, y2, x3, y3)) { + // + //i += 3; + //continue; + // + //} + // + //default: + // + //} + // + //if (colorFill) { + // + //context.beginPath (); + //context.moveTo (x1, y1); + //context.lineTo (x2, y2); + //context.lineTo (x3, y3); + //context.closePath (); + //context.fill (); + //i += 3; + //continue; + // + //} + // + //context.save (); + //context.beginPath (); + //context.moveTo (x1, y1); + //context.lineTo (x2, y2); + //context.lineTo (x3, y3); + //context.closePath (); + // + //context.clip (); + // + //uvx1 = uvt[iax] * pattern.width; + //uvx2 = uvt[ibx] * pattern.width; + //uvx3 = uvt[icx] * pattern.width; + //uvy1 = uvt[iay] * pattern.height; + //uvy2 = uvt[iby] * pattern.height; + //uvy3 = uvt[icy] * pattern.height; + // + //denom = uvx1 * (uvy3 - uvy2) - uvx2 * uvy3 + uvx3 * uvy2 + (uvx2 - uvx3) * uvy1; + // + //if (denom == 0) { + // + //i += 3; + //continue; + // + //} + // + //t1 = - (uvy1 * (x3 - x2) - uvy2 * x3 + uvy3 * x2 + (uvy2 - uvy3) * x1) / denom; + //t2 = (uvy2 * y3 + uvy1 * (y2 - y3) - uvy3 * y2 + (uvy3 - uvy2) * y1) / denom; + //t3 = (uvx1 * (x3 - x2) - uvx2 * x3 + uvx3 * x2 + (uvx2 - uvx3) * x1) / denom; + //t4 = - (uvx2 * y3 + uvx1 * (y2 - y3) - uvx3 * y2 + (uvx3 - uvx2) * y1) / denom; + //dx = (uvx1 * (uvy3 * x2 - uvy2 * x3) + uvy1 * (uvx2 * x3 - uvx3 * x2) + (uvx3 * uvy2 - uvx2 * uvy3) * x1) / denom; + //dy = (uvx1 * (uvy3 * y2 - uvy2 * y3) + uvy1 * (uvx2 * y3 - uvx3 * y2) + (uvx3 * uvy2 - uvx2 * uvy3) * y1) / denom; + // + //context.transform (t1, t2, t3, t4, dx, dy); + //context.drawImage (pattern, 0, 0); + //context.restore (); + // + //i += 3; + // + //} + // + //case DrawTiles (sheet, tileData, smooth, flags, count): + // + //var useScale = (flags & Graphics.TILE_SCALE) > 0; + //var useRotation = (flags & Graphics.TILE_ROTATION) > 0; + //var useTransform = (flags & Graphics.TILE_TRANS_2x2) > 0; + //var useRGB = (flags & Graphics.TILE_RGB) > 0; + //var useAlpha = (flags & Graphics.TILE_ALPHA) > 0; + //var useRect = (flags & Graphics.TILE_RECT) > 0; + //var useOrigin = (flags & Graphics.TILE_ORIGIN) > 0; + //var useBlendAdd = (flags & Graphics.TILE_BLEND_ADD) > 0; + // + //if (useTransform) { useScale = false; useRotation = false; } + // + //var scaleIndex = 0; + //var rotationIndex = 0; + //var rgbIndex = 0; + //var alphaIndex = 0; + //var transformIndex = 0; + // + //var numValues = 3; + // + //if (useRect) { numValues = useOrigin ? 8 : 6; } + //if (useScale) { scaleIndex = numValues; numValues ++; } + //if (useRotation) { rotationIndex = numValues; numValues ++; } + //if (useTransform) { transformIndex = numValues; numValues += 4; } + //if (useRGB) { rgbIndex = numValues; numValues += 3; } + //if (useAlpha) { alphaIndex = numValues; numValues ++; } + // + //var totalCount = tileData.length; + //if (count >= 0 && totalCount > count) totalCount = count; + //var itemCount = Std.int (totalCount / numValues); + //var index = 0; + // + //var rect = null; + //var center = null; + //var previousTileID = -1; + // + //var surface:Dynamic; + //sheet.__bitmap.__sync (); + //surface = sheet.__bitmap.__image.src; + // + //if (useBlendAdd) { + // + //context.globalCompositeOperation = "lighter"; + // + //} + // + //while (index < totalCount) { + // + //var tileID = (!useRect) ? Std.int (tileData[index + 2]) : -1; + // + //if (!useRect && tileID != previousTileID) { + // + //rect = sheet.__tileRects[tileID]; + //center = sheet.__centerPoints[tileID]; + // + //previousTileID = tileID; + // + //} else if (useRect) { + // + //rect = sheet.__rectTile; + //rect.setTo (tileData[index + 2], tileData[index + 3], tileData[index + 4], tileData[index + 5]); + //center = sheet.__point; + // + //if (useOrigin) { + // + //center.setTo (tileData[index + 6], tileData[index + 7]); + // + //} else { + // + //center.setTo (0, 0); + // + //} + // + //} + // + //if (rect != null && rect.width > 0 && rect.height > 0 && center != null) { + // + //context.save (); + //context.translate (tileData[index], tileData[index + 1]); + // + //if (useRotation) { + // + //context.rotate (tileData[index + rotationIndex]); + // + //} + // + //var scale = 1.0; + // + //if (useScale) { + // + //scale = tileData[index + scaleIndex]; + // + //} + // + //if (useTransform) { + // + //context.transform (tileData[index + transformIndex], tileData[index + transformIndex + 1], tileData[index + transformIndex + 2], tileData[index + transformIndex + 3], 0, 0); + // + //} + // + //if (useAlpha) { + // + //context.globalAlpha = tileData[index + alphaIndex]; + // + //} + // + //context.drawImage (surface, rect.x, rect.y, rect.width, rect.height, -center.x * scale, -center.y * scale, rect.width * scale, rect.height * scale); + //context.restore (); + // + //} + // + //index += numValues; + // + //} + // + //if (useBlendAdd) { + // + //context.globalCompositeOperation = "source-over"; + // + //} + // + //default: + // + //openfl.Lib.notImplemented ("CanvasGraphics"); + // + //} + // + //} + // + //} + // + //graphics.__dirty = false; + // + //if (fillCommands.length > 0) { + // + //endFill (); + // + //} + // + //if (strokeCommands.length > 0) { + // + //endStroke (); + // + //} + // + //} + // + //#end + + } + + + public static function renderMask (graphics:Graphics, renderSession:RenderSession) { + + //if (graphics.__commands.length != 0) { + // + //var context = renderSession.context; + // + //var positionX = 0.0; + //var positionY = 0.0; + // + //var offsetX = 0; + //var offsetY = 0; + // + //for (command in graphics.__commands) { + // + //switch (command) { + // + //case CubicCurveTo (cx1, cx2, cy1, cy2, x, y): + // + //context.bezierCurveTo (cx1 - offsetX, cy1 - offsetY, cx2 - offsetX, cy2 - offsetY, x - offsetX, y - offsetY); + //positionX = x; + //positionY = y; + // + //case CurveTo (cx, cy, x, y): + // + //context.quadraticCurveTo (cx - offsetX, cy - offsetY, x - offsetX, y - offsetY); + //positionX = x; + //positionY = y; + // + //case DrawCircle (x, y, radius): + // + //context.arc (x - offsetX, y - offsetY, radius, 0, Math.PI * 2, true); + // + //case DrawEllipse (x, y, width, height): + // + //x -= offsetX; + //y -= offsetY; + // + //var kappa = .5522848, + //ox = (width / 2) * kappa, // control point offset horizontal + //oy = (height / 2) * kappa, // control point offset vertical + //xe = x + width, // x-end + //ye = y + height, // y-end + //xm = x + width / 2, // x-middle + //ym = y + height / 2; // y-middle + // + ////closePath (false); + ////beginPath (); + //context.moveTo (x, ym); + //context.bezierCurveTo (x, ym - oy, xm - ox, y, xm, y); + //context.bezierCurveTo (xm + ox, y, xe, ym - oy, xe, ym); + //context.bezierCurveTo (xe, ym + oy, xm + ox, ye, xm, ye); + //context.bezierCurveTo (xm - ox, ye, x, ym + oy, x, ym); + ////closePath (false); + // + //case DrawRect (x, y, width, height): + // + //context.rect (x - offsetX, y - offsetY, width, height); + // + //case DrawRoundRect (x, y, width, height, rx, ry): + // + //drawRoundRect (x - offsetX, y - offsetY, width, height, rx, ry); + // + //case LineTo (x, y): + // + //context.lineTo (x - offsetX, y - offsetY); + //positionX = x; + //positionY = y; + // + //case MoveTo (x, y): + // + //context.moveTo (x - offsetX, y - offsetY); + //positionX = x; + //positionY = y; + // + //default: + // + //} + // + //} + // + //} + + } + + +} \ No newline at end of file diff --git a/openfl/_internal/renderer/cairo/CairoRenderer.hx b/openfl/_internal/renderer/cairo/CairoRenderer.hx new file mode 100644 index 0000000000..1259415510 --- /dev/null +++ b/openfl/_internal/renderer/cairo/CairoRenderer.hx @@ -0,0 +1,53 @@ +package openfl._internal.renderer.cairo; + + +import lime.graphics.cairo.Cairo; +import lime.math.Matrix3; +import openfl._internal.renderer.AbstractRenderer; +import openfl._internal.renderer.RenderSession; +import openfl.display.Stage; + +@:access(openfl.display.Stage) +@:allow(openfl.display.Stage) + + +class CairoRenderer extends AbstractRenderer { + + + private var cairo:Cairo; + + + public function new (width:Int, height:Int, cairo:Cairo) { + + super (width, height); + + this.cairo = cairo; + + renderSession = new RenderSession (); + renderSession.cairo = cairo; + renderSession.roundPixels = true; + renderSession.renderer = this; + //#if !neko + //renderSession.maskManager = new MaskManager (renderSession); + //#end + + } + + + public override function render (stage:Stage):Void { + + cairo.transform (new Matrix3 ()); + + if (stage.__clearBeforeRender) { + + cairo.setSourceRGB (stage.__colorSplit[0], stage.__colorSplit[1], stage.__colorSplit[2]); + cairo.paint (); + + } + + stage.__renderCairo (renderSession); + + } + + +} \ No newline at end of file diff --git a/openfl/_internal/renderer/cairo/CairoShape.hx b/openfl/_internal/renderer/cairo/CairoShape.hx new file mode 100644 index 0000000000..50843e871f --- /dev/null +++ b/openfl/_internal/renderer/cairo/CairoShape.hx @@ -0,0 +1,76 @@ +package openfl._internal.renderer.cairo; + + +import openfl.display.DisplayObject; + +@:access(openfl.display.DisplayObject) +@:access(openfl.display.Graphics) + + +class CairoShape { + + + public static inline function render (shape:DisplayObject, renderSession:RenderSession):Void { + + if (!shape.__renderable || shape.__worldAlpha <= 0) return; + + var graphics = shape.__graphics; + + if (graphics != null) { + + CairoGraphics.render (graphics, renderSession); + + //#if old + //CanvasGraphics.render (graphics, renderSession); + //#else + //CanvasGraphics.renderObjectGraphics (shape, renderSession); + //#end + + //if (graphics.__canvas != null) { + // + //if (shape.__mask != null) { + // + //renderSession.maskManager.pushMask (shape.__mask); + // + //} + // + //var context = renderSession.context; + //var scrollRect = shape.scrollRect; + // + //context.globalAlpha = shape.__worldAlpha; + //var transform = shape.__worldTransform; + // + //if (renderSession.roundPixels) { + // + //context.setTransform (transform.a, transform.b, transform.c, transform.d, Std.int (transform.tx), Std.int (transform.ty)); + // + //} else { + // + //context.setTransform (transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); + // + //} + // + //if (scrollRect == null) { + // + //context.drawImage (graphics.__canvas, graphics.__bounds.x, graphics.__bounds.y); + // + //} else { + // + //context.drawImage (graphics.__canvas, scrollRect.x - graphics.__bounds.x, scrollRect.y - graphics.__bounds.y, scrollRect.width, scrollRect.height, graphics.__bounds.x + scrollRect.x, graphics.__bounds.y + scrollRect.y, scrollRect.width, scrollRect.height); + // + //} + // + //if (shape.__mask != null) { + // + //renderSession.maskManager.popMask (); + // + //} + // + //} + + } + + } + + +} \ No newline at end of file diff --git a/openfl/display/DisplayObject.hx b/openfl/display/DisplayObject.hx index 569ef595ae..18078b8c55 100644 --- a/openfl/display/DisplayObject.hx +++ b/openfl/display/DisplayObject.hx @@ -2,6 +2,7 @@ package openfl.display; #if !flash #if !openfl_legacy import lime.ui.MouseCursor; +import openfl._internal.renderer.cairo.CairoShape; import openfl._internal.renderer.canvas.CanvasGraphics; import openfl._internal.renderer.canvas.CanvasShape; import openfl._internal.renderer.dom.DOMShape; @@ -1104,6 +1105,17 @@ class DisplayObject extends EventDispatcher implements IBitmapDrawable { } + @:noCompletion @:dox(hide) public function __renderCairo (renderSession:RenderSession):Void { + + if (__graphics != null) { + + CairoShape.render (this, renderSession); + + } + + } + + @:noCompletion @:dox(hide) public function __renderCanvas (renderSession:RenderSession):Void { if (__graphics != null) { diff --git a/openfl/display/Stage.hx b/openfl/display/Stage.hx index 01a14865b6..da36bf0968 100644 --- a/openfl/display/Stage.hx +++ b/openfl/display/Stage.hx @@ -19,6 +19,7 @@ import lime.ui.KeyCode; import lime.ui.KeyModifier; import lime.ui.Mouse; import openfl._internal.renderer.AbstractRenderer; +import openfl._internal.renderer.cairo.CairoRenderer; import openfl._internal.renderer.canvas.CanvasRenderer; import openfl._internal.renderer.dom.DOMRenderer; import openfl._internal.renderer.opengl.GLRenderer; @@ -618,6 +619,10 @@ class Stage extends DisplayObjectContainer implements IModule { __renderer = new DOMRenderer (stageWidth, stageHeight, element); + case CAIRO (cairo): + + __renderer = new CairoRenderer (stageWidth, stageHeight, cairo); + default: } @@ -911,6 +916,17 @@ class Stage extends DisplayObjectContainer implements IModule { if (__renderer != null) { + switch (context) { + + case CAIRO (cairo): + + cast (__renderer, CairoRenderer).cairo = cairo; + @:privateAccess (__renderer.renderSession).cairo = cairo; + + default: + + } + __renderer.render (this); } From b01789390488197e7a82b7a8c144161b584e2465 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Sat, 2 May 2015 17:12:16 -0700 Subject: [PATCH 100/150] Some more work on Cairo rendering --- .../_internal/renderer/cairo/CairoGraphics.hx | 736 +++++++++--------- openfl/_internal/renderer/cairo/CairoShape.hx | 29 +- .../renderer/canvas/CanvasGraphics.hx | 9 - openfl/display/Graphics.hx | 2 + openfl/geom/Matrix.hx | 8 + 5 files changed, 389 insertions(+), 395 deletions(-) diff --git a/openfl/_internal/renderer/cairo/CairoGraphics.hx b/openfl/_internal/renderer/cairo/CairoGraphics.hx index 89f933850d..9cf5bd5b2e 100644 --- a/openfl/_internal/renderer/cairo/CairoGraphics.hx +++ b/openfl/_internal/renderer/cairo/CairoGraphics.hx @@ -1,6 +1,8 @@ package openfl._internal.renderer.cairo; +import lime.graphics.cairo.Cairo; +import lime.graphics.cairo.CairoSurface; import openfl._internal.renderer.RenderSession; import openfl.display.BitmapData; import openfl.display.CapsStyle; @@ -27,6 +29,7 @@ class CairoGraphics { private static var bitmapFill:BitmapData; private static var bitmapRepeat:Bool; private static var bounds:Rectangle; + private static var cairo:Cairo; private static var fillCommands:Array; private static var graphics:Graphics; private static var hasFill:Bool; @@ -35,11 +38,6 @@ class CairoGraphics { private static var pendingMatrix:Matrix; private static var strokeCommands:Array; - #if (js && html5) - private static var context:CanvasRenderingContext2D; - private static var pattern:CanvasPattern; - #end - private static function beginPatternFill (bitmapFill:BitmapData, bitmapRepeat:Bool):Void { @@ -87,23 +85,18 @@ class CairoGraphics { private static function endFill ():Void { - //#if (js && html5) - //context.beginPath (); - //playCommands (fillCommands, false); - //fillCommands = []; - //#end + cairo.newPath (); + playCommands (fillCommands, false); + fillCommands = []; } private static function endStroke ():Void { - //#if (js && html5) - //context.beginPath (); - //playCommands (strokeCommands, true); - //context.closePath (); - //strokeCommands = []; - //#end + cairo.newPath (); + playCommands (strokeCommands, true); + strokeCommands = []; } @@ -196,38 +189,37 @@ class CairoGraphics { private static function playCommands (commands:Array, stroke:Bool = false):Void { - //#if (js && html5) - //bounds = graphics.__bounds; - // - //var offsetX = bounds.x; - //var offsetY = bounds.y; - // - //var positionX = 0.0; - //var positionY = 0.0; - // - //var closeGap = false; - //var startX = 0.0; - //var startY = 0.0; - // - //for (command in commands) { - // - //switch (command) { - // - //case CubicCurveTo (cx1, cy1, cx2, cy2, x, y): - // + bounds = graphics.__bounds; + + var offsetX = bounds.x; + var offsetY = bounds.y; + + var positionX = 0.0; + var positionY = 0.0; + + var closeGap = false; + var startX = 0.0; + var startY = 0.0; + + for (command in commands) { + + switch (command) { + + case CubicCurveTo (cx1, cy1, cx2, cy2, x, y): + //context.bezierCurveTo (cx1 - offsetX, cy1 - offsetY, cx2 - offsetX, cy2 - offsetY, x - offsetX, y - offsetY); - // - //case CurveTo (cx, cy, x, y): - // + + case CurveTo (cx, cy, x, y): + //context.quadraticCurveTo (cx - offsetX, cy - offsetY, x - offsetX, y - offsetY); - // - //case DrawCircle (x, y, radius): - // - //context.moveTo (x - offsetX + radius, y - offsetY); - //context.arc (x - offsetX, y - offsetY, radius, 0, Math.PI * 2, true); - // - //case DrawEllipse (x, y, width, height): - // + + case DrawCircle (x, y, radius): + + cairo.moveTo (x - offsetX + radius, y - offsetY); + cairo.arcNegative (x - offsetX, y - offsetY, radius, 0, Math.PI * 2); + + case DrawEllipse (x, y, width, height): + //x -= offsetX; //y -= offsetY; // @@ -244,47 +236,47 @@ class CairoGraphics { //context.bezierCurveTo (xm + ox, y, xe, ym - oy, xe, ym); //context.bezierCurveTo (xe, ym + oy, xm + ox, ye, xm, ye); //context.bezierCurveTo (xm - ox, ye, x, ym + oy, x, ym); - // - //case DrawRoundRect (x, y, width, height, rx, ry): - // + + case DrawRoundRect (x, y, width, height, rx, ry): + //drawRoundRect (x - offsetX, y - offsetY, width, height, rx, ry); - // - //case LineTo (x, y): - // - //context.lineTo (x - offsetX, y - offsetY); - // - //positionX = x; - //positionY = y; - // - //case MoveTo (x, y): - // - //context.moveTo (x - offsetX, y - offsetY); - // - //positionX = x; - //positionY = y; - // - //closeGap = true; - //startX = x; - //startY = y; - // - //case LineStyle (thickness, color, alpha, pixelHinting, scaleMode, caps, joints, miterLimit): - // - //if (stroke && hasStroke) { - // + + case LineTo (x, y): + + cairo.lineTo (x - offsetX, y - offsetY); + + positionX = x; + positionY = y; + + case MoveTo (x, y): + + cairo.moveTo (x - offsetX, y - offsetY); + + positionX = x; + positionY = y; + + closeGap = true; + startX = x; + startY = y; + + case LineStyle (thickness, color, alpha, pixelHinting, scaleMode, caps, joints, miterLimit): + + if (stroke && hasStroke) { + //context.closePath (); //context.stroke (); //context.beginPath (); - // - //} - // - //context.moveTo (positionX - offsetX, positionY - offsetY); - // - //if (thickness == null) { - // - //hasStroke = false; - // - //} else { - // + + } + + cairo.moveTo (positionX - offsetX, positionY - offsetY); + + if (thickness == null) { + + hasStroke = false; + + } else { + //context.lineWidth = thickness; // //context.lineJoin = (joints == null ? "round" : Std.string (joints).toLowerCase ()); @@ -308,48 +300,51 @@ class CairoGraphics { //context.strokeStyle = (color == null ? "#000000" : "rgba(" + r + ", " + g + ", " + b + ", " + alpha + ")"); // //} - // - //hasStroke = true; - // - //} - // - //case BeginBitmapFill (bitmap, matrix, repeat, smooth): - // - //if (bitmap != bitmapFill || repeat != bitmapRepeat) { - // - //bitmapFill = bitmap; - //bitmapRepeat = repeat; + + hasStroke = true; + + } + + case BeginBitmapFill (bitmap, matrix, repeat, smooth): + + if (bitmap != bitmapFill || repeat != bitmapRepeat) { + + bitmapFill = bitmap; + bitmapRepeat = repeat; //pattern = null; - //hasFill = false; - // - //bitmap.__sync (); - // - //} - // - //if (matrix != null) { - // - //pendingMatrix = matrix; - //inversePendingMatrix = matrix.clone (); - //inversePendingMatrix.invert (); - // - //} else { - // - //pendingMatrix = null; - //inversePendingMatrix = null; - // - //} - // - //case BeginFill (rgb, alpha): - // - //if (alpha < 0.005) { - // - //hasFill = false; - // - //} else { - // + hasFill = false; + + bitmap.__sync (); + + } + + if (matrix != null) { + + pendingMatrix = matrix; + inversePendingMatrix = matrix.clone (); + inversePendingMatrix.invert (); + + } else { + + pendingMatrix = null; + inversePendingMatrix = null; + + } + + case BeginFill (rgb, alpha): + + if (alpha < 0.005) { + + hasFill = false; + + } else { + + cairo.setSourceRGBA (((rgb & 0xFF0000) >>> 16) / 0xFF, ((rgb & 0x00FF00) >>> 8) / 0xFF, (rgb & 0x0000FF) / 0xFF, alpha); + //if (alpha == 1) { // - //context.fillStyle = "#" + StringTools.hex (rgb, 6); + ////cairo.setSourceRGB ( + ////context.fillStyle = "#" + StringTools.hex (rgb, 6); // //} else { // @@ -357,249 +352,250 @@ class CairoGraphics { //var g = (rgb & 0x00FF00) >>> 8; //var b = (rgb & 0x0000FF); // - //context.fillStyle = "rgba(" + r + ", " + g + ", " + b + ", " + alpha + ")"; + ////context.fillStyle = "rgba(" + r + ", " + g + ", " + b + ", " + alpha + ")"; // //} - // - //bitmapFill = null; - //hasFill = true; - // - //} - // - //case BeginGradientFill (type, colors, alphas, ratios, matrix, spreadMethod, interpolationMethod, focalPointRatio): - // - //var gradientFill = null; - // - //switch (type) { - // - //case RADIAL: - // + + bitmapFill = null; + hasFill = true; + + } + + case BeginGradientFill (type, colors, alphas, ratios, matrix, spreadMethod, interpolationMethod, focalPointRatio): + + var gradientFill = null; + + switch (type) { + + case RADIAL: + //if (matrix == null) matrix = new Matrix (); //var point = matrix.transformPoint (new Point (1638.4, 0)); //gradientFill = context.createRadialGradient (matrix.tx, matrix.ty, 0, matrix.tx, matrix.ty, (point.x - matrix.tx) / 2); - // - //case LINEAR: - // + + case LINEAR: + //var matrix = matrix != null ? matrix.clone () : new Matrix (); //var point1 = matrix.transformPoint (new Point (-819.2, 0)); //var point2 = matrix.transformPoint (new Point (819.2, 0)); // //gradientFill = context.createLinearGradient (point1.x, point1.y, point2.x, point2.y); - // - //} - // - //for (i in 0...colors.length) { - // - //var rgb = colors[i]; - //var alpha = alphas[i]; - //var r = (rgb & 0xFF0000) >>> 16; - //var g = (rgb & 0x00FF00) >>> 8; - //var b = (rgb & 0x0000FF); - // - //var ratio = ratios[i] / 0xFF; - //if (ratio < 0) ratio = 0; - //if (ratio > 1) ratio = 1; - // + + } + + for (i in 0...colors.length) { + + var rgb = colors[i]; + var alpha = alphas[i]; + var r = (rgb & 0xFF0000) >>> 16; + var g = (rgb & 0x00FF00) >>> 8; + var b = (rgb & 0x0000FF); + + var ratio = ratios[i] / 0xFF; + if (ratio < 0) ratio = 0; + if (ratio > 1) ratio = 1; + //gradientFill.addColorStop (ratio, "rgba(" + r + ", " + g + ", " + b + ", " + alpha + ")"); - // - //} - // + + } + //context.fillStyle = gradientFill; - // - //bitmapFill = null; - //hasFill = true; - // - //case DrawRect (x, y, width, height): - // - //var optimizationUsed = false; - // - //if (bitmapFill != null) { - // - //var st:Float = 0; - //var sr:Float = 0; - //var sb:Float = 0; - //var sl:Float = 0; - // - //var canOptimizeMatrix = true; - // - //if (pendingMatrix != null) { - // - //if (pendingMatrix.b != 0 || pendingMatrix.c != 0) { - // - //canOptimizeMatrix = false; - // - //} else { - // - //var stl = inversePendingMatrix.transformPoint(new Point(x, y)); - //var sbr = inversePendingMatrix.transformPoint(new Point(x + width, y + height)); - // - //st = stl.y; - //sl = stl.x; - //sb = sbr.y; - //sr = sbr.x; - // - //} - // - //} else { - // - //st = y; - //sl = x; - //sb = y + height; - //sr = x + width; - // - //} - // - //if (canOptimizeMatrix && st >= 0 && sl >= 0 && sr <= bitmapFill.width && sb <= bitmapFill.height) { - // - //optimizationUsed = true; + + bitmapFill = null; + hasFill = true; + + case DrawRect (x, y, width, height): + + var optimizationUsed = false; + + if (bitmapFill != null) { + + var st:Float = 0; + var sr:Float = 0; + var sb:Float = 0; + var sl:Float = 0; + + var canOptimizeMatrix = true; + + if (pendingMatrix != null) { + + if (pendingMatrix.b != 0 || pendingMatrix.c != 0) { + + canOptimizeMatrix = false; + + } else { + + var stl = inversePendingMatrix.transformPoint(new Point(x, y)); + var sbr = inversePendingMatrix.transformPoint(new Point(x + width, y + height)); + + st = stl.y; + sl = stl.x; + sb = sbr.y; + sr = sbr.x; + + } + + } else { + + st = y; + sl = x; + sb = y + height; + sr = x + width; + + } + + if (canOptimizeMatrix && st >= 0 && sl >= 0 && sr <= bitmapFill.width && sb <= bitmapFill.height) { + + optimizationUsed = true; //context.drawImage (bitmapFill.__image.src, sl, st, sr - sl, sb - st, x - offsetX, y - offsetY, width, height); - //} - //} - // - //if (!optimizationUsed) { - // - //context.rect (x - offsetX, y - offsetY, width, height); - //} - // - // - //default: - // - //} - // - //} - // - //if (stroke && hasStroke) { - // - //if (hasFill && closeGap) { - // - //context.lineTo (startX - offsetX, startY - offsetY); - // - //} - // - //context.stroke (); - // - //} - // - //if (!stroke) { - // - //if (hasFill || bitmapFill != null) { - // - //if (bitmapFill != null) { - // - //beginPatternFill (bitmapFill, bitmapRepeat); - // - //} - // - //context.translate (-bounds.x, -bounds.y); - // - //if (pendingMatrix != null) { - // + } + } + + if (!optimizationUsed) { + + cairo.rectangle (x - offsetX, y - offsetY, width, height); + + } + + + default: + + } + + } + + if (stroke && hasStroke) { + + if (hasFill && closeGap) { + + cairo.lineTo (startX - offsetX, startY - offsetY); + + } + + cairo.stroke (); + + } + + if (!stroke) { + + if (hasFill || bitmapFill != null) { + + if (bitmapFill != null) { + + beginPatternFill (bitmapFill, bitmapRepeat); + + } + + cairo.translate (-bounds.x, -bounds.y); + + if (pendingMatrix != null) { + //context.transform (pendingMatrix.a, pendingMatrix.b, pendingMatrix.c, pendingMatrix.d, pendingMatrix.tx, pendingMatrix.ty); - //context.fill (); + cairo.fill (); //context.transform (inversePendingMatrix.a, inversePendingMatrix.b, inversePendingMatrix.c, inversePendingMatrix.d, inversePendingMatrix.tx, inversePendingMatrix.ty); - // - //} else { - // - //context.fill (); - // - //} - // - //context.translate (bounds.x, bounds.y); - //context.closePath (); - // - //} - // - //} - //#end + + } else { + + cairo.fill (); + + } + + cairo.translate (bounds.x, bounds.y); + cairo.closePath (); + cairo.paint (); + + } + + } } public static function render (graphics:Graphics, renderSession:RenderSession):Void { - //#if (js && html5) - // - //if (graphics.__dirty) { - // - //CanvasGraphics.graphics = graphics; - //bounds = graphics.__bounds; - // - //if (!graphics.__visible || graphics.__commands.length == 0 || bounds == null || bounds.width == 0 || bounds.height == 0) { - // - //graphics.__canvas = null; - //graphics.__context = null; - // - //} else { - // - //if (graphics.__canvas == null) { - // - //graphics.__canvas = cast Browser.document.createElement ("canvas"); - //graphics.__context = graphics.__canvas.getContext ("2d"); - ////untyped (context).mozImageSmoothingEnabled = false; - ////untyped (context).webkitImageSmoothingEnabled = false; - ////context.imageSmoothingEnabled = false; - //} - // - //context = graphics.__context; - // - //graphics.__canvas.width = Math.ceil (bounds.width); - //graphics.__canvas.height = Math.ceil (bounds.height); - // - //var offsetX = bounds.x; - //var offsetY = bounds.y; - // - //fillCommands = new Array (); - //strokeCommands = new Array (); - // - //hasFill = false; - //hasStroke = false; - //bitmapFill = null; - //bitmapRepeat = false; - // - //inline function endAndPush( command : DrawCommand ) - //{ - //endFill(); - //endStroke(); - // - //strokeCommands.push( command ); - //fillCommands.push( command ); - //} - // - //for (command in graphics.__commands) { - // - //switch (command) { - // - //case CubicCurveTo (_, _, _, _, _, _), CurveTo (_, _, _, _), LineTo (_, _), MoveTo (_, _): - // - //fillCommands.push (command); - //strokeCommands.push (command); - // - //case EndFill: - // - //endFill (); - //endStroke (); - //hasFill = false; - // - //case LineStyle (_, _, _, _, _, _, _, _): - // - //strokeCommands.push (command); - // - //case BeginBitmapFill (_, _, _, _), BeginFill (_, _), BeginGradientFill (_, _, _, _, _, _, _, _): - // - //endFill (); - //endStroke (); - // - //fillCommands.push (command); - //strokeCommands.push (command); - // - //case DrawCircle (_, _, _), DrawEllipse (_, _, _, _), DrawRect (_, _, _, _), DrawRoundRect (_, _, _, _, _, _): - // - //endFill (); - //endStroke (); - // - //fillCommands.push (command); - //strokeCommands.push (command); - // + if (graphics.__dirty) { + + CairoGraphics.graphics = graphics; + bounds = graphics.__bounds; + + if (!graphics.__visible || graphics.__commands.length == 0 || bounds == null || bounds.width == 0 || bounds.height == 0) { + + if (graphics.__cairo != null) { + + graphics.__cairo.destroy (); + graphics.__cairo = null; + + } + + } else { + + if (graphics.__cairo != null) { + + var surface = graphics.__cairo.target; + + if (bounds.width != surface.width || bounds.height != surface.height) { + + graphics.__cairo.destroy (); + graphics.__cairo = null; + + } + + } + + if (graphics.__cairo == null) { + + var surface = new CairoSurface (ARGB32, Std.int (bounds.width), Std.int (bounds.height)); + graphics.__cairo = new Cairo (surface); + surface.destroy (); + + } + + var offsetX = bounds.x; + var offsetY = bounds.y; + + fillCommands = new Array (); + strokeCommands = new Array (); + + hasFill = false; + hasStroke = false; + bitmapFill = null; + bitmapRepeat = false; + + for (command in graphics.__commands) { + + switch (command) { + + case CubicCurveTo (_, _, _, _, _, _), CurveTo (_, _, _, _), LineTo (_, _), MoveTo (_, _): + + fillCommands.push (command); + strokeCommands.push (command); + + case EndFill: + + endFill (); + endStroke (); + hasFill = false; + + case LineStyle (_, _, _, _, _, _, _, _): + + strokeCommands.push (command); + + case BeginBitmapFill (_, _, _, _), BeginFill (_, _), BeginGradientFill (_, _, _, _, _, _, _, _): + + endFill (); + endStroke (); + + fillCommands.push (command); + strokeCommands.push (command); + + case DrawCircle (_, _, _), DrawEllipse (_, _, _, _), DrawRect (_, _, _, _), DrawRoundRect (_, _, _, _, _, _): + + endFill (); + endStroke (); + + fillCommands.push (command); + strokeCommands.push (command); + //case DrawTriangles (vertices, indices, uvtData, culling, _, _): // //endFill (); @@ -882,33 +878,31 @@ class CairoGraphics { // //} // - //default: - // - //openfl.Lib.notImplemented ("CanvasGraphics"); - // - //} - // - //} - // - //} - // - //graphics.__dirty = false; - // - //if (fillCommands.length > 0) { - // - //endFill (); - // - //} - // - //if (strokeCommands.length > 0) { - // - //endStroke (); - // - //} - // - //} - // - //#end + default: + + openfl.Lib.notImplemented ("CairoGraphics"); + + } + + } + + } + + graphics.__dirty = false; + + if (fillCommands.length > 0) { + + endFill (); + + } + + if (strokeCommands.length > 0) { + + endStroke (); + + } + + } } diff --git a/openfl/_internal/renderer/cairo/CairoShape.hx b/openfl/_internal/renderer/cairo/CairoShape.hx index 50843e871f..7e8a543bd2 100644 --- a/openfl/_internal/renderer/cairo/CairoShape.hx +++ b/openfl/_internal/renderer/cairo/CairoShape.hx @@ -20,25 +20,19 @@ class CairoShape { CairoGraphics.render (graphics, renderSession); - //#if old - //CanvasGraphics.render (graphics, renderSession); - //#else - //CanvasGraphics.renderObjectGraphics (shape, renderSession); - //#end - - //if (graphics.__canvas != null) { - // + if (graphics.__cairo != null) { + //if (shape.__mask != null) { // //renderSession.maskManager.pushMask (shape.__mask); // //} - // - //var context = renderSession.context; - //var scrollRect = shape.scrollRect; - // + + var cairo = renderSession.cairo; + var scrollRect = shape.scrollRect; + //context.globalAlpha = shape.__worldAlpha; - //var transform = shape.__worldTransform; + var transform = shape.__worldTransform; // //if (renderSession.roundPixels) { // @@ -49,6 +43,11 @@ class CairoShape { //context.setTransform (transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); // //} + + cairo.transform (@:privateAccess (shape.__worldTransform).__toMatrix3 ()); + cairo.setSourceSurface (graphics.__cairo.target, graphics.__bounds.x, graphics.__bounds.y); + cairo.paint (); + // //if (scrollRect == null) { // @@ -65,8 +64,8 @@ class CairoShape { //renderSession.maskManager.popMask (); // //} - // - //} + + } } diff --git a/openfl/_internal/renderer/canvas/CanvasGraphics.hx b/openfl/_internal/renderer/canvas/CanvasGraphics.hx index dca2588959..87cddc4078 100644 --- a/openfl/_internal/renderer/canvas/CanvasGraphics.hx +++ b/openfl/_internal/renderer/canvas/CanvasGraphics.hx @@ -563,15 +563,6 @@ class CanvasGraphics { bitmapFill = null; bitmapRepeat = false; - inline function endAndPush( command : DrawCommand ) - { - endFill(); - endStroke(); - - strokeCommands.push( command ); - fillCommands.push( command ); - } - for (command in graphics.__commands) { switch (command) { diff --git a/openfl/display/Graphics.hx b/openfl/display/Graphics.hx index 370d0b1c8f..89d55ea26f 100644 --- a/openfl/display/Graphics.hx +++ b/openfl/display/Graphics.hx @@ -1,6 +1,7 @@ package openfl.display; #if !flash #if !openfl_legacy +import lime.graphics.cairo.Cairo; import openfl._internal.renderer.opengl.utils.FilterTexture; import openfl.errors.ArgumentError; import openfl._internal.renderer.opengl.utils.GraphicsRenderer; @@ -46,6 +47,7 @@ class Graphics { public static inline var TILE_BLEND_ADD = 0x00010000; @:noCompletion private var __bounds:Rectangle; + @:noCompletion private var __cairo:Cairo; @:noCompletion private var __commands:Array = []; @:noCompletion private var __dirty(default, set):Bool = true; @:noCompletion private var __glStack:Array = []; diff --git a/openfl/geom/Matrix.hx b/openfl/geom/Matrix.hx index d4dbe5d573..96ab46889f 100644 --- a/openfl/geom/Matrix.hx +++ b/openfl/geom/Matrix.hx @@ -1,6 +1,7 @@ package openfl.geom; #if !flash #if !openfl_legacy +import lime.math.Matrix3; import openfl.geom.Point; import lime.utils.Float32Array; @@ -755,6 +756,13 @@ class Matrix { } + @:noCompletion private function __toMatrix3 ():Matrix3 { + + return new Matrix3 (a, b, c, d, tx, ty); + + } + + @:noCompletion public inline function __transformX (pos:Point):Float { return pos.x * a + pos.y * c + tx; From c33604e5d091c45fd19910da76f863544cf8525e Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Sat, 2 May 2015 22:23:04 -0700 Subject: [PATCH 101/150] Cairo render improvements --- .../_internal/renderer/cairo/CairoGraphics.hx | 16 +++++--- .../_internal/renderer/cairo/CairoRenderer.hx | 2 +- openfl/_internal/renderer/cairo/CairoShape.hx | 5 ++- openfl/display/DisplayObjectContainer.hx | 41 +++++++++++++++++++ 4 files changed, 55 insertions(+), 9 deletions(-) diff --git a/openfl/_internal/renderer/cairo/CairoGraphics.hx b/openfl/_internal/renderer/cairo/CairoGraphics.hx index 9cf5bd5b2e..0d5fe647ae 100644 --- a/openfl/_internal/renderer/cairo/CairoGraphics.hx +++ b/openfl/_internal/renderer/cairo/CairoGraphics.hx @@ -3,6 +3,7 @@ package openfl._internal.renderer.cairo; import lime.graphics.cairo.Cairo; import lime.graphics.cairo.CairoSurface; +import lime.math.Matrix3; import openfl._internal.renderer.RenderSession; import openfl.display.BitmapData; import openfl.display.CapsStyle; @@ -18,6 +19,7 @@ import openfl.Vector; @:access(openfl.display.BitmapData) @:access(openfl.display.Graphics) @:access(openfl.display.Tilesheet) +@:access(openfl.geom.Matrix) class CairoGraphics { @@ -216,7 +218,7 @@ class CairoGraphics { case DrawCircle (x, y, radius): cairo.moveTo (x - offsetX + radius, y - offsetY); - cairo.arcNegative (x - offsetX, y - offsetY, radius, 0, Math.PI * 2); + cairo.arc (x - offsetX, y - offsetY, radius, 0, Math.PI * 2); case DrawEllipse (x, y, width, height): @@ -425,8 +427,8 @@ class CairoGraphics { } else { - var stl = inversePendingMatrix.transformPoint(new Point(x, y)); - var sbr = inversePendingMatrix.transformPoint(new Point(x + width, y + height)); + var stl = inversePendingMatrix.transformPoint (new Point (x, y)); + var sbr = inversePendingMatrix.transformPoint (new Point (x + width, y + height)); st = stl.y; sl = stl.x; @@ -490,9 +492,9 @@ class CairoGraphics { if (pendingMatrix != null) { - //context.transform (pendingMatrix.a, pendingMatrix.b, pendingMatrix.c, pendingMatrix.d, pendingMatrix.tx, pendingMatrix.ty); + cairo.transform (pendingMatrix.__toMatrix3 ()); cairo.fill (); - //context.transform (inversePendingMatrix.a, inversePendingMatrix.b, inversePendingMatrix.c, inversePendingMatrix.d, inversePendingMatrix.tx, inversePendingMatrix.ty); + cairo.transform (inversePendingMatrix.__toMatrix3 ()); } else { @@ -502,7 +504,7 @@ class CairoGraphics { cairo.translate (bounds.x, bounds.y); cairo.closePath (); - cairo.paint (); + //cairo.paint (); } @@ -550,6 +552,8 @@ class CairoGraphics { } + cairo = graphics.__cairo; + var offsetX = bounds.x; var offsetY = bounds.y; diff --git a/openfl/_internal/renderer/cairo/CairoRenderer.hx b/openfl/_internal/renderer/cairo/CairoRenderer.hx index 1259415510..e7d5f7864c 100644 --- a/openfl/_internal/renderer/cairo/CairoRenderer.hx +++ b/openfl/_internal/renderer/cairo/CairoRenderer.hx @@ -36,7 +36,7 @@ class CairoRenderer extends AbstractRenderer { public override function render (stage:Stage):Void { - cairo.transform (new Matrix3 ()); + cairo.identityMatrix (); if (stage.__clearBeforeRender) { diff --git a/openfl/_internal/renderer/cairo/CairoShape.hx b/openfl/_internal/renderer/cairo/CairoShape.hx index 7e8a543bd2..aebda5da5d 100644 --- a/openfl/_internal/renderer/cairo/CairoShape.hx +++ b/openfl/_internal/renderer/cairo/CairoShape.hx @@ -33,7 +33,7 @@ class CairoShape { //context.globalAlpha = shape.__worldAlpha; var transform = shape.__worldTransform; - // + //if (renderSession.roundPixels) { // //context.setTransform (transform.a, transform.b, transform.c, transform.d, Std.int (transform.tx), Std.int (transform.ty)); @@ -44,9 +44,10 @@ class CairoShape { // //} + cairo.identityMatrix (); cairo.transform (@:privateAccess (shape.__worldTransform).__toMatrix3 ()); cairo.setSourceSurface (graphics.__cairo.target, graphics.__bounds.x, graphics.__bounds.y); - cairo.paint (); + cairo.paintWithAlpha (shape.__worldAlpha); // //if (scrollRect == null) { diff --git a/openfl/display/DisplayObjectContainer.hx b/openfl/display/DisplayObjectContainer.hx index 01a1e1ac46..fe96d52f2a 100644 --- a/openfl/display/DisplayObjectContainer.hx +++ b/openfl/display/DisplayObjectContainer.hx @@ -768,6 +768,47 @@ class DisplayObjectContainer extends InteractiveObject { } + @:noCompletion @:dox(hide) public override function __renderCairo (renderSession:RenderSession):Void { + + if (!__renderable || __worldAlpha <= 0) return; + + super.__renderCairo (renderSession); + + //if (scrollRect != null) { + // + //renderSession.maskManager.pushRect (scrollRect, __worldTransform); + // + //} + // + //if (__mask != null) { + // + //renderSession.maskManager.pushMask (__mask); + // + //} + + for (child in __children) { + + child.__renderCairo (renderSession); + + } + + __removedChildren = []; + + //if (__mask != null) { + // + //renderSession.maskManager.popMask (); + // + //} + // + //if (scrollRect != null) { + // + //renderSession.maskManager.popMask (); + // + //} + + } + + @:noCompletion @:dox(hide) public override function __renderCanvas (renderSession:RenderSession):Void { if (!__renderable || __worldAlpha <= 0) return; From 19880ef153ec24a69d641c21da4ebf85c76a92e1 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Sat, 2 May 2015 22:27:55 -0700 Subject: [PATCH 102/150] Surface size fix --- openfl/_internal/renderer/cairo/CairoGraphics.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openfl/_internal/renderer/cairo/CairoGraphics.hx b/openfl/_internal/renderer/cairo/CairoGraphics.hx index 0d5fe647ae..3a8be5ba84 100644 --- a/openfl/_internal/renderer/cairo/CairoGraphics.hx +++ b/openfl/_internal/renderer/cairo/CairoGraphics.hx @@ -546,7 +546,7 @@ class CairoGraphics { if (graphics.__cairo == null) { - var surface = new CairoSurface (ARGB32, Std.int (bounds.width), Std.int (bounds.height)); + var surface = new CairoSurface (ARGB32, Math.ceil (bounds.width), Math.ceil (bounds.height)); graphics.__cairo = new Cairo (surface); surface.destroy (); From a738b3b958e0634163310e9e6dad244febf625a2 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Sun, 3 May 2015 03:19:03 -0700 Subject: [PATCH 103/150] Minor tweak --- openfl/_internal/renderer/cairo/CairoShape.hx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openfl/_internal/renderer/cairo/CairoShape.hx b/openfl/_internal/renderer/cairo/CairoShape.hx index aebda5da5d..2697109451 100644 --- a/openfl/_internal/renderer/cairo/CairoShape.hx +++ b/openfl/_internal/renderer/cairo/CairoShape.hx @@ -5,6 +5,7 @@ import openfl.display.DisplayObject; @:access(openfl.display.DisplayObject) @:access(openfl.display.Graphics) +@:access(openfl.geom.Matrix) class CairoShape { @@ -44,8 +45,7 @@ class CairoShape { // //} - cairo.identityMatrix (); - cairo.transform (@:privateAccess (shape.__worldTransform).__toMatrix3 ()); + cairo.matrix = transform.__toMatrix3 (); cairo.setSourceSurface (graphics.__cairo.target, graphics.__bounds.x, graphics.__bounds.y); cairo.paintWithAlpha (shape.__worldAlpha); From fd9252077eb985fc1950cd6b62bfe89d3e2f39d8 Mon Sep 17 00:00:00 2001 From: Daniel Uranga Date: Mon, 4 May 2015 11:13:43 -0300 Subject: [PATCH 104/150] Made "URLLoadersManager" class private. Added Mutex. --- openfl/_legacy/net/URLLoader.hx | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/openfl/_legacy/net/URLLoader.hx b/openfl/_legacy/net/URLLoader.hx index 9c1e90b0f8..86f6f11978 100644 --- a/openfl/_legacy/net/URLLoader.hx +++ b/openfl/_legacy/net/URLLoader.hx @@ -13,15 +13,22 @@ import openfl.net.URLRequestHeader; import openfl.net.URLVariables; import openfl.utils.ByteArray; import openfl.Lib; +#if cpp import cpp.vm.Thread; +import cpp.vm.Mutex; +#elseif neko +import neko.vm.Thread; +import neko.vm.Mutex; +#end -class URLLoadersManager { +private class URLLoadersManager { static var instance : URLLoadersManager; var managersThread : Thread; var activeLoaders : List; var loadsQueue : Array<{loader : URLLoader, request : URLRequest}>; + var loadsQueueMutex : Mutex; public static function getInstance() : URLLoadersManager { if (instance==null) { @@ -33,6 +40,7 @@ class URLLoadersManager { function new() { activeLoaders = new List(); loadsQueue = []; + loadsQueueMutex = new Mutex(); managersThread = Thread.create(mainLoop); } @@ -40,7 +48,9 @@ class URLLoadersManager { while (true) { + loadsQueueMutex.acquire(); var loadCall = loadsQueue.shift(); + loadsQueueMutex.release(); if (loadCall!=null) { loadCall.loader.loadInCURLThread(loadCall.request); } @@ -63,7 +73,9 @@ class URLLoadersManager { } // mainLoop public function enqueueLoad(loader : URLLoader, request : URLRequest) { + loadsQueueMutex.acquire(); loadsQueue.push({loader : loader, request : request}); + loadsQueueMutex.release(); } public function activeLoadersIsEmpty() { From b665260244733fecbc0e7b98cde33a8d1f80884e Mon Sep 17 00:00:00 2001 From: Daniel Uranga Date: Mon, 4 May 2015 11:26:01 -0300 Subject: [PATCH 105/150] Cleanup, style fix --- openfl/_legacy/net/URLLoader.hx | 276 +++++++++++++++----------------- 1 file changed, 131 insertions(+), 145 deletions(-) diff --git a/openfl/_legacy/net/URLLoader.hx b/openfl/_legacy/net/URLLoader.hx index 86f6f11978..8e3b6a1436 100644 --- a/openfl/_legacy/net/URLLoader.hx +++ b/openfl/_legacy/net/URLLoader.hx @@ -30,39 +30,39 @@ private class URLLoadersManager { var loadsQueue : Array<{loader : URLLoader, request : URLRequest}>; var loadsQueueMutex : Mutex; - public static function getInstance() : URLLoadersManager { + public static function getInstance () : URLLoadersManager { if (instance==null) { - instance = new URLLoadersManager(); + instance = new URLLoadersManager (); } return instance; } - function new() { - activeLoaders = new List(); + function new () { + activeLoaders = new List (); loadsQueue = []; - loadsQueueMutex = new Mutex(); - managersThread = Thread.create(mainLoop); + loadsQueueMutex = new Mutex (); + managersThread = Thread.create (mainLoop); } - function mainLoop() { + function mainLoop () { while (true) { - loadsQueueMutex.acquire(); - var loadCall = loadsQueue.shift(); - loadsQueueMutex.release(); + loadsQueueMutex.acquire (); + var loadCall = loadsQueue.shift (); + loadsQueueMutex.release (); if (loadCall!=null) { - loadCall.loader.loadInCURLThread(loadCall.request); + loadCall.loader.loadInCURLThread (loadCall.request); } - if (!activeLoaders.isEmpty()) { - lime_curl_process_loaders(); + if (!activeLoaders.isEmpty ()) { + lime_curl_process_loaders (); var oldLoaders = activeLoaders; - activeLoaders = new List(); + activeLoaders = new List (); for (loader in oldLoaders) { - loader.update(); + loader.update (); if (loader.state == URLLoader.urlLoading) { - activeLoaders.push(loader); + activeLoaders.push (loader); } } } @@ -72,54 +72,54 @@ private class URLLoadersManager { } // mainLoop - public function enqueueLoad(loader : URLLoader, request : URLRequest) { - loadsQueueMutex.acquire(); - loadsQueue.push({loader : loader, request : request}); - loadsQueueMutex.release(); + public function enqueueLoad (loader : URLLoader, request : URLRequest) { + loadsQueueMutex.acquire (); + loadsQueue.push ({loader : loader, request : request}); + loadsQueueMutex.release (); } public function activeLoadersIsEmpty() { - return activeLoaders.isEmpty(); + return activeLoaders.isEmpty (); } - public function getActiveLoaders() : List { + public function getActiveLoaders () : List { if (Thread.current()!=managersThread) throw "Wrong thread : getActiveLoaders"; return activeLoaders; } - public function create(request : URLRequest) : Dynamic { + public function create (request : URLRequest) : Dynamic { if (Thread.current()!=managersThread) throw "Wrong thread : create"; - return lime_curl_create(request); + return lime_curl_create (request); } - public function updateLoader(handle : Dynamic, loader : URLLoader) : Void { + public function updateLoader (handle : Dynamic, loader : URLLoader) : Void { if (Thread.current()!=managersThread) throw "Wrong thread : updateLoader"; - lime_curl_update_loader(handle, loader); + lime_curl_update_loader (handle, loader); } - public function getCode(handle : Dynamic) : Int { + public function getCode (handle : Dynamic) : Int { if (Thread.current()!=managersThread) throw "Wrong thread : getCode"; - return lime_curl_get_code(handle); + return lime_curl_get_code (handle); } - public function getErrorMessage(handle : Dynamic) : String { + public function getErrorMessage (handle : Dynamic) : String { if (Thread.current()!=managersThread) throw "Wrong thread : getErrorMessage"; - return lime_curl_get_error_message(handle); + return lime_curl_get_error_message (handle); } - public function getData(handle : Dynamic) : ByteArray { + public function getData (handle : Dynamic) : ByteArray { if (Thread.current()!=managersThread) throw "Wrong thread : getData"; - return lime_curl_get_data(handle); + return lime_curl_get_data (handle); } - public function getCookies(handle : Dynamic) : Array { + public function getCookies (handle : Dynamic) : Array { if (Thread.current()!=managersThread) throw "Wrong thread : getCookies"; - return lime_curl_get_cookies(handle); + return lime_curl_get_cookies (handle); } - public function getHeaders(handle : Dynamic) : Array { + public function getHeaders (handle : Dynamic) : Array { if (Thread.current()!=managersThread) throw "Wrong thread : getHeaders"; - return lime_curl_get_headers(handle); + return lime_curl_get_headers (handle); } // Native Methods @@ -136,79 +136,76 @@ private class URLLoadersManager { } class URLLoader extends EventDispatcher { - - + + public var bytesLoaded (default, null):Int; public var bytesTotal (default, null):Int; public var data:Dynamic; public var dataFormat:URLLoaderDataFormat; - - //@:noCompletion private static var activeLoaders = new List (); + @:noCompletion private static inline var urlInvalid = 0; @:noCompletion private static inline var urlInit = 1; - + @:allow(openfl._legacy.net.URLLoadersManager) @:noCompletion private static inline var urlLoading = 2; - + @:noCompletion private static inline var urlComplete = 3; @:noCompletion private static inline var urlError = 4; - + @:allow(openfl._legacy.net.URLLoadersManager) @:noCompletion private var state:Int; - + @:noCompletion private var __handle:Dynamic; @:noCompletion public var __onComplete:Dynamic -> Bool; - - + + public function new (request:URLRequest = null) { - + super (); - + __handle = 0; bytesLoaded = 0; bytesTotal = -1; state = urlInvalid; dataFormat = URLLoaderDataFormat.TEXT; - + if (request != null) { - + load (request); - + } - + } - - + + public function close ():Void { - - - + + + } - - + + private function dispatchHTTPStatus (code:Int):Void { - + var event = new HTTPStatusEvent (HTTPStatusEvent.HTTP_STATUS, false, false, code); - //var headers:Array = lime_curl_get_headers (__handle); var headers = URLLoadersManager.getInstance().getHeaders(__handle); - + for (header in headers) { - + var index = header.indexOf(": "); if (index > 0) { - + event.responseHeaders.push (new URLRequestHeader (header.substr (0, index), header.substr (index + 2, header.length - index - 4))); - + } - + } - - //dispatchEvent (event); + enqueueEvent(this, event); - + } - - + + public function getCookies ():Array { trace("GET COOKIES"); return []; @@ -216,95 +213,93 @@ class URLLoader extends EventDispatcher { return lime_curl_get_cookies (__handle); */ } - - + + public static function hasActive ():Bool { - + return !URLLoadersManager.getInstance().activeLoadersIsEmpty(); - + } - - + + public static function initialize (caCertFilePath:String):Void { trace("INITIALIZE"); /* lime_curl_initialize (caCertFilePath); */ - + } - - + + public function load (request:URLRequest):Void { - + URLLoadersManager.getInstance().enqueueLoad(this, request); } @:allow(openfl._legacy.net.URLLoadersManager) - function loadInCURLThread(request:URLRequest):Void { + function loadInCURLThread (request:URLRequest):Void { state = urlInit; - + var pref = request.url.substr (0, 7); if (pref != "http://" && pref != "https:/") { - + try { - + var bytes = ByteArray.readFile (request.url); - + if (bytes == null) { - + throw ("Could not open file \"" + request.url + "\""); - + } - + switch (dataFormat) { - + case TEXT: data = bytes.asString (); case VARIABLES: data = new URLVariables(bytes.asString()); default: data = bytes; - + } - + } catch (e:Dynamic) { - + onError (e); return; - + } - + __dataComplete (); - + } else { - + request.__prepare (); - //__handle = lime_curl_create (request); __handle = URLLoadersManager.getInstance().create(request); - + if (__handle == null) { - + onError ("Could not open URL"); - + } else { - + URLLoadersManager.getInstance().getActiveLoaders().push (this); - + } - + } } - - + + private function onError (msg:String):Void { - + URLLoadersManager.getInstance().getActiveLoaders().remove (this); - //dispatchEvent (new IOErrorEvent (IOErrorEvent.IO_ERROR, true, false, msg)); enqueueEvent(this, new IOErrorEvent (IOErrorEvent.IO_ERROR, true, false, msg)); - + } - + @:allow(openfl._legacy.net.URLLoadersManager) private function update():Void { @@ -312,27 +307,22 @@ class URLLoader extends EventDispatcher { var old_loaded = bytesLoaded; var old_total = bytesTotal; - //lime_curl_update_loader (__handle, this); URLLoadersManager.getInstance().updateLoader(__handle, this); if (old_total < 0 && bytesTotal > 0) { - //dispatchEvent (new Event (Event.OPEN)); enqueueEvent(this, new Event (Event.OPEN)); } - + if (bytesTotal > 0 && bytesLoaded != old_loaded) { - //dispatchEvent (new ProgressEvent (ProgressEvent.PROGRESS, false, false, bytesLoaded, bytesTotal)); var evt = new ProgressEvent (ProgressEvent.PROGRESS, false, false, bytesLoaded, bytesTotal); enqueueEvent(this, evt); } - - //var code:Int = lime_curl_get_code (__handle); + var code = URLLoadersManager.getInstance().getCode(__handle); - + if (state == urlComplete) { dispatchHTTPStatus (code); - //var bytes:ByteArray = lime_curl_get_data (__handle); var bytes = URLLoadersManager.getInstance().getData(__handle); switch (dataFormat) { case TEXT, VARIABLES: @@ -342,61 +332,57 @@ class URLLoader extends EventDispatcher { } if (code < 400) { - __dataComplete (); + __dataComplete (); } else { var event = new IOErrorEvent (IOErrorEvent.IO_ERROR, true, false, data, code); __handle = null; - //dispatchEvent (event); enqueueEvent(this, event); } - + } else if (state == urlError) { dispatchHTTPStatus (code); var errorMessage = URLLoadersManager.getInstance().getErrorMessage(__handle); var event = new IOErrorEvent (IOErrorEvent.IO_ERROR, true, false, errorMessage, code); __handle = null; - //dispatchEvent (event); enqueueEvent(this, event); } - + } - + } - - + + @:noCompletion private function __dataComplete ():Void { - + URLLoadersManager.getInstance().getActiveLoaders().remove (this); - + if (__onComplete != null) { - + if (__onComplete (data)) { - - //dispatchEvent (new Event (Event.COMPLETE)); + enqueueEvent(this, new Event (Event.COMPLETE)); - + } else { - + __dispatchIOErrorEvent (); - + } - + } else { - - //dispatchEvent (new Event (Event.COMPLETE)); + enqueueEvent(this, new Event (Event.COMPLETE)); - + } - + } - - + + @:noCompletion public static function __loadPending ():Bool { - + return !URLLoadersManager.getInstance().activeLoadersIsEmpty(); - + } - + static var eventsQueue : Array<{loader : URLLoader, event : Event}> = []; static function enqueueEvent(loader : URLLoader, event : Event) { @@ -415,4 +401,4 @@ class URLLoader extends EventDispatcher { #else typedef URLLoader = openfl.net.URLLoader; -#end \ No newline at end of file +#end From 2d4687c21c65463d8e945c48a4cd9e98f277344d Mon Sep 17 00:00:00 2001 From: Daniel Uranga Date: Mon, 4 May 2015 12:17:25 -0300 Subject: [PATCH 106/150] Added "getCookies" implementation --- openfl/_legacy/net/URLLoader.hx | 48 ++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/openfl/_legacy/net/URLLoader.hx b/openfl/_legacy/net/URLLoader.hx index 8e3b6a1436..b37d28c41e 100644 --- a/openfl/_legacy/net/URLLoader.hx +++ b/openfl/_legacy/net/URLLoader.hx @@ -21,6 +21,11 @@ import neko.vm.Thread; import neko.vm.Mutex; #end +private enum ManagersThreadMessage { + GetCookiesCall (thread : Thread, handle : Dynamic); + GetCookiesResponse (ret : Array); +} + private class URLLoadersManager { static var instance : URLLoadersManager; @@ -67,7 +72,20 @@ private class URLLoadersManager { } } - Sys.sleep(0.05); + var msg = Thread.readMessage(false); + if (msg!=null) { + msg = cast (msg, ManagersThreadMessage); + switch (msg) { + case GetCookiesCall (callerThread, handle): { + var cookies : Array = lime_curl_get_cookies (handle); + callerThread.sendMessage (GetCookiesResponse (cookies)); + } + default: {} + } + } + + Sys.sleep(0.1); + } } // mainLoop @@ -112,16 +130,24 @@ private class URLLoadersManager { return lime_curl_get_data (handle); } - public function getCookies (handle : Dynamic) : Array { - if (Thread.current()!=managersThread) throw "Wrong thread : getCookies"; - return lime_curl_get_cookies (handle); - } - public function getHeaders (handle : Dynamic) : Array { if (Thread.current()!=managersThread) throw "Wrong thread : getHeaders"; return lime_curl_get_headers (handle); } + public function getCookies (handle : Dynamic) : Array { + managersThread.sendMessage (GetCookiesCall (Thread.current(), handle)); + var msg : ManagersThreadMessage = Thread.readMessage(true); + switch (msg) { + case (GetCookiesResponse (result)): { + return result; + } + default: { + return []; + } + } + } + // Native Methods private static var lime_curl_create = Lib.load ("lime-legacy", "lime_legacy_curl_create", 1); private static var lime_curl_process_loaders = Lib.load ("lime-legacy", "lime_legacy_curl_process_loaders", 0); @@ -207,17 +233,13 @@ class URLLoader extends EventDispatcher { public function getCookies ():Array { - trace("GET COOKIES"); - return []; - /* - return lime_curl_get_cookies (__handle); - */ + return URLLoadersManager.getInstance().getCookies (__handle); } public static function hasActive ():Bool { - return !URLLoadersManager.getInstance().activeLoadersIsEmpty(); + return !URLLoadersManager.getInstance().activeLoadersIsEmpty (); } @@ -301,7 +323,7 @@ class URLLoader extends EventDispatcher { } @:allow(openfl._legacy.net.URLLoadersManager) - private function update():Void { + private function update ():Void { if (__handle != null) { From 9bda60effb60173048c1f8a200bd1d28b208ffe4 Mon Sep 17 00:00:00 2001 From: Daniel Uranga Date: Mon, 4 May 2015 12:53:29 -0300 Subject: [PATCH 107/150] Added "initialize" implementation --- openfl/_legacy/net/URLLoader.hx | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/openfl/_legacy/net/URLLoader.hx b/openfl/_legacy/net/URLLoader.hx index b37d28c41e..ce2f8d13e2 100644 --- a/openfl/_legacy/net/URLLoader.hx +++ b/openfl/_legacy/net/URLLoader.hx @@ -22,8 +22,9 @@ import neko.vm.Mutex; #end private enum ManagersThreadMessage { - GetCookiesCall (thread : Thread, handle : Dynamic); + GetCookiesCall (callerThread : Thread, handle : Dynamic); GetCookiesResponse (ret : Array); + InitializeCall (caCertFilePath : String); } private class URLLoadersManager { @@ -80,6 +81,9 @@ private class URLLoadersManager { var cookies : Array = lime_curl_get_cookies (handle); callerThread.sendMessage (GetCookiesResponse (cookies)); } + case InitializeCall (caCertFilePath): { + lime_curl_initialize (caCertFilePath); + } default: {} } } @@ -135,6 +139,11 @@ private class URLLoadersManager { return lime_curl_get_headers (handle); } + public function initialize (caCertFilePath : String) : Void { + managersThread.sendMessage (InitializeCall (caCertFilePath)); + return; + } + public function getCookies (handle : Dynamic) : Array { managersThread.sendMessage (GetCookiesCall (Thread.current(), handle)); var msg : ManagersThreadMessage = Thread.readMessage(true); @@ -245,10 +254,8 @@ class URLLoader extends EventDispatcher { public static function initialize (caCertFilePath:String):Void { - trace("INITIALIZE"); - /* - lime_curl_initialize (caCertFilePath); - */ + + URLLoadersManager.getInstance().initialize (caCertFilePath); } From a6c6f25af9e191c4c2d41f71fc8963164e01687f Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Mon, 4 May 2015 16:14:42 -0700 Subject: [PATCH 108/150] More work on Cairo renderer --- openfl/_internal/renderer/cairo/CairoShape.hx | 22 +++++++------ openfl/display/Bitmap.hx | 8 +++++ openfl/display/BitmapData.hx | 33 +++++++++++++++++++ 3 files changed, 53 insertions(+), 10 deletions(-) diff --git a/openfl/_internal/renderer/cairo/CairoShape.hx b/openfl/_internal/renderer/cairo/CairoShape.hx index 2697109451..8e2505c2bf 100644 --- a/openfl/_internal/renderer/cairo/CairoShape.hx +++ b/openfl/_internal/renderer/cairo/CairoShape.hx @@ -35,17 +35,19 @@ class CairoShape { //context.globalAlpha = shape.__worldAlpha; var transform = shape.__worldTransform; - //if (renderSession.roundPixels) { - // - //context.setTransform (transform.a, transform.b, transform.c, transform.d, Std.int (transform.tx), Std.int (transform.ty)); - // - //} else { - // - //context.setTransform (transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); - // - //} + if (renderSession.roundPixels) { + + var matrix = transform.__toMatrix3 (); + matrix.tx = Math.round (matrix.tx); + matrix.ty = Math.round (matrix.ty); + cairo.matrix = matrix; + + } else { + + cairo.matrix = transform.__toMatrix3 (); + + } - cairo.matrix = transform.__toMatrix3 (); cairo.setSourceSurface (graphics.__cairo.target, graphics.__bounds.x, graphics.__bounds.y); cairo.paintWithAlpha (shape.__worldAlpha); diff --git a/openfl/display/Bitmap.hx b/openfl/display/Bitmap.hx index 03548f11d2..a824563214 100644 --- a/openfl/display/Bitmap.hx +++ b/openfl/display/Bitmap.hx @@ -1,6 +1,7 @@ package openfl.display; #if !flash #if !openfl_legacy +import openfl._internal.renderer.cairo.CairoBitmap; import openfl._internal.renderer.canvas.CanvasBitmap; import openfl._internal.renderer.dom.DOMBitmap; import openfl._internal.renderer.opengl.GLBitmap; @@ -145,6 +146,13 @@ class Bitmap extends DisplayObjectContainer { } + @:noCompletion @:dox(hide) public override function __renderCairo (renderSession:RenderSession):Void { + + CairoBitmap.render (this, renderSession); + + } + + @:noCompletion @:dox(hide) public override function __renderCanvas (renderSession:RenderSession):Void { CanvasBitmap.render (this, renderSession); diff --git a/openfl/display/BitmapData.hx b/openfl/display/BitmapData.hx index 70a5dd0703..20146cc219 100644 --- a/openfl/display/BitmapData.hx +++ b/openfl/display/BitmapData.hx @@ -1,6 +1,7 @@ package openfl.display; #if !flash #if !openfl_legacy +import lime.graphics.cairo.CairoSurface; import lime.graphics.ImageChannel; import lime.graphics.opengl.GLBuffer; import lime.graphics.opengl.GLTexture; @@ -139,6 +140,8 @@ class BitmapData implements IBitmapDrawable { @:noCompletion private var __buffer:GLBuffer; @:noCompletion private var __image:Image; @:noCompletion private var __isValid:Bool; + @:noCompletion private var __surface:CairoSurface; + @:noCompletion private var __surfaceImage:Image; @:noCompletion private var __texture:GLTexture; @:noCompletion private var __textureImage:Image; @:noCompletion private var __framebuffer:FilterTexture; @@ -880,6 +883,36 @@ class BitmapData implements IBitmapDrawable { } + public function getSurface ():CairoSurface { + + if (!__isValid) return null; + + if (__surface == null) { + + __image.dirty = true; + + } + + if (__image != null && __image.dirty) { + + if (__surface != null) { + + __surface.destroy (); + + } + + __surfaceImage = __image.clone (); + __surfaceImage.format = BGRA; + __surface = CairoSurface.fromImage (__surfaceImage); + __image.dirty = false; + + } + + return __surface; + + } + + public function getTexture (gl:GLRenderContext):GLTexture { if (!__isValid) return null; From 0ba2942f66f36331ec1360f567b4e324c3489c43 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Mon, 4 May 2015 20:45:54 -0700 Subject: [PATCH 109/150] Improve Cairo render --- .../_internal/renderer/cairo/CairoGraphics.hx | 52 +++++++++++-------- openfl/display/BitmapData.hx | 1 + 2 files changed, 31 insertions(+), 22 deletions(-) diff --git a/openfl/_internal/renderer/cairo/CairoGraphics.hx b/openfl/_internal/renderer/cairo/CairoGraphics.hx index 3a8be5ba84..2dc5f2bd65 100644 --- a/openfl/_internal/renderer/cairo/CairoGraphics.hx +++ b/openfl/_internal/renderer/cairo/CairoGraphics.hx @@ -265,9 +265,9 @@ class CairoGraphics { if (stroke && hasStroke) { - //context.closePath (); - //context.stroke (); - //context.beginPath (); + cairo.closePath (); + cairo.strokePreserve (); + cairo.newPath (); } @@ -279,28 +279,36 @@ class CairoGraphics { } else { - //context.lineWidth = thickness; - // - //context.lineJoin = (joints == null ? "round" : Std.string (joints).toLowerCase ()); - //context.lineCap = (caps == null ? "round" : switch (caps) { - //case CapsStyle.NONE: "butt"; - //default: Std.string (caps).toLowerCase (); - //}); - // - //context.miterLimit = (miterLimit == null ? 3 : miterLimit); - // + cairo.lineWidth = thickness; + + cairo.lineJoin = switch (joints) { + case MITER: MITER; + case BEVEL: BEVEL; + default: ROUND; + } + + cairo.lineCap = switch (caps) { + case ROUND: ROUND; + case SQUARE: SQUARE; + default: BUTT; + } + + cairo.miterLimit = (miterLimit == null ? 3 : miterLimit); + //if (alpha == 1 || alpha == null) { // //context.strokeStyle = (color == null ? "#000000" : "#" + StringTools.hex (color & 0x00FFFFFF, 6)); // //} else { - // - //var r = (color & 0xFF0000) >>> 16; - //var g = (color & 0x00FF00) >>> 8; - //var b = (color & 0x0000FF); - // + + var r = (color & 0xFF0000) >>> 16; + var g = (color & 0x00FF00) >>> 8; + var b = (color & 0x0000FF); + + cairo.setSourceRGBA (r / 0xFF, g / 0xFF, b / 0xFF, alpha); + //context.strokeStyle = (color == null ? "#000000" : "rgba(" + r + ", " + g + ", " + b + ", " + alpha + ")"); - // + //} hasStroke = true; @@ -474,7 +482,7 @@ class CairoGraphics { } - cairo.stroke (); + cairo.strokePreserve (); } @@ -493,12 +501,12 @@ class CairoGraphics { if (pendingMatrix != null) { cairo.transform (pendingMatrix.__toMatrix3 ()); - cairo.fill (); + cairo.fillPreserve (); cairo.transform (inversePendingMatrix.__toMatrix3 ()); } else { - cairo.fill (); + cairo.fillPreserve (); } diff --git a/openfl/display/BitmapData.hx b/openfl/display/BitmapData.hx index 20146cc219..bbb789e92a 100644 --- a/openfl/display/BitmapData.hx +++ b/openfl/display/BitmapData.hx @@ -903,6 +903,7 @@ class BitmapData implements IBitmapDrawable { __surfaceImage = __image.clone (); __surfaceImage.format = BGRA; + __surfaceImage.premultiplied = true; __surface = CairoSurface.fromImage (__surfaceImage); __image.dirty = false; From f998b991fb36bb8f1fc3eaa5373cfdba1fee6ddb Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Mon, 4 May 2015 21:04:43 -0700 Subject: [PATCH 110/150] Add missing Bitmap class --- .../_internal/renderer/cairo/CairoBitmap.hx | 108 ++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 openfl/_internal/renderer/cairo/CairoBitmap.hx diff --git a/openfl/_internal/renderer/cairo/CairoBitmap.hx b/openfl/_internal/renderer/cairo/CairoBitmap.hx new file mode 100644 index 0000000000..8d2a4cefe5 --- /dev/null +++ b/openfl/_internal/renderer/cairo/CairoBitmap.hx @@ -0,0 +1,108 @@ +package openfl._internal.renderer.cairo; + + +#if cpp +import cpp.Pointer; +#end +import lime.graphics.cairo.CairoFormat; +import lime.graphics.cairo.CairoSurface; +import openfl._internal.renderer.RenderSession; +import openfl.display.Bitmap; + +@:access(lime.graphics.ImageBuffer) +@:access(openfl.display.Bitmap) +@:access(openfl.display.BitmapData) +@:access(openfl.geom.Matrix) + + +class CairoBitmap { + + + public static inline function render (bitmap:Bitmap, renderSession:RenderSession):Void { + + if (!bitmap.__renderable || bitmap.__worldAlpha <= 0) return; + + //var context = renderSession.context; + var cairo = renderSession.cairo; + + if (bitmap.bitmapData != null && bitmap.bitmapData.__isValid) { + + //if (bitmap.__mask != null) { + // + //renderSession.maskManager.pushMask (bitmap.__mask); + // + //} + + //bitmap.bitmapData.__sync (); + + //context.globalAlpha = bitmap.__worldAlpha; + var transform = bitmap.__worldTransform; + //var scrollRect = bitmap.scrollRect; + + if (renderSession.roundPixels) { + + var matrix = transform.__toMatrix3 (); + matrix.tx = Math.round (matrix.tx); + matrix.ty = Math.round (matrix.ty); + cairo.matrix = matrix; + //context.setTransform (transform.a, transform.b, transform.c, transform.d, Std.int (transform.tx), Std.int (transform.ty)); + + } else { + + cairo.matrix = transform.__toMatrix3 (); + //context.setTransform (transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); + + } + + //if (!bitmap.smoothing) { + // + //untyped (context).mozImageSmoothingEnabled = false; + //untyped (context).webkitImageSmoothingEnabled = false; + //untyped (context).imageSmoothingEnabled = false; + // + //} + + var surface = bitmap.bitmapData.getSurface (); + + if (surface != null) { + + //if (scrollRect == null) { + + //cairo.setSourceRGB (1, 0, 0); + //cairo.newPath (); + //trace (image.width); + //cairo.rectangle (0, 0, image.width, image.height); + cairo.setSourceSurface (surface, 0, 0); + cairo.paintWithAlpha (bitmap.__worldAlpha); + //cairo.paintWithAlpha (bitmap.__worldAlpha); + + //context.drawImage (bitmap.bitmapData.__image.src, 0, 0); + + //} else { + // + //context.drawImage (bitmap.bitmapData.__image.src, scrollRect.x, scrollRect.y, scrollRect.width, scrollRect.height, scrollRect.x, scrollRect.y, scrollRect.width, scrollRect.height); + // + //} + + } + + //if (!bitmap.smoothing) { + // + //untyped (context).mozImageSmoothingEnabled = true; + //untyped (context).webkitImageSmoothingEnabled = true; + //untyped (context).imageSmoothingEnabled = true; + // + //} + + //if (bitmap.__mask != null) { + // + //renderSession.maskManager.popMask (); + // + //} + + } + + } + + +} \ No newline at end of file From 458819dd2f1ff7563bd8ca18ca839fb5d3eca1e3 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Mon, 4 May 2015 21:18:04 -0700 Subject: [PATCH 111/150] Minor tweak --- openfl/_internal/renderer/cairo/CairoBitmap.hx | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/openfl/_internal/renderer/cairo/CairoBitmap.hx b/openfl/_internal/renderer/cairo/CairoBitmap.hx index 8d2a4cefe5..1e59d6125b 100644 --- a/openfl/_internal/renderer/cairo/CairoBitmap.hx +++ b/openfl/_internal/renderer/cairo/CairoBitmap.hx @@ -73,8 +73,16 @@ class CairoBitmap { //trace (image.width); //cairo.rectangle (0, 0, image.width, image.height); cairo.setSourceSurface (surface, 0, 0); - cairo.paintWithAlpha (bitmap.__worldAlpha); - //cairo.paintWithAlpha (bitmap.__worldAlpha); + + if (bitmap.__worldAlpha == 1) { + + cairo.paint (); + + } else { + + cairo.paintWithAlpha (bitmap.__worldAlpha); + + } //context.drawImage (bitmap.bitmapData.__image.src, 0, 0); From c0209954ad497641467640ad9b45e36706c37b2d Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Tue, 5 May 2015 22:38:55 -0700 Subject: [PATCH 112/150] More work on Cairo graphics drawing --- .../_internal/renderer/cairo/CairoGraphics.hx | 790 ++++++++++-------- 1 file changed, 430 insertions(+), 360 deletions(-) diff --git a/openfl/_internal/renderer/cairo/CairoGraphics.hx b/openfl/_internal/renderer/cairo/CairoGraphics.hx index 2dc5f2bd65..4edc765d41 100644 --- a/openfl/_internal/renderer/cairo/CairoGraphics.hx +++ b/openfl/_internal/renderer/cairo/CairoGraphics.hx @@ -2,6 +2,8 @@ package openfl._internal.renderer.cairo; import lime.graphics.cairo.Cairo; +import lime.graphics.cairo.CairoExtend; +import lime.graphics.cairo.CairoPattern; import lime.graphics.cairo.CairoSurface; import lime.math.Matrix3; import openfl._internal.renderer.RenderSession; @@ -37,30 +39,55 @@ class CairoGraphics { private static var hasFill:Bool; private static var hasStroke:Bool; private static var inversePendingMatrix:Matrix; + private static var pattern:CairoPattern; private static var pendingMatrix:Matrix; private static var strokeCommands:Array; private static function beginPatternFill (bitmapFill:BitmapData, bitmapRepeat:Bool):Void { - //#if (js && html5) - //if (hasFill || bitmapFill == null) return; - // - //if (pattern == null) { - // - //pattern = context.createPattern (bitmapFill.__image.src, bitmapRepeat ? "repeat" : "no-repeat"); - // - //} - // - //context.fillStyle = pattern; - //hasFill = true; - //#end + if (hasFill || bitmapFill == null) return; + + if (pattern == null) { + + pattern = CairoPattern.createForSurface (bitmapFill.getSurface ()); + + if (bitmapRepeat) { + + pattern.extend = CairoExtend.REPEAT; + + } + + } + + cairo.source = pattern; + hasFill = true; } private static function createTempPatternCanvas (bitmap:BitmapData, repeat:Bool, width:Int, height:Int) { + var surface = new CairoSurface (ARGB32, width, height); + var pattern = CairoPattern.createForSurface (surface); + + if (repeat) { + + pattern.extend = REPEAT; + + } + + cairo.source = pattern; + cairo.newPath (); + cairo.moveTo (0, 0); + cairo.lineTo (0, height); + cairo.lineTo (width, height); + cairo.lineTo (width, 0); + cairo.lineTo (0, 0); + cairo.closePath (); + cairo.fill (); + return surface; + // TODO: Don't create extra canvas elements like this //#if (js && html5) @@ -98,6 +125,7 @@ class CairoGraphics { cairo.newPath (); playCommands (strokeCommands, true); + cairo.closePath (); strokeCommands = []; } @@ -209,7 +237,7 @@ class CairoGraphics { case CubicCurveTo (cx1, cy1, cx2, cy2, x, y): - //context.bezierCurveTo (cx1 - offsetX, cy1 - offsetY, cx2 - offsetX, cy2 - offsetY, x - offsetX, y - offsetY); + cairo.curveTo (cx1 - offsetX, cy1 - offsetY, cx2 - offsetX, cy2 - offsetY, x - offsetX, y - offsetY); case CurveTo (cx, cy, x, y): @@ -222,22 +250,22 @@ class CairoGraphics { case DrawEllipse (x, y, width, height): - //x -= offsetX; - //y -= offsetY; - // - //var kappa = .5522848, - //ox = (width / 2) * kappa, // control point offset horizontal - //oy = (height / 2) * kappa, // control point offset vertical - //xe = x + width, // x-end - //ye = y + height, // y-end - //xm = x + width / 2, // x-middle - //ym = y + height / 2; // y-middle - // - //context.moveTo (x, ym); - //context.bezierCurveTo (x, ym - oy, xm - ox, y, xm, y); - //context.bezierCurveTo (xm + ox, y, xe, ym - oy, xe, ym); - //context.bezierCurveTo (xe, ym + oy, xm + ox, ye, xm, ye); - //context.bezierCurveTo (xm - ox, ye, x, ym + oy, x, ym); + x -= offsetX; + y -= offsetY; + + var kappa = .5522848, + ox = (width / 2) * kappa, // control point offset horizontal + oy = (height / 2) * kappa, // control point offset vertical + xe = x + width, // x-end + ye = y + height, // y-end + xm = x + width / 2, // x-middle + ym = y + height / 2; // y-middle + + cairo.moveTo (x, ym); + cairo.curveTo (x, ym - oy, xm - ox, y, xm, y); + cairo.curveTo (xm + ox, y, xe, ym - oy, xe, ym); + cairo.curveTo (xe, ym + oy, xm + ox, ye, xm, ye); + cairo.curveTo (xm - ox, ye, x, ym + oy, x, ym); case DrawRoundRect (x, y, width, height, rx, ry): @@ -281,16 +309,32 @@ class CairoGraphics { cairo.lineWidth = thickness; - cairo.lineJoin = switch (joints) { - case MITER: MITER; - case BEVEL: BEVEL; - default: ROUND; + if (joints == null) { + + cairo.lineJoin = ROUND; + + } else { + + cairo.lineJoin = switch (joints) { + case MITER: MITER; + case BEVEL: BEVEL; + default: ROUND; + } + } - cairo.lineCap = switch (caps) { - case ROUND: ROUND; - case SQUARE: SQUARE; - default: BUTT; + if (caps == null) { + + cairo.lineCap = BUTT; + + } else { + + cairo.lineCap = switch (caps) { + case ROUND: ROUND; + case SQUARE: SQUARE; + default: BUTT; + } + } cairo.miterLimit = (miterLimit == null ? 3 : miterLimit); @@ -321,10 +365,10 @@ class CairoGraphics { bitmapFill = bitmap; bitmapRepeat = repeat; - //pattern = null; + pattern = null; hasFill = false; - bitmap.__sync (); + //bitmap.__sync (); } @@ -416,56 +460,64 @@ class CairoGraphics { case DrawRect (x, y, width, height): - var optimizationUsed = false; - - if (bitmapFill != null) { - - var st:Float = 0; - var sr:Float = 0; - var sb:Float = 0; - var sl:Float = 0; - - var canOptimizeMatrix = true; + //var optimizationUsed = false; + // + //if (bitmapFill != null) { + // + //var st:Float = 0; + //var sr:Float = 0; + //var sb:Float = 0; + //var sl:Float = 0; + // + //var canOptimizeMatrix = true; + // + //if (pendingMatrix != null) { + // + //if (pendingMatrix.b != 0 || pendingMatrix.c != 0) { + // + //canOptimizeMatrix = false; + // + //} else { + // + //var stl = inversePendingMatrix.transformPoint (new Point (x, y)); + //var sbr = inversePendingMatrix.transformPoint (new Point (x + width, y + height)); + // + //st = stl.y; + //sl = stl.x; + //sb = sbr.y; + //sr = sbr.x; + // + //} + // + //} else { + // + //st = y; + //sl = x; + //sb = y + height; + //sr = x + width; + // + //} + // + //if (canOptimizeMatrix && st >= 0 && sl >= 0 && sr <= bitmapFill.width && sb <= bitmapFill.height) { + // + //optimizationUsed = true; + ////context.drawImage (bitmapFill.__image.src, sl, st, sr - sl, sb - st, x - offsetX, y - offsetY, width, height); + //} + //} + // + //if (!optimizationUsed) { - if (pendingMatrix != null) { - - if (pendingMatrix.b != 0 || pendingMatrix.c != 0) { - - canOptimizeMatrix = false; - - } else { - - var stl = inversePendingMatrix.transformPoint (new Point (x, y)); - var sbr = inversePendingMatrix.transformPoint (new Point (x + width, y + height)); - - st = stl.y; - sl = stl.x; - sb = sbr.y; - sr = sbr.x; - - } - - } else { - - st = y; - sl = x; - sb = y + height; - sr = x + width; + if (pattern != null) { - } - - if (canOptimizeMatrix && st >= 0 && sl >= 0 && sr <= bitmapFill.width && sb <= bitmapFill.height) { + var matrix = pattern.matrix; + matrix.translate (x, y); + pattern.matrix = matrix; - optimizationUsed = true; - //context.drawImage (bitmapFill.__image.src, sl, st, sr - sl, sb - st, x - offsetX, y - offsetY, width, height); } - } - - if (!optimizationUsed) { cairo.rectangle (x - offsetX, y - offsetY, width, height); - } + //} default: @@ -608,288 +660,306 @@ class CairoGraphics { fillCommands.push (command); strokeCommands.push (command); - //case DrawTriangles (vertices, indices, uvtData, culling, _, _): - // - //endFill (); - //endStroke (); - // - //var v = vertices; - //var ind = indices; - //var uvt = uvtData; - //var pattern:CanvasElement = null; - //var colorFill = bitmapFill == null; - // - //if (colorFill && uvt != null) { - // - //// Flash doesn't draw anything if the fill isn't a bitmap and there are uvt values - //break; - // - //} - // - //if (!colorFill) { - // - ////TODO move this to Graphics? - // - //if (uvtData == null) { - // - //uvtData = new Vector (); - // - //for (i in 0...(Std.int (v.length / 2))) { - // - //uvtData.push (v[i * 2] / bitmapFill.width); - //uvtData.push (v[i * 2 + 1] / bitmapFill.height); - // - //} - // - //} - // - //var skipT = uvtData.length != v.length; - //var normalizedUVT = normalizeUVT (uvtData, skipT); - //var maxUVT = normalizedUVT.max; - //uvt = normalizedUVT.uvt; - // - //if (maxUVT > 1) { - // - //pattern = createTempPatternCanvas (bitmapFill, bitmapRepeat, Std.int (bounds.width), Std.int (bounds.height)); - // - //} else { - // - //pattern = createTempPatternCanvas (bitmapFill, bitmapRepeat, bitmapFill.width, bitmapFill.height); - // - //} - // - //} - // - //var i = 0; - //var l = ind.length; - // - //var a:Int, b:Int, c:Int; - //var iax:Int, iay:Int, ibx:Int, iby:Int, icx:Int, icy:Int; - //var x1:Float, y1:Float, x2:Float, y2:Float, x3:Float, y3:Float; - //var uvx1:Float, uvy1:Float, uvx2:Float, uvy2:Float, uvx3:Float, uvy3:Float; - //var denom:Float; - //var t1:Float, t2:Float, t3:Float, t4:Float; - //var dx:Float, dy:Float; - // - //while (i < l) { - // - //a = i; - //b = i + 1; - //c = i + 2; - // - //iax = ind[a] * 2; - //iay = ind[a] * 2 + 1; - //ibx = ind[b] * 2; - //iby = ind[b] * 2 + 1; - //icx = ind[c] * 2; - //icy = ind[c] * 2 + 1; - // - //x1 = v[iax]; - //y1 = v[iay]; - //x2 = v[ibx]; - //y2 = v[iby]; - //x3 = v[icx]; - //y3 = v[icy]; - // - //switch (culling) { - // - //case POSITIVE: - // - //if (!isCCW (x1, y1, x2, y2, x3, y3)) { - // - //i += 3; - //continue; - // - //} - // - //case NEGATIVE: - // - //if (isCCW (x1, y1, x2, y2, x3, y3)) { - // - //i += 3; - //continue; - // - //} - // - //default: - // - //} - // - //if (colorFill) { - // - //context.beginPath (); - //context.moveTo (x1, y1); - //context.lineTo (x2, y2); - //context.lineTo (x3, y3); - //context.closePath (); - //context.fill (); - //i += 3; - //continue; - // - //} - // - //context.save (); - //context.beginPath (); - //context.moveTo (x1, y1); - //context.lineTo (x2, y2); - //context.lineTo (x3, y3); - //context.closePath (); - // - //context.clip (); - // - //uvx1 = uvt[iax] * pattern.width; - //uvx2 = uvt[ibx] * pattern.width; - //uvx3 = uvt[icx] * pattern.width; - //uvy1 = uvt[iay] * pattern.height; - //uvy2 = uvt[iby] * pattern.height; - //uvy3 = uvt[icy] * pattern.height; - // - //denom = uvx1 * (uvy3 - uvy2) - uvx2 * uvy3 + uvx3 * uvy2 + (uvx2 - uvx3) * uvy1; - // - //if (denom == 0) { - // - //i += 3; - //continue; - // - //} - // - //t1 = - (uvy1 * (x3 - x2) - uvy2 * x3 + uvy3 * x2 + (uvy2 - uvy3) * x1) / denom; - //t2 = (uvy2 * y3 + uvy1 * (y2 - y3) - uvy3 * y2 + (uvy3 - uvy2) * y1) / denom; - //t3 = (uvx1 * (x3 - x2) - uvx2 * x3 + uvx3 * x2 + (uvx2 - uvx3) * x1) / denom; - //t4 = - (uvx2 * y3 + uvx1 * (y2 - y3) - uvx3 * y2 + (uvx3 - uvx2) * y1) / denom; - //dx = (uvx1 * (uvy3 * x2 - uvy2 * x3) + uvy1 * (uvx2 * x3 - uvx3 * x2) + (uvx3 * uvy2 - uvx2 * uvy3) * x1) / denom; - //dy = (uvx1 * (uvy3 * y2 - uvy2 * y3) + uvy1 * (uvx2 * y3 - uvx3 * y2) + (uvx3 * uvy2 - uvx2 * uvy3) * y1) / denom; - // - //context.transform (t1, t2, t3, t4, dx, dy); - //context.drawImage (pattern, 0, 0); - //context.restore (); - // - //i += 3; - // - //} - // - //case DrawTiles (sheet, tileData, smooth, flags, count): - // - //var useScale = (flags & Graphics.TILE_SCALE) > 0; - //var useRotation = (flags & Graphics.TILE_ROTATION) > 0; - //var useTransform = (flags & Graphics.TILE_TRANS_2x2) > 0; - //var useRGB = (flags & Graphics.TILE_RGB) > 0; - //var useAlpha = (flags & Graphics.TILE_ALPHA) > 0; - //var useRect = (flags & Graphics.TILE_RECT) > 0; - //var useOrigin = (flags & Graphics.TILE_ORIGIN) > 0; - //var useBlendAdd = (flags & Graphics.TILE_BLEND_ADD) > 0; - // - //if (useTransform) { useScale = false; useRotation = false; } - // - //var scaleIndex = 0; - //var rotationIndex = 0; - //var rgbIndex = 0; - //var alphaIndex = 0; - //var transformIndex = 0; - // - //var numValues = 3; - // - //if (useRect) { numValues = useOrigin ? 8 : 6; } - //if (useScale) { scaleIndex = numValues; numValues ++; } - //if (useRotation) { rotationIndex = numValues; numValues ++; } - //if (useTransform) { transformIndex = numValues; numValues += 4; } - //if (useRGB) { rgbIndex = numValues; numValues += 3; } - //if (useAlpha) { alphaIndex = numValues; numValues ++; } - // - //var totalCount = tileData.length; - //if (count >= 0 && totalCount > count) totalCount = count; - //var itemCount = Std.int (totalCount / numValues); - //var index = 0; - // - //var rect = null; - //var center = null; - //var previousTileID = -1; - // - //var surface:Dynamic; - //sheet.__bitmap.__sync (); - //surface = sheet.__bitmap.__image.src; - // - //if (useBlendAdd) { - // + case DrawTriangles (vertices, indices, uvtData, culling, _, _): + + endFill (); + endStroke (); + + var v = vertices; + var ind = indices; + var uvt = uvtData; + var pattern:CairoSurface = null; + var colorFill = bitmapFill == null; + + if (colorFill && uvt != null) { + + // Flash doesn't draw anything if the fill isn't a bitmap and there are uvt values + break; + + } + + if (!colorFill) { + + //TODO move this to Graphics? + + if (uvtData == null) { + + uvtData = new Vector (); + + for (i in 0...(Std.int (v.length / 2))) { + + uvtData.push (v[i * 2] / bitmapFill.width); + uvtData.push (v[i * 2 + 1] / bitmapFill.height); + + } + + } + + var skipT = uvtData.length != v.length; + var normalizedUVT = normalizeUVT (uvtData, skipT); + var maxUVT = normalizedUVT.max; + uvt = normalizedUVT.uvt; + + if (maxUVT > 1) { + + pattern = createTempPatternCanvas (bitmapFill, bitmapRepeat, Std.int (bounds.width), Std.int (bounds.height)); + + } else { + + pattern = createTempPatternCanvas (bitmapFill, bitmapRepeat, bitmapFill.width, bitmapFill.height); + + } + + } + + var i = 0; + var l = ind.length; + + var a:Int, b:Int, c:Int; + var iax:Int, iay:Int, ibx:Int, iby:Int, icx:Int, icy:Int; + var x1:Float, y1:Float, x2:Float, y2:Float, x3:Float, y3:Float; + var uvx1:Float, uvy1:Float, uvx2:Float, uvy2:Float, uvx3:Float, uvy3:Float; + var denom:Float; + var t1:Float, t2:Float, t3:Float, t4:Float; + var dx:Float, dy:Float; + + while (i < l) { + + a = i; + b = i + 1; + c = i + 2; + + iax = ind[a] * 2; + iay = ind[a] * 2 + 1; + ibx = ind[b] * 2; + iby = ind[b] * 2 + 1; + icx = ind[c] * 2; + icy = ind[c] * 2 + 1; + + x1 = v[iax]; + y1 = v[iay]; + x2 = v[ibx]; + y2 = v[iby]; + x3 = v[icx]; + y3 = v[icy]; + + switch (culling) { + + case POSITIVE: + + if (!isCCW (x1, y1, x2, y2, x3, y3)) { + + i += 3; + continue; + + } + + case NEGATIVE: + + if (isCCW (x1, y1, x2, y2, x3, y3)) { + + i += 3; + continue; + + } + + default: + + } + + if (colorFill) { + + cairo.newPath (); + cairo.moveTo (x1, y1); + cairo.lineTo (x2, y2); + cairo.lineTo (x3, y3); + cairo.closePath (); + cairo.fillPreserve (); + i += 3; + continue; + + } + + cairo.save (); + cairo.newPath (); + cairo.moveTo (x1, y1); + cairo.lineTo (x2, y2); + cairo.lineTo (x3, y3); + cairo.closePath (); + + cairo.clip (); + + uvx1 = uvt[iax] * pattern.width; + uvx2 = uvt[ibx] * pattern.width; + uvx3 = uvt[icx] * pattern.width; + uvy1 = uvt[iay] * pattern.height; + uvy2 = uvt[iby] * pattern.height; + uvy3 = uvt[icy] * pattern.height; + + denom = uvx1 * (uvy3 - uvy2) - uvx2 * uvy3 + uvx3 * uvy2 + (uvx2 - uvx3) * uvy1; + + if (denom == 0) { + + i += 3; + continue; + + } + + t1 = - (uvy1 * (x3 - x2) - uvy2 * x3 + uvy3 * x2 + (uvy2 - uvy3) * x1) / denom; + t2 = (uvy2 * y3 + uvy1 * (y2 - y3) - uvy3 * y2 + (uvy3 - uvy2) * y1) / denom; + t3 = (uvx1 * (x3 - x2) - uvx2 * x3 + uvx3 * x2 + (uvx2 - uvx3) * x1) / denom; + t4 = - (uvx2 * y3 + uvx1 * (y2 - y3) - uvx3 * y2 + (uvx3 - uvx2) * y1) / denom; + dx = (uvx1 * (uvy3 * x2 - uvy2 * x3) + uvy1 * (uvx2 * x3 - uvx3 * x2) + (uvx3 * uvy2 - uvx2 * uvy3) * x1) / denom; + dy = (uvx1 * (uvy3 * y2 - uvy2 * y3) + uvy1 * (uvx2 * y3 - uvx3 * y2) + (uvx3 * uvy2 - uvx2 * uvy3) * y1) / denom; + + var matrix = new Matrix3 (t1, t2, t3, t4, dx, dy); + //cairo.transform (t1, t2, t3, t4, dx, dy); + cairo.transform (matrix); + cairo.setSourceSurface (pattern, 0, 0); + cairo.paint (); + //cairo.drawImage (pattern, 0, 0); + cairo.restore (); + + i += 3; + + } + + case DrawTiles (sheet, tileData, smooth, flags, count): + + return; + + var useScale = (flags & Graphics.TILE_SCALE) > 0; + var useRotation = (flags & Graphics.TILE_ROTATION) > 0; + var useTransform = (flags & Graphics.TILE_TRANS_2x2) > 0; + var useRGB = (flags & Graphics.TILE_RGB) > 0; + var useAlpha = (flags & Graphics.TILE_ALPHA) > 0; + var useRect = (flags & Graphics.TILE_RECT) > 0; + var useOrigin = (flags & Graphics.TILE_ORIGIN) > 0; + var useBlendAdd = (flags & Graphics.TILE_BLEND_ADD) > 0; + + if (useTransform) { useScale = false; useRotation = false; } + + var scaleIndex = 0; + var rotationIndex = 0; + var rgbIndex = 0; + var alphaIndex = 0; + var transformIndex = 0; + + var numValues = 3; + + if (useRect) { numValues = useOrigin ? 8 : 6; } + if (useScale) { scaleIndex = numValues; numValues ++; } + if (useRotation) { rotationIndex = numValues; numValues ++; } + if (useTransform) { transformIndex = numValues; numValues += 4; } + if (useRGB) { rgbIndex = numValues; numValues += 3; } + if (useAlpha) { alphaIndex = numValues; numValues ++; } + + var totalCount = tileData.length; + if (count >= 0 && totalCount > count) totalCount = count; + var itemCount = Std.int (totalCount / numValues); + var index = 0; + + var rect = null; + var center = null; + var previousTileID = -1; + + var surface:Dynamic; + sheet.__bitmap.__sync (); + surface = sheet.__bitmap.getSurface (); + + cairo.setSourceSurface (surface, 0, 0); + + if (useBlendAdd) { + + cairo.operator = ADD; //context.globalCompositeOperation = "lighter"; - // - //} - // - //while (index < totalCount) { - // - //var tileID = (!useRect) ? Std.int (tileData[index + 2]) : -1; - // - //if (!useRect && tileID != previousTileID) { - // - //rect = sheet.__tileRects[tileID]; - //center = sheet.__centerPoints[tileID]; - // - //previousTileID = tileID; - // - //} else if (useRect) { - // - //rect = sheet.__rectTile; - //rect.setTo (tileData[index + 2], tileData[index + 3], tileData[index + 4], tileData[index + 5]); - //center = sheet.__point; - // - //if (useOrigin) { - // - //center.setTo (tileData[index + 6], tileData[index + 7]); - // - //} else { - // - //center.setTo (0, 0); - // - //} - // - //} - // - //if (rect != null && rect.width > 0 && rect.height > 0 && center != null) { - // - //context.save (); - //context.translate (tileData[index], tileData[index + 1]); - // - //if (useRotation) { - // - //context.rotate (tileData[index + rotationIndex]); - // - //} - // - //var scale = 1.0; - // - //if (useScale) { - // - //scale = tileData[index + scaleIndex]; - // - //} - // - //if (useTransform) { - // - //context.transform (tileData[index + transformIndex], tileData[index + transformIndex + 1], tileData[index + transformIndex + 2], tileData[index + transformIndex + 3], 0, 0); - // - //} - // - //if (useAlpha) { - // + + } + + while (index < totalCount) { + + var tileID = (!useRect) ? Std.int (tileData[index + 2]) : -1; + + if (!useRect && tileID != previousTileID) { + + rect = sheet.__tileRects[tileID]; + center = sheet.__centerPoints[tileID]; + + previousTileID = tileID; + + } else if (useRect) { + + rect = sheet.__rectTile; + rect.setTo (tileData[index + 2], tileData[index + 3], tileData[index + 4], tileData[index + 5]); + center = sheet.__point; + + if (useOrigin) { + + center.setTo (tileData[index + 6], tileData[index + 7]); + + } else { + + center.setTo (0, 0); + + } + + } + + if (rect != null && rect.width > 0 && rect.height > 0 && center != null) { + + cairo.save (); + cairo.translate (tileData[index], tileData[index + 1]); + + if (useRotation) { + + //cairo.rotate (tileData[index + rotationIndex]); + + } + + var scale = 1.0; + + if (useScale) { + + scale = tileData[index + scaleIndex]; + + } + + if (useTransform) { + + var matrix = new Matrix3 (tileData[index + transformIndex], tileData[index + transformIndex + 1], tileData[index + transformIndex + 2], tileData[index + transformIndex + 3], 0, 0); + cairo.transform (matrix); + + } + + //cairo.setSourceSurface ( + + if (useAlpha) { + + cairo.paintWithAlpha (tileData[index + alphaIndex]); //context.globalAlpha = tileData[index + alphaIndex]; - // - //} - // + + } else { + + cairo.paint (); + + } + //context.drawImage (surface, rect.x, rect.y, rect.width, rect.height, -center.x * scale, -center.y * scale, rect.width * scale, rect.height * scale); - //context.restore (); - // - //} - // - //index += numValues; - // - //} - // - //if (useBlendAdd) { - // + cairo.restore (); + + } + + index += numValues; + + } + + if (useBlendAdd) { + + cairo.operator = OVER; //context.globalCompositeOperation = "source-over"; - // - //} - // + + } + default: openfl.Lib.notImplemented ("CairoGraphics"); From e2d7dfd44c3298eea796d8ee7dbf2b03db911793 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Wed, 6 May 2015 00:23:20 -0700 Subject: [PATCH 113/150] More work on Graphics --- .../_internal/renderer/cairo/CairoGraphics.hx | 168 +++++++++++------- 1 file changed, 101 insertions(+), 67 deletions(-) diff --git a/openfl/_internal/renderer/cairo/CairoGraphics.hx b/openfl/_internal/renderer/cairo/CairoGraphics.hx index 4edc765d41..16726e393c 100644 --- a/openfl/_internal/renderer/cairo/CairoGraphics.hx +++ b/openfl/_internal/renderer/cairo/CairoGraphics.hx @@ -6,6 +6,7 @@ import lime.graphics.cairo.CairoExtend; import lime.graphics.cairo.CairoPattern; import lime.graphics.cairo.CairoSurface; import lime.math.Matrix3; +import lime.math.Vector2; import openfl._internal.renderer.RenderSession; import openfl.display.BitmapData; import openfl.display.CapsStyle; @@ -35,32 +36,33 @@ class CairoGraphics { private static var bounds:Rectangle; private static var cairo:Cairo; private static var fillCommands:Array; + private static var fillPattern:CairoPattern; private static var graphics:Graphics; private static var hasFill:Bool; private static var hasStroke:Bool; private static var inversePendingMatrix:Matrix; - private static var pattern:CairoPattern; private static var pendingMatrix:Matrix; private static var strokeCommands:Array; + private static var strokePattern:CairoPattern; private static function beginPatternFill (bitmapFill:BitmapData, bitmapRepeat:Bool):Void { if (hasFill || bitmapFill == null) return; - if (pattern == null) { + if (fillPattern == null) { - pattern = CairoPattern.createForSurface (bitmapFill.getSurface ()); + fillPattern = CairoPattern.createForSurface (bitmapFill.getSurface ()); if (bitmapRepeat) { - pattern.extend = CairoExtend.REPEAT; + fillPattern.extend = CairoExtend.REPEAT; } } - cairo.source = pattern; + cairo.source = fillPattern; hasFill = true; } @@ -86,6 +88,7 @@ class CairoGraphics { cairo.lineTo (0, 0); cairo.closePath (); cairo.fill (); + pattern.destroy (); return surface; // TODO: Don't create extra canvas elements like this @@ -133,36 +136,34 @@ class CairoGraphics { private static function drawRoundRect (x:Float, y:Float, width:Float, height:Float, rx:Float, ry:Float):Void { - //#if (js && html5) - //if (ry == -1) ry = rx; - // - //rx *= 0.5; - //ry *= 0.5; - // - //if (rx > width / 2) rx = width / 2; - //if (ry > height / 2) ry = height / 2; - // - //var xe = x + width, - //ye = y + height, - //cx1 = -rx + (rx * SIN45), - //cx2 = -rx + (rx * TAN22), - //cy1 = -ry + (ry * SIN45), - //cy2 = -ry + (ry * TAN22); - // - //context.moveTo (xe, ye - ry); - //context.quadraticCurveTo (xe, ye + cy2, xe + cx1, ye + cy1); - //context.quadraticCurveTo (xe + cx2, ye, xe - rx, ye); - //context.lineTo (x + rx, ye); - //context.quadraticCurveTo (x - cx2, ye, x - cx1, ye + cy1); - //context.quadraticCurveTo (x, ye + cy2, x, ye - ry); - //context.lineTo (x, y + ry); - //context.quadraticCurveTo (x, y - cy2, x - cx1, y - cy1); - //context.quadraticCurveTo (x - cx2, y, x + rx, y); - //context.lineTo (xe - rx, y); - //context.quadraticCurveTo (xe + cx2, y, xe + cx1, y - cy1); - //context.quadraticCurveTo (xe, y - cy2, xe, y + ry); - //context.lineTo (xe, ye - ry); - //#end + if (ry == -1) ry = rx; + + rx *= 0.5; + ry *= 0.5; + + if (rx > width / 2) rx = width / 2; + if (ry > height / 2) ry = height / 2; + + var xe = x + width, + ye = y + height, + cx1 = -rx + (rx * SIN45), + cx2 = -rx + (rx * TAN22), + cy1 = -ry + (ry * SIN45), + cy2 = -ry + (ry * TAN22); + + cairo.moveTo (xe, ye - ry); + quadraticCurveTo (xe, ye + cy2, xe + cx1, ye + cy1); + quadraticCurveTo (xe + cx2, ye, xe - rx, ye); + cairo.lineTo (x + rx, ye); + quadraticCurveTo (x - cx2, ye, x - cx1, ye + cy1); + quadraticCurveTo (x, ye + cy2, x, ye - ry); + cairo.lineTo (x, y + ry); + quadraticCurveTo (x, y - cy2, x - cx1, y - cy1); + quadraticCurveTo (x - cx2, y, x + rx, y); + cairo.lineTo (xe - rx, y); + quadraticCurveTo (xe + cx2, y, xe + cx1, y - cy1); + quadraticCurveTo (xe, y - cy2, xe, y + ry); + cairo.lineTo (xe, ye - ry); } @@ -241,7 +242,7 @@ class CairoGraphics { case CurveTo (cx, cy, x, y): - //context.quadraticCurveTo (cx - offsetX, cy - offsetY, x - offsetX, y - offsetY); + quadraticCurveTo (cx - offsetX, cy - offsetY, x - offsetX, y - offsetY); case DrawCircle (x, y, radius): @@ -269,7 +270,7 @@ class CairoGraphics { case DrawRoundRect (x, y, width, height, rx, ry): - //drawRoundRect (x - offsetX, y - offsetY, width, height, rx, ry); + drawRoundRect (x - offsetX, y - offsetY, width, height, rx, ry); case LineTo (x, y): @@ -294,6 +295,7 @@ class CairoGraphics { if (stroke && hasStroke) { cairo.closePath (); + cairo.source = strokePattern; cairo.strokePreserve (); cairo.newPath (); @@ -339,21 +341,25 @@ class CairoGraphics { cairo.miterLimit = (miterLimit == null ? 3 : miterLimit); - //if (alpha == 1 || alpha == null) { - // - //context.strokeStyle = (color == null ? "#000000" : "#" + StringTools.hex (color & 0x00FFFFFF, 6)); - // - //} else { + if (strokePattern != null) { - var r = (color & 0xFF0000) >>> 16; - var g = (color & 0x00FF00) >>> 8; - var b = (color & 0x0000FF); + strokePattern.destroy (); - cairo.setSourceRGBA (r / 0xFF, g / 0xFF, b / 0xFF, alpha); + } + + var r = ((color & 0xFF0000) >>> 16) / 0xFF; + var g = ((color & 0x00FF00) >>> 8) / 0xFF; + var b = (color & 0x0000FF) / 0xFF; + + if (alpha == 1 || alpha == null) { - //context.strokeStyle = (color == null ? "#000000" : "rgba(" + r + ", " + g + ", " + b + ", " + alpha + ")"); + strokePattern = CairoPattern.createRGB (r, g, b); - //} + } else { + + strokePattern = CairoPattern.createRGBA (r, g, b, alpha); + + } hasStroke = true; @@ -365,7 +371,14 @@ class CairoGraphics { bitmapFill = bitmap; bitmapRepeat = repeat; - pattern = null; + + if (fillPattern != null) { + + fillPattern.destroy (); + + } + + fillPattern = null; hasFill = false; //bitmap.__sync (); @@ -393,22 +406,13 @@ class CairoGraphics { } else { - cairo.setSourceRGBA (((rgb & 0xFF0000) >>> 16) / 0xFF, ((rgb & 0x00FF00) >>> 8) / 0xFF, (rgb & 0x0000FF) / 0xFF, alpha); + if (fillPattern != null) { + + fillPattern.destroy (); + + } - //if (alpha == 1) { - // - ////cairo.setSourceRGB ( - ////context.fillStyle = "#" + StringTools.hex (rgb, 6); - // - //} else { - // - //var r = (rgb & 0xFF0000) >>> 16; - //var g = (rgb & 0x00FF00) >>> 8; - //var b = (rgb & 0x0000FF); - // - ////context.fillStyle = "rgba(" + r + ", " + g + ", " + b + ", " + alpha + ")"; - // - //} + fillPattern = CairoPattern.createRGBA (((rgb & 0xFF0000) >>> 16) / 0xFF, ((rgb & 0x00FF00) >>> 8) / 0xFF, (rgb & 0x0000FF) / 0xFF, alpha); bitmapFill = null; hasFill = true; @@ -507,11 +511,11 @@ class CairoGraphics { // //if (!optimizationUsed) { - if (pattern != null) { + if (fillPattern != null) { - var matrix = pattern.matrix; + var matrix = fillPattern.matrix; matrix.translate (x, y); - pattern.matrix = matrix; + fillPattern.matrix = matrix; } @@ -534,6 +538,7 @@ class CairoGraphics { } + cairo.source = strokePattern; cairo.strokePreserve (); } @@ -546,6 +551,10 @@ class CairoGraphics { beginPatternFill (bitmapFill, bitmapRepeat); + } else { + + cairo.source = fillPattern; + } cairo.translate (-bounds.x, -bounds.y); @@ -573,6 +582,31 @@ class CairoGraphics { } + private static function quadraticCurveTo (cx:Float, cy:Float, x:Float, y:Float):Void { + + var current = null; + + if (!cairo.hasCurrentPoint) { + + cairo.moveTo (cx, cy); + current = new Vector2 (cx, cy); + + } else { + + current = cairo.currentPoint; + + } + + var cx1 = current.x + ((2 / 3) * (cx - current.x)); + var cy1 = current.y + ((2 / 3) * (cy - current.y)); + var cx2 = x + ((2 / 3) * (cx - x)); + var cy2 = y + ((2 / 3) * (cy - y)); + + cairo.curveTo (cx1, cy1, cx2, cy2, x, y); + + } + + public static function render (graphics:Graphics, renderSession:RenderSession):Void { if (graphics.__dirty) { From fc1e9a246385cf4ce7d890b92f3568d492619ed2 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Wed, 6 May 2015 01:02:34 -0700 Subject: [PATCH 114/150] Fix default Cairo line cap, implement gradient --- .../_internal/renderer/cairo/CairoGraphics.hx | 47 +++++++++++++------ 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/openfl/_internal/renderer/cairo/CairoGraphics.hx b/openfl/_internal/renderer/cairo/CairoGraphics.hx index 16726e393c..e40683f7f5 100644 --- a/openfl/_internal/renderer/cairo/CairoGraphics.hx +++ b/openfl/_internal/renderer/cairo/CairoGraphics.hx @@ -318,23 +318,27 @@ class CairoGraphics { } else { cairo.lineJoin = switch (joints) { + case MITER: MITER; case BEVEL: BEVEL; default: ROUND; + } } if (caps == null) { - cairo.lineCap = BUTT; + cairo.lineCap = ROUND; } else { cairo.lineCap = switch (caps) { - case ROUND: ROUND; + + case NONE: BUTT; case SQUARE: SQUARE; - default: BUTT; + default: ROUND; + } } @@ -427,17 +431,30 @@ class CairoGraphics { case RADIAL: - //if (matrix == null) matrix = new Matrix (); - //var point = matrix.transformPoint (new Point (1638.4, 0)); - //gradientFill = context.createRadialGradient (matrix.tx, matrix.ty, 0, matrix.tx, matrix.ty, (point.x - matrix.tx) / 2); + if (matrix == null) matrix = new Matrix (); + var point = matrix.transformPoint (new Point (1638.4, 0)); + + if (fillPattern != null) { + + fillPattern.destroy (); + + } + + fillPattern = CairoPattern.createRadial (matrix.tx, matrix.ty, 0, matrix.tx, matrix.ty, (point.x - matrix.tx) / 2); case LINEAR: - //var matrix = matrix != null ? matrix.clone () : new Matrix (); - //var point1 = matrix.transformPoint (new Point (-819.2, 0)); - //var point2 = matrix.transformPoint (new Point (819.2, 0)); - // - //gradientFill = context.createLinearGradient (point1.x, point1.y, point2.x, point2.y); + var matrix = matrix != null ? matrix.clone () : new Matrix (); + var point1 = matrix.transformPoint (new Point (-819.2, 0)); + var point2 = matrix.transformPoint (new Point (819.2, 0)); + + if (fillPattern != null) { + + fillPattern.destroy (); + + } + + fillPattern = CairoPattern.createLinear (point1.x, point1.y, point2.x, point2.y); } @@ -445,15 +462,15 @@ class CairoGraphics { var rgb = colors[i]; var alpha = alphas[i]; - var r = (rgb & 0xFF0000) >>> 16; - var g = (rgb & 0x00FF00) >>> 8; - var b = (rgb & 0x0000FF); + var r = ((rgb & 0xFF0000) >>> 16) / 0xFF; + var g = ((rgb & 0x00FF00) >>> 8) / 0xFF; + var b = (rgb & 0x0000FF) / 0xFF; var ratio = ratios[i] / 0xFF; if (ratio < 0) ratio = 0; if (ratio > 1) ratio = 1; - //gradientFill.addColorStop (ratio, "rgba(" + r + ", " + g + ", " + b + ", " + alpha + ")"); + fillPattern.addColorStopRGBA (ratio, r, g, b, alpha); } From 8249f1747c1ed5328c9ded54ac87fe91d724d97d Mon Sep 17 00:00:00 2001 From: Jay Sistar Date: Wed, 6 May 2015 15:30:44 -0400 Subject: [PATCH 115/150] Fixing another case where rendering will go wrong if a shader was set --- openfl/display/BitmapData.hx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/openfl/display/BitmapData.hx b/openfl/display/BitmapData.hx index bbb789e92a..4bdaf1b67e 100644 --- a/openfl/display/BitmapData.hx +++ b/openfl/display/BitmapData.hx @@ -1716,7 +1716,10 @@ class BitmapData implements IBitmapDrawable { // enable writing to all the colors and alpha gl.colorMask(true, true, true, true); renderSession.blendModeManager.setBlendMode(BlendMode.NORMAL); - + + // set default shader + renderSession.shaderManager.setShader(renderSession.shaderManager.defaultShader, true); + if (clearBuffer || drawSelf) { __framebuffer.clear(); } From 9576b956c58615acb1e4838bc5dc8dc99fa75d55 Mon Sep 17 00:00:00 2001 From: Daniel Uranga Date: Wed, 6 May 2015 17:41:39 -0300 Subject: [PATCH 116/150] Removed unnecessary tests that were causing crashes with bugged Thread class comparisons --- openfl/_legacy/net/URLLoader.hx | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/openfl/_legacy/net/URLLoader.hx b/openfl/_legacy/net/URLLoader.hx index ce2f8d13e2..0f5e4f911b 100644 --- a/openfl/_legacy/net/URLLoader.hx +++ b/openfl/_legacy/net/URLLoader.hx @@ -105,37 +105,30 @@ private class URLLoadersManager { } public function getActiveLoaders () : List { - if (Thread.current()!=managersThread) throw "Wrong thread : getActiveLoaders"; return activeLoaders; } public function create (request : URLRequest) : Dynamic { - if (Thread.current()!=managersThread) throw "Wrong thread : create"; return lime_curl_create (request); } public function updateLoader (handle : Dynamic, loader : URLLoader) : Void { - if (Thread.current()!=managersThread) throw "Wrong thread : updateLoader"; lime_curl_update_loader (handle, loader); } public function getCode (handle : Dynamic) : Int { - if (Thread.current()!=managersThread) throw "Wrong thread : getCode"; return lime_curl_get_code (handle); } public function getErrorMessage (handle : Dynamic) : String { - if (Thread.current()!=managersThread) throw "Wrong thread : getErrorMessage"; return lime_curl_get_error_message (handle); } public function getData (handle : Dynamic) : ByteArray { - if (Thread.current()!=managersThread) throw "Wrong thread : getData"; return lime_curl_get_data (handle); } public function getHeaders (handle : Dynamic) : Array { - if (Thread.current()!=managersThread) throw "Wrong thread : getHeaders"; return lime_curl_get_headers (handle); } @@ -190,6 +183,8 @@ class URLLoader extends EventDispatcher { @:allow(openfl._legacy.net.URLLoadersManager) @:noCompletion private var state:Int; + @:noCompletion static var eventsQueue : Array<{loader : URLLoader, event : Event}> = []; + @:noCompletion private var __handle:Dynamic; @:noCompletion public var __onComplete:Dynamic -> Bool; @@ -412,8 +407,6 @@ class URLLoader extends EventDispatcher { } - static var eventsQueue : Array<{loader : URLLoader, event : Event}> = []; - static function enqueueEvent(loader : URLLoader, event : Event) { eventsQueue.push({loader : loader, event : event}); } From c3511b121e43ad6b08d077c07aec94a8e7d31366 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Wed, 6 May 2015 16:57:54 -0700 Subject: [PATCH 117/150] Update CairoGraphics.hx --- openfl/_internal/renderer/cairo/CairoGraphics.hx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openfl/_internal/renderer/cairo/CairoGraphics.hx b/openfl/_internal/renderer/cairo/CairoGraphics.hx index e40683f7f5..a409c4bc8c 100644 --- a/openfl/_internal/renderer/cairo/CairoGraphics.hx +++ b/openfl/_internal/renderer/cairo/CairoGraphics.hx @@ -75,7 +75,7 @@ class CairoGraphics { if (repeat) { - pattern.extend = REPEAT; + pattern.extend = CairoExtend.REPEAT; } @@ -1125,4 +1125,4 @@ class CairoGraphics { } -} \ No newline at end of file +} From 8c0b86d29d9fd9497f5cecc6f4ca3048d748a027 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Thu, 7 May 2015 09:48:43 -0700 Subject: [PATCH 118/150] Start on Cairo MaskManager --- .../_internal/renderer/AbstractMaskManager.hx | 45 +++ openfl/_internal/renderer/RenderSession.hx | 3 +- .../_internal/renderer/cairo/CairoBitmap.hx | 20 +- .../_internal/renderer/cairo/CairoGraphics.hx | 158 +++++----- .../renderer/cairo/CairoMaskManager.hx | 66 ++++ .../_internal/renderer/cairo/CairoRenderer.hx | 4 +- openfl/_internal/renderer/cairo/CairoShape.hx | 20 +- .../{MaskManager.hx => CanvasMaskManager.hx} | 16 +- .../renderer/canvas/CanvasRenderer.hx | 2 +- .../_internal/renderer/opengl/GLRenderer.hx | 6 +- .../{MaskManager.hx => GLMaskManager.hx} | 48 ++- .../renderer/opengl/utils/StencilManager.hx | 8 +- openfl/display/Bitmap.hx | 19 +- openfl/display/BitmapData.hx | 289 +++++++++++------- openfl/display/DisplayObject.hx | 28 +- openfl/display/DisplayObjectContainer.hx | 98 +++--- openfl/display/IBitmapDrawable.hx | 4 +- 17 files changed, 537 insertions(+), 297 deletions(-) create mode 100644 openfl/_internal/renderer/AbstractMaskManager.hx create mode 100644 openfl/_internal/renderer/cairo/CairoMaskManager.hx rename openfl/_internal/renderer/canvas/{MaskManager.hx => CanvasMaskManager.hx} (71%) rename openfl/_internal/renderer/opengl/utils/{MaskManager.hx => GLMaskManager.hx} (79%) diff --git a/openfl/_internal/renderer/AbstractMaskManager.hx b/openfl/_internal/renderer/AbstractMaskManager.hx new file mode 100644 index 0000000000..a7087a7380 --- /dev/null +++ b/openfl/_internal/renderer/AbstractMaskManager.hx @@ -0,0 +1,45 @@ +package openfl._internal.renderer; + + +import openfl.display.*; +import openfl.geom.*; + +@:access(openfl.display.DisplayObject) +@:keep + + +class AbstractMaskManager { + + + private var renderSession:RenderSession; + + + public function new (renderSession:RenderSession) { + + this.renderSession = renderSession; + + } + + + public function pushMask (mask:DisplayObject):Void { + + + + } + + + public function pushRect (rect:Rectangle, transform:Matrix):Void { + + + + } + + + public function popMask ():Void { + + + + } + + +} \ No newline at end of file diff --git a/openfl/_internal/renderer/RenderSession.hx b/openfl/_internal/renderer/RenderSession.hx index 2e946ffbd2..81f5ce70ad 100644 --- a/openfl/_internal/renderer/RenderSession.hx +++ b/openfl/_internal/renderer/RenderSession.hx @@ -8,7 +8,6 @@ import lime.graphics.GLRenderContext; import lime.graphics.opengl.GLFramebuffer; import openfl._internal.renderer.opengl.utils.BlendModeManager; import openfl._internal.renderer.opengl.utils.FilterManager; -import openfl._internal.renderer.opengl.utils.MaskManager; import openfl._internal.renderer.opengl.utils.ShaderManager; import openfl._internal.renderer.opengl.utils.SpriteBatch; import openfl._internal.renderer.opengl.utils.StencilManager; @@ -36,7 +35,7 @@ class RenderSession { public var currentBlendMode:BlendMode; public var shaderManager:ShaderManager; - public var maskManager:#if neko MaskManager #else Dynamic #end; + public var maskManager:AbstractMaskManager; public var filterManager:FilterManager; public var blendModeManager:BlendModeManager; public var spriteBatch:SpriteBatch; diff --git a/openfl/_internal/renderer/cairo/CairoBitmap.hx b/openfl/_internal/renderer/cairo/CairoBitmap.hx index 1e59d6125b..ec8a21b4cc 100644 --- a/openfl/_internal/renderer/cairo/CairoBitmap.hx +++ b/openfl/_internal/renderer/cairo/CairoBitmap.hx @@ -27,11 +27,11 @@ class CairoBitmap { if (bitmap.bitmapData != null && bitmap.bitmapData.__isValid) { - //if (bitmap.__mask != null) { - // - //renderSession.maskManager.pushMask (bitmap.__mask); - // - //} + if (bitmap.__mask != null) { + + renderSession.maskManager.pushMask (bitmap.__mask); + + } //bitmap.bitmapData.__sync (); @@ -102,11 +102,11 @@ class CairoBitmap { // //} - //if (bitmap.__mask != null) { - // - //renderSession.maskManager.popMask (); - // - //} + if (bitmap.__mask != null) { + + renderSession.maskManager.popMask (); + + } } diff --git a/openfl/_internal/renderer/cairo/CairoGraphics.hx b/openfl/_internal/renderer/cairo/CairoGraphics.hx index e40683f7f5..007ca52e45 100644 --- a/openfl/_internal/renderer/cairo/CairoGraphics.hx +++ b/openfl/_internal/renderer/cairo/CairoGraphics.hx @@ -1042,85 +1042,85 @@ class CairoGraphics { public static function renderMask (graphics:Graphics, renderSession:RenderSession) { - //if (graphics.__commands.length != 0) { - // - //var context = renderSession.context; - // - //var positionX = 0.0; - //var positionY = 0.0; - // - //var offsetX = 0; - //var offsetY = 0; - // - //for (command in graphics.__commands) { - // - //switch (command) { - // - //case CubicCurveTo (cx1, cx2, cy1, cy2, x, y): - // - //context.bezierCurveTo (cx1 - offsetX, cy1 - offsetY, cx2 - offsetX, cy2 - offsetY, x - offsetX, y - offsetY); - //positionX = x; - //positionY = y; - // - //case CurveTo (cx, cy, x, y): - // - //context.quadraticCurveTo (cx - offsetX, cy - offsetY, x - offsetX, y - offsetY); - //positionX = x; - //positionY = y; - // - //case DrawCircle (x, y, radius): - // - //context.arc (x - offsetX, y - offsetY, radius, 0, Math.PI * 2, true); - // - //case DrawEllipse (x, y, width, height): - // - //x -= offsetX; - //y -= offsetY; - // - //var kappa = .5522848, - //ox = (width / 2) * kappa, // control point offset horizontal - //oy = (height / 2) * kappa, // control point offset vertical - //xe = x + width, // x-end - //ye = y + height, // y-end - //xm = x + width / 2, // x-middle - //ym = y + height / 2; // y-middle - // - ////closePath (false); - ////beginPath (); - //context.moveTo (x, ym); - //context.bezierCurveTo (x, ym - oy, xm - ox, y, xm, y); - //context.bezierCurveTo (xm + ox, y, xe, ym - oy, xe, ym); - //context.bezierCurveTo (xe, ym + oy, xm + ox, ye, xm, ye); - //context.bezierCurveTo (xm - ox, ye, x, ym + oy, x, ym); - ////closePath (false); - // - //case DrawRect (x, y, width, height): - // - //context.rect (x - offsetX, y - offsetY, width, height); - // - //case DrawRoundRect (x, y, width, height, rx, ry): - // - //drawRoundRect (x - offsetX, y - offsetY, width, height, rx, ry); - // - //case LineTo (x, y): - // - //context.lineTo (x - offsetX, y - offsetY); - //positionX = x; - //positionY = y; - // - //case MoveTo (x, y): - // - //context.moveTo (x - offsetX, y - offsetY); - //positionX = x; - //positionY = y; - // - //default: - // - //} - // - //} - // - //} + if (graphics.__commands.length != 0) { + + var cairo = renderSession.cairo; + + var positionX = 0.0; + var positionY = 0.0; + + var offsetX = 0; + var offsetY = 0; + + for (command in graphics.__commands) { + + switch (command) { + + case CubicCurveTo (cx1, cx2, cy1, cy2, x, y): + + cairo.curveTo (cx1 - offsetX, cy1 - offsetY, cx2 - offsetX, cy2 - offsetY, x - offsetX, y - offsetY); + positionX = x; + positionY = y; + + case CurveTo (cx, cy, x, y): + + quadraticCurveTo (cx - offsetX, cy - offsetY, x - offsetX, y - offsetY); + positionX = x; + positionY = y; + + case DrawCircle (x, y, radius): + + cairo.arc (x - offsetX, y - offsetY, radius, 0, Math.PI * 2); + + case DrawEllipse (x, y, width, height): + + x -= offsetX; + y -= offsetY; + + var kappa = .5522848, + ox = (width / 2) * kappa, // control point offset horizontal + oy = (height / 2) * kappa, // control point offset vertical + xe = x + width, // x-end + ye = y + height, // y-end + xm = x + width / 2, // x-middle + ym = y + height / 2; // y-middle + + //closePath (false); + //beginPath (); + cairo.moveTo (x, ym); + cairo.curveTo (x, ym - oy, xm - ox, y, xm, y); + cairo.curveTo (xm + ox, y, xe, ym - oy, xe, ym); + cairo.curveTo (xe, ym + oy, xm + ox, ye, xm, ye); + cairo.curveTo (xm - ox, ye, x, ym + oy, x, ym); + //closePath (false); + + case DrawRect (x, y, width, height): + + cairo.rectangle (x - offsetX, y - offsetY, width, height); + + case DrawRoundRect (x, y, width, height, rx, ry): + + drawRoundRect (x - offsetX, y - offsetY, width, height, rx, ry); + + case LineTo (x, y): + + cairo.lineTo (x - offsetX, y - offsetY); + positionX = x; + positionY = y; + + case MoveTo (x, y): + + cairo.moveTo (x - offsetX, y - offsetY); + positionX = x; + positionY = y; + + default: + + } + + } + + } } diff --git a/openfl/_internal/renderer/cairo/CairoMaskManager.hx b/openfl/_internal/renderer/cairo/CairoMaskManager.hx new file mode 100644 index 0000000000..6998820a80 --- /dev/null +++ b/openfl/_internal/renderer/cairo/CairoMaskManager.hx @@ -0,0 +1,66 @@ +package openfl._internal.renderer.cairo; + + +import lime.math.Matrix3; +import openfl._internal.renderer.AbstractMaskManager; +import openfl.display.*; +import openfl.geom.*; + +@:access(openfl.display.DisplayObject) +@:access(openfl.geom.Matrix) +@:keep + + +class CairoMaskManager extends AbstractMaskManager { + + + public function new (renderSession:RenderSession) { + + super (renderSession); + + } + + + public override function pushMask (mask:DisplayObject):Void { + + var cairo = renderSession.cairo; + + cairo.save (); + + //var cacheAlpha = mask.__worldAlpha; + var transform = mask.__getTransform (); + + cairo.matrix = transform.__toMatrix3 (); + + cairo.newPath (); + mask.__renderCairoMask (renderSession); + + cairo.clipPreserve (); + + //mask.worldAlpha = cacheAlpha; + + } + + + public override function pushRect (rect:Rectangle, transform:Matrix):Void { + + var cairo = renderSession.cairo; + cairo.save (); + + cairo.matrix = new Matrix3 (transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); + + cairo.newPath (); + cairo.rectangle (rect.x, rect.y, rect.width, rect.height); + cairo.clipPreserve (); + + } + + + public override function popMask ():Void { + + renderSession.cairo.restore (); + + } + + +} \ No newline at end of file diff --git a/openfl/_internal/renderer/cairo/CairoRenderer.hx b/openfl/_internal/renderer/cairo/CairoRenderer.hx index e7d5f7864c..1160df3011 100644 --- a/openfl/_internal/renderer/cairo/CairoRenderer.hx +++ b/openfl/_internal/renderer/cairo/CairoRenderer.hx @@ -27,9 +27,7 @@ class CairoRenderer extends AbstractRenderer { renderSession.cairo = cairo; renderSession.roundPixels = true; renderSession.renderer = this; - //#if !neko - //renderSession.maskManager = new MaskManager (renderSession); - //#end + renderSession.maskManager = new CairoMaskManager (renderSession); } diff --git a/openfl/_internal/renderer/cairo/CairoShape.hx b/openfl/_internal/renderer/cairo/CairoShape.hx index 8e2505c2bf..8dabadc317 100644 --- a/openfl/_internal/renderer/cairo/CairoShape.hx +++ b/openfl/_internal/renderer/cairo/CairoShape.hx @@ -23,11 +23,11 @@ class CairoShape { if (graphics.__cairo != null) { - //if (shape.__mask != null) { - // - //renderSession.maskManager.pushMask (shape.__mask); - // - //} + if (shape.__mask != null) { + + renderSession.maskManager.pushMask (shape.__mask); + + } var cairo = renderSession.cairo; var scrollRect = shape.scrollRect; @@ -62,11 +62,11 @@ class CairoShape { // //} // - //if (shape.__mask != null) { - // - //renderSession.maskManager.popMask (); - // - //} + if (shape.__mask != null) { + + renderSession.maskManager.popMask (); + + } } diff --git a/openfl/_internal/renderer/canvas/MaskManager.hx b/openfl/_internal/renderer/canvas/CanvasMaskManager.hx similarity index 71% rename from openfl/_internal/renderer/canvas/MaskManager.hx rename to openfl/_internal/renderer/canvas/CanvasMaskManager.hx index f6bb8c83c8..3a12e5aad1 100644 --- a/openfl/_internal/renderer/canvas/MaskManager.hx +++ b/openfl/_internal/renderer/canvas/CanvasMaskManager.hx @@ -1,6 +1,7 @@ package openfl._internal.renderer.canvas; +import openfl._internal.renderer.AbstractMaskManager; import openfl.display.*; import openfl.geom.*; @@ -8,20 +9,17 @@ import openfl.geom.*; @:keep -class MaskManager { - - - private var renderSession:RenderSession; +class CanvasMaskManager extends AbstractMaskManager { public function new (renderSession:RenderSession) { - this.renderSession = renderSession; + super (renderSession); } - public function pushMask (mask:DisplayObject):Void { + public override function pushMask (mask:DisplayObject):Void { var context = renderSession.context; @@ -33,7 +31,7 @@ class MaskManager { context.setTransform (transform.a, transform.c, transform.b, transform.d, transform.tx, transform.ty); context.beginPath (); - mask.__renderMask (renderSession); + mask.__renderCanvasMask (renderSession); context.clip (); @@ -42,7 +40,7 @@ class MaskManager { } - public function pushRect (rect:Rectangle, transform:Matrix):Void { + public override function pushRect (rect:Rectangle, transform:Matrix):Void { var context = renderSession.context; context.save (); @@ -56,7 +54,7 @@ class MaskManager { } - public function popMask ():Void { + public override function popMask ():Void { renderSession.context.restore (); diff --git a/openfl/_internal/renderer/canvas/CanvasRenderer.hx b/openfl/_internal/renderer/canvas/CanvasRenderer.hx index 38a59813a7..99cc0f2344 100644 --- a/openfl/_internal/renderer/canvas/CanvasRenderer.hx +++ b/openfl/_internal/renderer/canvas/CanvasRenderer.hx @@ -26,7 +26,7 @@ class CanvasRenderer extends AbstractRenderer { renderSession.roundPixels = true; renderSession.renderer = this; #if !neko - renderSession.maskManager = new MaskManager(renderSession); + renderSession.maskManager = new CanvasMaskManager(renderSession); #end } diff --git a/openfl/_internal/renderer/opengl/GLRenderer.hx b/openfl/_internal/renderer/opengl/GLRenderer.hx index 273452fdfa..b3d3a4a3be 100644 --- a/openfl/_internal/renderer/opengl/GLRenderer.hx +++ b/openfl/_internal/renderer/opengl/GLRenderer.hx @@ -31,7 +31,7 @@ class GLRenderer extends AbstractRenderer { public var filterManager:FilterManager; public var gl:GLRenderContext; public var _glContextId:Int; - public var maskManager:MaskManager; + public var maskManager:GLMaskManager; public var offset:Point; public var options:Dynamic; public var preserveDrawingBuffer:Bool; @@ -113,7 +113,6 @@ class GLRenderer extends AbstractRenderer { shaderManager = new ShaderManager (gl); spriteBatch = new SpriteBatch (gl); - maskManager = new MaskManager (gl); filterManager = new FilterManager (gl, this.transparent); stencilManager = new StencilManager (gl); blendModeManager = new BlendModeManager (gl); @@ -131,6 +130,9 @@ class GLRenderer extends AbstractRenderer { renderSession.defaultFramebuffer = this.defaultFramebuffer; renderSession.projectionMatrix = this.projectionMatrix; + maskManager = new GLMaskManager (renderSession); + renderSession.maskManager = maskManager; + shaderManager.setShader(shaderManager.defaultShader); gl.disable (gl.DEPTH_TEST); diff --git a/openfl/_internal/renderer/opengl/utils/MaskManager.hx b/openfl/_internal/renderer/opengl/utils/GLMaskManager.hx similarity index 79% rename from openfl/_internal/renderer/opengl/utils/MaskManager.hx rename to openfl/_internal/renderer/opengl/utils/GLMaskManager.hx index a17d244b09..7d671f4dd8 100644 --- a/openfl/_internal/renderer/opengl/utils/MaskManager.hx +++ b/openfl/_internal/renderer/opengl/utils/GLMaskManager.hx @@ -2,32 +2,60 @@ package openfl._internal.renderer.opengl.utils; import lime.graphics.GLRenderContext; +import openfl._internal.renderer.AbstractMaskManager; import openfl._internal.renderer.RenderSession; import openfl.display.DisplayObject; -class MaskManager { + +class GLMaskManager extends AbstractMaskManager { + public var gl:GLRenderContext; - public function new(gl:GLRenderContext) { - setContext(gl); + + public function new (renderSession:RenderSession) { + + super (renderSession); + + setContext (renderSession.gl); + } - public function destroy() { + + public function destroy () { + gl = null; + } - public function setContext(gl:GLRenderContext) { - this.gl = gl; + + public override function pushMask (mask:DisplayObject) { + + renderSession.stencilManager.pushMask (mask, renderSession); + } - public function pushMask(object:DisplayObject, renderSession:RenderSession) { - renderSession.stencilManager.pushMask(object, renderSession); + + public override function popMask () { + + renderSession.stencilManager.popMask (null, renderSession); + } - public function popMask(object:DisplayObject, renderSession:RenderSession) { - renderSession.stencilManager.popMask(object, renderSession); + + public function setContext (gl:GLRenderContext) { + + if (renderSession != null) { + + renderSession.gl = gl; + + } + + this.gl = gl; + } + + } /* diff --git a/openfl/_internal/renderer/opengl/utils/StencilManager.hx b/openfl/_internal/renderer/opengl/utils/StencilManager.hx index ccf457d3df..1fe9c69c99 100644 --- a/openfl/_internal/renderer/opengl/utils/StencilManager.hx +++ b/openfl/_internal/renderer/opengl/utils/StencilManager.hx @@ -137,10 +137,10 @@ class StencilManager { public function popMask(object:DisplayObject, renderSession:RenderSession) { - var maskGraphics:Graphics = object.__maskGraphics; - if (maskGraphics == null || maskGraphics.__commands.length <= 0) { - return; - } + //var maskGraphics:Graphics = object.__maskGraphics; + //if (maskGraphics == null || maskGraphics.__commands.length <= 0) { + //return; + //} stencilMask--; diff --git a/openfl/display/Bitmap.hx b/openfl/display/Bitmap.hx index a824563214..66689f2d0a 100644 --- a/openfl/display/Bitmap.hx +++ b/openfl/display/Bitmap.hx @@ -153,6 +153,13 @@ class Bitmap extends DisplayObjectContainer { } + @:noCompletion @:dox(hide) public override function __renderCairoMask (renderSession:RenderSession):Void { + + renderSession.cairo.rectangle (0, 0, width, height); + + } + + @:noCompletion @:dox(hide) public override function __renderCanvas (renderSession:RenderSession):Void { CanvasBitmap.render (this, renderSession); @@ -160,23 +167,23 @@ class Bitmap extends DisplayObjectContainer { } - @:noCompletion @:dox(hide) public override function __renderDOM (renderSession:RenderSession):Void { + @:noCompletion @:dox(hide) public override function __renderCanvasMask (renderSession:RenderSession):Void { - DOMBitmap.render (this, renderSession); + renderSession.context.rect (0, 0, width, height); } - @:noCompletion @:dox(hide) public override function __renderGL (renderSession:RenderSession):Void { + @:noCompletion @:dox(hide) public override function __renderDOM (renderSession:RenderSession):Void { - GLBitmap.render (this, renderSession); + DOMBitmap.render (this, renderSession); } - @:noCompletion @:dox(hide) public override function __renderMask (renderSession:RenderSession):Void { + @:noCompletion @:dox(hide) public override function __renderGL (renderSession:RenderSession):Void { - renderSession.context.rect (0, 0, width, height); + GLBitmap.render (this, renderSession); } diff --git a/openfl/display/BitmapData.hx b/openfl/display/BitmapData.hx index bbb789e92a..0be1fa8c61 100644 --- a/openfl/display/BitmapData.hx +++ b/openfl/display/BitmapData.hx @@ -96,6 +96,7 @@ import js.Browser; @:access(lime.graphics.ImageBuffer) @:access(lime.math.Rectangle) @:access(openfl.geom.ColorTransform) +@:access(openfl.geom.Matrix) @:access(openfl.geom.Point) @:access(openfl.geom.Rectangle) @@ -1560,6 +1561,133 @@ class BitmapData implements IBitmapDrawable { } + @:noCompletion @:dox(hide) public function __drawGL (renderSession:RenderSession, width:Int, height:Int, source:IBitmapDrawable, matrix:Matrix = null, colorTransform:ColorTransform = null, blendMode:BlendMode = null, clipRect:Rectangle = null, smoothing:Bool = false, drawSelf:Bool = false, clearBuffer:Bool = false, readPixels:Bool = false):Void { + + var renderer = @:privateAccess Lib.current.stage.__renderer; + if (renderer == null) return; + + var renderSession = @:privateAccess renderer.renderSession; + var gl:GLRenderContext = renderSession.gl; + if (gl == null) return; + + var spritebatch = renderSession.spriteBatch; + var renderTransparent = renderSession.renderer.transparent; + + var tmpRect = clipRect == null ? new Rectangle (0, 0, width, height) : clipRect.clone (); + + renderSession.renderer.transparent = transparent; + + if (__framebuffer == null) { + + __framebuffer = new FilterTexture (gl, width, height, smoothing); + + } + + __framebuffer.resize (width, height); + gl.bindFramebuffer (gl.FRAMEBUFFER, __framebuffer.frameBuffer); + + renderer.setViewport (0, 0, width, height); + + spritebatch.begin (renderSession, drawSelf ? null : tmpRect); + + // enable writing to all the colors and alpha + gl.colorMask (true, true, true, true); + renderSession.blendModeManager.setBlendMode (BlendMode.NORMAL); + + if (clearBuffer || drawSelf) { + + __framebuffer.clear (); + + } + + if (drawSelf) { + + __worldTransform.identity (); + __flipMatrix (__worldTransform); + this.__renderGL (renderSession); + spritebatch.stop (); + gl.deleteTexture (__texture); + spritebatch.start (tmpRect); + + } + + var ctCache = source.__worldColorTransform; + var matrixCache = source.__worldTransform; + var blendModeCache = source.blendMode; + var cached = source.__cacheAsBitmap; + + var m = matrix != null ? matrix.clone () : new Matrix (); + + __flipMatrix (m); + + source.__worldTransform = m; + source.__worldColorTransform = colorTransform != null ? colorTransform : new ColorTransform (); + source.blendMode = blendMode; + source.__cacheAsBitmap = false; + + source.__updateChildren (false); + + source.__renderGL (renderSession); + + source.__worldColorTransform = ctCache; + source.__worldTransform = matrixCache; + source.blendMode = blendModeCache; + source.__cacheAsBitmap = cached; + + source.__updateChildren (true); + + spritebatch.finish (); + + if (readPixels) { + + // TODO is this possible? + if (__image.width != width || __image.height != height) { + + __image.resize (width, height); + + } + + gl.readPixels (0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, __image.buffer.data); + + } + + gl.bindFramebuffer (gl.FRAMEBUFFER, renderSession.defaultFramebuffer); + + renderer.setViewport (0, 0, renderSession.renderer.width, renderSession.renderer.height); + + renderSession.renderer.transparent = renderTransparent; + + gl.colorMask (true, true, true, renderSession.renderer.transparent); + + __usingFramebuffer = true; + + if (__image != null) { + + __image.dirty = false; + __image.premultiplied = true; + + } + + __createUVs (); + __isValid = true; + + } + + + @:noCompletion @:dox(hide) private inline function __flipMatrix (m:Matrix):Void { + + var tx = m.tx; + var ty = m.ty; + m.tx = 0; + m.ty = 0; + m.scale (1, -1); + m.translate (0, height); + m.tx += tx; + m.ty -= ty; + + } + + @:noCompletion private static inline function __flipPixel (pixel:Int):Int { return (pixel & 0xFF) << 24 | (pixel >> 8 & 0xFF) << 16 | (pixel >> 16 & 0xFF) << 8 | (pixel >> 24 & 0xFF); @@ -1649,169 +1777,91 @@ class BitmapData implements IBitmapDrawable { } - @:noCompletion @:dox(hide) public function __renderCanvas (renderSession:RenderSession):Void { + @:noCompletion @:dox(hide) public function __renderCairo (renderSession:RenderSession):Void { - #if (js && html5) if (!__isValid) return; - ImageCanvasUtil.sync (__image); - - var context = renderSession.context; + var cairo = renderSession.cairo; if (__worldTransform == null) __worldTransform = new Matrix (); - context.globalAlpha = 1; + //context.globalAlpha = 1; var transform = __worldTransform; if (renderSession.roundPixels) { - context.setTransform (transform.a, transform.b, transform.c, transform.d, Std.int (transform.tx), Std.int (transform.ty)); + var matrix = transform.__toMatrix3 (); + matrix.tx = Math.round (matrix.tx); + matrix.ty = Math.round (matrix.ty); + cairo.matrix = matrix; + //context.setTransform (transform.a, transform.b, transform.c, transform.d, Std.int (transform.tx), Std.int (transform.ty)); } else { - context.setTransform (transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); + cairo.matrix = transform.__toMatrix3 (); + //context.setTransform (transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); } - context.drawImage (__image.buffer.src, 0, 0); - #end + var surface = getSurface (); + + if (surface != null) { + + cairo.setSourceSurface (surface, 0, 0); + cairo.paint (); + + } } - @:noCompletion @:dox(hide) public function __renderGL (renderSession:RenderSession):Void { + @:noCompletion @:dox(hide) public function __renderCairoMask (renderSession:RenderSession):Void { + - renderSession.spriteBatch.renderBitmapData(this, false, __worldTransform, __worldColorTransform, __worldColorTransform.alphaMultiplier, blendMode); } - @:noCompletion @:dox(hide) public function __drawGL (renderSession:RenderSession, width:Int, height:Int, source:IBitmapDrawable, matrix:Matrix = null, colorTransform:ColorTransform = null, blendMode:BlendMode = null, clipRect:Rectangle = null, smoothing:Bool = false, drawSelf:Bool = false, clearBuffer:Bool = false, readPixels:Bool = false):Void { - - var renderer = @:privateAccess Lib.current.stage.__renderer; - if (renderer == null) return; - - var renderSession = @:privateAccess renderer.renderSession; - var gl:GLRenderContext = renderSession.gl; - if (gl == null) return; - - var spritebatch = renderSession.spriteBatch; - var renderTransparent = renderSession.renderer.transparent; - - var tmpRect = clipRect == null ? new Rectangle(0, 0, width, height) : clipRect.clone(); - - renderSession.renderer.transparent = transparent; - - if (__framebuffer == null) { - __framebuffer = new FilterTexture(gl, width, height, smoothing); - } - - __framebuffer.resize(width, height); - gl.bindFramebuffer(gl.FRAMEBUFFER, __framebuffer.frameBuffer); - - renderer.setViewport (0, 0, width, height); - - spritebatch.begin(renderSession, drawSelf ? null : tmpRect); - - // enable writing to all the colors and alpha - gl.colorMask(true, true, true, true); - renderSession.blendModeManager.setBlendMode(BlendMode.NORMAL); - - if (clearBuffer || drawSelf) { - __framebuffer.clear(); - } - - if (drawSelf) { - __worldTransform.identity(); - __flipMatrix(__worldTransform); - this.__renderGL(renderSession); - spritebatch.stop(); - gl.deleteTexture(__texture); - spritebatch.start(tmpRect); - } - - var ctCache = source.__worldColorTransform; - var matrixCache = source.__worldTransform; - var blendModeCache = source.blendMode; - var cached = source.__cacheAsBitmap; - - var m = matrix != null ? matrix.clone() : new Matrix (); - - __flipMatrix(m); - - source.__worldTransform = m; - source.__worldColorTransform = colorTransform != null ? colorTransform : new ColorTransform(); - source.blendMode = blendMode; - source.__cacheAsBitmap = false; + @:noCompletion @:dox(hide) public function __renderCanvas (renderSession:RenderSession):Void { - source.__updateChildren (false); + #if (js && html5) + if (!__isValid) return; - source.__renderGL (renderSession); + ImageCanvasUtil.sync (__image); - source.__worldColorTransform = ctCache; - source.__worldTransform = matrixCache; - source.blendMode = blendModeCache; - source.__cacheAsBitmap = cached; + var context = renderSession.context; - source.__updateChildren (true); + if (__worldTransform == null) __worldTransform = new Matrix (); - spritebatch.finish(); + context.globalAlpha = 1; + var transform = __worldTransform; - if (readPixels) { + if (renderSession.roundPixels) { - // TODO is this possible? - if (__image.width != width || __image.height != height) { - - __image.resize(width, height); - - } + context.setTransform (transform.a, transform.b, transform.c, transform.d, Std.int (transform.tx), Std.int (transform.ty)); - gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, __image.buffer.data); + } else { + + context.setTransform (transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); } - gl.bindFramebuffer(gl.FRAMEBUFFER, renderSession.defaultFramebuffer); - - renderer.setViewport (0, 0, renderSession.renderer.width, renderSession.renderer.height); - - renderSession.renderer.transparent = renderTransparent; - - gl.colorMask(true, true, true, renderSession.renderer.transparent); - - __usingFramebuffer = true; - if(__image != null) { - __image.dirty = false; - __image.premultiplied = true; - } - __createUVs(); - __isValid = true; - - } - - @:noCompletion @:dox(hide) private inline function __flipMatrix (m:Matrix):Void { - - var tx = m.tx; - var ty = m.ty; - m.tx = 0; - m.ty = 0; - m.scale(1, -1); - m.translate(0, height); - m.tx += tx; - m.ty -= ty; + context.drawImage (__image.buffer.src, 0, 0); + #end } - @:noCompletion @:dox(hide) public function __renderMask (renderSession:RenderSession):Void { + @:noCompletion @:dox(hide) public function __renderCanvasMask (renderSession:RenderSession):Void { } - @:noCompletion @:dox(hide) public function __updateMask (maskGraphics:Graphics):Void { - + @:noCompletion @:dox(hide) public function __renderGL (renderSession:RenderSession):Void { + renderSession.spriteBatch.renderBitmapData (this, false, __worldTransform, __worldColorTransform, __worldColorTransform.alphaMultiplier, blendMode); } @@ -1883,6 +1933,13 @@ class BitmapData implements IBitmapDrawable { + } + + + @:noCompletion @:dox(hide) public function __updateMask (maskGraphics:Graphics):Void { + + + } diff --git a/openfl/display/DisplayObject.hx b/openfl/display/DisplayObject.hx index 18078b8c55..b9bf64cd78 100644 --- a/openfl/display/DisplayObject.hx +++ b/openfl/display/DisplayObject.hx @@ -2,6 +2,7 @@ package openfl.display; #if !flash #if !openfl_legacy import lime.ui.MouseCursor; +import openfl._internal.renderer.cairo.CairoGraphics; import openfl._internal.renderer.cairo.CairoShape; import openfl._internal.renderer.canvas.CanvasGraphics; import openfl._internal.renderer.canvas.CanvasShape; @@ -1116,6 +1117,17 @@ class DisplayObject extends EventDispatcher implements IBitmapDrawable { } + @:noCompletion @:dox(hide) public function __renderCairoMask (renderSession:RenderSession):Void { + + if (__graphics != null) { + + CairoGraphics.renderMask (__graphics, renderSession); + + } + + } + + @:noCompletion @:dox(hide) public function __renderCanvas (renderSession:RenderSession):Void { if (__graphics != null) { @@ -1127,35 +1139,35 @@ class DisplayObject extends EventDispatcher implements IBitmapDrawable { } - @:noCompletion @:dox(hide) public function __renderDOM (renderSession:RenderSession):Void { + @:noCompletion @:dox(hide) public function __renderCanvasMask (renderSession:RenderSession):Void { if (__graphics != null) { - DOMShape.render (this, renderSession); + CanvasGraphics.renderMask (__graphics, renderSession); } } - @:noCompletion @:dox(hide) public function __renderGL (renderSession:RenderSession):Void { - - if (!__renderable || __worldAlpha <= 0) return; + @:noCompletion @:dox(hide) public function __renderDOM (renderSession:RenderSession):Void { if (__graphics != null) { - GraphicsRenderer.render (this, renderSession); + DOMShape.render (this, renderSession); } } - @:noCompletion @:dox(hide) public function __renderMask (renderSession:RenderSession):Void { + @:noCompletion @:dox(hide) public function __renderGL (renderSession:RenderSession):Void { + + if (!__renderable || __worldAlpha <= 0) return; if (__graphics != null) { - CanvasGraphics.renderMask (__graphics, renderSession); + GraphicsRenderer.render (this, renderSession); } diff --git a/openfl/display/DisplayObjectContainer.hx b/openfl/display/DisplayObjectContainer.hx index fe96d52f2a..396d5ca4ba 100644 --- a/openfl/display/DisplayObjectContainer.hx +++ b/openfl/display/DisplayObjectContainer.hx @@ -1,6 +1,7 @@ package openfl.display; #if !flash #if !openfl_legacy +import openfl._internal.renderer.cairo.CairoGraphics; import openfl._internal.renderer.canvas.CanvasGraphics; import openfl._internal.renderer.RenderSession; import openfl.display.Stage; @@ -780,11 +781,11 @@ class DisplayObjectContainer extends InteractiveObject { // //} // - //if (__mask != null) { - // - //renderSession.maskManager.pushMask (__mask); - // - //} + if (__mask != null) { + + renderSession.maskManager.pushMask (__mask); + + } for (child in __children) { @@ -794,11 +795,11 @@ class DisplayObjectContainer extends InteractiveObject { __removedChildren = []; - //if (__mask != null) { - // - //renderSession.maskManager.popMask (); - // - //} + if (__mask != null) { + + renderSession.maskManager.popMask (); + + } // //if (scrollRect != null) { // @@ -809,6 +810,28 @@ class DisplayObjectContainer extends InteractiveObject { } + @:noCompletion @:dox(hide) public override function __renderCairoMask (renderSession:RenderSession):Void { + + if (__graphics != null) { + + CairoGraphics.renderMask (__graphics, renderSession); + + } + + var bounds = new Rectangle (); + __getLocalBounds (bounds); + + renderSession.cairo.rectangle (0, 0, bounds.width, bounds.height); + + /*for (child in __children) { + + child.__renderMask (renderSession); + + }*/ + + } + + @:noCompletion @:dox(hide) public override function __renderCanvas (renderSession:RenderSession):Void { if (!__renderable || __worldAlpha <= 0) return; @@ -854,6 +877,28 @@ class DisplayObjectContainer extends InteractiveObject { } + @:noCompletion @:dox(hide) public override function __renderCanvasMask (renderSession:RenderSession):Void { + + if (__graphics != null) { + + CanvasGraphics.renderMask (__graphics, renderSession); + + } + + var bounds = new Rectangle (); + __getLocalBounds (bounds); + + renderSession.context.rect (0, 0, bounds.width, bounds.height); + + /*for (child in __children) { + + child.__renderMask (renderSession); + + }*/ + + } + + @:noCompletion @:dox(hide) public override function __renderDOM (renderSession:RenderSession):Void { #if !neko @@ -908,7 +953,7 @@ class DisplayObjectContainer extends InteractiveObject { if (masked) { renderSession.spriteBatch.stop (); - renderSession.maskManager.pushMask (this, renderSession); + renderSession.maskManager.pushMask (this); renderSession.spriteBatch.start (); } @@ -921,35 +966,16 @@ class DisplayObjectContainer extends InteractiveObject { } - if(masked) { - renderSession.spriteBatch.stop(); - renderSession.maskManager.popMask(this, renderSession); - renderSession.spriteBatch.start(); - } - - __removedChildren = []; - - } - - - @:noCompletion @:dox(hide) public override function __renderMask (renderSession:RenderSession):Void { - - if (__graphics != null) { + if (masked) { - CanvasGraphics.renderMask (__graphics, renderSession); + renderSession.spriteBatch.stop (); + //renderSession.maskManager.popMask (this); + renderSession.maskManager.popMask (); + renderSession.spriteBatch.start (); } - var bounds = new Rectangle (); - __getLocalBounds (bounds); - - renderSession.context.rect (0, 0, bounds.width, bounds.height); - - /*for (child in __children) { - - child.__renderMask (renderSession); - - }*/ + __removedChildren = []; } diff --git a/openfl/display/IBitmapDrawable.hx b/openfl/display/IBitmapDrawable.hx index 02bcd8f5f2..81bcfbc0e2 100644 --- a/openfl/display/IBitmapDrawable.hx +++ b/openfl/display/IBitmapDrawable.hx @@ -14,9 +14,11 @@ interface IBitmapDrawable { private var __cacheAsBitmap:Bool; + function __renderCairo (renderSession:RenderSession):Void; + function __renderCairoMask (renderSession:RenderSession):Void; function __renderCanvas (renderSession:RenderSession):Void; + function __renderCanvasMask (renderSession:RenderSession):Void; function __renderGL (renderSession:RenderSession):Void; - function __renderMask (renderSession:RenderSession):Void; function __updateChildren (transformOnly:Bool):Void; function __updateMask (maskGraphics:Graphics):Void; From 72acd5768e10764296f0fb9f4d94df8cfcdc4743 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Thu, 7 May 2015 11:27:33 -0700 Subject: [PATCH 119/150] Fix unit test (for now) --- .travis.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index e581ff8f30..9682229241 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,8 +35,10 @@ before_script: - haxelib run munit gen script: - - haxelib run lime test neko - - haxelib run lime test neko -Ddisable-cffi + #- haxelib run lime test neko + #- haxelib run lime test neko -Ddisable-cffi + - haxelib run lime build neko + - haxelib run lime build neko -Ddisable-cffi - haxelib run lime test neko -Dlegacy - haxelib run munit test -as3 -norun - haxelib run munit test -browser phantomjs From fb40751236aa7fd9f6ed61691d45c506cb02b3e1 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Thu, 7 May 2015 14:14:46 -0700 Subject: [PATCH 120/150] Handle initial sound transform volume on native --- openfl/media/Sound.hx | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/openfl/media/Sound.hx b/openfl/media/Sound.hx index 23bd0e9c70..4abb66a3cb 100644 --- a/openfl/media/Sound.hx +++ b/openfl/media/Sound.hx @@ -421,20 +421,21 @@ class Sound extends EventDispatcher { */ public function play (startTime:Float = 0.0, loops:Int = 0, sndTransform:SoundTransform = null):SoundChannel { - if (sndTransform == null) { - - sndTransform = new SoundTransform (1, 0); - - } - - // TODO: handle start time, loops, sound transform + // TODO: handle pan #if !html5 var source = new AudioSource (__buffer); source.offset = Std.int (startTime * 1000); if (loops > 1) source.loops = loops - 1; + if (sndTransform != null) source.gain = sndTransform.volume; return new SoundChannel (source); #else + if (sndTransform == null) { + + sndTransform = new SoundTransform (1, 0); + + } + var instance = if (loops > 1) SoundJS.play (__soundID, SoundJS.INTERRUPT_ANY, 0, Std.int (startTime), loops - 1, sndTransform.volume, sndTransform.pan); From ca0de50c417df79a115b630c12a6177a820127c7 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Thu, 7 May 2015 15:16:59 -0700 Subject: [PATCH 121/150] Better cleanup for native sounds --- openfl/media/SoundChannel.hx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/openfl/media/SoundChannel.hx b/openfl/media/SoundChannel.hx index 409b80d3eb..2df0007f0f 100644 --- a/openfl/media/SoundChannel.hx +++ b/openfl/media/SoundChannel.hx @@ -106,6 +106,7 @@ class SoundChannel extends EventDispatcher { #if !html5 __source.stop (); + __dispose (); #else __soundInstance.stop (); #end @@ -118,8 +119,12 @@ class SoundChannel extends EventDispatcher { if (!__isValid) return; + #if !html5 + source.dispose (); + #else __soundInstance.stop (); __soundInstance = null; + #end } #end @@ -213,6 +218,7 @@ class SoundChannel extends EventDispatcher { @:noCompletion private function source_onComplete ():Void { + __dispose (); dispatchEvent (new Event (Event.SOUND_COMPLETE)); } From a3dde80c80cdea0b87d5dca150d20d2d0fe31963 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Thu, 7 May 2015 15:18:33 -0700 Subject: [PATCH 122/150] Set isValid to false on sound cleanup --- openfl/media/SoundChannel.hx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openfl/media/SoundChannel.hx b/openfl/media/SoundChannel.hx index 2df0007f0f..c32ebd04e4 100644 --- a/openfl/media/SoundChannel.hx +++ b/openfl/media/SoundChannel.hx @@ -126,6 +126,8 @@ class SoundChannel extends EventDispatcher { __soundInstance = null; #end + __isValid = false; + } #end From fb749d7949cee55746903d507e073daa88e0695d Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Thu, 7 May 2015 16:13:56 -0700 Subject: [PATCH 123/150] Compile fix --- openfl/media/SoundChannel.hx | 2 -- 1 file changed, 2 deletions(-) diff --git a/openfl/media/SoundChannel.hx b/openfl/media/SoundChannel.hx index c32ebd04e4..05d5fe150d 100644 --- a/openfl/media/SoundChannel.hx +++ b/openfl/media/SoundChannel.hx @@ -114,7 +114,6 @@ class SoundChannel extends EventDispatcher { } - #if html5 @:noCompletion private function __dispose ():Void { if (!__isValid) return; @@ -129,7 +128,6 @@ class SoundChannel extends EventDispatcher { __isValid = false; } - #end From 143884accdc5227e42bc88947e92c580aa737942 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Thu, 7 May 2015 17:10:19 -0700 Subject: [PATCH 124/150] Compile fix --- openfl/media/SoundChannel.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openfl/media/SoundChannel.hx b/openfl/media/SoundChannel.hx index 05d5fe150d..afc8894421 100644 --- a/openfl/media/SoundChannel.hx +++ b/openfl/media/SoundChannel.hx @@ -119,7 +119,7 @@ class SoundChannel extends EventDispatcher { if (!__isValid) return; #if !html5 - source.dispose (); + __source.dispose (); #else __soundInstance.stop (); __soundInstance = null; From 7535f9e148ca49203d9f4c8b345318a262b886d1 Mon Sep 17 00:00:00 2001 From: Jay Sistar Date: Sat, 9 May 2015 00:23:24 -0400 Subject: [PATCH 125/150] Make setRenderToBackBuffer() set the viewport as setRenderToTexture() does. --- openfl/display3D/Context3D.hx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openfl/display3D/Context3D.hx b/openfl/display3D/Context3D.hx index 74c75ac9e8..dd7648bcda 100755 --- a/openfl/display3D/Context3D.hx +++ b/openfl/display3D/Context3D.hx @@ -640,6 +640,8 @@ class Context3D { } + GL.viewport (Std.int (scrollRect.x), Std.int (scrollRect.y), Std.int (scrollRect.width), Std.int (scrollRect.height)); + } @@ -1046,4 +1048,4 @@ private class SamplerState { #else typedef Context3D = flash.display3D.Context3D; -#end \ No newline at end of file +#end From 4030707664c478de1bef0b325f95ed5f45230343 Mon Sep 17 00:00:00 2001 From: MrCdK Date: Mon, 11 May 2015 03:39:26 +0200 Subject: [PATCH 126/150] Fixes #656 --- openfl/_internal/renderer/opengl/utils/GraphicsRenderer.hx | 1 + 1 file changed, 1 insertion(+) diff --git a/openfl/_internal/renderer/opengl/utils/GraphicsRenderer.hx b/openfl/_internal/renderer/opengl/utils/GraphicsRenderer.hx index 490e9378d6..e2256ac546 100644 --- a/openfl/_internal/renderer/opengl/utils/GraphicsRenderer.hx +++ b/openfl/_internal/renderer/opengl/utils/GraphicsRenderer.hx @@ -1517,6 +1517,7 @@ class GLBucketData { stride = 0; rawVerts = false; rawIndices = false; + drawMode = gl.TRIANGLE_STRIP; } public function upload():Void { From a9887e9e0253a5a608601d738718e01fe08d3aaa Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Tue, 12 May 2015 07:11:45 -0700 Subject: [PATCH 127/150] Support compile with newer Lime --- openfl/display/Stage.hx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/openfl/display/Stage.hx b/openfl/display/Stage.hx index da36bf0968..a34d6027d8 100644 --- a/openfl/display/Stage.hx +++ b/openfl/display/Stage.hx @@ -777,6 +777,20 @@ class Stage extends DisplayObjectContainer implements IModule { + } + + + public function onTextEdit (text:String, start:Int, length:Int):Void { + + + + } + + + public function onTextInput (text:String):Void { + + + } From d74116ad018ef16b9a71b8118de0dff926a2d6af Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Tue, 12 May 2015 12:43:29 -0700 Subject: [PATCH 128/150] Update to 3.0.4 --- haxe/Timer.hx | 15 +++++---------- haxelib.json | 4 ++-- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/haxe/Timer.hx b/haxe/Timer.hx index bc05c111e7..788bf2fefc 100644 --- a/haxe/Timer.hx +++ b/haxe/Timer.hx @@ -1,5 +1,5 @@ package haxe; -#if (macro || (!neko && !cpp)) +#if (macro || (!neko && !cpp && !nodejs)) // Original haxe.Timer class @@ -41,7 +41,7 @@ package haxe; the child class. **/ class Timer { - #if (flash || js || java) + #if (flash || js || java || python) #if (flash || js) private var id : Null; @@ -62,12 +62,9 @@ class Timer { The accuracy of this may be platform-dependent. **/ public function new( time_ms : Int ){ - #if flash9 + #if flash var me = this; id = untyped __global__["flash.utils.setInterval"](function() { me.run(); },time_ms); - #elseif flash - var me = this; - id = untyped _global["setInterval"](function() { me.run(); },time_ms); #elseif js var me = this; id = untyped setInterval(function() me.run(),time_ms); @@ -89,10 +86,8 @@ class Timer { #if (flash || js) if( id == null ) return; - #if flash9 + #if flash untyped __global__["flash.utils.clearInterval"](id); - #elseif flash - untyped _global["clearInterval"](id); #elseif js untyped clearInterval(id); #end @@ -190,7 +185,7 @@ private class TimerTask extends java.util.TimerTask { this.timer = timer; } - @:overload public function run():Void { + @:overload override public function run():Void { timer.run(); } } diff --git a/haxelib.json b/haxelib.json index c2c927b83c..751776139d 100644 --- a/haxelib.json +++ b/haxelib.json @@ -4,7 +4,7 @@ "license": "MIT", "tags": [], "description": "The \"Open Flash Library\" for fast 2D development", - "version": "3.0.3", - "releasenote": "Improvements to text, sound, bitmapData.draw", + "version": "3.0.4", + "releasenote": "Big improvements to canvas Graphics accuracy, text input support, HTML5 scrollRect", "contributors": [ "singmajesty" ] } From 96352360f9736e18895b07904c4ebc41eff336da Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Tue, 12 May 2015 12:43:35 -0700 Subject: [PATCH 129/150] Update CHANGELOG --- CHANGELOG.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d0ef3891f..b4cea8ad6d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,26 @@ +3.0.4 (05/12/2015) +------------------ + +* Improved accuracy of HTML5 canvas Graphics renderer +* Added support for window hardware=false +* Added initial Cairo renderer support +* Made big improvements to HTML5 canvas TextField input +* Added MouseEvent.MOUSE_LEAVE event support +* Improved HTML5 canvas linear gradient support +* Improved Stage3D texture uploads +* Implemented BitmapData.getColorBoundsRect +* Improved checks for invalid BitmapData in Assets +* Improved beginBitmapFill for GL Graphics +* Improved pixel snapping support for GL rendering +* Improved cleanup of native sound channels +* Improved compatibility between Stage3D and internal GL rendering +* Fixed HTML5 canvas scrollRect +* Fixed handling of embedded fonts in some cases +* Fixed some issues with bounds calculations +* Fixed support for initial SoundTransform volume on native +* Improved non-blocking HTTPS support (legacy) + + 3.0.3 (04/21/2015) ------------------ From 3455ccccdb56a6dfad85f7f3a7ed3bacd42c7da6 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Tue, 12 May 2015 21:29:58 -0700 Subject: [PATCH 130/150] Improve Error classes --- openfl/errors/ArgumentError.hx | 6 ++++-- openfl/errors/EOFError.hx | 2 ++ openfl/errors/IOError.hx | 2 ++ openfl/errors/IllegalOperationError.hx | 6 ++++-- openfl/errors/RangeError.hx | 6 ++++-- openfl/errors/SecurityError.hx | 6 ++++-- openfl/errors/TypeError.hx | 6 ++++-- 7 files changed, 24 insertions(+), 10 deletions(-) diff --git a/openfl/errors/ArgumentError.hx b/openfl/errors/ArgumentError.hx index 10f3a807c3..560ba336e7 100644 --- a/openfl/errors/ArgumentError.hx +++ b/openfl/errors/ArgumentError.hx @@ -4,9 +4,11 @@ package openfl.errors; #if !flash class ArgumentError extends Error { - public function new (inMessage:String = "") { + public function new (message:String = "") { - super (inMessage); + super (message); + + name = "ArgumentError"; } diff --git a/openfl/errors/EOFError.hx b/openfl/errors/EOFError.hx index b6b81a679d..d7b30e21cd 100644 --- a/openfl/errors/EOFError.hx +++ b/openfl/errors/EOFError.hx @@ -19,6 +19,8 @@ class EOFError extends Error { super ("End of file was encountered", 2030); + name = "EOFError"; + } diff --git a/openfl/errors/IOError.hx b/openfl/errors/IOError.hx index b3337cd1c5..4d6622af49 100644 --- a/openfl/errors/IOError.hx +++ b/openfl/errors/IOError.hx @@ -8,6 +8,8 @@ class IOError extends Error { super (message); + name = "IOError"; + } diff --git a/openfl/errors/IllegalOperationError.hx b/openfl/errors/IllegalOperationError.hx index 557e07fefa..a420f0c70c 100644 --- a/openfl/errors/IllegalOperationError.hx +++ b/openfl/errors/IllegalOperationError.hx @@ -31,9 +31,11 @@ class IllegalOperationError extends Error { * * @param message A string associated with the error object. */ - public function new (inMessage:String = "") { + public function new (message:String = "") { - super (inMessage, 0); + super (message, 0); + + name = "IllegalOperationError"; } diff --git a/openfl/errors/RangeError.hx b/openfl/errors/RangeError.hx index b4cd239867..cecbee995f 100644 --- a/openfl/errors/RangeError.hx +++ b/openfl/errors/RangeError.hx @@ -4,9 +4,11 @@ package openfl.errors; #if !flash class RangeError extends Error { - public function new (inMessage:String = "") { + public function new (message:String = "") { - super (inMessage, 0); + super (message, 0); + + name = "RangeError"; } diff --git a/openfl/errors/SecurityError.hx b/openfl/errors/SecurityError.hx index e86788b289..499f11f2c8 100644 --- a/openfl/errors/SecurityError.hx +++ b/openfl/errors/SecurityError.hx @@ -4,9 +4,11 @@ package openfl.errors; #if !flash class SecurityError extends Error { - public function new (inMessage:String = "") { + public function new (message:String = "") { - super (inMessage, 0); + super (message, 0); + + name = "SecurityError"; } diff --git a/openfl/errors/TypeError.hx b/openfl/errors/TypeError.hx index 45bdb122fd..4870e6f397 100644 --- a/openfl/errors/TypeError.hx +++ b/openfl/errors/TypeError.hx @@ -4,9 +4,11 @@ package openfl.errors; #if !flash class TypeError extends Error { - public function new (inMessage:String = "") { + public function new (message:String = "") { - super (inMessage, 0); + super (message, 0); + + name = "TypeError"; } From 9d4aaf0356fbf7fff1f6d46dd219e1dcf2f0e907 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Wed, 13 May 2015 10:15:11 -0700 Subject: [PATCH 131/150] Fix dispatch order for events and don't handle preventDefault() the same as stopPropagation() --- openfl/display/DisplayObjectContainer.hx | 6 ++++-- openfl/events/Event.hx | 9 +++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/openfl/display/DisplayObjectContainer.hx b/openfl/display/DisplayObjectContainer.hx index 396d5ca4ba..7928e88224 100644 --- a/openfl/display/DisplayObjectContainer.hx +++ b/openfl/display/DisplayObjectContainer.hx @@ -635,7 +635,9 @@ class DisplayObjectContainer extends InteractiveObject { } - if (notifyChilden) { + var canceled = super.__broadcast (event, notifyChilden); + + if (!canceled && notifyChilden) { for (child in __children) { @@ -651,7 +653,7 @@ class DisplayObjectContainer extends InteractiveObject { } - return super.__broadcast (event, notifyChilden); + return canceled; } diff --git a/openfl/events/Event.hx b/openfl/events/Event.hx index 11eca7e27e..068cb3d46c 100644 --- a/openfl/events/Event.hx +++ b/openfl/events/Event.hx @@ -341,6 +341,7 @@ class Event { @:noCompletion private var __isCancelled:Bool; @:noCompletion private var __isCancelledNow:Bool; + @:noCompletion private var __preventDefault:Bool; /** @@ -408,7 +409,7 @@ class Event { */ public function isDefaultPrevented ():Bool { - return (__isCancelled || __isCancelledNow); + return __preventDefault; } @@ -421,7 +422,11 @@ class Event { */ public function preventDefault ():Void { - __isCancelled = true; + if (cancelable) { + + __preventDefault = true; + + } } From b510bd37c1c9f34c099415d4c785e4523f609abb Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Wed, 13 May 2015 11:10:59 -0700 Subject: [PATCH 132/150] Add hybrid to unit test --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 9682229241..405a750da2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,6 +40,7 @@ script: - haxelib run lime build neko - haxelib run lime build neko -Ddisable-cffi - haxelib run lime test neko -Dlegacy + - haxelib run lime test neko -Dhybrid - haxelib run munit test -as3 -norun - haxelib run munit test -browser phantomjs - haxelib run lime test linux From 85ff74f85681caf3554c87c940719a1b62886919 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Wed, 13 May 2015 11:12:20 -0700 Subject: [PATCH 133/150] Build fix --- openfl/_legacy/display/HybridStage.hx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/openfl/_legacy/display/HybridStage.hx b/openfl/_legacy/display/HybridStage.hx index 68a9d7e9dc..1c250cf909 100644 --- a/openfl/_legacy/display/HybridStage.hx +++ b/openfl/_legacy/display/HybridStage.hx @@ -190,6 +190,20 @@ class HybridStage extends ManagedStage implements IModule { } + public function onTextEdit (text:String, start:Int, length:Int):Void { + + + + } + + + public function onTextInput (text:String):Void { + + + + } + + public function onTouchMove (x:Float, y:Float, id:Int):Void { var flags = ManagedStage.efPrimaryTouch; From ea442d68b0dc56510ca364f8c82ec89e9485c2e4 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Wed, 13 May 2015 11:40:21 -0700 Subject: [PATCH 134/150] Update to 3.0.5 --- haxelib.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/haxelib.json b/haxelib.json index 751776139d..209b111f82 100644 --- a/haxelib.json +++ b/haxelib.json @@ -4,7 +4,7 @@ "license": "MIT", "tags": [], "description": "The \"Open Flash Library\" for fast 2D development", - "version": "3.0.4", - "releasenote": "Big improvements to canvas Graphics accuracy, text input support, HTML5 scrollRect", + "version": "3.0.5", + "releasenote": "Minor improvements to errors and events", "contributors": [ "singmajesty" ] } From dad01451ad28da05119957c35bcfd225dc9104bb Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Wed, 13 May 2015 11:40:28 -0700 Subject: [PATCH 135/150] Update CHANGELOG --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b4cea8ad6d..0588152096 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +3.0.5 (05/13/2015) +------------------ + +* Improved formatting for thrown errors on HTML5 +* Separated the behavior of event preventDefault from stopPropagation +* Fixed the event dispatch order for DisplayObjectContainer +* Fixed support for -Dhybrid using latest Lime release + + 3.0.4 (05/12/2015) ------------------ From d189c270a7b828eacd40ff4eacad396b748f5798 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Thu, 14 May 2015 01:07:01 -0700 Subject: [PATCH 136/150] Improve dispatch behavior (fixes openfl/lime#437) --- openfl/display/DisplayObjectContainer.hx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openfl/display/DisplayObjectContainer.hx b/openfl/display/DisplayObjectContainer.hx index 7928e88224..c6f58fc7e7 100644 --- a/openfl/display/DisplayObjectContainer.hx +++ b/openfl/display/DisplayObjectContainer.hx @@ -635,9 +635,9 @@ class DisplayObjectContainer extends InteractiveObject { } - var canceled = super.__broadcast (event, notifyChilden); + var result = super.__broadcast (event, notifyChilden); - if (!canceled && notifyChilden) { + if (!event.__isCancelled && notifyChilden) { for (child in __children) { @@ -653,7 +653,7 @@ class DisplayObjectContainer extends InteractiveObject { } - return canceled; + return result; } From 3b3e0ab355f85a8ba09992910243068ca26e9d65 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Thu, 14 May 2015 01:08:24 -0700 Subject: [PATCH 137/150] Update to 3.0.6 --- haxelib.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/haxelib.json b/haxelib.json index 209b111f82..ac6c54a0fa 100644 --- a/haxelib.json +++ b/haxelib.json @@ -4,7 +4,7 @@ "license": "MIT", "tags": [], "description": "The \"Open Flash Library\" for fast 2D development", - "version": "3.0.5", - "releasenote": "Minor improvements to errors and events", + "version": "3.0.6", + "releasenote": "Minor fix", "contributors": [ "singmajesty" ] } From 235a44fddb0945b234a2f56c56d70de10091e5c0 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Thu, 14 May 2015 01:08:30 -0700 Subject: [PATCH 138/150] Update CHANGELOG --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0588152096..01ffc34241 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +3.0.6 (05/14/2015) +------------------ + +* Fix regression in event dispatch behavior + + 3.0.5 (05/13/2015) ------------------ From b1b094fbe41acf6334096778711cbd77f5ea3494 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Thu, 14 May 2015 16:41:11 -0700 Subject: [PATCH 139/150] Hook into Lime frameRate support --- openfl/display/Stage.hx | 53 +++++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/openfl/display/Stage.hx b/openfl/display/Stage.hx index a34d6027d8..0c7c673d89 100644 --- a/openfl/display/Stage.hx +++ b/openfl/display/Stage.hx @@ -319,7 +319,7 @@ class Stage extends DisplayObjectContainer implements IModule { * For more information, see the "Security" chapter in * the ActionScript 3.0 Developer's Guide. */ - public var frameRate:Float; + public var frameRate (get, set):Float; /** * A value from the StageQuality class that specifies which rendering quality @@ -579,7 +579,6 @@ class Stage extends DisplayObjectContainer implements IModule { align = StageAlign.TOP_LEFT; allowsFullScreen = false; - frameRate = 60; quality = StageQuality.HIGH; scaleMode = StageScaleMode.NO_SCALE; stageFocusRect = true; @@ -1586,6 +1585,34 @@ class Stage extends DisplayObjectContainer implements IModule { } + @:noCompletion private inline function get_displayState ():StageDisplayState { + + return __displayState; + + } + + + @:noCompletion private function set_displayState (value:StageDisplayState):StageDisplayState { + + switch (value) { + + case NORMAL: + + //Lib.application.window.minimized = false; + Lib.application.window.fullscreen = false; + + default: + + //Lib.application.window.minimized = false; + Lib.application.window.fullscreen = true; + + } + + return __displayState = value; + + } + + @:noCompletion private function get_focus ():InteractiveObject { return __focus; @@ -1626,30 +1653,16 @@ class Stage extends DisplayObjectContainer implements IModule { } - @:noCompletion private inline function get_displayState ():StageDisplayState { + @:noCompletion private function get_frameRate ():Float { - return __displayState; + return Lib.application.frameRate; } - @:noCompletion private function set_displayState (value:StageDisplayState):StageDisplayState { + @:noCompletion private function set_frameRate (value:Float):Float { - switch (value) { - - case NORMAL: - - //Lib.application.window.minimized = false; - Lib.application.window.fullscreen = false; - - default: - - //Lib.application.window.minimized = false; - Lib.application.window.fullscreen = true; - - } - - return __displayState = value; + return Lib.application.frameRate = value; } From 1185f542f61f571191afaf757efa5d7391112b26 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Fri, 15 May 2015 10:31:27 -0700 Subject: [PATCH 140/150] Work on URLLoader --- openfl/net/URLLoader.hx | 207 ++++++++++++++++++++++++++++++++- openfl/net/URLRequestMethod.hx | 14 +-- 2 files changed, 213 insertions(+), 8 deletions(-) diff --git a/openfl/net/URLLoader.hx b/openfl/net/URLLoader.hx index 66138e9a80..b545a69614 100644 --- a/openfl/net/URLLoader.hx +++ b/openfl/net/URLLoader.hx @@ -1,6 +1,8 @@ package openfl.net; #if !flash #if (!openfl_legacy || disable_legacy_networking) +import lime.app.Event; +import lime.utils.ByteArray; import openfl.events.Event; import openfl.events.EventDispatcher; import openfl.events.HTTPStatusEvent; @@ -17,6 +19,14 @@ import js.Browser; import js.Lib; #end +#if lime_curl +import lime.net.curl.CURL; +import lime.net.curl.CURLEasy; +import lime.net.curl.CURLCode; +import lime.net.curl.CURLInfo; +import lime.net.curl.CURLOption; +#end + /** * The URLLoader class downloads data from a URL as text, binary data, or @@ -149,6 +159,12 @@ class URLLoader extends EventDispatcher { public var dataFormat (default, set):URLLoaderDataFormat; + #if lime_curl + private var __curl:CURL; + private var __data:String; + #end + + /** * Creates a URLLoader object. * @@ -165,6 +181,11 @@ class URLLoader extends EventDispatcher { bytesTotal = 0; dataFormat = URLLoaderDataFormat.TEXT; + #if lime_curl + __data = ""; + __curl = CURLEasy.init (); + #end + if (request != null) { load (request); @@ -182,7 +203,9 @@ class URLLoader extends EventDispatcher { */ public function close ():Void { - + #if lime_curl + CURLEasy.cleanup (__curl); + #end } @@ -299,6 +322,8 @@ class URLLoader extends EventDispatcher { #if (js && html5) requestUrl (request.url, request.method, request.data, request.formatRequestHeaders ()); + #elseif lime_curl + requestUrl (request.url, request.method, request.data, request.formatRequestHeaders ()); #end } @@ -466,6 +491,186 @@ class URLLoader extends EventDispatcher { }; } + + + #elseif lime_curl + + + private function prepareData (data:Dynamic):ByteArray { + + var uri:ByteArray = new ByteArray (); + + if (Std.is (data, ByteArray)) { + + var data:ByteArray = cast data; + uri = data; + + } else if (Std.is (data, URLVariables)) { + + var data:URLVariables = cast data; + var tmp:String = ""; + + for (p in Reflect.fields (data)) { + + if (tmp.length != 0) tmp += "&"; + tmp += StringTools.urlEncode (p) + "=" + StringTools.urlEncode (Reflect.field (data, p)); + + } + + uri.writeUTFBytes (tmp); + + } else { + + if (data != null) { + + uri.writeUTFBytes (Std.string (data)); + + } + + } + + return uri; + + } + + + private function requestUrl (url:String, method:URLRequestMethod, data:Dynamic, requestHeaders:Array):Void { + + var uri = prepareData(data); + uri.position = 0; + + __data = ""; + bytesLoaded = 0; + bytesTotal = 0; + + CURLEasy.reset (__curl); + CURLEasy.setopt (__curl, URL, url); + + switch (method) { + + case HEAD: + + CURLEasy.setopt(__curl, NOBODY, true); + + case GET: + + CURLEasy.setopt(__curl, HTTPGET, true); + + case POST: + + CURLEasy.setopt(__curl, POST, true); + CURLEasy.setopt(__curl, READFUNCTION, readFunction.bind(_, uri)); + CURLEasy.setopt(__curl, POSTFIELDSIZE, uri.length); + CURLEasy.setopt(__curl, INFILESIZE, uri.length); + + case PUT: + + CURLEasy.setopt(__curl, UPLOAD, true); + CURLEasy.setopt(__curl, READFUNCTION, readFunction.bind(_, uri)); + CURLEasy.setopt(__curl, INFILESIZE, uri.length); + + case _: + + CURLEasy.setopt(__curl, CUSTOMREQUEST, cast method); + CURLEasy.setopt(__curl, READFUNCTION, readFunction.bind(_, uri)); + CURLEasy.setopt(__curl, INFILESIZE, uri.length); + + } + + var headers:Array = []; + headers.push ("Expect: "); // removes the default cURL value + + for (requestHeader in requestHeaders) { + + headers.push ('${requestHeader.name}: ${requestHeader.value}'); + + } + + CURLEasy.setopt (__curl, HTTPHEADER, headers); + + CURLEasy.setopt (__curl, PROGRESSFUNCTION, progressFunction); + + CURLEasy.setopt (__curl, WRITEFUNCTION, writeFunction); + CURLEasy.setopt (__curl, HEADERFUNCTION, headerFunction); + + CURLEasy.setopt (__curl, SSL_VERIFYPEER, false); + CURLEasy.setopt (__curl, SSL_VERIFYHOST, false); + CURLEasy.setopt (__curl, USERAGENT, "libcurl-agent/1.0"); + CURLEasy.setopt (__curl, CONNECTTIMEOUT, 30); + + var result = CURLEasy.perform (__curl); + var responseCode = CURLEasy.getinfo (__curl, RESPONSE_CODE); + + if (result == CURLCode.OK) { + + /* + switch(dataFormat) { + case BINARY: this.data = __data; + default: this.data = __data.asString(); + } + */ + this.data = __data; + + onStatus (Std.parseInt (responseCode)); + + var evt = new Event (Event.COMPLETE); + evt.currentTarget = this; + dispatchEvent (evt); + + } else { + + onError ("Problem with curl: " + result); + + } + + } + + + private function writeFunction (output:String, size:Int, nmemb:Int):Int { + + __data += output; + return size * nmemb; + + } + + + private function headerFunction (output:String, size:Int, nmemb:Int):Int { + + // TODO + return size * nmemb; + + } + + + private function progressFunction (dltotal:Float, dlnow:Float, uptotal:Float, upnow:Float):Int { + + if (upnow > bytesLoaded || dlnow > bytesLoaded || uptotal > bytesTotal || dltotal > bytesTotal) { + + if (upnow > bytesLoaded) bytesLoaded = Std.int (upnow); + if (dlnow > bytesLoaded) bytesLoaded = Std.int (dlnow); + if (uptotal > bytesTotal) bytesTotal = Std.int (uptotal); + if (dltotal > bytesTotal) bytesTotal = Std.int (dltotal); + + var evt = new ProgressEvent (ProgressEvent.PROGRESS); + evt.currentTarget = this; + evt.bytesLoaded = bytesLoaded; + evt.bytesTotal = bytesTotal; + dispatchEvent (evt); + + } + + return 0; + + } + + + private function readFunction (max:Int, input:ByteArray):String { + + return input == null ? "" : input.readUTFBytes (Std.int (Math.min (max, input.length - input.position))); + + } + + #end diff --git a/openfl/net/URLRequestMethod.hx b/openfl/net/URLRequestMethod.hx index 5da36ee804..be572d1f3c 100644 --- a/openfl/net/URLRequestMethod.hx +++ b/openfl/net/URLRequestMethod.hx @@ -6,27 +6,27 @@ package openfl.net; #if !flash #if (!openfl_legacy || disable_legacy_networking) * URLRequest object should use the POST method or the * GET method when sending data to a server. */ -class URLRequestMethod { +@:enum abstract URLRequestMethod(String) from String to String { /** * Specifies that the URLRequest object is a DELETE. */ - public static var DELETE:String = "DELETE"; + var DELETE = "DELETE"; /** * Specifies that the URLRequest object is a GET. */ - public static var GET:String = "GET"; + var GET = "GET"; /** * Specifies that the URLRequest object is a HEAD. */ - public static var HEAD:String = "HEAD"; + var HEAD = "HEAD"; /** * Specifies that the URLRequest object is OPTIONS. */ - public static var OPTIONS:String = "OPTIONS"; + var OPTIONS = "OPTIONS"; /** * Specifies that the URLRequest object is a POST. @@ -36,12 +36,12 @@ class URLRequestMethod { * that uses the POST method(one that has its method property * set to URLRequestMethod.POST) as using the GET method.

*/ - public static var POST:String = "POST"; + var POST = "POST"; /** * Specifies that the URLRequest object is a PUT. */ - public static var PUT:String = "PUT"; + var PUT = "PUT"; } From 92647f46e908aa1945b52b58daf634c59a29b18f Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Fri, 15 May 2015 13:41:27 -0700 Subject: [PATCH 141/150] Rough implementation of GameInput API --- openfl/display/Stage.hx | 12 +-- openfl/events/GameInputEvent.hx | 63 +++++++++++++ openfl/ui/GameInput.hx | 155 ++++++++++++++++++++++++++++++++ openfl/ui/GameInputControl.hx | 54 +++++++++++ openfl/ui/GameInputDevice.hx | 142 +++++++++++++++++++++++++++++ 5 files changed, 421 insertions(+), 5 deletions(-) create mode 100644 openfl/events/GameInputEvent.hx create mode 100644 openfl/ui/GameInput.hx create mode 100644 openfl/ui/GameInputControl.hx create mode 100644 openfl/ui/GameInputDevice.hx diff --git a/openfl/display/Stage.hx b/openfl/display/Stage.hx index 0c7c673d89..18cdd21efc 100644 --- a/openfl/display/Stage.hx +++ b/openfl/display/Stage.hx @@ -34,6 +34,7 @@ import openfl.geom.Matrix; import openfl.geom.Point; import openfl.geom.Rectangle; import openfl.text.TextField; +import openfl.ui.GameInput; import openfl.ui.Keyboard; import openfl.ui.KeyLocation; @@ -163,6 +164,7 @@ import js.Browser; */ @:access(openfl.events.Event) +@:access(openfl.ui.GameInput) @:access(openfl.ui.Keyboard) @@ -667,35 +669,35 @@ class Stage extends DisplayObjectContainer implements IModule { public function onGamepadAxisMove (gamepad:Gamepad, axis:GamepadAxis, value:Float):Void { - + GameInput.__onGamepadAxisMove (gamepad, axis, value); } public function onGamepadButtonDown (gamepad:Gamepad, button:GamepadButton):Void { - + GameInput.__onGamepadButtonDown (gamepad, button); } public function onGamepadButtonUp (gamepad:Gamepad, button:GamepadButton):Void { - + GameInput.__onGamepadButtonUp (gamepad, button); } public function onGamepadConnect (gamepad:Gamepad):Void { - + GameInput.__onGamepadConnect (gamepad); } public function onGamepadDisconnect (gamepad:Gamepad):Void { - + GameInput.__onGamepadDisconnect (gamepad); } diff --git a/openfl/events/GameInputEvent.hx b/openfl/events/GameInputEvent.hx new file mode 100644 index 0000000000..ebcc171c5c --- /dev/null +++ b/openfl/events/GameInputEvent.hx @@ -0,0 +1,63 @@ +package openfl.events; #if !flash + + +import openfl.ui.GameInputDevice; + + +/** + * The GameInputEvent class represents an event that is dispatched when a game input device has either been added or removed from the application platform. A game input device also dispatches events when it is turned on or off. + */ +class GameInputEvent extends Event { + + + /** + * Indicates that a compatible device has been connected or turned on. + */ + public static var DEVICE_ADDED = "deviceAdded"; + + /** + * Indicates that one of the enumerated devices has been disconnected or turned off. + */ + public static var DEVICE_REMOVED = "deviceRemoved"; + + /** + * Dispatched when a game input device is connected but is not usable. + */ + public static var DEVICE_UNUSABLE = "deviceUnusable"; + + + /** + * Returns a reference to the device that was added or removed. When a device is added, use this property to get a reference to the new device, instead of enumerating all of the devices to find the new one. + */ + public var device (default, null):GameInputDevice; + + + public function new (type:String, bubbles:Bool = true, cancelable:Bool = false, device:GameInputDevice = null) { + + super (type, bubbles, cancelable); + + this.device = device; + + } + + + public override function clone ():Event { + + return new GameInputEvent (type, bubbles, cancelable, device); + + } + + + public override function toString ():String { + + return "[GameInputEvent type=" + type + " bubbles=" + bubbles + " cancelable=" + cancelable + " device=" + device + "]"; + + } + + +} + + +#else +typedef GameInputEvent = flash.events.GameInputEvent; +#end \ No newline at end of file diff --git a/openfl/ui/GameInput.hx b/openfl/ui/GameInput.hx new file mode 100644 index 0000000000..a71574ee34 --- /dev/null +++ b/openfl/ui/GameInput.hx @@ -0,0 +1,155 @@ +package openfl.ui; #if !flash + + +import lime.ui.Gamepad; +import lime.ui.GamepadAxis; +import lime.ui.GamepadButton; +import openfl.events.Event; +import openfl.events.EventDispatcher; +import openfl.events.GameInputEvent; + +@:access(openfl.ui.GameInputControl) +@:access(openfl.ui.GameInputDevice) + + +class GameInput extends EventDispatcher { + + + public static var isAvailable = true; + public static var numDevices (default, null) = 0; + + private static var __devices = new Map (); + private static var __instances = []; + + + public function new () { + + super (); + + __instances.push (this); + + } + + + public static function getDeviceAt (index:Int):GameInputDevice { + + if (Gamepad.devices.exists (index)) { + + return __devices.get (Gamepad.devices.get (index)); + + } + + return null; + + } + + + private static function __onGamepadAxisMove (gamepad:Gamepad, axis:GamepadAxis, value:Float):Void { + + var device = __devices.get (gamepad); + + if (device.enabled) { + + if (!device.__axis.exists (axis)) { + + var control = new GameInputControl (device, "AXIS_" + axis, -1, 1); + device.__axis.set (axis, control); + device.__controls.push (control); + + } + + var control = device.__axis.get (axis); + control.value = value; + control.dispatchEvent (new Event (Event.CHANGE)); + + } + + } + + + private static function __onGamepadButtonDown (gamepad:Gamepad, button:GamepadButton):Void { + + var device = __devices.get (gamepad); + + if (device.enabled) { + + if (!device.__button.exists (button)) { + + var control = new GameInputControl (device, "BUTTON_" + button, 0, 1); + device.__button.set (button, control); + device.__controls.push (control); + + } + + var control = device.__button.get (button); + control.value = 1; + control.dispatchEvent (new Event (Event.CHANGE)); + + } + + } + + + private static function __onGamepadButtonUp (gamepad:Gamepad, button:GamepadButton):Void { + + var device = __devices.get (gamepad); + + if (device.enabled) { + + if (!device.__button.exists (button)) { + + var control = new GameInputControl (device, "BUTTON_" + button, 0, 1); + device.__button.set (button, control); + device.__controls.push (control); + + } + + var control = device.__button.get (button); + control.value = 0; + control.dispatchEvent (new Event (Event.CHANGE)); + + } + + } + + + private static function __onGamepadConnect (gamepad:Gamepad):Void { + + var device = new GameInputDevice (gamepad); + __devices.set (gamepad, device); + + for (instance in __instances) { + + instance.dispatchEvent (new GameInputEvent (GameInputEvent.DEVICE_ADDED, device)); + + } + + } + + + private static function __onGamepadDisconnect (gamepad:Gamepad):Void { + + var device = __devices.get (gamepad); + + if (device != null) { + + __devices.remove (gamepad); + + for (instance in __instances) { + + instance.dispatchEvent (new GameInputEvent (GameInputEvent.DEVICE_REMOVED, device)); + + } + + } + + } + + + +} + + +#else +typedef GameInput = flash.ui.GameInput; +#end \ No newline at end of file diff --git a/openfl/ui/GameInputControl.hx b/openfl/ui/GameInputControl.hx new file mode 100644 index 0000000000..60421f0a5d --- /dev/null +++ b/openfl/ui/GameInputControl.hx @@ -0,0 +1,54 @@ +package openfl.ui; #if !flash + + +import openfl.events.EventDispatcher; + + +class GameInputControl extends EventDispatcher { + + + /** + * Returns the GameInputDevice object that contains this control. + */ + public var device (default, null):GameInputDevice; + + /** + * Returns the id of this control. + */ + public var id (default, null):String; + + /** + * Returns the maximum value for this control. + */ + public var maxValue (default, null):Float; + + /** + * Returns the minimum value for this control. + */ + public var minValue (default, null):Float; + + /** + * Returns the value for this control. + */ + public var value (default, null):Float; + + + private function new (device:GameInputDevice, id:String, minValue:Float, maxValue:Float, value:Float = 0) { + + super (); + + this.device = device; + this.id = id; + this.minValue = minValue; + this.maxValue = maxValue; + this.value = value; + + } + + +} + + +#else +typedef GameInputControl = flash.ui.GameInputControl; +#end \ No newline at end of file diff --git a/openfl/ui/GameInputDevice.hx b/openfl/ui/GameInputDevice.hx new file mode 100644 index 0000000000..5542dccd5d --- /dev/null +++ b/openfl/ui/GameInputDevice.hx @@ -0,0 +1,142 @@ +package openfl.ui; #if !flash + + +import lime.ui.Gamepad; +import openfl.utils.ByteArray; + +@:access(openfl.ui.GameInputControl) + + +class GameInputDevice { + + + public static var MAX_BUFFER_SIZE = 32000; + + /** + * Enables or disables this device. + */ + public var enabled:Bool; + + /** + * Returns the ID of this device. + */ + public var id (default, null):String; + + /** + * Returns the name of this device. + */ + public var name (default, null):String; + + /** + * Returns the number of controls on this device. + */ + public var numControls (get, never):Int; + + /** + * Specifies the rate (in milliseconds) at which to retrieve control values. + */ + public var sampleInterval:Int; + + @:noCompletion private var __axis = new Map (); + @:noCompletion private var __button = new Map (); + @:noCompletion private var __controls = new Array (); + @:noCompletion private var __gamepad:Gamepad; + + + @:noCompletion private function new (gamepad:Gamepad) { + + __gamepad = gamepad; + var control; + + for (i in 0...6) { + + control = new GameInputControl (this, "AXIS_" + i, -1, 1); + __axis.set (i, control); + __controls.push (control); + + } + + for (i in 0...15) { + + control = new GameInputControl (this, "BUTTON_" + i, 0, 1); + __button.set (i, control); + __controls.push (control); + + } + + } + + + /** + * Writes cached sample values to the ByteArray. + * @param data + * @param append + * @return + */ + public function getCachedSamples (data:ByteArray, append:Bool = false):Int { + + return 0; + + } + + + /** + * Retrieves a specific control from a device. + * @param i + * @return + */ + public function getControlAt (i:Int):GameInputControl { + + if (i >= 0 && i < __controls.length) { + + return __controls[i]; + + } + + return null; + + } + + + /** + * Requests this device to start keeping a cache of sampled values. + * @param numSamples + * @param controls + */ + public function startCachingSamples (numSamples:Int, controls:Vector):Void { + + + + } + + + /** + * Stops sample caching. + */ + public function stopCachingSamples ():Void { + + + + } + + + + + // Get & Set Methods + + + + + private function get_numControls ():Int { + + return __controls.length; + + } + + +} + + +#else +typedef GameInputDevice = flash.ui.GameInputDevice; +#end \ No newline at end of file From b1c2ed3be41ada1742e8dbbb8c5a65c9c2137665 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Fri, 15 May 2015 13:49:02 -0700 Subject: [PATCH 142/150] Set numDevices and game input device name and id --- openfl/ui/GameInput.hx | 4 +++- openfl/ui/GameInputDevice.hx | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/openfl/ui/GameInput.hx b/openfl/ui/GameInput.hx index a71574ee34..d458f080c2 100644 --- a/openfl/ui/GameInput.hx +++ b/openfl/ui/GameInput.hx @@ -115,8 +115,9 @@ class GameInput extends EventDispatcher { private static function __onGamepadConnect (gamepad:Gamepad):Void { - var device = new GameInputDevice (gamepad); + var device = new GameInputDevice (gamepad.guid, gamepad.name); __devices.set (gamepad, device); + numDevices = Lambda.count (__devices); for (instance in __instances) { @@ -134,6 +135,7 @@ class GameInput extends EventDispatcher { if (device != null) { __devices.remove (gamepad); + numDevices = Lambda.count (__devices); for (instance in __instances) { diff --git a/openfl/ui/GameInputDevice.hx b/openfl/ui/GameInputDevice.hx index 5542dccd5d..7abaa2ae63 100644 --- a/openfl/ui/GameInputDevice.hx +++ b/openfl/ui/GameInputDevice.hx @@ -43,9 +43,11 @@ class GameInputDevice { @:noCompletion private var __gamepad:Gamepad; - @:noCompletion private function new (gamepad:Gamepad) { + @:noCompletion private function new (id:String, name:String) { + + this.id = id; + this.name = name; - __gamepad = gamepad; var control; for (i in 0...6) { From 6919dbba8f76e2b32d65cabe2128f545b44046ae Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Fri, 15 May 2015 16:45:47 -0700 Subject: [PATCH 143/150] Improve Cairo scrollRect support --- .../_internal/renderer/cairo/CairoBitmap.hx | 28 +++++++++---------- openfl/_internal/renderer/cairo/CairoShape.hx | 22 +++++++-------- openfl/display/DisplayObjectContainer.hx | 24 ++++++++-------- 3 files changed, 36 insertions(+), 38 deletions(-) diff --git a/openfl/_internal/renderer/cairo/CairoBitmap.hx b/openfl/_internal/renderer/cairo/CairoBitmap.hx index ec8a21b4cc..98c82a3ad0 100644 --- a/openfl/_internal/renderer/cairo/CairoBitmap.hx +++ b/openfl/_internal/renderer/cairo/CairoBitmap.hx @@ -5,6 +5,7 @@ package openfl._internal.renderer.cairo; import cpp.Pointer; #end import lime.graphics.cairo.CairoFormat; +import lime.graphics.cairo.CairoPattern; import lime.graphics.cairo.CairoSurface; import openfl._internal.renderer.RenderSession; import openfl.display.Bitmap; @@ -37,7 +38,7 @@ class CairoBitmap { //context.globalAlpha = bitmap.__worldAlpha; var transform = bitmap.__worldTransform; - //var scrollRect = bitmap.scrollRect; + var scrollRect = bitmap.scrollRect; if (renderSession.roundPixels) { @@ -65,15 +66,20 @@ class CairoBitmap { var surface = bitmap.bitmapData.getSurface (); if (surface != null) { - - //if (scrollRect == null) { - //cairo.setSourceRGB (1, 0, 0); - //cairo.newPath (); - //trace (image.width); - //cairo.rectangle (0, 0, image.width, image.height); cairo.setSourceSurface (surface, 0, 0); + if (scrollRect != null) { + + cairo.pushGroup (); + cairo.setSourceSurface (surface, 0, 0); + cairo.newPath (); + cairo.rectangle (scrollRect.x, scrollRect.y, scrollRect.width, scrollRect.height); + cairo.fill (); + cairo.popGroupToSource (); + + } + if (bitmap.__worldAlpha == 1) { cairo.paint (); @@ -84,14 +90,6 @@ class CairoBitmap { } - //context.drawImage (bitmap.bitmapData.__image.src, 0, 0); - - //} else { - // - //context.drawImage (bitmap.bitmapData.__image.src, scrollRect.x, scrollRect.y, scrollRect.width, scrollRect.height, scrollRect.x, scrollRect.y, scrollRect.width, scrollRect.height); - // - //} - } //if (!bitmap.smoothing) { diff --git a/openfl/_internal/renderer/cairo/CairoShape.hx b/openfl/_internal/renderer/cairo/CairoShape.hx index 8dabadc317..a20b2adefe 100644 --- a/openfl/_internal/renderer/cairo/CairoShape.hx +++ b/openfl/_internal/renderer/cairo/CairoShape.hx @@ -49,19 +49,19 @@ class CairoShape { } cairo.setSourceSurface (graphics.__cairo.target, graphics.__bounds.x, graphics.__bounds.y); + + if (scrollRect != null) { + + cairo.pushGroup (); + cairo.newPath (); + cairo.rectangle (graphics.__bounds.x + scrollRect.x, graphics.__bounds.y + scrollRect.y, scrollRect.width, scrollRect.height); + cairo.fill (); + cairo.popGroupToSource (); + + } + cairo.paintWithAlpha (shape.__worldAlpha); - // - //if (scrollRect == null) { - // - //context.drawImage (graphics.__canvas, graphics.__bounds.x, graphics.__bounds.y); - // - //} else { - // - //context.drawImage (graphics.__canvas, scrollRect.x - graphics.__bounds.x, scrollRect.y - graphics.__bounds.y, scrollRect.width, scrollRect.height, graphics.__bounds.x + scrollRect.x, graphics.__bounds.y + scrollRect.y, scrollRect.width, scrollRect.height); - // - //} - // if (shape.__mask != null) { renderSession.maskManager.popMask (); diff --git a/openfl/display/DisplayObjectContainer.hx b/openfl/display/DisplayObjectContainer.hx index c6f58fc7e7..fcd88c6df0 100644 --- a/openfl/display/DisplayObjectContainer.hx +++ b/openfl/display/DisplayObjectContainer.hx @@ -777,12 +777,12 @@ class DisplayObjectContainer extends InteractiveObject { super.__renderCairo (renderSession); - //if (scrollRect != null) { - // - //renderSession.maskManager.pushRect (scrollRect, __worldTransform); - // - //} - // + if (scrollRect != null) { + + renderSession.maskManager.pushRect (scrollRect, __worldTransform); + + } + if (__mask != null) { renderSession.maskManager.pushMask (__mask); @@ -802,12 +802,12 @@ class DisplayObjectContainer extends InteractiveObject { renderSession.maskManager.popMask (); } - // - //if (scrollRect != null) { - // - //renderSession.maskManager.popMask (); - // - //} + + if (scrollRect != null) { + + renderSession.maskManager.popMask (); + + } } From 9d9b831943686b6eefd13768840e56d1808e2e20 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Fri, 15 May 2015 17:10:53 -0700 Subject: [PATCH 144/150] Improve Cairo masking --- .../_internal/renderer/cairo/CairoMaskManager.hx | 5 ++--- openfl/display/DisplayObjectContainer.hx | 14 +++++++------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/openfl/_internal/renderer/cairo/CairoMaskManager.hx b/openfl/_internal/renderer/cairo/CairoMaskManager.hx index 6998820a80..c87c5e38a2 100644 --- a/openfl/_internal/renderer/cairo/CairoMaskManager.hx +++ b/openfl/_internal/renderer/cairo/CairoMaskManager.hx @@ -34,8 +34,7 @@ class CairoMaskManager extends AbstractMaskManager { cairo.newPath (); mask.__renderCairoMask (renderSession); - - cairo.clipPreserve (); + cairo.clip (); //mask.worldAlpha = cacheAlpha; @@ -51,7 +50,7 @@ class CairoMaskManager extends AbstractMaskManager { cairo.newPath (); cairo.rectangle (rect.x, rect.y, rect.width, rect.height); - cairo.clipPreserve (); + cairo.clip (); } diff --git a/openfl/display/DisplayObjectContainer.hx b/openfl/display/DisplayObjectContainer.hx index fcd88c6df0..f1f357a061 100644 --- a/openfl/display/DisplayObjectContainer.hx +++ b/openfl/display/DisplayObjectContainer.hx @@ -820,16 +820,16 @@ class DisplayObjectContainer extends InteractiveObject { } - var bounds = new Rectangle (); - __getLocalBounds (bounds); + //var bounds = new Rectangle (); + //__getLocalBounds (bounds); + // + //renderSession.cairo.rectangle (0, 0, bounds.width, bounds.height); - renderSession.cairo.rectangle (0, 0, bounds.width, bounds.height); - - /*for (child in __children) { + for (child in __children) { - child.__renderMask (renderSession); + child.__renderCairoMask (renderSession); - }*/ + } } From 56ea01013374567091a0e0553f9b7f2e434e8066 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Fri, 15 May 2015 17:20:35 -0700 Subject: [PATCH 145/150] Improve code completion --- openfl/_legacy/display/SimpleButton.hx | 4 ++-- openfl/text/TextField.hx | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/openfl/_legacy/display/SimpleButton.hx b/openfl/_legacy/display/SimpleButton.hx index 74077bb64f..a13e685577 100644 --- a/openfl/_legacy/display/SimpleButton.hx +++ b/openfl/_legacy/display/SimpleButton.hx @@ -76,7 +76,7 @@ class SimpleButton extends InteractiveObject { } - public function set_overState (value:DisplayObject):DisplayObject { + private function set_overState (value:DisplayObject):DisplayObject { overState = value; lime_simple_button_set_state (__handle, 2, value == null ? null : value.__handle); @@ -106,7 +106,7 @@ class SimpleButton extends InteractiveObject { } - public function set_upState (value:DisplayObject):DisplayObject { + private function set_upState (value:DisplayObject):DisplayObject { upState = value; lime_simple_button_set_state (__handle, 0, value == null ? null : value.__handle); diff --git a/openfl/text/TextField.hx b/openfl/text/TextField.hx index 2a7da60816..db32e3f9c6 100644 --- a/openfl/text/TextField.hx +++ b/openfl/text/TextField.hx @@ -2156,14 +2156,14 @@ class TextField extends InteractiveObject { } - @:noCompletion public function get_textColor ():Int { + @:noCompletion private function get_textColor ():Int { return __textFormat.color; } - @:noCompletion public function set_textColor (value:Int):Int { + @:noCompletion private function set_textColor (value:Int):Int { if (value != __textFormat.color) __dirty = true; @@ -2181,7 +2181,7 @@ class TextField extends InteractiveObject { } - @:noCompletion public function get_textWidth ():Float { + @:noCompletion private function get_textWidth ():Float { #if (js && html5) @@ -2224,7 +2224,7 @@ class TextField extends InteractiveObject { } - @:noCompletion public function get_textHeight ():Float { + @:noCompletion private function get_textHeight ():Float { #if (js && html5) @@ -2264,7 +2264,7 @@ class TextField extends InteractiveObject { } - @:noCompletion public function set_type (value:TextFieldType):TextFieldType { + @:noCompletion private function set_type (value:TextFieldType):TextFieldType { if (value != type) { @@ -2289,7 +2289,7 @@ class TextField extends InteractiveObject { } - override public function get_width ():Float { + override private function get_width ():Float { if (autoSize == TextFieldAutoSize.LEFT) { @@ -2305,7 +2305,7 @@ class TextField extends InteractiveObject { } - override public function set_width (value:Float):Float { + override private function set_width (value:Float):Float { if (scaleX != 1 || __width != value) { @@ -2320,14 +2320,14 @@ class TextField extends InteractiveObject { } - @:noCompletion public function get_wordWrap ():Bool { + @:noCompletion private function get_wordWrap ():Bool { return wordWrap; } - @:noCompletion public function set_wordWrap (value:Bool):Bool { + @:noCompletion private function set_wordWrap (value:Bool):Bool { //if (value != wordWrap) __dirty = true; return wordWrap = value; From bb9045a280db9bc4f9a1bd3bc3cd7acdf8f95bc4 Mon Sep 17 00:00:00 2001 From: Kane Wallmann Date: Sat, 16 May 2015 19:20:04 +1000 Subject: [PATCH 146/150] Enhanced Cairo graphics renderer --- .../_internal/renderer/cairo/CairoGraphics.hx | 533 +++++++++--------- openfl/display/Graphics.hx | 9 +- 2 files changed, 267 insertions(+), 275 deletions(-) diff --git a/openfl/_internal/renderer/cairo/CairoGraphics.hx b/openfl/_internal/renderer/cairo/CairoGraphics.hx index 9af1ca77cf..46aa79d851 100644 --- a/openfl/_internal/renderer/cairo/CairoGraphics.hx +++ b/openfl/_internal/renderer/cairo/CairoGraphics.hx @@ -11,7 +11,10 @@ import openfl._internal.renderer.RenderSession; import openfl.display.BitmapData; import openfl.display.CapsStyle; import openfl.display.DisplayObject; +import openfl.display.GradientType; import openfl.display.Graphics; +import openfl.display.InterpolationMethod; +import openfl.display.SpreadMethod; import openfl.geom.Matrix; import openfl.geom.Point; import openfl.geom.Rectangle; @@ -31,8 +34,6 @@ class CairoGraphics { private static var SIN45 = 0.70710678118654752440084436210485; private static var TAN22 = 0.4142135623730950488016887242097; - private static var bitmapFill:BitmapData; - private static var bitmapRepeat:Bool; private static var bounds:Rectangle; private static var cairo:Cairo; private static var fillCommands:Array; @@ -45,34 +46,14 @@ class CairoGraphics { private static var strokeCommands:Array; private static var strokePattern:CairoPattern; - - private static function beginPatternFill (bitmapFill:BitmapData, bitmapRepeat:Bool):Void { - - if (hasFill || bitmapFill == null) return; - - if (fillPattern == null) { - - fillPattern = CairoPattern.createForSurface (bitmapFill.getSurface ()); - - if (bitmapRepeat) { - - fillPattern.extend = CairoExtend.REPEAT; - - } - - } + private static var bitmapFill:BitmapData; + private static var bitmapRepeat:Bool; - cairo.source = fillPattern; - hasFill = true; - - } - - - private static function createTempPatternCanvas (bitmap:BitmapData, repeat:Bool, width:Int, height:Int) { + private static function createTempPatternCanvas (bitmap:BitmapData, repeat:Bool, width:Int, height:Int) : CairoPattern{ var surface = new CairoSurface (ARGB32, width, height); var pattern = CairoPattern.createForSurface (surface); - + if (repeat) { pattern.extend = CairoExtend.REPEAT; @@ -88,8 +69,8 @@ class CairoGraphics { cairo.lineTo (0, 0); cairo.closePath (); cairo.fill (); - pattern.destroy (); - return surface; + surface.destroy (); + return pattern; // TODO: Don't create extra canvas elements like this @@ -120,7 +101,6 @@ class CairoGraphics { cairo.newPath (); playCommands (fillCommands, false); fillCommands = []; - } @@ -130,7 +110,6 @@ class CairoGraphics { playCommands (strokeCommands, true); cairo.closePath (); strokeCommands = []; - } @@ -217,6 +196,98 @@ class CairoGraphics { } + private static function createGradientPattern( type:GradientType, colors:Array, alphas:Array, ratios:Array, matrix:Matrix, spreadMethod:Null, interpolationMethod:Null, focalPointRatio:Null ): CairoPattern { + + var pattern : CairoPattern = null; + + switch (type) { + + case RADIAL: + + if (matrix == null) matrix = new Matrix (); + + var point = matrix.transformPoint (new Point (1638.4, 0)); + + pattern = CairoPattern.createRadial (matrix.tx, matrix.ty, 0, matrix.tx, matrix.ty, (point.x - matrix.tx) / 2); + + case LINEAR: + + if (matrix == null) matrix = new Matrix (); + + var point1 = matrix.transformPoint (new Point (-819.2, 0)); + var point2 = matrix.transformPoint (new Point (819.2, 0)); + + pattern = CairoPattern.createLinear (point1.x, point1.y, point2.x, point2.y); + + } + + for (i in 0...colors.length) { + + var rgb = colors[i]; + var alpha = alphas[i]; + var r = ((rgb & 0xFF0000) >>> 16) / 0xFF; + var g = ((rgb & 0x00FF00) >>> 8) / 0xFF; + var b = (rgb & 0x0000FF) / 0xFF; + + var ratio = ratios[i] / 0xFF; + if (ratio < 0) ratio = 0; + if (ratio > 1) ratio = 1; + + pattern.addColorStopRGBA (ratio, r, g, b, alpha); + + } + + var mat = pattern.matrix; + + mat.tx = bounds.x; + mat.ty = bounds.y; + + pattern.matrix = mat; + + return pattern; + } + + private static function createImagePattern (bitmapFill:BitmapData, matrix:Matrix, bitmapRepeat:Bool):CairoPattern { + + var pattern = CairoPattern.createForSurface (bitmapFill.getSurface ()); + + if (bitmapRepeat) { + pattern.extend = CairoExtend.REPEAT; + } + + var mat = pattern.matrix; + + if ( matrix != null ) + { + mat.a = matrix.a; + mat.b = matrix.b; + mat.c = matrix.c; + mat.d = matrix.d; + + mat.tx = -matrix.tx + bounds.x; + mat.ty = -matrix.ty + bounds.y; + } + else + { + mat.tx = bounds.x; + mat.ty = bounds.y; + } + + pattern.matrix = mat; + + return pattern; + } + + private static function closePath() : Void { + + if ( strokePattern == null ) + return; + + cairo.closePath(); + cairo.source = strokePattern; + cairo.strokePreserve (); + cairo.newPath (); + } private static function playCommands (commands:Array, stroke:Bool = false):Void { @@ -230,7 +301,9 @@ class CairoGraphics { var closeGap = false; var startX = 0.0; - var startY = 0.0; + var startY = 0.0; + + cairo.fillRule = EVEN_ODD; for (command in commands) { @@ -249,6 +322,10 @@ class CairoGraphics { cairo.moveTo (x - offsetX + radius, y - offsetY); cairo.arc (x - offsetX, y - offsetY, radius, 0, Math.PI * 2); + case DrawRect (x, y, width, height): + + cairo.rectangle (x - offsetX, y - offsetY, width, height); + case DrawEllipse (x, y, width, height): x -= offsetX; @@ -293,14 +370,8 @@ class CairoGraphics { case LineStyle (thickness, color, alpha, pixelHinting, scaleMode, caps, joints, miterLimit): if (stroke && hasStroke) { - - cairo.closePath (); - cairo.source = strokePattern; - cairo.strokePreserve (); - cairo.newPath (); - + closePath(); } - cairo.moveTo (positionX - offsetX, positionY - offsetY); if (thickness == null) { @@ -309,6 +380,8 @@ class CairoGraphics { } else { + hasStroke = true; + cairo.lineWidth = thickness; if (joints == null) { @@ -345,63 +418,73 @@ class CairoGraphics { cairo.miterLimit = (miterLimit == null ? 3 : miterLimit); - if (strokePattern != null) { - - strokePattern.destroy (); + if ( color != null ) + { + var r = ((color & 0xFF0000) >>> 16) / 0xFF; + var g = ((color & 0x00FF00) >>> 8) / 0xFF; + var b = (color & 0x0000FF) / 0xFF; - } - - var r = ((color & 0xFF0000) >>> 16) / 0xFF; - var g = ((color & 0x00FF00) >>> 8) / 0xFF; - var b = (color & 0x0000FF) / 0xFF; - - if (alpha == 1 || alpha == null) { - - strokePattern = CairoPattern.createRGB (r, g, b); - - } else { - - strokePattern = CairoPattern.createRGBA (r, g, b, alpha); + + if (strokePattern != null) { + strokePattern.destroy(); + } + if (alpha == 1 || alpha == null) { + + strokePattern = CairoPattern.createRGB (r, g, b); + + } else { + + strokePattern = CairoPattern.createRGBA (r, g, b, alpha); + } } - - hasStroke = true; - } - case BeginBitmapFill (bitmap, matrix, repeat, smooth): + case LineGradientStyle (type, colors, alphas, ratios, matrix, spreadMethod, interpolationMethod, focalPointRatio): - if (bitmap != bitmapFill || repeat != bitmapRepeat) { - - bitmapFill = bitmap; - bitmapRepeat = repeat; - - if (fillPattern != null) { - - fillPattern.destroy (); - - } - - fillPattern = null; - hasFill = false; - - //bitmap.__sync (); - + if (stroke && hasStroke) { + closePath(); } - if (matrix != null) { - - pendingMatrix = matrix; - inversePendingMatrix = matrix.clone (); - inversePendingMatrix.invert (); - - } else { - - pendingMatrix = null; - inversePendingMatrix = null; - + if (strokePattern != null) { + strokePattern.destroy(); } - + + cairo.moveTo (positionX - offsetX, positionY - offsetY); + + strokePattern = createGradientPattern( type, colors, alphas, ratios, matrix, spreadMethod, interpolationMethod, focalPointRatio ); + + hasStroke = true; + + case LineBitmapStyle (bitmap, matrix, repeat, smooth): + + if (stroke && hasStroke) { + closePath(); + } + + if (strokePattern != null) { + strokePattern.destroy(); + } + + cairo.moveTo (positionX - offsetX, positionY - offsetY); + + strokePattern = createImagePattern( bitmap, matrix, repeat ); + + hasStroke = true; + + case BeginBitmapFill (bitmap, matrix, repeat, smooth): + + if (fillPattern != null) { + fillPattern.destroy (); + } + + fillPattern = createImagePattern( bitmap, matrix, repeat ); + + bitmapFill = bitmap; + bitmapRepeat = repeat; + + hasFill = true; + case BeginFill (rgb, alpha): if (alpha < 0.005) { @@ -409,137 +492,29 @@ class CairoGraphics { hasFill = false; } else { - + if (fillPattern != null) { - fillPattern.destroy (); - } fillPattern = CairoPattern.createRGBA (((rgb & 0xFF0000) >>> 16) / 0xFF, ((rgb & 0x00FF00) >>> 8) / 0xFF, (rgb & 0x0000FF) / 0xFF, alpha); - - bitmapFill = null; hasFill = true; - } - - case BeginGradientFill (type, colors, alphas, ratios, matrix, spreadMethod, interpolationMethod, focalPointRatio): - - var gradientFill = null; - - switch (type) { - - case RADIAL: - - if (matrix == null) matrix = new Matrix (); - var point = matrix.transformPoint (new Point (1638.4, 0)); - - if (fillPattern != null) { - - fillPattern.destroy (); - - } - - fillPattern = CairoPattern.createRadial (matrix.tx, matrix.ty, 0, matrix.tx, matrix.ty, (point.x - matrix.tx) / 2); - - case LINEAR: - - var matrix = matrix != null ? matrix.clone () : new Matrix (); - var point1 = matrix.transformPoint (new Point (-819.2, 0)); - var point2 = matrix.transformPoint (new Point (819.2, 0)); - - if (fillPattern != null) { - - fillPattern.destroy (); - - } - - fillPattern = CairoPattern.createLinear (point1.x, point1.y, point2.x, point2.y); - - } - - for (i in 0...colors.length) { - - var rgb = colors[i]; - var alpha = alphas[i]; - var r = ((rgb & 0xFF0000) >>> 16) / 0xFF; - var g = ((rgb & 0x00FF00) >>> 8) / 0xFF; - var b = (rgb & 0x0000FF) / 0xFF; - - var ratio = ratios[i] / 0xFF; - if (ratio < 0) ratio = 0; - if (ratio > 1) ratio = 1; - - fillPattern.addColorStopRGBA (ratio, r, g, b, alpha); - - } - - //context.fillStyle = gradientFill; bitmapFill = null; - hasFill = true; - case DrawRect (x, y, width, height): - //var optimizationUsed = false; - // - //if (bitmapFill != null) { - // - //var st:Float = 0; - //var sr:Float = 0; - //var sb:Float = 0; - //var sl:Float = 0; - // - //var canOptimizeMatrix = true; - // - //if (pendingMatrix != null) { - // - //if (pendingMatrix.b != 0 || pendingMatrix.c != 0) { - // - //canOptimizeMatrix = false; - // - //} else { - // - //var stl = inversePendingMatrix.transformPoint (new Point (x, y)); - //var sbr = inversePendingMatrix.transformPoint (new Point (x + width, y + height)); - // - //st = stl.y; - //sl = stl.x; - //sb = sbr.y; - //sr = sbr.x; - // - //} - // - //} else { - // - //st = y; - //sl = x; - //sb = y + height; - //sr = x + width; - // - //} - // - //if (canOptimizeMatrix && st >= 0 && sl >= 0 && sr <= bitmapFill.width && sb <= bitmapFill.height) { - // - //optimizationUsed = true; - ////context.drawImage (bitmapFill.__image.src, sl, st, sr - sl, sb - st, x - offsetX, y - offsetY, width, height); - //} - //} - // - //if (!optimizationUsed) { - - if (fillPattern != null) { - - var matrix = fillPattern.matrix; - matrix.translate (x, y); - fillPattern.matrix = matrix; - - } - - cairo.rectangle (x - offsetX, y - offsetY, width, height); - - //} + case BeginGradientFill (type, colors, alphas, ratios, matrix, spreadMethod, interpolationMethod, focalPointRatio): + if (fillPattern != null) { + fillPattern.destroy (); + } + + fillPattern = createGradientPattern( type, colors, alphas, ratios, matrix, spreadMethod, interpolationMethod, focalPointRatio ); + + hasFill = true; + bitmapFill = null; + default: @@ -557,43 +532,28 @@ class CairoGraphics { cairo.source = strokePattern; cairo.strokePreserve (); - + } - if (!stroke) { + if (!stroke && hasFill) { - if (hasFill || bitmapFill != null) { - - if (bitmapFill != null) { - - beginPatternFill (bitmapFill, bitmapRepeat); - - } else { - - cairo.source = fillPattern; - - } + cairo.source = fillPattern; + cairo.translate ( -bounds.x, -bounds.y); + + if (pendingMatrix != null) { - cairo.translate (-bounds.x, -bounds.y); + cairo.transform (pendingMatrix.__toMatrix3 ()); + cairo.fillPreserve (); + cairo.transform (inversePendingMatrix.__toMatrix3 ()); - if (pendingMatrix != null) { - - cairo.transform (pendingMatrix.__toMatrix3 ()); - cairo.fillPreserve (); - cairo.transform (inversePendingMatrix.__toMatrix3 ()); - - } else { - - cairo.fillPreserve (); - - } + } else { - cairo.translate (bounds.x, bounds.y); - cairo.closePath (); - //cairo.paint (); + cairo.fillPreserve (); } + cairo.translate (bounds.x, bounds.y); + cairo.closePath (); } } @@ -657,7 +617,7 @@ class CairoGraphics { if (graphics.__cairo == null) { - var surface = new CairoSurface (ARGB32, Math.ceil (bounds.width), Math.ceil (bounds.height)); + var surface = new CairoSurface (ARGB32, Math.ceil (bounds.width+2), Math.ceil (bounds.height+2)); graphics.__cairo = new Cairo (surface); surface.destroy (); @@ -673,11 +633,12 @@ class CairoGraphics { hasFill = false; hasStroke = false; - bitmapFill = null; - bitmapRepeat = false; + fillPattern = null; + strokePattern = null; + for (command in graphics.__commands) { - + switch (command) { case CubicCurveTo (_, _, _, _, _, _), CurveTo (_, _, _, _), LineTo (_, _), MoveTo (_, _): @@ -690,11 +651,12 @@ class CairoGraphics { endFill (); endStroke (); hasFill = false; + bitmapFill = null; - case LineStyle (_, _, _, _, _, _, _, _): + case LineStyle (_, _, _, _, _, _, _, _), LineGradientStyle (_, _, _, _, _, _, _, _), LineBitmapStyle (_, _, _, _): strokeCommands.push (command); - + case BeginBitmapFill (_, _, _, _), BeginFill (_, _), BeginGradientFill (_, _, _, _, _, _, _, _): endFill (); @@ -705,8 +667,8 @@ class CairoGraphics { case DrawCircle (_, _, _), DrawEllipse (_, _, _, _), DrawRect (_, _, _, _), DrawRoundRect (_, _, _, _, _, _): - endFill (); - endStroke (); + //endFill (); + //endStroke (); fillCommands.push (command); strokeCommands.push (command); @@ -719,16 +681,17 @@ class CairoGraphics { var v = vertices; var ind = indices; var uvt = uvtData; - var pattern:CairoSurface = null; + var pattern:CairoPattern = null; var colorFill = bitmapFill == null; if (colorFill && uvt != null) { - // Flash doesn't draw anything if the fill isn't a bitmap and there are uvt values break; - } + var width = 0; + var height = 0; + if (!colorFill) { //TODO move this to Graphics? @@ -752,15 +715,21 @@ class CairoGraphics { uvt = normalizedUVT.uvt; if (maxUVT > 1) { + width = Std.int (bounds.width); + height = Std.int (bounds.height); - pattern = createTempPatternCanvas (bitmapFill, bitmapRepeat, Std.int (bounds.width), Std.int (bounds.height)); } else { - pattern = createTempPatternCanvas (bitmapFill, bitmapRepeat, bitmapFill.width, bitmapFill.height); + width = bitmapFill.width; + height = bitmapFill.height; } + pattern = createImagePattern( bitmapFill, null, bitmapRepeat ); + + //pattern = createTempPatternCanvas (bitmapFill, bitmapRepeat, width, height); + cairo.source = pattern; } var i = 0; @@ -836,16 +805,15 @@ class CairoGraphics { cairo.moveTo (x1, y1); cairo.lineTo (x2, y2); cairo.lineTo (x3, y3); - cairo.closePath (); - + cairo.closePath (); cairo.clip (); - uvx1 = uvt[iax] * pattern.width; - uvx2 = uvt[ibx] * pattern.width; - uvx3 = uvt[icx] * pattern.width; - uvy1 = uvt[iay] * pattern.height; - uvy2 = uvt[iby] * pattern.height; - uvy3 = uvt[icy] * pattern.height; + uvx1 = uvt[iax] * width; + uvx2 = uvt[ibx] * width; + uvx3 = uvt[icx] * width; + uvy1 = uvt[iay] * height; + uvy2 = uvt[iby] * height; + uvy3 = uvt[icy] * height; denom = uvx1 * (uvy3 - uvy2) - uvx2 * uvy3 + uvx3 * uvy2 + (uvx2 - uvx3) * uvy1; @@ -864,11 +832,11 @@ class CairoGraphics { dy = (uvx1 * (uvy3 * y2 - uvy2 * y3) + uvy1 * (uvx2 * y3 - uvx3 * y2) + (uvx3 * uvy2 - uvx2 * uvy3) * y1) / denom; var matrix = new Matrix3 (t1, t2, t3, t4, dx, dy); - //cairo.transform (t1, t2, t3, t4, dx, dy); - cairo.transform (matrix); - cairo.setSourceSurface (pattern, 0, 0); + pattern.matrix = matrix; + + //cairo.transform( matrix ); + cairo.paint (); - //cairo.drawImage (pattern, 0, 0); cairo.restore (); i += 3; @@ -876,8 +844,9 @@ class CairoGraphics { } case DrawTiles (sheet, tileData, smooth, flags, count): - - return; + + endFill (); + endStroke (); var useScale = (flags & Graphics.TILE_SCALE) > 0; var useRotation = (flags & Graphics.TILE_ROTATION) > 0; @@ -918,8 +887,11 @@ class CairoGraphics { sheet.__bitmap.__sync (); surface = sheet.__bitmap.getSurface (); - cairo.setSourceSurface (surface, 0, 0); + var pattern = CairoPattern.createForSurface( surface ); + //cairo.setSourceSurface (surface, 0, 0); + cairo.source = pattern; + if (useBlendAdd) { cairo.operator = ADD; @@ -929,7 +901,18 @@ class CairoGraphics { while (index < totalCount) { - var tileID = (!useRect) ? Std.int (tileData[index + 2]) : -1; + // Std.int doesn't handle null on neko target + #if neko + var f : Float = tileData[index + 2]; + var i = 0; + + if( f != null ) + i = Std.int ( f ); + #else + var i = Std.int( tileData[index +2] ); + #end + + var tileID = (!useRect) ? i : -1; if (!useRect && tileID != previousTileID) { @@ -960,13 +943,9 @@ class CairoGraphics { cairo.save (); cairo.translate (tileData[index], tileData[index + 1]); - - if (useRotation) { - - //cairo.rotate (tileData[index + rotationIndex]); - - } - + + var matrix : Matrix3 = new Matrix3(); + var scale = 1.0; if (useScale) { @@ -977,12 +956,20 @@ class CairoGraphics { if (useTransform) { - var matrix = new Matrix3 (tileData[index + transformIndex], tileData[index + transformIndex + 1], tileData[index + transformIndex + 2], tileData[index + transformIndex + 3], 0, 0); - cairo.transform (matrix); + matrix = new Matrix3 (tileData[index + transformIndex], tileData[index + transformIndex + 1], tileData[index + transformIndex + 2], tileData[index + transformIndex + 3], 0, 0); + pattern.matrix = matrix; + } + + matrix.translate( -tileData[index], -tileData[index + 1] ); + + if (useRotation) { + matrix.rotate(tileData[index + rotationIndex]); } - //cairo.setSourceSurface ( + matrix.scale( 1/scale, 1/scale ); + + pattern.matrix = matrix; if (useAlpha) { @@ -1011,6 +998,8 @@ class CairoGraphics { } + + default: openfl.Lib.notImplemented ("CairoGraphics"); diff --git a/openfl/display/Graphics.hx b/openfl/display/Graphics.hx index 89d55ea26f..f6321fac9a 100644 --- a/openfl/display/Graphics.hx +++ b/openfl/display/Graphics.hx @@ -66,6 +66,7 @@ class Graphics { #end + public function new () { __commands = new Array (); @@ -708,7 +709,7 @@ class Graphics { */ public function lineBitmapStyle (bitmap:BitmapData, matrix:Matrix = null, repeat:Bool = true, smooth:Bool = false):Void { - openfl.Lib.notImplemented ("Graphics.lineBitmapStyle"); + __commands.push (LineBitmapStyle (bitmap, matrix != null ? matrix.clone () : null, repeat, smooth)); } @@ -767,7 +768,7 @@ class Graphics { */ public function lineGradientStyle (type:GradientType, colors:Array, alphas:Array, ratios:Array, matrix:Matrix = null, spreadMethod:SpreadMethod = null, interpolationMethod:InterpolationMethod = null, focalPointRatio:Null = null):Void { - openfl.Lib.notImplemented ("Graphics.lineGradientStyle"); + __commands.push (LineGradientStyle (type, colors, alphas, ratios, matrix, spreadMethod, interpolationMethod, focalPointRatio)); } @@ -913,7 +914,7 @@ class Graphics { */ public function lineStyle (thickness:Null = null, color:Null = null, alpha:Null = null, pixelHinting:Null = null, scaleMode:LineScaleMode = null, caps:CapsStyle = null, joints:JointStyle = null, miterLimit:Null = null):Void { - __halfStrokeWidth = thickness > __halfStrokeWidth ? thickness : __halfStrokeWidth; + __halfStrokeWidth = thickness > __halfStrokeWidth ? thickness/2 : __halfStrokeWidth; __commands.push (LineStyle (thickness, color, alpha, pixelHinting, scaleMode, caps, joints, miterLimit)); if (thickness != null) __visible = true; @@ -1066,6 +1067,8 @@ class Graphics { DrawTriangles (vertices:Vector, indices:Vector, uvtData:Vector, culling:TriangleCulling, colors:Vector, blendMode:Int); EndFill; LineStyle (thickness:Null, color:Null, alpha:Null, pixelHinting:Null, scaleMode:LineScaleMode, caps:CapsStyle, joints:JointStyle, miterLimit:Null); + LineBitmapStyle (bitmap:BitmapData, matrix:Matrix, repeat:Bool, smooth:Bool); + LineGradientStyle (type:GradientType, colors:Array, alphas:Array, ratios:Array, matrix:Matrix, spreadMethod:Null, interpolationMethod:Null, focalPointRatio:Null); LineTo (x:Float, y:Float); MoveTo (x:Float, y:Float); DrawPathC(commands:Vector, data:Vector, winding:GraphicsPathWinding); From af497b410c596477301d65836720ac3ea5566136 Mon Sep 17 00:00:00 2001 From: Kane Wallmann Date: Sun, 17 May 2015 00:17:27 +1000 Subject: [PATCH 147/150] Added text renderer for Cairo --- .../renderer/cairo/CairoTextField.hx | 21 ++ .../renderer/cairo/CairoTextRenderer.hx | 283 ++++++++++++++++++ openfl/text/TextField.hx | 8 + 3 files changed, 312 insertions(+) create mode 100644 openfl/_internal/renderer/cairo/CairoTextField.hx create mode 100644 openfl/_internal/renderer/cairo/CairoTextRenderer.hx diff --git a/openfl/_internal/renderer/cairo/CairoTextField.hx b/openfl/_internal/renderer/cairo/CairoTextField.hx new file mode 100644 index 0000000000..93b51d70bc --- /dev/null +++ b/openfl/_internal/renderer/cairo/CairoTextField.hx @@ -0,0 +1,21 @@ +package openfl._internal.renderer.cairo; + +import openfl._internal.renderer.cairo.CairoGraphics; +import openfl._internal.renderer.cairo.CairoTextRenderer; +import openfl._internal.renderer.RenderSession; +import openfl.display.Graphics; +import openfl.text.TextField; + +@:access(openfl.text.TextField) + + +class CairoTextField { + + + public static function render (textField:TextField, renderSession:RenderSession) { + + if (!textField.__renderable || textField.__worldAlpha <= 0) return; + + CairoTextRenderer.render (textField); + } +} diff --git a/openfl/_internal/renderer/cairo/CairoTextRenderer.hx b/openfl/_internal/renderer/cairo/CairoTextRenderer.hx new file mode 100644 index 0000000000..f42d6607cf --- /dev/null +++ b/openfl/_internal/renderer/cairo/CairoTextRenderer.hx @@ -0,0 +1,283 @@ +package openfl._internal.renderer.cairo; + + +import lime.graphics.Image; +import lime.text.Font.NativeGlyphData; +import lime.text.Glyph; +import lime.text.TextLayout; +import openfl._internal.renderer.RenderSession; +import openfl.display.BitmapData; +import openfl.display.Graphics; +import openfl.display.Tilesheet; +import openfl.geom.Point; +import openfl.geom.Rectangle; +import openfl.text.Font; +import openfl.text.TextField; +import openfl.text.TextFieldAutoSize; +import openfl.text.TextFormat; +import openfl.text.TextFormatAlign; + +@:access(openfl.text.TextField) + + +class CairoTextRenderer { + + private static var glyphMap = new Map> (); + + + public static function render (textField:TextField) { + + if (textField.__graphics == null) { + + textField.__graphics = new Graphics (); + + } + + if (textField.__dirty) { + + var graphics = textField.__graphics; + graphics.clear (); + + if (textField.border || textField.background) { + + if (textField.border) { + + graphics.lineStyle (1, textField.borderColor); + + } + + if (textField.background) { + + graphics.beginFill (textField.backgroundColor); + + } + + graphics.drawRect (0.5, 0.5, textField.__width - 1, textField.__height - 1); + + } + + update( textField ); + + textField.__dirty = false; + } + } + +public static function update (textField:TextField):Bool { + + if (textField.__dirty) { + + if (textField.__text != null && textField.__text != "") { + + var text = textField.text; + + if (textField.displayAsPassword) { + + var length = text.length; + var mask = ""; + + for (i in 0...length) { + + mask += "*"; + + } + + text = mask; + + } + + /*var measurements = textField.__measureText (); + var textWidth = 0.0; + + for (measurement in measurements) { + + textWidth += measurement; + + } + + if (textField.autoSize == TextFieldAutoSize.LEFT) { + + textField.__width = textWidth + 4; + textField.__height = textField.textHeight + 4; + + }*/ + + var textWidth = 50; + + if (textField.__ranges == null) { + + renderText (textField, text, textField.__textFormat, 2, textWidth); + + } else { + + var currentIndex = 0; + var range; + var offsetX = 2.0; + + for (i in 0...textField.__ranges.length) { + + range = textField.__ranges[i]; + + renderText (textField, text.substring (range.start, range.end), range.format, offsetX, textWidth); + //offsetX += measurements[i]; + + } + + } + + } else { + + if (textField.autoSize == TextFieldAutoSize.LEFT) { + + textField.__width = 4; + textField.__height = 4; + + } + + } + + textField.__dirty = false; + return true; + } + + return false; + + } + + private static inline function renderText (textField:TextField, text:String, format:TextFormat, offsetX:Float, textWidth:Float):Void { + + var font : Font = textField.__getFontInstance ( format ); + + if (font != null && format.size != null) { + + var graphics : Graphics = textField.__graphics; + + var glyphs : Array; + + if ( glyphMap.exists( font ) ) + { + glyphs = glyphMap.get( font ); + } + else + { + var glyphData = font.decompose(); + glyphs = glyphData.glyphs; + + glyphMap.set( font, glyphs ); + } + + var size = Std.int (format.size); + + var denom : Float = 20 / size * 1024; + + var lines = text.split ("\n"); + + var tlm = textField.getLineMetrics (0); + + var x : Float = offsetX; + var y : Float = 2 + tlm.ascent; + + var line_i:Int = 0; + var oldX = x; + + if (textField.__textLayout == null) { + + textField.__textLayout = new TextLayout (); + + } + + var textLayout:TextLayout = textField.__textLayout; + + var glyphCodes = new Map(); + for ( g in glyphs ) + { + glyphCodes.set( g.char_code, g ); + } + + for (line in lines) + { + tlm = textField.getLineMetrics (line_i); + + //x position must be reset every line and recalculated + x = oldX; + + x += switch (format.align) { + + case LEFT, JUSTIFY: 0; //the renderer has already positioned the text at the right spot past the 2px left margin + case CENTER: ((textField.__width - 4) - tlm.width) / 2; //subtract 4 from textfield.__width because __width includes the 2px margin on both sides, which doesn't count + case RIGHT: ((textField.__width - 4) - tlm.width); //same thing here + + } + + textLayout.text = null; + textLayout.font = font; + textLayout.size = size; + textLayout.text = line; + + var a = 0; + + var tx : Float = 0; + var ty : Float = 0; + + for (position in textLayout.positions) + { + var glyph = glyphCodes[ line.charCodeAt( a ) ]; + + var points = glyph.points; + + var i = 0; + + graphics.beginFill( format.color ); + + while( i < points.length ) + { + switch( points[i] ) + { + case 1: + + tx = x + position.offset.x + points[i + 1]/denom; + ty = y + position.offset.y - points[i + 2]/denom; + + graphics.moveTo( tx, ty ); + + i += 3; + + case 2: + + tx += points[i + 1]/denom; + ty -= points[i + 2]/denom; + + graphics.lineTo( tx, ty ); + + i += 3; + + case 3: + + var cx = tx + points[i + 1]/denom; + var cy = ty - points[i + 2]/denom; + + tx = cx + points[i + 3]/denom; + ty = cy - points[i + 4]/denom; + + graphics.curveTo( tx, ty, cx, cy ); + i += 5; + } + + } + + graphics.endFill( ); + + x += position.advance.x; + y -= position.advance.y; + + a++; + } + + y += tlm.height; //always add the line height at the end + line_i++; + } + + } + } + + +} diff --git a/openfl/text/TextField.hx b/openfl/text/TextField.hx index db32e3f9c6..fdcf0a734a 100644 --- a/openfl/text/TextField.hx +++ b/openfl/text/TextField.hx @@ -10,8 +10,10 @@ import lime.system.System; import lime.text.TextLayout; import lime.ui.Mouse; import lime.ui.MouseCursor; +import openfl._internal.renderer.cairo.CairoShape; import openfl._internal.renderer.canvas.CanvasTextField; import openfl._internal.renderer.dom.DOMTextField; +import openfl._internal.renderer.cairo.CairoTextField; import openfl._internal.renderer.opengl.GLTextField; import openfl._internal.renderer.RenderSession; import openfl.display.DisplayObject; @@ -1607,6 +1609,12 @@ class TextField extends InteractiveObject { } + @:noCompletion public override function __renderCairo (renderSession:RenderSession):Void { + + CairoTextField.render (this, renderSession); + super.__renderCairo(renderSession); + + } @:noCompletion public override function __renderCanvas (renderSession:RenderSession):Void { From 6f2f4732e48824a8dcf3046f3b158a957ed2082d Mon Sep 17 00:00:00 2001 From: Kane Wallmann Date: Sun, 17 May 2015 08:21:58 +1000 Subject: [PATCH 148/150] Fixed poor text renderering --- .../renderer/cairo/CairoTextField.hx | 2 + .../renderer/cairo/CairoTextRenderer.hx | 40 ++++++++++++------- openfl/text/TextField.hx | 2 - 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/openfl/_internal/renderer/cairo/CairoTextField.hx b/openfl/_internal/renderer/cairo/CairoTextField.hx index 93b51d70bc..d7829d55c0 100644 --- a/openfl/_internal/renderer/cairo/CairoTextField.hx +++ b/openfl/_internal/renderer/cairo/CairoTextField.hx @@ -2,6 +2,7 @@ package openfl._internal.renderer.cairo; import openfl._internal.renderer.cairo.CairoGraphics; import openfl._internal.renderer.cairo.CairoTextRenderer; +import openfl._internal.renderer.opengl.utils.GraphicsRenderer; import openfl._internal.renderer.RenderSession; import openfl.display.Graphics; import openfl.text.TextField; @@ -17,5 +18,6 @@ class CairoTextField { if (!textField.__renderable || textField.__worldAlpha <= 0) return; CairoTextRenderer.render (textField); + CairoShape.render (textField, renderSession); } } diff --git a/openfl/_internal/renderer/cairo/CairoTextRenderer.hx b/openfl/_internal/renderer/cairo/CairoTextRenderer.hx index f42d6607cf..93c9ebd1fc 100644 --- a/openfl/_internal/renderer/cairo/CairoTextRenderer.hx +++ b/openfl/_internal/renderer/cairo/CairoTextRenderer.hx @@ -62,7 +62,7 @@ class CairoTextRenderer { } } -public static function update (textField:TextField):Bool { + public static function update (textField:TextField):Bool { if (textField.__dirty) { @@ -85,7 +85,7 @@ public static function update (textField:TextField):Bool { } - /*var measurements = textField.__measureText (); + var measurements = textField.__measureText (); var textWidth = 0.0; for (measurement in measurements) { @@ -99,9 +99,7 @@ public static function update (textField:TextField):Bool { textField.__width = textWidth + 4; textField.__height = textField.textHeight + 4; - }*/ - - var textWidth = 50; + } if (textField.__ranges == null) { @@ -118,7 +116,7 @@ public static function update (textField:TextField):Bool { range = textField.__ranges[i]; renderText (textField, text.substring (range.start, range.end), range.format, offsetX, textWidth); - //offsetX += measurements[i]; + offsetX += measurements[i]; } @@ -153,6 +151,8 @@ public static function update (textField:TextField):Bool { var glyphs : Array; + textField.__textLayout.font = font; + if ( glyphMap.exists( font ) ) { glyphs = glyphMap.get( font ); @@ -165,24 +165,22 @@ public static function update (textField:TextField):Bool { glyphMap.set( font, glyphs ); } + var tlm = textField.getLineMetrics (0); + + var x : Float = offsetX; + var y : Float = 2 + tlm.ascent; + var size = Std.int (format.size); var denom : Float = 20 / size * 1024; var lines = text.split ("\n"); - var tlm = textField.getLineMetrics (0); - - var x : Float = offsetX; - var y : Float = 2 + tlm.ascent; - var line_i:Int = 0; var oldX = x; if (textField.__textLayout == null) { - textField.__textLayout = new TextLayout (); - } var textLayout:TextLayout = textField.__textLayout; @@ -258,8 +256,22 @@ public static function update (textField:TextField):Bool { tx = cx + points[i + 3]/denom; ty = cy - points[i + 4]/denom; - graphics.curveTo( tx, ty, cx, cy ); + graphics.curveTo( cx, cy, tx, ty ); i += 5; + + case 4: + + var c1x = tx + points[i + 1]/denom; + var c1y = ty - points[i + 2]/denom; + + var c2x = c1x + points[i + 3]/denom; + var c2y = c1y - points[i + 4]/denom; + + tx = c2x + points[i + 5]/denom; + ty = c2y - points[i + 6]/denom; + + graphics.cubicCurveTo( c1x, c1y, c2x, c2y, tx, ty ); + i += 7; } } diff --git a/openfl/text/TextField.hx b/openfl/text/TextField.hx index fdcf0a734a..5cc7d9b56c 100644 --- a/openfl/text/TextField.hx +++ b/openfl/text/TextField.hx @@ -1612,8 +1612,6 @@ class TextField extends InteractiveObject { @:noCompletion public override function __renderCairo (renderSession:RenderSession):Void { CairoTextField.render (this, renderSession); - super.__renderCairo(renderSession); - } @:noCompletion public override function __renderCanvas (renderSession:RenderSession):Void { From 82243c6a62649bf00d0c625415463732af6a4348 Mon Sep 17 00:00:00 2001 From: Kane Wallmann Date: Sun, 17 May 2015 09:24:54 +1000 Subject: [PATCH 149/150] Fixes and performance tweaks --- .../_internal/renderer/cairo/CairoGraphics.hx | 99 ++++--------------- 1 file changed, 19 insertions(+), 80 deletions(-) diff --git a/openfl/_internal/renderer/cairo/CairoGraphics.hx b/openfl/_internal/renderer/cairo/CairoGraphics.hx index 46aa79d851..8d01357668 100644 --- a/openfl/_internal/renderer/cairo/CairoGraphics.hx +++ b/openfl/_internal/renderer/cairo/CairoGraphics.hx @@ -52,47 +52,16 @@ class CairoGraphics { private static function createTempPatternCanvas (bitmap:BitmapData, repeat:Bool, width:Int, height:Int) : CairoPattern{ var surface = new CairoSurface (ARGB32, width, height); - var pattern = CairoPattern.createForSurface (surface); + var pattern = CairoPattern.createForSurface (bitmap.getSurface()); if (repeat) { - pattern.extend = CairoExtend.REPEAT; - } cairo.source = pattern; - cairo.newPath (); - cairo.moveTo (0, 0); - cairo.lineTo (0, height); - cairo.lineTo (width, height); - cairo.lineTo (width, 0); - cairo.lineTo (0, 0); - cairo.closePath (); - cairo.fill (); + cairo.paint (); surface.destroy (); return pattern; - - // TODO: Don't create extra canvas elements like this - - //#if (js && html5) - //var canvas:CanvasElement = cast Browser.document.createElement ("canvas"); - //var context = canvas.getContext ("2d"); - // - //canvas.width = width; - //canvas.height = height; - // - //context.fillStyle = context.createPattern (bitmap.__image.src, repeat ? "repeat" : "no-repeat"); - //context.beginPath (); - //context.moveTo (0, 0); - //context.lineTo (0, height); - //context.lineTo (width, height); - //context.lineTo (width, 0); - //context.lineTo (0, 0); - //context.closePath (); - //context.fill (); - //return canvas; - //#end - } @@ -726,10 +695,8 @@ class CairoGraphics { } - pattern = createImagePattern( bitmapFill, null, bitmapRepeat ); + pattern = createTempPatternCanvas (bitmapFill, bitmapRepeat, width, height); - //pattern = createTempPatternCanvas (bitmapFill, bitmapRepeat, width, height); - cairo.source = pattern; } var i = 0; @@ -832,9 +799,9 @@ class CairoGraphics { dy = (uvx1 * (uvy3 * y2 - uvy2 * y3) + uvy1 * (uvx2 * y3 - uvx3 * y2) + (uvx3 * uvy2 - uvx2 * uvy3) * y1) / denom; var matrix = new Matrix3 (t1, t2, t3, t4, dx, dy); - pattern.matrix = matrix; - - //cairo.transform( matrix ); + + cairo.transform( matrix ); + cairo.source = pattern; cairo.paint (); cairo.restore (); @@ -886,17 +853,9 @@ class CairoGraphics { var surface:Dynamic; sheet.__bitmap.__sync (); surface = sheet.__bitmap.getSurface (); - - var pattern = CairoPattern.createForSurface( surface ); - - //cairo.setSourceSurface (surface, 0, 0); - cairo.source = pattern; - - if (useBlendAdd) { + if (useBlendAdd) { cairo.operator = ADD; - //context.globalCompositeOperation = "lighter"; - } while (index < totalCount) { @@ -942,47 +901,32 @@ class CairoGraphics { if (rect != null && rect.width > 0 && rect.height > 0 && center != null) { cairo.save (); - cairo.translate (tileData[index], tileData[index + 1]); - - var matrix : Matrix3 = new Matrix3(); - - var scale = 1.0; - - if (useScale) { - - scale = tileData[index + scaleIndex]; - - } - + if (useTransform) { - - matrix = new Matrix3 (tileData[index + transformIndex], tileData[index + transformIndex + 1], tileData[index + transformIndex + 2], tileData[index + transformIndex + 3], 0, 0); - pattern.matrix = matrix; + var matrix = new Matrix3 (tileData[index + transformIndex], tileData[index + transformIndex + 1], tileData[index + transformIndex + 2], tileData[index + transformIndex + 3], 0, 0); + cairo.matrix = matrix; } - matrix.translate( -tileData[index], -tileData[index + 1] ); + cairo.translate( tileData[index], tileData[index + 1] ); + if (useRotation) { - - matrix.rotate(tileData[index + rotationIndex]); + cairo.rotate(tileData[index + rotationIndex]); } - matrix.scale( 1/scale, 1/scale ); + if (useScale) { + var scale = tileData[index + scaleIndex]; + cairo.scale( scale, scale ); + } - pattern.matrix = matrix; + cairo.setSourceSurface( surface, 0, 0 ); if (useAlpha) { - cairo.paintWithAlpha (tileData[index + alphaIndex]); - //context.globalAlpha = tileData[index + alphaIndex]; - } else { - cairo.paint (); - } - //context.drawImage (surface, rect.x, rect.y, rect.width, rect.height, -center.x * scale, -center.y * scale, rect.width * scale, rect.height * scale); cairo.restore (); } @@ -992,14 +936,9 @@ class CairoGraphics { } if (useBlendAdd) { - cairo.operator = OVER; - //context.globalCompositeOperation = "source-over"; - } - - - + default: openfl.Lib.notImplemented ("CairoGraphics"); From 88020b0c7c8cb2ca0b845cab4ce1c59b84c765d1 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Sat, 16 May 2015 20:36:57 -0700 Subject: [PATCH 150/150] Improve Cairo bitmap fill matrix --- .../_internal/renderer/cairo/CairoGraphics.hx | 82 +++++++++++++------ 1 file changed, 56 insertions(+), 26 deletions(-) diff --git a/openfl/_internal/renderer/cairo/CairoGraphics.hx b/openfl/_internal/renderer/cairo/CairoGraphics.hx index 8d01357668..5f6e5ab951 100644 --- a/openfl/_internal/renderer/cairo/CairoGraphics.hx +++ b/openfl/_internal/renderer/cairo/CairoGraphics.hx @@ -38,6 +38,7 @@ class CairoGraphics { private static var cairo:Cairo; private static var fillCommands:Array; private static var fillPattern:CairoPattern; + private static var fillPatternMatrix:Matrix; private static var graphics:Graphics; private static var hasFill:Bool; private static var hasStroke:Bool; @@ -219,30 +220,35 @@ class CairoGraphics { private static function createImagePattern (bitmapFill:BitmapData, matrix:Matrix, bitmapRepeat:Bool):CairoPattern { var pattern = CairoPattern.createForSurface (bitmapFill.getSurface ()); - + if (bitmapRepeat) { + pattern.extend = CairoExtend.REPEAT; - } - - var mat = pattern.matrix; - - if ( matrix != null ) - { - mat.a = matrix.a; - mat.b = matrix.b; - mat.c = matrix.c; - mat.d = matrix.d; - mat.tx = -matrix.tx + bounds.x; - mat.ty = -matrix.ty + bounds.y; - } - else - { - mat.tx = bounds.x; - mat.ty = bounds.y; } - pattern.matrix = mat; + fillPatternMatrix = matrix; + + //var mat = pattern.matrix; + // + //if ( matrix != null ) + //{ + //var matrix = matrix.invert (); + //mat.a = matrix.a; + //mat.b = matrix.b; + //mat.c = matrix.c; + //mat.d = matrix.d; + // + //mat.tx = matrix.tx - bounds.x; + //mat.ty = matrix.ty - bounds.y; + //} + //else + //{ + //mat.tx = bounds.x; + //mat.ty = bounds.y; + //} + // + //pattern.matrix = mat; return pattern; } @@ -444,10 +450,12 @@ class CairoGraphics { case BeginBitmapFill (bitmap, matrix, repeat, smooth): if (fillPattern != null) { + fillPattern.destroy (); + } - fillPattern = createImagePattern( bitmap, matrix, repeat ); + fillPattern = createImagePattern (bitmap, matrix, repeat); bitmapFill = bitmap; bitmapRepeat = repeat; @@ -463,11 +471,15 @@ class CairoGraphics { } else { if (fillPattern != null) { + fillPattern.destroy (); + fillPatternMatrix = null; + } fillPattern = CairoPattern.createRGBA (((rgb & 0xFF0000) >>> 16) / 0xFF, ((rgb & 0x00FF00) >>> 8) / 0xFF, (rgb & 0x0000FF) / 0xFF, alpha); hasFill = true; + } bitmapFill = null; @@ -476,14 +488,16 @@ class CairoGraphics { case BeginGradientFill (type, colors, alphas, ratios, matrix, spreadMethod, interpolationMethod, focalPointRatio): if (fillPattern != null) { + fillPattern.destroy (); + fillPatternMatrix = null; + } - + fillPattern = createGradientPattern( type, colors, alphas, ratios, matrix, spreadMethod, interpolationMethod, focalPointRatio ); - + hasFill = true; bitmapFill = null; - default: @@ -506,9 +520,25 @@ class CairoGraphics { if (!stroke && hasFill) { - cairo.source = fillPattern; cairo.translate ( -bounds.x, -bounds.y); + if (fillPatternMatrix != null) { + + var matrix = fillPatternMatrix.clone (); + matrix.invert (); + + if (pendingMatrix != null) { + + matrix.concat (pendingMatrix); + + } + + fillPattern.matrix = matrix.__toMatrix3 (); + + } + + cairo.source = fillPattern; + if (pendingMatrix != null) { cairo.transform (pendingMatrix.__toMatrix3 ()); @@ -605,7 +635,7 @@ class CairoGraphics { fillPattern = null; strokePattern = null; - + for (command in graphics.__commands) { switch (command) { @@ -799,7 +829,7 @@ class CairoGraphics { dy = (uvx1 * (uvy3 * y2 - uvy2 * y3) + uvy1 * (uvx2 * y3 - uvx3 * y2) + (uvx3 * uvy2 - uvx2 * uvy3) * y1) / denom; var matrix = new Matrix3 (t1, t2, t3, t4, dx, dy); - + cairo.transform( matrix ); cairo.source = pattern;