瀏覽代碼

[ts][webgl] Added VertexEffect, SwirlEffect and JitterEffect, and implemented it in WebGL SkeletonRenderer. SwirlEffect is a bit broken..

badlogic 8 年之前
父節點
當前提交
5aebd65c01

+ 33 - 2
spine-ts/build/spine-webgl.d.ts

@@ -962,6 +962,8 @@ declare module spine {
         static signum(value: number): number;
         static signum(value: number): number;
         static toInt(x: number): number;
         static toInt(x: number): number;
         static cbrt(x: number): number;
         static cbrt(x: number): number;
+        static randomTriangular(min: number, max: number): number;
+        static randomTriangularWith(min: number, max: number, mode: number): number;
     }
     }
     class Utils {
     class Utils {
         static SUPPORTS_TYPED_ARRAYS: boolean;
         static SUPPORTS_TYPED_ARRAYS: boolean;
@@ -1022,8 +1024,8 @@ declare module spine {
 declare module spine {
 declare module spine {
     interface VertexEffect {
     interface VertexEffect {
         begin(skeleton: Skeleton): void;
         begin(skeleton: Skeleton): void;
-        transform(): any;
-        end(): any;
+        transform(position: Vector2, uv: Vector2, light: Color, dark: Color): void;
+        end(): void;
     }
     }
 }
 }
 declare module spine {
 declare module spine {
@@ -1176,6 +1178,30 @@ declare module spine {
         computeWorldVertices(bone: Bone, worldVertices: ArrayLike<number>, offset: number, stride: number): void;
         computeWorldVertices(bone: Bone, worldVertices: ArrayLike<number>, offset: number, stride: number): void;
     }
     }
 }
 }
+declare module spine {
+    class JitterEffect implements VertexEffect {
+        jitterX: number;
+        jitterY: number;
+        constructor(jitterX: number, jitterY: number);
+        begin(skeleton: Skeleton): void;
+        transform(position: Vector2, uv: Vector2, light: Color, dark: Color): void;
+        end(): void;
+    }
+}
+declare module spine {
+    class SwirlEffect implements VertexEffect {
+        centerX: number;
+        centerY: number;
+        radius: number;
+        angle: number;
+        private worldX;
+        private worldY;
+        constructor(radius: number);
+        begin(skeleton: Skeleton): void;
+        transform(position: Vector2, uv: Vector2, light: Color, dark: Color): void;
+        end(): void;
+    }
+}
 declare module spine.webgl {
 declare module spine.webgl {
     class AssetManager extends spine.AssetManager {
     class AssetManager extends spine.AssetManager {
         constructor(context: ManagedWebGLRenderingContext | WebGLRenderingContext, pathPrefix?: string);
         constructor(context: ManagedWebGLRenderingContext | WebGLRenderingContext, pathPrefix?: string);
@@ -1547,6 +1573,7 @@ declare module spine.webgl {
     class SkeletonRenderer {
     class SkeletonRenderer {
         static QUAD_TRIANGLES: number[];
         static QUAD_TRIANGLES: number[];
         premultipliedAlpha: boolean;
         premultipliedAlpha: boolean;
+        vertexEffect: VertexEffect;
         private tempColor;
         private tempColor;
         private tempColor2;
         private tempColor2;
         private vertices;
         private vertices;
@@ -1554,6 +1581,10 @@ declare module spine.webgl {
         private twoColorTint;
         private twoColorTint;
         private renderable;
         private renderable;
         private clipper;
         private clipper;
+        private temp;
+        private temp2;
+        private temp3;
+        private temp4;
         constructor(context: ManagedWebGLRenderingContext, twoColorTint?: boolean);
         constructor(context: ManagedWebGLRenderingContext, twoColorTint?: boolean);
         draw(batcher: PolygonBatcher, skeleton: Skeleton): void;
         draw(batcher: PolygonBatcher, skeleton: Skeleton): void;
     }
     }

+ 141 - 19
spine-ts/build/spine-webgl.js

@@ -5747,6 +5747,16 @@ var spine;
             var y = Math.pow(Math.abs(x), 1 / 3);
             var y = Math.pow(Math.abs(x), 1 / 3);
             return x < 0 ? -y : y;
             return x < 0 ? -y : y;
         };
         };
+        MathUtils.randomTriangular = function (min, max) {
+            return MathUtils.randomTriangularWith(min, max, (min + max) * 0.5);
+        };
+        MathUtils.randomTriangularWith = function (min, max, mode) {
+            var u = Math.random();
+            var d = max - min;
+            if (u <= (mode - min) / d)
+                return min + Math.sqrt(u * d * (mode - min));
+            return max - Math.sqrt((1 - u) * d * (max - mode));
+        };
         return MathUtils;
         return MathUtils;
     }());
     }());
     MathUtils.PI = 3.1415927;
     MathUtils.PI = 3.1415927;
@@ -6317,6 +6327,62 @@ var spine;
     spine.RegionAttachment = RegionAttachment;
     spine.RegionAttachment = RegionAttachment;
 })(spine || (spine = {}));
 })(spine || (spine = {}));
 var spine;
 var spine;
+(function (spine) {
+    var JitterEffect = (function () {
+        function JitterEffect(jitterX, jitterY) {
+            this.jitterX = 0;
+            this.jitterY = 0;
+            this.jitterX = jitterX;
+            this.jitterY = jitterY;
+        }
+        JitterEffect.prototype.begin = function (skeleton) {
+        };
+        JitterEffect.prototype.transform = function (position, uv, light, dark) {
+            position.x += spine.MathUtils.randomTriangular(-this.jitterX, this.jitterY);
+            position.y += spine.MathUtils.randomTriangular(-this.jitterX, this.jitterY);
+        };
+        JitterEffect.prototype.end = function () {
+        };
+        return JitterEffect;
+    }());
+    spine.JitterEffect = JitterEffect;
+})(spine || (spine = {}));
+var spine;
+(function (spine) {
+    var SwirlEffect = (function () {
+        function SwirlEffect(radius) {
+            this.centerX = 0;
+            this.centerY = 0;
+            this.radius = 0;
+            this.angle = 0;
+            this.worldX = 0;
+            this.worldY = 0;
+            this.radius = radius;
+        }
+        SwirlEffect.prototype.begin = function (skeleton) {
+            this.worldX = skeleton.x + this.centerX;
+            this.worldY = skeleton.y + this.centerY;
+        };
+        SwirlEffect.prototype.transform = function (position, uv, light, dark) {
+            var radAngle = this.angle * spine.MathUtils.degreesToRadians;
+            var x = position.x - this.worldX;
+            var y = position.y - this.worldY;
+            var dist = Math.sqrt(x * x + y * y);
+            if (dist < this.radius) {
+                var theta = radAngle * (Math.pow(((this.radius - dist) / this.radius) - 1, 2) * (2 % 2 == 0 ? -1 : 1) + 1);
+                var cos = Math.cos(theta);
+                var sin = Math.sin(theta);
+                position.x = cos * x - sin * y + this.worldX;
+                position.y = sin * x + cos * y + this.worldY;
+            }
+        };
+        SwirlEffect.prototype.end = function () {
+        };
+        return SwirlEffect;
+    }());
+    spine.SwirlEffect = SwirlEffect;
+})(spine || (spine = {}));
+var spine;
 (function (spine) {
 (function (spine) {
     var webgl;
     var webgl;
     (function (webgl) {
     (function (webgl) {
@@ -8420,12 +8486,17 @@ var spine;
             function SkeletonRenderer(context, twoColorTint) {
             function SkeletonRenderer(context, twoColorTint) {
                 if (twoColorTint === void 0) { twoColorTint = true; }
                 if (twoColorTint === void 0) { twoColorTint = true; }
                 this.premultipliedAlpha = false;
                 this.premultipliedAlpha = false;
+                this.vertexEffect = null;
                 this.tempColor = new spine.Color();
                 this.tempColor = new spine.Color();
                 this.tempColor2 = new spine.Color();
                 this.tempColor2 = new spine.Color();
                 this.vertexSize = 2 + 2 + 4;
                 this.vertexSize = 2 + 2 + 4;
                 this.twoColorTint = false;
                 this.twoColorTint = false;
                 this.renderable = new Renderable(null, 0, 0);
                 this.renderable = new Renderable(null, 0, 0);
                 this.clipper = new spine.SkeletonClipping();
                 this.clipper = new spine.SkeletonClipping();
+                this.temp = new spine.Vector2();
+                this.temp2 = new spine.Vector2();
+                this.temp3 = new spine.Color();
+                this.temp4 = new spine.Color();
                 this.twoColorTint = twoColorTint;
                 this.twoColorTint = twoColorTint;
                 if (twoColorTint)
                 if (twoColorTint)
                     this.vertexSize += 4;
                     this.vertexSize += 4;
@@ -8436,6 +8507,10 @@ var spine;
                 var premultipliedAlpha = this.premultipliedAlpha;
                 var premultipliedAlpha = this.premultipliedAlpha;
                 var twoColorTint = this.twoColorTint;
                 var twoColorTint = this.twoColorTint;
                 var blendMode = null;
                 var blendMode = null;
+                var tempPos = this.temp;
+                var tempUv = this.temp2;
+                var tempLight = this.temp3;
+                var tempDark = this.temp4;
                 var renderable = this.renderable;
                 var renderable = this.renderable;
                 var uvs = null;
                 var uvs = null;
                 var triangles = null;
                 var triangles = null;
@@ -8510,28 +8585,75 @@ var spine;
                         }
                         }
                         else {
                         else {
                             var verts = renderable.vertices;
                             var verts = renderable.vertices;
-                            if (!twoColorTint) {
-                                for (var v = 2, u = 0, n_3 = renderable.numFloats; v < n_3; v += vertexSize, u += 2) {
-                                    verts[v] = finalColor.r;
-                                    verts[v + 1] = finalColor.g;
-                                    verts[v + 2] = finalColor.b;
-                                    verts[v + 3] = finalColor.a;
-                                    verts[v + 4] = uvs[u];
-                                    verts[v + 5] = uvs[u + 1];
+                            if (this.vertexEffect != null) {
+                                var vertexEffect = this.vertexEffect;
+                                if (!twoColorTint) {
+                                    for (var v = 0, u = 0, n_3 = renderable.numFloats; v < n_3; v += vertexSize, u += 2) {
+                                        tempPos.x = verts[v];
+                                        tempPos.y = verts[v + 1];
+                                        tempUv.x = uvs[u];
+                                        tempUv.y = uvs[u + 1];
+                                        tempLight.setFromColor(finalColor);
+                                        tempDark.set(0, 0, 0, 0);
+                                        vertexEffect.transform(tempPos, tempUv, tempLight, tempDark);
+                                        verts[v] = tempPos.x;
+                                        verts[v + 1] = tempPos.y;
+                                        verts[v + 2] = tempLight.r;
+                                        verts[v + 3] = tempLight.g;
+                                        verts[v + 4] = tempLight.b;
+                                        verts[v + 5] = tempLight.a;
+                                        verts[v + 6] = tempUv.x;
+                                        verts[v + 7] = tempUv.y;
+                                    }
+                                }
+                                else {
+                                    for (var v = 0, u = 0, n_4 = renderable.numFloats; v < n_4; v += vertexSize, u += 2) {
+                                        tempPos.x = verts[v];
+                                        tempPos.y = verts[v + 1];
+                                        tempUv.x = uvs[u];
+                                        tempUv.y = uvs[u + 1];
+                                        tempLight.setFromColor(finalColor);
+                                        tempDark.setFromColor(darkColor);
+                                        vertexEffect.transform(tempPos, tempUv, tempLight, tempDark);
+                                        verts[v] = tempPos.x;
+                                        verts[v + 1] = tempPos.y;
+                                        verts[v + 2] = tempLight.r;
+                                        verts[v + 3] = tempLight.g;
+                                        verts[v + 4] = tempLight.b;
+                                        verts[v + 5] = tempLight.a;
+                                        verts[v + 6] = tempUv.x;
+                                        verts[v + 7] = tempUv.y;
+                                        verts[v + 8] = tempDark.r;
+                                        verts[v + 9] = tempDark.g;
+                                        verts[v + 10] = tempDark.b;
+                                        verts[v + 11] = tempDark.a;
+                                    }
                                 }
                                 }
                             }
                             }
                             else {
                             else {
-                                for (var v = 2, u = 0, n_4 = renderable.numFloats; v < n_4; v += vertexSize, u += 2) {
-                                    verts[v] = finalColor.r;
-                                    verts[v + 1] = finalColor.g;
-                                    verts[v + 2] = finalColor.b;
-                                    verts[v + 3] = finalColor.a;
-                                    verts[v + 4] = uvs[u];
-                                    verts[v + 5] = uvs[u + 1];
-                                    verts[v + 6] = darkColor.r;
-                                    verts[v + 7] = darkColor.g;
-                                    verts[v + 8] = darkColor.b;
-                                    verts[v + 9] = darkColor.a;
+                                if (!twoColorTint) {
+                                    for (var v = 2, u = 0, n_5 = renderable.numFloats; v < n_5; v += vertexSize, u += 2) {
+                                        verts[v] = finalColor.r;
+                                        verts[v + 1] = finalColor.g;
+                                        verts[v + 2] = finalColor.b;
+                                        verts[v + 3] = finalColor.a;
+                                        verts[v + 4] = uvs[u];
+                                        verts[v + 5] = uvs[u + 1];
+                                    }
+                                }
+                                else {
+                                    for (var v = 2, u = 0, n_6 = renderable.numFloats; v < n_6; v += vertexSize, u += 2) {
+                                        verts[v] = finalColor.r;
+                                        verts[v + 1] = finalColor.g;
+                                        verts[v + 2] = finalColor.b;
+                                        verts[v + 3] = finalColor.a;
+                                        verts[v + 4] = uvs[u];
+                                        verts[v + 5] = uvs[u + 1];
+                                        verts[v + 6] = darkColor.r;
+                                        verts[v + 7] = darkColor.g;
+                                        verts[v + 8] = darkColor.b;
+                                        verts[v + 9] = darkColor.a;
+                                    }
                                 }
                                 }
                             }
                             }
                             var view = renderable.vertices.subarray(0, renderable.numFloats);
                             var view = renderable.vertices.subarray(0, renderable.numFloats);

文件差異過大導致無法顯示
+ 0 - 0
spine-ts/build/spine-webgl.js.map


+ 11 - 0
spine-ts/core/src/Utils.ts

@@ -158,6 +158,17 @@ module spine {
 			var y = Math.pow(Math.abs(x), 1/3);
 			var y = Math.pow(Math.abs(x), 1/3);
 			return x < 0 ? -y : y;
 			return x < 0 ? -y : y;
 		}
 		}
+
+		static randomTriangular (min: number, max: number): number {
+			return MathUtils.randomTriangularWith(min, max, (min + max) * 0.5);
+		}
+
+		static randomTriangularWith (min: number, max: number, mode: number): number {
+			let u = Math.random();
+			let d = max - min;
+			if (u <= (mode - min) / d) return min + Math.sqrt(u * d * (mode - min));
+			return max - Math.sqrt((1 - u) * d * (max - mode));
+		}
 	}
 	}
 
 
 	export class Utils {
 	export class Utils {

+ 37 - 0
spine-ts/core/src/VertexEffect.ts

@@ -0,0 +1,37 @@
+/******************************************************************************
+ * Spine Runtimes Software License v2.5
+ *
+ * Copyright (c) 2013-2016, Esoteric Software
+ * All rights reserved.
+ *
+ * You are granted a perpetual, non-exclusive, non-sublicensable, and
+ * non-transferable license to use, install, execute, and perform the Spine
+ * Runtimes software and derivative works solely for personal or internal
+ * use. Without the written permission of Esoteric Software (see Section 2 of
+ * the Spine Software License Agreement), you may not (a) modify, translate,
+ * adapt, or develop new applications using the Spine Runtimes or otherwise
+ * create derivative works or improvements of the Spine Runtimes or (b) remove,
+ * delete, alter, or obscure any trademarks or any copyright, trademark, patent,
+ * or other intellectual property or proprietary rights notices on or in the
+ * Software, including any copy thereof. Redistributions in binary or source
+ * form must include this license and terms.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF
+ * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+module spine {
+	export interface VertexEffect {
+		begin(skeleton: Skeleton): void;
+		transform(position: Vector2, uv: Vector2, light: Color, dark: Color): void;
+		end(): void;
+	}
+}

+ 52 - 0
spine-ts/core/src/vertexeffects/JitterEffect.ts

@@ -0,0 +1,52 @@
+/******************************************************************************
+ * Spine Runtimes Software License v2.5
+ *
+ * Copyright (c) 2013-2016, Esoteric Software
+ * All rights reserved.
+ *
+ * You are granted a perpetual, non-exclusive, non-sublicensable, and
+ * non-transferable license to use, install, execute, and perform the Spine
+ * Runtimes software and derivative works solely for personal or internal
+ * use. Without the written permission of Esoteric Software (see Section 2 of
+ * the Spine Software License Agreement), you may not (a) modify, translate,
+ * adapt, or develop new applications using the Spine Runtimes or otherwise
+ * create derivative works or improvements of the Spine Runtimes or (b) remove,
+ * delete, alter, or obscure any trademarks or any copyright, trademark, patent,
+ * or other intellectual property or proprietary rights notices on or in the
+ * Software, including any copy thereof. Redistributions in binary or source
+ * form must include this license and terms.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF
+ * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+module spine {
+	export class JitterEffect implements VertexEffect {
+		jitterX = 0;
+		jitterY = 0;
+
+		constructor (jitterX: number, jitterY: number) {
+			this.jitterX = jitterX;
+			this.jitterY = jitterY;
+		}
+
+		begin(skeleton: Skeleton): void {
+		}
+
+		transform(position: Vector2, uv: Vector2, light: Color, dark: Color): void {
+			position.x += MathUtils.randomTriangular(-this.jitterX, this.jitterY);
+			position.y += MathUtils.randomTriangular(-this.jitterX, this.jitterY);
+		}
+
+		end(): void {
+		}
+	}
+}

+ 67 - 0
spine-ts/core/src/vertexeffects/SwirlEffect.ts

@@ -0,0 +1,67 @@
+/******************************************************************************
+ * Spine Runtimes Software License v2.5
+ *
+ * Copyright (c) 2013-2016, Esoteric Software
+ * All rights reserved.
+ *
+ * You are granted a perpetual, non-exclusive, non-sublicensable, and
+ * non-transferable license to use, install, execute, and perform the Spine
+ * Runtimes software and derivative works solely for personal or internal
+ * use. Without the written permission of Esoteric Software (see Section 2 of
+ * the Spine Software License Agreement), you may not (a) modify, translate,
+ * adapt, or develop new applications using the Spine Runtimes or otherwise
+ * create derivative works or improvements of the Spine Runtimes or (b) remove,
+ * delete, alter, or obscure any trademarks or any copyright, trademark, patent,
+ * or other intellectual property or proprietary rights notices on or in the
+ * Software, including any copy thereof. Redistributions in binary or source
+ * form must include this license and terms.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF
+ * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+module spine {
+	export class SwirlEffect implements VertexEffect {
+
+		centerX = 0;
+		centerY = 0;
+		radius = 0;
+		angle = 0;
+		private worldX = 0;
+		private worldY = 0;
+
+		constructor (radius: number) {
+			this.radius = radius;
+		}
+
+		begin(skeleton: Skeleton): void {
+			this.worldX = skeleton.x + this.centerX;
+			this.worldY = skeleton.y + this.centerY;
+		}
+
+		transform(position: Vector2, uv: Vector2, light: Color, dark: Color): void {
+			let radAngle = this.angle * MathUtils.degreesToRadians;
+			let x = position.x - this.worldX;
+			let y = position.y - this.worldY;
+			let dist = Math.sqrt(x * x + y * y);
+			if (dist < this.radius) {
+				let theta = radAngle * (Math.pow(((this.radius - dist) / this.radius) - 1, 2) * (2 % 2 == 0 ? -1 : 1) + 1);
+				let cos = Math.cos(theta);
+				let sin = Math.sin(theta);
+				position.x = cos * x - sin * y + this.worldX;
+				position.y = sin * x + cos * y + this.worldY;
+			}
+		}
+
+		end(): void {
+		}
+	}
+}

+ 43 - 8
spine-ts/webgl/example/index.html

@@ -13,6 +13,8 @@
 <span>Skeleton:</span><select id="skeletonList"></select>
 <span>Skeleton:</span><select id="skeletonList"></select>
 <span>Animation:</span><select id="animationList"></select>
 <span>Animation:</span><select id="animationList"></select>
 <span>Skin:</span><select id="skinList"></select>
 <span>Skin:</span><select id="skinList"></select>
+<span>Vertex Effect:</span><select id="effectList"></select>
+<span>Debug:</span><input type="checkbox" id="debug">
 <div>
 <div>
 </center>
 </center>
 </body>
 </body>
@@ -29,7 +31,10 @@ var skeletonRenderer;
 var debugRenderer;
 var debugRenderer;
 var shapes;
 var shapes;
 var skeletons = {};
 var skeletons = {};
-var activeSkeleton = "vine";
+var activeSkeleton = "spineboy";
+var swirlEffect = new spine.SwirlEffect(0);
+var jitterEffect = new spine.JitterEffect(20, 20);
+var swirlTime = 0;
 
 
 function init () {
 function init () {
 	// Setup canvas and WebGL context. We pass alpha: false to canvas.getContext() so we don't use premultiplied alpha when
 	// Setup canvas and WebGL context. We pass alpha: false to canvas.getContext() so we don't use premultiplied alpha when
@@ -177,6 +182,14 @@ function setupUI () {
 		if (skeletonName === activeSkeleton) option.attr("selected", "selected");
 		if (skeletonName === activeSkeleton) option.attr("selected", "selected");
 		skeletonList.append(option);
 		skeletonList.append(option);
 	}
 	}
+	var effectList = $("#effectList");
+	var effects = ["None", "Swirl", "Jitter"];
+	for (var effect in effects) {
+		var effectName = effects[effect];
+		var option = $("<option></option>");
+		option.attr("value", effectName).text(effectName);
+		effectList.append(option);
+	}
 	var setupAnimationUI = function() {
 	var setupAnimationUI = function() {
 		var animationList = $("#animationList");
 		var animationList = $("#animationList");
 		animationList.empty();
 		animationList.empty();
@@ -244,6 +257,7 @@ function render () {
 	// Apply the animation state based on the delta time.
 	// Apply the animation state based on the delta time.
 	var state = skeletons[activeSkeleton].state;
 	var state = skeletons[activeSkeleton].state;
 	var skeleton = skeletons[activeSkeleton].skeleton;
 	var skeleton = skeletons[activeSkeleton].skeleton;
+	var bounds = skeletons[activeSkeleton].bounds;
 	var premultipliedAlpha = skeletons[activeSkeleton].premultipliedAlpha;
 	var premultipliedAlpha = skeletons[activeSkeleton].premultipliedAlpha;
 	state.update(delta);
 	state.update(delta);
 	state.apply(skeleton);
 	state.apply(skeleton);
@@ -256,6 +270,24 @@ function render () {
 
 
 	// Start the batch and tell the SkeletonRenderer to render the active skeleton.
 	// Start the batch and tell the SkeletonRenderer to render the active skeleton.
 	batcher.begin(shader);
 	batcher.begin(shader);
+
+	var effect = $("#effectList option:selected").text();
+	if (effect == "None") {
+		skeletonRenderer.vertexEffect = null;
+	} else if (effect == "Swirl") {
+		swirlTime += delta;
+		var percent = swirlTime % 2;
+		if (percent > 1) percent = 1 - (percent -1 );
+		// swirlEffect.angle = -60 + 120 * (perecent < 0.5 ? Math.pow(percent * 2, 2) / 2 : Math.pow((percent - 1) * 2, 2) / -2 + 1);
+		swirlEffect.angle = 360 * percent;
+		swirlEffect.centerX = 200; //bounds.offset.x + bounds.size.x / 2
+		swirlEffect.centerY = 200; //bounds.offset.y + bounds.size.y / 2
+		swirlEffect.radius = Math.sqrt(bounds.size.x * bounds.size.x + bounds.size.y * bounds.size.y);
+		skeletonRenderer.vertexEffect = swirlEffect;
+	} else if (effect == "Jitter") {
+		skeletonRenderer.vertexEffect = jitterEffect;
+	}
+
 	skeletonRenderer.premultipliedAlpha = premultipliedAlpha;
 	skeletonRenderer.premultipliedAlpha = premultipliedAlpha;
 	skeletonRenderer.draw(batcher, skeleton);
 	skeletonRenderer.draw(batcher, skeleton);
 	batcher.end();
 	batcher.end();
@@ -263,13 +295,16 @@ function render () {
 	shader.unbind();
 	shader.unbind();
 
 
 	// draw debug information
 	// draw debug information
-	debugShader.bind();
-	debugShader.setUniform4x4f(spine.webgl.Shader.MVP_MATRIX, mvp.values);
-	debugRenderer.premultipliedAlpha = premultipliedAlpha;
-	shapes.begin(debugShader);
-	debugRenderer.draw(shapes, skeleton);
-	shapes.end();
-	debugShader.unbind();
+	var debug = $('#debug').is(':checked');
+	if (debug) {
+		debugShader.bind();
+		debugShader.setUniform4x4f(spine.webgl.Shader.MVP_MATRIX, mvp.values);
+		debugRenderer.premultipliedAlpha = premultipliedAlpha;
+		shapes.begin(debugShader);
+		debugRenderer.draw(shapes, skeleton);
+		shapes.end();
+		debugShader.unbind();
+	}
 
 
 	requestAnimationFrame(render);
 	requestAnimationFrame(render);
 }
 }

+ 74 - 19
spine-ts/webgl/src/SkeletonRenderer.ts

@@ -37,6 +37,7 @@ module spine.webgl {
 		static QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0];
 		static QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0];
 
 
 		premultipliedAlpha = false;
 		premultipliedAlpha = false;
+		vertexEffect: VertexEffect = null;
 		private tempColor = new Color();
 		private tempColor = new Color();
 		private tempColor2 = new Color();
 		private tempColor2 = new Color();
 		private vertices:ArrayLike<number>;
 		private vertices:ArrayLike<number>;
@@ -44,6 +45,10 @@ module spine.webgl {
 		private twoColorTint = false;
 		private twoColorTint = false;
 		private renderable: Renderable = new Renderable(null, 0, 0);
 		private renderable: Renderable = new Renderable(null, 0, 0);
 		private clipper: SkeletonClipping = new SkeletonClipping();
 		private clipper: SkeletonClipping = new SkeletonClipping();
+		private temp = new Vector2();
+		private temp2 = new Vector2();
+		private temp3 = new Color();
+		private temp4 = new Color();
 
 
 		constructor (context: ManagedWebGLRenderingContext, twoColorTint: boolean = true) {
 		constructor (context: ManagedWebGLRenderingContext, twoColorTint: boolean = true) {
 			this.twoColorTint = twoColorTint;
 			this.twoColorTint = twoColorTint;
@@ -58,6 +63,11 @@ module spine.webgl {
 			let twoColorTint = this.twoColorTint;
 			let twoColorTint = this.twoColorTint;
 			let blendMode: BlendMode = null;
 			let blendMode: BlendMode = null;
 
 
+			let tempPos = this.temp;
+			let tempUv = this.temp2;
+			let tempLight = this.temp3;
+			let tempDark = this.temp4;
+
 			let renderable: Renderable = this.renderable;
 			let renderable: Renderable = this.renderable;
 			let uvs: ArrayLike<number> = null;
 			let uvs: ArrayLike<number> = null;
 			let triangles: Array<number> = null;
 			let triangles: Array<number> = null;
@@ -128,27 +138,72 @@ module spine.webgl {
 						batcher.draw(texture, clippedVertices, clippedTriangles);
 						batcher.draw(texture, clippedVertices, clippedTriangles);
 					} else {
 					} else {
 						let verts = renderable.vertices;
 						let verts = renderable.vertices;
-						if (!twoColorTint) {
-							for (let v = 2, u = 0, n = renderable.numFloats; v < n; v += vertexSize, u += 2) {
-								verts[v] = finalColor.r;
-								verts[v + 1] = finalColor.g;
-								verts[v + 2] = finalColor.b;
-								verts[v + 3] = finalColor.a;
-								verts[v + 4] = uvs[u];
-								verts[v + 5] = uvs[u + 1];
+						if (this.vertexEffect != null) {
+							let vertexEffect = this.vertexEffect;
+							if (!twoColorTint) {
+								for (let v = 0, u = 0, n = renderable.numFloats; v < n; v += vertexSize, u += 2) {
+									tempPos.x = verts[v];
+									tempPos.y = verts[v + 1];
+									tempUv.x = uvs[u];
+									tempUv.y = uvs[u + 1]
+									tempLight.setFromColor(finalColor);
+									tempDark.set(0, 0, 0, 0);
+									vertexEffect.transform(tempPos, tempUv, tempLight, tempDark);
+									verts[v] = tempPos.x;
+									verts[v + 1] = tempPos.y;
+									verts[v + 2] = tempLight.r;
+									verts[v + 3] = tempLight.g;
+									verts[v + 4] = tempLight.b;
+									verts[v + 5] = tempLight.a;
+									verts[v + 6] = tempUv.x;
+									verts[v + 7] = tempUv.y
+								}
+							} else {
+								for (let v = 0, u = 0, n = renderable.numFloats; v < n; v += vertexSize, u += 2) {
+									tempPos.x = verts[v];
+									tempPos.y = verts[v + 1];
+									tempUv.x = uvs[u];
+									tempUv.y = uvs[u + 1]
+									tempLight.setFromColor(finalColor);
+									tempDark.setFromColor(darkColor);
+									vertexEffect.transform(tempPos, tempUv, tempLight, tempDark);
+									verts[v] = tempPos.x;
+									verts[v + 1] = tempPos.y;
+									verts[v + 2] = tempLight.r;
+									verts[v + 3] = tempLight.g;
+									verts[v + 4] = tempLight.b;
+									verts[v + 5] = tempLight.a;
+									verts[v + 6] = tempUv.x;
+									verts[v + 7] = tempUv.y
+									verts[v + 8] = tempDark.r;
+									verts[v + 9] = tempDark.g;
+									verts[v + 10] = tempDark.b;
+									verts[v + 11] = tempDark.a;
+								}
 							}
 							}
 						} else {
 						} else {
-							for (let v = 2, u = 0, n = renderable.numFloats; v < n; v += vertexSize, u += 2) {
-								verts[v] = finalColor.r;
-								verts[v + 1] = finalColor.g;
-								verts[v + 2] = finalColor.b;
-								verts[v + 3] = finalColor.a;
-								verts[v + 4] = uvs[u];
-								verts[v + 5] = uvs[u + 1];
-								verts[v + 6] = darkColor.r;
-								verts[v + 7] = darkColor.g;
-								verts[v + 8] = darkColor.b;
-								verts[v + 9] = darkColor.a;
+							if (!twoColorTint) {
+								for (let v = 2, u = 0, n = renderable.numFloats; v < n; v += vertexSize, u += 2) {
+									verts[v] = finalColor.r;
+									verts[v + 1] = finalColor.g;
+									verts[v + 2] = finalColor.b;
+									verts[v + 3] = finalColor.a;
+									verts[v + 4] = uvs[u];
+									verts[v + 5] = uvs[u + 1];
+								}
+							} else {
+								for (let v = 2, u = 0, n = renderable.numFloats; v < n; v += vertexSize, u += 2) {
+									verts[v] = finalColor.r;
+									verts[v + 1] = finalColor.g;
+									verts[v + 2] = finalColor.b;
+									verts[v + 3] = finalColor.a;
+									verts[v + 4] = uvs[u];
+									verts[v + 5] = uvs[u + 1];
+									verts[v + 6] = darkColor.r;
+									verts[v + 7] = darkColor.g;
+									verts[v + 8] = darkColor.b;
+									verts[v + 9] = darkColor.a;
+								}
 							}
 							}
 						}
 						}
 						let view = (renderable.vertices as Float32Array).subarray(0, renderable.numFloats);
 						let view = (renderable.vertices as Float32Array).subarray(0, renderable.numFloats);

部分文件因文件數量過多而無法顯示