소스 검색

[ts][player] Added user defined global and per animation viewport. Viewports can also have padding.

badlogic 6 년 전
부모
커밋
f6eb468d32
5개의 변경된 파일234개의 추가작업 그리고 77개의 파일을 삭제
  1. 17 14
      spine-ts/build/spine-widget.d.ts
  2. 89 18
      spine-ts/build/spine-widget.js
  3. 0 0
      spine-ts/build/spine-widget.js.map
  4. 12 3
      spine-ts/widget/example/player-test.html
  5. 116 42
      spine-ts/widget/src/Player.ts

+ 17 - 14
spine-ts/build/spine-widget.d.ts

@@ -1683,6 +1683,16 @@ declare module spine.webgl {
     }
 }
 declare module spine {
+    interface Viewport {
+        x: number;
+        y: number;
+        width: number;
+        height: number;
+        padLeft: string | number;
+        padRight: string | number;
+        padTop: string | number;
+        padBottom: string | number;
+    }
     interface SpinePlayerConfig {
         jsonUrl: string;
         atlasUrl: string;
@@ -1708,20 +1718,12 @@ declare module spine {
             y: number;
             width: number;
             height: number;
-            padLeft: string;
-            padRight: string;
-            padTop: string;
-            padBottom: string;
-            animations: Map<{
-                x: number;
-                y: number;
-                width: number;
-                height: number;
-                padLeft: string;
-                padRight: string;
-                padTop: string;
-                padBottom: string;
-            }>;
+            padLeft: string | number;
+            padRight: string | number;
+            padTop: string | number;
+            padBottom: string | number;
+            animations: Map<Viewport>;
+            debugRender: boolean;
         };
         alpha: boolean;
         backgroundColor: string;
@@ -1779,6 +1781,7 @@ declare module spine {
         private play();
         private pause();
         private setAnimation(animation);
+        private percentageToWorldUnit(size, percentageOrAbsolute);
         private calculateAnimationViewport(animationName);
     }
 }

+ 89 - 18
spine-ts/build/spine-widget.js

@@ -9854,7 +9854,12 @@ var spine;
                     this.animationState.apply(this.skeleton);
                 }
                 this.skeleton.updateWorldTransform();
-                var viewport = this.currentViewport;
+                var viewport = {
+                    x: this.currentViewport.x - this.currentViewport.padLeft,
+                    y: this.currentViewport.y - this.currentViewport.padBottom,
+                    width: this.currentViewport.width + this.currentViewport.padLeft + this.currentViewport.padRight,
+                    height: this.currentViewport.height + this.currentViewport.padBottom + this.currentViewport.padTop
+                };
                 var viewportSize = this.scale(viewport.width, viewport.height, this.canvas.width, this.canvas.height);
                 this.sceneRenderer.camera.zoom = viewport.width / viewportSize.x;
                 this.sceneRenderer.camera.position.x = viewport.x + viewport.width / 2;
@@ -9892,6 +9897,10 @@ var spine;
                     this.sceneRenderer.circle(false, skeleton.x + bone.worldX, skeleton.y + bone.worldY, 20, colorOuter);
                 }
                 gl.lineWidth(1);
+                if (this.config.viewport.debugRender) {
+                    this.sceneRenderer.rect(false, this.currentViewport.x, this.currentViewport.y, this.currentViewport.width, this.currentViewport.height, spine.Color.GREEN);
+                    this.sceneRenderer.rect(false, viewport.x, viewport.y, viewport.width, viewport.height, spine.Color.RED);
+                }
                 this.sceneRenderer.end();
                 this.sceneRenderer.camera.zoom = 0;
             }
@@ -9956,6 +9965,25 @@ var spine;
                 this.skeleton.setSkinByName(this.config.skin);
                 this.skeleton.setSlotsToSetupPose();
             }
+            if (!this.config.viewport) {
+                this.config.viewport = {
+                    animations: {},
+                    debugRender: false
+                };
+            }
+            if (typeof this.config.viewport.debugRender === "undefined")
+                this.config.viewport.debugRender = false;
+            if (!this.config.viewport.animations) {
+                this.config.viewport.animations = {};
+            }
+            else {
+                Object.getOwnPropertyNames(this.config.viewport.animations).forEach(function (animation) {
+                    if (!skeletonData.findAnimation(animation)) {
+                        _this.showError("Error: animation '" + animation + "' for which a viewport was specified does not exist in skeleton.");
+                        return;
+                    }
+                });
+            }
             if (this.config.animations && this.config.animations.length > 0) {
                 this.config.animations.forEach(function (animation) {
                     if (!_this.skeleton.data.findAnimation(animation)) {
@@ -9988,18 +10016,6 @@ var spine;
                     _this.playTime = time;
                 };
             }
-            if (!this.config.viewport || !this.config.viewport.x || !this.config.viewport.y || !this.config.viewport.width || !this.config.viewport.height) {
-                this.config.viewport = {
-                    x: 0,
-                    y: 0,
-                    width: 0,
-                    height: 0,
-                    padLeft: "0",
-                    padRight: "0",
-                    padTop: "0",
-                    padBottom: "0"
-                };
-            }
             this.setupInput();
             if (skeletonData.skins.length == 1)
                 this.skinButton.classList.add("spine-player-hidden");
@@ -10112,11 +10128,66 @@ var spine;
         };
         SpinePlayer.prototype.setAnimation = function (animation) {
             this.previousViewport = this.currentViewport;
-            this.currentViewport = this.calculateAnimationViewport(animation);
+            var animViewport = this.calculateAnimationViewport(animation);
+            var viewport = {
+                x: animViewport.x,
+                y: animViewport.y,
+                width: animViewport.width,
+                height: animViewport.height,
+                padLeft: "10%",
+                padRight: "10%",
+                padTop: "10%",
+                padBottom: "10%"
+            };
+            var globalViewport = this.config.viewport;
+            if (typeof globalViewport.x !== "undefined" && typeof globalViewport.y !== "undefined" && typeof globalViewport.width !== "undefined" && typeof globalViewport.height !== "undefined") {
+                viewport.x = globalViewport.x;
+                viewport.y = globalViewport.y;
+                viewport.width = globalViewport.width;
+                viewport.height = globalViewport.height;
+            }
+            if (typeof globalViewport.padLeft !== "undefined")
+                viewport.padLeft = globalViewport.padLeft;
+            if (typeof globalViewport.padRight !== "undefined")
+                viewport.padRight = globalViewport.padRight;
+            if (typeof globalViewport.padTop !== "undefined")
+                viewport.padTop = globalViewport.padTop;
+            if (typeof globalViewport.padBottom !== "undefined")
+                viewport.padBottom = globalViewport.padBottom;
+            var userAnimViewport = this.config.viewport.animations[animation];
+            if (userAnimViewport) {
+                if (typeof userAnimViewport.x !== "undefined" && typeof userAnimViewport.y !== "undefined" && typeof userAnimViewport.width !== "undefined" && typeof userAnimViewport.height !== "undefined") {
+                    viewport.x = userAnimViewport.x;
+                    viewport.y = userAnimViewport.y;
+                    viewport.width = userAnimViewport.width;
+                    viewport.height = userAnimViewport.height;
+                }
+                if (typeof userAnimViewport.padLeft !== "undefined")
+                    viewport.padLeft = userAnimViewport.padLeft;
+                if (typeof userAnimViewport.padRight !== "undefined")
+                    viewport.padRight = userAnimViewport.padRight;
+                if (typeof userAnimViewport.padTop !== "undefined")
+                    viewport.padTop = userAnimViewport.padTop;
+                if (typeof userAnimViewport.padBottom !== "undefined")
+                    viewport.padBottom = userAnimViewport.padBottom;
+            }
+            viewport.padLeft = this.percentageToWorldUnit(viewport.width, viewport.padLeft);
+            viewport.padRight = this.percentageToWorldUnit(viewport.width, viewport.padRight);
+            viewport.padBottom = this.percentageToWorldUnit(viewport.height, viewport.padBottom);
+            viewport.padTop = this.percentageToWorldUnit(viewport.height, viewport.padTop);
+            this.currentViewport = viewport;
             this.animationState.clearTracks();
             this.skeleton.setToSetupPose();
             this.animationState.setAnimation(0, this.config.animation, true);
         };
+        SpinePlayer.prototype.percentageToWorldUnit = function (size, percentageOrAbsolute) {
+            if (typeof percentageOrAbsolute === "string") {
+                return size * parseFloat(percentageOrAbsolute.substr(0, percentageOrAbsolute.length - 1)) / 100;
+            }
+            else {
+                return percentageOrAbsolute;
+            }
+        };
         SpinePlayer.prototype.calculateAnimationViewport = function (animationName) {
             var animation = this.skeleton.data.findAnimation(animationName);
             this.animationState.clearTracks();
@@ -10145,10 +10216,10 @@ var spine;
             size.x = maxX - minX;
             size.y = maxY - minY;
             return {
-                x: offset.x + size.x / 2 - size.x / 2 * 1.2,
-                y: offset.y + size.y / 2 - size.y / 2 * 1.2,
-                width: size.x * 1.2,
-                height: size.y * 1.2
+                x: offset.x,
+                y: offset.y,
+                width: size.x,
+                height: size.y
             };
         };
         SpinePlayer.HOVER_COLOR_INNER = new spine.Color(0.478, 0, 0, 0.25);

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 0 - 0
spine-ts/build/spine-widget.js.map


+ 12 - 3
spine-ts/widget/example/player-test.html

@@ -22,10 +22,19 @@ body {
 		jsonUrl: "assets/spineboy-pro.json",
 		atlasUrl: "assets/spineboy-pma.atlas",
 		premultipliedAlpha: true,
-		animations: ["walk", "jump"],
-		controlBones: ["root"],
 		backgroundColor: "#cccccc",
-		fullScreenBackgroundColor: "#cc0000",
+		viewport: {
+			padLeft: "10%",
+			padRight: "10%",
+			padTop: "10%",
+			padBottom: "10%",
+			debugRender: true,
+			animations: {
+				"jump": {
+					padTop: "-20%"
+				}
+			}
+		}
 	});
 </script>
 </body>

+ 116 - 42
spine-ts/widget/src/Player.ts

@@ -29,6 +29,17 @@
  *****************************************************************************/
 
  module spine {
+	export interface Viewport {
+		x: number,
+		y: number,
+		width: number,
+		height: number,
+		padLeft: string | number
+		padRight: string | number
+		padTop: string | number
+		padBottom: string | number
+	}
+
 	export interface SpinePlayerConfig {
 		/* the URL of the skeleton .json file */
 		jsonUrl: string
@@ -75,20 +86,12 @@
 			y: number
 			width: number
 			height: number
-			padLeft: string
-			padRight: string
-			padTop: string
-			padBottom: string
-			animations: Map<{
-				x: number,
-				y: number,
-				width: number,
-				height: number,
-				padLeft: string,
-				padRight: string,
-				padTop: string,
-				padBottom: string,
-			}>
+			padLeft: string | number
+			padRight: string | number
+			padTop: string | number
+			padBottom: string | number
+			animations: Map<Viewport>
+			debugRender: boolean
 		}
 
 		/* Optional: whether the canvas should be transparent. Default: false. */
@@ -270,13 +273,6 @@
 		}
 	}
 
-	interface Viewport {
-		x: number
-		y: number
-		width: number
-		height: number
-	}
-
 	export class SpinePlayer {
 		static HOVER_COLOR_INNER = new spine.Color(0.478, 0, 0, 0.25);
 		static HOVER_COLOR_OUTER = new spine.Color(1, 1, 1, 1);
@@ -700,7 +696,13 @@
 
 				this.skeleton.updateWorldTransform();
 
-				let viewport = this.currentViewport;
+				let viewport = {
+					x: this.currentViewport.x - (this.currentViewport.padLeft as number),
+					y: this.currentViewport.y - (this.currentViewport.padBottom as number),
+					width: this.currentViewport.width + (this.currentViewport.padLeft as number) + (this.currentViewport.padRight as number),
+					height: this.currentViewport.height + (this.currentViewport.padBottom as number) + (this.currentViewport.padTop as number)
+				}
+
 				let viewportSize = this.scale(viewport.width, viewport.height, this.canvas.width, this.canvas.height);
 
 				this.sceneRenderer.camera.zoom = viewport.width / viewportSize.x;
@@ -745,6 +747,12 @@
 				}
 				gl.lineWidth(1);
 
+				// Render the viewport bounds
+				if (this.config.viewport.debugRender) {
+					this.sceneRenderer.rect(false, this.currentViewport.x, this.currentViewport.y, this.currentViewport.width, this.currentViewport.height, Color.GREEN);
+					this.sceneRenderer.rect(false, viewport.x, viewport.y, viewport.width, viewport.height, Color.RED);
+				}
+
 				this.sceneRenderer.end();
 
 				this.sceneRenderer.camera.zoom = 0;
@@ -818,6 +826,27 @@
 				this.skeleton.setSlotsToSetupPose();
 			}
 
+			// Setup empty viewport if none is given and check
+			// if all animations for which viewports where given
+			// exist.
+			if (!this.config.viewport) {
+				(this.config.viewport as any) = {
+					animations: {},
+					debugRender: false
+				}
+			}
+			if (typeof this.config.viewport.debugRender === "undefined") this.config.viewport.debugRender = false;
+			if (!this.config.viewport.animations) {
+				this.config.viewport.animations = {};
+			} else {
+				Object.getOwnPropertyNames(this.config.viewport.animations).forEach((animation: string) => {
+					if (!skeletonData.findAnimation(animation)) {
+						this.showError(`Error: animation '${animation}' for which a viewport was specified does not exist in skeleton.`);
+						return;
+					}
+				});
+			}
+
 			// Setup the animations after viewport, so default bounds don't get messed up.
 			if (this.config.animations && this.config.animations.length > 0) {
 				this.config.animations.forEach(animation => {
@@ -855,20 +884,6 @@
 				}
 			}
 
-			// Setup viewport after skin is set
-			if (!this.config.viewport || !this.config.viewport.x || !this.config.viewport.y || !this.config.viewport.width || !this.config.viewport.height) {
-				this.config.viewport = {
-					x: 0,
-					y: 0,
-					width: 0,
-					height: 0,
-					padLeft: "0",
-					padRight: "0",
-					padTop: "0",
-					padBottom: "0"
-				}
-			}
-
 			// Setup the input processor and controllable bones
 			this.setupInput();
 
@@ -988,14 +1003,73 @@
 		}
 
 		private setAnimation (animation: string) {
+			// Determine viewport
 			this.previousViewport = this.currentViewport;
-			this.currentViewport = this.calculateAnimationViewport(animation);
+			let animViewport = this.calculateAnimationViewport(animation);
+
+			// The calculated animation viewport is the base
+			let viewport: Viewport = {
+				x: animViewport.x,
+				y: animViewport.y,
+				width: animViewport.width,
+				height: animViewport.height,
+				padLeft: "10%",
+				padRight: "10%",
+				padTop: "10%",
+				padBottom: "10%"
+			}
+
+			// Override with global viewport settings if they exist
+			let globalViewport = this.config.viewport;
+			if (typeof globalViewport.x !== "undefined" && typeof globalViewport.y !== "undefined" && typeof globalViewport.width !== "undefined" && typeof globalViewport.height !== "undefined") {
+				viewport.x = globalViewport.x;
+				viewport.y = globalViewport.y;
+				viewport.width = globalViewport.width;
+				viewport.height = globalViewport.height;
+			}
+			if (typeof globalViewport.padLeft !== "undefined") viewport.padLeft = globalViewport.padLeft;
+			if (typeof globalViewport.padRight !== "undefined") viewport.padRight = globalViewport.padRight;
+			if (typeof globalViewport.padTop !== "undefined") viewport.padTop = globalViewport.padTop;
+			if (typeof globalViewport.padBottom !== "undefined") viewport.padBottom = globalViewport.padBottom;
+
+			// Override with animation viewport settings given by user for final result.
+			let userAnimViewport = this.config.viewport.animations[animation];
+			if (userAnimViewport) {
+				if (typeof userAnimViewport.x !== "undefined" && typeof userAnimViewport.y !== "undefined" && typeof userAnimViewport.width !== "undefined" && typeof userAnimViewport.height !== "undefined") {
+					viewport.x = userAnimViewport.x;
+					viewport.y = userAnimViewport.y;
+					viewport.width = userAnimViewport.width;
+					viewport.height = userAnimViewport.height;
+				}
+				if (typeof userAnimViewport.padLeft !== "undefined") viewport.padLeft = userAnimViewport.padLeft;
+				if (typeof userAnimViewport.padRight !== "undefined") viewport.padRight = userAnimViewport.padRight;
+				if (typeof userAnimViewport.padTop !== "undefined") viewport.padTop = userAnimViewport.padTop;
+				if (typeof userAnimViewport.padBottom !== "undefined") viewport.padBottom = userAnimViewport.padBottom;
+			}
+
+			// Translate percentage paddings to world units
+			viewport.padLeft = this.percentageToWorldUnit(viewport.width, viewport.padLeft);
+			viewport.padRight = this.percentageToWorldUnit(viewport.width, viewport.padRight);
+			viewport.padBottom = this.percentageToWorldUnit(viewport.height, viewport.padBottom);
+			viewport.padTop = this.percentageToWorldUnit(viewport.height, viewport.padTop);
+
+			// Adjust x, y, width, and height by padding.
+			this.currentViewport = viewport;
+
 			this.animationState.clearTracks();
 			this.skeleton.setToSetupPose();
 			this.animationState.setAnimation(0, this.config.animation, true);
 		}
 
-		private calculateAnimationViewport (animationName: string): Viewport {
+		private percentageToWorldUnit(size: number, percentageOrAbsolute: string | number): number {
+			if (typeof percentageOrAbsolute === "string") {
+				return size * parseFloat(percentageOrAbsolute.substr(0, percentageOrAbsolute.length - 1)) / 100;
+			} else {
+				return percentageOrAbsolute;
+			}
+		}
+
+		private calculateAnimationViewport (animationName: string) {
 			let animation = this.skeleton.data.findAnimation(animationName);
 			this.animationState.clearTracks();
 			this.skeleton.setToSetupPose()
@@ -1028,10 +1102,10 @@
 			size.y = maxY - minY;
 
 			return {
-				x: offset.x + size.x / 2 - size.x / 2 * 1.2,
-				y: offset.y + size.y / 2 - size.y / 2 * 1.2,
-				width: size.x * 1.2,
-				height: size.y * 1.2
+				x: offset.x,
+				y: offset.y,
+				width: size.x,
+				height: size.y
 			};
 		}
 	}

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.