From 8c487eb74513d0055344f306205dc2e1f6b4aa17 Mon Sep 17 00:00:00 2001 From: Ralty <78720179+Raltyro@users.noreply.github.com> Date: Tue, 4 Aug 2026 11:49:23 +0700 Subject: [PATCH] Re-apply huge modifications # Conflicts: # src/openfl/media/SoundChannel.hx # Conflicts: # src/openfl/display/Graphics.hx # src/openfl/display/Shader.hx # src/openfl/display3D/textures/TextureBase.hx # Conflicts: # lib/flash-externs/src/flash/display/Shader.hx # src/openfl/display/DisplayObjectShader.hx # src/openfl/display/GraphicsShader.hx # src/openfl/display/OpenGLRenderer.hx # src/openfl/display/Shader.hx # src/openfl/display/ShaderParameter.hx # src/openfl/display/ShaderParameterType.hx # src/openfl/display/_internal/DrawCommandBuffer.hx # src/openfl/display/_internal/DrawCommandReader.hx # src/openfl/display3D/Context3D.hx # src/openfl/display3D/IndexBuffer3D.hx # src/openfl/display3D/Program3D.hx # src/openfl/display3D/VertexBuffer3D.hx # src/openfl/utils/Assets.hx --- src/openfl/display/BitmapData.hx | 23 +- src/openfl/display/DisplayObjectShader.hx | 109 +- src/openfl/display/Graphics.hx | 7 + src/openfl/display/GraphicsShader.hx | 109 +- src/openfl/display/Shader.hx | 1359 +++++++++-------- src/openfl/display/ShaderData.hx | 2 +- src/openfl/display/ShaderInput.hx | 2 +- src/openfl/display/ShaderParameter.hx | 184 ++- src/openfl/display/ShaderParameterType.hx | 172 ++- src/openfl/display/_internal/CairoGraphics.hx | 4 +- .../_internal/Context3DAlphaMaskShader.hx | 2 - .../display/_internal/Context3DBitmap.hx | 2 +- .../display/_internal/Context3DGraphics.hx | 61 +- .../display/_internal/Context3DMaskShader.hx | 2 - .../display/_internal/Context3DVideo.hx | 2 +- .../display/_internal/DrawCommandBuffer.hx | 202 ++- .../display/_internal/DrawCommandReader.hx | 34 + .../display/_internal/DrawCommandType.hx | 3 + src/openfl/display3D/Context3D.hx | 33 +- src/openfl/display3D/IndexBuffer3D.hx | 11 +- src/openfl/display3D/Program3D.hx | 910 +++++------ src/openfl/display3D/VertexBuffer3D.hx | 12 +- src/openfl/filters/BlurFilter.hx | 19 +- src/openfl/filters/ColorMatrixFilter.hx | 12 +- src/openfl/filters/ConvolutionFilter.hx | 2 +- src/openfl/filters/DisplacementMapFilter.hx | 20 +- src/openfl/filters/DropShadowFilter.hx | 21 +- src/openfl/filters/GlowFilter.hx | 60 +- src/openfl/geom/Matrix3D.hx | 354 ++--- src/openfl/utils/Assets.hx | 128 +- src/openfl/utils/BitmapDataUtil.hx | 289 ++++ src/openfl/utils/GLSLSourceAssembler.hx | 590 +++++++ src/openfl/utils/_internal/Log.hx | 10 +- src/openfl/utils/_internal/ShaderMacro.hx | 724 +++------ 34 files changed, 3232 insertions(+), 2242 deletions(-) create mode 100644 src/openfl/utils/BitmapDataUtil.hx create mode 100644 src/openfl/utils/GLSLSourceAssembler.hx diff --git a/src/openfl/display/BitmapData.hx b/src/openfl/display/BitmapData.hx index 7403dcb849..bb96436bf3 100644 --- a/src/openfl/display/BitmapData.hx +++ b/src/openfl/display/BitmapData.hx @@ -3223,10 +3223,11 @@ class BitmapData implements IBitmapDrawable if (allowFramebuffer && __texture != null && __texture.__glFramebuffer != null - && Lib.current.stage.__renderer.__type == OPENGL) + && __texture.__context != null + && __texture.__context.gl != null) { - var renderer:OpenGLRenderer = cast Lib.current.stage.__renderer; - var context = renderer.__context3D; + var context = __texture.__context; + var color:ARGB = (color : ARGB); var useScissor = !this.rect.equals(rect); @@ -3234,6 +3235,8 @@ class BitmapData implements IBitmapDrawable var cacheRTTDepthStencil = context.__state.renderToTextureDepthStencil; var cacheRTTAntiAlias = context.__state.renderToTextureAntiAlias; var cacheRTTSurfaceSelector = context.__state.renderToTextureSurfaceSelector; + var cacheSE = context.__state.scissorEnabled; + var cacheSR = context.__state.scissorRectangle; context.setRenderToTexture(__texture); @@ -3258,11 +3261,6 @@ class BitmapData implements IBitmapDrawable context.__clear(useScissor, color.r / 0xFF, color.g / 0xFF, color.b / 0xFF, transparent ? color.a / 0xFF : 1, 0, 0, Context3DClearMask.COLOR); - if (useScissor) - { - context.setScissorRectangle(null); - } - if (cacheRTT != null) { context.setRenderToTexture(cacheRTT, cacheRTTDepthStencil, cacheRTTAntiAlias, cacheRTTSurfaceSelector); @@ -3271,6 +3269,15 @@ class BitmapData implements IBitmapDrawable { context.setRenderToBackBuffer(); } + + if (cacheSE) + { + context.setScissorRectangle(cacheSR); + } + else + { + context.setScissorRectangle(null); + } } else if (readable) { diff --git a/src/openfl/display/DisplayObjectShader.hx b/src/openfl/display/DisplayObjectShader.hx index 3c225c36eb..90d34c4431 100644 --- a/src/openfl/display/DisplayObjectShader.hx +++ b/src/openfl/display/DisplayObjectShader.hx @@ -5,87 +5,64 @@ import openfl.utils.ByteArray; class DisplayObjectShader extends Shader { @:glVertexHeader("attribute float openfl_Alpha; - attribute vec4 openfl_ColorMultiplier; - attribute vec4 openfl_ColorOffset; - attribute vec4 openfl_Position; - attribute vec2 openfl_TextureCoord; +attribute vec4 openfl_ColorMultiplier; +attribute vec4 openfl_ColorOffset; +attribute vec4 openfl_Position; +attribute vec2 openfl_TextureCoord; - varying float openfl_Alphav; - varying vec4 openfl_ColorMultiplierv; - varying vec4 openfl_ColorOffsetv; - varying vec2 openfl_TextureCoordv; +varying float openfl_Alphav; +varying vec4 openfl_ColorMultiplierv; +varying vec4 openfl_ColorOffsetv; +varying vec2 openfl_TextureCoordv; - uniform mat4 openfl_Matrix; - uniform bool openfl_HasColorTransform; - uniform vec2 openfl_TextureSize;") - @:glVertexBody("openfl_Alphav = openfl_Alpha; - openfl_TextureCoordv = openfl_TextureCoord; +uniform mat4 openfl_Matrix; +uniform bool openfl_HasColorTransform; +uniform vec2 openfl_TextureSize;") - if (openfl_HasColorTransform) { + @:glVertexBody("openfl_Alphav = openfl_Alpha; +openfl_TextureCoordv = openfl_TextureCoord; - openfl_ColorMultiplierv = openfl_ColorMultiplier; - openfl_ColorOffsetv = openfl_ColorOffset / 255.0; +if (openfl_HasColorTransform) { + openfl_ColorMultiplierv = openfl_ColorMultiplier; + openfl_ColorOffsetv = openfl_ColorOffset / 255.0; +} - } +gl_Position = openfl_Matrix * openfl_Position;") - gl_Position = openfl_Matrix * openfl_Position;") @:glVertexSource("#pragma header +void main(void) { + #pragma body +}") - void main(void) { - - #pragma body - - }") @:glFragmentHeader("varying float openfl_Alphav; - varying vec4 openfl_ColorMultiplierv; - varying vec4 openfl_ColorOffsetv; - varying vec2 openfl_TextureCoordv; - - uniform bool openfl_HasColorTransform; - uniform sampler2D openfl_Texture; - uniform vec2 openfl_TextureSize;") - @:glFragmentBody("vec4 color = texture2D (openfl_Texture, openfl_TextureCoordv); - - if (color.a == 0.0) { - - gl_FragColor = vec4 (0.0, 0.0, 0.0, 0.0); - - } else if (openfl_HasColorTransform) { - - color = vec4 (color.rgb / color.a, color.a); +varying vec4 openfl_ColorMultiplierv; +varying vec4 openfl_ColorOffsetv; +varying vec2 openfl_TextureCoordv; - mat4 colorMultiplier = mat4 (0); - colorMultiplier[0][0] = openfl_ColorMultiplierv.x; - colorMultiplier[1][1] = openfl_ColorMultiplierv.y; - colorMultiplier[2][2] = openfl_ColorMultiplierv.z; - colorMultiplier[3][3] = 1.0; // openfl_ColorMultiplierv.w; +uniform bool openfl_HasColorTransform; +uniform vec2 openfl_TextureSize; +uniform sampler2D openfl_Texture;") - color = clamp (openfl_ColorOffsetv + (color * colorMultiplier), 0.0, 1.0); + @:glFragmentBody("vec4 color = texture2D(openfl_Texture, openfl_TextureCoordv); - if (color.a > 0.0) { +if (color.a == 0.0 || openfl_Alphav == 0.0) discard; +else if (openfl_HasColorTransform) { + color = vec4(color.rgb / color.a, color.a); + vec4 mult = vec4(openfl_ColorMultiplierv.rgb, 1.0); + color = clamp(openfl_ColorOffsetv + (color * mult), 0.0, 1.0); - gl_FragColor = vec4 (color.rgb * color.a * openfl_Alphav, color.a * openfl_Alphav); - - } else { - - gl_FragColor = vec4 (0.0, 0.0, 0.0, 0.0); - - } - - } else { - - gl_FragColor = color * openfl_Alphav; + gl_FragColor = vec4(color.rgb * color.a * openfl_Alphav, color.a * openfl_Alphav); + if (color.a == 0.0) discard; +} +else { + gl_FragColor = color * openfl_Alphav; +}") - }") @:glFragmentSource("#pragma header - - void main(void) { - - #pragma body - - }") - public function new(code:ByteArray = null) - { +void main(void) { + #pragma body +}") + public function new(code:ByteArray = null) { super(code); } } diff --git a/src/openfl/display/Graphics.hx b/src/openfl/display/Graphics.hx index 8a9d7b9589..cb3eb2dbb4 100644 --- a/src/openfl/display/Graphics.hx +++ b/src/openfl/display/Graphics.hx @@ -6,6 +6,7 @@ import openfl.display._internal.Context3DBuffer; import openfl.display._internal.DrawCommandBuffer; import openfl.display._internal.DrawCommandReader; import openfl.display._internal.ShaderBuffer; +import openfl.display3D.Context3DCompareMode; import openfl.display3D.IndexBuffer3D; import openfl.display3D.VertexBuffer3D; import openfl.errors.ArgumentError; @@ -1566,6 +1567,12 @@ import js.html.CanvasRenderingContext2D; __commands.overrideBlendMode(blendMode); } + public function overrideDepthTest(depthTest:Bool = false, compareMode:Context3DCompareMode):Void + { + if (compareMode == null) compareMode = ALWAYS; + __commands.overrideDepthTest(depthTest, compareMode); + } + /** Queries a Sprite or Shape object (and optionally, its children) for its vector graphics content. The result is a Vector of IGraphicsData objects. Transformations diff --git a/src/openfl/display/GraphicsShader.hx b/src/openfl/display/GraphicsShader.hx index 5df21e928d..b626c98280 100644 --- a/src/openfl/display/GraphicsShader.hx +++ b/src/openfl/display/GraphicsShader.hx @@ -5,87 +5,64 @@ import openfl.utils.ByteArray; class GraphicsShader extends Shader { @:glVertexHeader("attribute float openfl_Alpha; - attribute vec4 openfl_ColorMultiplier; - attribute vec4 openfl_ColorOffset; - attribute vec4 openfl_Position; - attribute vec2 openfl_TextureCoord; +attribute vec4 openfl_ColorMultiplier; +attribute vec4 openfl_ColorOffset; +attribute vec4 openfl_Position; +attribute vec2 openfl_TextureCoord; - varying float openfl_Alphav; - varying vec4 openfl_ColorMultiplierv; - varying vec4 openfl_ColorOffsetv; - varying vec2 openfl_TextureCoordv; +varying float openfl_Alphav; +varying vec4 openfl_ColorMultiplierv; +varying vec4 openfl_ColorOffsetv; +varying vec2 openfl_TextureCoordv; - uniform mat4 openfl_Matrix; - uniform bool openfl_HasColorTransform; - uniform vec2 openfl_TextureSize;", true) - @:glVertexBody("openfl_Alphav = openfl_Alpha; - openfl_TextureCoordv = openfl_TextureCoord; +uniform mat4 openfl_Matrix; +uniform bool openfl_HasColorTransform; +uniform vec2 openfl_TextureSize;") - if (openfl_HasColorTransform) { + @:glVertexBody("openfl_Alphav = openfl_Alpha; +openfl_TextureCoordv = openfl_TextureCoord; - openfl_ColorMultiplierv = openfl_ColorMultiplier; - openfl_ColorOffsetv = openfl_ColorOffset / 255.0; +if (openfl_HasColorTransform) { + openfl_ColorMultiplierv = openfl_ColorMultiplier; + openfl_ColorOffsetv = openfl_ColorOffset / 255.0; +} - } +gl_Position = openfl_Matrix * openfl_Position;") - gl_Position = openfl_Matrix * openfl_Position;") @:glVertexSource("#pragma header +void main(void) { + #pragma body +}") - void main(void) { - - #pragma body - - }") @:glFragmentHeader("varying float openfl_Alphav; - varying vec4 openfl_ColorMultiplierv; - varying vec4 openfl_ColorOffsetv; - varying vec2 openfl_TextureCoordv; - - uniform bool openfl_HasColorTransform; - uniform vec2 openfl_TextureSize; - uniform sampler2D bitmap;", true) - @:glFragmentBody("vec4 color = texture2D (bitmap, openfl_TextureCoordv); - - if (color.a == 0.0) { - - gl_FragColor = vec4 (0.0, 0.0, 0.0, 0.0); - - } else if (openfl_HasColorTransform) { - - color = vec4 (color.rgb / color.a, color.a); +varying vec4 openfl_ColorMultiplierv; +varying vec4 openfl_ColorOffsetv; +varying vec2 openfl_TextureCoordv; - mat4 colorMultiplier = mat4 (0); - colorMultiplier[0][0] = openfl_ColorMultiplierv.x; - colorMultiplier[1][1] = openfl_ColorMultiplierv.y; - colorMultiplier[2][2] = openfl_ColorMultiplierv.z; - colorMultiplier[3][3] = 1.0; // openfl_ColorMultiplierv.w; +uniform bool openfl_HasColorTransform; +uniform vec2 openfl_TextureSize; +uniform sampler2D bitmap;") - color = clamp (openfl_ColorOffsetv + (color * colorMultiplier), 0.0, 1.0); + @:glFragmentBody("vec4 color = texture2D(bitmap, openfl_TextureCoordv); - if (color.a > 0.0) { +if (color.a == 0.0 || openfl_Alphav == 0.0) discard; +else if (openfl_HasColorTransform) { + color = vec4(color.rgb / color.a, color.a); + vec4 mult = vec4(openfl_ColorMultiplierv.rgb, 1.0); + color = clamp(openfl_ColorOffsetv + (color * mult), 0.0, 1.0); - gl_FragColor = vec4 (color.rgb * color.a * openfl_Alphav, color.a * openfl_Alphav); - - } else { - - gl_FragColor = vec4 (0.0, 0.0, 0.0, 0.0); - - } - - } else { - - gl_FragColor = color * openfl_Alphav; + gl_FragColor = vec4(color.rgb * color.a * openfl_Alphav, color.a * openfl_Alphav); + if (color.a == 0.0) discard; +} +else { + gl_FragColor = color * openfl_Alphav; +}") - }", true) @:glFragmentSource("#pragma header - - void main(void) { - - #pragma body - - }") - public function new(code:ByteArray = null) - { +void main(void) { + #pragma body +}") + public function new(code:ByteArray = null) { super(code); } } diff --git a/src/openfl/display/Shader.hx b/src/openfl/display/Shader.hx index a6b5e6d8c1..8ba18f4825 100644 --- a/src/openfl/display/Shader.hx +++ b/src/openfl/display/Shader.hx @@ -3,128 +3,129 @@ package openfl.display; import openfl.display3D.Context3DWrapMode; import openfl.display3D.Context3DMipFilter; import openfl.display3D.Context3DTextureFilter; -import openfl.display._internal.ShaderBuffer; -import openfl.display3D.Context3D; -import openfl.display3D.Program3D; import openfl.display3D._internal.GLProgram; import openfl.display3D._internal.GLShader; -import openfl.utils.ByteArray; +import openfl.display._internal.ShaderBuffer; import openfl.utils._internal.Float32Array; import openfl.utils._internal.Log; +import openfl.display3D.Context3D; +import openfl.display3D.Program3D; +import openfl.utils.Assets; +import openfl.utils.ByteArray; +import openfl.utils.GLSLSourceAssembler; import openfl.Lib; +#if lime +import lime.graphics.opengl.GL; +#end /** // TODO: Document GLSL Shaders - A Shader instance represents a Pixel Bender shader kernel in ActionScript. - To use a shader in your application, you create a Shader instance for it. - You then use that Shader instance in the appropriate way according to the - effect you want to create. For example, to use the shader as a filter, you - assign the Shader instance to the `shader` property of a ShaderFilter - object. - A shader defines a function that executes on all the pixels in an image, - one pixel at a time. The result of each call to the function is the output - color at that pixel coordinate in the image. A shader can specify one or - more input images, which are images whose content can be used in - determining the output of the function. A shader can also specify one or - more parameters, which are input values that can be used in calculating - the function output. In a single shader execution, the input and parameter - values are constant. The only thing that varies is the coordinate of the - pixel whose color is the function result. Shader function calls for - multiple output pixel coordinates execute in parallel to improve shader - execution performance. - - The shader bytecode can be loaded at run time using a URLLoader instance. - The following example demonstrates loading a shader bytecode file at run - time and linking it to a Shader instance. - - ```as3 - var loader:URLLoader = new URLLoader(); - loader.dataFormat = URLLoaderDataFormat.BINARY; - loader.addEventListener(Event.COMPLETE, onLoadComplete); - loader.load(new URLRequest("myShader.pbj")); - var shader:Shader; - - function onLoadComplete(event:Event):void { - // Create a new shader and set the loaded data as its bytecode - shader = new Shader(); - shader.byteCode = loader.data; - - // You can also pass the bytecode to the Shader() constructor like this: - // shader = new Shader(loader.data); - - // do something with the shader - } - ``` - - You can also embed the shader into the SWF at compile time using the - `[Embed]` metadata tag. The `[Embed]` metadata tag is only available if - you use the Flex SDK to compile the SWF. The `[Embed]` tag's `source` - parameter points to the shader file, and its `mimeType` parameter is - `"application/octet-stream"`, as in this example: - - ```as3 - [Embed(source="myShader.pbj", mimeType="application/octet-stream)] var MyShaderClass:Class; - - // ... - - // create a new shader and set the embedded shader as its bytecode var - shaderShader = new Shader(); - shader.byteCode = new MyShaderClass(); - - // You can also pass the bytecode to the Shader() constructor like this: - // var shader:Shader = new Shader(new MyShaderClass()); - - // do something with the shader - ``` - - In either case, you link the raw shader (the `URLLoader.data` property or - an instance of the `[Embed]` data class) to the Shader instance. As the - previous examples demonstrate, you can do this in two ways. You can pass - the shader bytecode as an argument to the `Shader()` constructor. - Alternatively, you can set it as the Shader instance's `byteCode` - property. - - Once a Shader instance is created, it can be used in one of several ways: - - * A shader fill: The output of the shader is used as a fill for content - drawn with the drawing API. Pass the Shader instance as an argument to the - `Graphics.beginShaderFill()` method. - * A shader filter: The output of the shader is used as a graphic filter - applied to a display object. Assign the Shader instance to the `shader` - property of a ShaderFilter instance. - * A blend mode: The output of the shader is rendered as the blending - between two overlapping display objects. Assign the Shader instance to the - `blendShader` property of the upper of the two display objects. - * Background shader processing: The shader executes in the background, - avoiding the possibility of freezing the display, and dispatches an event - when processing is complete. Assign the Shader instance to the `shader` - property of a ShaderJob instance. - - Shader fills, filters, and blends are not supported under GPU rendering. - - **Mobile Browser Support:** This feature is not supported in mobile - browsers. - - _Adobe AIR profile support:_ This feature is supported on all desktop operating - systems, but it is not supported on all mobile devices. It is not - supported on AIR for TV devices. See - [AIR Profile Support](https://help.adobe.com/en_US/air/build/WS144092a96ffef7cc16ddeea2126bb46b82f-8000.html) - for more information regarding API support across multiple profiles. **/ @:access(openfl.display3D.Context3D) @:access(openfl.display3D.Program3D) +@:access(openfl.display.OpenGLRenderer) @:access(openfl.display.ShaderInput) @:access(openfl.display.ShaderParameter) @:access(openfl.display.Stage) @:access(openfl.events.UncaughtErrorEvents) -// #if (!display && !macro) #if !macro @:autoBuild(openfl.utils._internal.ShaderMacro.build()) #end class Shader { + public static function getParameterTypeFromGLEnum(type:Int, isArray:Bool):Null + { + return switch (type) + { + case GL.BOOL: isArray ? BOOLV : BOOL; + case GL.FLOAT: isArray ? FLOATV : FLOAT; + case GL.INT, GL.UNSIGNED_INT: isArray ? INTV : INT; + case GL.BOOL_VEC2: isArray ? BOOL2V : BOOL2; + case GL.BOOL_VEC3: isArray ? BOOL3V : BOOL3; + case GL.BOOL_VEC4: isArray ? BOOL4V : BOOL4; + case GL.INT_VEC2, GL.UNSIGNED_INT_VEC2: isArray ? INT2V : INT2; + case GL.INT_VEC3, GL.UNSIGNED_INT_VEC3: isArray ? INT3V : INT3; + case GL.INT_VEC4, GL.UNSIGNED_INT_VEC4: isArray ? INT4V : INT4; + case GL.FLOAT_VEC2: isArray ? FLOAT2V : FLOAT2; + case GL.FLOAT_VEC3: isArray ? FLOAT3V : FLOAT3; + case GL.FLOAT_VEC4: isArray ? FLOAT4V : FLOAT4; + case GL.FLOAT_MAT2: isArray ? MATRIX2X2V : MATRIX2X2; + case GL.FLOAT_MAT2x3: isArray ? MATRIX2X3V : MATRIX2X3; + case GL.FLOAT_MAT2x4: isArray ? MATRIX2X4V : MATRIX2X4; + case GL.FLOAT_MAT3x2: isArray ? MATRIX3X2V : MATRIX3X2; + case GL.FLOAT_MAT3: isArray ? MATRIX3X3V : MATRIX3X3; + case GL.FLOAT_MAT3x4: isArray ? MATRIX3X4V : MATRIX3X4; + case GL.FLOAT_MAT4x2: isArray ? MATRIX4X2V : MATRIX4X2; + case GL.FLOAT_MAT4x3: isArray ? MATRIX4X3V : MATRIX4X3; + case GL.FLOAT_MAT4: isArray ? MATRIX4X4V : MATRIX4X4; + default: null; + } + } + + public static function getParameterTypeFromGLSL(string:String, isArray:Bool):Null + { + return switch (string) + { + case "bool": isArray ? BOOLV : BOOL; + case "double", "float": isArray ? FLOATV : FLOAT; + case "int", "uint": isArray ? INTV : INT; + case "bvec2": isArray ? BOOL2V : BOOL2; + case "bvec3": isArray ? BOOL3V : BOOL3; + case "bvec4": isArray ? BOOL4V : BOOL4; + case "ivec2", "uvec2": isArray ? INT2V : INT2; + case "ivec3", "uvec3": isArray ? INT3V : INT3; + case "ivec4", "uvec4": isArray ? INT4V : INT4; + case "vec2", "dvec2": isArray ? FLOAT2V : FLOAT2; + case "vec3", "dvec3": isArray ? FLOAT3V : FLOAT3; + case "vec4", "dvec4": isArray ? FLOAT4V : FLOAT4; + case "mat2", "mat2x2": isArray ? MATRIX2X2V : MATRIX2X2; + case "mat2x3": isArray ? MATRIX2X3V : MATRIX2X3; + case "mat2x4": isArray ? MATRIX2X4V : MATRIX2X4; + case "mat3x2": isArray ? MATRIX3X2V : MATRIX3X2; + case "mat3", "mat3x3": isArray ? MATRIX3X3V : MATRIX3X3; + case "mat3x4": isArray ? MATRIX3X4V : MATRIX3X4; + case "mat4x2": isArray ? MATRIX4X2V : MATRIX4X2; + case "mat4x3": isArray ? MATRIX4X3V : MATRIX4X3; + case "mat4", "mat4x4": isArray ? MATRIX4X4V : MATRIX4X4; + default: null; + } + } + + public static function processGLSLParameter(source:String, storageType:String, callback:ShaderProcessParameterCallback):String + { + var isVertex = storageType != "uniform", regex:EReg = switch (storageType) + { + case "uniform": ~/\buniform\s+([A-Za-z0-9_]+)\s+([A-Za-z0-9_]+)(?:\s*)?(?:\[(\w+)\])?\s*(?:=)?\s*(.+?(?=;))?/gu; + case "in": ~/\bin\s+([A-Za-z0-9_]+)\s+([A-Za-z0-9_]+)(?:\s*)?(?:\[(\w+)\])?/gu; + case "attribute": ~/\battribute\s+([A-Za-z0-9_]+)\s+([A-Za-z0-9_]+)(?:\s*)?(?:\[(\w+)\])?/gu; + default: throw "Unknown storageType for Shader.processGLSLParameter " + storageType; + } + + var arrayLength:Null, position; + return regex.map(source, (_) -> + { + if (regex.matched(3) == null) arrayLength = 0; + else if ((arrayLength = Std.parseInt(regex.matched(3))) == null) arrayLength = 1; + + callback(isVertex, regex.matched(1), regex.matched(2), arrayLength, isVertex ? null : regex.matched(4)); + + if (isVertex) + { + position = regex.matchedPos(); + return source.substr(position.pos, position.len); + } + else + { + return 'uniform ${regex.matched(1)} ${regex.matched(2)}${arrayLength == 0 ? "" : "[" + regex.matched(3) + "]"}'; + } + }); + } + /** - The raw shader bytecode for this Shader instance. + The raw Pixel Bender shader bytecode for this Shader + instance. + + This property is used only on the Flash target. **/ public var byteCode(null, default):ByteArray; @@ -143,43 +144,80 @@ class Shader /** Get or set the GLSL version used in the header when compiling with GLSL. + When set to null, it will sets to the default GLSL version from either + the source or GLSLSourceAssembler.getDefaultVersion when it gets + compiled later. + + @default The default value is determined at compile time, or whatever assembly this shader is using. + **/ + public var glVersion(get, set):Null; + + /** + The raw of this GLSL Version used before being applied to compile with GLSL. + **/ + public var glVersionRaw(get, never):Null; - - `120` is required for initialization (i.e. providing a default value for) `uniform` variables - @default The default value is determined at compile time. + /** + Provides additional `#extension` directives to insert in the vertex shaders. + + Example: + ``` + @:glVertexExtensions("OES_standard_derivatives", "require") + // or @:glExtensions("OES_standard_derivatives", "require") + ``` **/ - public var glVersion(get, set):String; + public var glVertexExtensions(get, set):Map; /** - Provides additional `#extension` directives to insert in the vertex and fragment shaders. + Provides additional `#extension` directives to insert in the fragment shaders. Example: ``` - @:glExtensions([{name: "OES_standard_derivatives", behavior: "require"}]) - @:glVertexExtensions([{name: "OES_standard_derivatives", behavior: "require"}]) - @:glFragmentExtensions([{name: "OES_standard_derivatives", behavior: "require"}]) + @:glFragmentExtensions("OES_standard_derivatives", "require") + // or @:glExtensions("OES_standard_derivatives", "require") ``` **/ - public var glVertexExtensions(get, set):Array<{name:String, behavior:String}>; + public var glFragmentExtensions(get, set):Map; + + /** + Provides an additional pragmas to use in (child class of) vertex shaders. + + Example: + ``` + @:glVertexHeader(...) + @:glVertexBody(...) + ``` + **/ + public var glVertexPragmas(get, set):Map; + + /** + Provides an additional pragmas to use in (child class of) fragment shaders. - public var glFragmentExtensions(get, set):Array<{name:String, behavior:String}>; + Example: + ``` + @:glFragmentHeader(...) + @:glFragmentBody(...) + ``` + **/ + public var glFragmentPragmas(get, set):Map; /** The default GLSL vertex header, before being applied to the vertex source. **/ - public var glFragmentHeaderRaw(get, null):String; + public var glFragmentHeaderRaw(get, never):String; /** The default GLSL vertex body, before being applied to the vertex source. **/ - public var glFragmentBodyRaw(get, null):String; + public var glFragmentBodyRaw(get, never):String; /** The default GLSL fragment source, before `#pragma` values are replaced. **/ - public var glFragmentSourceRaw(get, null):String; + public var glFragmentSourceRaw(get, never):String; /** - Get or set the fragment source used when compiling with GLSL. + Get or set the fragment source used when targeting OpenGL. This property is not available on the Flash target. **/ @@ -191,24 +229,23 @@ class Shader This property is not available on the Flash target. **/ @SuppressWarnings("checkstyle:Dynamic") public var glProgram(default, null):GLProgram; - /** The default GLSL vertex header, before being applied to the vertex source. **/ - public var glVertexHeaderRaw(get, null):String; + public var glVertexHeaderRaw(get, never):String; /** The default GLSL vertex body, before being applied to the vertex source. **/ - public var glVertexBodyRaw(get, null):String; + public var glVertexBodyRaw(get, never):String; /** The default GLSL vertex source, before `#pragma` values are replaced. **/ - public var glVertexSourceRaw(get, null):String; + public var glVertexSourceRaw(get, never):String; /** - Get or set the vertex source used when compiling with GLSL. + Get or set the vertex source used when targeting OpenGL. This property is not available on the Flash target. **/ @@ -253,7 +290,7 @@ class Shader * `reciprocal(x)` * `sqrt(x)` **/ - public var precisionHint:ShaderPrecision; + public var precisionHint(get, set):ShaderPrecision; /** The compiled Program3D if available. @@ -264,20 +301,22 @@ class Shader @:noCompletion private var __alpha:ShaderParameter; @:noCompletion private var __bitmap:ShaderInput; + @:noCompletion private var __cacheProgramId:String; @:noCompletion private var __colorMultiplier:ShaderParameter; @:noCompletion private var __colorOffset:ShaderParameter; @:noCompletion private var __context:Context3D; @:noCompletion private var __data:ShaderData; - @:noCompletion private var __glVertexExtensions:Array<{name:String, behavior:String}>; - @:noCompletion private var __glFragmentExtensions:Array<{name:String, behavior:String}>; + @:noCompletion private var __fieldList:Array; + @:noCompletion private var __glVertexExtensions:Map; + @:noCompletion private var __glFragmentExtensions:Map; + @:noCompletion private var __glVertexPragmas:Map; + @:noCompletion private var __glFragmentPragmas:Map; + @:noCompletion private var __glVersionRaw:Null; @:noCompletion private var __glVersion:String; - @:noCompletion private var __glFragmentHeaderRaw:String; - @:noCompletion private var __glFragmentBodyRaw:String; @:noCompletion private var __glFragmentSourceRaw:String; @:noCompletion private var __glFragmentSource:String; + @:noCompletion private var __glSourceAssembler:GLSLSourceAssembler; @:noCompletion private var __glSourceDirty:Bool; - @:noCompletion private var __glVertexHeaderRaw:String; - @:noCompletion private var __glVertexBodyRaw:String; @:noCompletion private var __glVertexSourceRaw:String; @:noCompletion private var __glVertexSource:String; @:noCompletion private var __hasColorTransform:ShaderParameter; @@ -289,6 +328,7 @@ class Shader @:noCompletion private var __paramFloat:Array>; @:noCompletion private var __paramInt:Array>; @:noCompletion private var __position:ShaderParameter; + @:noCompletion private var __precisionHint:ShaderPrecision; @:noCompletion private var __textureCoord:ShaderParameter; @:noCompletion private var __texture:ShaderInput; @:noCompletion private var __textureSize:ShaderParameter; @@ -301,11 +341,19 @@ class Shader public function new(code:ByteArray = null) { byteCode = code; - precisionHint = FULL; __glSourceDirty = true; __numPasses = 1; - __data = new ShaderData(code); + __precisionHint = FULL; + __createAssembler(); + } + + @:noCompletion private function __createAssembler():Void + { + if (__glSourceAssembler == null) + { + __glSourceAssembler = new GLSLSourceAssembler(); + } } @:noCompletion private function __clearUseArray():Void @@ -326,151 +374,6 @@ class Shader } } - // private function __clone ():Shader { - // var classType = Type.getClass (this); - // var shader = Type.createInstance (classType, []); - // for (input in __inputBitmapData) { - // if (input.input != null) { - // var field = Reflect.field (shader.data, input.name); - // field.channels = input.channels; - // field.height = input.height; - // field.input = input.input; - // field.smoothing = input.smoothing; - // field.width = input.width; - // } - // } - // for (param in __paramBool) { - // if (param.value != null) { - // Reflect.field (shader.data, param.name).value = param.value.copy (); - // } - // } - // for (param in __paramFloat) { - // if (param.value != null) { - // Reflect.field (shader.data, param.name).value = param.value.copy (); - // } - // } - // for (param in __paramInt) { - // if (param.value != null) { - // Reflect.field (shader.data, param.name).value = param.value.copy (); - // } - // } - // return shader; - // } - @:noCompletion private function __createGLShader(source:String, type:Int):GLShader - { - var gl = __context.gl; - - var shader = gl.createShader(type); - gl.shaderSource(shader, source); - gl.compileShader(shader); - var shaderInfoLog = gl.getShaderInfoLog(shader); - var hasInfoLog = shaderInfoLog != null && StringTools.trim(shaderInfoLog) != ""; - var isError = gl.getShaderParameter(shader, gl.COMPILE_STATUS) == 0; - - if (hasInfoLog || isError) - { - __logGLShaderInfo(isError, type, shaderInfoLog, source); - } - - return shader; - } - - /** - * Retrieves the line number from a shader log line. - */ - #if windows - // 0(5) : whatever - @:noCompletion private var __lineExtractor = ~/^\d+\((\d+)\) : (.+$)/; - #else // (html5 || macos || linux) - // ERROR: 0:5:whatever - @:noCompletion private var __lineExtractor = ~/^\w+?: \d+:(\d+):(.+$)/; - #end - - /** - * Searches for strings that have only whitespace. - * - * **Note:** Searching for all whitespace via `~/^\s*$/` caused false-negatives, - * notably: `String.fromCharCode(0)` is `false` but `\W` is `true`. - */ - @:noCompletion private var __isEmptyLine = ~/^\W*$/; - - @:noCompletion private function __logGLShaderInfo(isError:Bool, type:Int, infoLog:String, source:String):Void - { - var message = ""; - var lines = source.split("\n"); - var failingLine:String = null; - for (log in infoLog.split("\n")) - { - // ignore empty lines - if (__isEmptyLine.match(log)) continue; - - // look for a line number - if (!__lineExtractor.match(log)) - { - // Could not find expected info, abort pretty formatting - failingLine = log; - break; - } - - var lineNumberStr = __lineExtractor.matched(1); - var lineNumber = Std.parseInt(lineNumberStr); - var info = __lineExtractor.matched(2); - if (lineNumber >= lines.length) - { - // EOF errors will not have a valid line - message += '\n\n $lineNumber | $info'; - } - else - { - // Add the relevant line to each log - var line = lines[lineNumber - 1]; - var indent = StringTools.lpad("|", " ", lineNumberStr.length + 3); - message += '\n\n $lineNumber | $line\n$indent ${info}'; - } - } - - // If we couldn't parse the logs, output the old, verbose format - if (failingLine != null) message = '\nFailed to simplify log:"$failingLine"\n$infoLog\n$source'; - - var typeName = (type == __context.gl.VERTEX_SHADER) ? "vertex" : "fragment"; - if (isError) Log.error('Error compiling $typeName shader $message'); - else - Log.debug('Info compiling $typeName shader $message'); - } - - @:noCompletion private function __createGLProgram(vertexSource:String, fragmentSource:String):GLProgram - { - var gl = __context.gl; - - var vertexShader = __createGLShader(vertexSource, gl.VERTEX_SHADER); - var fragmentShader = __createGLShader(fragmentSource, gl.FRAGMENT_SHADER); - - var program = gl.createProgram(); - - // Fix support for drivers that don't draw if attribute 0 is disabled - for (param in __paramFloat) - { - if (param.name.indexOf("Position") > -1 && StringTools.startsWith(param.name, "openfl_")) - { - gl.bindAttribLocation(program, 0, param.name); - break; - } - } - - gl.attachShader(program, vertexShader); - gl.attachShader(program, fragmentShader); - gl.linkProgram(program); - - if (gl.getProgramParameter(program, gl.LINK_STATUS) == 0) - { - var message = "Unable to initialize the shader program"; - message += "\n" + gl.getProgramInfoLog(program); - Log.error(message); - } - - return program; - } - @:noCompletion private function __disable():Void { if (program != null) @@ -489,7 +392,6 @@ class Shader { input.__disableGL(__context, textureCount); textureCount++; - if (textureCount == gl.MAX_TEXTURE_IMAGE_UNITS) break; } for (parameter in __paramBool) @@ -536,7 +438,9 @@ class Shader for (input in __inputBitmapData) { gl.uniform1i(input.index, textureCount); + textureCount++; + //if (textureCount == gl.MAX_TEXTURE_IMAGE_UNITS) break; } #if lime @@ -547,6 +451,21 @@ class Shader #end } + @:noCompletion private function __resetParams():Void + { + #if haxe4 + if (__inputBitmapData == null) __inputBitmapData = new Array(); else __inputBitmapData.resize(0); + if (__paramBool == null) __paramBool = new Array(); else __paramBool.resize(0); + if (__paramFloat == null) __paramFloat = new Array(); else __paramFloat.resize(0); + if (__paramInt == null) __paramInt = new Array(); else __paramInt.resize(0); + #else + __inputBitmapData = new Array(); + __paramBool = new Array(); + __paramFloat = new Array(); + __paramInt = new Array(); + #end + } + @:noCompletion private function __init():Void { if (__data == null) @@ -554,398 +473,472 @@ class Shader __data = cast new ShaderData(null); } - if (__glFragmentSource != null && __glVertexSource != null && (program == null || __glSourceDirty)) + if (__glFragmentSourceRaw != null && __glVertexSourceRaw != null && (program == null || __glSourceDirty)) { __initGL(); } } - @:noCompletion private function __buildSourcePrefix(isFragment:Bool):String + @:noCompletion private function __initGL():Void { - var extensions = ""; + var id = __cacheProgramId != null ? __cacheProgramId + (__precisionHint == FAST ? "FAST" : "") : null; - var extList = (isFragment ? __glFragmentExtensions : __glVertexExtensions); - - for (ext in extList) + if (__glSourceDirty) { - extensions += "#extension " + ext.name + " : " + ext.behavior + "\n"; - } + program = null; + glProgram = null; - var complexBlendsSupported = OpenGLRenderer.__complexBlendsSupported && isFragment; - var standardDerivativesSupported = OpenGLRenderer.__standardDerivativesSupported && isFragment; + __resetParams(); - #if lime - if (__context.__context.type == OPENGL) - { - complexBlendsSupported = complexBlendsSupported && (__glVersion == "150" || !StringTools.startsWith(__glVersion, "1")); - } - else if (__context.__context.type == OPENGLES) - { - complexBlendsSupported = complexBlendsSupported && !StringTools.startsWith(__glVersion, "1"); - } - #end + if (id != null) + { + if (__context != null) + { + program = __context.__programs.get(id); + } + else if (Lib.current.stage != null) + { + __context = Lib.current.stage.context3D; + if (__context != null) + { + program = __context.__programs.get(id); + } + } + } - if (complexBlendsSupported) - { - extensions += "#extension GL_KHR_blend_equation_advanced : enable\n"; + if (program != null) + { + glProgram = program.__glProgram; + __glVertexSource = program.__glVertexSource; + __glFragmentSource = program.__glFragmentSource; + __glVersion = program.__glFragmentVersion != null ? program.__glFragmentVersion : program.__glVertexVersion; - #if lime - if (__context.__context.type == OPENGL) + __buildParamData(); + } + else { - // compiling without this gives the error - // 'gl_SampleID' : required extension not requested: GL_ARB_sample_shading - extensions += "#extension GL_ARB_sample_shading : enable\n"; + __refreshGLSource(); + + if (id == null) + { + id = (__cacheProgramId = __glVertexSource + __glFragmentSource) + (__precisionHint == FAST ? "FAST" : ""); + } + + if (__context != null) + { + program = __context.__programs.get(id); + if (program != null) glProgram = program.__glProgram; + else __initProgram(id); + + __buildParamData(); + } + else + { + processGLSLParameter(__glVertexSource, "attribute", __processGLSLParameterCallback); + processGLSLParameter(__glVertexSource, "in", __processGLSLParameterCallback); + processGLSLParameter(__glVertexSource, "uniform", __processGLSLParameterCallback); + processGLSLParameter(__glFragmentSource, "uniform", __processGLSLParameterCallback); + } } - #end - } - if (standardDerivativesSupported) - { - extensions += "#extension GL_OES_standard_derivatives : enable\n"; + __glSourceDirty = false; } - - // #version must be the first directive and cannot be repeated, - // while #extension directives must be before any non-preprocessor tokens. - - var prefix = "#version " - + __glVersion - + " - " - + extensions - + " - #ifdef GL_ES - " - + (precisionHint == FULL ? "#ifdef GL_FRAGMENT_PRECISION_HIGH - precision highp float; - #else - precision mediump float; - #endif" : "precision lowp float;") - + " - #endif - "; - - if (complexBlendsSupported) + else if (__context != null && program == null) { - prefix += "#ifdef GL_KHR_blend_equation_advanced\nlayout (blend_support_all_equations) out;\n#endif\n"; + if (id != null) + { + program = __context.__programs.get(id); + if (program != null) glProgram = program.__glProgram; + else __initProgram(id); + } + else + { + __initProgram(null); + } + __buildParamData(); } - - return prefix; } - @:noCompletion private function __initGL():Void + @:noCompletion private function __initProgram(id:String):Void { - if (__glSourceDirty || __paramBool == null) - { - __glSourceDirty = false; - program = null; - - __inputBitmapData = new Array(); - __paramBool = new Array(); - __paramFloat = new Array(); - __paramInt = new Array(); - - __processGLData(glVertexSource, "attribute"); - __processGLData(glVertexSource, "in"); - __processGLData(glVertexSource, "uniform"); - __processGLData(glFragmentSource, "uniform"); - } + program = __context.createProgram(GLSL); - if (__context != null && program == null) + if (openfl.Lib.current.stage.__uncaughtErrorEvents.__enabled) { - var gl = __context.gl; - - var vertex = __buildSourcePrefix(false) + glVertexSource; - var fragment = __buildSourcePrefix(true) + glFragmentSource; - - var id = vertex + fragment; - - if (__context.__programs.exists(id)) + try { - program = __context.__programs.get(id); + program.uploadSources(__glVertexSource, __glFragmentSource); + if (id != null) __context.__programs.set(id, program); } - else + catch (e:Dynamic) { - program = __context.createProgram(GLSL); + openfl.Lib.current.stage.__handleError(e); + } + } + else + { + program.uploadSources(__glVertexSource, __glFragmentSource); + if (id != null) __context.__programs.set(id, program); + } - // TODO - // program.uploadSources (vertex, fragment); + glProgram = program.__glProgram; + } - if (Lib.current.stage.__uncaughtErrorEvents.__enabled) - { - try - { - program.__glProgram = __createGLProgram(vertex, fragment); - } - catch (e:Dynamic) - { - Lib.current.stage.__handleError(e); + @:noCompletion private function __refreshGLSource():Void + { + __glVertexSource = __glSourceAssembler.assembleSource(__glVertexSourceRaw, __glVertexPragmas, + __glVertexExtensions, __glVersionRaw, true, true, __precisionHint); - program.__glProgram = null; - } - } - else - program.__glProgram = __createGLProgram(vertex, fragment); + __glFragmentSource = __glSourceAssembler.assembleSource(__glFragmentSourceRaw, __glFragmentPragmas, + __glFragmentExtensions, __glVersionRaw, false, true, __precisionHint); - __context.__programs.set(id, program); - } + __glVersion = GLSLSourceAssembler.getVersionFromSource(__glFragmentSource, + GLSLSourceAssembler.getVersionFromSource(__glVertexSource, GLSLSourceAssembler.getDefaultVersion())); + } - if (program != null) - { - glProgram = program.__glProgram; + @:noCompletion private function __processGLSLParameterCallback(isVertex:Bool, typeName:String, name:String, arrayLength:Int, + defaultAssign:Null):Void + { + if (StringTools.startsWith(name, "gl_")) + { + return; + } - for (input in __inputBitmapData) - { - if (input.__isUniform) - { - input.index = gl.getUniformLocation(glProgram, input.name); - } - else - { - input.index = gl.getAttribLocation(glProgram, input.name); - } - } + var type = getParameterTypeFromGLSL(typeName, arrayLength != 0), isSampler = StringTools.startsWith(typeName, "sampler"); + __registerParameter(name, type, isSampler, arrayLength == 0 ? 1 : arrayLength, null, !isVertex, + __getParameterDefault(defaultAssign, type, isSampler)); + } - for (parameter in __paramBool) - { - if (parameter.__isUniform) - { - parameter.index = gl.getUniformLocation(glProgram, parameter.name); - } - else - { - parameter.index = gl.getAttribLocation(glProgram, parameter.name); - } - } + @:noCompletion private function __getParameterDefault(assign:Null, type:ShaderParameterType, isSampler:Bool):Dynamic + { + // isSampler may not be logically possible. + if (assign == null || isSampler) return null; - for (parameter in __paramFloat) - { - if (parameter.__isUniform) - { - parameter.index = gl.getUniformLocation(glProgram, parameter.name); - } - else - { - parameter.index = gl.getAttribLocation(glProgram, parameter.name); - } - } + assign = StringTools.trim(assign); - for (parameter in __paramInt) - { - if (parameter.__isUniform) - { - parameter.index = gl.getUniformLocation(glProgram, parameter.name); - } - else - { - parameter.index = gl.getAttribLocation(glProgram, parameter.name); - } - } + if (assign.charCodeAt(0) == '['.code && assign.charCodeAt(assign.length - 1) == ']'.code) + { + final array = []; + + var index = 1, endIndex:Int, value; + while (index != 0) + { + value = __parseParameterValue(StringTools.trim(assign.substr(index, endIndex = assign.indexOf(',', index))), type); + if (value is Array) for (v in cast(value, Array)) array.push(v); + else array.push(value); + index = endIndex + 1; } + + return array; + } + else + { + var value = __parseParameterValue(assign, type); + if (value is Array) return value; + else return [value]; } } - @:noCompletion private function __processGLData(source:String, storageType:String):Void + @:noCompletion private function __parseParameterValue(assign:Null, type:ShaderParameterType):Dynamic { - var position, name, type, regex; - - if (storageType == "uniform") + // Poorly implemented but this is okay for now. + var typeMatch = ~/([A-Za-z0-9_]+)\s*\((\w+)\)/; + if (typeMatch.match(assign)) { - regex = ~/uniform ([A-Za-z0-9]+) ([A-Za-z0-9_]+)/; + var func = typeMatch.matched(1), value = typeMatch.matched(2); + switch (func) + { + case 'sin': return Math.sin(Std.parseFloat(value)); + case 'cos': return Math.cos(Std.parseFloat(value)); + case 'tan': return Math.tan(Std.parseFloat(value)); + case 'asin': return Math.asin(Std.parseFloat(value)); + case 'acos': return Math.acos(Std.parseFloat(value)); + default: + var matchedType = getParameterTypeFromGLSL(func, false); + if (matchedType == null/* || matchedType != type*/) return null; + else return [for (v in value.split(',')) __parseValue(StringTools.trim(v), type)]; + } } - else if (storageType == "in") + else { - regex = ~/in ([A-Za-z0-9]+) ([A-Za-z0-9_]+)/; + return __parseValue(assign, type); } - else + } + + @:noCompletion private function __parseValue(value:Null, type:ShaderParameterType):Dynamic + { + switch (type) { - regex = ~/attribute ([A-Za-z0-9]+) ([A-Za-z0-9_]+)/; + case BOOL, BOOL2, BOOL3, BOOL4, BOOLV, BOOL2V, BOOL3V, BOOL4V: return value == "true"; + case FLOAT, FLOAT2, FLOAT3, FLOAT4, FLOATV, FLOAT2V, FLOAT3V, FLOAT4V: return Std.parseFloat(value); + case INT, INT2, INT3, INT4, INTV, INT2V, INT3V, INT4V: return Std.parseInt(value); + default: return null; } + } - var lastMatch = 0; + @:noCompletion private function __buildParamData():Void + { + var name:String; + for (i in 0...program.__glslAttribNames.length) + { + name = program.__glslAttribNames[i]; + if (StringTools.startsWith(name, "gl_")) + { + continue; + } - while (regex.matchSub(source, lastMatch)) + __registerParameter(name, program.__glslAttribTypes[i], false, program.__glslAttribSizes[i], program.__glslAttribLocations[i], false, null); + } + + for (i in 0...program.__glslSamplerNames.length) { - type = regex.matched(1); - name = regex.matched(2); + __registerParameter(program.__glslSamplerNames[i], null, true, 1, program.__glslSamplerLocations[i], + true, __getParameterDefault(program.__glslUniformDefaults[i], null, true)); + } + for (i in 0...program.__glslUniformNames.length) + { + name = program.__glslUniformNames[i]; if (StringTools.startsWith(name, "gl_")) { continue; } - var isUniform = (storageType == "uniform"); + __registerParameter(name, program.__glslUniformTypes[i], false, program.__glslUniformSizes[i], program.__glslUniformLocations[i], + true, __getParameterDefault(program.__glslUniformDefaults[i], program.__glslUniformTypes[i], false)); + } + } - if (StringTools.startsWith(type, "sampler")) - { - var input = new ShaderInput(); - input.name = name; - input.__isUniform = isUniform; - __inputBitmapData.push(input); + @:noCompletion private function __registerParameter(name:String, type:ShaderParameterType, isSampler:Bool, + size:Int, location:Dynamic/*GLUniformLocation*/, isUniform:Bool, defaultValue:Dynamic) + { + var arrayLength = switch (type) + { + case MATRIX2X2, MATRIX2X3, MATRIX2X4: 2; + case MATRIX3X3, MATRIX3X2, MATRIX3X4: 3; + case MATRIX4X4, MATRIX4X2, MATRIX4X3: 4; + default: size; + } - switch (name) - { - case "openfl_Texture": - __texture = input; - case "bitmap": - __bitmap = input; - default: - } + var length = switch (type) + { + case BOOL2, BOOL2V, INT2, INT2V, FLOAT2, FLOAT2V, MATRIX2X2: 2; + case BOOL3, BOOL3V, INT3, INT3V, FLOAT3, FLOAT3V, MATRIX3X3: 3; + case BOOL4, BOOL4V, INT4, INT4V, FLOAT4, FLOAT4V, MATRIX4X4, MATRIX2X2V: 4; + + case MATRIX2X3, MATRIX4X3: 3; + case MATRIX2X4, MATRIX3X4: 4; + case MATRIX3X2, MATRIX4X2: 2; + + case MATRIX3X3V: 9; + case MATRIX4X4V: 16; + case MATRIX2X3V, MATRIX3X2V: 6; + case MATRIX2X4V, MATRIX4X2V: 8; + case MATRIX3X4V, MATRIX4X3V: 12; + default: 1; + } + length *= arrayLength; - Reflect.setField(__data, name, input); + if (location == null) location = -1; + inline function register(x:Any) + { + Reflect.setField(__data, name, x); + if (__isGenerated && __thisHasField(name)) + { try { - if (__isGenerated) Reflect.setField(this, name, input); - if (__isGenerated && thisHasField(name)) Reflect.setProperty(this, name, input); + Reflect.setField(this, name, x); + //Reflect.setProperty(this, name, x); } - catch (e:Dynamic) + catch (e) { Log.debug('Failed to set field $name: $e'); } } - else if (!Reflect.hasField(__data, name) || Reflect.field(__data, name) == null) - { - var parameterType:ShaderParameterType = switch (type) - { - case "bool": BOOL; - case "double", "float": FLOAT; - case "int", "uint": INT; - case "bvec2": BOOL2; - case "bvec3": BOOL3; - case "bvec4": BOOL4; - case "ivec2", "uvec2": INT2; - case "ivec3", "uvec3": INT3; - case "ivec4", "uvec4": INT4; - case "vec2", "dvec2": FLOAT2; - case "vec3", "dvec3": FLOAT3; - case "vec4", "dvec4": FLOAT4; - case "mat2", "mat2x2": MATRIX2X2; - case "mat2x3": MATRIX2X3; - case "mat2x4": MATRIX2X4; - case "mat3x2": MATRIX3X2; - case "mat3", "mat3x3": MATRIX3X3; - case "mat3x4": MATRIX3X4; - case "mat4x2": MATRIX4X2; - case "mat4x3": MATRIX4X3; - case "mat4", "mat4x4": MATRIX4X4; - default: null; - } - - var length = switch (parameterType) - { - case BOOL2, INT2, FLOAT2: 2; - case BOOL3, INT3, FLOAT3: 3; - case BOOL4, INT4, FLOAT4, MATRIX2X2: 4; - case MATRIX3X3: 9; - case MATRIX4X4: 16; - default: 1; - } + } - var arrayLength = switch (parameterType) + var dyn = Reflect.field(__data, name); + if (dyn != null) + { + if (isSampler) + { + var input:ShaderInput = cast dyn; + if (input != null) { - case MATRIX2X2: 2; - case MATRIX3X3: 3; - case MATRIX4X4: 4; - default: 1; + if (input.input == null) input.input = cast defaultValue; + if (__inputBitmapData != null) + { + if ((input.index = location) == -1) __inputBitmapData.remove(input); + else if (!__inputBitmapData.contains(input)) __inputBitmapData.push(input); + } + return;// register(input); } - - switch (parameterType) + } + else + { + switch (type) { - case BOOL, BOOL2, BOOL3, BOOL4: - var parameter = new ShaderParameter(); - parameter.name = name; - parameter.type = parameterType; - parameter.__arrayLength = arrayLength; - parameter.__isBool = true; - parameter.__isUniform = isUniform; - parameter.__length = length; - __paramBool.push(parameter); - - if (name == "openfl_HasColorTransform") + case BOOL, BOOL2, BOOL3, BOOL4, BOOLV, BOOL2V, BOOL3V, BOOL4V: + var parameter:ShaderParameter = cast dyn; + if (parameter != null) { - __hasColorTransform = parameter; - } - - Reflect.setField(__data, name, parameter); + if (parameter.value == null) parameter.value = cast defaultValue; + parameter.__arrayLength = arrayLength; + parameter.__isUniform = isUniform; + parameter.__length = length; - try - { - if (__isGenerated) Reflect.setField(this, name, parameter); - if (__isGenerated && thisHasField(name)) Reflect.setProperty(this, name, parameter); + if (__paramBool != null) + { + if ((parameter.index = location) == -1) __paramBool.remove(parameter); + else if (!__paramBool.contains(parameter)) __paramBool.push(parameter); + } + return;// register(parameter); } - catch (e:Dynamic) + case INT, INT2, INT3, INT4, INTV, INT2V, INT3V, INT4V: + var parameter:ShaderParameter = cast dyn; + if (parameter != null) { - Log.debug('Failed to set field $name: $e'); - } - - case INT, INT2, INT3, INT4: - var parameter = new ShaderParameter(); - parameter.name = name; - parameter.type = parameterType; - parameter.__arrayLength = arrayLength; - parameter.__isInt = true; - parameter.__isUniform = isUniform; - parameter.__length = length; - __paramInt.push(parameter); + if (parameter.value == null) parameter.value = cast defaultValue; + parameter.__arrayLength = arrayLength; + parameter.__isUniform = isUniform; + parameter.__length = length; - Reflect.setField(__data, name, parameter); - - try - { - if (__isGenerated) Reflect.setField(this, name, parameter); - if (__isGenerated && thisHasField(name)) Reflect.setProperty(this, name, parameter); - } - catch (e:Dynamic) - { - Log.debug('Failed to set field $name: $e'); + if (__paramInt != null) + { + if ((parameter.index = location) == -1) __paramInt.remove(parameter); + else if (!__paramInt.contains(parameter)) __paramInt.push(parameter); + } + return;// register(parameter); } default: - var parameter = new ShaderParameter(); - parameter.name = name; - parameter.type = parameterType; - parameter.__arrayLength = arrayLength; - #if lime - if (arrayLength > 0) parameter.__uniformMatrix = new Float32Array(arrayLength * arrayLength); - #end - parameter.__isFloat = true; - parameter.__isUniform = isUniform; - parameter.__length = length; - __paramFloat.push(parameter); - - if (StringTools.startsWith(name, "openfl_")) + var parameter:ShaderParameter = cast dyn; + if (parameter != null) { - switch (name) + if (parameter.value == null) parameter.value = cast defaultValue; + parameter.__arrayLength = arrayLength; + parameter.__isUniform = isUniform; + parameter.__length = length; + + if (__paramFloat != null) { - case "openfl_Alpha": __alpha = parameter; - case "openfl_ColorMultiplier": __colorMultiplier = parameter; - case "openfl_ColorOffset": __colorOffset = parameter; - case "openfl_Matrix": __matrix = parameter; - case "openfl_Position": __position = parameter; - case "openfl_TextureCoord": __textureCoord = parameter; - case "openfl_TextureSize": __textureSize = parameter; - default: + if ((parameter.index = location) == -1) __paramFloat.remove(parameter); + else if (!__paramFloat.contains(parameter)) __paramFloat.push(parameter); } + return;// register(parameter); } + } + } + } - Reflect.setField(__data, name, parameter); + if (isSampler) + { + var input = new ShaderInput(); + input.input = cast defaultValue; + input.name = name; + input.__isUniform = true; + + switch (name) { + case "openfl_Texture": __texture = input; + case "bitmap": __bitmap = input; + default: + } - try - { - if (__isGenerated) Reflect.setField(this, name, parameter); - if (__isGenerated && thisHasField(name)) Reflect.setProperty(this, name, parameter); - } - catch (e:Dynamic) - { - Log.debug('Failed to set field $name: $e'); - } - } + if (__inputBitmapData != null) + { + if ((input.index = location) == -1) __inputBitmapData.remove(input); + else if (!__inputBitmapData.contains(input)) __inputBitmapData.push(input); } + register(input); + } + else + { + switch (type) + { + case BOOL, BOOL2, BOOL3, BOOL4, BOOLV, BOOL2V, BOOL3V, BOOL4V: + var parameter = new ShaderParameter(); + parameter.name = name; + parameter.type = type; + parameter.value = cast defaultValue; + parameter.__arrayLength = arrayLength; + parameter.__isBool = true; + parameter.__isUniform = isUniform; + parameter.__length = length; + + if (name == "openfl_HasColorTransform") + { + __hasColorTransform = parameter; + } - position = regex.matchedPos(); - lastMatch = position.pos + position.len; + if (__paramBool != null) + { + if ((parameter.index = location) == -1) __paramBool.remove(parameter); + else if (!__paramBool.contains(parameter)) __paramBool.push(parameter); + } + register(parameter); + + case INT, INT2, INT3, INT4, INTV, INT2V, INT3V, INT4V: + var parameter = new ShaderParameter(); + parameter.name = name; + parameter.type = type; + parameter.value = cast defaultValue; + parameter.__arrayLength = arrayLength; + parameter.__isInt = true; + parameter.__isUniform = isUniform; + parameter.__length = length; + + if (__paramInt != null) + { + if ((parameter.index = location) == -1) __paramInt.remove(parameter); + else if (!__paramInt.contains(parameter)) __paramInt.push(parameter); + } + register(parameter); + + default: + var parameter = new ShaderParameter(); + parameter.name = name; + parameter.type = type; + parameter.value = cast defaultValue; + parameter.__arrayLength = arrayLength; + #if lime + if (arrayLength > 0) parameter.__uniformMatrix = new Float32Array(length); + #end + parameter.__isFloat = true; + parameter.__isUniform = isUniform; + parameter.__length = length; + + switch (name) + { + case "openfl_Alpha": __alpha = parameter; + case "openfl_ColorMultiplier": __colorMultiplier = parameter; + case "openfl_ColorOffset": __colorOffset = parameter; + case "openfl_Matrix": __matrix = parameter; + case "openfl_Position": __position = parameter; + case "openfl_TextureCoord": __textureCoord = parameter; + case "openfl_TextureSize": __textureSize = parameter; + default: + } + + if (__paramFloat != null) + { + if ((parameter.index = location) == -1) __paramFloat.remove(parameter); + else if (!__paramFloat.contains(parameter)) __paramFloat.push(parameter); + } + register(parameter); + } } } + @:noCompletion private function __thisHasField(name:String) + { + // Reflect.hasField(this, name) is REALLY expensive so we cache the result. + if (__fieldList == null) + { + __fieldList = Reflect.fields(this).concat(Type.getInstanceFields(Type.getClass(this))); + } + return __fieldList.indexOf(name) != -1; + } + @:noCompletion private function __update():Void { if (program != null) @@ -966,10 +959,14 @@ class Shader { var textureCount = 0; + var gl = __context.gl; + for (input in __inputBitmapData) { input.__updateGL(__context, textureCount); textureCount++; + + //if (textureCount == gl.MAX_TEXTURE_IMAGE_UNITS) break; } for (parameter in __paramBool) @@ -988,8 +985,7 @@ class Shader } } - @:noCompletion private function __updateGLFromBuffer(shaderBuffer:ShaderBuffer, bufferOffset:Int):Void - { + @:noCompletion private function __updateGLFromBuffer(shaderBuffer:ShaderBuffer, bufferOffset:Int):Void { var textureCount = 0; var input:ShaderInput; var inputData:BitmapData; @@ -997,16 +993,15 @@ class Shader var inputMipFilter:Context3DMipFilter; var inputWrap:Context3DWrapMode; - for (i in 0...shaderBuffer.inputCount) - { + // not this + for (i in 0...shaderBuffer.inputCount) { input = shaderBuffer.inputRefs[i]; inputData = shaderBuffer.inputs[i]; inputFilter = shaderBuffer.inputFilter[i]; inputMipFilter = shaderBuffer.inputMipFilter[i]; inputWrap = shaderBuffer.inputWrap[i]; - if (inputData != null) - { + if (inputData != null) { input.__updateGL(__context, textureCount, inputData, inputFilter, inputMipFilter, inputWrap); textureCount++; } @@ -1014,10 +1009,8 @@ class Shader var gl = __context.gl; - if (shaderBuffer.paramDataLength > 0) - { - if (shaderBuffer.paramDataBuffer == null) - { + if (shaderBuffer.paramDataLength > 0) { + if (shaderBuffer.paramDataBuffer == null) { shaderBuffer.paramDataBuffer = gl.createBuffer(); } @@ -1025,9 +1018,7 @@ class Shader __context.__bindGLArrayBuffer(shaderBuffer.paramDataBuffer); gl.bufferData(gl.ARRAY_BUFFER, shaderBuffer.paramData, gl.DYNAMIC_DRAW); - } - else - { + } else { // Log.verbose ("bind buffer null"); __context.__bindGLArrayBuffer(null); @@ -1049,18 +1040,14 @@ class Shader var overrideFloatValue:Array = null; var overrideIntValue:Array = null; - for (i in 0...shaderBuffer.paramCount) - { + for (i in 0...shaderBuffer.paramCount) { hasOverride = false; - if (i < boolCount) - { + if (i < boolCount) { boolRef = shaderBuffer.paramRefs_Bool[boolIndex]; - for (j in 0...shaderBuffer.overrideBoolCount) - { - if (boolRef.name == shaderBuffer.overrideBoolNames[j]) - { + for (j in 0...shaderBuffer.overrideBoolCount) { + if (boolRef.name == shaderBuffer.overrideBoolNames[j]) { overrideBoolValue = shaderBuffer.overrideBoolValues[j]; hasOverride = true; break; @@ -1077,15 +1064,11 @@ class Shader } boolIndex++; - } - else if (i < boolCount + floatCount) - { + } else if (i < boolCount + floatCount) { floatRef = shaderBuffer.paramRefs_Float[floatIndex]; - for (j in 0...shaderBuffer.overrideFloatCount) - { - if (floatRef.name == shaderBuffer.overrideFloatNames[j]) - { + for (j in 0...shaderBuffer.overrideFloatCount) { + if (floatRef.name == shaderBuffer.overrideFloatNames[j]) { overrideFloatValue = shaderBuffer.overrideFloatValues[j]; hasOverride = true; break; @@ -1102,15 +1085,11 @@ class Shader } floatIndex++; - } - else - { + } else { intRef = shaderBuffer.paramRefs_Int[intIndex]; - for (j in 0...shaderBuffer.overrideIntCount) - { - if (intRef.name == shaderBuffer.overrideIntNames[j]) - { + for (j in 0...shaderBuffer.overrideIntCount) { + if (intRef.name == shaderBuffer.overrideIntNames[j]) { overrideIntValue = cast shaderBuffer.overrideIntValues[j]; hasOverride = true; break; @@ -1131,6 +1110,15 @@ class Shader } } + @:noCompletion private function __setDirty():Void + { + //if (!__glSourceDirty) + //{ + __cacheProgramId = null; + __glSourceDirty = true; + //} + } + // Get & Set Methods @:noCompletion private function get_data():ShaderData { @@ -1144,92 +1132,117 @@ class Shader @:noCompletion private function set_data(value:ShaderData):ShaderData { - return __data = cast value; + return __data = value; } - @:noCompletion private function get_glFragmentHeaderRaw():String + @:noCompletion private function get_glVersionRaw():Null { - return __glFragmentHeaderRaw; + return __glVersionRaw; } - @:noCompletion private function get_glFragmentBodyRaw():String + @:noCompletion private function get_glVersion():Null { - return __glFragmentBodyRaw; + if (__glSourceDirty) + { + __init(); + } + + return __glVersion; } - @:noCompletion private function get_glFragmentSourceRaw():String + @:noCompletion private function set_glVersion(value:Null):Null { - return __glFragmentSourceRaw; + if (__glSourceDirty ? value != __glVersionRaw : value != __glVersion) + { + __setDirty(); + } + + return __glVersionRaw = value; } - @:noCompletion private function get_glFragmentSource():String + @:noCompletion private function get_glVertexExtensions():Map { - return __glFragmentSource; + return __glVertexExtensions; } - @:noCompletion private function get_glVersion():String + @:noCompletion private function get_glFragmentExtensions():Map { - return __glVersion; + return __glFragmentExtensions; } - @:noCompletion private function get_glVertexExtensions():Array<{name:String, behavior:String}> + @:noCompletion private function set_glVertexExtensions(value:Map):Map { - return __glVertexExtensions; + __setDirty(); + return __glVertexExtensions = value; } - @:noCompletion private function get_glFragmentExtensions():Array<{name:String, behavior:String}> + @:noCompletion private function set_glFragmentExtensions(value:Map):Map { - return __glFragmentExtensions; + __setDirty(); + return __glFragmentExtensions = value; } - @:noCompletion private function set_glFragmentSource(value:String):String + @:noCompletion private function get_glVertexPragmas():Map { - if (value != __glFragmentSource) - { - __glSourceDirty = true; - } + return __glVertexPragmas; + } - return __glFragmentSource = value; + @:noCompletion private function get_glFragmentPragmas():Map + { + return __glFragmentPragmas; } - @:noCompletion private function set_glVersion(value:String):String + @:noCompletion private function set_glVertexPragmas(value:Map):Map { - if (value != __glVersion) - { - __glSourceDirty = true; - } + __setDirty(); + return __glVertexPragmas = value; + } - return __glVersion = value; + @:noCompletion private function set_glFragmentPragmas(value:Map):Map + { + __setDirty(); + return __glFragmentPragmas = value; } - @:noCompletion private function set_glVertexExtensions(value:Array<{name:String, behavior:String}>):Array<{name:String, behavior:String}> + @:noCompletion private function get_glFragmentHeaderRaw():String { - if (value != __glVertexExtensions) - { - __glSourceDirty = true; - } + return __glFragmentPragmas.get("header"); + } - return __glVertexExtensions = value; + @:noCompletion private function get_glFragmentBodyRaw():String + { + return __glFragmentPragmas.get("body"); } - @:noCompletion private function set_glFragmentExtensions(value:Array<{name:String, behavior:String}>):Array<{name:String, behavior:String}> + @:noCompletion private function get_glFragmentSourceRaw():String { - if (value != __glFragmentExtensions) + return __glFragmentSourceRaw; + } + + @:noCompletion private function get_glFragmentSource():String + { + if (__glSourceDirty) { - __glSourceDirty = true; + __init(); } - return __glFragmentExtensions = value; + return __glFragmentSource; + } + + @:noCompletion private function set_glFragmentSource(value:String):String + { + __setDirty(); + return __glFragmentSourceRaw = value; } @:noCompletion private function get_glVertexHeaderRaw():String { - return __glVertexHeaderRaw; + return __glVertexPragmas.get("header"); } @:noCompletion private function get_glVertexBodyRaw():String { - return __glVertexBodyRaw; + return __glVertexPragmas.get("body"); } @:noCompletion private function get_glVertexSourceRaw():String @@ -1239,28 +1252,46 @@ class Shader @:noCompletion private function get_glVertexSource():String { + if (__glSourceDirty) + { + __init(); + } + return __glVertexSource; } @:noCompletion private function set_glVertexSource(value:String):String { - if (value != __glVertexSource) - { - __glSourceDirty = true; - } - - return __glVertexSource = value; + __setDirty(); + return __glVertexSourceRaw = value; } - private var __fieldList:Array = null; + @:noCompletion private function get_precisionHint():ShaderPrecision + { + return __precisionHint; + } - private function thisHasField(name:String) + @:noCompletion private function set_precisionHint(value:ShaderPrecision):ShaderPrecision { - // Reflect.hasField(this, name) is REALLY expensive so we cache the result. - if (__fieldList == null) + if (__precisionHint != value && program != null && !__glSourceDirty) { - __fieldList = Reflect.fields(this).concat(Type.getInstanceFields(Type.getClass(this))); + var id = __cacheProgramId != null ? __cacheProgramId + (value == FAST ? "FAST" : "") : null; + + if (id != null && __context != null && __context.__programs.exists(id)) + { + program = __context.__programs.get(id); + __glVertexSource = program.__glVertexSource; + __glFragmentSource = program.__glFragmentSource; + } + else + { + program = null; + __refreshGLSource(); + } } - return __fieldList.indexOf(name) != -1; + return __precisionHint = value; } } + +//typedef ShaderProcessParameterCallback = (isVertex:Bool, typeName:String, name:String, arrayLength:Int, defaultAssign:Null) -> Void; +typedef ShaderProcessParameterCallback = Bool->String->String->Int->Null->Void; diff --git a/src/openfl/display/ShaderData.hx b/src/openfl/display/ShaderData.hx index 0ea9c5db71..4619cf6578 100644 --- a/src/openfl/display/ShaderData.hx +++ b/src/openfl/display/ShaderData.hx @@ -95,7 +95,7 @@ abstract ShaderData(Dynamic) from Dynamic to Dynamic @param byteCode The shader's byte code. **/ - public function new(byteArray:ByteArray) + public function new(byteArray:Null) { this = {}; } diff --git a/src/openfl/display/ShaderInput.hx b/src/openfl/display/ShaderInput.hx index 39729efee4..7c71e27c85 100644 --- a/src/openfl/display/ShaderInput.hx +++ b/src/openfl/display/ShaderInput.hx @@ -137,7 +137,7 @@ import openfl.display3D.Context3D; channels = 0; filter = NEAREST; height = 0; - index = 0; + index = -1; mipFilter = MIPNONE; width = 0; wrap = CLAMP; diff --git a/src/openfl/display/ShaderParameter.hx b/src/openfl/display/ShaderParameter.hx index d52d239896..9f828fa5c3 100644 --- a/src/openfl/display/ShaderParameter.hx +++ b/src/openfl/display/ShaderParameter.hx @@ -1,5 +1,6 @@ package openfl.display; +import lime.utils.Int32Array; import openfl.utils._internal.Float32Array; import openfl.display3D.Context3D; @@ -160,7 +161,7 @@ import openfl.display3D.Context3D; public function new() { - index = 0; + index = -1; } @:noCompletion private function __disableGL(context:Context3D):Void @@ -205,6 +206,14 @@ import openfl.display3D.Context3D; gl.uniform3i(index, boolValue[0] ? 1 : 0, boolValue[1] ? 1 : 0, boolValue[2] ? 1 : 0); case BOOL4: gl.uniform4i(index, boolValue[0] ? 1 : 0, boolValue[1] ? 1 : 0, boolValue[2] ? 1 : 0, boolValue[3] ? 1 : 0); + case BOOLV: + gl.uniform1iv(index, new Int32Array([for (v in boolValue) v ? 1 : 0])); + case BOOL2V: + gl.uniform2iv(index, new Int32Array([for (v in boolValue) v ? 1 : 0])); + case BOOL3V: + gl.uniform3iv(index, new Int32Array([for (v in boolValue) v ? 1 : 0])); + case BOOL4V: + gl.uniform4iv(index, new Int32Array([for (v in boolValue) v ? 1 : 0])); case FLOAT: gl.uniform1f(index, floatValue[0]); case FLOAT2: @@ -213,6 +222,14 @@ import openfl.display3D.Context3D; gl.uniform3f(index, floatValue[0], floatValue[1], floatValue[2]); case FLOAT4: gl.uniform4f(index, floatValue[0], floatValue[1], floatValue[2], floatValue[3]); + case FLOATV: + gl.uniform1fv(index, new Float32Array(floatValue)); + case FLOAT2V: + gl.uniform2fv(index, new Float32Array(floatValue)); + case FLOAT3V: + gl.uniform3fv(index, new Float32Array(floatValue)); + case FLOAT4V: + gl.uniform4fv(index, new Float32Array(floatValue)); case MATRIX2X2: for (i in 0...4) @@ -221,6 +238,9 @@ import openfl.display3D.Context3D; } gl.uniformMatrix2fv(index, false, __uniformMatrix); + case MATRIX2X2V: + gl.uniformMatrix2fv(index, false, new Float32Array(floatValue)); + // case MATRIX2X3: // case MATRIX2X4: // case MATRIX3X2: @@ -232,6 +252,9 @@ import openfl.display3D.Context3D; } gl.uniformMatrix3fv(index, false, __uniformMatrix); + case MATRIX3X3V: + gl.uniformMatrix3fv(index, false, new Float32Array(floatValue)); + // case MATRIX3X4: // case MATRIX4X2: // case MATRIX4X3: @@ -243,6 +266,9 @@ import openfl.display3D.Context3D; } gl.uniformMatrix4fv(index, false, __uniformMatrix); + case MATRIX4X4V: + gl.uniformMatrix4fv(index, false, new Float32Array(floatValue)); + case INT: gl.uniform1i(index, intValue[0]); case INT2: @@ -251,6 +277,14 @@ import openfl.display3D.Context3D; gl.uniform3i(index, intValue[0], intValue[1], intValue[2]); case INT4: gl.uniform4i(index, intValue[0], intValue[1], intValue[2], intValue[3]); + case INTV: + gl.uniform1iv(index, new Int32Array(intValue)); + case INT2V: + gl.uniform2iv(index, new Int32Array(intValue)); + case INT3V: + gl.uniform3iv(index, new Int32Array(intValue)); + case INT4V: + gl.uniform4iv(index, new Int32Array(intValue)); default: } @@ -276,6 +310,23 @@ import openfl.display3D.Context3D; case FLOAT4: gl.uniform4f(index, 0, 0, 0, 0); + case INTV, BOOLV: + gl.uniform1iv(index, new Int32Array([for (i in 0...__length) 0])); + case INT2V, BOOL2V: + gl.uniform2iv(index, new Int32Array([for (i in 0...__length) 0])); + case INT3V, BOOL3V: + gl.uniform3iv(index, new Int32Array([for (i in 0...__length) 0])); + case INT4V, BOOL4V: + gl.uniform4iv(index, new Int32Array([for (i in 0...__length) 0])); + case FLOATV: + gl.uniform1fv(index, new Float32Array([for (i in 0...__length) 0])); + case FLOAT2V: + gl.uniform2fv(index, new Float32Array([for (i in 0...__length) 0])); + case FLOAT3V: + gl.uniform3fv(index, new Float32Array([for (i in 0...__length) 0])); + case FLOAT4V: + gl.uniform4fv(index, new Float32Array([for (i in 0...__length) 0])); + case MATRIX2X2: for (i in 0...4) { @@ -283,6 +334,9 @@ import openfl.display3D.Context3D; } gl.uniformMatrix2fv(index, false, __uniformMatrix); + case MATRIX2X2V: + gl.uniformMatrix2fv(index, false, new Float32Array([for (i in 0...__length) 0])); + // case MATRIX2X3: // case MATRIX2X4: // case MATRIX3X2: @@ -294,6 +348,9 @@ import openfl.display3D.Context3D; } gl.uniformMatrix3fv(index, false, __uniformMatrix); + case MATRIX3X3V: + gl.uniformMatrix3fv(index, false, new Float32Array([for (i in 0...__length) 0])); + // case MATRIX3X4: // case MATRIX4X2: // case MATRIX4X3: @@ -305,6 +362,9 @@ import openfl.display3D.Context3D; } gl.uniformMatrix4fv(index, false, __uniformMatrix); + case MATRIX4X4V: + gl.uniformMatrix4fv(index, false, new Float32Array([for (i in 0...__length) 0])); + default: } } @@ -330,6 +390,15 @@ import openfl.display3D.Context3D; gl.vertexAttrib3f(index, boolValue[0] ? 1 : 0, boolValue[1] ? 1 : 0, boolValue[2] ? 1 : 0); case BOOL4: gl.vertexAttrib4f(index, boolValue[0] ? 1 : 0, boolValue[1] ? 1 : 0, boolValue[2] ? 1 : 0, boolValue[3] ? 1 : 0); + // vertexAttrib1iv doesnt seem to exists, it only seems like pragma only + case BOOLV: + gl.vertexAttrib1fv(index, new Float32Array([for (v in boolValue) v ? 1 : 0])); + case BOOL2V: + gl.vertexAttrib2fv(index, new Float32Array([for (v in boolValue) v ? 1 : 0])); + case BOOL3V: + gl.vertexAttrib3fv(index, new Float32Array([for (v in boolValue) v ? 1 : 0])); + case BOOL4V: + gl.vertexAttrib4fv(index, new Float32Array([for (v in boolValue) v ? 1 : 0])); case FLOAT: gl.vertexAttrib1f(index, floatValue[0]); case FLOAT2: @@ -338,6 +407,14 @@ import openfl.display3D.Context3D; gl.vertexAttrib3f(index, floatValue[0], floatValue[1], floatValue[2]); case FLOAT4: gl.vertexAttrib4f(index, floatValue[0], floatValue[1], floatValue[2], floatValue[3]); + case FLOATV: + gl.vertexAttrib1fv(index, floatValue); + case FLOAT2V, MATRIX2X2V: + gl.vertexAttrib2fv(index, floatValue); + case FLOAT3V, MATRIX3X3V: + gl.vertexAttrib3fv(index, floatValue); + case FLOAT4V, MATRIX4X4V: + gl.vertexAttrib4fv(index, floatValue); case MATRIX2X2: for (i in 0...2) @@ -365,6 +442,14 @@ import openfl.display3D.Context3D; gl.vertexAttrib3f(index, intValue[0], intValue[1], intValue[2]); case INT4: gl.vertexAttrib4f(index, intValue[0], intValue[1], intValue[2], intValue[3]); + case INTV: + gl.vertexAttrib1fv(index, cast (intValue, Float32Array)); + case INT2V: + gl.vertexAttrib2fv(index, cast (intValue, Float32Array)); + case INT3V: + gl.vertexAttrib3fv(index, cast (intValue, Float32Array)); + case INT4V: + gl.vertexAttrib4fv(index, cast (intValue, Float32Array)); default: } } @@ -381,6 +466,34 @@ import openfl.display3D.Context3D; case BOOL4, FLOAT4, INT4: gl.vertexAttrib4f(index, 0, 0, 0, 0); + // vertexAttrib1iv doesnt seem to exists, it only seems like pragma only + case BOOLV: + gl.vertexAttrib1fv(index, new Float32Array([for (i in 0...__length) 0])); + case BOOL2V: + gl.vertexAttrib2fv(index, new Float32Array([for (i in 0...__length) 0])); + case BOOL3V: + gl.vertexAttrib3fv(index, new Float32Array([for (i in 0...__length) 0])); + case BOOL4V: + gl.vertexAttrib4fv(index, new Float32Array([for (i in 0...__length) 0])); + + case INTV: + gl.vertexAttrib1fv(index, new Float32Array([for (i in 0...__length) 0])); + case INT2V: + gl.vertexAttrib2fv(index, new Float32Array([for (i in 0...__length) 0])); + case INT3V: + gl.vertexAttrib3fv(index, new Float32Array([for (i in 0...__length) 0])); + case INT4V: + gl.vertexAttrib4fv(index, new Float32Array([for (i in 0...__length) 0])); + + case FLOATV: + gl.vertexAttrib1fv(index, new Float32Array([for (i in 0...__length) 0])); + case FLOAT2V, MATRIX2X2V: + gl.vertexAttrib2fv(index, new Float32Array([for (i in 0...__length) 0])); + case FLOAT3V, MATRIX3X3V: + gl.vertexAttrib3fv(index, new Float32Array([for (i in 0...__length) 0])); + case FLOAT4V, MATRIX4X4V: + gl.vertexAttrib4fv(index, new Float32Array([for (i in 0...__length) 0])); + case MATRIX2X2: for (i in 0...2) { @@ -445,6 +558,24 @@ import openfl.display3D.Context3D; case FLOAT4: gl.uniform4f(index, buffer[position], buffer[position + 1], buffer[position + 2], buffer[position + 3]); + case INTV, BOOLV: + gl.uniform1iv(index, buffer.subarray(position, position + __length)); + case INT2V, BOOL2V: + gl.uniform2iv(index, buffer.subarray(position, position + __length)); + case INT3V, BOOL3V: + gl.uniform3iv(index, buffer.subarray(position, position + __length)); + case INT4V, BOOL4V: + gl.uniform4iv(index, buffer.subarray(position, position + __length)); + + case FLOATV: + gl.uniform1fv(index, buffer.subarray(position, position + __length)); + case FLOAT2V: + gl.uniform2fv(index, buffer.subarray(position, position + __length)); + case FLOAT3V: + gl.uniform3fv(index, buffer.subarray(position, position + __length)); + case FLOAT4V: + gl.uniform4fv(index, buffer.subarray(position, position + __length)); + case MATRIX2X2: for (i in 0...4) { @@ -452,7 +583,16 @@ import openfl.display3D.Context3D; } gl.uniformMatrix2fv(index, false, __uniformMatrix); + case MATRIX2X2V: + gl.uniformMatrix2fv(index, false, buffer.subarray(position, position + __length)); + // matrix AxB is not supported by lime // case MATRIX2X3: + // for (i in 0...6) + // { + // __uniformMatrix[i] = buffer[position + i]; + // } + // var _gl:WebGL2RenderContext = cast gl; + // _gl.uniformMatrix2x3fv(index, false, __uniformMatrix); // case MATRIX2X4: // case MATRIX3X2: @@ -463,6 +603,9 @@ import openfl.display3D.Context3D; } gl.uniformMatrix3fv(index, false, __uniformMatrix); + case MATRIX3X3V: + gl.uniformMatrix3fv(index, false, buffer.subarray(position, position + __length)); + // case MATRIX3X4: // case MATRIX4X2: // case MATRIX4X3: @@ -474,6 +617,9 @@ import openfl.display3D.Context3D; } gl.uniformMatrix4fv(index, false, __uniformMatrix); + case MATRIX4X4V: + gl.uniformMatrix4fv(index, false, buffer.subarray(position, position + __length)); + default: } } @@ -500,18 +646,33 @@ import openfl.display3D.Context3D; case BOOL4, FLOAT4, INT4: gl.vertexAttrib4f(index, buffer[position], buffer[position + 1], buffer[position + 2], buffer[position + 3]); + case FLOATV, INTV, BOOLV: + gl.vertexAttrib1fv(index, buffer.subarray(position, position + __length)); + case FLOAT2V, INT2V, BOOL2V: + gl.vertexAttrib2fv(index, buffer.subarray(position, position + __length)); + case FLOAT3V, INT3V, BOOL3V: + gl.vertexAttrib3fv(index, buffer.subarray(position, position + __length)); + case FLOAT4V, INT4V, BOOL4V: + gl.vertexAttrib4fv(index, buffer.subarray(position, position + __length)); + case MATRIX2X2: for (i in 0...2) { gl.vertexAttrib2f(index + i, buffer[position + i * 2], buffer[position + i * 2 + 1]); } + case MATRIX2X2V: + gl.vertexAttrib2fv(index, buffer.subarray(position, position + __length)); + case MATRIX3X3: for (i in 0...3) { gl.vertexAttrib3f(index + i, buffer[position + i * 3], buffer[position + i * 3 + 1], buffer[position + i * 3 + 2]); } + case MATRIX3X3V: + gl.vertexAttrib3fv(index, buffer.subarray(position, position + __length)); + case MATRIX4X4: for (i in 0...4) { @@ -519,6 +680,9 @@ import openfl.display3D.Context3D; buffer[position + i * 4 + 3]); } + case MATRIX4X4V: + gl.vertexAttrib4fv(index, buffer.subarray(position, position + __length)); + default: } } @@ -535,24 +699,42 @@ import openfl.display3D.Context3D; case BOOL4, FLOAT4, INT4: gl.vertexAttrib4f(index, 0, 0, 0, 0); + case FLOATV, INTV, BOOLV: + gl.vertexAttrib1fv(index, new Float32Array([for (i in 0...__length) 0])); + case FLOAT2V, INT2V, BOOL2V: + gl.vertexAttrib2fv(index, new Float32Array([for (i in 0...__length) 0])); + case FLOAT3V, INT3V, BOOL3V: + gl.vertexAttrib3fv(index, new Float32Array([for (i in 0...__length) 0])); + case FLOAT4V, INT4V, BOOL4V: + gl.vertexAttrib4fv(index, new Float32Array([for (i in 0...__length) 0])); + case MATRIX2X2: for (i in 0...2) { gl.vertexAttrib2f(index + i, 0, 0); } + case MATRIX2X2V: + gl.vertexAttrib2fv(index, new Float32Array([for (i in 0...__length) 0])); + case MATRIX3X3: for (i in 0...3) { gl.vertexAttrib3f(index + i, 0, 0, 0); } + case MATRIX3X3V: + gl.vertexAttrib3fv(index, new Float32Array([for (i in 0...__length) 0])); + case MATRIX4X4: for (i in 0...4) { gl.vertexAttrib4f(index + i, 0, 0, 0, 0); } + case MATRIX4X4V: + gl.vertexAttrib4fv(index, new Float32Array([for (i in 0...__length) 0])); + default: } } diff --git a/src/openfl/display/ShaderParameterType.hx b/src/openfl/display/ShaderParameterType.hx index 4e5333adbf..90ccdb00af 100644 --- a/src/openfl/display/ShaderParameterType.hx +++ b/src/openfl/display/ShaderParameterType.hx @@ -24,24 +24,48 @@ enum abstract ShaderParameterType(Null) **/ public var BOOL = 0; + /** + Indicates that the shader parameter is defined as a `bool[...]` value, + equivalent to an Array of Boolean instances in ActionScript. + **/ + public var BOOLV = 21; + /** Indicates that the shader parameter is defined as a `bool2` value, equivalent to an Array of two Boolean instances in ActionScript. **/ public var BOOL2 = 1; + /** + Indicates that the shader parameter is defined as a `bool2[...]` value, + equivalent to an Array of 2 pairs of Boolean instances in ActionScript. + **/ + public var BOOL2V = 22; + /** Indicates that the shader parameter is defined as a `bool3` value, equivalent to an Array of three Boolean instances in ActionScript. **/ public var BOOL3 = 2; + /** + Indicates that the shader parameter is defined as a `bool3[...]` value, + equivalent to an Array of 3 triples of Boolean instances in ActionScript. + **/ + public var BOOL3V = 23; + /** Indicates that the shader parameter is defined as a `bool4` value, equivalent to an Array of four Boolean instances in ActionScript. **/ public var BOOL4 = 3; + /** + Indicates that the shader parameter is defined as a `bool4[...]` value, + equivalent to an Array of 4 quadruplets of Boolean instances in ActionScript. + **/ + public var BOOL4V = 24; + /** Indicates that the shader parameter is defined as a `float` value, equivalent to a single Number instance in ActionScript. @@ -58,24 +82,48 @@ enum abstract ShaderParameterType(Null) **/ public var FLOAT = 4; + /** + Indicates that the shader parameter is defined as a `float[...]` value, + equivalent to an Array of Number instances in ActionScript. + **/ + public var FLOATV = 25; + /** Indicates that the shader parameter is defined as a `float2` value, equivalent to an Array of two Number instances in ActionScript. **/ public var FLOAT2 = 5; + /** + Indicates that the shader parameter is defined as a `float2[...]` value, + equivalent to an Array of 2 pairs of Number instances in ActionScript. + **/ + public var FLOAT2V = 26; + /** Indicates that the shader parameter is defined as a `float3` value, equivalent to an Array of three Number instances in ActionScript. **/ public var FLOAT3 = 6; + /** + Indicates that the shader parameter is defined as a `float3[...]` value, + equivalent to an Array of 3 triplets of Number instances in ActionScript. + **/ + public var FLOAT3V = 27; + /** Indicates that the shader parameter is defined as a `float4` value, equivalent to an Array of four Number instances in ActionScript. **/ public var FLOAT4 = 7; + /** + Indicates that the shader parameter is defined as a `float4[...]` value, + equivalent to an Array of 4 quadruplets of Number instances in ActionScript. + **/ + public var FLOAT4V = 28; + /** Indicates that the shader parameter is defined as an `int` value, equivalent to a single int or uint instance in ActionScript. @@ -92,24 +140,48 @@ enum abstract ShaderParameterType(Null) **/ public var INT = 8; + /** + Indicates that the shader parameter is defined as an `int[...]` value, + equivalent to an Array of int or uint instances in ActionScript. + **/ + public var INTV = 29; + /** Indicates that the shader parameter is defined as an `int2` value, equivalent to an Array of two int or uint instances in ActionScript. **/ public var INT2 = 9; + /** + Indicates that the shader parameter is defined as an `int2[...]` value, + equivalent to an Array of 2 pairs of int or uint instances in ActionScript. + **/ + public var INT2V = 30; + /** Indicates that the shader parameter is defined as an `int3` value, equivalent to an Array of three int or uint instances in ActionScript. **/ public var INT3 = 10; + /** + Indicates that the shader parameter is defined as an `int3[...]` value, + equivalent to an Array of 3 triplets of int or uint instances in ActionScript. + **/ + public var INT3V = 31; + /** Indicates that the shader parameter is defined as an `int4` value, equivalent to an Array of four int or uint instances in ActionScript. **/ public var INT4 = 11; + /** + Indicates that the shader parameter is defined as an `int4[...]` value, + equivalent to an Array of 4 quadruplets of int or uint instances in ActionScript. + **/ + public var INT4V = 32; + /** Indicates that the shader parameter is defined as a `float2x2` value, equivalent to a 2-by-2 matrix. This matrix is represented as an Array @@ -117,6 +189,12 @@ enum abstract ShaderParameterType(Null) **/ public var MATRIX2X2 = 12; + /** + Indicates that the shader parameter is defined as a `float2x2[...]` value, + equivalent to an Array of 2 2x2 matrices of Number instances in ActionScript. + **/ + public var MATRIX2X2V = 33; + /** Indicates that the shader parameter is defined as a `float2x3` value, equivalent to a 2-by-3 matrix. This matrix is represented as an Array @@ -124,6 +202,12 @@ enum abstract ShaderParameterType(Null) **/ public var MATRIX2X3 = 13; + /** + Indicates that the shader parameter is defined as a `float2x3[...]` value, + equivalent to an Array of 2 2x3 matrices of Float instances in Haxe. + **/ + public var MATRIX2X3V = 34; + /** Indicates that the shader parameter is defined as a `float2x4` value, equivalent to a 2-by-4 matrix. This matrix is represented as an Array @@ -131,6 +215,12 @@ enum abstract ShaderParameterType(Null) **/ public var MATRIX2X4 = 14; + /** + Indicates that the shader parameter is defined as a `float2x4[...]` value, + equivalent to an Array of 2 2x4 matrices of Float instances in Haxe. + **/ + public var MATRIX2X4V = 35; + /** Indicates that the shader parameter is defined as a `float3x2` value, equivalent to a 3-by-2 matrix. This matrix is represented as an Array @@ -138,6 +228,12 @@ enum abstract ShaderParameterType(Null) **/ public var MATRIX3X2 = 15; + /** + Indicates that the shader parameter is defined as a `float3x2[...]` value, + equivalent to an Array of 3 3x2 matrices of Float instances in Haxe. + **/ + public var MATRIX3X2V = 36; + /** Indicates that the shader parameter is defined as a `float3x3` value, equivalent to a 3-by-3 matrix. This matrix is represented as an Array @@ -145,6 +241,12 @@ enum abstract ShaderParameterType(Null) **/ public var MATRIX3X3 = 16; + /** + Indicates that the shader parameter is defined as a `float3x3[...]` value, + equivalent to an Array of 3 3x3 matrices of Number instances in ActionScript. + **/ + public var MATRIX3X3V = 37; + /** Indicates that the shader parameter is defined as a `float3x4` value, equivalent to a 3-by-4 matrix. This matrix is represented as an Array @@ -152,6 +254,12 @@ enum abstract ShaderParameterType(Null) **/ public var MATRIX3X4 = 17; + /** + Indicates that the shader parameter is defined as a `float3x4[...]` value, + equivalent to an Array of 3 3x4 matrices of Float instances in Haxe. + **/ + public var MATRIX3X4V = 38; + /** Indicates that the shader parameter is defined as a `float4x2` value, equivalent to a 4-by-2 matrix. This matrix is represented as an Array @@ -159,6 +267,12 @@ enum abstract ShaderParameterType(Null) **/ public var MATRIX4X2 = 18; + /** + Indicates that the shader parameter is defined as a `float4x2[...]` value, + equivalent to an Array of 4 4x2 matrices of Float instances in Haxe. + **/ + public var MATRIX4X2V = 39; + /** Indicates that the shader parameter is defined as a `float4x3` value, equivalent to a 4-by-3 matrix. This matrix is represented as an Array @@ -166,6 +280,12 @@ enum abstract ShaderParameterType(Null) **/ public var MATRIX4X3 = 19; + /** + Indicates that the shader parameter is defined as a `float4x3[...]` value, + equivalent to an Array of 4 4x3 matrices of Float instances in Haxe. + **/ + public var MATRIX4X3V = 40; + /** Indicates that the shader parameter is defined as a `float4x4` value, equivalent to a 4-by-4 matrix. This matrix is represented as an Array @@ -173,22 +293,40 @@ enum abstract ShaderParameterType(Null) **/ public var MATRIX4X4 = 20; + /** + Indicates that the shader parameter is defined as a `float4x4[...]` value, + equivalent to an Array of 4 4x4 matrices of Number instances in ActionScript. + **/ + public var MATRIX4X4V = 41; + @:from private static function fromString(value:String):ShaderParameterType { return switch (value) { case "bool": BOOL; case "bool2": BOOL2; - case "bool3": BOOL2; - case "bool4": BOOL2; + case "bool3": BOOL3; + case "bool4": BOOL4; + case "bool[]": BOOLV; + case "bool2[]": BOOL2V; + case "bool3[]": BOOL3V; + case "bool4[]": BOOL4V; case "float": FLOAT; case "float2": FLOAT2; case "float3": FLOAT3; case "float4": FLOAT4; + case "float[]": FLOATV; + case "float2[]": FLOAT2V; + case "float3[]": FLOAT3V; + case "float4[]": FLOAT4V; case "int": INT; case "int2": INT2; case "int3": INT3; case "int4": INT4; + case "int[]": INTV; + case "int2[]": INT2V; + case "int3[]": INT3V; + case "int4[]": INT4V; case "matrix2x2": MATRIX2X2; case "matrix2x3": MATRIX2X3; case "matrix2x4": MATRIX2X4; @@ -198,6 +336,15 @@ enum abstract ShaderParameterType(Null) case "matrix4x2": MATRIX4X2; case "matrix4x3": MATRIX4X3; case "matrix4x4": MATRIX4X4; + case "matrix2x2[]": MATRIX2X2V; + case "matrix2x3[]": MATRIX2X3V; + case "matrix2x4[]": MATRIX2X4V; + case "matrix3x2[]": MATRIX3X2V; + case "matrix3x3[]": MATRIX3X3V; + case "matrix3x4[]": MATRIX3X4V; + case "matrix4x2[]": MATRIX4X2V; + case "matrix4x3[]": MATRIX4X3V; + case "matrix4x4[]": MATRIX4X4V; default: null; } } @@ -210,14 +357,26 @@ enum abstract ShaderParameterType(Null) case ShaderParameterType.BOOL2: "bool2"; case ShaderParameterType.BOOL3: "bool3"; case ShaderParameterType.BOOL4: "bool4"; + case ShaderParameterType.BOOLV: "bool[]"; + case ShaderParameterType.BOOL2V: "bool2[]"; + case ShaderParameterType.BOOL3V: "bool3[]"; + case ShaderParameterType.BOOL4V: "bool4[]"; case ShaderParameterType.FLOAT: "float"; case ShaderParameterType.FLOAT2: "float2"; case ShaderParameterType.FLOAT3: "float3"; case ShaderParameterType.FLOAT4: "float4"; + case ShaderParameterType.FLOATV: "float[]"; + case ShaderParameterType.FLOAT2V: "float2[]"; + case ShaderParameterType.FLOAT3V: "float3[]"; + case ShaderParameterType.FLOAT4V: "float4[]"; case ShaderParameterType.INT: "int"; case ShaderParameterType.INT2: "int2"; case ShaderParameterType.INT3: "int3"; case ShaderParameterType.INT4: "int4"; + case ShaderParameterType.INTV: "int[]"; + case ShaderParameterType.INT2V: "int2[]"; + case ShaderParameterType.INT3V: "int3[]"; + case ShaderParameterType.INT4V: "int4[]"; case ShaderParameterType.MATRIX2X2: "matrix2x2"; case ShaderParameterType.MATRIX2X3: "matrix2x3"; case ShaderParameterType.MATRIX2X4: "matrix2x4"; @@ -227,6 +386,15 @@ enum abstract ShaderParameterType(Null) case ShaderParameterType.MATRIX4X2: "matrix4x2"; case ShaderParameterType.MATRIX4X3: "matrix4x3"; case ShaderParameterType.MATRIX4X4: "matrix4x4"; + case ShaderParameterType.MATRIX2X2V: "matrix2x2[]"; + case ShaderParameterType.MATRIX2X3V: "matrix2x3[]"; + case ShaderParameterType.MATRIX2X4V: "matrix2x4[]"; + case ShaderParameterType.MATRIX3X2V: "matrix3x2[]"; + case ShaderParameterType.MATRIX3X3V: "matrix3x3[]"; + case ShaderParameterType.MATRIX3X4V: "matrix3x4[]"; + case ShaderParameterType.MATRIX4X2V: "matrix4x2[]"; + case ShaderParameterType.MATRIX4X3V: "matrix4x3[]"; + case ShaderParameterType.MATRIX4X4V: "matrix4x4[]"; default: null; } } diff --git a/src/openfl/display/_internal/CairoGraphics.hx b/src/openfl/display/_internal/CairoGraphics.hx index 76cee4ba22..5a92dc7848 100644 --- a/src/openfl/display/_internal/CairoGraphics.hx +++ b/src/openfl/display/_internal/CairoGraphics.hx @@ -32,8 +32,8 @@ import lime.math.Vector2; class CairoGraphics { #if lime_cairo - private static var SIN45:Float = 0.70710678118654752440084436210485; - private static var TAN22:Float = 0.4142135623730950488016887242097; + private static inline var SIN45:Float = 0.70710678118654752440084436210485; + private static inline var TAN22:Float = 0.4142135623730950488016887242097; private static var allowSmoothing:Bool; private static var bitmapRepeat:Bool; private static var bounds:Rectangle; diff --git a/src/openfl/display/_internal/Context3DAlphaMaskShader.hx b/src/openfl/display/_internal/Context3DAlphaMaskShader.hx index 7a47a81f10..e14e9472f9 100644 --- a/src/openfl/display/_internal/Context3DAlphaMaskShader.hx +++ b/src/openfl/display/_internal/Context3DAlphaMaskShader.hx @@ -5,8 +5,6 @@ import openfl.display.Shader; class Context3DAlphaMaskShader extends Shader { - public static var opaqueBitmapData:BitmapData = new BitmapData(1, 1, false, 0); - @:glFragmentHeader("varying vec2 openfl_TextureCoordv; uniform sampler2D openfl_Texture;") diff --git a/src/openfl/display/_internal/Context3DBitmap.hx b/src/openfl/display/_internal/Context3DBitmap.hx index ffac5f3d09..0c026a73ab 100644 --- a/src/openfl/display/_internal/Context3DBitmap.hx +++ b/src/openfl/display/_internal/Context3DBitmap.hx @@ -97,7 +97,7 @@ class Context3DBitmap var shader = renderer.__maskShader; renderer.setShader(shader); - renderer.applyBitmapData(Context3DMaskShader.opaqueBitmapData, true); + renderer.applyBitmapData(Context3DGraphics.blankBitmapData, true); renderer.applyMatrix(renderer.__getMatrix(bitmap.__renderTransform, bitmap.pixelSnapping)); renderer.updateShader(); diff --git a/src/openfl/display/_internal/Context3DGraphics.hx b/src/openfl/display/_internal/Context3DGraphics.hx index ccd57383aa..a6790bc83e 100644 --- a/src/openfl/display/_internal/Context3DGraphics.hx +++ b/src/openfl/display/_internal/Context3DGraphics.hx @@ -8,6 +8,7 @@ import openfl.utils._internal.UInt16Array; import openfl.display.BitmapData; import openfl.display.Graphics; import openfl.display.OpenGLRenderer; +import openfl.display3D.Context3DCompareMode; import openfl.geom.ColorTransform; import openfl.geom.Matrix; import openfl.geom.Rectangle; @@ -29,7 +30,8 @@ import openfl.display._internal.stats.DrawCallContext; @SuppressWarnings("checkstyle:FieldDocComment") class Context3DGraphics { - private static var blankBitmapData = new BitmapData(1, 1, false, 0); + public static var blankBitmapData:BitmapData = new BitmapData(1, 1, false, 0); + private static var maskRender:Bool; private static var tempColorTransform = new ColorTransform(1, 1, 1, 1, 0, 0, 0, 0); private static var tempVerticesVector:Vector = new Vector(); @@ -220,7 +222,7 @@ class Context3DGraphics var hasIndices = (indices != null); var transformABCD = false, transformXY = false; - var length = hasIndices ? indices.length : Math.floor(rects.length / 4); + var length = hasIndices ? indices.length : rects.length >> 2; if (length == 0) return; if (transforms != null) @@ -602,6 +604,9 @@ class Context3DGraphics case OVERRIDE_BLEND_MODE: data.skip(type); + case OVERRIDE_DEPTH_TEST: + data.skip(type); + default: data.destroy(); return false; @@ -672,7 +677,7 @@ class Context3DGraphics var width = graphics.__width; var height = graphics.__height; - if (bounds != null && width >= 1 && height >= 1) + if (bounds != null && width > 0 && height > 0) { if (graphics.__hardwareDirty || (graphics.__quadBuffer == null && graphics.__vertexBuffer == null && graphics.__vertexBufferUVT == null)) @@ -694,8 +699,7 @@ class Context3DGraphics var context = renderer.__context3D; var gl = context.gl; - var matrix = Matrix.__pool.get(); - + var matrix:Matrix = null; var shaderBuffer:ShaderBuffer = null; var bitmap:BitmapData = null; var bitmapMatrix:Matrix = null; @@ -732,7 +736,7 @@ class Context3DGraphics var vertexBuffer = hasUVTData ? graphics.__vertexBufferUVT : graphics.__vertexBuffer; var bufferPosition = hasUVTData ? vertexBufferPositionUVT : vertexBufferPosition; - var uMatrix = renderer.__getMatrix(graphics.__owner.__renderTransform, AUTO); + var uMatrix = renderer.__getMatrix(graphics.__owner.__renderTransform, NEVER); var shader:Shader; if (shaderBuffer != null && !maskRender) @@ -741,9 +745,9 @@ class Context3DGraphics renderer.__setShaderBuffer(shaderBuffer); renderer.applyMatrix(uMatrix); - renderer.applyBitmapData(bitmap, false, repeat); - renderer.applyAlpha(1); - renderer.applyColorTransform(null); + renderer.applyBitmapData(bitmap, smooth, repeat); + renderer.applyAlpha(graphics.__owner.__worldAlpha); + renderer.applyColorTransform(graphics.__owner.__worldColorTransform); renderer.__updateShaderBuffer(shaderBufferOffset); } else if (bitmap != null) @@ -761,7 +765,7 @@ class Context3DGraphics shader = maskRender ? renderer.__maskShader : renderer.__initGraphicsShader(null); renderer.setShader(shader); renderer.applyMatrix(uMatrix); - renderer.applyBitmapData(blankBitmapData, true, repeat); + renderer.applyBitmapData(blankBitmapData, false, repeat); #if lime var color:ARGB = (fill : ARGB); var worldColorTransform = graphics.__owner.__worldColorTransform; @@ -856,10 +860,7 @@ class Context3DGraphics case BEGIN_FILL: var c = data.readBeginFill(); - var color = Std.int(c.color); - var alpha = Std.int(c.alpha * 0xFF); - - fill = (color & 0xFFFFFF) | (alpha << 24); + fill = (Std.int(c.color) & 0xFFFFFF) | (Std.int(c.alpha * 0xFF) << 24); shaderBuffer = null; bitmap = null; bitmapMatrix = null; @@ -885,20 +886,13 @@ class Context3DGraphics if (bitmap != null || fill != null) { var c = data.readDrawQuads(); - var rects = c.rects; - var indices = c.indices; - var transforms = c.transforms; - - #if cpp - var rects:Array = rects == null ? null : untyped (rects).__array; - var indices:Array = indices == null ? null : untyped (indices).__array; - var transforms:Array = transforms == null ? null : untyped (transforms).__array; - #end - var hasIndices = (indices != null); - var length = hasIndices ? indices.length : Math.floor(rects.length / 4); + var length:Int; + if (c.indices != null) length = c.indices.length; + else if (c.rects != null) length = c.rects.length >> 2; + else length = 0; - var uMatrix = renderer.__getMatrix(graphics.__owner.__renderTransform, AUTO); + var uMatrix = renderer.__getMatrix(graphics.__owner.__renderTransform, NEVER); var shader:Shader; if (shaderBuffer != null && !maskRender) @@ -927,7 +921,7 @@ class Context3DGraphics shader = maskRender ? renderer.__maskShader : renderer.__initGraphicsShader(null); renderer.setShader(shader); renderer.applyMatrix(uMatrix); - renderer.applyBitmapData(blankBitmapData, true, repeat); + renderer.applyBitmapData(blankBitmapData, false, false); #if lime var color:ARGB = (fill : ARGB); var worldColorTransform = graphics.__owner.__worldColorTransform; @@ -977,6 +971,7 @@ class Context3DGraphics renderer.__clearShader(); } + case DRAW_CIRCLE: var c = data.readDrawCircle(); var radius = c.radius; @@ -1038,6 +1033,7 @@ class Context3DGraphics height = (scaledBottom - scaledTop) / graphics.__owner.scaleY; } + if (matrix == null) matrix = Matrix.__pool.get(); matrix.identity(); matrix.scale(width, height); matrix.tx = x; @@ -1047,7 +1043,7 @@ class Context3DGraphics var shader = maskRender ? renderer.__maskShader : renderer.__initGraphicsShader(null); renderer.setShader(shader); renderer.applyMatrix(renderer.__getMatrix(matrix, AUTO)); - renderer.applyBitmapData(blankBitmapData, true, repeat); + renderer.applyBitmapData(blankBitmapData, false, false); #if lime var color:ARGB = (fill : ARGB); var worldColorTransform = graphics.__owner.__worldColorTransform; @@ -1098,6 +1094,8 @@ class Context3DGraphics shaderBuffer = null; data.skip(type); context.setCulling(NONE); + context.__setGLDepthTest(false); + context.setDepthTest(false, ALWAYS); case MOVE_TO: var c = data.readMoveTo(); @@ -1108,12 +1106,17 @@ class Context3DGraphics var c = data.readOverrideBlendMode(); renderer.__setBlendMode(c.blendMode); + case OVERRIDE_DEPTH_TEST: + var c = data.readOverrideDepthTest(); + context.__setGLDepthTest(c.depthTest); + context.setDepthTest(c.depthTest, c.compareMode); + default: data.skip(type); } } - Matrix.__pool.release(matrix); + if (matrix != null) Matrix.__pool.release(matrix); } graphics.__dirty = false; diff --git a/src/openfl/display/_internal/Context3DMaskShader.hx b/src/openfl/display/_internal/Context3DMaskShader.hx index 458136a988..2cd907e87e 100644 --- a/src/openfl/display/_internal/Context3DMaskShader.hx +++ b/src/openfl/display/_internal/Context3DMaskShader.hx @@ -5,8 +5,6 @@ import openfl.display.Shader; class Context3DMaskShader extends Shader { - public static var opaqueBitmapData:BitmapData = new BitmapData(1, 1, false, 0); - @:glFragmentHeader("varying vec2 openfl_TextureCoordv; uniform sampler2D openfl_Texture;") diff --git a/src/openfl/display/_internal/Context3DVideo.hx b/src/openfl/display/_internal/Context3DVideo.hx index e6a85d7a26..53d81fda0d 100644 --- a/src/openfl/display/_internal/Context3DVideo.hx +++ b/src/openfl/display/_internal/Context3DVideo.hx @@ -111,7 +111,7 @@ class Context3DVideo var shader = renderer.__maskShader; renderer.setShader(shader); - renderer.applyBitmapData(Context3DMaskShader.opaqueBitmapData, true); + renderer.applyBitmapData(Context3DGraphics.blankBitmapData, true); renderer.applyMatrix(renderer.__getMatrix(video.__renderTransform, AUTO)); renderer.updateShader(); diff --git a/src/openfl/display/_internal/DrawCommandBuffer.hx b/src/openfl/display/_internal/DrawCommandBuffer.hx index d01fc98e9d..5096d2151a 100644 --- a/src/openfl/display/_internal/DrawCommandBuffer.hx +++ b/src/openfl/display/_internal/DrawCommandBuffer.hx @@ -9,6 +9,7 @@ import openfl.display.JointStyle; import openfl.display.LineScaleMode; import openfl.display.SpreadMethod; import openfl.display.TriangleCulling; +import openfl.display3D.Context3DCompareMode; import openfl.geom.Matrix; import openfl.Vector; @@ -16,8 +17,6 @@ import openfl.Vector; @SuppressWarnings("checkstyle:FieldDocComment") class DrawCommandBuffer { - private static var empty:DrawCommandBuffer = new DrawCommandBuffer(); - public var length(get, never):Int; public var types:Array; @@ -31,23 +30,14 @@ class DrawCommandBuffer public function new() { - copyOnWrite = true; - - if (empty == null) - { - types = []; - - b = []; - i = []; - f = []; - o = []; - ff = []; - ii = []; - } - else - { - clear(); - } + types = []; + + b = []; + i = []; + f = []; + o = []; + ff = []; + ii = []; } public function append(other:DrawCommandBuffer):DrawCommandBuffer @@ -135,6 +125,9 @@ class DrawCommandBuffer case WINDING_NON_ZERO: var c = data.readWindingNonZero(); windingNonZero(); + case OVERRIDE_DEPTH_TEST: + var c = data.readOverrideDepthTest(); + overrideDepthTest(c.depthTest, c.compareMode); default: } } @@ -143,7 +136,38 @@ class DrawCommandBuffer return other; } - public function beginBitmapFill(bitmap:BitmapData, matrix:Matrix, repeat:Bool, smooth:Bool):Void + public function clear():Void + { + types.resize(0); + + b.resize(0); + i.resize(0); + f.resize(0); + o.resize(0); + ff.resize(0); + ii.resize(0); + } + + public function copy():DrawCommandBuffer + { + var copy = new DrawCommandBuffer(); + copy.append(this); + return copy; + } + + public function destroy():Void + { + types = null; + + b = null; + i = null; + f = null; + o = null; + ff = null; + ii = null; + } + + public inline function beginBitmapFill(bitmap:BitmapData, matrix:Matrix, repeat:Bool, smooth:Bool):Void { prepareWrite(); @@ -154,7 +178,7 @@ class DrawCommandBuffer b.push(smooth); } - public function beginFill(color:Int, alpha:Float):Void + public inline function beginFill(color:Int, alpha:Float):Void { prepareWrite(); @@ -163,7 +187,7 @@ class DrawCommandBuffer f.push(alpha); } - public function beginGradientFill(type:GradientType, colors:Array, alphas:Array, ratios:Array, matrix:Matrix, spreadMethod:SpreadMethod, + public inline function beginGradientFill(type:GradientType, colors:Array, alphas:Array, ratios:Array, matrix:Matrix, spreadMethod:SpreadMethod, interpolationMethod:InterpolationMethod, focalPointRatio:Float):Void { prepareWrite(); @@ -179,7 +203,7 @@ class DrawCommandBuffer f.push(focalPointRatio); } - public function beginShaderFill(shaderBuffer:ShaderBuffer):Void + public inline function beginShaderFill(shaderBuffer:ShaderBuffer):Void { prepareWrite(); @@ -187,46 +211,7 @@ class DrawCommandBuffer o.push(shaderBuffer); } - public function clear():Void - { - if (!copyOnWrite) - { - // if these arrays have already been copied, then we should be able - // to reuse them instead of creating new copies. this will result in - // fewer temporary objects that need to be garbage collected - - types.resize(0); - - b.resize(0); - i.resize(0); - f.resize(0); - o.resize(0); - ff.resize(0); - ii.resize(0); - - return; - } - - types = empty.types; - - b = empty.b; - i = empty.i; - f = empty.f; - o = empty.o; - ff = empty.ff; - ii = empty.ii; - - copyOnWrite = true; - } - - public function copy():DrawCommandBuffer - { - var copy = new DrawCommandBuffer(); - copy.append(this); - return copy; - } - - public function cubicCurveTo(controlX1:Float, controlY1:Float, controlX2:Float, controlY2:Float, anchorX:Float, anchorY:Float):Void + public inline function cubicCurveTo(controlX1:Float, controlY1:Float, controlX2:Float, controlY2:Float, anchorX:Float, anchorY:Float):Void { prepareWrite(); @@ -239,7 +224,7 @@ class DrawCommandBuffer f.push(anchorY); } - public function curveTo(controlX:Float, controlY:Float, anchorX:Float, anchorY:Float):Void + public inline function curveTo(controlX:Float, controlY:Float, anchorX:Float, anchorY:Float):Void { prepareWrite(); @@ -250,21 +235,7 @@ class DrawCommandBuffer f.push(anchorY); } - public function destroy():Void - { - clear(); - - types = null; - - b = null; - i = null; - f = null; - o = null; - ff = null; - ii = null; - } - - public function drawCircle(x:Float, y:Float, radius:Float):Void + public inline function drawCircle(x:Float, y:Float, radius:Float):Void { prepareWrite(); @@ -274,7 +245,7 @@ class DrawCommandBuffer f.push(radius); } - public function drawEllipse(x:Float, y:Float, width:Float, height:Float):Void + public inline function drawEllipse(x:Float, y:Float, width:Float, height:Float):Void { prepareWrite(); @@ -285,7 +256,7 @@ class DrawCommandBuffer f.push(height); } - public function drawQuads(rects:Vector, indices:Vector, transforms:Vector):Void + public inline function drawQuads(rects:Vector, indices:Vector, transforms:Vector):Void { prepareWrite(); @@ -295,7 +266,7 @@ class DrawCommandBuffer o.push(transforms); } - public function drawRect(x:Float, y:Float, width:Float, height:Float):Void + public inline function drawRect(x:Float, y:Float, width:Float, height:Float):Void { prepareWrite(); @@ -306,7 +277,7 @@ class DrawCommandBuffer f.push(height); } - public function drawRoundRect(x:Float, y:Float, width:Float, height:Float, ellipseWidth:Float, ellipseHeight:Null):Void + public inline function drawRoundRect(x:Float, y:Float, width:Float, height:Float, ellipseWidth:Float, ellipseHeight:Null):Void { prepareWrite(); @@ -319,7 +290,7 @@ class DrawCommandBuffer o.push(ellipseHeight); } - public function drawTriangles(vertices:Vector, indices:Vector, uvtData:Vector, culling:TriangleCulling):Void + public inline function drawTriangles(vertices:Vector, indices:Vector, uvtData:Vector, culling:TriangleCulling):Void { prepareWrite(); @@ -330,14 +301,14 @@ class DrawCommandBuffer o.push(culling); } - public function endFill():Void + public inline function endFill():Void { prepareWrite(); types.push(END_FILL); } - public function lineBitmapStyle(bitmap:BitmapData, matrix:Matrix, repeat:Bool, smooth:Bool):Void + public inline function lineBitmapStyle(bitmap:BitmapData, matrix:Matrix, repeat:Bool, smooth:Bool):Void { prepareWrite(); @@ -348,7 +319,7 @@ class DrawCommandBuffer b.push(smooth); } - public function lineGradientStyle(type:GradientType, colors:Array, alphas:Array, ratios:Array, matrix:Matrix, spreadMethod:SpreadMethod, + public inline function lineGradientStyle(type:GradientType, colors:Array, alphas:Array, ratios:Array, matrix:Matrix, spreadMethod:SpreadMethod, interpolationMethod:InterpolationMethod, focalPointRatio:Float):Void { prepareWrite(); @@ -364,7 +335,7 @@ class DrawCommandBuffer f.push(focalPointRatio); } - public function lineStyle(thickness:Null, color:Int, alpha:Float, pixelHinting:Bool, scaleMode:LineScaleMode, caps:CapsStyle, joints:JointStyle, + public inline function lineStyle(thickness:Null, color:Int, alpha:Float, pixelHinting:Bool, scaleMode:LineScaleMode, caps:CapsStyle, joints:JointStyle, miterLimit:Float):Void { prepareWrite(); @@ -380,7 +351,7 @@ class DrawCommandBuffer f.push(miterLimit); } - public function lineTo(x:Float, y:Float):Void + public inline function lineTo(x:Float, y:Float):Void { prepareWrite(); @@ -389,7 +360,7 @@ class DrawCommandBuffer f.push(y); } - public function moveTo(x:Float, y:Float):Void + public inline function moveTo(x:Float, y:Float):Void { prepareWrite(); @@ -398,23 +369,7 @@ class DrawCommandBuffer f.push(y); } - private function prepareWrite():Void - { - if (copyOnWrite) - { - types = types.copy(); - b = b.copy(); - i = i.copy(); - f = f.copy(); - o = o.copy(); - ff = ff.copy(); - ii = ii.copy(); - - copyOnWrite = false; - } - } - - public function overrideBlendMode(blendMode:BlendMode):Void + public inline function overrideBlendMode(blendMode:BlendMode):Void { prepareWrite(); @@ -422,7 +377,7 @@ class DrawCommandBuffer o.push(blendMode); } - public function overrideMatrix(matrix:Matrix):Void + public inline function overrideMatrix(matrix:Matrix):Void { prepareWrite(); @@ -430,22 +385,47 @@ class DrawCommandBuffer o.push(matrix); } - public function windingEvenOdd():Void + public inline function windingEvenOdd():Void { prepareWrite(); types.push(WINDING_EVEN_ODD); } - public function windingNonZero():Void + public inline function windingNonZero():Void { prepareWrite(); types.push(WINDING_NON_ZERO); } + public inline function overrideDepthTest(depthTest:Bool, compareMode:Context3DCompareMode):Void + { + prepareWrite(); + + types.push(OVERRIDE_DEPTH_TEST); + b.push(depthTest); + o.push(compareMode); + } + + private inline function prepareWrite():Void + { + if (copyOnWrite) + { + types = types.copy(); + b = b.copy(); + i = i.copy(); + f = f.copy(); + o = o.copy(); + ff = ff.copy(); + ii = ii.copy(); + + copyOnWrite = false; + } + } + // Get & Set Methods - private function get_length():Int + private inline function get_length():Int { return types.length; } diff --git a/src/openfl/display/_internal/DrawCommandReader.hx b/src/openfl/display/_internal/DrawCommandReader.hx index 7a25b58a7e..2a1f8e84fb 100644 --- a/src/openfl/display/_internal/DrawCommandReader.hx +++ b/src/openfl/display/_internal/DrawCommandReader.hx @@ -9,6 +9,7 @@ import openfl.display.JointStyle; import openfl.display.LineScaleMode; import openfl.display.SpreadMethod; import openfl.display.TriangleCulling; +import openfl.display3D.Context3DCompareMode; import openfl.geom.Matrix; import openfl.Vector; @@ -113,6 +114,10 @@ class DrawCommandReader case OVERRIDE_MATRIX: oPos += 1; // matrix + case OVERRIDE_DEPTH_TEST: + bPos += 1; // depthTest + oPos += 1; // compareMode + case WINDING_EVEN_ODD, WINDING_NON_ZERO: // no parameters @@ -312,6 +317,13 @@ class DrawCommandReader return new WindingNonZeroView(this); } + public inline function readOverrideDepthTest():OverrideDepthTest + { + advance(); + prev = OVERRIDE_DEPTH_TEST; + return new OverrideDepthTest(this); + } + public function reset():Void { bPos = iPos = fPos = oPos = ffPos = iiPos = tsPos = 0; @@ -1025,3 +1037,25 @@ abstract WindingNonZeroView(DrawCommandReader) this = d; } } + +abstract OverrideDepthTest(DrawCommandReader) +{ + public inline function new(d:DrawCommandReader) + { + this = d; + } + + public var depthTest(get, never):Bool; + + private inline function get_depthTest():Bool + { + return this.bool(0); + } + + public var compareMode(get, never):Context3DCompareMode; + + private inline function get_compareMode():Context3DCompareMode + { + return this.obj(0); + } +} diff --git a/src/openfl/display/_internal/DrawCommandType.hx b/src/openfl/display/_internal/DrawCommandType.hx index aa0d62c2b8..6267d15b3d 100644 --- a/src/openfl/display/_internal/DrawCommandType.hx +++ b/src/openfl/display/_internal/DrawCommandType.hx @@ -26,4 +26,7 @@ enum abstract DrawCommandType(Int) var WINDING_EVEN_ODD; var WINDING_NON_ZERO; var UNKNOWN; + + // custom + var OVERRIDE_DEPTH_TEST; } diff --git a/src/openfl/display3D/Context3D.hx b/src/openfl/display3D/Context3D.hx index 91c0702753..bad7202f0c 100644 --- a/src/openfl/display3D/Context3D.hx +++ b/src/openfl/display3D/Context3D.hx @@ -14,6 +14,7 @@ import openfl.display3D.textures.VideoTexture; import openfl.display.BitmapData; import openfl.display.Stage; import openfl.display.Stage3D; +import openfl.display.OpenGLRenderer; import openfl.errors.Error; import openfl.errors.IllegalOperationError; import openfl.events.EventDispatcher; @@ -25,14 +26,12 @@ import openfl.utils._internal.UInt16Array; import openfl.utils._internal.UInt8Array; import openfl.utils.AGALMiniAssembler; import openfl.utils.ByteArray; -import openfl.display.OpenGLRenderer; #if lime import lime.graphics.opengl.GL; import lime.graphics.Image; import lime.graphics.ImageBuffer; import lime.graphics.RenderContext; import lime.graphics.WebGLRenderContext; -import lime.math.Rectangle as LimeRectangle; import lime.math.Vector2; #end @@ -280,6 +279,7 @@ import lime.math.Vector2; @:noCompletion private var __state:Context3DState; @:noCompletion private var __vertexConstants:Float32Array; @:noCompletion private var __usingComplexBlend:Bool; + @:noCompletion private var __tempMatrixData:Float32Array; @:noCompletion private function new(stage:Stage, contextState:Context3DState = null, stage3D:Stage3D = null) { @@ -459,7 +459,7 @@ import lime.math.Vector2; public function clear(red:Float = 0, green:Float = 0, blue:Float = 0, alpha:Float = 1, depth:Float = 1, stencil:UInt = 0, mask:UInt = Context3DClearMask.ALL):Void { - __clear(false, red, green, blue, alpha, depth, stencil, mask); + inline __clear(false, red, green, blue, alpha, depth, stencil, mask); } @:noCompletion private function __clear(useScissor:Bool, red:Float = 0, green:Float = 0, blue:Float = 0, alpha:Float = 1, depth:Float = 1, @@ -485,11 +485,12 @@ import lime.math.Vector2; || __contextState.colorMaskBlue != true || __contextState.colorMaskAlpha != true #end) { - gl.colorMask(true, true, true, true); - __contextState.colorMaskRed = true; - __contextState.colorMaskGreen = true; - __contextState.colorMaskBlue = true; - __contextState.colorMaskAlpha = true; + gl.colorMask( + __contextState.colorMaskRed = true, + __contextState.colorMaskGreen = true, + __contextState.colorMaskBlue = true, + __contextState.colorMaskAlpha = true + ); } gl.clearColor(red, green, blue, alpha); @@ -501,8 +502,7 @@ import lime.math.Vector2; if (#if openfl_disable_context_cache true #else __contextState.depthMask != true #end) { - gl.depthMask(true); - __contextState.depthMask = true; + gl.depthMask(__contextState.depthMask = true); } gl.clearDepth(depth); @@ -514,12 +514,10 @@ import lime.math.Vector2; if (#if openfl_disable_context_cache true #else __contextState.stencilWriteMask != 0xFF #end) { - gl.stencilMask(0xFF); - __contextState.stencilWriteMask = 0xFF; + gl.stencilMask(__contextState.stencilWriteMask = 0xFF); } gl.clearStencil(stencil); - __contextState.stencilWriteMask = 0xFF; } if (clearMask == 0) return; @@ -1136,7 +1134,7 @@ import lime.math.Vector2; #if lime if (destination == null) return; - var sourceRect = srcRect != null ? srcRect.__toLimeRectangle() : new LimeRectangle(0, 0, backBufferWidth, backBufferHeight); + var sourceRect = srcRect != null ? srcRect.__toLimeRectangle() : new lime.math.Rectangle(0, 0, backBufferWidth, backBufferHeight); var destVector = destPoint != null ? destPoint.__toLimeVector2() : new Vector2(); if (__stage.context3D == this) @@ -2513,7 +2511,7 @@ import lime.math.Vector2; if (__context.type == OPENGL) { // TODO: Cache? - gl.enable(gl.TEXTURE_2D); + gl.enable(texture.__textureTarget); } #end @@ -2817,11 +2815,6 @@ import lime.math.Vector2; } } - @:noCompletion private inline function __glBlendBarrier():Void - { - gl.blendBarrier(); - } - // Get & Set Methods @:noCompletion private function get_enableErrorChecking():Bool { diff --git a/src/openfl/display3D/IndexBuffer3D.hx b/src/openfl/display3D/IndexBuffer3D.hx index dc0e57bcb6..04f1d83ea6 100644 --- a/src/openfl/display3D/IndexBuffer3D.hx +++ b/src/openfl/display3D/IndexBuffer3D.hx @@ -25,7 +25,7 @@ import openfl.Vector; { @:noCompletion private var __context:Context3D; @:noCompletion private var __id:GLBuffer; - @:noCompletion private var __memoryUsage:Int = -1; + @:noCompletion private var __memoryUsage:Int; @:noCompletion private var __numIndices:Int; @:noCompletion private var __tempUInt16Array:UInt16Array; @:noCompletion private var __usage:Int; @@ -49,6 +49,8 @@ import openfl.Vector; { var gl = __context.gl; gl.deleteBuffer(__id); + __id = null; + __memoryUsage = 0; } /** @@ -91,9 +93,14 @@ import openfl.Vector; if (data == null) return; var gl = __context.gl; __context.__bindGLElementArrayBuffer(__id); - if (__memoryUsage == data.byteLength) gl.bufferSubData(gl.ELEMENT_ARRAY_BUFFER, 0, data); + if (__memoryUsage == data.byteLength) + { + gl.bufferSubData(gl.ELEMENT_ARRAY_BUFFER, 0, data); + } else + { gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, data, __usage); + } __memoryUsage = data.byteLength; } diff --git a/src/openfl/display3D/Program3D.hx b/src/openfl/display3D/Program3D.hx index 3a3e922819..acef067e73 100644 --- a/src/openfl/display3D/Program3D.hx +++ b/src/openfl/display3D/Program3D.hx @@ -7,47 +7,27 @@ import openfl.display3D._internal.AGALConverter; import openfl.display._internal.SamplerState; import openfl.utils._internal.Float32Array; import openfl.utils._internal.Log; +import openfl.display.Shader; import openfl.display.ShaderParameterType; import openfl.errors.IllegalOperationError; import openfl.utils.ByteArray; +import openfl.utils.GLSLSourceAssembler; import openfl.Vector; #if lime import lime.graphics.opengl.GL; import lime.utils.BytePointer; #end -/** - The Program3D class represents a pair of rendering programs (also called "shaders") - uploaded to the rendering context. - - Programs managed by a Program3D object control the entire rendering of triangles - during a Context3D drawTriangles() call. Upload the binary bytecode to the rendering - context using the upload method. (Once uploaded, the program in the original byte - array is no longer referenced; changing or discarding the source byte array does - not change the program.) - - Programs always consist of two linked parts: A vertex and a fragment program. - - 1. The vertex program operates on data defined in VertexBuffer3D objects and is - responsible for projecting vertices into clip space and passing any required vertex - data, such as color, to the fragment shader. - 2. The fragment shader operates on the attributes passed to it by the vertex program - and produces a color for every rasterized fragment of a triangle, resulting in pixel - colors. Note that fragment programs have several names in 3D programming literature, - including fragment shader and pixel shader. - - Designate which program pair to use for subsequent rendering operations by passing the - corresponding Program3D instance to the Context3D `setProgram()` method. - - You cannot create a Program3D object directly; use the Context3D `createProgram()` - method instead. -**/ @:access(openfl.display3D.Context3D) @:access(openfl.display.ShaderInput) @:access(openfl.display.ShaderParameter) +@:access(openfl.display.Shader) @:access(openfl.display.Stage) +@:access(openfl.utils.GLSLSourceAssembler) @:final class Program3D { + @:noCompletion private var __context:Context3D; + @:noCompletion private var __format:Context3DProgramFormat; @:noCompletion private var __agalAlphaSamplerEnabled:Array; @:noCompletion private var __agalAlphaSamplerUniforms:List; @:noCompletion private var __agalFragmentUniformMap:UniformMap; @@ -56,20 +36,25 @@ import lime.utils.BytePointer; @:noCompletion private var __agalSamplerUsageMask:Int; @:noCompletion private var __agalUniforms:List; @:noCompletion private var __agalVertexUniformMap:UniformMap; - @:noCompletion private var __context:Context3D; - @:noCompletion private var __format:Context3DProgramFormat; @:noCompletion private var __glFragmentShader:GLShader; + @:noCompletion private var __glVertexShader:GLShader; @:noCompletion private var __glFragmentSource:String; + @:noCompletion private var __glFragmentVersion:String; + @:noCompletion private var __glVertexSource:String; + @:noCompletion private var __glVertexVersion:String; @:noCompletion private var __glProgram:GLProgram; + @:noCompletion private var __glslSamplerLocations:Array>; + @:noCompletion private var __glslSamplerDefaults:Array; + @:noCompletion private var __glslSamplerNames:Array; + @:noCompletion private var __glslAttribLocations:Array>; @:noCompletion private var __glslAttribNames:Array; @:noCompletion private var __glslAttribTypes:Array; - @:noCompletion private var __glslSamplerNames:Array; - @:noCompletion private var __glslUniformLocations:Array; + @:noCompletion private var __glslAttribSizes:Array; + @:noCompletion private var __glslUniformLocations:Array>; + @:noCompletion private var __glslUniformDefaults:Array; @:noCompletion private var __glslUniformNames:Array; @:noCompletion private var __glslUniformTypes:Array; - @:noCompletion private var __glVertexShader:GLShader; - @:noCompletion private var __glVertexSource:String; - // @:noCompletion private var __memUsage:Int; + @:noCompletion private var __glslUniformSizes:Array; @:noCompletion private var __samplerStates:Array; @:noCompletion private function new(context3D:Context3D, format:Context3DProgramFormat) @@ -79,7 +64,6 @@ import lime.utils.BytePointer; if (__format == AGAL) { - // __memUsage = 0; __agalSamplerUsageMask = 0; __agalUniforms = new List(); __agalSamplerUniforms = new List(); @@ -88,34 +72,28 @@ import lime.utils.BytePointer; } else { + __glslSamplerLocations = new Array(); + __glslSamplerDefaults = new Array(); + __glslSamplerNames = new Array(); + __glslAttribLocations = new Array(); __glslAttribNames = new Array(); __glslAttribTypes = new Array(); - __glslSamplerNames = new Array(); + __glslAttribSizes = new Array(); __glslUniformLocations = new Array(); + __glslUniformDefaults = new Array(); __glslUniformNames = new Array(); __glslUniformTypes = new Array(); + __glslUniformSizes = new Array(); } __samplerStates = new Array(); } - /** - Frees all resources associated with this object. After disposing a - Program3D object, calling `upload()` and rendering using this object will fail. - **/ public function dispose():Void { __deleteShaders(); } - /** - **BETA** - - Get the index for the specified shader attribute. - - @returns The index, or -1 if the attribute is not bound or - was not found in the shader sources - **/ public function getAttributeIndex(name:String):Int { if (__format == AGAL) @@ -135,21 +113,13 @@ import lime.utils.BytePointer; { for (i in 0...__glslAttribNames.length) { - if (__glslAttribNames[i] == name) return i; + if (__glslAttribNames[i] == name) return __glslAttribLocations[i] == null ? -1 : __glslAttribLocations[i]; } return -1; } } - /** - **BETA** - - Get the index for the specified shader constant. - - @returns The index, or -1 if the constant is not bound or - was not found in the shader sources - **/ public function getConstantIndex(name:String):Int { if (__format == AGAL) @@ -173,215 +143,16 @@ import lime.utils.BytePointer; { for (i in 0...__glslUniformNames.length) { - if (__glslUniformNames[i] == name) return cast __glslUniformLocations[i]; + if (__glslUniformNames[i] == name) return __glslUniformLocations[i] == null ? -1 : cast __glslUniformLocations[i]; } return -1; } } - /** - Uploads a pair of rendering programs expressed in AGAL (Adobe Graphics Assembly - Language) bytecode. - - Program bytecode can be created using the Pixel Bender 3D offline tools. It can - also be created dynamically. The AGALMiniAssembler class is a utility class - that compiles AGAL assembly language programs to AGAL bytecode. The class is not - part of the runtime. When you upload the shader programs, the bytecode is - compiled into the native shader language for the current device (for example, - OpenGL or Direct3D). The runtime validates the bytecode on upload. - - The programs run whenever the Context3D `drawTriangles()` method is invoked. The - vertex program is executed once for each vertex in the list of triangles to be - drawn. The fragment program is executed once for each pixel on a triangle surface. - - The "variables" used by a shader program are called registers. The following - registers are defined: - - | Name | Number per Fragment program | Number per Vertex program | Purpose | - | --- | --- | --- | --- | - | Attribute | n/a | 8 | Vertex shader input; read from a vertex buffer specified using `Context3D.setVertexBufferAt()`. | - | Constant | 28 | 128 | Shader input; set using the `Context3D.setProgramConstants()` family of functions. | - | Temporary | 8 | 8 | Temporary register for computation, not accessible outside program. | - | Output | 1 | 1 | Shader output: in a vertex program, the output is the clipspace position; in a fragment program, the output is a color. | - | Varying | 8 | 8 | Transfer interpolated data between vertex and fragment shaders. The varying registers from the vertex program are applied as input to the fragment program. Values are interpolated according to the distance from the triangle vertices. | - | Sampler | 8 | n/a | Fragment shader input; read from a texture specified using `Context3D.setTextureAt()` | - - A vertex program receives input from two sources: vertex buffers and constant - registers. Specify which vertex data to use for a particular vertex attribute - register using the Context3D `setVertexBufferAt()` method. You can define up to - eight input registers for vertex attributes. The vertex attribute values are read - from the vertex buffer for each vertex in the triangle list and placed in the - attribute register. Specify constant registers using the Context3D - `setProgramConstantsFromMatrix()` or `setProgramConstantsFromVector()` - methods. Constant registers retain the same value for every vertex in the - triangle list. (You can only modify the constant values between calls to - `drawTriangles().`) - - The vertex program is responsible for projecting the triangle vertices into - clip space (the canonical viewing area within ±1 on the x and y axes and 0-1 on - the z axis) and placing the transformed coordinates in its output register. - (Typically, the appropriate projection matrix is provided to the shader in a set - of constant registers.) The vertex program must also copy any vertex attributes - or computed values needed by the fragment program to a special set of variables - called varying registers. When a fragment shader runs, the value supplied in a - varying register is linearly interpolated according to the distance of the - current fragment from each triangle vertex. - - A fragment program receives input from the varying registers and from a separate - set of constant registers (set with `setProgramConstantsFromMatrix()` or - `setProgramConstantsFromVector()`). You can also read texture data from textures - uploaded to the rendering context using sampler registers. Specify which texture - to access with a particular sampler register using the Context3D `setTextureAt()` - method. The fragment program is responsible for setting its output register to a - color value. - - @param vertexProgram AGAL bytecode for the Vertex program. The ByteArray object - must use the little endian format. - @param fragmentProgram AGAL bytecode for the Fragment program. The ByteArray - object must use the little endian format. - @throws TypeError Null Pointer Error: if vertexProgram or fragmentProgram is - `null`. - @throws Error Object Disposed: if the Program3D object was disposed either - directly by a call to `dispose()`, or indirectly by calling the Context3D - `dispose()` or because the rendering context was disposed because of device loss. - @throws ArgumentError Agal Program Too Small: when either program code array - is smaller than 31 bytes length. This is the size of the shader bytecode of a - one-instruction program. - @throws ArgumentError Program Must Be Little Endian: if either of the program - byte code arrays is not little endian. - @throws Error Native Shader Compilation Failed: if the output of the AGAL - translator is not a compilable native shader language program. This error is only - thrown in release players. - @throws Error Native Shader Compilation Failed OpenGL: if the output of the - AGAL translator is not a compilable OpengGL shader language program, and - includes compilation diagnostics. This error is only thrown in debug players. - @throws Error Native Shader Compilation Failed D3D9: if the output of the AGAL - translator is not a compilable Direct3D shader language program, and includes - compilation diagnostics. This error is only thrown in debug players. - - The following errors are thrown when the AGAL bytecode validation fails: - - @throws Error Not An Agal Program: if the header "magic byte" is wrong. The - first byte of the bytecode must be 0xa0. This error can indicate that the byte - array is set to the wrong endian order. - @throws Error Bad Agal Version: if the AGAL version is not supported by the - current SWF version. The AGAL version must be set to 1 for SWF version 13. - @throws Error Bad Agal Program Type: if the AGAL program type identifier is - not valid. The third byte in the byte code must be 0xa1. This error can indicates - that the byte array is set to the wrong endian order. - @throws Error Bad Agal Shader Type: if the shader type code is not either - fragment or vertex (1 or 0). - @throws Error Invalid Agal Opcode Out Of Range: if an invalid opcode is - encountered in the token stream. - @throws Error Invalid Agal Opcode Not Implemented: if an invalid opcode is - encountered in the token stream. - @throws Error Agal Opcode Only Allowed In Fragment Program: if an opcode is - encountered in the token stream of the vertex program that is only allowed in fragment programs, such as KIL or TEX. - @throws Error Bad Agal Source Operands: if both source operands are constant - registers. You must compute the result outside the shader program and pass it - in using a single constant register. - @throws Error Both Operands Are Indirect Reads: if both operands are indirect - reads. - @throws Error Opcode Destination Must Be All Zero: if a token with an opcode - (such as KIL) that has no destination sets a non-zero value for the destination - register. - @throws Error Opcode Destination Must Use Mask: if an opcode that produces - only a 3 component result is used without masking. - @throws Error Too Many Tokens: if there are too many tokens (more than 200) in - an AGAL program. - @throws Error Fragment Shader Type: if the fragment program type (byte 6 of - fragmentProgram parameter) is not set to 1. - @throws Error Vertex Shader Type: if the vertex program type (byte 6 of - vertexProgram parameter) is not set to 0. - @throws Error Varying Read But Not Written To: if the fragment shader reads a - varying register that was never written to by the vertex shader. - @throws Error Varying Partial Write: if a varying register is only partially - written to. All components of a varying register must be written to. - @throws Error Fragment Write All Components: if a fragment color output is only - partially written to. All four components of the color output must be written to. - @throws Error Vertex Write All Components: if a vertex clip space output is only - partially written to. All components of the vertex clip space output must be - written to. - @throws Error Unused Operand: if an unused operand in a token is not set to all - zero. - @throws Error Sampler Register Only In Fragment: if a texture sampler register - is used in a vertex program. - @throws Error Sampler Register Second Operand: if a sampler register is used - as a destination or first operand of an AGAL token. - @throws Error Indirect Only Allowed In Vertex: if indirect addressing is used - in a fragment program. - @throws Error Indirect Only Into Constant Registers: if indirect addressing - is used on a non-constant register. - @throws Error Indirect Source Type: if the indirect source type is not - attribute, constant or temporary register. - @throws Error Indirect Addressing Fields Must Be Zero: if not all indirect - addressing fields are zero for direct addressing. - @throws Error Varying Registers Only Read In Fragment: if a varying register is - read in a vertex program. Varying registers can only be written in vertex - programs and read in fragment programs. - @throws Error Attribute Registers Only Read In Vertex: if an attribute - registers is read in a fragment program. Attribute registers can only be read - in vertex programs. - @throws Error Can Not Read Output Register: if an output (position or color) - register is read. Output registers can only be written to, not read. - @throws Error Temp Register Read Without Write: if a temporary register is read - without being written to earlier. - @throws Error Temp Register Component Read Without Write: if a specific - temporary register component is read without being written to earlier. - @throws Error Sampler Register Cannot Be Written To: if a sampler register is - written to. Sampler registers can only be read, not written to. - @throws Error Varying Registers Write: if a varying register is written to in - a fragment program. Varying registers can only be written in vertex programs and - read in fragment programs. - @throws Error Attribute Register Cannot Be Written To: if an attribute - register is written to. Attribute registers are read-only. - @throws Error Constant Register Cannot Be Written To: if a constant register - is written to inside a shader program. - @throws Error Destination Writemask Is Zero: if a destination writemask is - zero. All components of an output register must be set. - @throws Error AGAL Reserved Bits Should Be Zero: if any reserved bits in a - token are not zero. This indicates an error in creating the bytecode (or - malformed bytecode). - @throws Error Unknown Register Type: if an invalid register type index is used. - @throws Error Sampler Register Out Of Bounds: if an invalid sampler register - index is used. - @throws Error Varying Register Out Of Bounds: if an invalid varying register - index is used. - @throws Error Attribute Register Out Of Bounds: if an invalid attribute - register index is used. - @throws Error Constant Register Out Of Bounds: if an invalid constant - register index is used. - @throws Error Output Register Out Of Bounds: if an invalid output register - index is used. - @throws Error Temporary Register Out Of Bounds: if an invalid temporary - register index is used. - @throws Error Cube Map Sampler Must Use Clamp: if a cube map sampler does not - set the wrap mode to clamp. - @throws Error Unknown Sampler Dimension: if a sample uses an unknown sampler - dimension. (Only 2D and cube textures are supported.) - @throws Error Unknown Filter Mode: if a sampler uses an unknown filter mode. - (Only nearest neighbor and linear filtering are supported.) - @throws Error Unknown Mipmap Mode: if a sampler uses an unknown mipmap mode. - (Only none, nearest neighbor, and linear mipmap modes are supported.) - @throws Error Unknown Wrapping Mode if a sampler uses an unknown wrapping mode. - (Only clamp and repeat wrapping modes are supported.) - @throws Error Unknown Special Flag: if a sampler uses an unknown special flag. - @throws Error Output Color Not Maskable: You cannot mask the color output - register in a fragment program. All components of the color register must be set. - @throws Error Second Operand Must Be Sampler Register: The AGAL tex opcode must - have a sampler as the second source operand. - @throws Error Indirect Not Allowed: indirect addressing used where not allowed. - @throws Error Swizzle Must Be Scalar: swizzling error. - @throws Error Cant Swizzle 2nd Source: swizzling error. - @throws Error Second Use Of Sampler Must Have Same Params: all samplers that - access the same texture must use the same dimension, wrap, filter, special, and - mipmap settings. - @throws Error 3768: The Stage3D API may not be used during background execution. - **/ public function upload(vertexProgram:ByteArray, fragmentProgram:ByteArray):Void { - if (__format != AGAL) return; + if (__format != AGAL) throw "Program3D.upload is AGAL only, use uploadSources"; // var samplerStates = new Vector (Context3D.MAX_SAMPLERS); var samplerStates = new Array(); @@ -405,177 +176,15 @@ import lime.utils.BytePointer; } } - /** - **BETA** - - Uploads a pair of rendering programs expressed in GLSL (GL Shader Language). - **/ public function uploadSources(vertexSource:String, fragmentSource:String):Void { - if (__format != GLSL) return; - - // TODO: Precision hint? - - var prefix = "#ifdef GL_ES - #ifdef GL_FRAGMENT_PRECISION_HIGH - precision highp float; - #else - precision mediump float; - #endif - #endif - "; - - var vertex = prefix + vertexSource; - var fragment = prefix + fragmentSource; - - if (vertex == __glVertexSource && fragment == __glFragmentSource) return; + if (__format != GLSL) throw "Program3D.uploadSources is GL only, use upload"; - __processGLSLData(vertexSource, "attribute"); - __processGLSLData(vertexSource, "uniform"); - __processGLSLData(fragmentSource, "uniform"); + if (vertexSource == __glVertexSource && fragmentSource == __glFragmentSource) return; __deleteShaders(); - __uploadFromGLSL(vertex, fragment); - - // Sort by index - - var samplerNames = __glslSamplerNames; - var attribNames = __glslAttribNames; - var attribTypes = __glslAttribTypes; - var uniformNames = __glslUniformNames; - - __glslSamplerNames = new Array(); - __glslAttribNames = new Array(); - __glslAttribTypes = new Array(); - __glslUniformLocations = new Array(); - - var gl = __context.gl; - var index:Int, location; - - for (name in samplerNames) - { - index = cast gl.getUniformLocation(__glProgram, name); - __glslSamplerNames[index] = name; - } - - for (i in 0...attribNames.length) - { - index = gl.getAttribLocation(__glProgram, attribNames[i]); - __glslAttribNames[index] = attribNames[i]; - __glslAttribTypes[index] = attribTypes[i]; - } - - for (i in 0...uniformNames.length) - { - location = gl.getUniformLocation(__glProgram, uniformNames[i]); - __glslUniformLocations[i] = location; - } - } - - @:noCompletion private function __buildAGALUniformList():Void - { - if (__format == GLSL) return; - - #if lime - var gl = __context.gl; - - __agalUniforms.clear(); - __agalSamplerUniforms.clear(); - __agalAlphaSamplerUniforms.clear(); - __agalAlphaSamplerEnabled = []; - - __agalSamplerUsageMask = 0; - - var numActive = 0; - numActive = gl.getProgramParameter(__glProgram, gl.ACTIVE_UNIFORMS); - - var vertexUniforms = new List(); - var fragmentUniforms = new List(); - - for (i in 0...numActive) - { - var info = gl.getActiveUniform(__glProgram, i); - var name = info.name; - var size = info.size; - var uniformType = info.type; - - var uniform = new Uniform(__context); - uniform.name = name; - uniform.size = size; - uniform.type = uniformType; - - uniform.location = gl.getUniformLocation(__glProgram, uniform.name); - - var indexBracket = uniform.name.indexOf("["); - - if (indexBracket >= 0) - { - uniform.name = uniform.name.substring(0, indexBracket); - } - - switch (uniform.type) - { - case GL.FLOAT_MAT2: - uniform.regCount = 2; - case GL.FLOAT_MAT3: - uniform.regCount = 3; - case GL.FLOAT_MAT4: - uniform.regCount = 4; - default: - uniform.regCount = 1; - } - - uniform.regCount *= uniform.size; - - __agalUniforms.add(uniform); - - if (uniform.name == "vcPositionScale") - { - __agalPositionScale = uniform; - } - else if (StringTools.startsWith(uniform.name, "vc")) - { - uniform.regIndex = Std.parseInt(uniform.name.substring(2)); - uniform.regData = __context.__vertexConstants; - vertexUniforms.add(uniform); - } - else if (StringTools.startsWith(uniform.name, "fc")) - { - uniform.regIndex = Std.parseInt(uniform.name.substring(2)); - uniform.regData = __context.__fragmentConstants; - fragmentUniforms.add(uniform); - } - else if (StringTools.startsWith(uniform.name, "sampler") && uniform.name.indexOf("alpha") == -1) - { - uniform.regIndex = Std.parseInt(uniform.name.substring(7)); - __agalSamplerUniforms.add(uniform); - - for (reg in 0...uniform.regCount) - { - __agalSamplerUsageMask |= (1 << (uniform.regIndex + reg)); - } - } - else if (StringTools.startsWith(uniform.name, "sampler") && StringTools.endsWith(uniform.name, "_alpha")) - { - var len = uniform.name.indexOf("_") - 7; - uniform.regIndex = Std.parseInt(uniform.name.substring(7, 7 + len)) + 4; - __agalAlphaSamplerUniforms.add(uniform); - } - else if (StringTools.startsWith(uniform.name, "sampler") && StringTools.endsWith(uniform.name, "_alphaEnabled")) - { - uniform.regIndex = Std.parseInt(uniform.name.substring(7)); - __agalAlphaSamplerEnabled[uniform.regIndex] = uniform; - } - - if (Log.level == LogLevel.VERBOSE) - { - Log.verbose('${i} name:${uniform.name} type:${uniform.type} size:${uniform.size} location:${uniform.location}'); - } - } - - __agalVertexUniformMap = new UniformMap(Lambda.array(vertexUniforms)); - __agalFragmentUniformMap = new UniformMap(Lambda.array(fragmentUniforms)); - #end + __uploadFromGLSL(vertexSource, fragmentSource); + __buildGLSLParamList(); } @:noCompletion private function __deleteShaders():Void @@ -584,6 +193,7 @@ import lime.utils.BytePointer; if (__glProgram != null) { + gl.deleteProgram(__glProgram); __glProgram = null; } @@ -598,6 +208,34 @@ import lime.utils.BytePointer; gl.deleteShader(__glFragmentShader); __glFragmentShader = null; } + + #if haxe4 + __glslSamplerLocations.resize(0); + __glslSamplerDefaults.resize(0); + __glslSamplerNames.resize(0); + __glslAttribLocations.resize(0); + __glslAttribNames.resize(0); + __glslAttribTypes.resize(0); + __glslAttribSizes.resize(0); + __glslUniformLocations.resize(0); + __glslUniformDefaults.resize(0); + __glslUniformNames.resize(0); + __glslUniformTypes.resize(0); + __glslUniformSizes.resize(0); + #else + __glslSamplerLocations = new Array(); + __glslSamplerDefaults = new Array(); + __glslSamplerNames = new Array(); + __glslAttribLocations = new Array(); + __glslAttribNames = new Array(); + __glslAttribTypes = new Array(); + __glslAttribSizes = new Array(); + __glslUniformLocations = new Array(); + __glslUniformDefaults = new Array(); + __glslUniformNames = new Array(); + __glslUniformTypes = new Array(); + __glslUniformSizes = new Array(); + #end } @:noCompletion private function __disable():Void @@ -757,76 +395,110 @@ import lime.utils.BytePointer; } } - @:noCompletion private function __processGLSLData(source:String, storageType:String):Void + @:noCompletion private function __buildAGALUniformList():Void { - var lastMatch = 0, position, regex, name, type; + if (__format == GLSL) return; - if (storageType == "uniform") - { - regex = ~/uniform ([A-Za-z0-9]+) ([A-Za-z0-9_]+)/; - } - else - { - regex = ~/attribute ([A-Za-z0-9]+) ([A-Za-z0-9_]+)/; - } + #if lime + var gl = __context.gl; + + __agalUniforms.clear(); + __agalSamplerUniforms.clear(); + __agalAlphaSamplerUniforms.clear(); + __agalAlphaSamplerEnabled = []; + + __agalSamplerUsageMask = 0; + + var numActive = 0; + numActive = gl.getProgramParameter(__glProgram, gl.ACTIVE_UNIFORMS); + + var vertexUniforms = new List(); + var fragmentUniforms = new List(); - while (regex.matchSub(source, lastMatch)) + for (i in 0...numActive) { - type = regex.matched(1); - name = regex.matched(2); + var info = gl.getActiveUniform(__glProgram, i); + var name = info.name; + var size = info.size; + var uniformType = info.type; - if (StringTools.startsWith(name, "gl_")) + var uniform = new Uniform(__context); + uniform.name = name; + uniform.size = size; + uniform.type = uniformType; + + uniform.location = gl.getUniformLocation(__glProgram, uniform.name); + + var indexBracket = uniform.name.indexOf("["); + + if (indexBracket >= 0) { - continue; + uniform.name = uniform.name.substring(0, indexBracket); + } + + switch (uniform.type) + { + case GL.FLOAT_MAT2: + uniform.regCount = 2; + case GL.FLOAT_MAT3: + uniform.regCount = 3; + case GL.FLOAT_MAT4: + uniform.regCount = 4; + default: + uniform.regCount = 1; } - if (StringTools.startsWith(type, "sampler")) + uniform.regCount *= uniform.size; + + __agalUniforms.add(uniform); + + if (uniform.name == "vcPositionScale") { - __glslSamplerNames.push(name); + __agalPositionScale = uniform; } - else + else if (StringTools.startsWith(uniform.name, "vc")) { - var parameterType:ShaderParameterType = switch (type) - { - case "bool": BOOL; - case "double", "float": FLOAT; - case "int", "uint": INT; - case "bvec2": BOOL2; - case "bvec3": BOOL3; - case "bvec4": BOOL4; - case "ivec2", "uvec2": INT2; - case "ivec3", "uvec3": INT3; - case "ivec4", "uvec4": INT4; - case "vec2", "dvec2": FLOAT2; - case "vec3", "dvec3": FLOAT3; - case "vec4", "dvec4": FLOAT4; - case "mat2", "mat2x2": MATRIX2X2; - case "mat2x3": MATRIX2X3; - case "mat2x4": MATRIX2X4; - case "mat3x2": MATRIX3X2; - case "mat3", "mat3x3": MATRIX3X3; - case "mat3x4": MATRIX3X4; - case "mat4x2": MATRIX4X2; - case "mat4x3": MATRIX4X3; - case "mat4", "mat4x4": MATRIX4X4; - default: null; - } + uniform.regIndex = Std.parseInt(uniform.name.substring(2)); + uniform.regData = __context.__vertexConstants; + vertexUniforms.add(uniform); + } + else if (StringTools.startsWith(uniform.name, "fc")) + { + uniform.regIndex = Std.parseInt(uniform.name.substring(2)); + uniform.regData = __context.__fragmentConstants; + fragmentUniforms.add(uniform); + } + else if (StringTools.startsWith(uniform.name, "sampler") && uniform.name.indexOf("alpha") == -1) + { + uniform.regIndex = Std.parseInt(uniform.name.substring(7)); + __agalSamplerUniforms.add(uniform); - if (storageType == "uniform") - { - __glslUniformNames.push(name); - __glslUniformTypes.push(parameterType); - } - else + for (reg in 0...uniform.regCount) { - __glslAttribNames.push(name); - __glslAttribTypes.push(parameterType); + __agalSamplerUsageMask |= (1 << (uniform.regIndex + reg)); } } + else if (StringTools.startsWith(uniform.name, "sampler") && StringTools.endsWith(uniform.name, "_alpha")) + { + var len = uniform.name.indexOf("_") - 7; + uniform.regIndex = Std.parseInt(uniform.name.substring(7, 7 + len)) + 4; + __agalAlphaSamplerUniforms.add(uniform); + } + else if (StringTools.startsWith(uniform.name, "sampler") && StringTools.endsWith(uniform.name, "_alphaEnabled")) + { + uniform.regIndex = Std.parseInt(uniform.name.substring(7)); + __agalAlphaSamplerEnabled[uniform.regIndex] = uniform; + } - position = regex.matchedPos(); - lastMatch = position.pos + position.len; + if (Log.level == LogLevel.VERBOSE) + { + Log.verbose('${i} name:${uniform.name} type:${uniform.type} size:${uniform.size} location:${uniform.location}'); + } } + + __agalVertexUniformMap = new UniformMap(Lambda.array(vertexUniforms)); + __agalFragmentUniformMap = new UniformMap(Lambda.array(fragmentUniforms)); + #end } @:noCompletion private function __setPositionScale(positionScale:Float32Array):Void @@ -845,39 +517,67 @@ import lime.utils.BytePointer; __samplerStates[sampler] = state; } - @:noCompletion private function __uploadFromGLSL(vertexShaderSource:String, fragmentShaderSource:String):Void + @:noCompletion private function __createGLSLShader(source:String, type:Int):GLShader { var gl = __context.gl; - __glVertexSource = vertexShaderSource; - __glFragmentSource = fragmentShaderSource; + var glShader = gl.createShader(type); + gl.shaderSource(glShader, source); + gl.compileShader(glShader); - __glVertexShader = gl.createShader(gl.VERTEX_SHADER); - gl.shaderSource(__glVertexShader, vertexShaderSource); - gl.compileShader(__glVertexShader); + var shaderInfoLog = gl.getShaderInfoLog(glShader); + var hasInfoLog = shaderInfoLog != null && StringTools.trim(shaderInfoLog) != ""; + var isError = gl.getShaderParameter(glShader, gl.COMPILE_STATUS) == 0; - if (gl.getShaderParameter(__glVertexShader, gl.COMPILE_STATUS) == 0) + if (isError) { - var message = "Error compiling vertex shader"; - message += "\n" + gl.getShaderInfoLog(__glVertexShader); - message += "\n" + vertexShaderSource; - Log.error(message); + var message = "Error" + ((type == gl.VERTEX_SHADER) ? " compiling vertex shader" : " compiling fragment shader"); + message += "\n" + shaderInfoLog; + message += "\n" + source; + Log.info(message); } - - __glFragmentShader = gl.createShader(gl.FRAGMENT_SHADER); - gl.shaderSource(__glFragmentShader, fragmentShaderSource); - gl.compileShader(__glFragmentShader); - - if (gl.getShaderParameter(__glFragmentShader, gl.COMPILE_STATUS) == 0) + else if (hasInfoLog) { - var message = "Error compiling fragment shader"; - message += "\n" + gl.getShaderInfoLog(__glFragmentShader); - message += "\n" + fragmentShaderSource; - Log.error(message); + __logGLShaderInfo(isError, type, shaderInfoLog, source); + /* + var message = isError ? "Error" : "Info"; + message += (type == gl.VERTEX_SHADER) ? " compiling vertex shader" : " compiling fragment shader"; + message += "\n" + shaderInfoLog; + message += "\n" + source; + if (isError) Log.info(message);//Log.error(message); + else if (hasInfoLog) Log.info(message); + */ } + return glShader; + } + + @:noCompletion private function __uploadFromGLSL(vertexShaderSource:String, fragmentShaderSource:String):Void + { + var gl = __context.gl; + + __glVertexVersion = GLSLSourceAssembler.getVersionFromSource(__glVertexSource = vertexShaderSource); + __glFragmentVersion = GLSLSourceAssembler.getVersionFromSource(__glFragmentSource = fragmentShaderSource); + + vertexShaderSource = Shader.processGLSLParameter(vertexShaderSource, "attribute", __processGLSLParameterCallback); + vertexShaderSource = Shader.processGLSLParameter(vertexShaderSource, "in", __processGLSLParameterCallback); + vertexShaderSource = Shader.processGLSLParameter(vertexShaderSource, "uniform", __processGLSLParameterCallback); + fragmentShaderSource = Shader.processGLSLParameter(fragmentShaderSource, "uniform", __processGLSLParameterCallback); + + __glVertexShader = __createGLSLShader(vertexShaderSource, gl.VERTEX_SHADER); + __glFragmentShader = __createGLSLShader(fragmentShaderSource, gl.FRAGMENT_SHADER); __glProgram = gl.createProgram(); + gl.attachShader(__glProgram, __glVertexShader); + gl.attachShader(__glProgram, __glFragmentShader); + gl.linkProgram(__glProgram); + + if (gl.getProgramParameter(__glProgram, gl.LINK_STATUS) == 0) + { + Log.info("Unable to initialize the shader program\n" + gl.getProgramInfoLog(__glProgram)); + return; + } + if (__format == AGAL) { // TODO: AGAL version specific number of attributes? @@ -895,30 +595,213 @@ import lime.utils.BytePointer; } else { - // Fix support for drivers that don't draw if attribute 0 is disabled - for (name in __glslAttribNames) + // Fix support for drivers that don't draw if attribute 0 is disabled (just mainly for openfl old filter shaders) + if (gl.getAttribLocation(__glProgram, "openfl_Position") > 0) + { + gl.bindAttribLocation(__glProgram, 0, "openfl_Position"); + } + } + } + + @:noCompletion private function __buildGLSLParamList():Void + { + var gl = __context.gl; + var idx:Int, name:String, info; + var regexName = ~/([A-Za-z0-9_]+)(?:\[(\w+)\])?/; + + var num = gl.getProgramParameter(__glProgram, gl.ACTIVE_ATTRIBUTES); + for (i in 0...num) + { + regexName.match((info = gl.getActiveAttrib(__glProgram, i)).name); + idx = __glslAttribNames.indexOf(name = regexName.matched(1)); + if (idx == -1) + { + __glslAttribLocations.push(gl.getAttribLocation(__glProgram, info.name)); + __glslAttribNames.push(name); + __glslAttribTypes.push(Shader.getParameterTypeFromGLEnum(info.type, info.size > 1)); + __glslAttribSizes.push(info.size); + } + else { - if (name.indexOf("Position") > -1 && StringTools.startsWith(name, "openfl_")) + __glslAttribLocations[idx] = gl.getAttribLocation(__glProgram, info.name); + __glslAttribTypes[idx] = Shader.getParameterTypeFromGLEnum(info.type, info.size > 1); + __glslAttribSizes[idx] = info.size; + } + } + + var num = gl.getProgramParameter(__glProgram, gl.ACTIVE_UNIFORMS); + for (i in 0...num) + { + regexName.match((info = gl.getActiveUniform(__glProgram, i)).name); + name = regexName.matched(1); + if (info.type == gl.SAMPLER_2D || info.type == gl.SAMPLER_CUBE) + { + idx = __glslSamplerNames.indexOf(name); + if (idx == -1) { - gl.bindAttribLocation(__glProgram, 0, name); - break; + __glslSamplerLocations.push(gl.getUniformLocation(__glProgram, info.name)); + __glslSamplerDefaults.push(null); + __glslSamplerNames.push(name); + } + else + { + __glslSamplerLocations[idx] = gl.getUniformLocation(__glProgram, info.name); + } + } + else + { + idx = __glslUniformNames.indexOf(name); + if (idx == -1) + { + __glslUniformLocations.push(gl.getUniformLocation(__glProgram, info.name)); + __glslUniformDefaults.push(null); + __glslUniformNames.push(name); + __glslUniformTypes.push(Shader.getParameterTypeFromGLEnum(info.type, info.size > 1)); + __glslUniformSizes.push(info.size); + } + else + { + __glslUniformLocations[idx] = gl.getUniformLocation(__glProgram, info.name); + __glslUniformTypes[idx] = Shader.getParameterTypeFromGLEnum(info.type, info.size > 1); + __glslUniformSizes[idx] = info.size; } } } + } - gl.attachShader(__glProgram, __glVertexShader); - gl.attachShader(__glProgram, __glFragmentShader); - gl.linkProgram(__glProgram); - - if (gl.getProgramParameter(__glProgram, gl.LINK_STATUS) == 0) + @:noCompletion private function __processGLSLParameterCallback(isVertex:Bool, typeName:String, name:String, arrayLength:Int, + defaultAssign:Null):Void + { + if (isVertex) { - var message = "Unable to initialize the shader program"; - message += "\n" + gl.getProgramInfoLog(__glProgram); - Log.error(message); + if (!__glslAttribNames.contains(name)) + { + __glslAttribLocations.push(null); + __glslAttribNames.push(name); + __glslAttribTypes.push(Shader.getParameterTypeFromGLSL(typeName, arrayLength != 0)); + __glslAttribSizes.push(arrayLength == 0 ? 1 : arrayLength); + } + } + else + { + if (StringTools.startsWith(typeName, "sampler")) + { + if (!__glslAttribNames.contains(name)) + { + __glslSamplerLocations.push(null); + __glslSamplerDefaults.push(defaultAssign); + __glslSamplerNames.push(name); + } + } + else + { + if (!__glslUniformNames.contains(name)) + { + __glslUniformLocations.push(null); + __glslUniformDefaults.push(defaultAssign); + __glslUniformNames.push(name); + __glslUniformTypes.push(Shader.getParameterTypeFromGLSL(typeName, arrayLength != 0)); + __glslUniformSizes.push(arrayLength == 0 ? 1 : arrayLength); + } + } } } + + /** + * Retrieves the line number from a shader log line. + */ + #if windows + // 0(5) : whatever + @:noCompletion private var __lineExtractor = ~/^\d+\((\d+)\) : (.+$)/; + #else // (html5 || macos || linux) + // ERROR: 0:5:whatever + @:noCompletion private var __lineExtractor = ~/^\w+?: \d+:(\d+):(.+$)/; + #end + + /** + * Searches for strings that have only whitespace. + * + * **Note:** Searching for all whitespace via `~/^\s*$/` caused false-negatives, + * notably: `String.fromCharCode(0)` is `false` but `\W` is `true`. + */ + @:noCompletion private var __isEmptyLine = ~/^\W*$/; + + @:noCompletion private function __logGLShaderInfo(isError:Bool, type:Int, infoLog:String, source:String):Void { + var message = ""; + var lines = source.split("\n"); + var failingLine:String = null; + for (log in infoLog.split("\n")) { + // ignore empty lines + if (__isEmptyLine.match(log)) + continue; + + // look for a line number + if (!__lineExtractor.match(log)) { + // Could not find expected info, abort pretty formatting + failingLine = log; + break; + } + + var lineNumberStr = __lineExtractor.matched(1); + var lineNumber = Std.parseInt(lineNumberStr); + var info = __lineExtractor.matched(2); + if (lineNumber >= lines.length) { + // EOF errors will not have a valid line + message += '\n\n $lineNumber | $info'; + } else { + // Add the relevant line to each log + var line = lines[lineNumber - 1]; + var indent = StringTools.lpad("|", " ", lineNumberStr.length + 3); + #if haxe4 + var pos = getSourcePos(lines, lineNumber - 1); + message += '\n\n${pos.file}:${pos.lineNumber}\n ${pos.lineNumber} | $line\n$indent ${info}'; + #else + message += '\n\n $lineNumber | $line\n$indent ${info}'; + #end + } + } + + // If we couldn't parse the logs, output the old, verbose format + if (failingLine != null) + message = '\nFailed to simplify log:"$failingLine"\n$infoLog\n$source'; + + var typeName = (type == __context.gl.VERTEX_SHADER) ? "vertex" : "fragment"; + if (isError) { + Log.error('Error compiling $typeName shader $message'); + } else + Log.debug('Info compiling $typeName shader $message'); + } + + function getSourcePos(lines:Array, lineNumber:Int):{file:String, lineNumber:Int} { + var nests = 0; + var i = lineNumber; + var linesBack = 0; + while (i-- > 0) { + if (lines[i].indexOf("openfl_endregion") != -1) + nests++; + + if (nests == 0) + linesBack++; + + if (lines[i].indexOf("openfl_region") != -1) { + if (nests == 0) + break; + nests--; + } + } + + var sourceData = lines[i].split("// { openfl_region ")[1].split(":"); + return { + file: sourceData[0], + lineNumber: Std.parseInt(sourceData[1]) + linesBack - 1 + }; + } } +#if !openfl_debug +@:fileXml('tags="haxe,release"') +@:noDebug +#end @:access(openfl.display3D.Context3D) @SuppressWarnings("checkstyle:FieldDocComment") @:dox(hide) @:noCompletion class Uniform @@ -1013,6 +896,10 @@ import lime.utils.BytePointer; #end } +#if !openfl_debug +@:fileXml('tags="haxe,release"') +@:noDebug +#end @SuppressWarnings("checkstyle:FieldDocComment") @:dox(hide) @:noCompletion class UniformMap { @@ -1042,8 +929,9 @@ import lime.utils.BytePointer; } __registerLookup = []; - + #if haxe4 __registerLookup.resize(total); + #end for (uniform in __uniforms) { diff --git a/src/openfl/display3D/VertexBuffer3D.hx b/src/openfl/display3D/VertexBuffer3D.hx index 9a1ad5aac9..5df3f7adad 100644 --- a/src/openfl/display3D/VertexBuffer3D.hx +++ b/src/openfl/display3D/VertexBuffer3D.hx @@ -48,7 +48,7 @@ class VertexBuffer3D { @:noCompletion private var __context:Context3D; @:noCompletion private var __id:GLBuffer; - @:noCompletion private var __memoryUsage:Int = -1; + @:noCompletion private var __memoryUsage:Int; @:noCompletion private var __numVertices:Int; @:noCompletion private var __stride:Int; @:noCompletion private var __tempFloat32Array:Float32Array; @@ -76,6 +76,8 @@ class VertexBuffer3D { var gl = __context.gl; gl.deleteBuffer(__id); + __id = null; + __memoryUsage = 0; } /** @@ -123,9 +125,15 @@ class VertexBuffer3D var gl = __context.gl; __context.__bindGLArrayBuffer(__id); - if (__memoryUsage == data.byteLength) gl.bufferSubData(gl.ARRAY_BUFFER, 0, data); + + if (__memoryUsage == data.byteLength) + { + gl.bufferSubData(gl.ARRAY_BUFFER, 0, data); + } else + { gl.bufferData(gl.ARRAY_BUFFER, data, __usage); + } __memoryUsage = data.byteLength; } diff --git a/src/openfl/filters/BlurFilter.hx b/src/openfl/filters/BlurFilter.hx index c169f3872c..7087271e56 100644 --- a/src/openfl/filters/BlurFilter.hx +++ b/src/openfl/filters/BlurFilter.hx @@ -65,7 +65,12 @@ import lime._internal.graphics.ImageDataUtil; // TODO @:access(openfl.geom.Rectangle) @:final class BlurFilter extends BitmapFilter { - @:noCompletion private static var __blurShader:BlurShader = new BlurShader(); + @:noCompletion private static var __blurShader:BlurShader; + @:noCompletion private static inline function __getShader():BlurShader + { + if (__blurShader == null) __blurShader = new BlurShader(); + return __blurShader; + } /** The amount of horizontal blur. Valid values are from 0 to 255(floating @@ -170,22 +175,24 @@ import lime._internal.graphics.ImageDataUtil; // TODO @:noCompletion private override function __initShader(renderer:DisplayObjectRenderer, pass:Int, sourceBitmapData:BitmapData):Shader { + var shader = __getShader(); + #if !macro if (pass < __horizontalPasses) { var scale = Math.pow(0.5, pass >> 1); - __blurShader.uRadius.value[0] = blurX * scale; - __blurShader.uRadius.value[1] = 0; + shader.uRadius.value[0] = blurX * scale; + shader.uRadius.value[1] = 0; } else { var scale = Math.pow(0.5, (pass - __horizontalPasses) >> 1); - __blurShader.uRadius.value[0] = 0; - __blurShader.uRadius.value[1] = blurY * scale; + shader.uRadius.value[0] = 0; + shader.uRadius.value[1] = blurY * scale; } #end - return __blurShader; + return shader; } @:noCompletion inline function __padFor(value:Float):Int diff --git a/src/openfl/filters/ColorMatrixFilter.hx b/src/openfl/filters/ColorMatrixFilter.hx index bea3fdf496..93fcb79d4c 100644 --- a/src/openfl/filters/ColorMatrixFilter.hx +++ b/src/openfl/filters/ColorMatrixFilter.hx @@ -55,7 +55,12 @@ import lime.math.RGBA; **/ @:final class ColorMatrixFilter extends BitmapFilter { - @:noCompletion private static var __colorMatrixShader:ColorMatrixShader = new ColorMatrixShader(); + @:noCompletion private static var __colorMatrixShader:ColorMatrixShader; + @:noCompletion private static inline function __getShader():ColorMatrixShader + { + if (__colorMatrixShader == null) __colorMatrixShader = new ColorMatrixShader(); + return __colorMatrixShader; + } /** An array of 20 items for 4 x 5 color transform. The `matrix` property @@ -206,8 +211,9 @@ import lime.math.RGBA; @:noCompletion private override function __initShader(renderer:DisplayObjectRenderer, pass:Int, sourceBitmapData:BitmapData):Shader { - __colorMatrixShader.init(matrix); - return __colorMatrixShader; + var shader = __getShader(); + shader.init(matrix); + return shader; } // Get & Set Methods diff --git a/src/openfl/filters/ConvolutionFilter.hx b/src/openfl/filters/ConvolutionFilter.hx index 040ca1fa66..7f2e68cd1c 100644 --- a/src/openfl/filters/ConvolutionFilter.hx +++ b/src/openfl/filters/ConvolutionFilter.hx @@ -44,7 +44,7 @@ import openfl.display.Shader; **/ class ConvolutionFilter extends BitmapFilter { - @:noCompletion private static var __convolutionShader:ConvolutionShader = new ConvolutionShader(); + @:noCompletion private var __convolutionShader:ConvolutionShader = new ConvolutionShader(); /** The alpha transparency value of the substitute color. Valid values are diff --git a/src/openfl/filters/DisplacementMapFilter.hx b/src/openfl/filters/DisplacementMapFilter.hx index 9dcb42cf0c..a7f297efcf 100644 --- a/src/openfl/filters/DisplacementMapFilter.hx +++ b/src/openfl/filters/DisplacementMapFilter.hx @@ -61,7 +61,13 @@ import lime.math.Vector4; @:access(openfl.geom.Rectangle) @:final class DisplacementMapFilter extends BitmapFilter { - @:noCompletion private static var __displacementMapShader:DisplacementMapShader = new DisplacementMapShader(); + @:noCompletion private static var __displacementMapShader:DisplacementMapShader; + @:noCompletion private static inline function __getShader():DisplacementMapShader + { + if (__displacementMapShader == null) __displacementMapShader = new DisplacementMapShader(); + return __displacementMapShader; + } + private static var __matrixData:Array = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]; private static var __offset:Array = [0.5, 0.5, 0.0, 0.0]; @@ -239,20 +245,22 @@ import lime.math.Vector4; @:noCompletion private override function __initShader(renderer:DisplayObjectRenderer, pass:Int, sourceBitmapData:BitmapData):Shader { + var shader = __getShader(); + #if !macro // TODO: mapX/mapY/mapU/mapV + offsets __updateMapMatrix(); - __displacementMapShader.uOffsets.value = __offset; - __displacementMapShader.uDisplacements.value = __matrixData; + shader.uOffsets.value = __offset; + shader.uDisplacements.value = __matrixData; - __displacementMapShader.mapTextureCoordsOffset.value = [mapPoint.x / __mapBitmap.width, mapPoint.y / __mapBitmap.height]; + shader.mapTextureCoordsOffset.value = [mapPoint.x / __mapBitmap.width, mapPoint.y / __mapBitmap.height]; - __displacementMapShader.mapTexture.input = __mapBitmap; + shader.mapTexture.input = __mapBitmap; #end - return __displacementMapShader; + return shader; } @:noCompletion private function __updateMapMatrix():Void diff --git a/src/openfl/filters/DropShadowFilter.hx b/src/openfl/filters/DropShadowFilter.hx index 948f735806..e2ff298aa8 100644 --- a/src/openfl/filters/DropShadowFilter.hx +++ b/src/openfl/filters/DropShadowFilter.hx @@ -63,7 +63,12 @@ import lime._internal.graphics.ImageDataUtil; // TODO @:access(openfl.geom.Rectangle) @:final class DropShadowFilter extends BitmapFilter { - @:noCompletion private static var __hideShader = new HideShader(); + @:noCompletion private static var __hideShader:HideShader; + @:noCompletion private static inline function __getHideShader():HideShader + { + if (__hideShader == null) __hideShader = new HideShader(); + return __hideShader; + } /** The alpha transparency value for the shadow color. Valid values are 0.0 to @@ -260,7 +265,7 @@ import lime._internal.graphics.ImageDataUtil; // TODO // Drop shadow is glow with an offset if (__inner && pass == 0) { - return GlowFilter.__invertAlphaShader; + return GlowFilter.__getInvertAlphaShader(); } var blurPass = pass - (__inner ? 1 : 0); @@ -268,7 +273,7 @@ import lime._internal.graphics.ImageDataUtil; // TODO if (blurPass < numBlurPasses) { - var shader = GlowFilter.__blurAlphaShader; + var shader = GlowFilter.__getBlurAlphaShader(); if (blurPass < __horizontalPasses) { var scale = Math.pow(0.5, blurPass >> 1) * 0.5; @@ -292,13 +297,13 @@ import lime._internal.graphics.ImageDataUtil; // TODO { if (__knockout || __hideObject) { - var shader = GlowFilter.__innerCombineKnockoutShader; + var shader = GlowFilter.__getInnerCombineKnockoutShader(); shader.sourceBitmap.input = sourceBitmapData; shader.offset.value[0] = __offsetX; shader.offset.value[1] = __offsetY; return shader; } - var shader = GlowFilter.__innerCombineShader; + var shader = GlowFilter.__getInnerCombineShader(); shader.sourceBitmap.input = sourceBitmapData; shader.offset.value[0] = __offsetX; shader.offset.value[1] = __offsetY; @@ -308,7 +313,7 @@ import lime._internal.graphics.ImageDataUtil; // TODO { if (__knockout) { - var shader = GlowFilter.__combineKnockoutShader; + var shader = GlowFilter.__getCombineKnockoutShader(); shader.sourceBitmap.input = sourceBitmapData; shader.offset.value[0] = __offsetX; shader.offset.value[1] = __offsetY; @@ -316,13 +321,13 @@ import lime._internal.graphics.ImageDataUtil; // TODO } else if (__hideObject) { - var shader = __hideShader; + var shader = __getHideShader(); shader.sourceBitmap.input = sourceBitmapData; shader.offset.value[0] = __offsetX; shader.offset.value[1] = __offsetY; return shader; } - var shader = GlowFilter.__combineShader; + var shader = GlowFilter.__getCombineShader(); shader.sourceBitmap.input = sourceBitmapData; shader.offset.value[0] = __offsetX; shader.offset.value[1] = __offsetY; diff --git a/src/openfl/filters/GlowFilter.hx b/src/openfl/filters/GlowFilter.hx index d040ea7c2f..eec79c10b0 100644 --- a/src/openfl/filters/GlowFilter.hx +++ b/src/openfl/filters/GlowFilter.hx @@ -63,12 +63,48 @@ import lime._internal.graphics.ImageDataUtil; // TODO @:access(openfl.geom.Rectangle) @:final class GlowFilter extends BitmapFilter { - @:noCompletion private static var __invertAlphaShader = new InvertAlphaShader(); - @:noCompletion private static var __blurAlphaShader = new BlurAlphaShader(); - @:noCompletion private static var __combineShader = new CombineShader(); - @:noCompletion private static var __innerCombineShader = new InnerCombineShader(); - @:noCompletion private static var __combineKnockoutShader = new CombineKnockoutShader(); - @:noCompletion private static var __innerCombineKnockoutShader = new InnerCombineKnockoutShader(); + @:noCompletion private static var __invertAlphaShader:InvertAlphaShader; + @:noCompletion private static inline function __getInvertAlphaShader():InvertAlphaShader + { + if (__invertAlphaShader == null) __invertAlphaShader = new InvertAlphaShader(); + return __invertAlphaShader; + } + + @:noCompletion private static var __blurAlphaShader:BlurAlphaShader; + @:noCompletion private static inline function __getBlurAlphaShader():BlurAlphaShader + { + if (__blurAlphaShader == null) __blurAlphaShader = new BlurAlphaShader(); + return __blurAlphaShader; + } + + @:noCompletion private static var __combineShader:CombineShader; + @:noCompletion private static inline function __getCombineShader():CombineShader + { + if (__combineShader == null) __combineShader = new CombineShader(); + return __combineShader; + } + + @:noCompletion private static var __innerCombineShader:InnerCombineShader; + @:noCompletion private static inline function __getInnerCombineShader():InnerCombineShader + { + if (__innerCombineShader == null) __innerCombineShader = new InnerCombineShader(); + return __innerCombineShader; + } + + @:noCompletion private static var __combineKnockoutShader:CombineKnockoutShader; + @:noCompletion private static inline function __getCombineKnockoutShader():CombineKnockoutShader + { + if (__combineKnockoutShader == null) __combineKnockoutShader = new CombineKnockoutShader(); + return __combineKnockoutShader; + } + + @:noCompletion private static var __innerCombineKnockoutShader:InnerCombineKnockoutShader; + @:noCompletion private static inline function __getInnerCombineKnockoutShader():InnerCombineKnockoutShader + { + if (__innerCombineKnockoutShader == null) __innerCombineKnockoutShader = new InnerCombineKnockoutShader(); + return __innerCombineKnockoutShader; + } + /** The alpha transparency value for the color. Valid values are 0 to 1. For @@ -234,7 +270,7 @@ import lime._internal.graphics.ImageDataUtil; // TODO // First pass of inner glow is invert alpha if (__inner && pass == 0) { - return __invertAlphaShader; + return __getInvertAlphaShader(); } var blurPass = pass - (__inner ? 1 : 0); @@ -242,7 +278,7 @@ import lime._internal.graphics.ImageDataUtil; // TODO if (blurPass < numBlurPasses) { - var shader = __blurAlphaShader; + var shader = __getBlurAlphaShader(); if (blurPass < __horizontalPasses) { var scale = Math.pow(0.5, blurPass >> 1) * 0.5; @@ -266,13 +302,13 @@ import lime._internal.graphics.ImageDataUtil; // TODO { if (__knockout) { - var shader = __innerCombineKnockoutShader; + var shader = __getInnerCombineKnockoutShader(); shader.sourceBitmap.input = sourceBitmapData; shader.offset.value[0] = 0.0; shader.offset.value[1] = 0.0; return shader; } - var shader = __innerCombineShader; + var shader = __getInnerCombineShader(); shader.sourceBitmap.input = sourceBitmapData; shader.offset.value[0] = 0.0; shader.offset.value[1] = 0.0; @@ -282,13 +318,13 @@ import lime._internal.graphics.ImageDataUtil; // TODO { if (__knockout) { - var shader = __combineKnockoutShader; + var shader = __getCombineKnockoutShader(); shader.sourceBitmap.input = sourceBitmapData; shader.offset.value[0] = 0.0; shader.offset.value[1] = 0.0; return shader; } - var shader = __combineShader; + var shader = __getCombineShader(); shader.sourceBitmap.input = sourceBitmapData; shader.offset.value[0] = 0.0; shader.offset.value[1] = 0.0; diff --git a/src/openfl/geom/Matrix3D.hx b/src/openfl/geom/Matrix3D.hx index 846d220627..106917dcac 100644 --- a/src/openfl/geom/Matrix3D.hx +++ b/src/openfl/geom/Matrix3D.hx @@ -48,6 +48,9 @@ import openfl.Vector; **/ class Matrix3D { + private static final __tempMatrix3D:Matrix3D = new Matrix3D(); + private static final __tempVector3D:Vector3D = new Vector3D(); + /** A Number that determines whether a matrix is invertible. @@ -102,7 +105,7 @@ class Matrix3D **/ public function append(lhs:Matrix3D):Void { - var m111:Float = this.rawData[0], + final m111:Float = this.rawData[0], m121:Float = this.rawData[4], m131:Float = this.rawData[8], m141:Float = this.rawData[12], @@ -209,28 +212,18 @@ class Matrix3D **/ public function appendRotation(degrees:Float, axis:Vector3D, pivotPoint:Vector3D = null):Void { - var tx:Float, ty:Float, tz:Float; - tx = ty = tz = 0; - - if (pivotPoint != null) - { - tx = pivotPoint.x; - ty = pivotPoint.y; - tz = pivotPoint.z; - } - var radian = degrees * Math.PI / 180; - var cos = Math.cos(radian); - var sin = Math.sin(radian); + final tx = pivotPoint?.x ?? 0, ty = pivotPoint?.y ?? 0, tz = pivotPoint?.z ?? 0, radian = degrees * Math.PI / 180; + final cos = Math.cos(radian), sin = Math.sin(radian); var x = axis.x; var y = axis.y; var z = axis.z; var x2 = x * x; var y2 = y * y; var z2 = z * z; - var ls = x2 + y2 + z2; + final ls = x2 + y2 + z2; if (ls != 0) { - var l = Math.sqrt(ls); + final l = Math.sqrt(ls); x /= l; y /= l; z /= l; @@ -238,9 +231,8 @@ class Matrix3D y2 /= ls; z2 /= ls; } - var ccos = 1 - cos; - var m = new Matrix3D(); - var d = m.rawData; + final ccos = 1 - cos; + final d = __tempMatrix3D.rawData; d[0] = x2 + (y2 + z2) * cos; d[1] = x * y * ccos + z * sin; d[2] = x * z * ccos - y * sin; @@ -253,7 +245,8 @@ class Matrix3D d[12] = (tx * (y2 + z2) - x * (ty * y + tz * z)) * ccos + (ty * z - tz * y) * sin; d[13] = (ty * (x2 + z2) - y * (tx * x + tz * z)) * ccos + (tz * x - tx * z) * sin; d[14] = (tz * (x2 + y2) - z * (tx * x + ty * y)) * ccos + (tx * y - ty * x) * sin; - this.append(m); + d[15] = 1; + this.append(__tempMatrix3D); } /** @@ -283,11 +276,13 @@ class Matrix3D @param yScale A multiplier used to scale the object along the y axis. @param zScale A multiplier used to scale the object along the z axis. **/ - public function appendScale(xScale:Float, yScale:Float, zScale:Float):Void + public inline function appendScale(xScale:Float, yScale:Float, zScale:Float):Void { - this.append(new Matrix3D(new Vector([ - xScale, 0.0, 0.0, 0.0, 0.0, yScale, 0.0, 0.0, 0.0, 0.0, zScale, 0.0, 0.0, 0.0, 0.0, 1.0 - ]))); + __tempMatrix3D.identity(); + __tempMatrix3D.rawData[0] = xScale; + __tempMatrix3D.rawData[5] = yScale; + __tempMatrix3D.rawData[10] = zScale; + this.append(__tempMatrix3D); } /** @@ -313,7 +308,7 @@ class Matrix3D @param y An incremental translation along the y axis. @param z An incremental translation along the z axis. **/ - public function appendTranslation(x:Float, y:Float, z:Float):Void + public inline function appendTranslation(x:Float, y:Float, z:Float):Void { rawData[12] += x; rawData[13] += y; @@ -413,9 +408,24 @@ class Matrix3D @param sourceMatrix3D The Matrix3D object from which to copy the data. **/ - public function copyFrom(other:Matrix3D):Void + public inline function copyFrom(other:Matrix3D):Void { - rawData = other.rawData.copy(); + rawData[0] = other.rawData[0]; + rawData[1] = other.rawData[1]; + rawData[2] = other.rawData[2]; + rawData[3] = other.rawData[3]; + rawData[4] = other.rawData[4]; + rawData[5] = other.rawData[5]; + rawData[6] = other.rawData[6]; + rawData[7] = other.rawData[7]; + rawData[8] = other.rawData[8]; + rawData[9] = other.rawData[9]; + rawData[10] = other.rawData[10]; + rawData[11] = other.rawData[11]; + rawData[12] = other.rawData[12]; + rawData[13] = other.rawData[13]; + rawData[14] = other.rawData[14]; + rawData[15] = other.rawData[15]; } /** @@ -429,22 +439,12 @@ class Matrix3D **/ public function copyRawDataFrom(vector:Vector, index:UInt = 0, transpose:Bool = false):Void { - if (transpose) - { - this.transpose(); - } - - var length = vector.length - index; + if (transpose) this.transpose(); - for (i in 0...length) - { - rawData[i] = vector[i + index]; - } + final length = vector.length - index; + for (i in 0...length) rawData[i] = vector[i + index]; - if (transpose) - { - this.transpose(); - } + if (transpose) this.transpose(); } /** @@ -458,20 +458,11 @@ class Matrix3D **/ public function copyRawDataTo(vector:Vector, index:UInt = 0, transpose:Bool = false):Void { - if (transpose) - { - this.transpose(); - } + if (transpose) this.transpose(); - for (i in 0...rawData.length) - { - vector[i + index] = rawData[i]; - } + for (i in 0...rawData.length) vector[i + index] = rawData[i]; - if (transpose) - { - this.transpose(); - } + if (transpose) this.transpose(); } /** @@ -555,16 +546,29 @@ class Matrix3D **/ public function copyToMatrix3D(other:Matrix3D):Void { - other.rawData = rawData.copy(); + other.rawData[0] = rawData[0]; + other.rawData[1] = rawData[1]; + other.rawData[2] = rawData[2]; + other.rawData[3] = rawData[3]; + other.rawData[4] = rawData[4]; + other.rawData[5] = rawData[5]; + other.rawData[6] = rawData[6]; + other.rawData[7] = rawData[7]; + other.rawData[8] = rawData[8]; + other.rawData[9] = rawData[9]; + other.rawData[10] = rawData[10]; + other.rawData[11] = rawData[11]; + other.rawData[12] = rawData[12]; + other.rawData[13] = rawData[13]; + other.rawData[14] = rawData[14]; + other.rawData[15] = rawData[15]; } @SuppressWarnings("checkstyle:FieldDocComment") @:dox(hide) @:noCompletion public static function create2D(x:Float, y:Float, scale:Float = 1, rotation:Float = 0):Matrix3D { - var theta = rotation * Math.PI / 180.0; - var c = Math.cos(theta); - var s = Math.sin(theta); - + final theta = rotation * Math.PI / 180.0; + final c = Math.cos(theta), s = Math.sin(theta); return new Matrix3D(new Vector([c * scale, -s * scale, 0, 0, s * scale, c * scale, 0, 0, 0, 0, 1, 0, x, y, 0, 1])); } @@ -577,27 +581,9 @@ class Matrix3D @SuppressWarnings("checkstyle:FieldDocComment") @:dox(hide) @:noCompletion public static function createOrtho(x0:Float, x1:Float, y0:Float, y1:Float, zNear:Float, zFar:Float):Matrix3D { - var sx = 1.0 / (x1 - x0); - var sy = 1.0 / (y1 - y0); - var sz = 1.0 / (zFar - zNear); - + final sx = 1.0 / (x1 - x0), sy = 1.0 / (y1 - y0), sz = 1.0 / (zFar - zNear); return new Matrix3D(new Vector([ - 2.0 * sx, - 0, - 0, - 0, - 0, - 2.0 * sy, - 0, - 0, - 0, - 0, - -2.0 * sz, - 0, - -(x0 + x1) * sx, - -(y0 + y1) * sy, - -(zNear + zFar) * sz, - 1 + 2.0 * sx, 0, 0, 0, 0, 2.0 * sy, 0, 0, 0, 0, -2.0 * sz, 0, -(x0 + x1) * sx, -(y0 + y1) * sy, -(zNear + zFar) * sz, 1 ])); } @@ -944,10 +930,8 @@ class Matrix3D **/ public function deltaTransformVector(v:Vector3D):Vector3D { - var x:Float = v.x, y:Float = v.y, z:Float = v.z; - - return new Vector3D((x * rawData[0] + y * rawData[4] + z * rawData[8]), (x * rawData[1] + y * rawData[5] + z * rawData[9]), - (x * rawData[2] + y * rawData[6] + z * rawData[10]), (x * rawData[3] + y * rawData[7] + z * rawData[11])); + return new Vector3D((v.x * rawData[0] + v.y * rawData[4] + v.z * rawData[8]), (v.x * rawData[1] + v.y * rawData[5] + v.z * rawData[9]), + (v.x * rawData[2] + v.y * rawData[6] + v.z * rawData[10]), (v.x * rawData[3] + v.y * rawData[7] + v.z * rawData[11])); } /** @@ -978,17 +962,15 @@ class Matrix3D **/ public function deltaTransformVectorToOutput(v:Vector3D, output:Vector3D):Vector3D { - var x:Float = v.x, y:Float = v.y, z:Float = v.z; - if (output != null) { - output.setTo((x * rawData[0] + y * rawData[4] + z * rawData[8]), (x * rawData[1] + y * rawData[5] + z * rawData[9]), - (x * rawData[2] + y * rawData[6] + z * rawData[10])); - output.w = (x * rawData[3] + y * rawData[7] + z * rawData[11]); + output.setTo((v.x * rawData[0] + v.y * rawData[4] + v.z * rawData[8]), (v.x * rawData[1] + v.y * rawData[5] + v.z * rawData[9]), + (v.x * rawData[2] + v.y * rawData[6] + v.z * rawData[10])); + output.w = (v.x * rawData[3] + v.y * rawData[7] + v.z * rawData[11]); return output; } - return new Vector3D((x * rawData[0] + y * rawData[4] + z * rawData[8]), (x * rawData[1] + y * rawData[5] + z * rawData[9]), - (x * rawData[2] + y * rawData[6] + z * rawData[10]), (x * rawData[3] + y * rawData[7] + z * rawData[11])); + return new Vector3D((v.x * rawData[0] + v.y * rawData[4] + v.z * rawData[8]), (v.x * rawData[1] + v.y * rawData[5] + v.z * rawData[9]), + (v.x * rawData[2] + v.y * rawData[6] + v.z * rawData[10]), (v.x * rawData[3] + v.y * rawData[7] + v.z * rawData[11])); } /** @@ -1006,9 +988,24 @@ class Matrix3D In other words, if a matrix is multiplied by an identity matrix, the result is a matrix that is the same as (identical to) the original matrix. **/ - public function identity():Void + public inline function identity():Void { - rawData = new Vector([1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0]); + rawData[0] = 1; + rawData[1] = 0; + rawData[2] = 0; + rawData[3] = 0; + rawData[4] = 0; + rawData[5] = 1; + rawData[6] = 0; + rawData[7] = 0; + rawData[8] = 0; + rawData[9] = 0; + rawData[10] = 1; + rawData[11] = 0; + rawData[12] = 0; + rawData[13] = 0; + rawData[14] = 0; + rawData[15] = 1; } /** @@ -1046,13 +1043,8 @@ class Matrix3D **/ public static function interpolate(thisMat:Matrix3D, toMat:Matrix3D, percent:Float):Matrix3D { - var m = new Matrix3D(); - - for (i in 0...16) - { - m.rawData[i] = thisMat.rawData[i] + (toMat.rawData[i] - thisMat.rawData[i]) * percent; - } - + final m = new Matrix3D(); + for (i in 0...16) m.rawData[i] = thisMat.rawData[i] + (toMat.rawData[i] - thisMat.rawData[i]) * percent; return m; } @@ -1092,16 +1084,8 @@ class Matrix3D **/ public static function interpolateToOutput(thisMat:Matrix3D, toMat:Matrix3D, percent:Float, output:Matrix3D):Matrix3D { - if (output == null) - { - output = new Matrix3D(); - } - - for (i in 0...16) - { - output.rawData[i] = thisMat.rawData[i] + (toMat.rawData[i] - thisMat.rawData[i]) * percent; - } - + if (output == null) output = new Matrix3D(); + for (i in 0...16) output.rawData[i] += (toMat.rawData[i] - thisMat.rawData[i]) * percent; return output; } @@ -1139,10 +1123,7 @@ class Matrix3D **/ public function interpolateTo(toMat:Matrix3D, percent:Float):Void { - for (i in 0...16) - { - rawData[i] = rawData[i] + (toMat.rawData[i] - rawData[i]) * percent; - } + for (i in 0...16) rawData[i] += (toMat.rawData[i] - rawData[i]) * percent; } /** @@ -1174,28 +1155,25 @@ class Matrix3D public function invert():Bool { var d = determinant; - var invertable = Math.abs(d) > 0.00000000001; - - if (invertable) - { + final invertable = Math.abs(d) > 0.0000001; + if (invertable) { d = 1 / d; - - var m11:Float = rawData[0]; - var m21:Float = rawData[4]; - var m31:Float = rawData[8]; - var m41:Float = rawData[12]; - var m12:Float = rawData[1]; - var m22:Float = rawData[5]; - var m32:Float = rawData[9]; - var m42:Float = rawData[13]; - var m13:Float = rawData[2]; - var m23:Float = rawData[6]; - var m33:Float = rawData[10]; - var m43:Float = rawData[14]; - var m14:Float = rawData[3]; - var m24:Float = rawData[7]; - var m34:Float = rawData[11]; - var m44:Float = rawData[15]; + final m11:Float = rawData[0], + m21:Float = rawData[4], + m31:Float = rawData[8], + m41:Float = rawData[12], + m12:Float = rawData[1], + m22:Float = rawData[5], + m32:Float = rawData[9], + m42:Float = rawData[13], + m13:Float = rawData[2], + m23:Float = rawData[6], + m33:Float = rawData[10], + m43:Float = rawData[14], + m14:Float = rawData[3], + m24:Float = rawData[7], + m34:Float = rawData[11], + m44:Float = rawData[15]; rawData[0] = d * (m22 * (m33 * m44 - m43 * m34) - m32 * (m23 * m44 - m43 * m24) + m42 * (m23 * m34 - m33 * m24)); rawData[1] = -d * (m12 * (m33 * m44 - m43 * m34) - m32 * (m13 * m44 - m43 * m14) + m42 * (m13 * m34 - m33 * m14)); @@ -1430,7 +1408,7 @@ class Matrix3D **/ public function prepend(rhs:Matrix3D):Void { - var m111:Float = rhs.rawData[0], + final m111:Float = rhs.rawData[0], m121:Float = rhs.rawData[4], m131:Float = rhs.rawData[8], m141:Float = rhs.rawData[12], @@ -1531,27 +1509,18 @@ class Matrix3D **/ public function prependRotation(degrees:Float, axis:Vector3D, pivotPoint:Vector3D = null):Void { - var tx:Float, ty:Float, tz:Float; - tx = ty = tz = 0; - if (pivotPoint != null) - { - tx = pivotPoint.x; - ty = pivotPoint.y; - tz = pivotPoint.z; - } - var radian = degrees * Math.PI / 180; - var cos = Math.cos(radian); - var sin = Math.sin(radian); + final tx = pivotPoint?.x ?? 0, ty = pivotPoint?.y ?? 0, tz = pivotPoint?.z ?? 0, radian = degrees * Math.PI / 180; + final cos = Math.cos(radian), sin = Math.sin(radian); var x = axis.x; var y = axis.y; var z = axis.z; var x2 = x * x; var y2 = y * y; var z2 = z * z; - var ls = x2 + y2 + z2; + final ls = x2 + y2 + z2; if (ls != 0) { - var l = Math.sqrt(ls); + final l = Math.sqrt(ls); x /= l; y /= l; z /= l; @@ -1559,9 +1528,8 @@ class Matrix3D y2 /= ls; z2 /= ls; } - var ccos = 1 - cos; - var m = new Matrix3D(); - var d = m.rawData; + final ccos = 1 - cos; + final d = __tempMatrix3D.rawData; d[0] = x2 + (y2 + z2) * cos; d[1] = x * y * ccos + z * sin; d[2] = x * z * ccos - y * sin; @@ -1574,8 +1542,8 @@ class Matrix3D d[12] = (tx * (y2 + z2) - x * (ty * y + tz * z)) * ccos + (ty * z - tz * y) * sin; d[13] = (ty * (x2 + z2) - y * (tx * x + tz * z)) * ccos + (tz * x - tx * z) * sin; d[14] = (tz * (x2 + y2) - z * (tx * x + ty * y)) * ccos + (tx * y - ty * x) * sin; - - this.prepend(m); + d[15] = 1; + this.prepend(__tempMatrix3D); } /** @@ -1606,11 +1574,13 @@ class Matrix3D @param yScale A multiplier used to scale the object along the y axis. @param zScale A multiplier used to scale the object along the z axis. **/ - public function prependScale(xScale:Float, yScale:Float, zScale:Float):Void + public inline function prependScale(xScale:Float, yScale:Float, zScale:Float):Void { - this.prepend(new Matrix3D(new Vector([ - xScale, 0.0, 0.0, 0.0, 0.0, yScale, 0.0, 0.0, 0.0, 0.0, zScale, 0.0, 0.0, 0.0, 0.0, 1.0 - ]))); + __tempMatrix3D.identity(); + __tempMatrix3D.rawData[0] = xScale; + __tempMatrix3D.rawData[5] = yScale; + __tempMatrix3D.rawData[10] = zScale; + this.prepend(__tempMatrix3D); } /** @@ -1642,11 +1612,13 @@ class Matrix3D @param y An incremental translation along the y axis. @param z An incremental translation along the z axis. **/ - public function prependTranslation(x:Float, y:Float, z:Float):Void + public inline function prependTranslation(x:Float, y:Float, z:Float):Void { - var m = new Matrix3D(); - m.position = new Vector3D(x, y, z); - this.prepend(m); + __tempMatrix3D.identity(); + __tempMatrix3D.rawData[12] = x; + __tempMatrix3D.rawData[13] = y; + __tempMatrix3D.rawData[14] = z; + this.prepend(__tempMatrix3D); } /** @@ -1796,13 +1768,9 @@ class Matrix3D **/ public function transformVector(v:Vector3D):Vector3D { - var x = v.x; - var y = v.y; - var z = v.z; - - return new Vector3D((x * rawData[0] + y * rawData[4] + z * rawData[8] + rawData[12]), - (x * rawData[1] + y * rawData[5] + z * rawData[9] + rawData[13]), (x * rawData[2] + y * rawData[6] + z * rawData[10] + rawData[14]), - (x * rawData[3] + y * rawData[7] + z * rawData[11] + rawData[15])); + return new Vector3D((v.x * rawData[0] + v.y * rawData[4] + v.z * rawData[8] + rawData[12]), + (v.x * rawData[1] + v.y * rawData[5] + v.z * rawData[9] + rawData[13]), (v.x * rawData[2] + v.y * rawData[6] + v.z * rawData[10] + rawData[14]), + (v.x * rawData[3] + v.y * rawData[7] + v.z * rawData[11] + rawData[15])); } /** @@ -1826,20 +1794,16 @@ class Matrix3D **/ public function transformVectorToOutput(v:Vector3D, output:Vector3D):Vector3D { - var x = v.x; - var y = v.y; - var z = v.z; - if (output != null) { - output.setTo((x * rawData[0] + y * rawData[4] + z * rawData[8] + rawData[12]), (x * rawData[1] + y * rawData[5] + z * rawData[9] + rawData[13]), - (x * rawData[2] + y * rawData[6] + z * rawData[10] + rawData[14])); - output.w = (x * rawData[3] + y * rawData[7] + z * rawData[11] + rawData[15]); + output.setTo((v.x * rawData[0] + v.y * rawData[4] + v.z * rawData[8] + rawData[12]), (v.x * rawData[1] + v.y * rawData[5] + v.z * rawData[9] + rawData[13]), + (v.x * rawData[2] + v.y * rawData[6] + v.z * rawData[10] + rawData[14])); + output.w = (v.x * rawData[3] + v.y * rawData[7] + v.z * rawData[11] + rawData[15]); return output; } - return new Vector3D((x * rawData[0] + y * rawData[4] + z * rawData[8] + rawData[12]), - (x * rawData[1] + y * rawData[5] + z * rawData[9] + rawData[13]), (x * rawData[2] + y * rawData[6] + z * rawData[10] + rawData[14]), - (x * rawData[3] + y * rawData[7] + z * rawData[11] + rawData[15])); + return new Vector3D((v.x * rawData[0] + v.y * rawData[4] + v.z * rawData[8] + rawData[12]), + (v.x * rawData[1] + v.y * rawData[5] + v.z * rawData[9] + rawData[13]), (v.x * rawData[2] + v.y * rawData[6] + v.z * rawData[10] + rawData[14]), + (v.x * rawData[3] + v.y * rawData[7] + v.z * rawData[11] + rawData[15])); } /** @@ -1892,19 +1856,31 @@ class Matrix3D **/ public function transpose():Void { - var oRawData = rawData.copy(); - rawData[1] = oRawData[4]; - rawData[2] = oRawData[8]; - rawData[3] = oRawData[12]; - rawData[4] = oRawData[1]; - rawData[6] = oRawData[9]; - rawData[7] = oRawData[13]; - rawData[8] = oRawData[2]; - rawData[9] = oRawData[6]; - rawData[11] = oRawData[14]; - rawData[12] = oRawData[3]; - rawData[13] = oRawData[7]; - rawData[14] = oRawData[11]; + final m1 = rawData[1], + m2 = rawData[2], + m3 = rawData[3], + m4 = rawData[4], + m6 = rawData[6], + m7 = rawData[7], + m8 = rawData[8], + m9 = rawData[9], + m11 = rawData[11], + m12 = rawData[12], + m13 = rawData[13], + m14 = rawData[14]; + + rawData[1] = m4; + rawData[2] = m8; + rawData[3] = m12; + rawData[4] = m1; + rawData[6] = m9; + rawData[7] = m13; + rawData[8] = m2; + rawData[9] = m6; + rawData[11] = m14; + rawData[12] = m3; + rawData[13] = m7; + rawData[14] = m11; } @:noCompletion private static function __getAxisRotation(x:Float, y:Float, z:Float, degrees:Float):Matrix3D diff --git a/src/openfl/utils/Assets.hx b/src/openfl/utils/Assets.hx index cf9ed4c89a..64f89b410b 100644 --- a/src/openfl/utils/Assets.hx +++ b/src/openfl/utils/Assets.hx @@ -10,6 +10,7 @@ import openfl.media.Sound; import openfl.text.Font; #if lime import lime.app.Promise; +import lime.media.AudioBuffer; import lime.utils.AssetLibrary as LimeAssetLibrary; import lime.utils.Assets as LimeAssets; #end @@ -42,6 +43,9 @@ import lime.utils.Assets as LimeAssets; @:access(openfl.utils.AssetLibrary) class Assets { + public static var allowCompressedTextures:Bool = true; + public static var allowHardwareTextures:Bool = true; + public static var cache:IAssetCache = new AssetCache(); @:noCompletion private static var dispatcher:EventDispatcher #if !macro = new EventDispatcher() #end; @@ -71,8 +75,10 @@ class Assets @param allowCompressedTextures Whether to check for compressed texture formats (e.g., ASTC) when the asset is a PNG. Defaults to true. @return Whether the requested asset ID and type exists **/ - public static function exists(id:String, type:AssetType = null, allowCompressedTextures:Bool = true):Bool + public static function exists(id:String, type:AssetType = null, ?allowCompressedTextures:Null):Bool { + if (allowCompressedTextures == null) allowCompressedTextures = Assets.allowCompressedTextures; + #if lime if (allowCompressedTextures) { @@ -127,8 +133,11 @@ class Assets @see [Working with bitmap assets](https://books.openfl.org/openfl-developers-guide/working-with-bitmaps/working-with-bitmap-assets.html) **/ - public static function getBitmapData(id:String, useCache:Bool = true, allowCompressedTextures:Bool = true):BitmapData + public static function getBitmapData(id:String, useCache:Bool = true, ?allowCompressedTextures:Null, ?allowHardwareTextures:Null):BitmapData { + if (allowCompressedTextures == null) allowCompressedTextures = Assets.allowCompressedTextures; + if (allowHardwareTextures == null) allowHardwareTextures = Assets.allowHardwareTextures; + #if (lime && tools && !display) if (useCache && cache.enabled && cache.hasBitmapData(id)) { @@ -162,11 +171,46 @@ class Assets } } + #if (cpp && lime_cffi && !macro && sys) + // HTML5 does not like synchronously loads bitmap, and it already caches all of the images initially. + // So the methods to get hardware textures with cached bytes will be cpp only. + // The reason why this exists so it doesn't have to make gc in under pressure for allocating temporary bytes + // just for to make it not readable later. + if (allowHardwareTextures) + { + var bitmapData = BitmapData.fromFile(LimeAssets.getPath(id), true); + if (bitmapData == null) + { + try + { + bitmapData = BitmapData.fromBytes(LimeAssets.getBytes(id), null, true); + } + catch (e) + { + // Causes crash for some reason for casting some weird stuff in lime getBytes AssetLibrary? + } + } + + if (bitmapData != null) + { + bitmapData.__asset = true; + + if (useCache && cache.enabled) + { + cache.setBitmapData(id, bitmapData); + } + + return bitmapData; + } + } + #end + var image = LimeAssets.getImage(id, false); if (image != null) { var bitmapData = BitmapData.fromImage(image); + if (allowHardwareTextures) bitmapData.toHardware(); bitmapData.__asset = true; @@ -229,7 +273,6 @@ class Assets if (limeFont != null) { var font = new Font(); - font.__fromLimeFont(limeFont); if (useCache && cache.enabled) @@ -303,7 +346,12 @@ class Assets public static function getMusic(id:String, useCache:Bool = true):Sound { - // TODO: Streaming sound + #if (lime_funkin && lime_native) + var path = getPath(id); + var buffer = AudioBuffer.fromFile(path, true); + if (buffer != null) return Sound.fromAudioBuffer(buffer); + #end + return getSound(id, useCache); } @@ -418,7 +466,6 @@ class Assets if (libraryBindings.exists(className)) { var library = libraryBindings.get(className); - if (instance == null) { Sprite.__constructor = function(instance:Sprite) @@ -491,7 +538,7 @@ class Assets @:noCompletion private static function isValidSound(sound:Sound):Bool { - #if ((tools && !display) && (cpp || nodejs)) + #if ((tools && !display) && (cpp || neko || nodejs)) return true; // return (sound.__handle != null && sound.__handle != 0); #else @@ -526,8 +573,11 @@ class Assets @see [Working with bitmap assets](https://books.openfl.org/openfl-developers-guide/working-with-bitmaps/working-with-bitmap-assets.html) **/ - public static function loadBitmapData(id:String, useCache:Null = true):Future + public static function loadBitmapData(id:String, useCache:Null = true, ?allowCompressedTextures:Null, ?allowHardwareTextures:Null):Future { + if (allowCompressedTextures == null) allowCompressedTextures = Assets.allowCompressedTextures; + if (allowHardwareTextures == null) allowHardwareTextures = Assets.allowHardwareTextures; + if (useCache == null) useCache = true; #if (lime && tools && !display) @@ -544,11 +594,48 @@ class Assets } } + if ((allowCompressedTextures || haxe.io.Path.extension(id) == "astc") && openfl.Lib.current.stage.context3D.isASTCSupported()) + { + final astcTexture:String = haxe.io.Path.withExtension(id, "astc"); + + if (LimeAssets.exists(astcTexture, BINARY)) + { + LimeAssets.loadBytes(astcTexture).onComplete(function(bytes) + { + if (bytes != null) + { + var bitmapData = BitmapData.fromTexture(openfl.Lib.current.stage.context3D.createASTCTexture(bytes), false); + bitmapData.__asset = true; + + if (useCache && cache.enabled) + { + cache.setBitmapData(id, bitmapData); + } + + promise.complete(bitmapData); + } + else + { + promise.error("[Assets] Could not load Image \"" + id + "\""); + } + }).onError(promise.error).onProgress(promise.progress); + + return promise.future; + } + + if (haxe.io.Path.extension(id) == "astc") + { + promise.error("[Assets] Could not load Image \"" + id + "\""); + return promise.future; + } + } + LimeAssets.loadImage(id, false).onComplete(function(image) { if (image != null) { var bitmapData = BitmapData.fromImage(image); + if (allowHardwareTextures) bitmapData.toHardware(); bitmapData.__asset = true; @@ -629,7 +716,6 @@ class Assets .onComplete(function(limeFont) { var font = new Font(); - font.__fromLimeFont(limeFont); if (useCache && cache.enabled) @@ -708,6 +794,17 @@ class Assets #if !html5 var promise = new Promise(); + if (useCache && cache.enabled && cache.hasSound(id)) + { + var sound = cache.getSound(id); + + if (isValidSound(sound)) + { + promise.complete(sound); + return promise.future; + } + } + LimeAssets.loadAudioBuffer(id, useCache) .onComplete(function(buffer) { @@ -805,6 +902,17 @@ class Assets #if lime var promise = new Promise(); + if (useCache && cache.enabled && cache.hasSound(id)) + { + var sound = cache.getSound(id); + + if (isValidSound(sound)) + { + promise.complete(sound); + return promise.future; + } + } + LimeAssets.loadAudioBuffer(id, useCache) .onComplete(function(buffer) { @@ -887,7 +995,9 @@ class Assets @:noCompletion private static function resolveEnum(name:String):Enum { - return Type.resolveEnum(name); + var value = Type.resolveEnum(name); + + return value; } public static function unloadLibrary(name:String):Void diff --git a/src/openfl/utils/BitmapDataUtil.hx b/src/openfl/utils/BitmapDataUtil.hx new file mode 100644 index 0000000000..8b8fc1b50b --- /dev/null +++ b/src/openfl/utils/BitmapDataUtil.hx @@ -0,0 +1,289 @@ +package openfl.utils; + +#if lime +import lime.graphics.opengl.GL; +import lime.graphics.Image; +import lime.graphics.ImageBuffer; +import lime.graphics.ImageType; +import lime.graphics.PixelFormat; +import openfl.display.Bitmap; +import openfl.display.BitmapData; +import openfl.display.DisplayObject; +import openfl.display.Graphics; +import openfl.display.IBitmapDrawable; +import openfl.display.OpenGLRenderer; +import openfl.display.Stage; +import openfl.display.Sprite; +import openfl.display.Shader; +import openfl.display3D.textures.TextureBase; +import openfl.display3D.Context3D; +import openfl.display3D.Context3DTextureFormat; +import openfl.filters.BitmapFilter; +import openfl.geom.ColorTransform; +import openfl.geom.Rectangle; +import openfl.geom.Point; +import openfl.geom.Matrix; +import openfl.utils._internal.UInt8Array; +import openfl.Lib; + +#if flixel +import flixel.math.FlxRect; +import flixel.FlxG; +#end + +final class BitmapDataUtil { + public static var maxTextureSize(get, never):Int; + inline static function get_maxTextureSize() return cast GL.getParameter(GL.MAX_TEXTURE_SIZE); + + public static var stage(get, never):Stage; + inline static function get_stage():Stage return #if flixel FlxG.stage #else Lib.current.stage #end; + + public static var context3D(get, never):Context3D; + inline static function get_context3D():Context3D return stage.context3D; + + public static var gfxBitmap:Bitmap; + public static var gfxSprite:Sprite; + public static var gfxRenderer:OpenGLRenderer; + + public static function prepareGfxSprite() @:privateAccess { + if (gfxSprite == null) { + (gfxSprite = new Sprite()).addChild(gfxBitmap = new Bitmap()); + gfxSprite.__cacheBitmapMatrix = new Matrix(); + gfxSprite.__cacheBitmapColorTransform = new ColorTransform(); + } + else { + gfxSprite.__cacheBitmapMatrix.identity(); + gfxSprite.__cacheBitmapColorTransform.__identity(); + } + } + + public static function prepareGfxRenderer() @:privateAccess { + prepareGfxSprite(); + + if (gfxRenderer == null) { + if ((gfxRenderer = cast gfxSprite.__cacheBitmapRenderer) == null || gfxRenderer.__type != OPENGL) { + gfxSprite.__cacheBitmapRenderer = cast gfxRenderer = new OpenGLRenderer(context3D); + } + gfxRenderer.__worldTransform = new Matrix(); + gfxRenderer.__worldColorTransform = new ColorTransform(); + gfxRenderer.__allowSmoothing = (gfxRenderer.__stage = stage).__renderer.__allowSmoothing; + } + else { + gfxRenderer.__worldTransform.identity(); + gfxRenderer.__worldColorTransform.__identity(); + gfxRenderer.__worldAlpha = 1; + gfxRenderer.__overrideBlendMode = gfxRenderer.__blendMode = null; + + gfxRenderer.__clearShader(); + //gfxRenderer.__copyShader(cast stage.__gfxRenderer); + } + } + + public static function copyFrom(dst:BitmapData, src:BitmapData, ?alpha:Float, ?matrix:Matrix, smoothing = false) @:privateAccess { + if (dst.image != null && src.image != null && alpha == null && matrix == null) { + dst.copyPixels(src, dst.rect, gfxSprite.__tempPoint = gfxSprite.__tempPoint ?? new Point()); + } + else { + prepareGfxRenderer(); + + final context = gfxRenderer.__context3D; + final cacheRTT = context.__state.renderToTexture, + cacheRTTDepthStencil = context.__state.renderToTextureDepthStencil, + cacheRTTAntiAlias = context.__state.renderToTextureAntiAlias, + cacheRTTSurfaceSelector = context.__state.renderToTextureSurfaceSelector; + + gfxRenderer.__setRenderTarget(dst); + if (alpha != null) gfxRenderer.__worldAlpha = alpha; + if (matrix != null) gfxRenderer.__worldTransform.concat(matrix); + gfxRenderer.__renderFilterPass(src, gfxRenderer.__defaultDisplayShader, smoothing, false); + + if (cacheRTT != null) context.setRenderToTexture(cacheRTT, cacheRTTDepthStencil, cacheRTTAntiAlias, cacheRTTSurfaceSelector); + else context.setRenderToBackBuffer(); + } + } + + public inline static function prepareCacheBitmapData(bitmap:BitmapData, width:Int, height:Int):BitmapData { + if (bitmap == null) return BitmapData.fromContext(context3D, width, height); + bitmap.resize(width, height); + return bitmap; + } + + public static function applyShaders(bitmap:BitmapData, shaders:Array) @:privateAccess { + prepareGfxRenderer(); + + final context = gfxRenderer.__context3D; + final cacheRTT = context.__state.renderToTexture, + cacheRTTDepthStencil = context.__state.renderToTextureDepthStencil, + cacheRTTAntiAlias = context.__state.renderToTextureAntiAlias, + cacheRTTSurfaceSelector = context.__state.renderToTextureSurfaceSelector; + + bitmap.getTexture(context); + + var bitmap2 = gfxSprite.__cacheBitmapData2 = prepareCacheBitmapData(gfxSprite.__cacheBitmapData2, bitmap.width, bitmap.height); + var cacheBitmap:BitmapData; + for (shader in shaders) { + gfxRenderer.__setRenderTarget(bitmap2); + + bitmap2.__fillRect(bitmap2.rect, 0, true); + gfxRenderer.__renderFilterPass(cacheBitmap = bitmap, shader, false, false); + + bitmap = bitmap2; + bitmap2 = cacheBitmap; + } + + if (bitmap == gfxSprite.__cacheBitmapData2) { + gfxRenderer.__setRenderTarget(bitmap2); + gfxRenderer.__renderFilterPass(bitmap, gfxRenderer.__defaultDisplayShader, false, false); + } + + if (cacheRTT != null) context.setRenderToTexture(cacheRTT, cacheRTTDepthStencil, cacheRTTAntiAlias, cacheRTTSurfaceSelector); + else context.setRenderToBackBuffer(); + } + + public static function applyFilters(bitmap:BitmapData, filters:Array, resizeBitmap = false, ?rect:#if flixel FlxRect #else Rectangle #end) @:privateAccess { + if (filters == null || filters.length == 0) return; + prepareGfxRenderer(); + + var width = bitmap.width, height = bitmap.height; + if (resizeBitmap) { + final flashRect = Rectangle.__pool.get(), cacheFilters = gfxSprite.__filters; + gfxSprite.__filters = filters; + gfxBitmap.bitmapData = bitmap; + gfxSprite.__getFilterBounds(flashRect, gfxSprite.__cacheBitmapMatrix); + gfxSprite.__filters = cacheFilters; + + if (rect != null) { + #if flixel + rect.copyFromFlash(flashRect); + #else + rect.copyFrom(flashRect); + #end + } + bitmap.resize(width = Math.floor(flashRect.width), height = Math.floor(flashRect.height)); + Rectangle.__pool.release(flashRect); + } + else if (rect != null) + rect.set(0, 0, width, height); + + var bitmap2 = gfxSprite.__cacheBitmapData2 = prepareCacheBitmapData(gfxSprite.__cacheBitmapData2, width, height); + var bitmap3 = gfxSprite.__cacheBitmapData3, cacheBitmap:BitmapData; + + if (bitmap.__texture != null && gfxRenderer != null) { + final context = gfxRenderer.__context3D; + final cacheRTT = context.__state.renderToTexture, + cacheRTTDepthStencil = context.__state.renderToTextureDepthStencil, + cacheRTTAntiAlias = context.__state.renderToTextureAntiAlias, + cacheRTTSurfaceSelector = context.__state.renderToTextureSurfaceSelector; + + for (filter in filters) { + if (filter.__preserveObject) { + gfxRenderer.__setRenderTarget(bitmap3 = prepareCacheBitmapData(bitmap3, width, height)); + gfxRenderer.__renderFilterPass(bitmap, gfxRenderer.__defaultDisplayShader, false, false); + } + + for (i in 0...filter.__numShaderPasses) { + final shader = filter.__initShader(gfxRenderer, i, filter.__preserveObject ? bitmap3 : null); + gfxRenderer.__setBlendMode(filter.__shaderBlendMode); + gfxRenderer.__setRenderTarget(bitmap2); + + bitmap2.__fillRect(bitmap2.rect, 0, true); + gfxRenderer.__renderFilterPass(cacheBitmap = bitmap, shader, filter.__smooth, false); + + bitmap = bitmap2; + bitmap2 = cacheBitmap; + } + + gfxRenderer.__setBlendMode(NORMAL); + } + + if (bitmap == gfxSprite.__cacheBitmapData2) { + gfxRenderer.__setRenderTarget(bitmap2); + gfxRenderer.__renderFilterPass(bitmap, gfxRenderer.__defaultDisplayShader, false, false); + } + + if (cacheRTT != null) context.setRenderToTexture(cacheRTT, cacheRTTDepthStencil, cacheRTTAntiAlias, cacheRTTSurfaceSelector); + else context.setRenderToBackBuffer(); + } + + gfxSprite.__cacheBitmapData3 = bitmap3; + } + + public static function draw(dst:BitmapData, src:IBitmapDrawable, ?matrix:Matrix, smoothing = false, onlyGraphics = false) @:privateAccess { + prepareGfxRenderer(); + + final context = gfxRenderer.__context3D; + final cacheRTT = context.__state.renderToTexture, + cacheRTTDepthStencil = context.__state.renderToTextureDepthStencil, + cacheRTTAntiAlias = context.__state.renderToTextureAntiAlias, + cacheRTTSurfaceSelector = context.__state.renderToTextureSurfaceSelector; + + inline function _preDraw() { + dst.__textureContext = context.__context; + context.setRenderToTexture(dst.getTexture(context), true); + context.setColorMask(true, true, true, true); + context.setCulling(NONE); + context.setStencilActions(); + context.setStencilReferenceValue(0, 0, 0); + context.setScissorRectangle(null); + + gfxRenderer.__blendMode = null; + gfxRenderer.__setBlendMode(NORMAL); + gfxRenderer.__setRenderTarget(dst); + gfxRenderer.__allowSmoothing = smoothing; + gfxRenderer.__pixelRatio = #if openfl_disable_hdpi 1 #else stage.window.scale #end; + + gfxRenderer.__worldTransform.copyFrom(src.__renderTransform); + gfxRenderer.__worldTransform.invert(); + if (matrix != null) gfxRenderer.__worldTransform.concat(matrix); + + gfxSprite.__cacheBitmapColorTransform.__copyFrom(src.__worldColorTransform); + gfxSprite.__mask = src.__mask; gfxSprite.__scrollRect = src.__scrollRect; + + src.__worldColorTransform.__identity(); + src.__worldAlpha = 1; src.__mask = null; src.__scrollRect = null; + } + + inline function _postDraw() { + context.present(); + src.__worldColorTransform.__copyFrom(gfxSprite.__cacheBitmapColorTransform); + src.__mask = gfxSprite.__mask; src.__scrollRect = gfxSprite.__scrollRect; + gfxSprite.__mask = null; gfxSprite.__scrollRect = null; + } + + if (src is DisplayObject) { + final displayObject:DisplayObject = cast src; + gfxSprite.__visible = displayObject.__visible; + displayObject.__visible = true; + + src.__update(false, true); + if (src.__renderable) { + _preDraw(); + if (onlyGraphics && displayObject.__graphics != null) { + #if (openfl >= "9.5.0") + displayObject.__graphics.__bitmapScaleX = displayObject.__graphics.__bitmapScaleY = 1; + #else + displayObject.__graphics.__bitmapScale = 1; + #end + openfl.display._internal.Context3DShape.render(displayObject, gfxRenderer); + } + else gfxRenderer.__renderDrawable(src); + _postDraw(); + } + + displayObject.__visible = gfxSprite.__visible; + gfxSprite.__visible = true; + } + else if (!onlyGraphics) { + src.__update(false, true); + if (src.__renderable) { + _preDraw(); + gfxRenderer.__renderDrawable(src); + _postDraw(); + } + } + + if (cacheRTT != null) context.setRenderToTexture(cacheRTT, cacheRTTDepthStencil, cacheRTTAntiAlias, cacheRTTSurfaceSelector); + else context.setRenderToBackBuffer(); + } +} +#end \ No newline at end of file diff --git a/src/openfl/utils/GLSLSourceAssembler.hx b/src/openfl/utils/GLSLSourceAssembler.hx new file mode 100644 index 0000000000..037e6d9b09 --- /dev/null +++ b/src/openfl/utils/GLSLSourceAssembler.hx @@ -0,0 +1,590 @@ +package openfl.utils; + +import openfl.utils._internal.Log; +import openfl.display.OpenGLRenderer; +import openfl.display.Shader; +import openfl.display.ShaderPrecision; + +@:access(openfl.display.OpenGLRenderer) +class GLSLSourceAssembler +{ + /** + Gets this platform default GLSL version + **/ + public static function getDefaultVersion():String + { + // Specify the default glVersion. + // We can use compile defines to guess the value that prevents crashes in the majority of cases. + //return #if (android) "100" #elseif (web) "100" #elseif (mac) "120" #elseif (desktop) "150" #else "100" #end; + #if web + return "100"; + #elseif mac + return "410"; + #elseif android + return "320 es"; + #else + return "330 core"; + #end + } + + /** + Gets the GLSL Version from the source + **/ + public static function getVersionFromSource(source:String, ?defaultVersion:Null):Null + { + var glVersionFinder:EReg = __getVersionFinder(); + if (!glVersionFinder.match(source)) return defaultVersion; + + var profile:String = glVersionFinder.matched(2); + return profile == null ? glVersionFinder.matched(1) : glVersionFinder.matched(1) + " " + profile; + } + + /** + + **/ + public var fragmentExtensions:Map; + + /** + + **/ + public var fragmentPragmas:Map; + + /** + + **/ + public var fragmentSource:String; + + /** + + **/ + public var version:String; + + /** + + **/ + public var vertexExtensions:Map; + + /** + + **/ + public var vertexPragmas:Map; + + /** + + **/ + public var vertexSource:String; + + /** + Creates a new GLSLSourceAssembler instance + **/ + public function new() + { + fragmentExtensions = new Map(); + fragmentPragmas = new Map(); + vertexExtensions = new Map(); + vertexPragmas = new Map(); + } + + /** + Reset all values on this object + **/ + public function clear():Void + { + fragmentPragmas = new Map(); + fragmentExtensions = new Map(); + fragmentSource = null; + vertexPragmas = new Map(); + vertexExtensions = new Map(); + vertexSource = null; + version = null; + } + + /** + Merge another GLSLSourceAssembler with `this` + Modifies `this` GLSLSourceAssembler + **/ + public function concat(other:GLSLSourceAssembler):GLSLSourceAssembler + { + addFragmentPragmas(other.fragmentPragmas); + addFragmentExtensions(other.fragmentExtensions); + if (other.fragmentSource != null) fragmentSource = other.fragmentSource; + addVertexPragmas(other.vertexPragmas); + addVertexExtensions(other.vertexExtensions); + if (other.vertexSource != null) vertexSource = other.vertexSource; + if (other.version != null) version = other.version; + return this; + } + + /** + Add a GL extension for both vertex and fragment source + **/ + public function addExtension(extension:String, behavior:String = "require"):Void + { + addVertexExtension(extension, behavior); + addFragmentExtension(extension, behavior); + } + + /** + Adds GL extensions at once for both vertex and fragment source + **/ + public function addExtensions(extensions:Map):Void + { + addVertexExtensions(extensions); + addFragmentExtensions(extensions); + } + + /** + Add a GL extension for the fragment source + **/ + public function addFragmentExtension(extension:String, behavior:String = "require"):Void + { + fragmentExtensions.set(extension, behavior); + } + + /** + Adds GL extensions at once for the fragment source + **/ + public function addFragmentExtensions(extensions:Map):Void + { + for (key in extensions) fragmentExtensions[key] = extensions[key]; + } + + /** + Add a GL extension for the vertex shader + **/ + public function addVertexExtension(extension:String, behavior:String = "require"):Void + { + vertexExtensions.set(extension, behavior); + } + + /** + Adds GL extensions at once for the vertex source + **/ + public function addVertexExtensions(extensions:Map):Void + { + for (key in extensions) vertexExtensions[key] = extensions[key]; + } + + /** + Append a pragma that will be used for assembling the fragment source + **/ + public function addFragmentPragma(pragma:String, source:String):Void + { + fragmentPragmas.set(pragma, source); + } + + /** + Append a pragma that will be used for assembling the vertex source + **/ + public function addVertexPragma(pragma:String, source:String):Void + { + vertexPragmas.set(pragma, source); + } + + /** + Append pragmas at once that will be used for assembling the fragment source + **/ + public function addFragmentPragmas(pragmas:Map):Void + { + for (pragma in pragmas) addFragmentPragma(pragma, pragmas[pragma]); + } + + /** + Append pragmas at once that will be used for assembling the fragment source + **/ + public function addVertexPragmas(pragmas:Map):Void + { + for (pragma in pragmas) addVertexPragma(pragma, pragmas[pragma]); + } + + /** + Append source to the pragma body of the GLSL fragment source + A shortcut for `addFragmentPragma("body", source)` + **/ + public inline function addFragmentBody(source:String):Void + { + addFragmentPragma("body", source); + } + + /** + Append source to the pragma header of the GLSL fragment source + A shortcut for `addFragmentPragma("header", source)` + **/ + public inline function addFragmentHeader(source:String):Void + { + addFragmentPragma("header", source); + } + + /** + Append source to the pragma body of the GLSL vertex source + A shortcut for `addVertexPragma("body", source)` + **/ + public inline function addVertexBody(source:String):Void + { + addVertexPragma("body", source); + } + + /** + Append source to the pragma header of the GLSL vertex source + A shortcut for `addVertexPragma("header", source)` + **/ + public inline function addVertexHeader(source:String):Void + { + addVertexPragma("header", source); + } + + /** + Build necessary extensions for a GLSL source + **/ + public function buildExtensions(extensions:Map, version:String, isVertex:Bool):Map + { + var dataVersion = __getVersion(version); + return __buildExtensions(extensions, dataVersion.versionNumber, dataVersion.versionProfile, isVertex); + } + + /** + Apply compatibility transforms to the specified GLSL shader sources to convert for the specified newer version. + + @param source The GLSL source to convert. + @param targetVersion Optional; The target GLSL version. + @param isVertex Whether the GLSL source is a component of a vertex shader. False if it is a fragment shader. + @return The converted GLSL source. + **/ + public function applyCompatibility(source:String, ?targetVersion:String, isVertex:Bool):String + { + var dataVersion = __getVersion(targetVersion ?? getDefaultVersion()); + return __applyCompatibility(source, dataVersion.versionNumber, dataVersion.versionProfile, isVertex); + } + + /** + Assembles and finalize this GLSL fragment source code with optional compatibility. + + @param useCompatibility Whether to use a version conversion for finalizing. + @return The finalized GLSL fragment source code. + **/ + public function assembleFragmentSource(useCompatibility:Bool = true):String + { + return assembleSource(fragmentSource, fragmentPragmas, fragmentExtensions, version, false, useCompatibility); + } + + /** + Assembles and finalize this GLSL vertex source code with optional compatibility. + + @param useCompatibility Whether to use a version conversion for finalizing. + @return The finalized GLSL vertex source code. + **/ + public function assembleVertexSource(useCompatibility:Bool = true):String + { + return assembleSource(vertexSource, vertexPragmas, vertexExtensions, version, true, useCompatibility); + } + + /** + Assembles and finalize a GLSL source code with optional compatibility version conversion, extensions, and pragmas. + + @param source The GLSL source to be assembled. + @param pragmas Optional; The pragmas to be used for finalizing the source that have requested pragmas. + @param extensions Optional; The extensions to be used for finalizing. + @param version Optional; The target GLSL version to be used for finalizing. + @param isVertex Whether the GLSL source is a component of a vertex shader. False if it is a fragment shader. + @param useCompatibility Whether to use a version conversion for finalizing. + @return The finalized GLSL source. + **/ + public function assembleSource(source:String, ?pragmas:Map, ?extensions:Map, + ?version:String, isVertex:Bool, useCompatibility:Bool = true, precisionHint:ShaderPrecision = FULL):String + { + if (version == null) version = getDefaultVersion(); + + if (source == null) + { + // There's nothing to assemble with, but just return it with a prefix instead anyway. + var dataVersion = __getVersion(version); + return __appendPrefix(null, dataVersion.versionNumber, dataVersion.versionProfile, extensions, isVertex, precisionHint); + } + + source = __appendIncludes(source, isVertex); + + if (pragmas != null) + { + source = __getPragmaFinder().map(source, (glPragmaFinder:EReg) -> + { + var pragma = glPragmaFinder.matched(1); + return pragmas.exists(pragma) ? '/*pragma $pragma*/\n' + pragmas.get(pragma) + '\n' : 'pragma $pragma'; + }); + } + + var data = __getSource(source, version); + extensions = __buildExtensions(__getExtensions(source, extensions == null ? new Map() : extensions.copy()), + data.versionNumber, data.versionProfile, isVertex); + + if (useCompatibility) + { + data.source = __applyCompatibility(data.source, data.versionNumber, data.versionProfile, isVertex); + } + + return __appendPrefix(data.source, data.versionNumber, data.versionProfile, extensions, isVertex, precisionHint); + } + + private function __applyCompatibility(source:String, versionNumber:Int, versionProfile:Null, isVertex:Bool):String + { + // No processing needed on "compatibility" profile + if (versionProfile == "compatibility") return source; + + // Recall: Attribute values are per-vertex, varying values are per-fragment + // Thus, an `out` value in the vertex shader is an `in` value in the fragment shader + var attributeKeyword:EReg = ~/\battribute\s+([A-Za-z0-9_]+)\s+([^\s]+)/gu; + var varyingKeyword:EReg = ~/\bvarying\s+(?:lowp\s+|mediump\s+|highp\s+)?([A-Za-z0-9_]+)\s+([^\s]+)/gu; + + var texture2DKeyword:EReg = ~/texture2D/g; + var glFragColorKeyword:EReg = ~/gl_FragColor/g; + + if (versionNumber >= 300) + { + if (isVertex) + { + source = attributeKeyword.replace(source, "in $1 $2"); + source = varyingKeyword.replace(source, "out $1 $2"); + } + else + { + source = varyingKeyword.replace(source, "in $1 $2"); + } + + source = texture2DKeyword.replace(source, "texture"); + source = glFragColorKeyword.replace(source, "openfl_FragColor"); + + return source; + } + else + { + return source; + } + } + + private function __appendIncludes(source:String, isVertex:Bool, ?includedKeys:Map):String + { + if (includedKeys == null) includedKeys = []; + + return __getIncludeFinder().map(source, (regex:EReg) -> + { + var key = regex.matched(1); + if (includedKeys.get(key)) return '/*Recursive include $key*/\n'; + + var include = __getIncludeSource(key, isVertex); + if (include == null) return '/*Unknown include $key*/\n'; + + includedKeys.set(key, true); + return '/*include $key*/\n' + __appendIncludes(include, isVertex, includedKeys); + }); + } + + private function __appendPrefix(source:String, versionNumber:Int, versionProfile:Null, extensions:Map, isVertex:Bool, + precisionHint:Null):String + { + var output = new StringBuf(); + output.add('#version $versionNumber${versionProfile != null ? " " + versionProfile : ""}\n'); + + if (extensions != null) + { + for (key in extensions.keys()) output.add('#extension $key : ${extensions[key]}\n'); + } + + #if (js && html5) + if (precisionHint == FAST) + { + output.add("precision lowp float;\n"); + } + else + { + output.add("precision mediump float;\n"); + } + #else + if (precisionHint == FAST) + { + output.add("#ifdef GL_ES\nprecision lowp float;\n#endif\n"); + } + else + { + output.add("#ifdef GL_ES\n#ifdef GL_FRAGMENT_PRECISION_HIGH\nprecision highp float;\n#else\nprecision mediump float;\n#endif\n#endif\n"); + } + #end + + if (OpenGLRenderer.__complexBlendsSupported && !isVertex && versionNumber >= 150) + { + var behavior = extensions.get("GL_KHR_blend_equation_advanced"); + if (behavior == "enable" || behavior == "require") + { + output.add("#ifdef GL_KHR_blend_equation_advanced\nlayout (blend_support_all_equations) out;\n#endif\n"); + } + } + + if (source != null) + { + if (!isVertex && versionNumber >= 300 && versionProfile != "compatibility" && !StringTools.contains(source, "out vec4")) + { + output.add("out vec4 openfl_FragColor;\n"); + } + output.add(source); + } + + return output.toString(); + } + + private function __buildExtensions(extensions:Map, versionNumber:Int, versionProfile:Null, isVertex:Bool):Map + { + if (versionNumber >= 300 && versionNumber < 400) + { + // In 300, 310, 320, 330; it is required to include this extension. + if (!extensions.exists("GL_ARB_separate_shader_objects") && !extensions.exists("GL_EXT_separate_shader_objects")) + { + #if linux + extensions.set("GL_EXT_separate_shader_objects", "require"); + #else + extensions.set("GL_ARB_separate_shader_objects", "require"); + #end + } + } + + // Enable complex blend modes if supported. + if (OpenGLRenderer.__complexBlendsSupported && !isVertex && versionNumber >= 150) + { + extensions.set("GL_KHR_blend_equation_advanced", "enable"); + + // This is for getting complex blend modes to work with AMD Card quirks. + // 'gl_SampleID' : required extension not requested: GL_ARB_sample_shading + if (OpenGLRenderer.__complexBlendsSupported + && !extensions.exists("GL_ARB_sample_shading") && !extensions.exists("GL_OES_sample_shading")) + { + if (versionProfile == "es") extensions.set("GL_OES_sample_shading", "enable"); + else extensions.set("GL_ARB_sample_shading", "enable"); + } + } + + // Import standard derivative functions. + if (OpenGLRenderer.__standardDerivativesSupported && !isVertex) + { + extensions.set("GL_OES_standard_derivatives", "enable"); + } + + return extensions; + } + + private function __getIncludeSource(include:String, fromVertex:Bool):Null + { + return null; + } + + private static function __getSource(source:String, defaultVersion:String):{source:String, versionNumber:Int, versionProfile:Null} + { + var glVersionFinder:EReg = __getVersionFinder(); + if (glVersionFinder.match(source)) + { + return { + source: glVersionFinder.matchedLeft() + glVersionFinder.matchedRight(), + versionNumber: Std.parseInt(glVersionFinder.matched(1)), + versionProfile: glVersionFinder.matched(2) + }; + } + else + { + var glVersionSeperator:EReg = __getVersionSeperator(); + if (glVersionSeperator.match(defaultVersion)) + { + return { + source: source, + versionNumber: Std.parseInt(glVersionSeperator.matched(1)), + versionProfile: glVersionSeperator.matched(2) + }; + } + else + { + Log.error('Unable to find an unknown GLSL version "$defaultVersion"'); + return null; + } + } + } + + private static function __getExtensions(source:String, extensions:Map):Map + { + if (extensions == null) extensions = new Map(); + + var glExtensionFinder:EReg = __getExtensionFinder(), lastMatch = 0, position; + while (glExtensionFinder.matchSub(source, lastMatch)) + { + extensions.set(glExtensionFinder.matched(1), glExtensionFinder.matched(2)); + + position = glExtensionFinder.matchedPos(); + lastMatch = position.pos + position.len; + } + + return extensions; + } + + private static function __getVersion(version:String):{versionNumber:Int, versionProfile:Null} + { + var glVersionSeperator:EReg = __getVersionSeperator(); + if (glVersionSeperator.match(version)) + { + return { + versionNumber: Std.parseInt(glVersionSeperator.matched(1)), + versionProfile: glVersionSeperator.matched(2) + }; + } + else + { + Log.error('Unable to find an unknown GLSL version "${version}"'); + return null; + } + } + + /* + private static function __getVersionNumber(version:String):Int + { + var glVersionSeperator:EReg = __getVersionSeperator(); + if (glVersionSeperator.match(version)) return Std.parseInt(glVersionSeperator.matched(1)); + else + { + Log.error('Unable to get a GLSL version number from an unknown GLSL version "${version}"'); + return null; + } + } + + private static function __getVersionProfile(version:String):String + { + var glVersionSeperator:EReg = __getVersionSeperator(); + if (glVersionSeperator.match(version)) + { + version = glVersionSeperator.matched(2); + return version == null ? "" : version; + } + else + { + return ""; + } + } + */ + + private static inline function __getExtensionFinder():EReg + { + return ~/(?:^|\s)#extension\s+([A-Za-z0-9_]+)\s+:\s+(enable|require|warn|disable|all)\b/g; + } + + private static inline function __getPragmaFinder():EReg + { + return ~/(?:^|\s)#pragma\s+(?|"([^"]+)"|'([^']+)'|([^\s]+))/g; + } + + private static inline function __getIncludeFinder():EReg + { + return ~/(?:^|\s)#include\s+(?|"([^"]+)"|'([^']+)'|([^\s]+))/g; + } + + private static inline function __getVersionFinder():EReg + { + return ~/(?:^|\s)#version\s+(\d+)(?:\s+)?(core|es|compatibility)?\b/; + } + + private static inline function __getVersionSeperator():EReg + { + return ~/(\d+)(?:\s+)?(core|es|compatibility)?\b/; + } +} \ No newline at end of file diff --git a/src/openfl/utils/_internal/Log.hx b/src/openfl/utils/_internal/Log.hx index 134edb3cfb..2e50a2f3af 100644 --- a/src/openfl/utils/_internal/Log.hx +++ b/src/openfl/utils/_internal/Log.hx @@ -13,7 +13,7 @@ class Log public static var level:LogLevel; public static var throwErrors:Bool = true; - public static function debug(message:Dynamic, ?info:PosInfos):Void + public static dynamic function debug(message:Dynamic, ?info:PosInfos):Void { if (level >= LogLevel.DEBUG) { @@ -25,7 +25,7 @@ class Log } } - public static function error(message:Dynamic, ?info:PosInfos):Void + public static dynamic function error(message:Dynamic, ?info:PosInfos):Void { if (level >= LogLevel.ERROR) { @@ -46,7 +46,7 @@ class Log } } - public static function info(message:Dynamic, ?info:PosInfos):Void + public static dynamic function info(message:Dynamic, ?info:PosInfos):Void { if (level >= LogLevel.INFO) { @@ -80,7 +80,7 @@ class Log #end } - public static function verbose(message:Dynamic, ?info:PosInfos):Void + public static dynamic function verbose(message:Dynamic, ?info:PosInfos):Void { if (level >= LogLevel.VERBOSE) { @@ -88,7 +88,7 @@ class Log } } - public static function warn(message:Dynamic, ?info:PosInfos):Void + public static dynamic function warn(message:Dynamic, ?info:PosInfos):Void { if (level >= LogLevel.WARN) { diff --git a/src/openfl/utils/_internal/ShaderMacro.hx b/src/openfl/utils/_internal/ShaderMacro.hx index e9b9664e5b..cb71b7b61c 100644 --- a/src/openfl/utils/_internal/ShaderMacro.hx +++ b/src/openfl/utils/_internal/ShaderMacro.hx @@ -3,7 +3,6 @@ package openfl.utils._internal; #if macro import haxe.macro.Context; import haxe.macro.Expr; -import haxe.macro.Type; using haxe.macro.ExprTools; using haxe.macro.Tools; @@ -12,323 +11,182 @@ using haxe.macro.TypeTools; @SuppressWarnings("checkstyle:FieldDocComment") class ShaderMacro { - #if 0 - private static var __suppressWarning:Array> = [Expr]; - #end + //#if 0 + //private static var __suppressWarning:Array> = [Expr]; + //#end - public static function build():Array - { + public static function build():Array { var fields = Context.getBuildFields(); - var glFragmentHeader = ""; - var glFragmentBody = ""; - var glVertexHeader = ""; - var glVertexBody = ""; - - var glVersion:String = null; - - var glFragmentExtensions = []; - var glVertexExtensions = []; + var glFragmentPragmas:Map = [], glVertexPragmas:Map = []; + function addPragma(pragmas:Map, key:String, value:String) { + if (pragmas.exists(key)) pragmas.set(key, value + '\n' + pragmas.get(key)); + else pragmas.set(key, value); + } - var glFragmentSource = null; - var glFragmentSourceRaw = ""; - var glVertexSource = null; - var glVertexSourceRaw = ""; + var glFragmentExtensions:Map = [], glVertexExtensions:Map = []; + function addExtension(extensions:Map, meta:MetadataEntry) { + var name = meta.params[0].getValue(); + if (!extensions.exists(name)) { + var v = meta.params[1].getValue(); + if (v is Bool) extensions.set(name, v == true ? "require" : "disable"); + else if (v is String) extensions.set(name, cast v); + } + } - for (field in fields) - { - for (meta in field.meta) - { - switch (meta.name) - { - case "glVersion", ":glVersion": + var glFragmentSource:String = null, glVertexSource:String = null, glVersion:String = null; + var nextFragmentDontOverride = false, nextVertexDontOverride = false; + var prefixFragment = "glFragment", prefixVertex = "glVertex", name:String; + var fieldNames = new Map(); + + for (field in fields) { + for (meta in field.meta) { + switch (name = meta.name.charAt(0) == ":" ? meta.name.substr(1) : meta.name) { + case "glFragmentDontOverride": nextFragmentDontOverride = true; + case "glVertexDontOverride": nextVertexDontOverride = true; + case "glVersion": glVersion = meta.params[0].getValue(); - case "glExtensions", ":glExtensions": - glFragmentExtensions = glFragmentExtensions.concat(meta.params[0].getValue()); - glVertexExtensions = glVertexExtensions.concat(meta.params[0].getValue()); + case "glFragmentExtension": + addExtension(glFragmentExtensions, meta); - case "glFragmentExtensions", ":glFragmentExtensions": - glFragmentExtensions = glFragmentExtensions.concat(meta.params[0].getValue()); + case "glVertexExtension": + addExtension(glVertexExtensions, meta); - case "glVertexExtensions", ":glVertexExtensions": - glVertexExtensions = glVertexExtensions.concat(meta.params[0].getValue()); + case "glFragmentSource": + glFragmentSource = meta.params[0].getValue(); - default: - } - } + case "glVertexSource": + glVertexSource = meta.params[0].getValue(); - for (meta in field.meta) - { - /** - `@:glFragmentSource`, `@:glVertexSource`, `@:glFragmentHeader`, `@:glFragmentBody`, `@:glVertexHeader`, `@:glVertexBody` - all have a second argument which, if true, will use `processGLSLText` to convert the text to be compatible with the current GLSL version. - Defaults to false to prevent converting user-defined GLSL. - **/ - var shouldProcess = meta.params.length > 1 && cast(meta.params[1].getValue(), Bool); - - switch (meta.name) - { - case "glFragmentSource", ":glFragmentSource": - if (shouldProcess) - { - glFragmentSource = processGLSLText(meta.params[0].getValue(), glVersion, true); - } - else - { - glFragmentSource = meta.params[0].getValue(); - } + case "glExtension": + addExtension(glFragmentExtensions, meta); + addExtension(glVertexExtensions, meta); - case "glVertexSource", ":glVertexSource": - if (shouldProcess) - { - glVertexSource = processGLSLText(meta.params[0].getValue(), glVersion, false); - } - else - { - glVertexSource = meta.params[0].getValue(); - } + case "glFragmentPragma": + addPragma(glFragmentPragmas, meta.params[0].getValue(), meta.params[1].getValue()); - case "glFragmentHeader", ":glFragmentHeader": - if (shouldProcess) - { - glFragmentHeader += processGLSLText(meta.params[0].getValue(), glVersion, true); - } - else - { - glFragmentHeader += meta.params[0].getValue(); - } - - case "glFragmentBody", ":glFragmentBody": - if (shouldProcess) - { - glFragmentBody += processGLSLText(meta.params[0].getValue(), glVersion, true); - } - else - { - glFragmentBody += meta.params[0].getValue(); - } - - case "glVertexHeader", ":glVertexHeader": - if (shouldProcess) - { - glVertexHeader += processGLSLText(meta.params[0].getValue(), glVersion, false); - } - else - { - glVertexHeader += meta.params[0].getValue(); - } - - case "glVertexBody", ":glVertexBody": - if (shouldProcess) - { - glVertexBody += processGLSLText(meta.params[0].getValue(), glVersion, false); - } - else - { - glVertexBody += meta.params[0].getValue(); - } + case "glVertexPragma": + addPragma(glVertexPragmas, meta.params[0].getValue(), meta.params[1].getValue()); default: + if (name.substr(0, prefixFragment.length) == prefixFragment) + addPragma(glFragmentPragmas, name.substr(prefixFragment.length).toLowerCase(), meta.params[0].getValue()); + + if (name.substr(0, prefixVertex.length) == prefixVertex) + addPragma(glVertexPragmas, name.substr(prefixVertex.length).toLowerCase(), meta.params[0].getValue()); } } + + fieldNames.set(field.name, true); } - var pos = Context.currentPos(); - var localClass = Context.getLocalClass().get(); + var fragmentDontOverride = nextFragmentDontOverride, vertexDontOverride = nextVertexDontOverride; + + var pos = Context.currentPos(), localClass = Context.getLocalClass().get(); var superClass = localClass.superClass != null ? localClass.superClass.t.get() : null; - var parent = superClass; - var parentFields:Array; + var parent = superClass, parentFields; - while (parent != null) - { + while (parent != null) { parentFields = [parent.constructor.get()].concat(parent.fields.get()); - - for (field in parentFields) - { - for (meta in field.meta.get()) - { - switch (meta.name) - { - case "glVersion", ":glVersion": + for (field in parentFields) { + for (meta in field.meta.get()) { + switch (name = meta.name.charAt(0) == ":" ? meta.name.substr(1) : meta.name) { + case "glFragmentDontOverride": nextFragmentDontOverride = true; + case "glVertexDontOverride": nextVertexDontOverride = true; + case "glVersion": if (glVersion == null) glVersion = meta.params[0].getValue(); - case "glExtensions", ":glExtensions": - glFragmentExtensions = glFragmentExtensions.concat(meta.params[0].getValue()); - glVertexExtensions = glVertexExtensions.concat(meta.params[0].getValue()); + case "glFragmentExtension": + if (!fragmentDontOverride) addExtension(glFragmentExtensions, meta); - case "glFragmentExtensions", ":glFragmentExtensions": - glFragmentExtensions = glFragmentExtensions.concat(meta.params[0].getValue()); + case "glVertexExtension": + if (!vertexDontOverride) addExtension(glVertexExtensions, meta); - case "glVertexExtensions", ":glVertexExtensions": - glVertexExtensions = glVertexExtensions.concat(meta.params[0].getValue()); + case "glExtension": + if (!fragmentDontOverride) addExtension(glFragmentExtensions, meta); + if (!vertexDontOverride) addExtension(glVertexExtensions, meta); - default: - } - } + case "glFragmentSource": + if (glFragmentSource == null) glFragmentSource = meta.params[0].getValue(); - for (meta in field.meta.get()) - { - /** - `@:glFragmentSource`, `@:glVertexSource`, `@:glFragmentHeader`, `@:glFragmentBody`, `@:glVertexHeader`, `@:glVertexBody` - all have a second argument which, if true, will use `processGLSLText` to convert the text to be compatible with the current GLSL version. - Defaults to false to prevent converting user-defined GLSL. - **/ - var shouldProcess = meta.params.length > 1 && cast(meta.params[1].getValue(), Bool); - - switch (meta.name) - { - case "glFragmentSource", ":glFragmentSource": - if (glFragmentSource == null) - { - if (shouldProcess) - { - glFragmentSource = processGLSLText(meta.params[0].getValue(), glVersion, true); - } - else - { - glFragmentSource = meta.params[0].getValue(); - } - } - - case "glVertexSource", ":glVertexSource": - if (glVertexSource == null) - { - if (shouldProcess) - { - glVertexSource = processGLSLText(meta.params[0].getValue(), glVersion, false); - } - else - { - glVertexSource = meta.params[0].getValue(); - } - } - - case "glFragmentHeader", ":glFragmentHeader": - if (shouldProcess) - { - glFragmentHeader = processGLSLText(meta.params[0].getValue(), glVersion, true) + "\n" + glFragmentHeader; - } - else - { - glFragmentHeader = meta.params[0].getValue() + "\n" + glFragmentHeader; - } - - case "glFragmentBody", ":glFragmentBody": - if (shouldProcess) - { - glFragmentBody = processGLSLText(meta.params[0].getValue(), glVersion, true) + "\n" + glFragmentBody; - } - else - { - glFragmentBody = meta.params[0].getValue() + "\n" + glFragmentBody; - } - - case "glVertexHeader", ":glVertexHeader": - if (shouldProcess) - { - glVertexHeader = processGLSLText(meta.params[0].getValue(), glVersion, false) + "\n" + glVertexHeader; - } - else - { - glVertexHeader = meta.params[0].getValue() + "\n" + glVertexHeader; - } - - case "glVertexBody", ":glVertexBody": - if (shouldProcess) - { - glVertexBody = processGLSLText(meta.params[0].getValue(), glVersion, false) + "\n" + glVertexBody; - } - else - { - glVertexBody = meta.params[0].getValue() + "\n" + glVertexBody; - } + case "glVertexSource": + if (glVertexSource == null) glVertexSource = meta.params[0].getValue(); + + case "glFragmentPragma": + if (!fragmentDontOverride) addPragma(glFragmentPragmas, meta.params[0].getValue(), meta.params[1].getValue()); + + case "glVertexPragma": + if (!vertexDontOverride) addPragma(glVertexPragmas, meta.params[0].getValue(), meta.params[1].getValue()); default: + if (!fragmentDontOverride && name.substr(0, prefixFragment.length) == prefixFragment) + addPragma(glFragmentPragmas, name.substr(prefixFragment.length).toLowerCase(), meta.params[0].getValue()); + + if (!vertexDontOverride && name.substr(0, prefixVertex.length) == prefixVertex) + addPragma(glVertexPragmas, name.substr(prefixVertex.length).toLowerCase(), meta.params[0].getValue()); } } + + fieldNames.set(field.name, true); } - parent = parent.superClass != null ? parent.superClass.t.get() : null; - } + fragmentDontOverride = nextFragmentDontOverride; + vertexDontOverride = nextVertexDontOverride; - if (glVersion == null) - { - glVersion = getDefaultGLVersion(); + parent = parent.superClass != null ? parent.superClass.t.get() : null; } - glVertexHeader = buildGLSLHeaders(glVersion) + glVertexHeader; - glFragmentHeader = buildGLSLHeaders(glVersion) + glFragmentHeader; + if (glVertexSource != null || glFragmentSource != null) { + var paramBlock:Array = []; - glVertexExtensions = buildGLSLExtensions(glVertexExtensions, glVersion, false); - glFragmentExtensions = buildGLSLExtensions(glFragmentExtensions, glVersion, true); + processFields(glVertexSource, "attribute", fieldNames, fields, paramBlock, pos); + processFields(glVertexSource, "in", fieldNames, fields, paramBlock, pos); // For higher GLSL versions + processFields(glVertexSource, "uniform", fieldNames, fields, paramBlock, pos); + processFields(glFragmentSource, "uniform", fieldNames, fields, paramBlock, pos); - if (glVertexSource != null || glFragmentSource != null) - { - if (glFragmentSource != null && glFragmentHeader != null && glFragmentBody != null) - { - glFragmentSourceRaw = glFragmentSource; - glFragmentSource = StringTools.replace(glFragmentSource, "#pragma header", glFragmentHeader); - glFragmentSource = StringTools.replace(glFragmentSource, "#pragma body", glFragmentBody); - } + var position, pragmaSource, regex = ~/(?:^|\s)#pragma\s+(?|"([^"]+)"|'([^']+)'|([^\s]+))/g, lastMatch = 0; + while (regex.matchSub(glVertexSource, lastMatch)) { + if ((pragmaSource = glVertexPragmas.get(regex.matched(1))) != null) { + processFields(pragmaSource, "attribute", fieldNames, fields, paramBlock, pos); + processFields(pragmaSource, "in", fieldNames, fields, paramBlock, pos); // For higher GLSL versions + processFields(pragmaSource, "uniform", fieldNames, fields, paramBlock, pos); + } - if (glVertexSource != null && glVertexHeader != null && glVertexBody != null) - { - glVertexSourceRaw = glVertexSource; - glVertexSource = StringTools.replace(glVertexSource, "#pragma header", glVertexHeader); - glVertexSource = StringTools.replace(glVertexSource, "#pragma body", glVertexBody); + position = regex.matchedPos(); + lastMatch = position.pos + position.len; } - var shaderDataFields:Array = []; - var uniqueFields:Array = []; - - processFields(glVertexSource, "attribute", shaderDataFields, pos); - processFields(glVertexSource, "in", shaderDataFields, pos); // For higher GLSL versions - processFields(glVertexSource, "uniform", shaderDataFields, pos); - processFields(glFragmentSource, "uniform", shaderDataFields, pos); - - if (shaderDataFields.length > 0) - { - var fieldNames = new Map(); - - for (field in shaderDataFields) - { - parent = superClass; - - while (parent != null) - { - for (parentField in parent.fields.get()) - { - if (parentField.name == field.name) - { - fieldNames.set(field.name, true); - } - } + lastMatch = 0; + while (regex.matchSub(glFragmentSource, lastMatch)) { + if ((pragmaSource = glFragmentPragmas.get(regex.matched(1))) != null) { + processFields(pragmaSource, "uniform", fieldNames, fields, paramBlock, pos); + } - parent = parent.superClass != null ? parent.superClass.t.get() : null; - } + position = regex.matchedPos(); + lastMatch = position.pos + position.len; + } - if (!fieldNames.exists(field.name)) - { - uniqueFields.push(field); - } + var generateBlock:Array = [macro __isGenerated = true]; - fieldNames[field.name] = true; - } - } + generateBlock.push(macro __cacheProgramId = $v{localClass.pack.join(".") + "." + localClass.name}); + generateBlock.push(macro __glFragmentPragmas = $v{glFragmentPragmas}); + generateBlock.push(macro __glVertexPragmas = $v{glVertexPragmas}); + generateBlock.push(macro __glVersionRaw = $v{glVersion}); + generateBlock.push(macro __glVertexExtensions = $v{glVertexExtensions}); + generateBlock.push(macro __glFragmentExtensions = $v{glFragmentExtensions}); + if (glVertexSource != null) generateBlock.push(macro __glVertexSourceRaw = $v{glVertexSource}); + if (glFragmentSource != null) generateBlock.push(macro __glFragmentSourceRaw = $v{glFragmentSource}); - for (field in fields) - { - switch (field.name) - { + var newBlock:Array; + for (field in fields) { + switch (field.name) { case "new": - var block = switch (field.kind) - { + newBlock = switch (field.kind) { case FFun(f): if (f.expr == null) null; - switch (f.expr.expr) - { + switch (f.expr.expr) { case EBlock(e): e; default: null; } @@ -336,303 +194,147 @@ class ShaderMacro default: null; } - block.unshift(Context.parse("__isGenerated = true", pos)); - - if (glVertexSource != null) - { - block.unshift(macro if (__glVertexSource == null) - { - __glVertexSource = $v{glVertexSource}; - }); - } - - if (glFragmentSource != null) - { - block.unshift(macro if (__glFragmentSource == null) - { - __glFragmentSource = $v{glFragmentSource}; - }); - } - - if (glVertexSourceRaw != null) - { - block.unshift(macro if (__glVertexSourceRaw == null) - { - __glVertexSourceRaw = $v{glVertexSourceRaw}; - }); - } - - if (glFragmentSourceRaw != null) - { - block.unshift(macro if (__glFragmentSourceRaw == null) - { - __glFragmentSourceRaw = $v{glFragmentSourceRaw}; - }); - } - - if (glVertexBody != null) - { - block.unshift(macro if (__glVertexBodyRaw == null) - { - __glVertexBodyRaw = $v{glVertexBody}; - }); - } - - if (glFragmentBody != null) - { - block.unshift(macro if (__glFragmentBodyRaw == null) - { - __glFragmentBodyRaw = $v{glFragmentBody}; - }); - } - - if (glVertexHeader != null) - { - block.unshift(macro if (__glVertexHeaderRaw == null) - { - __glVertexHeaderRaw = $v{glVertexHeader}; - }); - } - - if (glFragmentHeader != null) - { - block.unshift(macro if (__glFragmentHeaderRaw == null) - { - __glFragmentHeaderRaw = $v{glFragmentHeader}; - }); - } - - if (glVertexExtensions != null) - { - block.unshift(macro if (__glVertexExtensions == null) - { - __glVertexExtensions = $v{glVertexExtensions}; - }); - } - - if (glFragmentExtensions != null) - { - block.unshift(macro if (__glFragmentExtensions == null) - { - __glFragmentExtensions = $v{glFragmentExtensions}; - }); - } - - if (glVersion != null) - { - block.unshift(macro if (__glVersion == null) - { - __glVersion = $v{glVersion}; - }); - } - - block.push(Context.parse("__initGL ()", pos)); - + break; default: } } - fields = fields.concat(uniqueFields); - } - - return fields; - } - - private static inline function getDefaultGLVersion():String - { - // Specify the default glVersion. - // We can use compile defines to guess the value that prevents crashes in the majority of cases. - return #if (android) "100" #elseif (web) "100" #elseif (mac) "120" #elseif (desktop) "150" #else "100" #end; - } - - /** - * Attempt to migrate GLSL code from the current (old) GLSL shader format to the specified (newer) one. - * @param source The source to convert. - * @param version The version to convert to. - * @param isFragment Whether the source is a fragment shader. False if it is a vertex shader. - * @return The converted source. - */ - private static function processGLSLText(source:String, glVersion:String, isFragment:Bool) - { - if (glVersion == "" || glVersion == null) return processGLSLText(source, getDefaultGLVersion(), isFragment); - - var attributeKeyword:EReg = ~/\battribute\s+([A-Za-z0-9_]+)\s+([A-Za-z0-9_]+)/g; - var varyingKeyword:EReg = ~/\bvarying\s+(?:lowp|mediump|highp\s+)?([A-Za-z0-9_]+)\s+([A-Za-z0-9_]+)/g; - var texture2DKeyword:EReg = ~/\btexture2D\b/g; - var glFragColorKeyword:EReg = ~/\bgl_FragColor\b/g; - var glVersionCleaner:EReg = ~/\b(\d+)\s*(?:core|es|compatibility)\b/g; - - switch (glVersionCleaner.replace(glVersion, '$1')) - { - case "300", "310", "320", "330", "400", "410", "420", "430", "440", "450", "460": - var result = source; - - if (isFragment) - { - result = varyingKeyword.replace(result, "in $1 $2"); - } - else - { - result = attributeKeyword.replace(result, "in $1 $2"); - result = varyingKeyword.replace(result, "out $1 $2"); - } - - result = texture2DKeyword.replace(result, "texture"); - result = glFragColorKeyword.replace(result, "openfl_FragColor"); - - return result; - default: - return source; - } - } - - private static function buildGLSLHeaders(glVersion:String):String - { - var glVersionCleaner:EReg = ~/\b(\d+)\s*(?:core|es|compatibility)\b/g; + if (newBlock == null) { + fields.push({ + name: "new", + access: [], + kind: FFun({args: [], expr: {pos: pos, expr: EBlock(newBlock = [macro super()])}}), + pos: pos + }); + } - switch (glVersionCleaner.replace(glVersion, '$1')) - { - case "300", "310", "320", "330", "400", "410", "420", "430", "440", "450", "460": - return "out vec4 openfl_FragColor;\n"; - default: - return ""; + for (e in paramBlock) newBlock.unshift(e); + newBlock.unshift(macro if (__data == null) __data = cast new openfl.display.ShaderData(null)); + newBlock.unshift(macro if (!__isGenerated) $b{generateBlock}); } - } - private static function buildGLSLExtensions(glExtensions:Array<{name:String, behavior:String}>, glVersion:String, - isFragment:Bool):Array<{name:String, behavior:String}> - { - return glExtensions; + return fields; } - private static function processFields(source:String, storageType:String, fields:Array, pos:Position):Void + private static function processFields(source:String, storageType:String, fieldNames:Map, fields:Array, + paramBlock:Array, pos:Position) { if (source == null) return; - var lastMatch = 0, position, regex, field:Field, name, type; - - if (storageType == "uniform") - { - regex = ~/uniform ([A-Za-z0-9]+) ([A-Za-z0-9_]+)/; - } - else if (storageType == "in") - { - regex = ~/in ([A-Za-z0-9]+) ([A-Za-z0-9_]+)/; - } - else + var isUniform = storageType == "uniform"; + var regex:EReg = switch (storageType) { - regex = ~/attribute ([A-Za-z0-9]+) ([A-Za-z0-9_]+)/; + case "uniform": ~/\buniform\s+([A-Za-z0-9_]+)\s+([A-Za-z0-9_]+)(?:\s*)?(?:\[(\w+)\])?\s*(?:=)?\s*(.+?(?=;))?/gu; + case "in": ~/\bin\s+([A-Za-z0-9_]+)\s+([A-Za-z0-9_]+)(?:\s*)?(?:\[(\w+)\])?/gu; + case "attribute": ~/\battribute\s+([A-Za-z0-9_]+)\s+([A-Za-z0-9_]+)(?:\s*)?(?:\[(\w+)\])?/gu; + default: throw "Unknown storageType " + storageType; } - var fieldAccess:Access; + var name, type:openfl.display.ShaderParameterType, isSampler:Bool, arrayLength:Null, size:Int, defaultAssign:Null; + var field:Field, fieldAccess:Access, fieldMeta:Metadata, fieldType:ComplexType; + var lastMatch = 0, position; while (regex.matchSub(source, lastMatch)) { - type = regex.matched(1); name = regex.matched(2); - - if (StringTools.startsWith(name, "gl_")) + if (fieldNames.exists(name) || StringTools.startsWith(name, "gl_")) { + position = regex.matchedPos(); + lastMatch = position.pos + position.len; continue; } - if (StringTools.startsWith(name, "openfl_")) - { - fieldAccess = APrivate; - } - else - { - fieldAccess = APublic; - } + if (regex.matched(3) == null) arrayLength = 0; + else if ((arrayLength = Std.parseInt(regex.matched(3))) == null) arrayLength = 1; - if (StringTools.startsWith(type, "sampler")) + if (StringTools.startsWith(regex.matched(1), "sampler")) { - field = { - name: name, - meta: [], - access: [fieldAccess], - kind: FVar(macro :openfl.display.ShaderInput), - pos: pos - }; + isSampler = true; + type = null; + fieldType = macro :openfl.display.ShaderInput; } else { - var parameterType:openfl.display.ShaderParameterType = switch (type) + isSampler = false; + type = switch (regex.matched(1)) { - case "bool": BOOL; - case "double", "float": FLOAT; - case "int", "uint": INT; - case "bvec2": BOOL2; - case "bvec3": BOOL3; - case "bvec4": BOOL4; - case "ivec2", "uvec2": INT2; - case "ivec3", "uvec3": INT3; - case "ivec4", "uvec4": INT4; - case "vec2", "dvec2": FLOAT2; - case "vec3", "dvec3": FLOAT3; - case "vec4", "dvec4": FLOAT4; - case "mat2", "mat2x2": MATRIX2X2; - case "mat2x3": MATRIX2X3; - case "mat2x4": MATRIX2X4; - case "mat3x2": MATRIX3X2; - case "mat3", "mat3x3": MATRIX3X3; - case "mat3x4": MATRIX3X4; - case "mat4x2": MATRIX4X2; - case "mat4x3": MATRIX4X3; - case "mat4", "mat4x4": MATRIX4X4; + case "bool": arrayLength != 0 ? BOOLV : BOOL; + case "double", "float": arrayLength != 0 ? FLOATV : FLOAT; + case "int", "uint": arrayLength != 0 ? INTV : INT; + case "bvec2": arrayLength != 0 ? BOOL2V : BOOL2; + case "bvec3": arrayLength != 0 ? BOOL3V : BOOL3; + case "bvec4": arrayLength != 0 ? BOOL4V : BOOL4; + case "ivec2", "uvec2": arrayLength != 0 ? INT2V : INT2; + case "ivec3", "uvec3": arrayLength != 0 ? INT3V : INT3; + case "ivec4", "uvec4": arrayLength != 0 ? INT4V : INT4; + case "vec2", "dvec2": arrayLength != 0 ? FLOAT2V : FLOAT2; + case "vec3", "dvec3": arrayLength != 0 ? FLOAT3V : FLOAT3; + case "vec4", "dvec4": arrayLength != 0 ? FLOAT4V : FLOAT4; + case "mat2", "mat2x2": arrayLength != 0 ? MATRIX2X2V : MATRIX2X2; + case "mat2x3": arrayLength != 0 ? MATRIX2X3V : MATRIX2X3; + case "mat2x4": arrayLength != 0 ? MATRIX2X4V : MATRIX2X4; + case "mat3x2": arrayLength != 0 ? MATRIX3X2V : MATRIX3X2; + case "mat3", "mat3x3": arrayLength != 0 ? MATRIX3X3V : MATRIX3X3; + case "mat3x4": arrayLength != 0 ? MATRIX3X4V : MATRIX3X4; + case "mat4x2": arrayLength != 0 ? MATRIX4X2V : MATRIX4X2; + case "mat4x3": arrayLength != 0 ? MATRIX4X3V : MATRIX4X3; + case "mat4", "mat4x4": arrayLength != 0 ? MATRIX4X4V : MATRIX4X4; default: null; } - switch (parameterType) + switch (type) { - case BOOL, BOOL2, BOOL3, BOOL4: - field = { - name: name, - meta: [{name: ":keep", pos: pos}], - access: [fieldAccess], - kind: FVar(macro :openfl.display.ShaderParameter), - pos: pos - }; - - case INT, INT2, INT3, INT4: - field = { - name: name, - meta: [{name: ":keep", pos: pos}], - access: [fieldAccess], - kind: FVar(macro :openfl.display.ShaderParameter), - pos: pos - }; + case BOOL, BOOL2, BOOL3, BOOL4, BOOLV, BOOL2V, BOOL3V, BOOL4V: + fieldType = macro :openfl.display.ShaderParameter; + + case INT, INT2, INT3, INT4, INTV, INT2V, INT3V, INT4V: + fieldType = macro :openfl.display.ShaderParameter; default: - field = { - name: name, - meta: [{name: ":keep", pos: pos}], - access: [fieldAccess], - kind: FVar(macro :openfl.display.ShaderParameter), - pos: pos - }; + fieldType = macro :openfl.display.ShaderParameter; } } if (StringTools.startsWith(name, "openfl_")) { - field.meta = [ + fieldMeta = [ {name: ":keep", pos: pos}, {name: ":dox", params: [macro hide], pos: pos}, {name: ":noCompletion", pos: pos}, {name: ":allow", params: [macro openfl.display._internal], pos: pos} ]; + fieldAccess = APrivate; } else { - field.meta = [{name: ":keep", pos: pos}]; + fieldMeta = [{name: ":keep", pos: pos}]; + fieldAccess = APublic; } + field = { + name: name, + meta: fieldMeta, + access: [fieldAccess], + kind: FVar(fieldType), + pos: pos + }; + fields.push(field); + fieldNames.set(name, true); + + size = arrayLength == 0 ? 1 : arrayLength; + defaultAssign = isUniform ? regex.matched(4) : null; + if (defaultAssign != null) { + paramBlock.push(macro __registerParameter($v{name}, cast $v{type}, $v{isSampler}, $v{size}, null, $v{isUniform}, + __getParameterDefault($v{defaultAssign}, cast $v{type}, $v{isSampler}))); + } + else { + paramBlock.push(macro __registerParameter($v{name}, cast $v{type}, $v{isSampler}, $v{size}, null, $v{isUniform}, null)); + } position = regex.matchedPos(); lastMatch = position.pos + position.len; } } } -#end +#end \ No newline at end of file