mirror of
https://github.com/photonstorm/phaser
synced 2024-12-19 09:34:02 +00:00
3634 lines
116 KiB
HTML
3634 lines
116 KiB
HTML
<!DOCTYPE html>
|
|
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>Phaser Source: d:/wamp/www/phaser/src/pixi/extras/Spine.js</title>
|
|
|
|
<!--[if lt IE 9]>
|
|
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
|
<![endif]-->
|
|
|
|
<link type="text/css" rel="stylesheet" href="styles/default.css">
|
|
|
|
<link type="text/css" rel="stylesheet" href="styles/sunlight.default.css">
|
|
|
|
|
|
<link type="text/css" rel="stylesheet" href="styles/site.cerulean.css">
|
|
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<div class="container-fluid">
|
|
<div class="navbar navbar-fixed-top navbar-inverse">
|
|
<div style="position: absolute; width: 143px; height: 31px; right: 10px; top: 10px; z-index: 1050"><a href="http://phaser.io"><img src="img/phaser.png" border="0" /></a></div>
|
|
<div class="navbar-inner">
|
|
<a class="brand" href="index.html">Phaser API</a>
|
|
<ul class="nav">
|
|
|
|
|
|
<li class="dropdown">
|
|
<a href="namespaces.list.html" class="dropdown-toggle" data-toggle="dropdown">Namespaces<b
|
|
class="caret"></b></a>
|
|
|
|
<ul class="dropdown-menu ">
|
|
|
|
<li class="class-depth-0">
|
|
<a href="Phaser.html">Phaser</a>
|
|
</li>
|
|
|
|
<li class="class-depth-0">
|
|
<a href="PIXI.html">PIXI</a>
|
|
</li>
|
|
|
|
|
|
</ul>
|
|
</li>
|
|
|
|
<li class="dropdown">
|
|
<a href="classes.list.html" class="dropdown-toggle" data-toggle="dropdown">Classes<b
|
|
class="caret"></b></a>
|
|
|
|
<ul class="dropdown-menu ">
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Animation.html">Animation</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.AnimationManager.html">AnimationManager</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.AnimationParser.html">AnimationParser</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.ArrayList.html">ArrayList</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.ArraySet.html">ArraySet</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.ArrayUtils.html">ArrayUtils</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.AudioSprite.html">AudioSprite</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.BitmapData.html">BitmapData</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.BitmapText.html">BitmapText</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Button.html">Button</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Cache.html">Cache</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Camera.html">Camera</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Canvas.html">Canvas</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Circle.html">Circle</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Color.html">Color</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Device.html">Device</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.DOM.html">DOM</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Easing.html">Easing</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Ellipse.html">Ellipse</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Events.html">Events</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Filter.html">Filter</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.FlexGrid.html">FlexGrid</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.FlexLayer.html">FlexLayer</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Frame.html">Frame</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.FrameData.html">FrameData</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Game.html">Game</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.GameObjectCreator.html">GameObjectCreator</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.GameObjectFactory.html">GameObjectFactory</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Gamepad.html">Gamepad</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.GamepadButton.html">GamepadButton</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Graphics.html">Graphics</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Group.html">Group</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Image.html">Image</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Input.html">Input</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.InputHandler.html">InputHandler</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Key.html">Key</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Keyboard.html">Keyboard</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Line.html">Line</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.LinkedList.html">LinkedList</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Loader.html">Loader</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.LoaderParser.html">LoaderParser</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Math.html">Math</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Mouse.html">Mouse</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.MSPointer.html">MSPointer</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Net.html">Net</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Particle.html">Particle</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Particles.html">Particles</a>
|
|
</li>
|
|
|
|
<li class="class-depth-2">
|
|
<a href="Phaser.Particles.Arcade.html">Arcade</a>
|
|
</li>
|
|
|
|
<li class="class-depth-3">
|
|
<a href="Phaser.Particles.Arcade.Emitter.html">Emitter</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Physics.html">Physics</a>
|
|
</li>
|
|
|
|
<li class="class-depth-2">
|
|
<a href="Phaser.Physics.Arcade.html">Arcade</a>
|
|
</li>
|
|
|
|
<li class="class-depth-3">
|
|
<a href="Phaser.Physics.Arcade.Body.html">Body</a>
|
|
</li>
|
|
|
|
<li class="class-depth-2">
|
|
<a href="Phaser.Physics.Ninja.html">Ninja</a>
|
|
</li>
|
|
|
|
<li class="class-depth-3">
|
|
<a href="Phaser.Physics.Ninja.AABB.html">AABB</a>
|
|
</li>
|
|
|
|
<li class="class-depth-3">
|
|
<a href="Phaser.Physics.Ninja.Body.html">Body</a>
|
|
</li>
|
|
|
|
<li class="class-depth-3">
|
|
<a href="Phaser.Physics.Ninja.Circle.html">Circle</a>
|
|
</li>
|
|
|
|
<li class="class-depth-3">
|
|
<a href="Phaser.Physics.Ninja.Tile.html">Tile</a>
|
|
</li>
|
|
|
|
<li class="class-depth-2">
|
|
<a href="Phaser.Physics.P2.html">P2</a>
|
|
</li>
|
|
|
|
<li class="class-depth-3">
|
|
<a href="Phaser.Physics.P2.Body.html">Body</a>
|
|
</li>
|
|
|
|
<li class="class-depth-3">
|
|
<a href="Phaser.Physics.P2.BodyDebug.html">BodyDebug</a>
|
|
</li>
|
|
|
|
<li class="class-depth-3">
|
|
<a href="Phaser.Physics.P2.CollisionGroup.html">CollisionGroup</a>
|
|
</li>
|
|
|
|
<li class="class-depth-3">
|
|
<a href="Phaser.Physics.P2.ContactMaterial.html">ContactMaterial</a>
|
|
</li>
|
|
|
|
<li class="class-depth-3">
|
|
<a href="Phaser.Physics.P2.DistanceConstraint.html">DistanceConstraint</a>
|
|
</li>
|
|
|
|
<li class="class-depth-3">
|
|
<a href="Phaser.Physics.P2.FixtureList.html">FixtureList</a>
|
|
</li>
|
|
|
|
<li class="class-depth-3">
|
|
<a href="Phaser.Physics.P2.GearConstraint.html">GearConstraint</a>
|
|
</li>
|
|
|
|
<li class="class-depth-3">
|
|
<a href="Phaser.Physics.P2.InversePointProxy.html">InversePointProxy</a>
|
|
</li>
|
|
|
|
<li class="class-depth-3">
|
|
<a href="Phaser.Physics.P2.LockConstraint.html">LockConstraint</a>
|
|
</li>
|
|
|
|
<li class="class-depth-3">
|
|
<a href="Phaser.Physics.P2.Material.html">Material</a>
|
|
</li>
|
|
|
|
<li class="class-depth-3">
|
|
<a href="Phaser.Physics.P2.PointProxy.html">PointProxy</a>
|
|
</li>
|
|
|
|
<li class="class-depth-3">
|
|
<a href="Phaser.Physics.P2.PrismaticConstraint.html">PrismaticConstraint</a>
|
|
</li>
|
|
|
|
<li class="class-depth-3">
|
|
<a href="Phaser.Physics.P2.RevoluteConstraint.html">RevoluteConstraint</a>
|
|
</li>
|
|
|
|
<li class="class-depth-3">
|
|
<a href="Phaser.Physics.P2.RotationalSpring.html">RotationalSpring</a>
|
|
</li>
|
|
|
|
<li class="class-depth-3">
|
|
<a href="Phaser.Physics.P2.Spring.html">Spring</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Plugin.html">Plugin</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.PluginManager.html">PluginManager</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Point.html">Point</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Pointer.html">Pointer</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Polygon.html">Polygon</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.QuadTree.html">QuadTree</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.RandomDataGenerator.html">RandomDataGenerator</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Rectangle.html">Rectangle</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.RenderTexture.html">RenderTexture</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.RequestAnimationFrame.html">RequestAnimationFrame</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.RetroFont.html">RetroFont</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Rope.html">Rope</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.ScaleManager.html">ScaleManager</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Signal.html">Signal</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.SignalBinding.html">SignalBinding</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.SinglePad.html">SinglePad</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Sound.html">Sound</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.SoundManager.html">SoundManager</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Sprite.html">Sprite</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.SpriteBatch.html">SpriteBatch</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Stage.html">Stage</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.State.html">State</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.StateManager.html">StateManager</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Text.html">Text</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Tile.html">Tile</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Tilemap.html">Tilemap</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.TilemapLayer.html">TilemapLayer</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.TilemapParser.html">TilemapParser</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Tileset.html">Tileset</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.TileSprite.html">TileSprite</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Time.html">Time</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Timer.html">Timer</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.TimerEvent.html">TimerEvent</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Touch.html">Touch</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Tween.html">Tween</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.TweenData.html">TweenData</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.TweenManager.html">TweenManager</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.Utils.html">Utils</a>
|
|
</li>
|
|
|
|
<li class="class-depth-2">
|
|
<a href="Phaser.Utils.Debug.html">Debug</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="Phaser.World.html">World</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.AbstractFilter.html">AbstractFilter</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.AjaxRequest.html">AjaxRequest</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.AlphaMaskFilter.html">AlphaMaskFilter</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.AsciiFilter.html">AsciiFilter</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.AssetLoader.html">AssetLoader</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.AtlasLoader.html">AtlasLoader</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.BaseTexture.html">BaseTexture</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.BitmapFontLoader.html">BitmapFontLoader</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.BitmapText.html">BitmapText</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.BlurFilter.html">BlurFilter</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.BlurXFilter.html">BlurXFilter</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.BlurYFilter.html">BlurYFilter</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.CanvasBuffer.html">CanvasBuffer</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.CanvasGraphics.html">CanvasGraphics</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.CanvasMaskManager.html">CanvasMaskManager</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.CanvasRenderer.html">CanvasRenderer</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.CanvasTinter.html">CanvasTinter</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.Circle.html">Circle</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.ColorMatrixFilter.html">ColorMatrixFilter</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.ColorStepFilter.html">ColorStepFilter</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.ComplexPrimitiveShader.html">ComplexPrimitiveShader</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.ConvolutionFilter.html">ConvolutionFilter</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.CrossHatchFilter.html">CrossHatchFilter</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.DisplacementFilter.html">DisplacementFilter</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.DisplayObject.html">DisplayObject</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.DisplayObjectContainer.html">DisplayObjectContainer</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.DotScreenFilter.html">DotScreenFilter</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.Ellipse.html">Ellipse</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.Event.html">Event</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.EventTarget.html">EventTarget</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.FilterBlock.html">FilterBlock</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.FilterTexture.html">FilterTexture</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.Graphics.html">Graphics</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.GraphicsData.html">GraphicsData</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.GrayFilter.html">GrayFilter</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.ImageLoader.html">ImageLoader</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.InteractionData.html">InteractionData</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.InteractionManager.html">InteractionManager</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.InvertFilter.html">InvertFilter</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.JsonLoader.html">JsonLoader</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.Matrix.html">Matrix</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.MovieClip.html">MovieClip</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.NoiseFilter.html">NoiseFilter</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.NormalMapFilter.html">NormalMapFilter</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.PixelateFilter.html">PixelateFilter</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.PIXI.html">PIXI</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.PixiFastShader.html">PixiFastShader</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.PixiShader.html">PixiShader</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.Point.html">Point</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.Polygon.html">Polygon</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.PolyK.html">PolyK</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.PrimitiveShader.html">PrimitiveShader</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.Rectangle.html">Rectangle</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.RenderTexture.html">RenderTexture</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.RGBSplitFilter.html">RGBSplitFilter</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.Rope.html">Rope</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.RoundedRectangle.html">RoundedRectangle</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.SepiaFilter.html">SepiaFilter</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.SmartBlurFilter.html">SmartBlurFilter</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.Spine.html">Spine</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.SpineLoader.html">SpineLoader</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.SpineTextureLoader.html">SpineTextureLoader</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.Sprite.html">Sprite</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.SpriteBatch.html">SpriteBatch</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.SpriteSheetLoader.html">SpriteSheetLoader</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.Stage.html">Stage</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.Strip.html">Strip</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.StripShader.html">StripShader</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.Text.html">Text</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.Texture.html">Texture</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.TilingSprite.html">TilingSprite</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.TiltShiftFilter.html">TiltShiftFilter</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.TiltShiftXFilter.html">TiltShiftXFilter</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.TiltShiftYFilter.html">TiltShiftYFilter</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.TwistFilter.html">TwistFilter</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.VideoTexture.html">VideoTexture</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.WebGLBlendModeManager.html">WebGLBlendModeManager</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.WebGLFastSpriteBatch.html">WebGLFastSpriteBatch</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.WebGLFilterManager.html">WebGLFilterManager</a>
|
|
</li>
|
|
|
|
<li class="class-depth-1">
|
|
<a href="PIXI.WebGLRenderer.html">WebGLRenderer</a>
|
|
</li>
|
|
|
|
|
|
</ul>
|
|
</li>
|
|
|
|
|
|
<li class="dropdown">
|
|
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Core<b class="caret"></b></a>
|
|
<ul class="dropdown-menu ">
|
|
<li class="class-depth-1"><a href="Phaser.Game.html">Game</a></li>
|
|
<li class="class-depth-1"><a href="Phaser.Group.html">Group</a></li>
|
|
<li class="class-depth-1"><a href="Phaser.World.html">World</a></li>
|
|
<li class="class-depth-1"><a href="Phaser.Loader.html">Loader</a></li>
|
|
<li class="class-depth-1"><a href="Phaser.Time.html">Time</a></li>
|
|
<li class="class-depth-1"><a href="Phaser.Camera.html">Camera</a></li>
|
|
<li class="class-depth-1"><a href="Phaser.StateManager.html">State Manager</a></li>
|
|
<li class="class-depth-1"><a href="Phaser.TweenManager.html">Tween Manager</a></li>
|
|
<li class="class-depth-1"><a href="Phaser.SoundManager.html">Sound Manager</a></li>
|
|
<li class="class-depth-1"><a href="Phaser.Input.html">Input Manager</a></li>
|
|
<li class="class-depth-1"><a href="Phaser.ScaleManager.html">Scale Manager</a></li>
|
|
</ul>
|
|
</li>
|
|
|
|
<li class="dropdown">
|
|
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Game Objects<b class="caret"></b></a>
|
|
<ul class="dropdown-menu ">
|
|
<li class="class-depth-1"><a href="Phaser.GameObjectFactory.html">Factory (game.add)</a></li>
|
|
<li class="class-depth-1"><a href="Phaser.GameObjectCreator.html">Creator (game.make)</a></li>
|
|
<li class="class-depth-1"><a href="Phaser.Sprite.html">Sprite</a></li>
|
|
<li class="class-depth-1"><a href="Phaser.Image.html">Image</a></li>
|
|
<li class="class-depth-1"><a href="Phaser.Sound.html">Sound</a></li>
|
|
<li class="class-depth-1"><a href="Phaser.Particles.Arcade.Emitter.html">Particle Emitter</a></li>
|
|
<li class="class-depth-1"><a href="Phaser.Particle.html">Particle</a></li>
|
|
<li class="class-depth-1"><a href="Phaser.Text.html">Text</a></li>
|
|
<li class="class-depth-1"><a href="Phaser.Tween.html">Tween</a></li>
|
|
<li class="class-depth-1"><a href="Phaser.BitmapText.html">BitmapText</a></li>
|
|
<li class="class-depth-1"><a href="Phaser.Tilemap.html">Tilemap</a></li>
|
|
<li class="class-depth-1"><a href="Phaser.BitmapData.html">BitmapData</a></li>
|
|
<li class="class-depth-1"><a href="Phaser.RetroFont.html">RetroFont</a></li>
|
|
<li class="class-depth-1"><a href="Phaser.Button.html">Button</a></li>
|
|
<li class="class-depth-1"><a href="Phaser.Animation.html">Animation</a></li>
|
|
<li class="class-depth-1"><a href="Phaser.Graphics.html">Graphics</a></li>
|
|
<li class="class-depth-1"><a href="Phaser.RenderTexture.html">RenderTexture</a></li>
|
|
<li class="class-depth-1"><a href="Phaser.TileSprite.html">TileSprite</a></li>
|
|
</ul>
|
|
</li>
|
|
|
|
<li class="dropdown">
|
|
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Geometry<b class="caret"></b></a>
|
|
<ul class="dropdown-menu ">
|
|
<li class="class-depth-1"><a href="Phaser.Circle.html">Circle</a></li>
|
|
<li class="class-depth-1"><a href="Phaser.Rectangle.html">Rectangle</a></li>
|
|
<li class="class-depth-1"><a href="Phaser.Point.html">Point</a></li>
|
|
<li class="class-depth-1"><a href="Phaser.Line.html">Line</a></li>
|
|
<li class="class-depth-1"><a href="Phaser.Ellipse.html">Ellipse</a></li>
|
|
<li class="class-depth-1"><a href="Phaser.Polygon.html">Polygon</a></li>
|
|
</ul>
|
|
</li>
|
|
|
|
<li class="dropdown">
|
|
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Physics<b class="caret"></b></a>
|
|
<ul class="dropdown-menu ">
|
|
<li class="class-depth-1"><a href="Phaser.Physics.Arcade.html">Arcade Physics</a></li>
|
|
<li class="class-depth-2"><a href="Phaser.Physics.Arcade.Body.html">Body</a></li>
|
|
<li class="class-depth-1"><a href="Phaser.Physics.P2.html">P2 Physics</a></li>
|
|
<li class="class-depth-2"><a href="Phaser.Physics.P2.Body.html">Body</a></li>
|
|
<li class="class-depth-2"><a href="Phaser.Physics.P2.Spring.html">Spring</a></li>
|
|
<li class="class-depth-2"><a href="Phaser.Physics.P2.CollisionGroup.html">CollisionGroup</a></li>
|
|
<li class="class-depth-2"><a href="Phaser.Physics.P2.ContactMaterial.html">ContactMaterial</a></li>
|
|
<li class="class-depth-1"><a href="Phaser.Physics.Ninja.html">Ninja Physics</a></li>
|
|
<li class="class-depth-2"><a href="Phaser.Physics.Body.html">Body</a></li>
|
|
</ul>
|
|
</li>
|
|
|
|
<li class="dropdown">
|
|
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Input<b class="caret"></b></a>
|
|
<ul class="dropdown-menu ">
|
|
<li class="class-depth-1"><a href="Phaser.InputHandler.html">Input Handler</a></li>
|
|
<li class="class-depth-1"><a href="Phaser.Pointer.html">Pointer</a></li>
|
|
<li class="class-depth-1"><a href="Phaser.Mouse.html">Mouse</a></li>
|
|
<li class="class-depth-1"><a href="Phaser.Keyboard.html">Keyboard</a></li>
|
|
<li class="class-depth-1"><a href="Phaser.Key.html">Key</a></li>
|
|
<li class="class-depth-1"><a href="Phaser.Gamepad.html">Gamepad</a></li>
|
|
</ul>
|
|
</li>
|
|
|
|
<li class="dropdown">
|
|
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Community<b class="caret"></b></a>
|
|
<ul class="dropdown-menu ">
|
|
<li class="class-depth-1"><a href="https://leanpub.com/u/photonstorm">Phaser Books</a></li>
|
|
<li class="class-depth-1"><a href="https://github.com/photonstorm/phaser">Phaser Github</a></li>
|
|
<li class="class-depth-1"><a href="http://examples.phaser.io">Phaser Examples</a></li>
|
|
<li class="class-depth-1"><a href="https://github.com/photonstorm/phaser-plugins">Phaser Plugins</a></li>
|
|
<li class="class-depth-1"><a href="http://www.html5gamedevs.com/forum/14-phaser/">Forum</a></li>
|
|
<li class="class-depth-1"><a href="http://stackoverflow.com/questions/tagged/phaser-framework">Stack Overflow</a></li>
|
|
<li class="class-depth-1"><a href="https://confirmsubscription.com/h/r/369DE48E3E86AF1E">Newsletter</a></li>
|
|
<li class="class-depth-1"><a href="https://twitter.com/photonstorm">Twitter</a></li>
|
|
<li class="class-depth-1"><a href="http://www.html5gamedevs.com/topic/4470-official-phaserio-irc-channel-phaserio-on-freenode/">IRC</a></li>
|
|
<li class="class-depth-1"><a href="https://www.gittip.com/photonstorm/">GitTip</a></li>
|
|
</ul>
|
|
</li>
|
|
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row-fluid">
|
|
|
|
|
|
<div class="span12">
|
|
|
|
<div id="main">
|
|
|
|
|
|
|
|
<h1 class="page-title">Source: d:/wamp/www/phaser/src/pixi/extras/Spine.js</h1>
|
|
|
|
<section>
|
|
<article>
|
|
<pre class="sunlight-highlight-javascript linenums">/******************************************************************************
|
|
* Spine Runtimes Software License
|
|
* Version 2.1
|
|
*
|
|
* Copyright (c) 2013, Esoteric Software
|
|
* All rights reserved.
|
|
*
|
|
* You are granted a perpetual, non-exclusive, non-sublicensable and
|
|
* non-transferable license to install, execute and perform the Spine Runtimes
|
|
* Software (the "Software") solely for internal use. Without the written
|
|
* permission of Esoteric Software (typically granted by licensing Spine), you
|
|
* may not (a) modify, translate, adapt or otherwise create derivative works,
|
|
* improvements of the Software or develop new applications using the Software
|
|
* 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 SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
|
* OR BUSINESS INTERRUPTION) 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.
|
|
*****************************************************************************/
|
|
|
|
var spine = {
|
|
radDeg: 180 / Math.PI,
|
|
degRad: Math.PI / 180,
|
|
temp: [],
|
|
Float32Array: (typeof(Float32Array) === 'undefined') ? Array : Float32Array,
|
|
Uint16Array: (typeof(Uint16Array) === 'undefined') ? Array : Uint16Array
|
|
};
|
|
|
|
spine.BoneData = function (name, parent) {
|
|
this.name = name;
|
|
this.parent = parent;
|
|
};
|
|
spine.BoneData.prototype = {
|
|
length: 0,
|
|
x: 0, y: 0,
|
|
rotation: 0,
|
|
scaleX: 1, scaleY: 1,
|
|
inheritScale: true,
|
|
inheritRotation: true,
|
|
flipX: false, flipY: false
|
|
};
|
|
|
|
spine.SlotData = function (name, boneData) {
|
|
this.name = name;
|
|
this.boneData = boneData;
|
|
};
|
|
spine.SlotData.prototype = {
|
|
r: 1, g: 1, b: 1, a: 1,
|
|
attachmentName: null,
|
|
additiveBlending: false
|
|
};
|
|
|
|
spine.IkConstraintData = function (name) {
|
|
this.name = name;
|
|
this.bones = [];
|
|
};
|
|
spine.IkConstraintData.prototype = {
|
|
target: null,
|
|
bendDirection: 1,
|
|
mix: 1
|
|
};
|
|
|
|
spine.Bone = function (boneData, skeleton, parent) {
|
|
this.data = boneData;
|
|
this.skeleton = skeleton;
|
|
this.parent = parent;
|
|
this.setToSetupPose();
|
|
};
|
|
spine.Bone.yDown = false;
|
|
spine.Bone.prototype = {
|
|
x: 0, y: 0,
|
|
rotation: 0, rotationIK: 0,
|
|
scaleX: 1, scaleY: 1,
|
|
flipX: false, flipY: false,
|
|
m00: 0, m01: 0, worldX: 0, // a b x
|
|
m10: 0, m11: 0, worldY: 0, // c d y
|
|
worldRotation: 0,
|
|
worldScaleX: 1, worldScaleY: 1,
|
|
worldFlipX: false, worldFlipY: false,
|
|
updateWorldTransform: function () {
|
|
var parent = this.parent;
|
|
if (parent) {
|
|
this.worldX = this.x * parent.m00 + this.y * parent.m01 + parent.worldX;
|
|
this.worldY = this.x * parent.m10 + this.y * parent.m11 + parent.worldY;
|
|
if (this.data.inheritScale) {
|
|
this.worldScaleX = parent.worldScaleX * this.scaleX;
|
|
this.worldScaleY = parent.worldScaleY * this.scaleY;
|
|
} else {
|
|
this.worldScaleX = this.scaleX;
|
|
this.worldScaleY = this.scaleY;
|
|
}
|
|
this.worldRotation = this.data.inheritRotation ? (parent.worldRotation + this.rotationIK) : this.rotationIK;
|
|
this.worldFlipX = parent.worldFlipX != this.flipX;
|
|
this.worldFlipY = parent.worldFlipY != this.flipY;
|
|
} else {
|
|
var skeletonFlipX = this.skeleton.flipX, skeletonFlipY = this.skeleton.flipY;
|
|
this.worldX = skeletonFlipX ? -this.x : this.x;
|
|
this.worldY = (skeletonFlipY != spine.Bone.yDown) ? -this.y : this.y;
|
|
this.worldScaleX = this.scaleX;
|
|
this.worldScaleY = this.scaleY;
|
|
this.worldRotation = this.rotationIK;
|
|
this.worldFlipX = skeletonFlipX != this.flipX;
|
|
this.worldFlipY = skeletonFlipY != this.flipY;
|
|
}
|
|
var radians = this.worldRotation * spine.degRad;
|
|
var cos = Math.cos(radians);
|
|
var sin = Math.sin(radians);
|
|
if (this.worldFlipX) {
|
|
this.m00 = -cos * this.worldScaleX;
|
|
this.m01 = sin * this.worldScaleY;
|
|
} else {
|
|
this.m00 = cos * this.worldScaleX;
|
|
this.m01 = -sin * this.worldScaleY;
|
|
}
|
|
if (this.worldFlipY != spine.Bone.yDown) {
|
|
this.m10 = -sin * this.worldScaleX;
|
|
this.m11 = -cos * this.worldScaleY;
|
|
} else {
|
|
this.m10 = sin * this.worldScaleX;
|
|
this.m11 = cos * this.worldScaleY;
|
|
}
|
|
},
|
|
setToSetupPose: function () {
|
|
var data = this.data;
|
|
this.x = data.x;
|
|
this.y = data.y;
|
|
this.rotation = data.rotation;
|
|
this.rotationIK = this.rotation;
|
|
this.scaleX = data.scaleX;
|
|
this.scaleY = data.scaleY;
|
|
this.flipX = data.flipX;
|
|
this.flipY = data.flipY;
|
|
},
|
|
worldToLocal: function (world) {
|
|
var dx = world[0] - this.worldX, dy = world[1] - this.worldY;
|
|
var m00 = this.m00, m10 = this.m10, m01 = this.m01, m11 = this.m11;
|
|
if (this.worldFlipX != (this.worldFlipY != spine.Bone.yDown)) {
|
|
m00 = -m00;
|
|
m11 = -m11;
|
|
}
|
|
var invDet = 1 / (m00 * m11 - m01 * m10);
|
|
world[0] = dx * m00 * invDet - dy * m01 * invDet;
|
|
world[1] = dy * m11 * invDet - dx * m10 * invDet;
|
|
},
|
|
localToWorld: function (local) {
|
|
var localX = local[0], localY = local[1];
|
|
local[0] = localX * this.m00 + localY * this.m01 + this.worldX;
|
|
local[1] = localX * this.m10 + localY * this.m11 + this.worldY;
|
|
}
|
|
};
|
|
|
|
spine.Slot = function (slotData, bone) {
|
|
this.data = slotData;
|
|
this.bone = bone;
|
|
this.setToSetupPose();
|
|
};
|
|
spine.Slot.prototype = {
|
|
r: 1, g: 1, b: 1, a: 1,
|
|
_attachmentTime: 0,
|
|
attachment: null,
|
|
attachmentVertices: [],
|
|
setAttachment: function (attachment) {
|
|
this.attachment = attachment;
|
|
this._attachmentTime = this.bone.skeleton.time;
|
|
this.attachmentVertices.length = 0;
|
|
},
|
|
setAttachmentTime: function (time) {
|
|
this._attachmentTime = this.bone.skeleton.time - time;
|
|
},
|
|
getAttachmentTime: function () {
|
|
return this.bone.skeleton.time - this._attachmentTime;
|
|
},
|
|
setToSetupPose: function () {
|
|
var data = this.data;
|
|
this.r = data.r;
|
|
this.g = data.g;
|
|
this.b = data.b;
|
|
this.a = data.a;
|
|
|
|
var slotDatas = this.bone.skeleton.data.slots;
|
|
for (var i = 0, n = slotDatas.length; i < n; i++) {
|
|
if (slotDatas[i] == data) {
|
|
this.setAttachment(!data.attachmentName ? null : this.bone.skeleton.getAttachmentBySlotIndex(i, data.attachmentName));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
spine.IkConstraint = function (data, skeleton) {
|
|
this.data = data;
|
|
this.mix = data.mix;
|
|
this.bendDirection = data.bendDirection;
|
|
|
|
this.bones = [];
|
|
for (var i = 0, n = data.bones.length; i < n; i++)
|
|
this.bones.push(skeleton.findBone(data.bones[i].name));
|
|
this.target = skeleton.findBone(data.target.name);
|
|
};
|
|
spine.IkConstraint.prototype = {
|
|
apply: function () {
|
|
var target = this.target;
|
|
var bones = this.bones;
|
|
switch (bones.length) {
|
|
case 1:
|
|
spine.IkConstraint.apply1(bones[0], target.worldX, target.worldY, this.mix);
|
|
break;
|
|
case 2:
|
|
spine.IkConstraint.apply2(bones[0], bones[1], target.worldX, target.worldY, this.bendDirection, this.mix);
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
/** Adjusts the bone rotation so the tip is as close to the target position as possible. The target is specified in the world
|
|
* coordinate system. */
|
|
spine.IkConstraint.apply1 = function (bone, targetX, targetY, alpha) {
|
|
var parentRotation = (!bone.data.inheritRotation || !bone.parent) ? 0 : bone.parent.worldRotation;
|
|
var rotation = bone.rotation;
|
|
var rotationIK = Math.atan2(targetY - bone.worldY, targetX - bone.worldX) * spine.radDeg - parentRotation;
|
|
bone.rotationIK = rotation + (rotationIK - rotation) * alpha;
|
|
};
|
|
/** Adjusts the parent and child bone rotations so the tip of the child is as close to the target position as possible. The
|
|
* target is specified in the world coordinate system.
|
|
* @param child Any descendant bone of the parent. */
|
|
spine.IkConstraint.apply2 = function (parent, child, targetX, targetY, bendDirection, alpha) {
|
|
var childRotation = child.rotation, parentRotation = parent.rotation;
|
|
if (!alpha) {
|
|
child.rotationIK = childRotation;
|
|
parent.rotationIK = parentRotation;
|
|
return;
|
|
}
|
|
var positionX, positionY, tempPosition = spine.temp;
|
|
var parentParent = parent.parent;
|
|
if (parentParent) {
|
|
tempPosition[0] = targetX;
|
|
tempPosition[1] = targetY;
|
|
parentParent.worldToLocal(tempPosition);
|
|
targetX = (tempPosition[0] - parent.x) * parentParent.worldScaleX;
|
|
targetY = (tempPosition[1] - parent.y) * parentParent.worldScaleY;
|
|
} else {
|
|
targetX -= parent.x;
|
|
targetY -= parent.y;
|
|
}
|
|
if (child.parent == parent) {
|
|
positionX = child.x;
|
|
positionY = child.y;
|
|
} else {
|
|
tempPosition[0] = child.x;
|
|
tempPosition[1] = child.y;
|
|
child.parent.localToWorld(tempPosition);
|
|
parent.worldToLocal(tempPosition);
|
|
positionX = tempPosition[0];
|
|
positionY = tempPosition[1];
|
|
}
|
|
var childX = positionX * parent.worldScaleX, childY = positionY * parent.worldScaleY;
|
|
var offset = Math.atan2(childY, childX);
|
|
var len1 = Math.sqrt(childX * childX + childY * childY), len2 = child.data.length * child.worldScaleX;
|
|
// Based on code by Ryan Juckett with permission: Copyright (c) 2008-2009 Ryan Juckett, http://www.ryanjuckett.com/
|
|
var cosDenom = 2 * len1 * len2;
|
|
if (cosDenom < 0.0001) {
|
|
child.rotationIK = childRotation + (Math.atan2(targetY, targetX) * spine.radDeg - parentRotation - childRotation) * alpha;
|
|
return;
|
|
}
|
|
var cos = (targetX * targetX + targetY * targetY - len1 * len1 - len2 * len2) / cosDenom;
|
|
if (cos < -1)
|
|
cos = -1;
|
|
else if (cos > 1)
|
|
cos = 1;
|
|
var childAngle = Math.acos(cos) * bendDirection;
|
|
var adjacent = len1 + len2 * cos, opposite = len2 * Math.sin(childAngle);
|
|
var parentAngle = Math.atan2(targetY * adjacent - targetX * opposite, targetX * adjacent + targetY * opposite);
|
|
var rotation = (parentAngle - offset) * spine.radDeg - parentRotation;
|
|
if (rotation > 180)
|
|
rotation -= 360;
|
|
else if (rotation < -180) //
|
|
rotation += 360;
|
|
parent.rotationIK = parentRotation + rotation * alpha;
|
|
rotation = (childAngle + offset) * spine.radDeg - childRotation;
|
|
if (rotation > 180)
|
|
rotation -= 360;
|
|
else if (rotation < -180) //
|
|
rotation += 360;
|
|
child.rotationIK = childRotation + (rotation + parent.worldRotation - child.parent.worldRotation) * alpha;
|
|
};
|
|
|
|
spine.Skin = function (name) {
|
|
this.name = name;
|
|
this.attachments = {};
|
|
};
|
|
spine.Skin.prototype = {
|
|
addAttachment: function (slotIndex, name, attachment) {
|
|
this.attachments[slotIndex + ":" + name] = attachment;
|
|
},
|
|
getAttachment: function (slotIndex, name) {
|
|
return this.attachments[slotIndex + ":" + name];
|
|
},
|
|
_attachAll: function (skeleton, oldSkin) {
|
|
for (var key in oldSkin.attachments) {
|
|
var colon = key.indexOf(":");
|
|
var slotIndex = parseInt(key.substring(0, colon));
|
|
var name = key.substring(colon + 1);
|
|
var slot = skeleton.slots[slotIndex];
|
|
if (slot.attachment && slot.attachment.name == name) {
|
|
var attachment = this.getAttachment(slotIndex, name);
|
|
if (attachment) slot.setAttachment(attachment);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
spine.Animation = function (name, timelines, duration) {
|
|
this.name = name;
|
|
this.timelines = timelines;
|
|
this.duration = duration;
|
|
};
|
|
spine.Animation.prototype = {
|
|
apply: function (skeleton, lastTime, time, loop, events) {
|
|
if (loop && this.duration != 0) {
|
|
time %= this.duration;
|
|
lastTime %= this.duration;
|
|
}
|
|
var timelines = this.timelines;
|
|
for (var i = 0, n = timelines.length; i < n; i++)
|
|
timelines[i].apply(skeleton, lastTime, time, events, 1);
|
|
},
|
|
mix: function (skeleton, lastTime, time, loop, events, alpha) {
|
|
if (loop && this.duration != 0) {
|
|
time %= this.duration;
|
|
lastTime %= this.duration;
|
|
}
|
|
var timelines = this.timelines;
|
|
for (var i = 0, n = timelines.length; i < n; i++)
|
|
timelines[i].apply(skeleton, lastTime, time, events, alpha);
|
|
}
|
|
};
|
|
spine.Animation.binarySearch = function (values, target, step) {
|
|
var low = 0;
|
|
var high = Math.floor(values.length / step) - 2;
|
|
if (!high) return step;
|
|
var current = high >>> 1;
|
|
while (true) {
|
|
if (values[(current + 1) * step] <= target)
|
|
low = current + 1;
|
|
else
|
|
high = current;
|
|
if (low == high) return (low + 1) * step;
|
|
current = (low + high) >>> 1;
|
|
}
|
|
};
|
|
spine.Animation.binarySearch1 = function (values, target) {
|
|
var low = 0;
|
|
var high = values.length - 2;
|
|
if (!high) return 1;
|
|
var current = high >>> 1;
|
|
while (true) {
|
|
if (values[current + 1] <= target)
|
|
low = current + 1;
|
|
else
|
|
high = current;
|
|
if (low == high) return low + 1;
|
|
current = (low + high) >>> 1;
|
|
}
|
|
};
|
|
spine.Animation.linearSearch = function (values, target, step) {
|
|
for (var i = 0, last = values.length - step; i <= last; i += step)
|
|
if (values[i] > target) return i;
|
|
return -1;
|
|
};
|
|
|
|
spine.Curves = function (frameCount) {
|
|
this.curves = []; // type, x, y, ...
|
|
//this.curves.length = (frameCount - 1) * 19/*BEZIER_SIZE*/;
|
|
};
|
|
spine.Curves.prototype = {
|
|
setLinear: function (frameIndex) {
|
|
this.curves[frameIndex * 19/*BEZIER_SIZE*/] = 0/*LINEAR*/;
|
|
},
|
|
setStepped: function (frameIndex) {
|
|
this.curves[frameIndex * 19/*BEZIER_SIZE*/] = 1/*STEPPED*/;
|
|
},
|
|
/** Sets the control handle positions for an interpolation bezier curve used to transition from this keyframe to the next.
|
|
* cx1 and cx2 are from 0 to 1, representing the percent of time between the two keyframes. cy1 and cy2 are the percent of
|
|
* the difference between the keyframe's values. */
|
|
setCurve: function (frameIndex, cx1, cy1, cx2, cy2) {
|
|
var subdiv1 = 1 / 10/*BEZIER_SEGMENTS*/, subdiv2 = subdiv1 * subdiv1, subdiv3 = subdiv2 * subdiv1;
|
|
var pre1 = 3 * subdiv1, pre2 = 3 * subdiv2, pre4 = 6 * subdiv2, pre5 = 6 * subdiv3;
|
|
var tmp1x = -cx1 * 2 + cx2, tmp1y = -cy1 * 2 + cy2, tmp2x = (cx1 - cx2) * 3 + 1, tmp2y = (cy1 - cy2) * 3 + 1;
|
|
var dfx = cx1 * pre1 + tmp1x * pre2 + tmp2x * subdiv3, dfy = cy1 * pre1 + tmp1y * pre2 + tmp2y * subdiv3;
|
|
var ddfx = tmp1x * pre4 + tmp2x * pre5, ddfy = tmp1y * pre4 + tmp2y * pre5;
|
|
var dddfx = tmp2x * pre5, dddfy = tmp2y * pre5;
|
|
|
|
var i = frameIndex * 19/*BEZIER_SIZE*/;
|
|
var curves = this.curves;
|
|
curves[i++] = 2/*BEZIER*/;
|
|
|
|
var x = dfx, y = dfy;
|
|
for (var n = i + 19/*BEZIER_SIZE*/ - 1; i < n; i += 2) {
|
|
curves[i] = x;
|
|
curves[i + 1] = y;
|
|
dfx += ddfx;
|
|
dfy += ddfy;
|
|
ddfx += dddfx;
|
|
ddfy += dddfy;
|
|
x += dfx;
|
|
y += dfy;
|
|
}
|
|
},
|
|
getCurvePercent: function (frameIndex, percent) {
|
|
percent = percent < 0 ? 0 : (percent > 1 ? 1 : percent);
|
|
var curves = this.curves;
|
|
var i = frameIndex * 19/*BEZIER_SIZE*/;
|
|
var type = curves[i];
|
|
if (type === 0/*LINEAR*/) return percent;
|
|
if (type == 1/*STEPPED*/) return 0;
|
|
i++;
|
|
var x = 0;
|
|
for (var start = i, n = i + 19/*BEZIER_SIZE*/ - 1; i < n; i += 2) {
|
|
x = curves[i];
|
|
if (x >= percent) {
|
|
var prevX, prevY;
|
|
if (i == start) {
|
|
prevX = 0;
|
|
prevY = 0;
|
|
} else {
|
|
prevX = curves[i - 2];
|
|
prevY = curves[i - 1];
|
|
}
|
|
return prevY + (curves[i + 1] - prevY) * (percent - prevX) / (x - prevX);
|
|
}
|
|
}
|
|
var y = curves[i - 1];
|
|
return y + (1 - y) * (percent - x) / (1 - x); // Last point is 1,1.
|
|
}
|
|
};
|
|
|
|
spine.RotateTimeline = function (frameCount) {
|
|
this.curves = new spine.Curves(frameCount);
|
|
this.frames = []; // time, angle, ...
|
|
this.frames.length = frameCount * 2;
|
|
};
|
|
spine.RotateTimeline.prototype = {
|
|
boneIndex: 0,
|
|
getFrameCount: function () {
|
|
return this.frames.length / 2;
|
|
},
|
|
setFrame: function (frameIndex, time, angle) {
|
|
frameIndex *= 2;
|
|
this.frames[frameIndex] = time;
|
|
this.frames[frameIndex + 1] = angle;
|
|
},
|
|
apply: function (skeleton, lastTime, time, firedEvents, alpha) {
|
|
var frames = this.frames;
|
|
if (time < frames[0]) return; // Time is before first frame.
|
|
|
|
var bone = skeleton.bones[this.boneIndex];
|
|
|
|
if (time >= frames[frames.length - 2]) { // Time is after last frame.
|
|
var amount = bone.data.rotation + frames[frames.length - 1] - bone.rotation;
|
|
while (amount > 180)
|
|
amount -= 360;
|
|
while (amount < -180)
|
|
amount += 360;
|
|
bone.rotation += amount * alpha;
|
|
return;
|
|
}
|
|
|
|
// Interpolate between the previous frame and the current frame.
|
|
var frameIndex = spine.Animation.binarySearch(frames, time, 2);
|
|
var prevFrameValue = frames[frameIndex - 1];
|
|
var frameTime = frames[frameIndex];
|
|
var percent = 1 - (time - frameTime) / (frames[frameIndex - 2/*PREV_FRAME_TIME*/] - frameTime);
|
|
percent = this.curves.getCurvePercent(frameIndex / 2 - 1, percent);
|
|
|
|
var amount = frames[frameIndex + 1/*FRAME_VALUE*/] - prevFrameValue;
|
|
while (amount > 180)
|
|
amount -= 360;
|
|
while (amount < -180)
|
|
amount += 360;
|
|
amount = bone.data.rotation + (prevFrameValue + amount * percent) - bone.rotation;
|
|
while (amount > 180)
|
|
amount -= 360;
|
|
while (amount < -180)
|
|
amount += 360;
|
|
bone.rotation += amount * alpha;
|
|
}
|
|
};
|
|
|
|
spine.TranslateTimeline = function (frameCount) {
|
|
this.curves = new spine.Curves(frameCount);
|
|
this.frames = []; // time, x, y, ...
|
|
this.frames.length = frameCount * 3;
|
|
};
|
|
spine.TranslateTimeline.prototype = {
|
|
boneIndex: 0,
|
|
getFrameCount: function () {
|
|
return this.frames.length / 3;
|
|
},
|
|
setFrame: function (frameIndex, time, x, y) {
|
|
frameIndex *= 3;
|
|
this.frames[frameIndex] = time;
|
|
this.frames[frameIndex + 1] = x;
|
|
this.frames[frameIndex + 2] = y;
|
|
},
|
|
apply: function (skeleton, lastTime, time, firedEvents, alpha) {
|
|
var frames = this.frames;
|
|
if (time < frames[0]) return; // Time is before first frame.
|
|
|
|
var bone = skeleton.bones[this.boneIndex];
|
|
|
|
if (time >= frames[frames.length - 3]) { // Time is after last frame.
|
|
bone.x += (bone.data.x + frames[frames.length - 2] - bone.x) * alpha;
|
|
bone.y += (bone.data.y + frames[frames.length - 1] - bone.y) * alpha;
|
|
return;
|
|
}
|
|
|
|
// Interpolate between the previous frame and the current frame.
|
|
var frameIndex = spine.Animation.binarySearch(frames, time, 3);
|
|
var prevFrameX = frames[frameIndex - 2];
|
|
var prevFrameY = frames[frameIndex - 1];
|
|
var frameTime = frames[frameIndex];
|
|
var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*PREV_FRAME_TIME*/] - frameTime);
|
|
percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent);
|
|
|
|
bone.x += (bone.data.x + prevFrameX + (frames[frameIndex + 1/*FRAME_X*/] - prevFrameX) * percent - bone.x) * alpha;
|
|
bone.y += (bone.data.y + prevFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - prevFrameY) * percent - bone.y) * alpha;
|
|
}
|
|
};
|
|
|
|
spine.ScaleTimeline = function (frameCount) {
|
|
this.curves = new spine.Curves(frameCount);
|
|
this.frames = []; // time, x, y, ...
|
|
this.frames.length = frameCount * 3;
|
|
};
|
|
spine.ScaleTimeline.prototype = {
|
|
boneIndex: 0,
|
|
getFrameCount: function () {
|
|
return this.frames.length / 3;
|
|
},
|
|
setFrame: function (frameIndex, time, x, y) {
|
|
frameIndex *= 3;
|
|
this.frames[frameIndex] = time;
|
|
this.frames[frameIndex + 1] = x;
|
|
this.frames[frameIndex + 2] = y;
|
|
},
|
|
apply: function (skeleton, lastTime, time, firedEvents, alpha) {
|
|
var frames = this.frames;
|
|
if (time < frames[0]) return; // Time is before first frame.
|
|
|
|
var bone = skeleton.bones[this.boneIndex];
|
|
|
|
if (time >= frames[frames.length - 3]) { // Time is after last frame.
|
|
bone.scaleX += (bone.data.scaleX * frames[frames.length - 2] - bone.scaleX) * alpha;
|
|
bone.scaleY += (bone.data.scaleY * frames[frames.length - 1] - bone.scaleY) * alpha;
|
|
return;
|
|
}
|
|
|
|
// Interpolate between the previous frame and the current frame.
|
|
var frameIndex = spine.Animation.binarySearch(frames, time, 3);
|
|
var prevFrameX = frames[frameIndex - 2];
|
|
var prevFrameY = frames[frameIndex - 1];
|
|
var frameTime = frames[frameIndex];
|
|
var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*PREV_FRAME_TIME*/] - frameTime);
|
|
percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent);
|
|
|
|
bone.scaleX += (bone.data.scaleX * (prevFrameX + (frames[frameIndex + 1/*FRAME_X*/] - prevFrameX) * percent) - bone.scaleX) * alpha;
|
|
bone.scaleY += (bone.data.scaleY * (prevFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - prevFrameY) * percent) - bone.scaleY) * alpha;
|
|
}
|
|
};
|
|
|
|
spine.ColorTimeline = function (frameCount) {
|
|
this.curves = new spine.Curves(frameCount);
|
|
this.frames = []; // time, r, g, b, a, ...
|
|
this.frames.length = frameCount * 5;
|
|
};
|
|
spine.ColorTimeline.prototype = {
|
|
slotIndex: 0,
|
|
getFrameCount: function () {
|
|
return this.frames.length / 5;
|
|
},
|
|
setFrame: function (frameIndex, time, r, g, b, a) {
|
|
frameIndex *= 5;
|
|
this.frames[frameIndex] = time;
|
|
this.frames[frameIndex + 1] = r;
|
|
this.frames[frameIndex + 2] = g;
|
|
this.frames[frameIndex + 3] = b;
|
|
this.frames[frameIndex + 4] = a;
|
|
},
|
|
apply: function (skeleton, lastTime, time, firedEvents, alpha) {
|
|
var frames = this.frames;
|
|
if (time < frames[0]) return; // Time is before first frame.
|
|
|
|
var r, g, b, a;
|
|
if (time >= frames[frames.length - 5]) {
|
|
// Time is after last frame.
|
|
var i = frames.length - 1;
|
|
r = frames[i - 3];
|
|
g = frames[i - 2];
|
|
b = frames[i - 1];
|
|
a = frames[i];
|
|
} else {
|
|
// Interpolate between the previous frame and the current frame.
|
|
var frameIndex = spine.Animation.binarySearch(frames, time, 5);
|
|
var prevFrameR = frames[frameIndex - 4];
|
|
var prevFrameG = frames[frameIndex - 3];
|
|
var prevFrameB = frames[frameIndex - 2];
|
|
var prevFrameA = frames[frameIndex - 1];
|
|
var frameTime = frames[frameIndex];
|
|
var percent = 1 - (time - frameTime) / (frames[frameIndex - 5/*PREV_FRAME_TIME*/] - frameTime);
|
|
percent = this.curves.getCurvePercent(frameIndex / 5 - 1, percent);
|
|
|
|
r = prevFrameR + (frames[frameIndex + 1/*FRAME_R*/] - prevFrameR) * percent;
|
|
g = prevFrameG + (frames[frameIndex + 2/*FRAME_G*/] - prevFrameG) * percent;
|
|
b = prevFrameB + (frames[frameIndex + 3/*FRAME_B*/] - prevFrameB) * percent;
|
|
a = prevFrameA + (frames[frameIndex + 4/*FRAME_A*/] - prevFrameA) * percent;
|
|
}
|
|
var slot = skeleton.slots[this.slotIndex];
|
|
if (alpha < 1) {
|
|
slot.r += (r - slot.r) * alpha;
|
|
slot.g += (g - slot.g) * alpha;
|
|
slot.b += (b - slot.b) * alpha;
|
|
slot.a += (a - slot.a) * alpha;
|
|
} else {
|
|
slot.r = r;
|
|
slot.g = g;
|
|
slot.b = b;
|
|
slot.a = a;
|
|
}
|
|
}
|
|
};
|
|
|
|
spine.AttachmentTimeline = function (frameCount) {
|
|
this.curves = new spine.Curves(frameCount);
|
|
this.frames = []; // time, ...
|
|
this.frames.length = frameCount;
|
|
this.attachmentNames = [];
|
|
this.attachmentNames.length = frameCount;
|
|
};
|
|
spine.AttachmentTimeline.prototype = {
|
|
slotIndex: 0,
|
|
getFrameCount: function () {
|
|
return this.frames.length;
|
|
},
|
|
setFrame: function (frameIndex, time, attachmentName) {
|
|
this.frames[frameIndex] = time;
|
|
this.attachmentNames[frameIndex] = attachmentName;
|
|
},
|
|
apply: function (skeleton, lastTime, time, firedEvents, alpha) {
|
|
var frames = this.frames;
|
|
if (time < frames[0]) {
|
|
if (lastTime > time) this.apply(skeleton, lastTime, Number.MAX_VALUE, null, 0);
|
|
return;
|
|
} else if (lastTime > time) //
|
|
lastTime = -1;
|
|
|
|
var frameIndex = time >= frames[frames.length - 1] ? frames.length - 1 : spine.Animation.binarySearch1(frames, time) - 1;
|
|
if (frames[frameIndex] < lastTime) return;
|
|
|
|
var attachmentName = this.attachmentNames[frameIndex];
|
|
skeleton.slots[this.slotIndex].setAttachment(
|
|
!attachmentName ? null : skeleton.getAttachmentBySlotIndex(this.slotIndex, attachmentName));
|
|
}
|
|
};
|
|
|
|
spine.EventTimeline = function (frameCount) {
|
|
this.frames = []; // time, ...
|
|
this.frames.length = frameCount;
|
|
this.events = [];
|
|
this.events.length = frameCount;
|
|
};
|
|
spine.EventTimeline.prototype = {
|
|
getFrameCount: function () {
|
|
return this.frames.length;
|
|
},
|
|
setFrame: function (frameIndex, time, event) {
|
|
this.frames[frameIndex] = time;
|
|
this.events[frameIndex] = event;
|
|
},
|
|
/** Fires events for frames > lastTime and <= time. */
|
|
apply: function (skeleton, lastTime, time, firedEvents, alpha) {
|
|
if (!firedEvents) return;
|
|
|
|
var frames = this.frames;
|
|
var frameCount = frames.length;
|
|
|
|
if (lastTime > time) { // Fire events after last time for looped animations.
|
|
this.apply(skeleton, lastTime, Number.MAX_VALUE, firedEvents, alpha);
|
|
lastTime = -1;
|
|
} else if (lastTime >= frames[frameCount - 1]) // Last time is after last frame.
|
|
return;
|
|
if (time < frames[0]) return; // Time is before first frame.
|
|
|
|
var frameIndex;
|
|
if (lastTime < frames[0])
|
|
frameIndex = 0;
|
|
else {
|
|
frameIndex = spine.Animation.binarySearch1(frames, lastTime);
|
|
var frame = frames[frameIndex];
|
|
while (frameIndex > 0) { // Fire multiple events with the same frame.
|
|
if (frames[frameIndex - 1] != frame) break;
|
|
frameIndex--;
|
|
}
|
|
}
|
|
var events = this.events;
|
|
for (; frameIndex < frameCount && time >= frames[frameIndex]; frameIndex++)
|
|
firedEvents.push(events[frameIndex]);
|
|
}
|
|
};
|
|
|
|
spine.DrawOrderTimeline = function (frameCount) {
|
|
this.frames = []; // time, ...
|
|
this.frames.length = frameCount;
|
|
this.drawOrders = [];
|
|
this.drawOrders.length = frameCount;
|
|
};
|
|
spine.DrawOrderTimeline.prototype = {
|
|
getFrameCount: function () {
|
|
return this.frames.length;
|
|
},
|
|
setFrame: function (frameIndex, time, drawOrder) {
|
|
this.frames[frameIndex] = time;
|
|
this.drawOrders[frameIndex] = drawOrder;
|
|
},
|
|
apply: function (skeleton, lastTime, time, firedEvents, alpha) {
|
|
var frames = this.frames;
|
|
if (time < frames[0]) return; // Time is before first frame.
|
|
|
|
var frameIndex;
|
|
if (time >= frames[frames.length - 1]) // Time is after last frame.
|
|
frameIndex = frames.length - 1;
|
|
else
|
|
frameIndex = spine.Animation.binarySearch1(frames, time) - 1;
|
|
|
|
var drawOrder = skeleton.drawOrder;
|
|
var slots = skeleton.slots;
|
|
var drawOrderToSetupIndex = this.drawOrders[frameIndex];
|
|
if (!drawOrderToSetupIndex) {
|
|
for (var i = 0, n = slots.length; i < n; i++)
|
|
drawOrder[i] = slots[i];
|
|
} else {
|
|
for (var i = 0, n = drawOrderToSetupIndex.length; i < n; i++)
|
|
drawOrder[i] = skeleton.slots[drawOrderToSetupIndex[i]];
|
|
}
|
|
|
|
}
|
|
};
|
|
|
|
spine.FfdTimeline = function (frameCount) {
|
|
this.curves = new spine.Curves(frameCount);
|
|
this.frames = [];
|
|
this.frames.length = frameCount;
|
|
this.frameVertices = [];
|
|
this.frameVertices.length = frameCount;
|
|
};
|
|
spine.FfdTimeline.prototype = {
|
|
slotIndex: 0,
|
|
attachment: 0,
|
|
getFrameCount: function () {
|
|
return this.frames.length;
|
|
},
|
|
setFrame: function (frameIndex, time, vertices) {
|
|
this.frames[frameIndex] = time;
|
|
this.frameVertices[frameIndex] = vertices;
|
|
},
|
|
apply: function (skeleton, lastTime, time, firedEvents, alpha) {
|
|
var slot = skeleton.slots[this.slotIndex];
|
|
if (slot.attachment != this.attachment) return;
|
|
|
|
var frames = this.frames;
|
|
if (time < frames[0]) return; // Time is before first frame.
|
|
|
|
var frameVertices = this.frameVertices;
|
|
var vertexCount = frameVertices[0].length;
|
|
|
|
var vertices = slot.attachmentVertices;
|
|
if (vertices.length != vertexCount) alpha = 1;
|
|
vertices.length = vertexCount;
|
|
|
|
if (time >= frames[frames.length - 1]) { // Time is after last frame.
|
|
var lastVertices = frameVertices[frames.length - 1];
|
|
if (alpha < 1) {
|
|
for (var i = 0; i < vertexCount; i++)
|
|
vertices[i] += (lastVertices[i] - vertices[i]) * alpha;
|
|
} else {
|
|
for (var i = 0; i < vertexCount; i++)
|
|
vertices[i] = lastVertices[i];
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Interpolate between the previous frame and the current frame.
|
|
var frameIndex = spine.Animation.binarySearch1(frames, time);
|
|
var frameTime = frames[frameIndex];
|
|
var percent = 1 - (time - frameTime) / (frames[frameIndex - 1] - frameTime);
|
|
percent = this.curves.getCurvePercent(frameIndex - 1, percent < 0 ? 0 : (percent > 1 ? 1 : percent));
|
|
|
|
var prevVertices = frameVertices[frameIndex - 1];
|
|
var nextVertices = frameVertices[frameIndex];
|
|
|
|
if (alpha < 1) {
|
|
for (var i = 0; i < vertexCount; i++) {
|
|
var prev = prevVertices[i];
|
|
vertices[i] += (prev + (nextVertices[i] - prev) * percent - vertices[i]) * alpha;
|
|
}
|
|
} else {
|
|
for (var i = 0; i < vertexCount; i++) {
|
|
var prev = prevVertices[i];
|
|
vertices[i] = prev + (nextVertices[i] - prev) * percent;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
spine.IkConstraintTimeline = function (frameCount) {
|
|
this.curves = new spine.Curves(frameCount);
|
|
this.frames = []; // time, mix, bendDirection, ...
|
|
this.frames.length = frameCount * 3;
|
|
};
|
|
spine.IkConstraintTimeline.prototype = {
|
|
ikConstraintIndex: 0,
|
|
getFrameCount: function () {
|
|
return this.frames.length / 3;
|
|
},
|
|
setFrame: function (frameIndex, time, mix, bendDirection) {
|
|
frameIndex *= 3;
|
|
this.frames[frameIndex] = time;
|
|
this.frames[frameIndex + 1] = mix;
|
|
this.frames[frameIndex + 2] = bendDirection;
|
|
},
|
|
apply: function (skeleton, lastTime, time, firedEvents, alpha) {
|
|
var frames = this.frames;
|
|
if (time < frames[0]) return; // Time is before first frame.
|
|
|
|
var ikConstraint = skeleton.ikConstraints[this.ikConstraintIndex];
|
|
|
|
if (time >= frames[frames.length - 3]) { // Time is after last frame.
|
|
ikConstraint.mix += (frames[frames.length - 2] - ikConstraint.mix) * alpha;
|
|
ikConstraint.bendDirection = frames[frames.length - 1];
|
|
return;
|
|
}
|
|
|
|
// Interpolate between the previous frame and the current frame.
|
|
var frameIndex = spine.Animation.binarySearch(frames, time, 3);
|
|
var prevFrameMix = frames[frameIndex + -2/*PREV_FRAME_MIX*/];
|
|
var frameTime = frames[frameIndex];
|
|
var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*PREV_FRAME_TIME*/] - frameTime);
|
|
percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent);
|
|
|
|
var mix = prevFrameMix + (frames[frameIndex + 1/*FRAME_MIX*/] - prevFrameMix) * percent;
|
|
ikConstraint.mix += (mix - ikConstraint.mix) * alpha;
|
|
ikConstraint.bendDirection = frames[frameIndex + -1/*PREV_FRAME_BEND_DIRECTION*/];
|
|
}
|
|
};
|
|
|
|
spine.FlipXTimeline = function (frameCount) {
|
|
this.curves = new spine.Curves(frameCount);
|
|
this.frames = []; // time, flip, ...
|
|
this.frames.length = frameCount * 2;
|
|
};
|
|
spine.FlipXTimeline.prototype = {
|
|
boneIndex: 0,
|
|
getFrameCount: function () {
|
|
return this.frames.length / 2;
|
|
},
|
|
setFrame: function (frameIndex, time, flip) {
|
|
frameIndex *= 2;
|
|
this.frames[frameIndex] = time;
|
|
this.frames[frameIndex + 1] = flip ? 1 : 0;
|
|
},
|
|
apply: function (skeleton, lastTime, time, firedEvents, alpha) {
|
|
var frames = this.frames;
|
|
if (time < frames[0]) {
|
|
if (lastTime > time) this.apply(skeleton, lastTime, Number.MAX_VALUE, null, 0);
|
|
return;
|
|
} else if (lastTime > time) //
|
|
lastTime = -1;
|
|
var frameIndex = (time >= frames[frames.length - 2] ? frames.length : spine.Animation.binarySearch(frames, time, 2)) - 2;
|
|
if (frames[frameIndex] < lastTime) return;
|
|
skeleton.bones[boneIndex].flipX = frames[frameIndex + 1] != 0;
|
|
}
|
|
};
|
|
|
|
spine.FlipYTimeline = function (frameCount) {
|
|
this.curves = new spine.Curves(frameCount);
|
|
this.frames = []; // time, flip, ...
|
|
this.frames.length = frameCount * 2;
|
|
};
|
|
spine.FlipYTimeline.prototype = {
|
|
boneIndex: 0,
|
|
getFrameCount: function () {
|
|
return this.frames.length / 2;
|
|
},
|
|
setFrame: function (frameIndex, time, flip) {
|
|
frameIndex *= 2;
|
|
this.frames[frameIndex] = time;
|
|
this.frames[frameIndex + 1] = flip ? 1 : 0;
|
|
},
|
|
apply: function (skeleton, lastTime, time, firedEvents, alpha) {
|
|
var frames = this.frames;
|
|
if (time < frames[0]) {
|
|
if (lastTime > time) this.apply(skeleton, lastTime, Number.MAX_VALUE, null, 0);
|
|
return;
|
|
} else if (lastTime > time) //
|
|
lastTime = -1;
|
|
var frameIndex = (time >= frames[frames.length - 2] ? frames.length : spine.Animation.binarySearch(frames, time, 2)) - 2;
|
|
if (frames[frameIndex] < lastTime) return;
|
|
skeleton.bones[boneIndex].flipY = frames[frameIndex + 1] != 0;
|
|
}
|
|
};
|
|
|
|
spine.SkeletonData = function () {
|
|
this.bones = [];
|
|
this.slots = [];
|
|
this.skins = [];
|
|
this.events = [];
|
|
this.animations = [];
|
|
this.ikConstraints = [];
|
|
};
|
|
spine.SkeletonData.prototype = {
|
|
name: null,
|
|
defaultSkin: null,
|
|
width: 0, height: 0,
|
|
version: null, hash: null,
|
|
/** @return May be null. */
|
|
findBone: function (boneName) {
|
|
var bones = this.bones;
|
|
for (var i = 0, n = bones.length; i < n; i++)
|
|
if (bones[i].name == boneName) return bones[i];
|
|
return null;
|
|
},
|
|
/** @return -1 if the bone was not found. */
|
|
findBoneIndex: function (boneName) {
|
|
var bones = this.bones;
|
|
for (var i = 0, n = bones.length; i < n; i++)
|
|
if (bones[i].name == boneName) return i;
|
|
return -1;
|
|
},
|
|
/** @return May be null. */
|
|
findSlot: function (slotName) {
|
|
var slots = this.slots;
|
|
for (var i = 0, n = slots.length; i < n; i++) {
|
|
if (slots[i].name == slotName) return slot[i];
|
|
}
|
|
return null;
|
|
},
|
|
/** @return -1 if the bone was not found. */
|
|
findSlotIndex: function (slotName) {
|
|
var slots = this.slots;
|
|
for (var i = 0, n = slots.length; i < n; i++)
|
|
if (slots[i].name == slotName) return i;
|
|
return -1;
|
|
},
|
|
/** @return May be null. */
|
|
findSkin: function (skinName) {
|
|
var skins = this.skins;
|
|
for (var i = 0, n = skins.length; i < n; i++)
|
|
if (skins[i].name == skinName) return skins[i];
|
|
return null;
|
|
},
|
|
/** @return May be null. */
|
|
findEvent: function (eventName) {
|
|
var events = this.events;
|
|
for (var i = 0, n = events.length; i < n; i++)
|
|
if (events[i].name == eventName) return events[i];
|
|
return null;
|
|
},
|
|
/** @return May be null. */
|
|
findAnimation: function (animationName) {
|
|
var animations = this.animations;
|
|
for (var i = 0, n = animations.length; i < n; i++)
|
|
if (animations[i].name == animationName) return animations[i];
|
|
return null;
|
|
},
|
|
/** @return May be null. */
|
|
findIkConstraint: function (ikConstraintName) {
|
|
var ikConstraints = this.ikConstraints;
|
|
for (var i = 0, n = ikConstraints.length; i < n; i++)
|
|
if (ikConstraints[i].name == ikConstraintName) return ikConstraints[i];
|
|
return null;
|
|
}
|
|
};
|
|
|
|
spine.Skeleton = function (skeletonData) {
|
|
this.data = skeletonData;
|
|
|
|
this.bones = [];
|
|
for (var i = 0, n = skeletonData.bones.length; i < n; i++) {
|
|
var boneData = skeletonData.bones[i];
|
|
var parent = !boneData.parent ? null : this.bones[skeletonData.bones.indexOf(boneData.parent)];
|
|
this.bones.push(new spine.Bone(boneData, this, parent));
|
|
}
|
|
|
|
this.slots = [];
|
|
this.drawOrder = [];
|
|
for (var i = 0, n = skeletonData.slots.length; i < n; i++) {
|
|
var slotData = skeletonData.slots[i];
|
|
var bone = this.bones[skeletonData.bones.indexOf(slotData.boneData)];
|
|
var slot = new spine.Slot(slotData, bone);
|
|
this.slots.push(slot);
|
|
this.drawOrder.push(slot);
|
|
}
|
|
|
|
this.ikConstraints = [];
|
|
for (var i = 0, n = skeletonData.ikConstraints.length; i < n; i++)
|
|
this.ikConstraints.push(new spine.IkConstraint(skeletonData.ikConstraints[i], this));
|
|
|
|
this.boneCache = [];
|
|
this.updateCache();
|
|
};
|
|
spine.Skeleton.prototype = {
|
|
x: 0, y: 0,
|
|
skin: null,
|
|
r: 1, g: 1, b: 1, a: 1,
|
|
time: 0,
|
|
flipX: false, flipY: false,
|
|
/** Caches information about bones and IK constraints. Must be called if bones or IK constraints are added or removed. */
|
|
updateCache: function () {
|
|
var ikConstraints = this.ikConstraints;
|
|
var ikConstraintsCount = ikConstraints.length;
|
|
|
|
var arrayCount = ikConstraintsCount + 1;
|
|
var boneCache = this.boneCache;
|
|
if (boneCache.length > arrayCount) boneCache.length = arrayCount;
|
|
for (var i = 0, n = boneCache.length; i < n; i++)
|
|
boneCache[i].length = 0;
|
|
while (boneCache.length < arrayCount)
|
|
boneCache[boneCache.length] = [];
|
|
|
|
var nonIkBones = boneCache[0];
|
|
var bones = this.bones;
|
|
|
|
outer:
|
|
for (var i = 0, n = bones.length; i < n; i++) {
|
|
var bone = bones[i];
|
|
var current = bone;
|
|
do {
|
|
for (var ii = 0; ii < ikConstraintsCount; ii++) {
|
|
var ikConstraint = ikConstraints[ii];
|
|
var parent = ikConstraint.bones[0];
|
|
var child= ikConstraint.bones[ikConstraint.bones.length - 1];
|
|
while (true) {
|
|
if (current == child) {
|
|
boneCache[ii].push(bone);
|
|
boneCache[ii + 1].push(bone);
|
|
continue outer;
|
|
}
|
|
if (child == parent) break;
|
|
child = child.parent;
|
|
}
|
|
}
|
|
current = current.parent;
|
|
} while (current);
|
|
nonIkBones[nonIkBones.length] = bone;
|
|
}
|
|
},
|
|
/** Updates the world transform for each bone. */
|
|
updateWorldTransform: function () {
|
|
var bones = this.bones;
|
|
for (var i = 0, n = bones.length; i < n; i++) {
|
|
var bone = bones[i];
|
|
bone.rotationIK = bone.rotation;
|
|
}
|
|
var i = 0, last = this.boneCache.length - 1;
|
|
while (true) {
|
|
var cacheBones = this.boneCache[i];
|
|
for (var ii = 0, nn = cacheBones.length; ii < nn; ii++)
|
|
cacheBones[ii].updateWorldTransform();
|
|
if (i == last) break;
|
|
this.ikConstraints[i].apply();
|
|
i++;
|
|
}
|
|
},
|
|
/** Sets the bones and slots to their setup pose values. */
|
|
setToSetupPose: function () {
|
|
this.setBonesToSetupPose();
|
|
this.setSlotsToSetupPose();
|
|
},
|
|
setBonesToSetupPose: function () {
|
|
var bones = this.bones;
|
|
for (var i = 0, n = bones.length; i < n; i++)
|
|
bones[i].setToSetupPose();
|
|
|
|
var ikConstraints = this.ikConstraints;
|
|
for (var i = 0, n = ikConstraints.length; i < n; i++) {
|
|
var ikConstraint = ikConstraints[i];
|
|
ikConstraint.bendDirection = ikConstraint.data.bendDirection;
|
|
ikConstraint.mix = ikConstraint.data.mix;
|
|
}
|
|
},
|
|
setSlotsToSetupPose: function () {
|
|
var slots = this.slots;
|
|
var drawOrder = this.drawOrder;
|
|
for (var i = 0, n = slots.length; i < n; i++) {
|
|
drawOrder[i] = slots[i];
|
|
slots[i].setToSetupPose(i);
|
|
}
|
|
},
|
|
/** @return May return null. */
|
|
getRootBone: function () {
|
|
return this.bones.length ? this.bones[0] : null;
|
|
},
|
|
/** @return May be null. */
|
|
findBone: function (boneName) {
|
|
var bones = this.bones;
|
|
for (var i = 0, n = bones.length; i < n; i++)
|
|
if (bones[i].data.name == boneName) return bones[i];
|
|
return null;
|
|
},
|
|
/** @return -1 if the bone was not found. */
|
|
findBoneIndex: function (boneName) {
|
|
var bones = this.bones;
|
|
for (var i = 0, n = bones.length; i < n; i++)
|
|
if (bones[i].data.name == boneName) return i;
|
|
return -1;
|
|
},
|
|
/** @return May be null. */
|
|
findSlot: function (slotName) {
|
|
var slots = this.slots;
|
|
for (var i = 0, n = slots.length; i < n; i++)
|
|
if (slots[i].data.name == slotName) return slots[i];
|
|
return null;
|
|
},
|
|
/** @return -1 if the bone was not found. */
|
|
findSlotIndex: function (slotName) {
|
|
var slots = this.slots;
|
|
for (var i = 0, n = slots.length; i < n; i++)
|
|
if (slots[i].data.name == slotName) return i;
|
|
return -1;
|
|
},
|
|
setSkinByName: function (skinName) {
|
|
var skin = this.data.findSkin(skinName);
|
|
if (!skin) throw "Skin not found: " + skinName;
|
|
this.setSkin(skin);
|
|
},
|
|
/** Sets the skin used to look up attachments before looking in the {@link SkeletonData#getDefaultSkin() default skin}.
|
|
* Attachments from the new skin are attached if the corresponding attachment from the old skin was attached. If there was
|
|
* no old skin, each slot's setup mode attachment is attached from the new skin.
|
|
* @param newSkin May be null. */
|
|
setSkin: function (newSkin) {
|
|
if (newSkin) {
|
|
if (this.skin)
|
|
newSkin._attachAll(this, this.skin);
|
|
else {
|
|
var slots = this.slots;
|
|
for (var i = 0, n = slots.length; i < n; i++) {
|
|
var slot = slots[i];
|
|
var name = slot.data.attachmentName;
|
|
if (name) {
|
|
var attachment = newSkin.getAttachment(i, name);
|
|
if (attachment) slot.setAttachment(attachment);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
this.skin = newSkin;
|
|
},
|
|
/** @return May be null. */
|
|
getAttachmentBySlotName: function (slotName, attachmentName) {
|
|
return this.getAttachmentBySlotIndex(this.data.findSlotIndex(slotName), attachmentName);
|
|
},
|
|
/** @return May be null. */
|
|
getAttachmentBySlotIndex: function (slotIndex, attachmentName) {
|
|
if (this.skin) {
|
|
var attachment = this.skin.getAttachment(slotIndex, attachmentName);
|
|
if (attachment) return attachment;
|
|
}
|
|
if (this.data.defaultSkin) return this.data.defaultSkin.getAttachment(slotIndex, attachmentName);
|
|
return null;
|
|
},
|
|
/** @param attachmentName May be null. */
|
|
setAttachment: function (slotName, attachmentName) {
|
|
var slots = this.slots;
|
|
for (var i = 0, n = slots.length; i < n; i++) {
|
|
var slot = slots[i];
|
|
if (slot.data.name == slotName) {
|
|
var attachment = null;
|
|
if (attachmentName) {
|
|
attachment = this.getAttachmentBySlotIndex(i, attachmentName);
|
|
if (!attachment) throw "Attachment not found: " + attachmentName + ", for slot: " + slotName;
|
|
}
|
|
slot.setAttachment(attachment);
|
|
return;
|
|
}
|
|
}
|
|
throw "Slot not found: " + slotName;
|
|
},
|
|
/** @return May be null. */
|
|
findIkConstraint: function (ikConstraintName) {
|
|
var ikConstraints = this.ikConstraints;
|
|
for (var i = 0, n = ikConstraints.length; i < n; i++)
|
|
if (ikConstraints[i].data.name == ikConstraintName) return ikConstraints[i];
|
|
return null;
|
|
},
|
|
update: function (delta) {
|
|
this.time += delta;
|
|
}
|
|
};
|
|
|
|
spine.EventData = function (name) {
|
|
this.name = name;
|
|
};
|
|
spine.EventData.prototype = {
|
|
intValue: 0,
|
|
floatValue: 0,
|
|
stringValue: null
|
|
};
|
|
|
|
spine.Event = function (data) {
|
|
this.data = data;
|
|
};
|
|
spine.Event.prototype = {
|
|
intValue: 0,
|
|
floatValue: 0,
|
|
stringValue: null
|
|
};
|
|
|
|
spine.AttachmentType = {
|
|
region: 0,
|
|
boundingbox: 1,
|
|
mesh: 2,
|
|
skinnedmesh: 3
|
|
};
|
|
|
|
spine.RegionAttachment = function (name) {
|
|
this.name = name;
|
|
this.offset = [];
|
|
this.offset.length = 8;
|
|
this.uvs = [];
|
|
this.uvs.length = 8;
|
|
};
|
|
spine.RegionAttachment.prototype = {
|
|
type: spine.AttachmentType.region,
|
|
x: 0, y: 0,
|
|
rotation: 0,
|
|
scaleX: 1, scaleY: 1,
|
|
width: 0, height: 0,
|
|
r: 1, g: 1, b: 1, a: 1,
|
|
path: null,
|
|
rendererObject: null,
|
|
regionOffsetX: 0, regionOffsetY: 0,
|
|
regionWidth: 0, regionHeight: 0,
|
|
regionOriginalWidth: 0, regionOriginalHeight: 0,
|
|
setUVs: function (u, v, u2, v2, rotate) {
|
|
var uvs = this.uvs;
|
|
if (rotate) {
|
|
uvs[2/*X2*/] = u;
|
|
uvs[3/*Y2*/] = v2;
|
|
uvs[4/*X3*/] = u;
|
|
uvs[5/*Y3*/] = v;
|
|
uvs[6/*X4*/] = u2;
|
|
uvs[7/*Y4*/] = v;
|
|
uvs[0/*X1*/] = u2;
|
|
uvs[1/*Y1*/] = v2;
|
|
} else {
|
|
uvs[0/*X1*/] = u;
|
|
uvs[1/*Y1*/] = v2;
|
|
uvs[2/*X2*/] = u;
|
|
uvs[3/*Y2*/] = v;
|
|
uvs[4/*X3*/] = u2;
|
|
uvs[5/*Y3*/] = v;
|
|
uvs[6/*X4*/] = u2;
|
|
uvs[7/*Y4*/] = v2;
|
|
}
|
|
},
|
|
updateOffset: function () {
|
|
var regionScaleX = this.width / this.regionOriginalWidth * this.scaleX;
|
|
var regionScaleY = this.height / this.regionOriginalHeight * this.scaleY;
|
|
var localX = -this.width / 2 * this.scaleX + this.regionOffsetX * regionScaleX;
|
|
var localY = -this.height / 2 * this.scaleY + this.regionOffsetY * regionScaleY;
|
|
var localX2 = localX + this.regionWidth * regionScaleX;
|
|
var localY2 = localY + this.regionHeight * regionScaleY;
|
|
var radians = this.rotation * spine.degRad;
|
|
var cos = Math.cos(radians);
|
|
var sin = Math.sin(radians);
|
|
var localXCos = localX * cos + this.x;
|
|
var localXSin = localX * sin;
|
|
var localYCos = localY * cos + this.y;
|
|
var localYSin = localY * sin;
|
|
var localX2Cos = localX2 * cos + this.x;
|
|
var localX2Sin = localX2 * sin;
|
|
var localY2Cos = localY2 * cos + this.y;
|
|
var localY2Sin = localY2 * sin;
|
|
var offset = this.offset;
|
|
offset[0/*X1*/] = localXCos - localYSin;
|
|
offset[1/*Y1*/] = localYCos + localXSin;
|
|
offset[2/*X2*/] = localXCos - localY2Sin;
|
|
offset[3/*Y2*/] = localY2Cos + localXSin;
|
|
offset[4/*X3*/] = localX2Cos - localY2Sin;
|
|
offset[5/*Y3*/] = localY2Cos + localX2Sin;
|
|
offset[6/*X4*/] = localX2Cos - localYSin;
|
|
offset[7/*Y4*/] = localYCos + localX2Sin;
|
|
},
|
|
computeVertices: function (x, y, bone, vertices) {
|
|
x += bone.worldX;
|
|
y += bone.worldY;
|
|
var m00 = bone.m00, m01 = bone.m01, m10 = bone.m10, m11 = bone.m11;
|
|
var offset = this.offset;
|
|
vertices[0/*X1*/] = offset[0/*X1*/] * m00 + offset[1/*Y1*/] * m01 + x;
|
|
vertices[1/*Y1*/] = offset[0/*X1*/] * m10 + offset[1/*Y1*/] * m11 + y;
|
|
vertices[2/*X2*/] = offset[2/*X2*/] * m00 + offset[3/*Y2*/] * m01 + x;
|
|
vertices[3/*Y2*/] = offset[2/*X2*/] * m10 + offset[3/*Y2*/] * m11 + y;
|
|
vertices[4/*X3*/] = offset[4/*X3*/] * m00 + offset[5/*X3*/] * m01 + x;
|
|
vertices[5/*X3*/] = offset[4/*X3*/] * m10 + offset[5/*X3*/] * m11 + y;
|
|
vertices[6/*X4*/] = offset[6/*X4*/] * m00 + offset[7/*Y4*/] * m01 + x;
|
|
vertices[7/*Y4*/] = offset[6/*X4*/] * m10 + offset[7/*Y4*/] * m11 + y;
|
|
}
|
|
};
|
|
|
|
spine.MeshAttachment = function (name) {
|
|
this.name = name;
|
|
};
|
|
spine.MeshAttachment.prototype = {
|
|
type: spine.AttachmentType.mesh,
|
|
vertices: null,
|
|
uvs: null,
|
|
regionUVs: null,
|
|
triangles: null,
|
|
hullLength: 0,
|
|
r: 1, g: 1, b: 1, a: 1,
|
|
path: null,
|
|
rendererObject: null,
|
|
regionU: 0, regionV: 0, regionU2: 0, regionV2: 0, regionRotate: false,
|
|
regionOffsetX: 0, regionOffsetY: 0,
|
|
regionWidth: 0, regionHeight: 0,
|
|
regionOriginalWidth: 0, regionOriginalHeight: 0,
|
|
edges: null,
|
|
width: 0, height: 0,
|
|
updateUVs: function () {
|
|
var width = this.regionU2 - this.regionU, height = this.regionV2 - this.regionV;
|
|
var n = this.regionUVs.length;
|
|
if (!this.uvs || this.uvs.length != n) {
|
|
this.uvs = new spine.Float32Array(n);
|
|
}
|
|
if (this.regionRotate) {
|
|
for (var i = 0; i < n; i += 2) {
|
|
this.uvs[i] = this.regionU + this.regionUVs[i + 1] * width;
|
|
this.uvs[i + 1] = this.regionV + height - this.regionUVs[i] * height;
|
|
}
|
|
} else {
|
|
for (var i = 0; i < n; i += 2) {
|
|
this.uvs[i] = this.regionU + this.regionUVs[i] * width;
|
|
this.uvs[i + 1] = this.regionV + this.regionUVs[i + 1] * height;
|
|
}
|
|
}
|
|
},
|
|
computeWorldVertices: function (x, y, slot, worldVertices) {
|
|
var bone = slot.bone;
|
|
x += bone.worldX;
|
|
y += bone.worldY;
|
|
var m00 = bone.m00, m01 = bone.m01, m10 = bone.m10, m11 = bone.m11;
|
|
var vertices = this.vertices;
|
|
var verticesCount = vertices.length;
|
|
if (slot.attachmentVertices.length == verticesCount) vertices = slot.attachmentVertices;
|
|
for (var i = 0; i < verticesCount; i += 2) {
|
|
var vx = vertices[i];
|
|
var vy = vertices[i + 1];
|
|
worldVertices[i] = vx * m00 + vy * m01 + x;
|
|
worldVertices[i + 1] = vx * m10 + vy * m11 + y;
|
|
}
|
|
}
|
|
};
|
|
|
|
spine.SkinnedMeshAttachment = function (name) {
|
|
this.name = name;
|
|
};
|
|
spine.SkinnedMeshAttachment.prototype = {
|
|
type: spine.AttachmentType.skinnedmesh,
|
|
bones: null,
|
|
weights: null,
|
|
uvs: null,
|
|
regionUVs: null,
|
|
triangles: null,
|
|
hullLength: 0,
|
|
r: 1, g: 1, b: 1, a: 1,
|
|
path: null,
|
|
rendererObject: null,
|
|
regionU: 0, regionV: 0, regionU2: 0, regionV2: 0, regionRotate: false,
|
|
regionOffsetX: 0, regionOffsetY: 0,
|
|
regionWidth: 0, regionHeight: 0,
|
|
regionOriginalWidth: 0, regionOriginalHeight: 0,
|
|
edges: null,
|
|
width: 0, height: 0,
|
|
updateUVs: function (u, v, u2, v2, rotate) {
|
|
var width = this.regionU2 - this.regionU, height = this.regionV2 - this.regionV;
|
|
var n = this.regionUVs.length;
|
|
if (!this.uvs || this.uvs.length != n) {
|
|
this.uvs = new spine.Float32Array(n);
|
|
}
|
|
if (this.regionRotate) {
|
|
for (var i = 0; i < n; i += 2) {
|
|
this.uvs[i] = this.regionU + this.regionUVs[i + 1] * width;
|
|
this.uvs[i + 1] = this.regionV + height - this.regionUVs[i] * height;
|
|
}
|
|
} else {
|
|
for (var i = 0; i < n; i += 2) {
|
|
this.uvs[i] = this.regionU + this.regionUVs[i] * width;
|
|
this.uvs[i + 1] = this.regionV + this.regionUVs[i + 1] * height;
|
|
}
|
|
}
|
|
},
|
|
computeWorldVertices: function (x, y, slot, worldVertices) {
|
|
var skeletonBones = slot.bone.skeleton.bones;
|
|
var weights = this.weights;
|
|
var bones = this.bones;
|
|
|
|
var w = 0, v = 0, b = 0, f = 0, n = bones.length, nn;
|
|
var wx, wy, bone, vx, vy, weight;
|
|
if (!slot.attachmentVertices.length) {
|
|
for (; v < n; w += 2) {
|
|
wx = 0;
|
|
wy = 0;
|
|
nn = bones[v++] + v;
|
|
for (; v < nn; v++, b += 3) {
|
|
bone = skeletonBones[bones[v]];
|
|
vx = weights[b];
|
|
vy = weights[b + 1];
|
|
weight = weights[b + 2];
|
|
wx += (vx * bone.m00 + vy * bone.m01 + bone.worldX) * weight;
|
|
wy += (vx * bone.m10 + vy * bone.m11 + bone.worldY) * weight;
|
|
}
|
|
worldVertices[w] = wx + x;
|
|
worldVertices[w + 1] = wy + y;
|
|
}
|
|
} else {
|
|
var ffd = slot.attachmentVertices;
|
|
for (; v < n; w += 2) {
|
|
wx = 0;
|
|
wy = 0;
|
|
nn = bones[v++] + v;
|
|
for (; v < nn; v++, b += 3, f += 2) {
|
|
bone = skeletonBones[bones[v]];
|
|
vx = weights[b] + ffd[f];
|
|
vy = weights[b + 1] + ffd[f + 1];
|
|
weight = weights[b + 2];
|
|
wx += (vx * bone.m00 + vy * bone.m01 + bone.worldX) * weight;
|
|
wy += (vx * bone.m10 + vy * bone.m11 + bone.worldY) * weight;
|
|
}
|
|
worldVertices[w] = wx + x;
|
|
worldVertices[w + 1] = wy + y;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
spine.BoundingBoxAttachment = function (name) {
|
|
this.name = name;
|
|
this.vertices = [];
|
|
};
|
|
spine.BoundingBoxAttachment.prototype = {
|
|
type: spine.AttachmentType.boundingbox,
|
|
computeWorldVertices: function (x, y, bone, worldVertices) {
|
|
x += bone.worldX;
|
|
y += bone.worldY;
|
|
var m00 = bone.m00, m01 = bone.m01, m10 = bone.m10, m11 = bone.m11;
|
|
var vertices = this.vertices;
|
|
for (var i = 0, n = vertices.length; i < n; i += 2) {
|
|
var px = vertices[i];
|
|
var py = vertices[i + 1];
|
|
worldVertices[i] = px * m00 + py * m01 + x;
|
|
worldVertices[i + 1] = px * m10 + py * m11 + y;
|
|
}
|
|
}
|
|
};
|
|
|
|
spine.AnimationStateData = function (skeletonData) {
|
|
this.skeletonData = skeletonData;
|
|
this.animationToMixTime = {};
|
|
};
|
|
spine.AnimationStateData.prototype = {
|
|
defaultMix: 0,
|
|
setMixByName: function (fromName, toName, duration) {
|
|
var from = this.skeletonData.findAnimation(fromName);
|
|
if (!from) throw "Animation not found: " + fromName;
|
|
var to = this.skeletonData.findAnimation(toName);
|
|
if (!to) throw "Animation not found: " + toName;
|
|
this.setMix(from, to, duration);
|
|
},
|
|
setMix: function (from, to, duration) {
|
|
this.animationToMixTime[from.name + ":" + to.name] = duration;
|
|
},
|
|
getMix: function (from, to) {
|
|
var key = from.name + ":" + to.name;
|
|
return this.animationToMixTime.hasOwnProperty(key) ? this.animationToMixTime[key] : this.defaultMix;
|
|
}
|
|
};
|
|
|
|
spine.TrackEntry = function () {};
|
|
spine.TrackEntry.prototype = {
|
|
next: null, previous: null,
|
|
animation: null,
|
|
loop: false,
|
|
delay: 0, time: 0, lastTime: -1, endTime: 0,
|
|
timeScale: 1,
|
|
mixTime: 0, mixDuration: 0, mix: 1,
|
|
onStart: null, onEnd: null, onComplete: null, onEvent: null
|
|
};
|
|
|
|
spine.AnimationState = function (stateData) {
|
|
this.data = stateData;
|
|
this.tracks = [];
|
|
this.events = [];
|
|
};
|
|
spine.AnimationState.prototype = {
|
|
onStart: null,
|
|
onEnd: null,
|
|
onComplete: null,
|
|
onEvent: null,
|
|
timeScale: 1,
|
|
update: function (delta) {
|
|
delta *= this.timeScale;
|
|
for (var i = 0; i < this.tracks.length; i++) {
|
|
var current = this.tracks[i];
|
|
if (!current) continue;
|
|
|
|
current.time += delta * current.timeScale;
|
|
if (current.previous) {
|
|
var previousDelta = delta * current.previous.timeScale;
|
|
current.previous.time += previousDelta;
|
|
current.mixTime += previousDelta;
|
|
}
|
|
|
|
var next = current.next;
|
|
if (next) {
|
|
next.time = current.lastTime - next.delay;
|
|
if (next.time >= 0) this.setCurrent(i, next);
|
|
} else {
|
|
// End non-looping animation when it reaches its end time and there is no next entry.
|
|
if (!current.loop && current.lastTime >= current.endTime) this.clearTrack(i);
|
|
}
|
|
}
|
|
},
|
|
apply: function (skeleton) {
|
|
for (var i = 0; i < this.tracks.length; i++) {
|
|
var current = this.tracks[i];
|
|
if (!current) continue;
|
|
|
|
this.events.length = 0;
|
|
|
|
var time = current.time;
|
|
var lastTime = current.lastTime;
|
|
var endTime = current.endTime;
|
|
var loop = current.loop;
|
|
if (!loop && time > endTime) time = endTime;
|
|
|
|
var previous = current.previous;
|
|
if (!previous) {
|
|
if (current.mix == 1)
|
|
current.animation.apply(skeleton, current.lastTime, time, loop, this.events);
|
|
else
|
|
current.animation.mix(skeleton, current.lastTime, time, loop, this.events, current.mix);
|
|
} else {
|
|
var previousTime = previous.time;
|
|
if (!previous.loop && previousTime > previous.endTime) previousTime = previous.endTime;
|
|
previous.animation.apply(skeleton, previousTime, previousTime, previous.loop, null);
|
|
|
|
var alpha = current.mixTime / current.mixDuration * current.mix;
|
|
if (alpha >= 1) {
|
|
alpha = 1;
|
|
current.previous = null;
|
|
}
|
|
current.animation.mix(skeleton, current.lastTime, time, loop, this.events, alpha);
|
|
}
|
|
|
|
for (var ii = 0, nn = this.events.length; ii < nn; ii++) {
|
|
var event = this.events[ii];
|
|
if (current.onEvent) current.onEvent(i, event);
|
|
if (this.onEvent) this.onEvent(i, event);
|
|
}
|
|
|
|
// Check if completed the animation or a loop iteration.
|
|
if (loop ? (lastTime % endTime > time % endTime) : (lastTime < endTime && time >= endTime)) {
|
|
var count = Math.floor(time / endTime);
|
|
if (current.onComplete) current.onComplete(i, count);
|
|
if (this.onComplete) this.onComplete(i, count);
|
|
}
|
|
|
|
current.lastTime = current.time;
|
|
}
|
|
},
|
|
clearTracks: function () {
|
|
for (var i = 0, n = this.tracks.length; i < n; i++)
|
|
this.clearTrack(i);
|
|
this.tracks.length = 0;
|
|
},
|
|
clearTrack: function (trackIndex) {
|
|
if (trackIndex >= this.tracks.length) return;
|
|
var current = this.tracks[trackIndex];
|
|
if (!current) return;
|
|
|
|
if (current.onEnd) current.onEnd(trackIndex);
|
|
if (this.onEnd) this.onEnd(trackIndex);
|
|
|
|
this.tracks[trackIndex] = null;
|
|
},
|
|
_expandToIndex: function (index) {
|
|
if (index < this.tracks.length) return this.tracks[index];
|
|
while (index >= this.tracks.length)
|
|
this.tracks.push(null);
|
|
return null;
|
|
},
|
|
setCurrent: function (index, entry) {
|
|
var current = this._expandToIndex(index);
|
|
if (current) {
|
|
var previous = current.previous;
|
|
current.previous = null;
|
|
|
|
if (current.onEnd) current.onEnd(index);
|
|
if (this.onEnd) this.onEnd(index);
|
|
|
|
entry.mixDuration = this.data.getMix(current.animation, entry.animation);
|
|
if (entry.mixDuration > 0) {
|
|
entry.mixTime = 0;
|
|
// If a mix is in progress, mix from the closest animation.
|
|
if (previous && current.mixTime / current.mixDuration < 0.5)
|
|
entry.previous = previous;
|
|
else
|
|
entry.previous = current;
|
|
}
|
|
}
|
|
|
|
this.tracks[index] = entry;
|
|
|
|
if (entry.onStart) entry.onStart(index);
|
|
if (this.onStart) this.onStart(index);
|
|
},
|
|
setAnimationByName: function (trackIndex, animationName, loop) {
|
|
var animation = this.data.skeletonData.findAnimation(animationName);
|
|
if (!animation) throw "Animation not found: " + animationName;
|
|
return this.setAnimation(trackIndex, animation, loop);
|
|
},
|
|
/** Set the current animation. Any queued animations are cleared. */
|
|
setAnimation: function (trackIndex, animation, loop) {
|
|
var entry = new spine.TrackEntry();
|
|
entry.animation = animation;
|
|
entry.loop = loop;
|
|
entry.endTime = animation.duration;
|
|
this.setCurrent(trackIndex, entry);
|
|
return entry;
|
|
},
|
|
addAnimationByName: function (trackIndex, animationName, loop, delay) {
|
|
var animation = this.data.skeletonData.findAnimation(animationName);
|
|
if (!animation) throw "Animation not found: " + animationName;
|
|
return this.addAnimation(trackIndex, animation, loop, delay);
|
|
},
|
|
/** Adds an animation to be played delay seconds after the current or last queued animation.
|
|
* @param delay May be <= 0 to use duration of previous animation minus any mix duration plus the negative delay. */
|
|
addAnimation: function (trackIndex, animation, loop, delay) {
|
|
var entry = new spine.TrackEntry();
|
|
entry.animation = animation;
|
|
entry.loop = loop;
|
|
entry.endTime = animation.duration;
|
|
|
|
var last = this._expandToIndex(trackIndex);
|
|
if (last) {
|
|
while (last.next)
|
|
last = last.next;
|
|
last.next = entry;
|
|
} else
|
|
this.tracks[trackIndex] = entry;
|
|
|
|
if (delay <= 0) {
|
|
if (last)
|
|
delay += last.endTime - this.data.getMix(last.animation, animation);
|
|
else
|
|
delay = 0;
|
|
}
|
|
entry.delay = delay;
|
|
|
|
return entry;
|
|
},
|
|
/** May be null. */
|
|
getCurrent: function (trackIndex) {
|
|
if (trackIndex >= this.tracks.length) return null;
|
|
return this.tracks[trackIndex];
|
|
}
|
|
};
|
|
|
|
spine.SkeletonJson = function (attachmentLoader) {
|
|
this.attachmentLoader = attachmentLoader;
|
|
};
|
|
spine.SkeletonJson.prototype = {
|
|
scale: 1,
|
|
readSkeletonData: function (root, name) {
|
|
var skeletonData = new spine.SkeletonData();
|
|
skeletonData.name = name;
|
|
|
|
// Skeleton.
|
|
var skeletonMap = root["skeleton"];
|
|
if (skeletonMap) {
|
|
skeletonData.hash = skeletonMap["hash"];
|
|
skeletonData.version = skeletonMap["spine"];
|
|
skeletonData.width = skeletonMap["width"] || 0;
|
|
skeletonData.height = skeletonMap["height"] || 0;
|
|
}
|
|
|
|
// Bones.
|
|
var bones = root["bones"];
|
|
for (var i = 0, n = bones.length; i < n; i++) {
|
|
var boneMap = bones[i];
|
|
var parent = null;
|
|
if (boneMap["parent"]) {
|
|
parent = skeletonData.findBone(boneMap["parent"]);
|
|
if (!parent) throw "Parent bone not found: " + boneMap["parent"];
|
|
}
|
|
var boneData = new spine.BoneData(boneMap["name"], parent);
|
|
boneData.length = (boneMap["length"] || 0) * this.scale;
|
|
boneData.x = (boneMap["x"] || 0) * this.scale;
|
|
boneData.y = (boneMap["y"] || 0) * this.scale;
|
|
boneData.rotation = (boneMap["rotation"] || 0);
|
|
boneData.scaleX = boneMap.hasOwnProperty("scaleX") ? boneMap["scaleX"] : 1;
|
|
boneData.scaleY = boneMap.hasOwnProperty("scaleY") ? boneMap["scaleY"] : 1;
|
|
boneData.inheritScale = boneMap.hasOwnProperty("inheritScale") ? boneMap["inheritScale"] : true;
|
|
boneData.inheritRotation = boneMap.hasOwnProperty("inheritRotation") ? boneMap["inheritRotation"] : true;
|
|
skeletonData.bones.push(boneData);
|
|
}
|
|
|
|
// IK constraints.
|
|
var ik = root["ik"];
|
|
if (ik) {
|
|
for (var i = 0, n = ik.length; i < n; i++) {
|
|
var ikMap = ik[i];
|
|
var ikConstraintData = new spine.IkConstraintData(ikMap["name"]);
|
|
|
|
var bones = ikMap["bones"];
|
|
for (var ii = 0, nn = bones.length; ii < nn; ii++) {
|
|
var bone = skeletonData.findBone(bones[ii]);
|
|
if (!bone) throw "IK bone not found: " + bones[ii];
|
|
ikConstraintData.bones.push(bone);
|
|
}
|
|
|
|
ikConstraintData.target = skeletonData.findBone(ikMap["target"]);
|
|
if (!ikConstraintData.target) throw "Target bone not found: " + ikMap["target"];
|
|
|
|
ikConstraintData.bendDirection = (!ikMap.hasOwnProperty("bendPositive") || ikMap["bendPositive"]) ? 1 : -1;
|
|
ikConstraintData.mix = ikMap.hasOwnProperty("mix") ? ikMap["mix"] : 1;
|
|
|
|
skeletonData.ikConstraints.push(ikConstraintData);
|
|
}
|
|
}
|
|
|
|
// Slots.
|
|
var slots = root["slots"];
|
|
for (var i = 0, n = slots.length; i < n; i++) {
|
|
var slotMap = slots[i];
|
|
var boneData = skeletonData.findBone(slotMap["bone"]);
|
|
if (!boneData) throw "Slot bone not found: " + slotMap["bone"];
|
|
var slotData = new spine.SlotData(slotMap["name"], boneData);
|
|
|
|
var color = slotMap["color"];
|
|
if (color) {
|
|
slotData.r = this.toColor(color, 0);
|
|
slotData.g = this.toColor(color, 1);
|
|
slotData.b = this.toColor(color, 2);
|
|
slotData.a = this.toColor(color, 3);
|
|
}
|
|
|
|
slotData.attachmentName = slotMap["attachment"];
|
|
slotData.additiveBlending = slotMap["additive"] && slotMap["additive"] == "true";
|
|
|
|
skeletonData.slots.push(slotData);
|
|
}
|
|
|
|
// Skins.
|
|
var skins = root["skins"];
|
|
for (var skinName in skins) {
|
|
if (!skins.hasOwnProperty(skinName)) continue;
|
|
var skinMap = skins[skinName];
|
|
var skin = new spine.Skin(skinName);
|
|
for (var slotName in skinMap) {
|
|
if (!skinMap.hasOwnProperty(slotName)) continue;
|
|
var slotIndex = skeletonData.findSlotIndex(slotName);
|
|
var slotEntry = skinMap[slotName];
|
|
for (var attachmentName in slotEntry) {
|
|
if (!slotEntry.hasOwnProperty(attachmentName)) continue;
|
|
var attachment = this.readAttachment(skin, attachmentName, slotEntry[attachmentName]);
|
|
if (attachment) skin.addAttachment(slotIndex, attachmentName, attachment);
|
|
}
|
|
}
|
|
skeletonData.skins.push(skin);
|
|
if (skin.name == "default") skeletonData.defaultSkin = skin;
|
|
}
|
|
|
|
// Events.
|
|
var events = root["events"];
|
|
for (var eventName in events) {
|
|
if (!events.hasOwnProperty(eventName)) continue;
|
|
var eventMap = events[eventName];
|
|
var eventData = new spine.EventData(eventName);
|
|
eventData.intValue = eventMap["int"] || 0;
|
|
eventData.floatValue = eventMap["float"] || 0;
|
|
eventData.stringValue = eventMap["string"] || null;
|
|
skeletonData.events.push(eventData);
|
|
}
|
|
|
|
// Animations.
|
|
var animations = root["animations"];
|
|
for (var animationName in animations) {
|
|
if (!animations.hasOwnProperty(animationName)) continue;
|
|
this.readAnimation(animationName, animations[animationName], skeletonData);
|
|
}
|
|
|
|
return skeletonData;
|
|
},
|
|
readAttachment: function (skin, name, map) {
|
|
name = map["name"] || name;
|
|
|
|
var type = spine.AttachmentType[map["type"] || "region"];
|
|
var path = map["path"] || name;
|
|
|
|
var scale = this.scale;
|
|
if (type == spine.AttachmentType.region) {
|
|
var region = this.attachmentLoader.newRegionAttachment(skin, name, path);
|
|
if (!region) return null;
|
|
region.path = path;
|
|
region.x = (map["x"] || 0) * scale;
|
|
region.y = (map["y"] || 0) * scale;
|
|
region.scaleX = map.hasOwnProperty("scaleX") ? map["scaleX"] : 1;
|
|
region.scaleY = map.hasOwnProperty("scaleY") ? map["scaleY"] : 1;
|
|
region.rotation = map["rotation"] || 0;
|
|
region.width = (map["width"] || 0) * scale;
|
|
region.height = (map["height"] || 0) * scale;
|
|
|
|
var color = map["color"];
|
|
if (color) {
|
|
region.r = this.toColor(color, 0);
|
|
region.g = this.toColor(color, 1);
|
|
region.b = this.toColor(color, 2);
|
|
region.a = this.toColor(color, 3);
|
|
}
|
|
|
|
region.updateOffset();
|
|
return region;
|
|
} else if (type == spine.AttachmentType.mesh) {
|
|
var mesh = this.attachmentLoader.newMeshAttachment(skin, name, path);
|
|
if (!mesh) return null;
|
|
mesh.path = path;
|
|
mesh.vertices = this.getFloatArray(map, "vertices", scale);
|
|
mesh.triangles = this.getIntArray(map, "triangles");
|
|
mesh.regionUVs = this.getFloatArray(map, "uvs", 1);
|
|
mesh.updateUVs();
|
|
|
|
color = map["color"];
|
|
if (color) {
|
|
mesh.r = this.toColor(color, 0);
|
|
mesh.g = this.toColor(color, 1);
|
|
mesh.b = this.toColor(color, 2);
|
|
mesh.a = this.toColor(color, 3);
|
|
}
|
|
|
|
mesh.hullLength = (map["hull"] || 0) * 2;
|
|
if (map["edges"]) mesh.edges = this.getIntArray(map, "edges");
|
|
mesh.width = (map["width"] || 0) * scale;
|
|
mesh.height = (map["height"] || 0) * scale;
|
|
return mesh;
|
|
} else if (type == spine.AttachmentType.skinnedmesh) {
|
|
var mesh = this.attachmentLoader.newSkinnedMeshAttachment(skin, name, path);
|
|
if (!mesh) return null;
|
|
mesh.path = path;
|
|
|
|
var uvs = this.getFloatArray(map, "uvs", 1);
|
|
var vertices = this.getFloatArray(map, "vertices", 1);
|
|
var weights = [];
|
|
var bones = [];
|
|
for (var i = 0, n = vertices.length; i < n; ) {
|
|
var boneCount = vertices[i++] | 0;
|
|
bones[bones.length] = boneCount;
|
|
for (var nn = i + boneCount * 4; i < nn; ) {
|
|
bones[bones.length] = vertices[i];
|
|
weights[weights.length] = vertices[i + 1] * scale;
|
|
weights[weights.length] = vertices[i + 2] * scale;
|
|
weights[weights.length] = vertices[i + 3];
|
|
i += 4;
|
|
}
|
|
}
|
|
mesh.bones = bones;
|
|
mesh.weights = weights;
|
|
mesh.triangles = this.getIntArray(map, "triangles");
|
|
mesh.regionUVs = uvs;
|
|
mesh.updateUVs();
|
|
|
|
color = map["color"];
|
|
if (color) {
|
|
mesh.r = this.toColor(color, 0);
|
|
mesh.g = this.toColor(color, 1);
|
|
mesh.b = this.toColor(color, 2);
|
|
mesh.a = this.toColor(color, 3);
|
|
}
|
|
|
|
mesh.hullLength = (map["hull"] || 0) * 2;
|
|
if (map["edges"]) mesh.edges = this.getIntArray(map, "edges");
|
|
mesh.width = (map["width"] || 0) * scale;
|
|
mesh.height = (map["height"] || 0) * scale;
|
|
return mesh;
|
|
} else if (type == spine.AttachmentType.boundingbox) {
|
|
var attachment = this.attachmentLoader.newBoundingBoxAttachment(skin, name);
|
|
var vertices = map["vertices"];
|
|
for (var i = 0, n = vertices.length; i < n; i++)
|
|
attachment.vertices.push(vertices[i] * scale);
|
|
return attachment;
|
|
}
|
|
throw "Unknown attachment type: " + type;
|
|
},
|
|
readAnimation: function (name, map, skeletonData) {
|
|
var timelines = [];
|
|
var duration = 0;
|
|
|
|
var slots = map["slots"];
|
|
for (var slotName in slots) {
|
|
if (!slots.hasOwnProperty(slotName)) continue;
|
|
var slotMap = slots[slotName];
|
|
var slotIndex = skeletonData.findSlotIndex(slotName);
|
|
|
|
for (var timelineName in slotMap) {
|
|
if (!slotMap.hasOwnProperty(timelineName)) continue;
|
|
var values = slotMap[timelineName];
|
|
if (timelineName == "color") {
|
|
var timeline = new spine.ColorTimeline(values.length);
|
|
timeline.slotIndex = slotIndex;
|
|
|
|
var frameIndex = 0;
|
|
for (var i = 0, n = values.length; i < n; i++) {
|
|
var valueMap = values[i];
|
|
var color = valueMap["color"];
|
|
var r = this.toColor(color, 0);
|
|
var g = this.toColor(color, 1);
|
|
var b = this.toColor(color, 2);
|
|
var a = this.toColor(color, 3);
|
|
timeline.setFrame(frameIndex, valueMap["time"], r, g, b, a);
|
|
this.readCurve(timeline, frameIndex, valueMap);
|
|
frameIndex++;
|
|
}
|
|
timelines.push(timeline);
|
|
duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 5 - 5]);
|
|
|
|
} else if (timelineName == "attachment") {
|
|
var timeline = new spine.AttachmentTimeline(values.length);
|
|
timeline.slotIndex = slotIndex;
|
|
|
|
var frameIndex = 0;
|
|
for (var i = 0, n = values.length; i < n; i++) {
|
|
var valueMap = values[i];
|
|
timeline.setFrame(frameIndex++, valueMap["time"], valueMap["name"]);
|
|
}
|
|
timelines.push(timeline);
|
|
duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]);
|
|
|
|
} else
|
|
throw "Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")";
|
|
}
|
|
}
|
|
|
|
var bones = map["bones"];
|
|
for (var boneName in bones) {
|
|
if (!bones.hasOwnProperty(boneName)) continue;
|
|
var boneIndex = skeletonData.findBoneIndex(boneName);
|
|
if (boneIndex == -1) throw "Bone not found: " + boneName;
|
|
var boneMap = bones[boneName];
|
|
|
|
for (var timelineName in boneMap) {
|
|
if (!boneMap.hasOwnProperty(timelineName)) continue;
|
|
var values = boneMap[timelineName];
|
|
if (timelineName == "rotate") {
|
|
var timeline = new spine.RotateTimeline(values.length);
|
|
timeline.boneIndex = boneIndex;
|
|
|
|
var frameIndex = 0;
|
|
for (var i = 0, n = values.length; i < n; i++) {
|
|
var valueMap = values[i];
|
|
timeline.setFrame(frameIndex, valueMap["time"], valueMap["angle"]);
|
|
this.readCurve(timeline, frameIndex, valueMap);
|
|
frameIndex++;
|
|
}
|
|
timelines.push(timeline);
|
|
duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 2 - 2]);
|
|
|
|
} else if (timelineName == "translate" || timelineName == "scale") {
|
|
var timeline;
|
|
var timelineScale = 1;
|
|
if (timelineName == "scale")
|
|
timeline = new spine.ScaleTimeline(values.length);
|
|
else {
|
|
timeline = new spine.TranslateTimeline(values.length);
|
|
timelineScale = this.scale;
|
|
}
|
|
timeline.boneIndex = boneIndex;
|
|
|
|
var frameIndex = 0;
|
|
for (var i = 0, n = values.length; i < n; i++) {
|
|
var valueMap = values[i];
|
|
var x = (valueMap["x"] || 0) * timelineScale;
|
|
var y = (valueMap["y"] || 0) * timelineScale;
|
|
timeline.setFrame(frameIndex, valueMap["time"], x, y);
|
|
this.readCurve(timeline, frameIndex, valueMap);
|
|
frameIndex++;
|
|
}
|
|
timelines.push(timeline);
|
|
duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 3 - 3]);
|
|
|
|
} else if (timelineName == "flipX" || timelineName == "flipY") {
|
|
var x = timelineName == "flipX";
|
|
var timeline = x ? new spine.FlipXTimeline(values.length) : new spine.FlipYTimeline(values.length);
|
|
timeline.boneIndex = boneIndex;
|
|
|
|
var field = x ? "x" : "y";
|
|
var frameIndex = 0;
|
|
for (var i = 0, n = values.length; i < n; i++) {
|
|
var valueMap = values[i];
|
|
timeline.setFrame(frameIndex, valueMap["time"], valueMap[field] || false);
|
|
frameIndex++;
|
|
}
|
|
timelines.push(timeline);
|
|
duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 2 - 2]);
|
|
} else
|
|
throw "Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")";
|
|
}
|
|
}
|
|
|
|
var ikMap = map["ik"];
|
|
for (var ikConstraintName in ikMap) {
|
|
if (!ikMap.hasOwnProperty(ikConstraintName)) continue;
|
|
var ikConstraint = skeletonData.findIkConstraint(ikConstraintName);
|
|
var values = ikMap[ikConstraintName];
|
|
var timeline = new spine.IkConstraintTimeline(values.length);
|
|
timeline.ikConstraintIndex = skeletonData.ikConstraints.indexOf(ikConstraint);
|
|
var frameIndex = 0;
|
|
for (var i = 0, n = values.length; i < n; i++) {
|
|
var valueMap = values[i];
|
|
var mix = valueMap.hasOwnProperty("mix") ? valueMap["mix"] : 1;
|
|
var bendDirection = (!valueMap.hasOwnProperty("bendPositive") || valueMap["bendPositive"]) ? 1 : -1;
|
|
timeline.setFrame(frameIndex, valueMap["time"], mix, bendDirection);
|
|
this.readCurve(timeline, frameIndex, valueMap);
|
|
frameIndex++;
|
|
}
|
|
timelines.push(timeline);
|
|
duration = Math.max(duration, timeline.frames[timeline.frameCount * 3 - 3]);
|
|
}
|
|
|
|
var ffd = map["ffd"];
|
|
for (var skinName in ffd) {
|
|
var skin = skeletonData.findSkin(skinName);
|
|
var slotMap = ffd[skinName];
|
|
for (slotName in slotMap) {
|
|
var slotIndex = skeletonData.findSlotIndex(slotName);
|
|
var meshMap = slotMap[slotName];
|
|
for (var meshName in meshMap) {
|
|
var values = meshMap[meshName];
|
|
var timeline = new spine.FfdTimeline(values.length);
|
|
var attachment = skin.getAttachment(slotIndex, meshName);
|
|
if (!attachment) throw "FFD attachment not found: " + meshName;
|
|
timeline.slotIndex = slotIndex;
|
|
timeline.attachment = attachment;
|
|
|
|
var isMesh = attachment.type == spine.AttachmentType.mesh;
|
|
var vertexCount;
|
|
if (isMesh)
|
|
vertexCount = attachment.vertices.length;
|
|
else
|
|
vertexCount = attachment.weights.length / 3 * 2;
|
|
|
|
var frameIndex = 0;
|
|
for (var i = 0, n = values.length; i < n; i++) {
|
|
var valueMap = values[i];
|
|
var vertices;
|
|
if (!valueMap["vertices"]) {
|
|
if (isMesh)
|
|
vertices = attachment.vertices;
|
|
else {
|
|
vertices = [];
|
|
vertices.length = vertexCount;
|
|
}
|
|
} else {
|
|
var verticesValue = valueMap["vertices"];
|
|
var vertices = [];
|
|
vertices.length = vertexCount;
|
|
var start = valueMap["offset"] || 0;
|
|
var nn = verticesValue.length;
|
|
if (this.scale == 1) {
|
|
for (var ii = 0; ii < nn; ii++)
|
|
vertices[ii + start] = verticesValue[ii];
|
|
} else {
|
|
for (var ii = 0; ii < nn; ii++)
|
|
vertices[ii + start] = verticesValue[ii] * this.scale;
|
|
}
|
|
if (isMesh) {
|
|
var meshVertices = attachment.vertices;
|
|
for (var ii = 0, nn = vertices.length; ii < nn; ii++)
|
|
vertices[ii] += meshVertices[ii];
|
|
}
|
|
}
|
|
|
|
timeline.setFrame(frameIndex, valueMap["time"], vertices);
|
|
this.readCurve(timeline, frameIndex, valueMap);
|
|
frameIndex++;
|
|
}
|
|
timelines[timelines.length] = timeline;
|
|
duration = Math.max(duration, timeline.frames[timeline.frameCount - 1]);
|
|
}
|
|
}
|
|
}
|
|
|
|
var drawOrderValues = map["drawOrder"];
|
|
if (!drawOrderValues) drawOrderValues = map["draworder"];
|
|
if (drawOrderValues) {
|
|
var timeline = new spine.DrawOrderTimeline(drawOrderValues.length);
|
|
var slotCount = skeletonData.slots.length;
|
|
var frameIndex = 0;
|
|
for (var i = 0, n = drawOrderValues.length; i < n; i++) {
|
|
var drawOrderMap = drawOrderValues[i];
|
|
var drawOrder = null;
|
|
if (drawOrderMap["offsets"]) {
|
|
drawOrder = [];
|
|
drawOrder.length = slotCount;
|
|
for (var ii = slotCount - 1; ii >= 0; ii--)
|
|
drawOrder[ii] = -1;
|
|
var offsets = drawOrderMap["offsets"];
|
|
var unchanged = [];
|
|
unchanged.length = slotCount - offsets.length;
|
|
var originalIndex = 0, unchangedIndex = 0;
|
|
for (var ii = 0, nn = offsets.length; ii < nn; ii++) {
|
|
var offsetMap = offsets[ii];
|
|
var slotIndex = skeletonData.findSlotIndex(offsetMap["slot"]);
|
|
if (slotIndex == -1) throw "Slot not found: " + offsetMap["slot"];
|
|
// Collect unchanged items.
|
|
while (originalIndex != slotIndex)
|
|
unchanged[unchangedIndex++] = originalIndex++;
|
|
// Set changed items.
|
|
drawOrder[originalIndex + offsetMap["offset"]] = originalIndex++;
|
|
}
|
|
// Collect remaining unchanged items.
|
|
while (originalIndex < slotCount)
|
|
unchanged[unchangedIndex++] = originalIndex++;
|
|
// Fill in unchanged items.
|
|
for (var ii = slotCount - 1; ii >= 0; ii--)
|
|
if (drawOrder[ii] == -1) drawOrder[ii] = unchanged[--unchangedIndex];
|
|
}
|
|
timeline.setFrame(frameIndex++, drawOrderMap["time"], drawOrder);
|
|
}
|
|
timelines.push(timeline);
|
|
duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]);
|
|
}
|
|
|
|
var events = map["events"];
|
|
if (events) {
|
|
var timeline = new spine.EventTimeline(events.length);
|
|
var frameIndex = 0;
|
|
for (var i = 0, n = events.length; i < n; i++) {
|
|
var eventMap = events[i];
|
|
var eventData = skeletonData.findEvent(eventMap["name"]);
|
|
if (!eventData) throw "Event not found: " + eventMap["name"];
|
|
var event = new spine.Event(eventData);
|
|
event.intValue = eventMap.hasOwnProperty("int") ? eventMap["int"] : eventData.intValue;
|
|
event.floatValue = eventMap.hasOwnProperty("float") ? eventMap["float"] : eventData.floatValue;
|
|
event.stringValue = eventMap.hasOwnProperty("string") ? eventMap["string"] : eventData.stringValue;
|
|
timeline.setFrame(frameIndex++, eventMap["time"], event);
|
|
}
|
|
timelines.push(timeline);
|
|
duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]);
|
|
}
|
|
|
|
skeletonData.animations.push(new spine.Animation(name, timelines, duration));
|
|
},
|
|
readCurve: function (timeline, frameIndex, valueMap) {
|
|
var curve = valueMap["curve"];
|
|
if (!curve)
|
|
timeline.curves.setLinear(frameIndex);
|
|
else if (curve == "stepped")
|
|
timeline.curves.setStepped(frameIndex);
|
|
else if (curve instanceof Array)
|
|
timeline.curves.setCurve(frameIndex, curve[0], curve[1], curve[2], curve[3]);
|
|
},
|
|
toColor: function (hexString, colorIndex) {
|
|
if (hexString.length != 8) throw "Color hexidecimal length must be 8, recieved: " + hexString;
|
|
return parseInt(hexString.substring(colorIndex * 2, (colorIndex * 2) + 2), 16) / 255;
|
|
},
|
|
getFloatArray: function (map, name, scale) {
|
|
var list = map[name];
|
|
var values = new spine.Float32Array(list.length);
|
|
var i = 0, n = list.length;
|
|
if (scale == 1) {
|
|
for (; i < n; i++)
|
|
values[i] = list[i];
|
|
} else {
|
|
for (; i < n; i++)
|
|
values[i] = list[i] * scale;
|
|
}
|
|
return values;
|
|
},
|
|
getIntArray: function (map, name) {
|
|
var list = map[name];
|
|
var values = new spine.Uint16Array(list.length);
|
|
for (var i = 0, n = list.length; i < n; i++)
|
|
values[i] = list[i] | 0;
|
|
return values;
|
|
}
|
|
};
|
|
|
|
spine.Atlas = function (atlasText, textureLoader) {
|
|
this.textureLoader = textureLoader;
|
|
this.pages = [];
|
|
this.regions = [];
|
|
|
|
var reader = new spine.AtlasReader(atlasText);
|
|
var tuple = [];
|
|
tuple.length = 4;
|
|
var page = null;
|
|
while (true) {
|
|
var line = reader.readLine();
|
|
if (line === null) break;
|
|
line = reader.trim(line);
|
|
if (!line.length)
|
|
page = null;
|
|
else if (!page) {
|
|
page = new spine.AtlasPage();
|
|
page.name = line;
|
|
|
|
if (reader.readTuple(tuple) == 2) { // size is only optional for an atlas packed with an old TexturePacker.
|
|
page.width = parseInt(tuple[0]);
|
|
page.height = parseInt(tuple[1]);
|
|
reader.readTuple(tuple);
|
|
}
|
|
page.format = spine.Atlas.Format[tuple[0]];
|
|
|
|
reader.readTuple(tuple);
|
|
page.minFilter = spine.Atlas.TextureFilter[tuple[0]];
|
|
page.magFilter = spine.Atlas.TextureFilter[tuple[1]];
|
|
|
|
var direction = reader.readValue();
|
|
page.uWrap = spine.Atlas.TextureWrap.clampToEdge;
|
|
page.vWrap = spine.Atlas.TextureWrap.clampToEdge;
|
|
if (direction == "x")
|
|
page.uWrap = spine.Atlas.TextureWrap.repeat;
|
|
else if (direction == "y")
|
|
page.vWrap = spine.Atlas.TextureWrap.repeat;
|
|
else if (direction == "xy")
|
|
page.uWrap = page.vWrap = spine.Atlas.TextureWrap.repeat;
|
|
|
|
textureLoader.load(page, line, this);
|
|
|
|
this.pages.push(page);
|
|
|
|
} else {
|
|
var region = new spine.AtlasRegion();
|
|
region.name = line;
|
|
region.page = page;
|
|
|
|
region.rotate = reader.readValue() == "true";
|
|
|
|
reader.readTuple(tuple);
|
|
var x = parseInt(tuple[0]);
|
|
var y = parseInt(tuple[1]);
|
|
|
|
reader.readTuple(tuple);
|
|
var width = parseInt(tuple[0]);
|
|
var height = parseInt(tuple[1]);
|
|
|
|
region.u = x / page.width;
|
|
region.v = y / page.height;
|
|
if (region.rotate) {
|
|
region.u2 = (x + height) / page.width;
|
|
region.v2 = (y + width) / page.height;
|
|
} else {
|
|
region.u2 = (x + width) / page.width;
|
|
region.v2 = (y + height) / page.height;
|
|
}
|
|
region.x = x;
|
|
region.y = y;
|
|
region.width = Math.abs(width);
|
|
region.height = Math.abs(height);
|
|
|
|
if (reader.readTuple(tuple) == 4) { // split is optional
|
|
region.splits = [parseInt(tuple[0]), parseInt(tuple[1]), parseInt(tuple[2]), parseInt(tuple[3])];
|
|
|
|
if (reader.readTuple(tuple) == 4) { // pad is optional, but only present with splits
|
|
region.pads = [parseInt(tuple[0]), parseInt(tuple[1]), parseInt(tuple[2]), parseInt(tuple[3])];
|
|
|
|
reader.readTuple(tuple);
|
|
}
|
|
}
|
|
|
|
region.originalWidth = parseInt(tuple[0]);
|
|
region.originalHeight = parseInt(tuple[1]);
|
|
|
|
reader.readTuple(tuple);
|
|
region.offsetX = parseInt(tuple[0]);
|
|
region.offsetY = parseInt(tuple[1]);
|
|
|
|
region.index = parseInt(reader.readValue());
|
|
|
|
this.regions.push(region);
|
|
}
|
|
}
|
|
};
|
|
spine.Atlas.prototype = {
|
|
findRegion: function (name) {
|
|
var regions = this.regions;
|
|
for (var i = 0, n = regions.length; i < n; i++)
|
|
if (regions[i].name == name) return regions[i];
|
|
return null;
|
|
},
|
|
dispose: function () {
|
|
var pages = this.pages;
|
|
for (var i = 0, n = pages.length; i < n; i++)
|
|
this.textureLoader.unload(pages[i].rendererObject);
|
|
},
|
|
updateUVs: function (page) {
|
|
var regions = this.regions;
|
|
for (var i = 0, n = regions.length; i < n; i++) {
|
|
var region = regions[i];
|
|
if (region.page != page) continue;
|
|
region.u = region.x / page.width;
|
|
region.v = region.y / page.height;
|
|
if (region.rotate) {
|
|
region.u2 = (region.x + region.height) / page.width;
|
|
region.v2 = (region.y + region.width) / page.height;
|
|
} else {
|
|
region.u2 = (region.x + region.width) / page.width;
|
|
region.v2 = (region.y + region.height) / page.height;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
spine.Atlas.Format = {
|
|
alpha: 0,
|
|
intensity: 1,
|
|
luminanceAlpha: 2,
|
|
rgb565: 3,
|
|
rgba4444: 4,
|
|
rgb888: 5,
|
|
rgba8888: 6
|
|
};
|
|
|
|
spine.Atlas.TextureFilter = {
|
|
nearest: 0,
|
|
linear: 1,
|
|
mipMap: 2,
|
|
mipMapNearestNearest: 3,
|
|
mipMapLinearNearest: 4,
|
|
mipMapNearestLinear: 5,
|
|
mipMapLinearLinear: 6
|
|
};
|
|
|
|
spine.Atlas.TextureWrap = {
|
|
mirroredRepeat: 0,
|
|
clampToEdge: 1,
|
|
repeat: 2
|
|
};
|
|
|
|
spine.AtlasPage = function () {};
|
|
spine.AtlasPage.prototype = {
|
|
name: null,
|
|
format: null,
|
|
minFilter: null,
|
|
magFilter: null,
|
|
uWrap: null,
|
|
vWrap: null,
|
|
rendererObject: null,
|
|
width: 0,
|
|
height: 0
|
|
};
|
|
|
|
spine.AtlasRegion = function () {};
|
|
spine.AtlasRegion.prototype = {
|
|
page: null,
|
|
name: null,
|
|
x: 0, y: 0,
|
|
width: 0, height: 0,
|
|
u: 0, v: 0, u2: 0, v2: 0,
|
|
offsetX: 0, offsetY: 0,
|
|
originalWidth: 0, originalHeight: 0,
|
|
index: 0,
|
|
rotate: false,
|
|
splits: null,
|
|
pads: null
|
|
};
|
|
|
|
spine.AtlasReader = function (text) {
|
|
this.lines = text.split(/\r\n|\r|\n/);
|
|
};
|
|
spine.AtlasReader.prototype = {
|
|
index: 0,
|
|
trim: function (value) {
|
|
return value.replace(/^\s+|\s+$/g, "");
|
|
},
|
|
readLine: function () {
|
|
if (this.index >= this.lines.length) return null;
|
|
return this.lines[this.index++];
|
|
},
|
|
readValue: function () {
|
|
var line = this.readLine();
|
|
var colon = line.indexOf(":");
|
|
if (colon == -1) throw "Invalid line: " + line;
|
|
return this.trim(line.substring(colon + 1));
|
|
},
|
|
/** Returns the number of tuple values read (1, 2 or 4). */
|
|
readTuple: function (tuple) {
|
|
var line = this.readLine();
|
|
var colon = line.indexOf(":");
|
|
if (colon == -1) throw "Invalid line: " + line;
|
|
var i = 0, lastMatch = colon + 1;
|
|
for (; i < 3; i++) {
|
|
var comma = line.indexOf(",", lastMatch);
|
|
if (comma == -1) break;
|
|
tuple[i] = this.trim(line.substr(lastMatch, comma - lastMatch));
|
|
lastMatch = comma + 1;
|
|
}
|
|
tuple[i] = this.trim(line.substring(lastMatch));
|
|
return i + 1;
|
|
}
|
|
};
|
|
|
|
spine.AtlasAttachmentLoader = function (atlas) {
|
|
this.atlas = atlas;
|
|
};
|
|
spine.AtlasAttachmentLoader.prototype = {
|
|
newRegionAttachment: function (skin, name, path) {
|
|
var region = this.atlas.findRegion(path);
|
|
if (!region) throw "Region not found in atlas: " + path + " (region attachment: " + name + ")";
|
|
var attachment = new spine.RegionAttachment(name);
|
|
attachment.rendererObject = region;
|
|
attachment.setUVs(region.u, region.v, region.u2, region.v2, region.rotate);
|
|
attachment.regionOffsetX = region.offsetX;
|
|
attachment.regionOffsetY = region.offsetY;
|
|
attachment.regionWidth = region.width;
|
|
attachment.regionHeight = region.height;
|
|
attachment.regionOriginalWidth = region.originalWidth;
|
|
attachment.regionOriginalHeight = region.originalHeight;
|
|
return attachment;
|
|
},
|
|
newMeshAttachment: function (skin, name, path) {
|
|
var region = this.atlas.findRegion(path);
|
|
if (!region) throw "Region not found in atlas: " + path + " (mesh attachment: " + name + ")";
|
|
var attachment = new spine.MeshAttachment(name);
|
|
attachment.rendererObject = region;
|
|
attachment.regionU = region.u;
|
|
attachment.regionV = region.v;
|
|
attachment.regionU2 = region.u2;
|
|
attachment.regionV2 = region.v2;
|
|
attachment.regionRotate = region.rotate;
|
|
attachment.regionOffsetX = region.offsetX;
|
|
attachment.regionOffsetY = region.offsetY;
|
|
attachment.regionWidth = region.width;
|
|
attachment.regionHeight = region.height;
|
|
attachment.regionOriginalWidth = region.originalWidth;
|
|
attachment.regionOriginalHeight = region.originalHeight;
|
|
return attachment;
|
|
},
|
|
newSkinnedMeshAttachment: function (skin, name, path) {
|
|
var region = this.atlas.findRegion(path);
|
|
if (!region) throw "Region not found in atlas: " + path + " (skinned mesh attachment: " + name + ")";
|
|
var attachment = new spine.SkinnedMeshAttachment(name);
|
|
attachment.rendererObject = region;
|
|
attachment.regionU = region.u;
|
|
attachment.regionV = region.v;
|
|
attachment.regionU2 = region.u2;
|
|
attachment.regionV2 = region.v2;
|
|
attachment.regionRotate = region.rotate;
|
|
attachment.regionOffsetX = region.offsetX;
|
|
attachment.regionOffsetY = region.offsetY;
|
|
attachment.regionWidth = region.width;
|
|
attachment.regionHeight = region.height;
|
|
attachment.regionOriginalWidth = region.originalWidth;
|
|
attachment.regionOriginalHeight = region.originalHeight;
|
|
return attachment;
|
|
},
|
|
newBoundingBoxAttachment: function (skin, name) {
|
|
return new spine.BoundingBoxAttachment(name);
|
|
}
|
|
};
|
|
|
|
spine.SkeletonBounds = function () {
|
|
this.polygonPool = [];
|
|
this.polygons = [];
|
|
this.boundingBoxes = [];
|
|
};
|
|
spine.SkeletonBounds.prototype = {
|
|
minX: 0, minY: 0, maxX: 0, maxY: 0,
|
|
update: function (skeleton, updateAabb) {
|
|
var slots = skeleton.slots;
|
|
var slotCount = slots.length;
|
|
var x = skeleton.x, y = skeleton.y;
|
|
var boundingBoxes = this.boundingBoxes;
|
|
var polygonPool = this.polygonPool;
|
|
var polygons = this.polygons;
|
|
|
|
boundingBoxes.length = 0;
|
|
for (var i = 0, n = polygons.length; i < n; i++)
|
|
polygonPool.push(polygons[i]);
|
|
polygons.length = 0;
|
|
|
|
for (var i = 0; i < slotCount; i++) {
|
|
var slot = slots[i];
|
|
var boundingBox = slot.attachment;
|
|
if (boundingBox.type != spine.AttachmentType.boundingbox) continue;
|
|
boundingBoxes.push(boundingBox);
|
|
|
|
var poolCount = polygonPool.length, polygon;
|
|
if (poolCount > 0) {
|
|
polygon = polygonPool[poolCount - 1];
|
|
polygonPool.splice(poolCount - 1, 1);
|
|
} else
|
|
polygon = [];
|
|
polygons.push(polygon);
|
|
|
|
polygon.length = boundingBox.vertices.length;
|
|
boundingBox.computeWorldVertices(x, y, slot.bone, polygon);
|
|
}
|
|
|
|
if (updateAabb) this.aabbCompute();
|
|
},
|
|
aabbCompute: function () {
|
|
var polygons = this.polygons;
|
|
var minX = Number.MAX_VALUE, minY = Number.MAX_VALUE, maxX = Number.MIN_VALUE, maxY = Number.MIN_VALUE;
|
|
for (var i = 0, n = polygons.length; i < n; i++) {
|
|
var vertices = polygons[i];
|
|
for (var ii = 0, nn = vertices.length; ii < nn; ii += 2) {
|
|
var x = vertices[ii];
|
|
var y = vertices[ii + 1];
|
|
minX = Math.min(minX, x);
|
|
minY = Math.min(minY, y);
|
|
maxX = Math.max(maxX, x);
|
|
maxY = Math.max(maxY, y);
|
|
}
|
|
}
|
|
this.minX = minX;
|
|
this.minY = minY;
|
|
this.maxX = maxX;
|
|
this.maxY = maxY;
|
|
},
|
|
/** Returns true if the axis aligned bounding box contains the point. */
|
|
aabbContainsPoint: function (x, y) {
|
|
return x >= this.minX && x <= this.maxX && y >= this.minY && y <= this.maxY;
|
|
},
|
|
/** Returns true if the axis aligned bounding box intersects the line segment. */
|
|
aabbIntersectsSegment: function (x1, y1, x2, y2) {
|
|
var minX = this.minX, minY = this.minY, maxX = this.maxX, maxY = this.maxY;
|
|
if ((x1 <= minX && x2 <= minX) || (y1 <= minY && y2 <= minY) || (x1 >= maxX && x2 >= maxX) || (y1 >= maxY && y2 >= maxY))
|
|
return false;
|
|
var m = (y2 - y1) / (x2 - x1);
|
|
var y = m * (minX - x1) + y1;
|
|
if (y > minY && y < maxY) return true;
|
|
y = m * (maxX - x1) + y1;
|
|
if (y > minY && y < maxY) return true;
|
|
var x = (minY - y1) / m + x1;
|
|
if (x > minX && x < maxX) return true;
|
|
x = (maxY - y1) / m + x1;
|
|
if (x > minX && x < maxX) return true;
|
|
return false;
|
|
},
|
|
/** Returns true if the axis aligned bounding box intersects the axis aligned bounding box of the specified bounds. */
|
|
aabbIntersectsSkeleton: function (bounds) {
|
|
return this.minX < bounds.maxX && this.maxX > bounds.minX && this.minY < bounds.maxY && this.maxY > bounds.minY;
|
|
},
|
|
/** Returns the first bounding box attachment that contains the point, or null. When doing many checks, it is usually more
|
|
* efficient to only call this method if {@link #aabbContainsPoint(float, float)} returns true. */
|
|
containsPoint: function (x, y) {
|
|
var polygons = this.polygons;
|
|
for (var i = 0, n = polygons.length; i < n; i++)
|
|
if (this.polygonContainsPoint(polygons[i], x, y)) return this.boundingBoxes[i];
|
|
return null;
|
|
},
|
|
/** Returns the first bounding box attachment that contains the line segment, or null. When doing many checks, it is usually
|
|
* more efficient to only call this method if {@link #aabbIntersectsSegment(float, float, float, float)} returns true. */
|
|
intersectsSegment: function (x1, y1, x2, y2) {
|
|
var polygons = this.polygons;
|
|
for (var i = 0, n = polygons.length; i < n; i++)
|
|
if (polygons[i].intersectsSegment(x1, y1, x2, y2)) return this.boundingBoxes[i];
|
|
return null;
|
|
},
|
|
/** Returns true if the polygon contains the point. */
|
|
polygonContainsPoint: function (polygon, x, y) {
|
|
var nn = polygon.length;
|
|
var prevIndex = nn - 2;
|
|
var inside = false;
|
|
for (var ii = 0; ii < nn; ii += 2) {
|
|
var vertexY = polygon[ii + 1];
|
|
var prevY = polygon[prevIndex + 1];
|
|
if ((vertexY < y && prevY >= y) || (prevY < y && vertexY >= y)) {
|
|
var vertexX = polygon[ii];
|
|
if (vertexX + (y - vertexY) / (prevY - vertexY) * (polygon[prevIndex] - vertexX) < x) inside = !inside;
|
|
}
|
|
prevIndex = ii;
|
|
}
|
|
return inside;
|
|
},
|
|
/** Returns true if the polygon contains the line segment. */
|
|
polygonIntersectsSegment: function (polygon, x1, y1, x2, y2) {
|
|
var nn = polygon.length;
|
|
var width12 = x1 - x2, height12 = y1 - y2;
|
|
var det1 = x1 * y2 - y1 * x2;
|
|
var x3 = polygon[nn - 2], y3 = polygon[nn - 1];
|
|
for (var ii = 0; ii < nn; ii += 2) {
|
|
var x4 = polygon[ii], y4 = polygon[ii + 1];
|
|
var det2 = x3 * y4 - y3 * x4;
|
|
var width34 = x3 - x4, height34 = y3 - y4;
|
|
var det3 = width12 * height34 - height12 * width34;
|
|
var x = (det1 * width34 - width12 * det2) / det3;
|
|
if (((x >= x3 && x <= x4) || (x >= x4 && x <= x3)) && ((x >= x1 && x <= x2) || (x >= x2 && x <= x1))) {
|
|
var y = (det1 * height34 - height12 * det2) / det3;
|
|
if (((y >= y3 && y <= y4) || (y >= y4 && y <= y3)) && ((y >= y1 && y <= y2) || (y >= y2 && y <= y1))) return true;
|
|
}
|
|
x3 = x4;
|
|
y3 = y4;
|
|
}
|
|
return false;
|
|
},
|
|
getPolygon: function (attachment) {
|
|
var index = this.boundingBoxes.indexOf(attachment);
|
|
return index == -1 ? null : this.polygons[index];
|
|
},
|
|
getWidth: function () {
|
|
return this.maxX - this.minX;
|
|
},
|
|
getHeight: function () {
|
|
return this.maxY - this.minY;
|
|
}
|
|
};
|
|
</pre>
|
|
</article>
|
|
</section>
|
|
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
<div class="clearfix"></div>
|
|
<footer>
|
|
|
|
|
|
<span class="copyright">
|
|
Phaser Copyright © 2012-2014 Photon Storm Ltd.
|
|
</span>
|
|
<br />
|
|
|
|
<span class="jsdoc-message">
|
|
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.3.0-dev</a>
|
|
on Tue Jan 06 2015 06:31:48 GMT-0000 (GMT) using the <a href="https://github.com/terryweiss/docstrap">DocStrap template</a>.
|
|
</span>
|
|
</footer>
|
|
</div>
|
|
|
|
|
|
<br clear="both">
|
|
</div>
|
|
|
|
</div>
|
|
<script src="scripts/sunlight.js"></script>
|
|
<script src="scripts/sunlight.javascript.js"></script>
|
|
<script src="scripts/sunlight-plugin.doclinks.js"></script>
|
|
<script src="scripts/sunlight-plugin.linenumbers.js"></script>
|
|
<script src="scripts/sunlight-plugin.menu.js"></script>
|
|
<script src="scripts/jquery.min.js"></script>
|
|
<script src="scripts/jquery.scrollTo.js"></script>
|
|
<script src="scripts/jquery.localScroll.js"></script>
|
|
<script src="scripts/bootstrap-dropdown.js"></script>
|
|
<script src="scripts/toc.js"></script>
|
|
|
|
<script> Sunlight.highlightAll({lineNumbers:true, showMenu: true, enableDoclinks :true}); </script>
|
|
|
|
<script>
|
|
$( function () {
|
|
$( "#toc" ).toc( {
|
|
anchorName : function(i, heading, prefix) {
|
|
return $(heading).attr("id") || ( prefix + i );
|
|
},
|
|
selectors : "h1,h2,h3,h4",
|
|
showAndHide : false,
|
|
scrollTo : 60
|
|
} );
|
|
$( "#toc>ul" ).addClass( "nav nav-pills nav-stacked" );
|
|
$( "#main span[id^='toc']" ).addClass( "toc-shim" );
|
|
|
|
} );
|
|
</script>
|
|
|
|
|
|
|
|
</body>
|
|
</html>
|