├── .gitattributes ├── .gitignore ├── BinToJson ├── App.config ├── BinToJson.csproj ├── Program.cs ├── Properties │ └── AssemblyInfo.cs ├── SkelDataConverter.cs └── packages.config ├── LICENSE ├── Program.cs ├── README.md ├── spine-csharp.sln └── spine-csharp ├── LICENSE ├── Properties └── AssemblyInfo.cs ├── README.md ├── SpineBinaryConverter.sln ├── nuget └── Spine.1.6.18.nuspec ├── spine-csharp.csproj └── src ├── Animation.cs ├── AnimationState.cs ├── AnimationStateData.cs ├── Atlas.cs ├── Attachments ├── AtlasAttachmentLoader.cs ├── Attachment.cs ├── AttachmentLoader.cs ├── AttachmentType.cs ├── BoundingBoxAttachment.cs ├── MeshAttachment.cs ├── PathAttachment.cs ├── RegionAttachment.cs └── VertexAttachment.cs ├── BlendMode.cs ├── Bone.cs ├── BoneData.cs ├── Event.cs ├── EventData.cs ├── ExposedList.cs ├── IUpdatable.cs ├── IkConstraint.cs ├── IkConstraintData.cs ├── Json.cs ├── MathUtils.cs ├── PathConstraint.cs ├── PathConstraintData.cs ├── Skeleton.cs ├── SkeletonBinary.cs ├── SkeletonBounds.cs ├── SkeletonData.cs ├── SkeletonJson.cs ├── Skin.cs ├── Slot.cs ├── SlotData.cs ├── TransformConstraint.cs └── TransformConstraintData.cs /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 150 | # checkin your Azure Web App publish settings, but sensitive information contained 151 | # in these scripts will be unencrypted 152 | PublishScripts/ 153 | 154 | # NuGet Packages 155 | *.nupkg 156 | # The packages folder can be ignored because of Package Restore 157 | **/packages/* 158 | # except build/, which is used as an MSBuild target. 159 | !**/packages/build/ 160 | # Uncomment if necessary however generally it will be regenerated when needed 161 | #!**/packages/repositories.config 162 | # NuGet v3's project.json files produces more ignoreable files 163 | *.nuget.props 164 | *.nuget.targets 165 | 166 | # Microsoft Azure Build Output 167 | csx/ 168 | *.build.csdef 169 | 170 | # Microsoft Azure Emulator 171 | ecf/ 172 | rcf/ 173 | 174 | # Windows Store app package directories and files 175 | AppPackages/ 176 | BundleArtifacts/ 177 | Package.StoreAssociation.xml 178 | _pkginfo.txt 179 | 180 | # Visual Studio cache files 181 | # files ending in .cache can be ignored 182 | *.[Cc]ache 183 | # but keep track of directories ending in .cache 184 | !*.[Cc]ache/ 185 | 186 | # Others 187 | ClientBin/ 188 | ~$* 189 | *~ 190 | *.dbmdl 191 | *.dbproj.schemaview 192 | *.jfm 193 | *.pfx 194 | *.publishsettings 195 | node_modules/ 196 | orleans.codegen.cs 197 | 198 | # Since there are multiple workflows, uncomment next line to ignore bower_components 199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 200 | #bower_components/ 201 | 202 | # RIA/Silverlight projects 203 | Generated_Code/ 204 | 205 | # Backup & report files from converting an old project file 206 | # to a newer Visual Studio version. Backup files are not needed, 207 | # because we have git ;-) 208 | _UpgradeReport_Files/ 209 | Backup*/ 210 | UpgradeLog*.XML 211 | UpgradeLog*.htm 212 | 213 | # SQL Server files 214 | *.mdf 215 | *.ldf 216 | 217 | # Business Intelligence projects 218 | *.rdl.data 219 | *.bim.layout 220 | *.bim_*.settings 221 | 222 | # Microsoft Fakes 223 | FakesAssemblies/ 224 | 225 | # GhostDoc plugin setting file 226 | *.GhostDoc.xml 227 | 228 | # Node.js Tools for Visual Studio 229 | .ntvs_analysis.dat 230 | 231 | # Visual Studio 6 build log 232 | *.plg 233 | 234 | # Visual Studio 6 workspace options file 235 | *.opt 236 | 237 | # Visual Studio LightSwitch build output 238 | **/*.HTMLClient/GeneratedArtifacts 239 | **/*.DesktopClient/GeneratedArtifacts 240 | **/*.DesktopClient/ModelManifest.xml 241 | **/*.Server/GeneratedArtifacts 242 | **/*.Server/ModelManifest.xml 243 | _Pvt_Extensions 244 | 245 | # Paket dependency manager 246 | .paket/paket.exe 247 | paket-files/ 248 | 249 | # FAKE - F# Make 250 | .fake/ 251 | 252 | # JetBrains Rider 253 | .idea/ 254 | *.sln.iml 255 | 256 | # CodeRush 257 | .cr/ 258 | 259 | # Python Tools for Visual Studio (PTVS) 260 | __pycache__/ 261 | *.pyc -------------------------------------------------------------------------------- /BinToJson/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /BinToJson/BinToJson.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {81612927-658C-4DAD-BF1C-06C5B274EFB5} 8 | Exe 9 | BinToJson 10 | BinToJson 11 | v4.7.1 12 | 512 13 | true 14 | true 15 | 16 | 17 | 18 | AnyCPU 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | {94144e22-2431-4a8f-ac04-dec22f7edd8f} 63 | spine-csharp 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /BinToJson/Program.cs: -------------------------------------------------------------------------------- 1 | using Spine; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.IO; 8 | using System.Web.Script.Serialization; 9 | 10 | namespace BinToJson 11 | { 12 | 13 | class Program 14 | { 15 | //Requires a skeleton file as input 16 | static void Main(string[] args) { 17 | if (args.Length < 1) { 18 | Console.WriteLine("Usage: Drag a binary Spine skeleton file onto this executable and this outputs a json-ified version in the same directory"); 19 | Console.ReadLine(); 20 | return; 21 | } 22 | SkeletonData skeletonData; 23 | string fileName = args[0]; 24 | 25 | //determines if the input file is json or bytes 26 | Atlas atlas = new Atlas(); 27 | if (fileName.Contains("json")) { 28 | //Converting json -> json is unnecessary, but makes bug-checking significantly easier 29 | var sb = new SkeletonJson(atlas); 30 | skeletonData = sb.ReadSkeletonData(fileName); 31 | } else { 32 | var sb = new SkeletonBinary(atlas); 33 | skeletonData = sb.ReadSkeletonData(fileName); 34 | } 35 | //Takes the skeletonData and converts it into a serializable object 36 | Dictionary jsonFile = SkelDataConverter.FromSkeletonData(skeletonData); 37 | 38 | //convert object to json string for storing 39 | JavaScriptSerializer jsonSerializer = new JavaScriptSerializer(); 40 | string json = jsonSerializer.Serialize(jsonFile); 41 | 42 | 43 | //Output file to same directory as input with "name 1", does not allow overwrites 44 | string preExtension = fileName.Substring(0, fileName.LastIndexOf('.')); 45 | int addNum = 1; 46 | string fullerName = preExtension; 47 | while(File.Exists(fullerName + ".json")) { 48 | fullerName = preExtension +" " + addNum; 49 | addNum++; 50 | } 51 | File.WriteAllText(fullerName+".json", json); 52 | 53 | 54 | } 55 | 56 | 57 | 58 | } 59 | 60 | 61 | } 62 | -------------------------------------------------------------------------------- /BinToJson/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("BinToJson")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("BinToJson")] 13 | [assembly: AssemblyCopyright("Copyright © 2019")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("81612927-658c-4dad-bf1c-06c5b274efb5")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /BinToJson/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /Program.cs: -------------------------------------------------------------------------------- 1 | using Spine; 2 | using System; 3 | 4 | namespace BinaryToJson 5 | { 6 | class Program 7 | { 8 | static void Main(string[] args) { 9 | if (args.Length < 1) { 10 | Console.WriteLine("Usage: Drag a binary Spine skeleton file onto this executable and this outputs a json-ified version"); 11 | Console.ReadLine(); 12 | return; 13 | } 14 | string fileName = args[0]; 15 | Atlas atlas = new Atlas(); 16 | 17 | var sb = new SkeletonBinary(atlas); 18 | sb.ReadSkeletonData(fileName); 19 | 20 | 21 | Console.ReadLine(); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SpineBinaryConverter 2 | Old Spine binary formats are unreadable with the current Spine animation program, and no backwards compatible version exists to edit Spine binary files before version 3.5. To fix this problem, this program takes old Spine skeleton binary files and converts them to the JSON equivelent so they can be parsed. 3 | 4 | ## Notices 5 | Currently, this repository uses spine-sharp version 3.4 from the [Spine runtimes](https://github.com/EsotericSoftware/spine-runtimes ) and therefore only parses version 3.4 binary files. It is possible to switch out the spine-sharp folder in this repository for a different version on the Spine-sharp github, but doing so will cause the program to fail to compile. More info in the Unfinished Work section under Version Swaping. 6 | 7 | 8 | 9 | ## Unfinished Work: ~85% Complete 10 | 1. Color Support: color timelines are unparsed, so files that change color over time will be unable to do so. 11 | 2. Event Support: files with interactable elements will not parse successfully and throw an error when trying to parse Events. 12 | 3. Version Swaping: Small changes were made to the original spine-sharp project to make parsing binary files easier. Currently the Deformation animations section has been changed to read pre-deformed vertices and offset. 13 | 14 | ## Usage 15 | Simply drag the skeleton file onto the exectuable to run the conversion process. The new file will be output to the same directory as the original file. 16 | 17 | ## Executables 18 | Latest Windows executable in releases or [here](https://github.com/PeterMoras/SpineBinaryConverter/releases/download/v0.85/SpineBinaryConverter.zip) 19 | -------------------------------------------------------------------------------- /spine-csharp.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28307.168 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "spine-csharp", "spine-csharp.csproj", "{94144E22-2431-4A8F-AC04-DEC22F7EDD8F}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BinToJson", "..\BinToJson\BinToJson.csproj", "{81612927-658C-4DAD-BF1C-06C5B274EFB5}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {94144E22-2431-4A8F-AC04-DEC22F7EDD8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {94144E22-2431-4A8F-AC04-DEC22F7EDD8F}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {94144E22-2431-4A8F-AC04-DEC22F7EDD8F}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {94144E22-2431-4A8F-AC04-DEC22F7EDD8F}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {81612927-658C-4DAD-BF1C-06C5B274EFB5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {81612927-658C-4DAD-BF1C-06C5B274EFB5}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {81612927-658C-4DAD-BF1C-06C5B274EFB5}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {81612927-658C-4DAD-BF1C-06C5B274EFB5}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {8CFA80F9-4049-4F55-AC91-073BAD2AD8D6} 30 | EndGlobalSection 31 | GlobalSection(MonoDevelopProperties) = preSolution 32 | StartupItem = spine-csharp.csproj 33 | EndGlobalSection 34 | EndGlobal 35 | -------------------------------------------------------------------------------- /spine-csharp/LICENSE: -------------------------------------------------------------------------------- 1 | Spine Runtimes Software License v2.5 2 | 3 | Copyright (c) 2013-2016, Esoteric Software 4 | All rights reserved. 5 | 6 | You are granted a perpetual, non-exclusive, non-sublicensable, and 7 | non-transferable license to use, install, execute, and perform the Spine 8 | Runtimes software and derivative works solely for personal or internal 9 | use. Without the written permission of Esoteric Software (see Section 2 of 10 | the Spine Software License Agreement), you may not (a) modify, translate, 11 | adapt, or develop new applications using the Spine Runtimes or otherwise 12 | create derivative works or improvements of the Spine Runtimes or (b) remove, 13 | delete, alter, or obscure any trademarks or any copyright, trademark, patent, 14 | or other intellectual property or proprietary rights notices on or in the 15 | Software, including any copy thereof. Redistributions in binary or source 16 | form must include this license and terms. 17 | 18 | THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 19 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 20 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 21 | EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 23 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF 24 | USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25 | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /spine-csharp/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("spine-csharp")] 9 | [assembly: AssemblyProduct("spine-csharp")] 10 | [assembly: AssemblyDescription("")] 11 | [assembly: AssemblyCompany("Esoteric Software")] 12 | [assembly: AssemblyCopyright("Copyright © Esoteric Software 2013-2016")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. Only Windows 19 | // assemblies support COM. 20 | [assembly: ComVisible(false)] 21 | 22 | // On Windows, the following GUID is for the ID of the typelib if this 23 | // project is exposed to COM. On other platforms, it unique identifies the 24 | // title storage container when deploying this assembly to the device. 25 | [assembly: Guid("3ac8567e-9ae8-4624-87b9-a84f0101c629")] 26 | 27 | // Version information for an assembly consists of the following four values: 28 | // 29 | // Major Version 30 | // Minor Version 31 | // Build Number 32 | // Revision 33 | // 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | -------------------------------------------------------------------------------- /spine-csharp/README.md: -------------------------------------------------------------------------------- 1 | # spine-csharp 2 | 3 | The spine-csharp runtime provides functionality to load and manipulate [Spine](http://esotericsoftware.com) skeletal animation data using C# (C Sharp). It does not perform rendering but can be extended to enable Spine animations for other C#-based projects. 4 | 5 | ## Licensing 6 | 7 | This Spine Runtime may only be used for personal or internal use, typically to evaluate Spine before purchasing. If you would like to incorporate a Spine Runtime into your applications, distribute software containing a Spine Runtime, or modify a Spine Runtime, then you will need a valid [Spine license](https://esotericsoftware.com/spine-purchase). Please see the [Spine Runtimes Software License](https://github.com/EsotericSoftware/spine-runtimes/blob/master/LICENSE) for detailed information. 8 | 9 | The Spine Runtimes are developed with the intent to be used with data exported from Spine. By purchasing Spine, `Section 2` of the [Spine Software License](https://esotericsoftware.com/files/license.txt) grants the right to create and distribute derivative works of the Spine Runtimes. 10 | 11 | ## Spine version 12 | 13 | spine-csharp works with data exported from the latest, non-beta version of Spine. 14 | 15 | spine-csharp supports all Spine features. 16 | 17 | ## Setup 18 | 19 | 1. Download the Spine Runtimes source using [git](https://help.github.com/articles/set-up-git) or by downloading it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/master.zip). 20 | 1. Open the `spine-csharp.sln` Visual Studio 2015 Community project file. 21 | 22 | Alternatively, the contents of the `spine-csharp/src` directory can be copied into your project. 23 | 24 | ## Runtimes Extending spine-csharp 25 | 26 | - [spine-monogame](https://github.com/EsotericSoftware/spine-runtimes/blob/master/spine-monogame) 27 | - [spine-tk2d](https://github.com/EsotericSoftware/spine-runtimes/blob/master/spine-tk2d) 28 | - [spine-unity](https://github.com/EsotericSoftware/spine-runtimes/blob/master/spine-unity) 29 | - [spine-xna](https://github.com/EsotericSoftware/spine-runtimes/blob/master/spine-xna) 30 | -------------------------------------------------------------------------------- /spine-csharp/SpineBinaryConverter.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28307.168 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "spine-csharp", "spine-csharp.csproj", "{94144E22-2431-4A8F-AC04-DEC22F7EDD8F}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BinToJson", "..\BinToJson\BinToJson.csproj", "{81612927-658C-4DAD-BF1C-06C5B274EFB5}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {94144E22-2431-4A8F-AC04-DEC22F7EDD8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {94144E22-2431-4A8F-AC04-DEC22F7EDD8F}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {94144E22-2431-4A8F-AC04-DEC22F7EDD8F}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {94144E22-2431-4A8F-AC04-DEC22F7EDD8F}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {81612927-658C-4DAD-BF1C-06C5B274EFB5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {81612927-658C-4DAD-BF1C-06C5B274EFB5}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {81612927-658C-4DAD-BF1C-06C5B274EFB5}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {81612927-658C-4DAD-BF1C-06C5B274EFB5}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {8CFA80F9-4049-4F55-AC91-073BAD2AD8D6} 30 | EndGlobalSection 31 | GlobalSection(MonoDevelopProperties) = preSolution 32 | StartupItem = spine-csharp.csproj 33 | EndGlobalSection 34 | EndGlobal 35 | -------------------------------------------------------------------------------- /spine-csharp/nuget/Spine.1.6.18.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Spine 5 | 1.6.18.0 6 | Esoteric Software 7 | Esoteric Software 8 | https://github.com/EsotericSoftware/spine-runtimes/blob/master/LICENSE 9 | http://esotericsoftware.com/ 10 | http://esotericsoftware.com/spine/files/logo-420.png 11 | true 12 | Spine is a 2D skeletal animation tool for game development and other animation projects. 13 | Spine features an intuitive workflow to rig and animate skeletons, a multiple-timeline dopesheet for retiming and tweaking animations, powerful exporting capabilities, and runtimes for many programming languages and game toolkits. 14 | Release build for .NET 4.0 of version 1.6.18 (changeset c732a687, 2013-10-24) 15 | Copyright 2013 16 | 2D skeletal animation runtime Spine 17 | 18 | -------------------------------------------------------------------------------- /spine-csharp/spine-csharp.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | {94144E22-2431-4A8F-AC04-DEC22F7EDD8F} 5 | 9.0.21022 6 | 2.0 7 | Debug 8 | x86 9 | Library 10 | Properties 11 | Spine 12 | spine-csharp 13 | v4.7.1 14 | 15 | 16 | v4.0 17 | Windows 18 | HiDef 19 | 99dfd52d-8beb-4e5c-a68b-365be39e8064 20 | Library 21 | 22 | 23 | 3.5 24 | 25 | 26 | 27 | true 28 | bin\Debug\ 29 | DEBUG;TRACE;WINDOWS 30 | true 31 | full 32 | AnyCPU 33 | false 34 | prompt 35 | false 36 | 37 | 38 | bin\Release\ 39 | TRACE;WINDOWS 40 | true 41 | true 42 | pdbonly 43 | AnyCPU 44 | false 45 | prompt 46 | false 47 | 48 | 49 | 50 | 51 | 52 | 4.0 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | Code 61 | 62 | 63 | Code 64 | 65 | 66 | Code 67 | 68 | 69 | Code 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | Code 82 | 83 | 84 | Code 85 | 86 | 87 | Code 88 | 89 | 90 | Code 91 | 92 | 93 | Code 94 | 95 | 96 | Code 97 | 98 | 99 | Code 100 | 101 | 102 | Code 103 | 104 | 105 | Code 106 | 107 | 108 | 109 | Code 110 | 111 | 112 | 113 | 114 | Code 115 | 116 | 117 | Code 118 | 119 | 120 | Code 121 | 122 | 123 | Code 124 | 125 | 126 | Code 127 | 128 | 129 | Code 130 | 131 | 132 | Code 133 | 134 | 135 | Code 136 | 137 | 138 | Code 139 | 140 | 141 | Code 142 | 143 | 144 | 145 | 146 | 154 | -------------------------------------------------------------------------------- /spine-csharp/src/AnimationState.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License v2.5 3 | * 4 | * Copyright (c) 2013-2016, Esoteric Software 5 | * All rights reserved. 6 | * 7 | * You are granted a perpetual, non-exclusive, non-sublicensable, and 8 | * non-transferable license to use, install, execute, and perform the Spine 9 | * Runtimes software and derivative works solely for personal or internal 10 | * use. Without the written permission of Esoteric Software (see Section 2 of 11 | * the Spine Software License Agreement), you may not (a) modify, translate, 12 | * adapt, or develop new applications using the Spine Runtimes or otherwise 13 | * create derivative works or improvements of the Spine Runtimes or (b) remove, 14 | * delete, alter, or obscure any trademarks or any copyright, trademark, patent, 15 | * or other intellectual property or proprietary rights notices on or in the 16 | * Software, including any copy thereof. Redistributions in binary or source 17 | * form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF 25 | * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 26 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | using System.Collections.Generic; 33 | using System.Text; 34 | 35 | namespace Spine { 36 | public class AnimationState { 37 | private AnimationStateData data; 38 | private ExposedList tracks = new ExposedList(); 39 | private ExposedList events = new ExposedList(); 40 | private float timeScale = 1; 41 | 42 | public AnimationStateData Data { get { return data; } } 43 | /// A list of tracks that have animations, which may contain nulls. 44 | public ExposedList Tracks { get { return tracks; } } 45 | public float TimeScale { get { return timeScale; } set { timeScale = value; } } 46 | 47 | public delegate void StartEndDelegate (AnimationState state, int trackIndex); 48 | public event StartEndDelegate Start; 49 | public event StartEndDelegate End; 50 | 51 | public delegate void EventDelegate (AnimationState state, int trackIndex, Event e); 52 | public event EventDelegate Event; 53 | 54 | public delegate void CompleteDelegate (AnimationState state, int trackIndex, int loopCount); 55 | public event CompleteDelegate Complete; 56 | 57 | public AnimationState (AnimationStateData data) { 58 | if (data == null) throw new ArgumentNullException("data", "data cannot be null."); 59 | this.data = data; 60 | } 61 | 62 | public void Update (float delta) { 63 | delta *= timeScale; 64 | for (int i = 0; i < tracks.Count; i++) { 65 | TrackEntry current = tracks.Items[i]; 66 | if (current == null) continue; 67 | 68 | float trackDelta = delta * current.timeScale; 69 | float time = current.time + trackDelta; 70 | float endTime = current.endTime; 71 | 72 | current.time = time; 73 | if (current.previous != null) { 74 | current.previous.time += trackDelta; 75 | current.mixTime += trackDelta; 76 | } 77 | 78 | // Check if completed the animation or a loop iteration. 79 | if (current.loop ? (current.lastTime % endTime > time % endTime) : (current.lastTime < endTime && time >= endTime)) { 80 | int count = (int)(time / endTime); 81 | current.OnComplete(this, i, count); 82 | if (Complete != null) Complete(this, i, count); 83 | } 84 | 85 | TrackEntry next = current.next; 86 | if (next != null) { 87 | next.time = current.lastTime - next.delay; 88 | if (next.time >= 0) SetCurrent(i, next); 89 | } else { 90 | // End non-looping animation when it reaches its end time and there is no next entry. 91 | if (!current.loop && current.lastTime >= current.endTime) ClearTrack(i); 92 | } 93 | } 94 | } 95 | 96 | public void Apply (Skeleton skeleton) { 97 | ExposedList events = this.events; 98 | 99 | for (int i = 0; i < tracks.Count; i++) { 100 | TrackEntry current = tracks.Items[i]; 101 | if (current == null) continue; 102 | 103 | events.Clear(); 104 | 105 | float time = current.time; 106 | bool loop = current.loop; 107 | if (!loop && time > current.endTime) time = current.endTime; 108 | 109 | TrackEntry previous = current.previous; 110 | if (previous == null) { 111 | if (current.mix == 1) 112 | current.animation.Apply(skeleton, current.lastTime, time, loop, events); 113 | else 114 | current.animation.Mix(skeleton, current.lastTime, time, loop, events, current.mix); 115 | } else { 116 | float previousTime = previous.time; 117 | if (!previous.loop && previousTime > previous.endTime) previousTime = previous.endTime; 118 | previous.animation.Apply(skeleton, previous.lastTime, previousTime, previous.loop, null); 119 | // Remove the line above, and uncomment the line below, to allow previous animations to fire events during mixing. 120 | //previous.animation.Apply(skeleton, previous.lastTime, previousTime, previous.loop, events); 121 | previous.lastTime = previousTime; 122 | 123 | float alpha = current.mixTime / current.mixDuration * current.mix; 124 | if (alpha >= 1) { 125 | alpha = 1; 126 | current.previous = null; 127 | } 128 | current.animation.Mix(skeleton, current.lastTime, time, loop, events, alpha); 129 | } 130 | 131 | for (int ii = 0, nn = events.Count; ii < nn; ii++) { 132 | Event e = events.Items[ii]; 133 | current.OnEvent(this, i, e); 134 | if (Event != null) Event(this, i, e); 135 | } 136 | 137 | current.lastTime = current.time; 138 | } 139 | } 140 | 141 | public void ClearTracks () { 142 | for (int i = 0, n = tracks.Count; i < n; i++) 143 | ClearTrack(i); 144 | tracks.Clear(); 145 | } 146 | 147 | public void ClearTrack (int trackIndex) { 148 | if (trackIndex >= tracks.Count) return; 149 | TrackEntry current = tracks.Items[trackIndex]; 150 | if (current == null) return; 151 | 152 | current.OnEnd(this, trackIndex); 153 | if (End != null) End(this, trackIndex); 154 | 155 | tracks.Items[trackIndex] = null; 156 | } 157 | 158 | private TrackEntry ExpandToIndex (int index) { 159 | if (index < tracks.Count) return tracks.Items[index]; 160 | while (index >= tracks.Count) 161 | tracks.Add(null); 162 | return null; 163 | } 164 | 165 | private void SetCurrent (int index, TrackEntry entry) { 166 | TrackEntry current = ExpandToIndex(index); 167 | if (current != null) { 168 | TrackEntry previous = current.previous; 169 | current.previous = null; 170 | 171 | current.OnEnd(this, index); 172 | if (End != null) End(this, index); 173 | 174 | entry.mixDuration = data.GetMix(current.animation, entry.animation); 175 | if (entry.mixDuration > 0) { 176 | entry.mixTime = 0; 177 | // If a mix is in progress, mix from the closest animation. 178 | if (previous != null && current.mixTime / current.mixDuration < 0.5f) 179 | entry.previous = previous; 180 | else 181 | entry.previous = current; 182 | } 183 | } 184 | 185 | tracks.Items[index] = entry; 186 | 187 | entry.OnStart(this, index); 188 | if (Start != null) Start(this, index); 189 | } 190 | 191 | /// 192 | public TrackEntry SetAnimation (int trackIndex, String animationName, bool loop) { 193 | Animation animation = data.skeletonData.FindAnimation(animationName); 194 | if (animation == null) throw new ArgumentException("Animation not found: " + animationName, "animationName"); 195 | return SetAnimation(trackIndex, animation, loop); 196 | } 197 | 198 | /// Set the current animation. Any queued animations are cleared. 199 | public TrackEntry SetAnimation (int trackIndex, Animation animation, bool loop) { 200 | if (animation == null) throw new ArgumentNullException("animation", "animation cannot be null."); 201 | TrackEntry entry = new TrackEntry(); 202 | entry.animation = animation; 203 | entry.loop = loop; 204 | entry.time = 0; 205 | entry.endTime = animation.Duration; 206 | SetCurrent(trackIndex, entry); 207 | return entry; 208 | } 209 | 210 | /// 211 | public TrackEntry AddAnimation (int trackIndex, String animationName, bool loop, float delay) { 212 | Animation animation = data.skeletonData.FindAnimation(animationName); 213 | if (animation == null) throw new ArgumentException("Animation not found: " + animationName, "animationName"); 214 | return AddAnimation(trackIndex, animation, loop, delay); 215 | } 216 | 217 | /// Adds an animation to be played delay seconds after the current or last queued animation. 218 | /// May be <= 0 to use duration of previous animation minus any mix duration plus the negative delay. 219 | public TrackEntry AddAnimation (int trackIndex, Animation animation, bool loop, float delay) { 220 | if (animation == null) throw new ArgumentNullException("animation", "animation cannot be null."); 221 | TrackEntry entry = new TrackEntry(); 222 | entry.animation = animation; 223 | entry.loop = loop; 224 | entry.time = 0; 225 | entry.endTime = animation.Duration; 226 | 227 | TrackEntry last = ExpandToIndex(trackIndex); 228 | if (last != null) { 229 | while (last.next != null) 230 | last = last.next; 231 | last.next = entry; 232 | } else 233 | tracks.Items[trackIndex] = entry; 234 | 235 | if (delay <= 0) { 236 | if (last != null) 237 | delay += last.endTime - data.GetMix(last.animation, animation); 238 | else 239 | delay = 0; 240 | } 241 | entry.delay = delay; 242 | 243 | return entry; 244 | } 245 | 246 | /// May be null. 247 | public TrackEntry GetCurrent (int trackIndex) { 248 | if (trackIndex >= tracks.Count) return null; 249 | return tracks.Items[trackIndex]; 250 | } 251 | 252 | override public String ToString () { 253 | StringBuilder buffer = new StringBuilder(); 254 | for (int i = 0, n = tracks.Count; i < n; i++) { 255 | TrackEntry entry = tracks.Items[i]; 256 | if (entry == null) continue; 257 | if (buffer.Length > 0) buffer.Append(", "); 258 | buffer.Append(entry.ToString()); 259 | } 260 | if (buffer.Length == 0) return ""; 261 | return buffer.ToString(); 262 | } 263 | } 264 | 265 | public class TrackEntry { 266 | internal TrackEntry next, previous; 267 | internal Animation animation; 268 | internal bool loop; 269 | internal float delay, time, lastTime = -1, endTime, timeScale = 1; 270 | internal float mixTime, mixDuration, mix = 1; 271 | 272 | public Animation Animation { get { return animation; } } 273 | public float Delay { get { return delay; } set { delay = value; } } 274 | public float Time { get { return time; } set { time = value; } } 275 | public float LastTime { get { return lastTime; } set { lastTime = value; } } 276 | public float EndTime { get { return endTime; } set { endTime = value; } } 277 | public float TimeScale { get { return timeScale; } set { timeScale = value; } } 278 | public float Mix { get { return mix; } set { mix = value; } } 279 | public bool Loop { get { return loop; } set { loop = value; } } 280 | 281 | public event AnimationState.StartEndDelegate Start; 282 | public event AnimationState.StartEndDelegate End; 283 | public event AnimationState.EventDelegate Event; 284 | public event AnimationState.CompleteDelegate Complete; 285 | 286 | internal void OnStart (AnimationState state, int index) { 287 | if (Start != null) Start(state, index); 288 | } 289 | 290 | internal void OnEnd (AnimationState state, int index) { 291 | if (End != null) End(state, index); 292 | } 293 | 294 | internal void OnEvent (AnimationState state, int index, Event e) { 295 | if (Event != null) Event(state, index, e); 296 | } 297 | 298 | internal void OnComplete (AnimationState state, int index, int loopCount) { 299 | if (Complete != null) Complete(state, index, loopCount); 300 | } 301 | 302 | override public String ToString () { 303 | return animation == null ? "" : animation.name; 304 | } 305 | } 306 | } 307 | -------------------------------------------------------------------------------- /spine-csharp/src/AnimationStateData.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License v2.5 3 | * 4 | * Copyright (c) 2013-2016, Esoteric Software 5 | * All rights reserved. 6 | * 7 | * You are granted a perpetual, non-exclusive, non-sublicensable, and 8 | * non-transferable license to use, install, execute, and perform the Spine 9 | * Runtimes software and derivative works solely for personal or internal 10 | * use. Without the written permission of Esoteric Software (see Section 2 of 11 | * the Spine Software License Agreement), you may not (a) modify, translate, 12 | * adapt, or develop new applications using the Spine Runtimes or otherwise 13 | * create derivative works or improvements of the Spine Runtimes or (b) remove, 14 | * delete, alter, or obscure any trademarks or any copyright, trademark, patent, 15 | * or other intellectual property or proprietary rights notices on or in the 16 | * Software, including any copy thereof. Redistributions in binary or source 17 | * form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF 25 | * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 26 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | using System.Collections.Generic; 33 | 34 | namespace Spine { 35 | public class AnimationStateData { 36 | internal SkeletonData skeletonData; 37 | private Dictionary animationToMixTime = new Dictionary(AnimationPairComparer.Instance); 38 | internal float defaultMix; 39 | 40 | public SkeletonData SkeletonData { get { return skeletonData; } } 41 | public float DefaultMix { get { return defaultMix; } set { defaultMix = value; } } 42 | 43 | public AnimationStateData (SkeletonData skeletonData) { 44 | if (skeletonData == null) throw new ArgumentException ("skeletonData cannot be null."); 45 | this.skeletonData = skeletonData; 46 | } 47 | 48 | public void SetMix (String fromName, String toName, float duration) { 49 | Animation from = skeletonData.FindAnimation(fromName); 50 | if (from == null) throw new ArgumentException("Animation not found: " + fromName); 51 | Animation to = skeletonData.FindAnimation(toName); 52 | if (to == null) throw new ArgumentException("Animation not found: " + toName); 53 | SetMix(from, to, duration); 54 | } 55 | 56 | public void SetMix (Animation from, Animation to, float duration) { 57 | if (from == null) throw new ArgumentNullException("from", "from cannot be null."); 58 | if (to == null) throw new ArgumentNullException("to", "to cannot be null."); 59 | AnimationPair key = new AnimationPair(from, to); 60 | animationToMixTime.Remove(key); 61 | animationToMixTime.Add(key, duration); 62 | } 63 | 64 | public float GetMix (Animation from, Animation to) { 65 | AnimationPair key = new AnimationPair(from, to); 66 | float duration; 67 | if (animationToMixTime.TryGetValue(key, out duration)) return duration; 68 | return defaultMix; 69 | } 70 | 71 | struct AnimationPair { 72 | public readonly Animation a1; 73 | public readonly Animation a2; 74 | 75 | public AnimationPair (Animation a1, Animation a2) { 76 | this.a1 = a1; 77 | this.a2 = a2; 78 | } 79 | } 80 | 81 | // Avoids boxing in the dictionary. 82 | class AnimationPairComparer : IEqualityComparer { 83 | internal static readonly AnimationPairComparer Instance = new AnimationPairComparer(); 84 | 85 | bool IEqualityComparer.Equals (AnimationPair x, AnimationPair y) { 86 | return ReferenceEquals(x.a1, y.a1) && ReferenceEquals(x.a2, y.a2); 87 | } 88 | 89 | int IEqualityComparer.GetHashCode (AnimationPair obj) { 90 | // from Tuple.CombineHashCodes // return (((h1 << 5) + h1) ^ h2); 91 | int h1 = obj.a1.GetHashCode(); 92 | return (((h1 << 5) + h1) ^ obj.a2.GetHashCode()); 93 | } 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /spine-csharp/src/Atlas.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License v2.5 3 | * 4 | * Copyright (c) 2013-2016, Esoteric Software 5 | * All rights reserved. 6 | * 7 | * You are granted a perpetual, non-exclusive, non-sublicensable, and 8 | * non-transferable license to use, install, execute, and perform the Spine 9 | * Runtimes software and derivative works solely for personal or internal 10 | * use. Without the written permission of Esoteric Software (see Section 2 of 11 | * the Spine Software License Agreement), you may not (a) modify, translate, 12 | * adapt, or develop new applications using the Spine Runtimes or otherwise 13 | * create derivative works or improvements of the Spine Runtimes or (b) remove, 14 | * delete, alter, or obscure any trademarks or any copyright, trademark, patent, 15 | * or other intellectual property or proprietary rights notices on or in the 16 | * Software, including any copy thereof. Redistributions in binary or source 17 | * form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF 25 | * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 26 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | using System.Collections.Generic; 33 | using System.IO; 34 | using System.Reflection; 35 | 36 | #if WINDOWS_STOREAPP 37 | using System.Threading.Tasks; 38 | using Windows.Storage; 39 | #endif 40 | 41 | namespace Spine { 42 | public class Atlas { 43 | List pages = new List(); 44 | List regions = new List(); 45 | TextureLoader textureLoader; 46 | 47 | #if !(UNITY_5 || UNITY_4 || UNITY_WSA || UNITY_WP8 || UNITY_WP8_1) // !UNITY 48 | #if WINDOWS_STOREAPP 49 | private async Task ReadFile(string path, TextureLoader textureLoader) { 50 | var folder = Windows.ApplicationModel.Package.Current.InstalledLocation; 51 | var file = await folder.GetFileAsync(path).AsTask().ConfigureAwait(false); 52 | using (var reader = new StreamReader(await file.OpenStreamForReadAsync().ConfigureAwait(false))) { 53 | try { 54 | Load(reader, Path.GetDirectoryName(path), textureLoader); 55 | } catch (Exception ex) { 56 | throw new Exception("Error reading atlas file: " + path, ex); 57 | } 58 | } 59 | } 60 | 61 | public Atlas(String path, TextureLoader textureLoader) { 62 | this.ReadFile(path, textureLoader).Wait(); 63 | } 64 | #else 65 | 66 | public Atlas (String path, TextureLoader textureLoader) { 67 | 68 | #if WINDOWS_PHONE 69 | Stream stream = Microsoft.Xna.Framework.TitleContainer.OpenStream(path); 70 | using (StreamReader reader = new StreamReader(stream)) { 71 | #else 72 | using (StreamReader reader = new StreamReader(path)) { 73 | #endif // WINDOWS_PHONE 74 | 75 | try { 76 | Load(reader, Path.GetDirectoryName(path), textureLoader); 77 | } catch (Exception ex) { 78 | throw new Exception("Error reading atlas file: " + path, ex); 79 | } 80 | 81 | } 82 | } 83 | #endif // WINDOWS_STOREAPP 84 | 85 | #endif // !(UNITY) 86 | public Atlas() { 87 | //initialize empty atlas 88 | } 89 | public Atlas (TextReader reader, String dir, TextureLoader textureLoader) { 90 | Load(reader, dir, textureLoader); 91 | } 92 | 93 | public Atlas (List pages, List regions) { 94 | this.pages = pages; 95 | this.regions = regions; 96 | this.textureLoader = null; 97 | } 98 | 99 | private void Load (TextReader reader, String imagesDir, TextureLoader textureLoader) { 100 | if (textureLoader == null) throw new ArgumentNullException("textureLoader cannot be null."); 101 | this.textureLoader = textureLoader; 102 | 103 | String[] tuple = new String[4]; 104 | AtlasPage page = null; 105 | while (true) { 106 | String line = reader.ReadLine(); 107 | if (line == null) break; 108 | if (line.Trim().Length == 0) 109 | page = null; 110 | else if (page == null) { 111 | page = new AtlasPage(); 112 | page.name = line; 113 | 114 | if (ReadTuple(reader, tuple) == 2) { // size is only optional for an atlas packed with an old TexturePacker. 115 | page.width = int.Parse(tuple[0]); 116 | page.height = int.Parse(tuple[1]); 117 | ReadTuple(reader, tuple); 118 | } 119 | page.format = (Format)Enum.Parse(typeof(Format), tuple[0], false); 120 | 121 | ReadTuple(reader, tuple); 122 | page.minFilter = (TextureFilter)Enum.Parse(typeof(TextureFilter), tuple[0], false); 123 | page.magFilter = (TextureFilter)Enum.Parse(typeof(TextureFilter), tuple[1], false); 124 | 125 | String direction = ReadValue(reader); 126 | page.uWrap = TextureWrap.ClampToEdge; 127 | page.vWrap = TextureWrap.ClampToEdge; 128 | if (direction == "x") 129 | page.uWrap = TextureWrap.Repeat; 130 | else if (direction == "y") 131 | page.vWrap = TextureWrap.Repeat; 132 | else if (direction == "xy") 133 | page.uWrap = page.vWrap = TextureWrap.Repeat; 134 | 135 | textureLoader.Load(page, Path.Combine(imagesDir, line)); 136 | 137 | pages.Add(page); 138 | 139 | } else { 140 | AtlasRegion region = new AtlasRegion(); 141 | region.name = line; 142 | region.page = page; 143 | 144 | region.rotate = Boolean.Parse(ReadValue(reader)); 145 | 146 | ReadTuple(reader, tuple); 147 | int x = int.Parse(tuple[0]); 148 | int y = int.Parse(tuple[1]); 149 | 150 | ReadTuple(reader, tuple); 151 | int width = int.Parse(tuple[0]); 152 | int height = int.Parse(tuple[1]); 153 | 154 | region.u = x / (float)page.width; 155 | region.v = y / (float)page.height; 156 | if (region.rotate) { 157 | region.u2 = (x + height) / (float)page.width; 158 | region.v2 = (y + width) / (float)page.height; 159 | } else { 160 | region.u2 = (x + width) / (float)page.width; 161 | region.v2 = (y + height) / (float)page.height; 162 | } 163 | region.x = x; 164 | region.y = y; 165 | region.width = Math.Abs(width); 166 | region.height = Math.Abs(height); 167 | 168 | if (ReadTuple(reader, tuple) == 4) { // split is optional 169 | region.splits = new int[] {int.Parse(tuple[0]), int.Parse(tuple[1]), 170 | int.Parse(tuple[2]), int.Parse(tuple[3])}; 171 | 172 | if (ReadTuple(reader, tuple) == 4) { // pad is optional, but only present with splits 173 | region.pads = new int[] {int.Parse(tuple[0]), int.Parse(tuple[1]), 174 | int.Parse(tuple[2]), int.Parse(tuple[3])}; 175 | 176 | ReadTuple(reader, tuple); 177 | } 178 | } 179 | 180 | region.originalWidth = int.Parse(tuple[0]); 181 | region.originalHeight = int.Parse(tuple[1]); 182 | 183 | ReadTuple(reader, tuple); 184 | region.offsetX = int.Parse(tuple[0]); 185 | region.offsetY = int.Parse(tuple[1]); 186 | 187 | region.index = int.Parse(ReadValue(reader)); 188 | 189 | regions.Add(region); 190 | } 191 | } 192 | } 193 | 194 | static String ReadValue (TextReader reader) { 195 | String line = reader.ReadLine(); 196 | int colon = line.IndexOf(':'); 197 | if (colon == -1) throw new Exception("Invalid line: " + line); 198 | return line.Substring(colon + 1).Trim(); 199 | } 200 | 201 | /// Returns the number of tuple values read (1, 2 or 4). 202 | static int ReadTuple (TextReader reader, String[] tuple) { 203 | String line = reader.ReadLine(); 204 | int colon = line.IndexOf(':'); 205 | if (colon == -1) throw new Exception("Invalid line: " + line); 206 | int i = 0, lastMatch = colon + 1; 207 | for (; i < 3; i++) { 208 | int comma = line.IndexOf(',', lastMatch); 209 | if (comma == -1) break; 210 | tuple[i] = line.Substring(lastMatch, comma - lastMatch).Trim(); 211 | lastMatch = comma + 1; 212 | } 213 | tuple[i] = line.Substring(lastMatch).Trim(); 214 | return i + 1; 215 | } 216 | 217 | public void FlipV () { 218 | for (int i = 0, n = regions.Count; i < n; i++) { 219 | AtlasRegion region = regions[i]; 220 | region.v = 1 - region.v; 221 | region.v2 = 1 - region.v2; 222 | } 223 | } 224 | 225 | /// Returns the first region found with the specified name. This method uses string comparison to find the region, so the result 226 | /// should be cached rather than calling this method multiple times. 227 | /// The region, or null. 228 | public AtlasRegion FindRegion (String name) { 229 | for (int i = 0, n = regions.Count; i < n; i++) 230 | if (regions[i].name == name) return regions[i]; 231 | return null; 232 | } 233 | 234 | public void Dispose () { 235 | if (textureLoader == null) return; 236 | for (int i = 0, n = pages.Count; i < n; i++) 237 | textureLoader.Unload(pages[i].rendererObject); 238 | } 239 | } 240 | 241 | public enum Format { 242 | Alpha, 243 | Intensity, 244 | LuminanceAlpha, 245 | RGB565, 246 | RGBA4444, 247 | RGB888, 248 | RGBA8888 249 | } 250 | 251 | public enum TextureFilter { 252 | Nearest, 253 | Linear, 254 | MipMap, 255 | MipMapNearestNearest, 256 | MipMapLinearNearest, 257 | MipMapNearestLinear, 258 | MipMapLinearLinear 259 | } 260 | 261 | public enum TextureWrap { 262 | MirroredRepeat, 263 | ClampToEdge, 264 | Repeat 265 | } 266 | 267 | public class AtlasPage { 268 | public String name; 269 | public Format format; 270 | public TextureFilter minFilter; 271 | public TextureFilter magFilter; 272 | public TextureWrap uWrap; 273 | public TextureWrap vWrap; 274 | public Object rendererObject; 275 | public int width, height; 276 | } 277 | 278 | public class AtlasRegion { 279 | public AtlasPage page; 280 | public String name; 281 | public int x, y, width, height; 282 | public float u, v, u2, v2; 283 | public float offsetX, offsetY; 284 | public int originalWidth, originalHeight; 285 | public int index; 286 | public bool rotate; 287 | public int[] splits; 288 | public int[] pads; 289 | } 290 | 291 | public interface TextureLoader { 292 | void Load (AtlasPage page, String path); 293 | void Unload (Object texture); 294 | } 295 | } 296 | -------------------------------------------------------------------------------- /spine-csharp/src/Attachments/AtlasAttachmentLoader.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License v2.5 3 | * 4 | * Copyright (c) 2013-2016, Esoteric Software 5 | * All rights reserved. 6 | * 7 | * You are granted a perpetual, non-exclusive, non-sublicensable, and 8 | * non-transferable license to use, install, execute, and perform the Spine 9 | * Runtimes software and derivative works solely for personal or internal 10 | * use. Without the written permission of Esoteric Software (see Section 2 of 11 | * the Spine Software License Agreement), you may not (a) modify, translate, 12 | * adapt, or develop new applications using the Spine Runtimes or otherwise 13 | * create derivative works or improvements of the Spine Runtimes or (b) remove, 14 | * delete, alter, or obscure any trademarks or any copyright, trademark, patent, 15 | * or other intellectual property or proprietary rights notices on or in the 16 | * Software, including any copy thereof. Redistributions in binary or source 17 | * form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF 25 | * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 26 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | 33 | namespace Spine { 34 | public class AtlasAttachmentLoader : AttachmentLoader { 35 | private Atlas[] atlasArray; 36 | 37 | public AtlasAttachmentLoader (params Atlas[] atlasArray) { 38 | if (atlasArray == null) throw new ArgumentNullException("atlas array cannot be null."); 39 | this.atlasArray = atlasArray; 40 | } 41 | 42 | public RegionAttachment NewRegionAttachment (Skin skin, String name, String path) { 43 | AtlasRegion region = FindRegion(path); 44 | if (region == null) 45 | region = new AtlasRegion(); 46 | if (region == null) throw new Exception("Region not found in atlas: " + path + " (region attachment: " + name + ")"); 47 | RegionAttachment attachment = new RegionAttachment(name); 48 | attachment.RendererObject = region; 49 | attachment.SetUVs(region.u, region.v, region.u2, region.v2, region.rotate); 50 | attachment.regionOffsetX = region.offsetX; 51 | attachment.regionOffsetY = region.offsetY; 52 | attachment.regionWidth = region.width; 53 | attachment.regionHeight = region.height; 54 | attachment.regionOriginalWidth = region.originalWidth; 55 | attachment.regionOriginalHeight = region.originalHeight; 56 | return attachment; 57 | } 58 | 59 | public MeshAttachment NewMeshAttachment (Skin skin, String name, String path) { 60 | 61 | AtlasRegion region = FindRegion(path); 62 | if (region == null) 63 | region = new AtlasRegion(); 64 | if (region == null) throw new Exception("Region not found in atlas: " + path + " (mesh attachment: " + name + ")"); 65 | MeshAttachment attachment = new MeshAttachment(name); 66 | attachment.RendererObject = region; 67 | attachment.RegionU = region.u; 68 | attachment.RegionV = region.v; 69 | attachment.RegionU2 = region.u2; 70 | attachment.RegionV2 = region.v2; 71 | attachment.RegionRotate = region.rotate; 72 | attachment.regionOffsetX = region.offsetX; 73 | attachment.regionOffsetY = region.offsetY; 74 | attachment.regionWidth = region.width; 75 | attachment.regionHeight = region.height; 76 | attachment.regionOriginalWidth = region.originalWidth; 77 | attachment.regionOriginalHeight = region.originalHeight; 78 | return attachment; 79 | } 80 | 81 | public BoundingBoxAttachment NewBoundingBoxAttachment (Skin skin, String name) { 82 | return new BoundingBoxAttachment(name); 83 | } 84 | 85 | public PathAttachment NewPathAttachment (Skin skin, String name) { 86 | return new PathAttachment (name); 87 | } 88 | 89 | public AtlasRegion FindRegion (string name) { 90 | AtlasRegion region; 91 | 92 | for (int i = 0; i < atlasArray.Length; i++) { 93 | region = atlasArray[i].FindRegion(name); 94 | if (region != null) 95 | return region; 96 | } 97 | 98 | return null; 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /spine-csharp/src/Attachments/Attachment.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License v2.5 3 | * 4 | * Copyright (c) 2013-2016, Esoteric Software 5 | * All rights reserved. 6 | * 7 | * You are granted a perpetual, non-exclusive, non-sublicensable, and 8 | * non-transferable license to use, install, execute, and perform the Spine 9 | * Runtimes software and derivative works solely for personal or internal 10 | * use. Without the written permission of Esoteric Software (see Section 2 of 11 | * the Spine Software License Agreement), you may not (a) modify, translate, 12 | * adapt, or develop new applications using the Spine Runtimes or otherwise 13 | * create derivative works or improvements of the Spine Runtimes or (b) remove, 14 | * delete, alter, or obscure any trademarks or any copyright, trademark, patent, 15 | * or other intellectual property or proprietary rights notices on or in the 16 | * Software, including any copy thereof. Redistributions in binary or source 17 | * form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF 25 | * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 26 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | 33 | namespace Spine { 34 | abstract public class Attachment { 35 | public String Name { get; private set; } 36 | public String Type { get; set; } 37 | 38 | public Attachment (String name) { 39 | if (name == null) throw new ArgumentNullException("name", "name cannot be null"); 40 | Name = name; 41 | // Type = type; 42 | } 43 | 44 | override public String ToString () { 45 | return Name; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /spine-csharp/src/Attachments/AttachmentLoader.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License v2.5 3 | * 4 | * Copyright (c) 2013-2016, Esoteric Software 5 | * All rights reserved. 6 | * 7 | * You are granted a perpetual, non-exclusive, non-sublicensable, and 8 | * non-transferable license to use, install, execute, and perform the Spine 9 | * Runtimes software and derivative works solely for personal or internal 10 | * use. Without the written permission of Esoteric Software (see Section 2 of 11 | * the Spine Software License Agreement), you may not (a) modify, translate, 12 | * adapt, or develop new applications using the Spine Runtimes or otherwise 13 | * create derivative works or improvements of the Spine Runtimes or (b) remove, 14 | * delete, alter, or obscure any trademarks or any copyright, trademark, patent, 15 | * or other intellectual property or proprietary rights notices on or in the 16 | * Software, including any copy thereof. Redistributions in binary or source 17 | * form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF 25 | * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 26 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | 33 | namespace Spine { 34 | public interface AttachmentLoader { 35 | /// May be null to not load any attachment. 36 | RegionAttachment NewRegionAttachment (Skin skin, String name, String path); 37 | 38 | /// May be null to not load any attachment. 39 | MeshAttachment NewMeshAttachment (Skin skin, String name, String path); 40 | 41 | /// May be null to not load any attachment. 42 | BoundingBoxAttachment NewBoundingBoxAttachment (Skin skin, String name); 43 | 44 | /// May be null to not load any attachment 45 | PathAttachment NewPathAttachment (Skin skin, String name); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /spine-csharp/src/Attachments/AttachmentType.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License v2.5 3 | * 4 | * Copyright (c) 2013-2016, Esoteric Software 5 | * All rights reserved. 6 | * 7 | * You are granted a perpetual, non-exclusive, non-sublicensable, and 8 | * non-transferable license to use, install, execute, and perform the Spine 9 | * Runtimes software and derivative works solely for personal or internal 10 | * use. Without the written permission of Esoteric Software (see Section 2 of 11 | * the Spine Software License Agreement), you may not (a) modify, translate, 12 | * adapt, or develop new applications using the Spine Runtimes or otherwise 13 | * create derivative works or improvements of the Spine Runtimes or (b) remove, 14 | * delete, alter, or obscure any trademarks or any copyright, trademark, patent, 15 | * or other intellectual property or proprietary rights notices on or in the 16 | * Software, including any copy thereof. Redistributions in binary or source 17 | * form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF 25 | * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 26 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | namespace Spine { 32 | public enum AttachmentType { 33 | Region, Boundingbox, Mesh, Linkedmesh, Path 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /spine-csharp/src/Attachments/BoundingBoxAttachment.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License v2.5 3 | * 4 | * Copyright (c) 2013-2016, Esoteric Software 5 | * All rights reserved. 6 | * 7 | * You are granted a perpetual, non-exclusive, non-sublicensable, and 8 | * non-transferable license to use, install, execute, and perform the Spine 9 | * Runtimes software and derivative works solely for personal or internal 10 | * use. Without the written permission of Esoteric Software (see Section 2 of 11 | * the Spine Software License Agreement), you may not (a) modify, translate, 12 | * adapt, or develop new applications using the Spine Runtimes or otherwise 13 | * create derivative works or improvements of the Spine Runtimes or (b) remove, 14 | * delete, alter, or obscure any trademarks or any copyright, trademark, patent, 15 | * or other intellectual property or proprietary rights notices on or in the 16 | * Software, including any copy thereof. Redistributions in binary or source 17 | * form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF 25 | * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 26 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | 33 | namespace Spine { 34 | /// Attachment that has a polygon for bounds checking. 35 | public class BoundingBoxAttachment : VertexAttachment { 36 | public BoundingBoxAttachment (string name) 37 | : base(name) { 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /spine-csharp/src/Attachments/MeshAttachment.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License v2.5 3 | * 4 | * Copyright (c) 2013-2016, Esoteric Software 5 | * All rights reserved. 6 | * 7 | * You are granted a perpetual, non-exclusive, non-sublicensable, and 8 | * non-transferable license to use, install, execute, and perform the Spine 9 | * Runtimes software and derivative works solely for personal or internal 10 | * use. Without the written permission of Esoteric Software (see Section 2 of 11 | * the Spine Software License Agreement), you may not (a) modify, translate, 12 | * adapt, or develop new applications using the Spine Runtimes or otherwise 13 | * create derivative works or improvements of the Spine Runtimes or (b) remove, 14 | * delete, alter, or obscure any trademarks or any copyright, trademark, patent, 15 | * or other intellectual property or proprietary rights notices on or in the 16 | * Software, including any copy thereof. Redistributions in binary or source 17 | * form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF 25 | * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 26 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | 33 | namespace Spine { 34 | /// Attachment that displays a texture region using a mesh. 35 | public class MeshAttachment : VertexAttachment { 36 | internal float regionOffsetX, regionOffsetY, regionWidth, regionHeight, regionOriginalWidth, regionOriginalHeight; 37 | internal float[] uvs, regionUVs; 38 | internal int[] triangles; 39 | internal float r = 1, g = 1, b = 1, a = 1; 40 | internal int hulllength; 41 | internal MeshAttachment parentMesh; 42 | internal bool inheritDeform; 43 | 44 | public int HullLength { get { return hulllength; } set { hulllength = value; } } 45 | public float[] RegionUVs { get { return regionUVs; } set { regionUVs = value; } } 46 | public float[] UVs { get { return uvs; } set { uvs = value; } } 47 | public int[] Triangles { get { return triangles; } set { triangles = value; } } 48 | 49 | public float R { get { return r; } set { r = value; } } 50 | public float G { get { return g; } set { g = value; } } 51 | public float B { get { return b; } set { b = value; } } 52 | public float A { get { return a; } set { a = value; } } 53 | 54 | public String Path { get; set; } 55 | public Object RendererObject { get; set; } 56 | public float RegionU { get; set; } 57 | public float RegionV { get; set; } 58 | public float RegionU2 { get; set; } 59 | public float RegionV2 { get; set; } 60 | public bool RegionRotate { get; set; } 61 | public float RegionOffsetX { get { return regionOffsetX; } set { regionOffsetX = value; } } 62 | public float RegionOffsetY { get { return regionOffsetY; } set { regionOffsetY = value; } } // Pixels stripped from the bottom left, unrotated. 63 | public float RegionWidth { get { return regionWidth; } set { regionWidth = value; } } 64 | public float RegionHeight { get { return regionHeight; } set { regionHeight = value; } } // Unrotated, stripped size. 65 | public float RegionOriginalWidth { get { return regionOriginalWidth; } set { regionOriginalWidth = value; } } 66 | public float RegionOriginalHeight { get { return regionOriginalHeight; } set { regionOriginalHeight = value; } } // Unrotated, unstripped size. 67 | 68 | public bool InheritDeform { get { return inheritDeform; } set { inheritDeform = value; } } 69 | 70 | public MeshAttachment ParentMesh { 71 | get { return parentMesh; } 72 | set { 73 | parentMesh = value; 74 | if (value != null) { 75 | bones = value.bones; 76 | vertices = value.vertices; 77 | worldVerticesLength = value.worldVerticesLength; 78 | regionUVs = value.regionUVs; 79 | triangles = value.triangles; 80 | HullLength = value.HullLength; 81 | Edges = value.Edges; 82 | Width = value.Width; 83 | Height = value.Height; 84 | } 85 | } 86 | } 87 | 88 | // Nonessential. 89 | public int[] Edges { get; set; } 90 | public float Width { get; set; } 91 | public float Height { get; set; } 92 | 93 | public MeshAttachment (string name) 94 | : base(name) { 95 | } 96 | 97 | public void UpdateUVs () { 98 | float u = RegionU, v = RegionV, width = RegionU2 - RegionU, height = RegionV2 - RegionV; 99 | 100 | float[] regionUVs = this.regionUVs; 101 | if (this.uvs == null || this.uvs.Length != regionUVs.Length) this.uvs = new float[regionUVs.Length]; 102 | float[] uvs = this.uvs; 103 | if (RegionRotate) { 104 | for (int i = 0, n = uvs.Length; i < n; i += 2) { 105 | uvs[i] = u + regionUVs[i + 1] * width; 106 | uvs[i + 1] = v + height - regionUVs[i] * height; 107 | } 108 | } else { 109 | for (int i = 0, n = uvs.Length; i < n; i += 2) { 110 | uvs[i] = u + regionUVs[i] * width; 111 | uvs[i + 1] = v + regionUVs[i + 1] * height; 112 | } 113 | } 114 | } 115 | 116 | override public bool ApplyDeform (VertexAttachment sourceAttachment) { 117 | return this == sourceAttachment || (inheritDeform && parentMesh == sourceAttachment); 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /spine-csharp/src/Attachments/PathAttachment.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License v2.5 3 | * 4 | * Copyright (c) 2013-2016, Esoteric Software 5 | * All rights reserved. 6 | * 7 | * You are granted a perpetual, non-exclusive, non-sublicensable, and 8 | * non-transferable license to use, install, execute, and perform the Spine 9 | * Runtimes software and derivative works solely for personal or internal 10 | * use. Without the written permission of Esoteric Software (see Section 2 of 11 | * the Spine Software License Agreement), you may not (a) modify, translate, 12 | * adapt, or develop new applications using the Spine Runtimes or otherwise 13 | * create derivative works or improvements of the Spine Runtimes or (b) remove, 14 | * delete, alter, or obscure any trademarks or any copyright, trademark, patent, 15 | * or other intellectual property or proprietary rights notices on or in the 16 | * Software, including any copy thereof. Redistributions in binary or source 17 | * form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF 25 | * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 26 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | using System.Collections.Generic; 33 | 34 | namespace Spine { 35 | public class PathAttachment : VertexAttachment { 36 | internal float[] lengths; 37 | internal bool closed, constantSpeed; 38 | 39 | 40 | /// The length in the setup pose from the start of the path to the end of each curve. 41 | public float[] Lengths { get { return lengths; } set { lengths = value; } } 42 | public bool Closed { get { return closed; } set { closed = value; } } 43 | public bool ConstantSpeed { get { return constantSpeed; } set { constantSpeed = value; } } 44 | 45 | public PathAttachment (String name) 46 | : base(name) { 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /spine-csharp/src/Attachments/RegionAttachment.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License v2.5 3 | * 4 | * Copyright (c) 2013-2016, Esoteric Software 5 | * All rights reserved. 6 | * 7 | * You are granted a perpetual, non-exclusive, non-sublicensable, and 8 | * non-transferable license to use, install, execute, and perform the Spine 9 | * Runtimes software and derivative works solely for personal or internal 10 | * use. Without the written permission of Esoteric Software (see Section 2 of 11 | * the Spine Software License Agreement), you may not (a) modify, translate, 12 | * adapt, or develop new applications using the Spine Runtimes or otherwise 13 | * create derivative works or improvements of the Spine Runtimes or (b) remove, 14 | * delete, alter, or obscure any trademarks or any copyright, trademark, patent, 15 | * or other intellectual property or proprietary rights notices on or in the 16 | * Software, including any copy thereof. Redistributions in binary or source 17 | * form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF 25 | * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 26 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | 33 | namespace Spine { 34 | /// Attachment that displays a texture region. 35 | public class RegionAttachment : Attachment { 36 | public const int X1 = 0; 37 | public const int Y1 = 1; 38 | public const int X2 = 2; 39 | public const int Y2 = 3; 40 | public const int X3 = 4; 41 | public const int Y3 = 5; 42 | public const int X4 = 6; 43 | public const int Y4 = 7; 44 | 45 | internal float x, y, rotation, scaleX = 1, scaleY = 1, width, height; 46 | internal float regionOffsetX, regionOffsetY, regionWidth, regionHeight, regionOriginalWidth, regionOriginalHeight; 47 | internal float[] offset = new float[8], uvs = new float[8]; 48 | internal float r = 1, g = 1, b = 1, a = 1; 49 | 50 | public float X { get { return x; } set { x = value; } } 51 | public float Y { get { return y; } set { y = value; } } 52 | public float Rotation { get { return rotation; } set { rotation = value; } } 53 | public float ScaleX { get { return scaleX; } set { scaleX = value; } } 54 | public float ScaleY { get { return scaleY; } set { scaleY = value; } } 55 | public float Width { get { return width; } set { width = value; } } 56 | public float Height { get { return height; } set { height = value; } } 57 | 58 | public float R { get { return r; } set { r = value; } } 59 | public float G { get { return g; } set { g = value; } } 60 | public float B { get { return b; } set { b = value; } } 61 | public float A { get { return a; } set { a = value; } } 62 | 63 | public String Path { get; set; } 64 | public Object RendererObject { get; set; } 65 | public float RegionOffsetX { get { return regionOffsetX; } set { regionOffsetX = value; } } 66 | public float RegionOffsetY { get { return regionOffsetY; } set { regionOffsetY = value; } } // Pixels stripped from the bottom left, unrotated. 67 | public float RegionWidth { get { return regionWidth; } set { regionWidth = value; } } 68 | public float RegionHeight { get { return regionHeight; } set { regionHeight = value; } } // Unrotated, stripped size. 69 | public float RegionOriginalWidth { get { return regionOriginalWidth; } set { regionOriginalWidth = value; } } 70 | public float RegionOriginalHeight { get { return regionOriginalHeight; } set { regionOriginalHeight = value; } } // Unrotated, unstripped size. 71 | 72 | public float[] Offset { get { return offset; } } 73 | public float[] UVs { get { return uvs; } } 74 | 75 | public RegionAttachment (string name) 76 | : base(name) { 77 | } 78 | 79 | public void SetUVs (float u, float v, float u2, float v2, bool rotate) { 80 | float[] uvs = this.uvs; 81 | if (rotate) { 82 | uvs[X2] = u; 83 | uvs[Y2] = v2; 84 | uvs[X3] = u; 85 | uvs[Y3] = v; 86 | uvs[X4] = u2; 87 | uvs[Y4] = v; 88 | uvs[X1] = u2; 89 | uvs[Y1] = v2; 90 | } else { 91 | uvs[X1] = u; 92 | uvs[Y1] = v2; 93 | uvs[X2] = u; 94 | uvs[Y2] = v; 95 | uvs[X3] = u2; 96 | uvs[Y3] = v; 97 | uvs[X4] = u2; 98 | uvs[Y4] = v2; 99 | } 100 | } 101 | 102 | public void UpdateOffset () { 103 | float width = this.width; 104 | float height = this.height; 105 | float scaleX = this.scaleX; 106 | float scaleY = this.scaleY; 107 | float regionScaleX = width / regionOriginalWidth * scaleX; 108 | float regionScaleY = height / regionOriginalHeight * scaleY; 109 | float localX = -width / 2 * scaleX + regionOffsetX * regionScaleX; 110 | float localY = -height / 2 * scaleY + regionOffsetY * regionScaleY; 111 | float localX2 = localX + regionWidth * regionScaleX; 112 | float localY2 = localY + regionHeight * regionScaleY; 113 | float rotation = this.rotation; 114 | float cos = MathUtils.CosDeg(rotation); 115 | float sin = MathUtils.SinDeg(rotation); 116 | float x = this.x; 117 | float y = this.y; 118 | float localXCos = localX * cos + x; 119 | float localXSin = localX * sin; 120 | float localYCos = localY * cos + y; 121 | float localYSin = localY * sin; 122 | float localX2Cos = localX2 * cos + x; 123 | float localX2Sin = localX2 * sin; 124 | float localY2Cos = localY2 * cos + y; 125 | float localY2Sin = localY2 * sin; 126 | float[] offset = this.offset; 127 | offset[X1] = localXCos - localYSin; 128 | offset[Y1] = localYCos + localXSin; 129 | offset[X2] = localXCos - localY2Sin; 130 | offset[Y2] = localY2Cos + localXSin; 131 | offset[X3] = localX2Cos - localY2Sin; 132 | offset[Y3] = localY2Cos + localX2Sin; 133 | offset[X4] = localX2Cos - localYSin; 134 | offset[Y4] = localYCos + localX2Sin; 135 | } 136 | 137 | public void ComputeWorldVertices (Bone bone, float[] worldVertices) { 138 | Skeleton skeleton = bone.skeleton; 139 | float x = skeleton.x + bone.worldX, y = skeleton.y + bone.worldY; 140 | float a = bone.a, b = bone.b, c = bone.c, d = bone.d; 141 | float[] offset = this.offset; 142 | worldVertices[X1] = offset[X1] * a + offset[Y1] * b + x; 143 | worldVertices[Y1] = offset[X1] * c + offset[Y1] * d + y; 144 | worldVertices[X2] = offset[X2] * a + offset[Y2] * b + x; 145 | worldVertices[Y2] = offset[X2] * c + offset[Y2] * d + y; 146 | worldVertices[X3] = offset[X3] * a + offset[Y3] * b + x; 147 | worldVertices[Y3] = offset[X3] * c + offset[Y3] * d + y; 148 | worldVertices[X4] = offset[X4] * a + offset[Y4] * b + x; 149 | worldVertices[Y4] = offset[X4] * c + offset[Y4] * d + y; 150 | } 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /spine-csharp/src/Attachments/VertexAttachment.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License v2.5 3 | * 4 | * Copyright (c) 2013-2016, Esoteric Software 5 | * All rights reserved. 6 | * 7 | * You are granted a perpetual, non-exclusive, non-sublicensable, and 8 | * non-transferable license to use, install, execute, and perform the Spine 9 | * Runtimes software and derivative works solely for personal or internal 10 | * use. Without the written permission of Esoteric Software (see Section 2 of 11 | * the Spine Software License Agreement), you may not (a) modify, translate, 12 | * adapt, or develop new applications using the Spine Runtimes or otherwise 13 | * create derivative works or improvements of the Spine Runtimes or (b) remove, 14 | * delete, alter, or obscure any trademarks or any copyright, trademark, patent, 15 | * or other intellectual property or proprietary rights notices on or in the 16 | * Software, including any copy thereof. Redistributions in binary or source 17 | * form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF 25 | * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 26 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | using System.Collections.Generic; 33 | 34 | namespace Spine { 35 | /// >An attachment with vertices that are transformed by one or more bones and can be deformed by a slot's vertices. 36 | public class VertexAttachment : Attachment { 37 | internal int[] bones; 38 | internal float[] vertices; 39 | internal int worldVerticesLength; 40 | 41 | public int[] Bones { get { return bones; } set { bones = value; } } 42 | public float[] Vertices { get { return vertices; } set { vertices = value; } } 43 | public int WorldVerticesLength { get { return worldVerticesLength; } set { worldVerticesLength = value; } } 44 | 45 | public VertexAttachment (String name) 46 | : base(name) { 47 | } 48 | 49 | public void ComputeWorldVertices (Slot slot, float[] worldVertices) { 50 | ComputeWorldVertices(slot, 0, worldVerticesLength, worldVertices, 0); 51 | } 52 | 53 | public void ComputeWorldVertices (Slot slot, int start, int count, float[] worldVertices, int offset) { 54 | count += offset; 55 | Skeleton skeleton = slot.Skeleton; 56 | float x = skeleton.x, y = skeleton.y; 57 | var deformArray = slot.attachmentVertices; 58 | float[] vertices = this.vertices; 59 | int[] bones = this.bones; 60 | if (bones == null) { 61 | if (deformArray.Count > 0) vertices = deformArray.Items; 62 | Bone bone = slot.bone; 63 | x += bone.worldX; 64 | y += bone.worldY; 65 | float a = bone.a, b = bone.b, c = bone.c, d = bone.d; 66 | for (int vv = start, w = offset; w < count; vv += 2, w += 2) { 67 | float vx = vertices[vv], vy = vertices[vv + 1]; 68 | worldVertices[w] = vx * a + vy * b + x; 69 | worldVertices[w + 1] = vx * c + vy * d + y; 70 | } 71 | return; 72 | } 73 | int v = 0, skip = 0; 74 | for (int i = 0; i < start; i += 2) { 75 | int n = bones[v]; 76 | v += n + 1; 77 | skip += n; 78 | } 79 | Bone[] skeletonBones = skeleton.Bones.Items; 80 | if (deformArray.Count == 0) { 81 | for (int w = offset, b = skip * 3; w < count; w += 2) { 82 | float wx = x, wy = y; 83 | int n = bones[v++]; 84 | n += v; 85 | for (; v < n; v++, b += 3) { 86 | Bone bone = skeletonBones[bones[v]]; 87 | float vx = vertices[b], vy = vertices[b + 1], weight = vertices[b + 2]; 88 | wx += (vx * bone.a + vy * bone.b + bone.worldX) * weight; 89 | wy += (vx * bone.c + vy * bone.d + bone.worldY) * weight; 90 | } 91 | worldVertices[w] = wx; 92 | worldVertices[w + 1] = wy; 93 | } 94 | } else { 95 | float[] deform = deformArray.Items; 96 | for (int w = offset, b = skip * 3, f = skip << 1; w < count; w += 2) { 97 | float wx = x, wy = y; 98 | int n = bones[v++]; 99 | n += v; 100 | for (; v < n; v++, b += 3, f += 2) { 101 | Bone bone = skeletonBones[bones[v]]; 102 | float vx = vertices[b] + deform[f], vy = vertices[b + 1] + deform[f + 1], weight = vertices[b + 2]; 103 | wx += (vx * bone.a + vy * bone.b + bone.worldX) * weight; 104 | wy += (vx * bone.c + vy * bone.d + bone.worldY) * weight; 105 | } 106 | worldVertices[w] = wx; 107 | worldVertices[w + 1] = wy; 108 | } 109 | } 110 | } 111 | 112 | /// Returns true if a deform originally applied to the specified attachment should be applied to this attachment. 113 | virtual public bool ApplyDeform (VertexAttachment sourceAttachment) { 114 | return this == sourceAttachment; 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /spine-csharp/src/BlendMode.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License v2.5 3 | * 4 | * Copyright (c) 2013-2016, Esoteric Software 5 | * All rights reserved. 6 | * 7 | * You are granted a perpetual, non-exclusive, non-sublicensable, and 8 | * non-transferable license to use, install, execute, and perform the Spine 9 | * Runtimes software and derivative works solely for personal or internal 10 | * use. Without the written permission of Esoteric Software (see Section 2 of 11 | * the Spine Software License Agreement), you may not (a) modify, translate, 12 | * adapt, or develop new applications using the Spine Runtimes or otherwise 13 | * create derivative works or improvements of the Spine Runtimes or (b) remove, 14 | * delete, alter, or obscure any trademarks or any copyright, trademark, patent, 15 | * or other intellectual property or proprietary rights notices on or in the 16 | * Software, including any copy thereof. Redistributions in binary or source 17 | * form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF 25 | * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 26 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | namespace Spine { 32 | public enum BlendMode { 33 | normal, additive, multiply, screen 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /spine-csharp/src/Bone.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License v2.5 3 | * 4 | * Copyright (c) 2013-2016, Esoteric Software 5 | * All rights reserved. 6 | * 7 | * You are granted a perpetual, non-exclusive, non-sublicensable, and 8 | * non-transferable license to use, install, execute, and perform the Spine 9 | * Runtimes software and derivative works solely for personal or internal 10 | * use. Without the written permission of Esoteric Software (see Section 2 of 11 | * the Spine Software License Agreement), you may not (a) modify, translate, 12 | * adapt, or develop new applications using the Spine Runtimes or otherwise 13 | * create derivative works or improvements of the Spine Runtimes or (b) remove, 14 | * delete, alter, or obscure any trademarks or any copyright, trademark, patent, 15 | * or other intellectual property or proprietary rights notices on or in the 16 | * Software, including any copy thereof. Redistributions in binary or source 17 | * form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF 25 | * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 26 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | 33 | namespace Spine { 34 | public class Bone : IUpdatable { 35 | static public bool yDown; 36 | 37 | internal BoneData data; 38 | internal Skeleton skeleton; 39 | internal Bone parent; 40 | internal ExposedList children = new ExposedList(); 41 | internal float x, y, rotation, scaleX, scaleY, shearX, shearY; 42 | internal float appliedRotation; 43 | 44 | internal float a, b, worldX; 45 | internal float c, d, worldY; 46 | internal float worldSignX, worldSignY; 47 | 48 | internal bool sorted; 49 | 50 | public BoneData Data { get { return data; } } 51 | public Skeleton Skeleton { get { return skeleton; } } 52 | public Bone Parent { get { return parent; } } 53 | public ExposedList Children { get { return children; } } 54 | public float X { get { return x; } set { x = value; } } 55 | public float Y { get { return y; } set { y = value; } } 56 | public float Rotation { get { return rotation; } set { rotation = value; } } 57 | /// The rotation, as calculated by any constraints. 58 | public float AppliedRotation { get { return appliedRotation; } set { appliedRotation = value; } } 59 | public float ScaleX { get { return scaleX; } set { scaleX = value; } } 60 | public float ScaleY { get { return scaleY; } set { scaleY = value; } } 61 | public float ShearX { get { return shearX; } set { shearX = value; } } 62 | public float ShearY { get { return shearY; } set { shearY = value; } } 63 | 64 | public float A { get { return a; } } 65 | public float B { get { return b; } } 66 | public float C { get { return c; } } 67 | public float D { get { return d; } } 68 | public float WorldX { get { return worldX; } } 69 | public float WorldY { get { return worldY; } } 70 | public float WorldSignX { get { return worldSignX; } } 71 | public float WorldSignY { get { return worldSignY; } } 72 | public float WorldRotationX { get { return MathUtils.Atan2(c, a) * MathUtils.radDeg; } } 73 | public float WorldRotationY { get { return MathUtils.Atan2(d, b) * MathUtils.radDeg; } } 74 | public float WorldScaleX { get { return (float)Math.Sqrt(a * a + c * c) * worldSignX; } } 75 | public float WorldScaleY { get { return (float)Math.Sqrt(b * b + d * d) * worldSignY; } } 76 | 77 | /// May be null. 78 | public Bone (BoneData data, Skeleton skeleton, Bone parent) { 79 | if (data == null) throw new ArgumentNullException("data", "data cannot be null."); 80 | if (skeleton == null) throw new ArgumentNullException("skeleton", "skeleton cannot be null."); 81 | this.data = data; 82 | this.skeleton = skeleton; 83 | this.parent = parent; 84 | SetToSetupPose(); 85 | } 86 | 87 | /// Same as . This method exists for Bone to implement . 88 | public void Update () { 89 | UpdateWorldTransform(x, y, rotation, scaleX, scaleY, shearX, shearY); 90 | } 91 | 92 | /// Computes the world transform using the parent bone and this bone's local transform. 93 | public void UpdateWorldTransform () { 94 | UpdateWorldTransform(x, y, rotation, scaleX, scaleY, shearX, shearY); 95 | } 96 | 97 | /// Computes the world transform using the parent bone and the specified local transform. 98 | public void UpdateWorldTransform (float x, float y, float rotation, float scaleX, float scaleY, float shearX, float shearY) { 99 | appliedRotation = rotation; 100 | 101 | float rotationY = rotation + 90 + shearY; 102 | float la = MathUtils.CosDeg(rotation + shearX) * scaleX, lb = MathUtils.CosDeg(rotationY) * scaleY; 103 | float lc = MathUtils.SinDeg(rotation + shearX) * scaleX, ld = MathUtils.SinDeg(rotationY) * scaleY; 104 | 105 | Bone parent = this.parent; 106 | if (parent == null) { // Root bone. 107 | Skeleton skeleton = this.skeleton; 108 | if (skeleton.flipX) { 109 | x = -x; 110 | la = -la; 111 | lb = -lb; 112 | } 113 | if (skeleton.flipY != yDown) { 114 | y = -y; 115 | lc = -lc; 116 | ld = -ld; 117 | } 118 | a = la; 119 | b = lb; 120 | c = lc; 121 | d = ld; 122 | worldX = x; 123 | worldY = y; 124 | worldSignX = Math.Sign(scaleX); 125 | worldSignY = Math.Sign(scaleY); 126 | return; 127 | } 128 | 129 | float pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d; 130 | worldX = pa * x + pb * y + parent.worldX; 131 | worldY = pc * x + pd * y + parent.worldY; 132 | worldSignX = parent.worldSignX * Math.Sign(scaleX); 133 | worldSignY = parent.worldSignY * Math.Sign(scaleY); 134 | 135 | if (data.inheritRotation && data.inheritScale) { 136 | a = pa * la + pb * lc; 137 | b = pa * lb + pb * ld; 138 | c = pc * la + pd * lc; 139 | d = pc * lb + pd * ld; 140 | } else { 141 | if (data.inheritRotation) { // No scale inheritance. 142 | pa = 1; 143 | pb = 0; 144 | pc = 0; 145 | pd = 1; 146 | do { 147 | float cos = MathUtils.CosDeg(parent.appliedRotation), sin = MathUtils.SinDeg(parent.appliedRotation); 148 | float temp = pa * cos + pb * sin; 149 | pb = pb * cos - pa * sin; 150 | pa = temp; 151 | temp = pc * cos + pd * sin; 152 | pd = pd * cos - pc * sin; 153 | pc = temp; 154 | 155 | if (!parent.data.inheritRotation) break; 156 | parent = parent.parent; 157 | } while (parent != null); 158 | a = pa * la + pb * lc; 159 | b = pa * lb + pb * ld; 160 | c = pc * la + pd * lc; 161 | d = pc * lb + pd * ld; 162 | } else if (data.inheritScale) { // No rotation inheritance. 163 | pa = 1; 164 | pb = 0; 165 | pc = 0; 166 | pd = 1; 167 | do { 168 | float cos = MathUtils.CosDeg(parent.appliedRotation), sin = MathUtils.SinDeg(parent.appliedRotation); 169 | float psx = parent.scaleX, psy = parent.scaleY; 170 | float za = cos * psx, zb = sin * psy, zc = sin * psx, zd = cos * psy; 171 | float temp = pa * za + pb * zc; 172 | pb = pb * zd - pa * zb; 173 | pa = temp; 174 | temp = pc * za + pd * zc; 175 | pd = pd * zd - pc * zb; 176 | pc = temp; 177 | 178 | if (psx >= 0) sin = -sin; 179 | temp = pa * cos + pb * sin; 180 | pb = pb * cos - pa * sin; 181 | pa = temp; 182 | temp = pc * cos + pd * sin; 183 | pd = pd * cos - pc * sin; 184 | pc = temp; 185 | 186 | if (!parent.data.inheritScale) break; 187 | parent = parent.parent; 188 | } while (parent != null); 189 | a = pa * la + pb * lc; 190 | b = pa * lb + pb * ld; 191 | c = pc * la + pd * lc; 192 | d = pc * lb + pd * ld; 193 | } else { 194 | a = la; 195 | b = lb; 196 | c = lc; 197 | d = ld; 198 | } 199 | if (skeleton.flipX) { 200 | a = -a; 201 | b = -b; 202 | } 203 | if (skeleton.flipY != yDown) { 204 | c = -c; 205 | d = -d; 206 | } 207 | } 208 | } 209 | 210 | public void SetToSetupPose () { 211 | BoneData data = this.data; 212 | x = data.x; 213 | y = data.y; 214 | rotation = data.rotation; 215 | scaleX = data.scaleX; 216 | scaleY = data.scaleY; 217 | shearX = data.shearX; 218 | shearY = data.shearY; 219 | } 220 | 221 | public float WorldToLocalRotationX { 222 | get { 223 | Bone parent = this.parent; 224 | if (parent == null) return rotation; 225 | float pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d, a = this.a, c = this.c; 226 | return MathUtils.Atan2(pa * c - pc * a, pd * a - pb * c) * MathUtils.radDeg; 227 | } 228 | } 229 | 230 | public float WorldToLocalRotationY { 231 | get { 232 | Bone parent = this.parent; 233 | if (parent == null) return rotation; 234 | float pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d, b = this.b, d = this.d; 235 | return MathUtils.Atan2(pa * d - pc * b, pd * b - pb * d) * MathUtils.radDeg; 236 | } 237 | } 238 | 239 | public void RotateWorld (float degrees) { 240 | float a = this.a, b = this.b, c = this.c, d = this.d; 241 | float cos = MathUtils.CosDeg(degrees), sin = MathUtils.SinDeg(degrees); 242 | this.a = cos * a - sin * c; 243 | this.b = cos * b - sin * d; 244 | this.c = sin * a + cos * c; 245 | this.d = sin * b + cos * d; 246 | } 247 | 248 | /// 249 | /// Computes the local transform from the world transform. This can be useful to perform processing on the local transform 250 | /// after the world transform has been modified directly (eg, by a constraint). 251 | /// 252 | /// Some redundant information is lost by the world transform, such as -1,-1 scale versus 180 rotation. The computed local 253 | /// transform values may differ from the original values but are functionally the same. 254 | /// 255 | public void UpdateLocalTransform () { 256 | Bone parent = this.parent; 257 | if (parent == null) { 258 | x = worldX; 259 | y = worldY; 260 | rotation = MathUtils.Atan2(c, a) * MathUtils.radDeg; 261 | scaleX = (float)Math.Sqrt(a * a + c * c); 262 | scaleY = (float)Math.Sqrt(b * b + d * d); 263 | float det = a * d - b * c; 264 | shearX = 0; 265 | shearY = MathUtils.Atan2(a * b + c * d, det) * MathUtils.radDeg; 266 | return; 267 | } 268 | float pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d; 269 | float pid = 1 / (pa * pd - pb * pc); 270 | float dx = worldX - parent.worldX, dy = worldY - parent.worldY; 271 | x = (dx * pd * pid - dy * pb * pid); 272 | y = (dy * pa * pid - dx * pc * pid); 273 | float ia = pid * pd; 274 | float id = pid * pa; 275 | float ib = pid * pb; 276 | float ic = pid * pc; 277 | float ra = ia * a - ib * c; 278 | float rb = ia * b - ib * d; 279 | float rc = id * c - ic * a; 280 | float rd = id * d - ic * b; 281 | shearX = 0; 282 | scaleX = (float)Math.Sqrt(ra * ra + rc * rc); 283 | if (scaleX > 0.0001f) { 284 | float det = ra * rd - rb * rc; 285 | scaleY = det / scaleX; 286 | shearY = MathUtils.Atan2(ra * rb + rc * rd, det) * MathUtils.radDeg; 287 | rotation = MathUtils.Atan2(rc, ra) * MathUtils.radDeg; 288 | } else { 289 | scaleX = 0; 290 | scaleY = (float)Math.Sqrt(rb * rb + rd * rd); 291 | shearY = 0; 292 | rotation = 90 - MathUtils.Atan2(rd, rb) * MathUtils.radDeg; 293 | } 294 | appliedRotation = rotation; 295 | } 296 | 297 | public void WorldToLocal (float worldX, float worldY, out float localX, out float localY) { 298 | float a = this.a, b = this.b, c = this.c, d = this.d; 299 | float invDet = 1 / (a * d - b * c); 300 | float x = worldX - this.worldX, y = worldY - this.worldY; 301 | localX = (x * d * invDet - y * b * invDet); 302 | localY = (y * a * invDet - x * c * invDet); 303 | } 304 | 305 | public void LocalToWorld (float localX, float localY, out float worldX, out float worldY) { 306 | worldX = localX * a + localY * b + this.worldX; 307 | worldY = localX * c + localY * d + this.worldY; 308 | } 309 | 310 | override public String ToString () { 311 | return data.name; 312 | } 313 | } 314 | } 315 | -------------------------------------------------------------------------------- /spine-csharp/src/BoneData.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License v2.5 3 | * 4 | * Copyright (c) 2013-2016, Esoteric Software 5 | * All rights reserved. 6 | * 7 | * You are granted a perpetual, non-exclusive, non-sublicensable, and 8 | * non-transferable license to use, install, execute, and perform the Spine 9 | * Runtimes software and derivative works solely for personal or internal 10 | * use. Without the written permission of Esoteric Software (see Section 2 of 11 | * the Spine Software License Agreement), you may not (a) modify, translate, 12 | * adapt, or develop new applications using the Spine Runtimes or otherwise 13 | * create derivative works or improvements of the Spine Runtimes or (b) remove, 14 | * delete, alter, or obscure any trademarks or any copyright, trademark, patent, 15 | * or other intellectual property or proprietary rights notices on or in the 16 | * Software, including any copy thereof. Redistributions in binary or source 17 | * form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF 25 | * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 26 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | 33 | namespace Spine { 34 | public class BoneData { 35 | internal int index; 36 | internal String name; 37 | internal BoneData parent; 38 | internal float length; 39 | internal float x, y, rotation, scaleX = 1, scaleY = 1, shearX, shearY; 40 | internal bool inheritRotation = true, inheritScale = true; 41 | 42 | /// May be null. 43 | public int Index { get { return index; } } 44 | public String Name { get { return name; } } 45 | public BoneData Parent { get { return parent; } } 46 | public float Length { get { return length; } set { length = value; } } 47 | public float X { get { return x; } set { x = value; } } 48 | public float Y { get { return y; } set { y = value; } } 49 | public float Rotation { get { return rotation; } set { rotation = value; } } 50 | public float ScaleX { get { return scaleX; } set { scaleX = value; } } 51 | public float ScaleY { get { return scaleY; } set { scaleY = value; } } 52 | public float ShearX { get { return shearX; } set { shearX = value; } } 53 | public float ShearY { get { return shearY; } set { shearY = value; } } 54 | public bool InheritRotation { get { return inheritRotation; } set { inheritRotation = value; } } 55 | public bool InheritScale { get { return inheritScale; } set { inheritScale = value; } } 56 | 57 | /// May be null. 58 | public BoneData (int index, String name, BoneData parent) { 59 | if (index < 0) throw new ArgumentException("index must be >= 0", "index"); 60 | if (name == null) throw new ArgumentNullException("name", "name cannot be null."); 61 | this.index = index; 62 | this.name = name; 63 | this.parent = parent; 64 | } 65 | 66 | override public String ToString () { 67 | return name; 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /spine-csharp/src/Event.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License v2.5 3 | * 4 | * Copyright (c) 2013-2016, Esoteric Software 5 | * All rights reserved. 6 | * 7 | * You are granted a perpetual, non-exclusive, non-sublicensable, and 8 | * non-transferable license to use, install, execute, and perform the Spine 9 | * Runtimes software and derivative works solely for personal or internal 10 | * use. Without the written permission of Esoteric Software (see Section 2 of 11 | * the Spine Software License Agreement), you may not (a) modify, translate, 12 | * adapt, or develop new applications using the Spine Runtimes or otherwise 13 | * create derivative works or improvements of the Spine Runtimes or (b) remove, 14 | * delete, alter, or obscure any trademarks or any copyright, trademark, patent, 15 | * or other intellectual property or proprietary rights notices on or in the 16 | * Software, including any copy thereof. Redistributions in binary or source 17 | * form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF 25 | * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 26 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | 33 | namespace Spine { 34 | public class Event { 35 | public EventData Data { get; private set; } 36 | public int Int { get; set; } 37 | public float Float { get; set; } 38 | public String String { get; set; } 39 | public float Time { get; private set; } 40 | 41 | public Event (float time, EventData data) { 42 | if (data == null) throw new ArgumentNullException("data", "data cannot be null."); 43 | Time = time; 44 | Data = data; 45 | } 46 | 47 | override public String ToString () { 48 | return Data.Name; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /spine-csharp/src/EventData.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License v2.5 3 | * 4 | * Copyright (c) 2013-2016, Esoteric Software 5 | * All rights reserved. 6 | * 7 | * You are granted a perpetual, non-exclusive, non-sublicensable, and 8 | * non-transferable license to use, install, execute, and perform the Spine 9 | * Runtimes software and derivative works solely for personal or internal 10 | * use. Without the written permission of Esoteric Software (see Section 2 of 11 | * the Spine Software License Agreement), you may not (a) modify, translate, 12 | * adapt, or develop new applications using the Spine Runtimes or otherwise 13 | * create derivative works or improvements of the Spine Runtimes or (b) remove, 14 | * delete, alter, or obscure any trademarks or any copyright, trademark, patent, 15 | * or other intellectual property or proprietary rights notices on or in the 16 | * Software, including any copy thereof. Redistributions in binary or source 17 | * form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF 25 | * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 26 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | 33 | namespace Spine { 34 | public class EventData { 35 | internal String name; 36 | 37 | public String Name { get { return name; } } 38 | public int Int { get; set; } 39 | public float Float { get; set; } 40 | public String String { get; set; } 41 | 42 | public EventData (String name) { 43 | if (name == null) throw new ArgumentNullException("name", "name cannot be null."); 44 | this.name = name; 45 | } 46 | 47 | override public String ToString () { 48 | return Name; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /spine-csharp/src/IUpdatable.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License v2.5 3 | * 4 | * Copyright (c) 2013-2016, Esoteric Software 5 | * All rights reserved. 6 | * 7 | * You are granted a perpetual, non-exclusive, non-sublicensable, and 8 | * non-transferable license to use, install, execute, and perform the Spine 9 | * Runtimes software and derivative works solely for personal or internal 10 | * use. Without the written permission of Esoteric Software (see Section 2 of 11 | * the Spine Software License Agreement), you may not (a) modify, translate, 12 | * adapt, or develop new applications using the Spine Runtimes or otherwise 13 | * create derivative works or improvements of the Spine Runtimes or (b) remove, 14 | * delete, alter, or obscure any trademarks or any copyright, trademark, patent, 15 | * or other intellectual property or proprietary rights notices on or in the 16 | * Software, including any copy thereof. Redistributions in binary or source 17 | * form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF 25 | * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 26 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | 33 | namespace Spine { 34 | public interface IUpdatable { 35 | void Update (); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /spine-csharp/src/IkConstraint.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License v2.5 3 | * 4 | * Copyright (c) 2013-2016, Esoteric Software 5 | * All rights reserved. 6 | * 7 | * You are granted a perpetual, non-exclusive, non-sublicensable, and 8 | * non-transferable license to use, install, execute, and perform the Spine 9 | * Runtimes software and derivative works solely for personal or internal 10 | * use. Without the written permission of Esoteric Software (see Section 2 of 11 | * the Spine Software License Agreement), you may not (a) modify, translate, 12 | * adapt, or develop new applications using the Spine Runtimes or otherwise 13 | * create derivative works or improvements of the Spine Runtimes or (b) remove, 14 | * delete, alter, or obscure any trademarks or any copyright, trademark, patent, 15 | * or other intellectual property or proprietary rights notices on or in the 16 | * Software, including any copy thereof. Redistributions in binary or source 17 | * form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF 25 | * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 26 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | 33 | namespace Spine { 34 | public class IkConstraint : IUpdatable { 35 | internal IkConstraintData data; 36 | internal ExposedList bones = new ExposedList(); 37 | internal Bone target; 38 | internal float mix; 39 | internal int bendDirection; 40 | 41 | internal int level; 42 | 43 | public IkConstraintData Data { get { return data; } } 44 | public ExposedList Bones { get { return bones; } } 45 | public Bone Target { get { return target; } set { target = value; } } 46 | public int BendDirection { get { return bendDirection; } set { bendDirection = value; } } 47 | public float Mix { get { return mix; } set { mix = value; } } 48 | 49 | public IkConstraint (IkConstraintData data, Skeleton skeleton) { 50 | if (data == null) throw new ArgumentNullException("data", "data cannot be null."); 51 | if (skeleton == null) throw new ArgumentNullException("skeleton", "skeleton cannot be null."); 52 | this.data = data; 53 | mix = data.mix; 54 | bendDirection = data.bendDirection; 55 | 56 | bones = new ExposedList(data.bones.Count); 57 | foreach (BoneData boneData in data.bones) 58 | bones.Add(skeleton.FindBone(boneData.name)); 59 | target = skeleton.FindBone(data.target.name); 60 | } 61 | 62 | public void Update () { 63 | Apply(); 64 | } 65 | 66 | public void Apply () { 67 | Bone target = this.target; 68 | ExposedList bones = this.bones; 69 | switch (bones.Count) { 70 | case 1: 71 | Apply(bones.Items[0], target.worldX, target.worldY, mix); 72 | break; 73 | case 2: 74 | Apply(bones.Items[0], bones.Items[1], target.worldX, target.worldY, bendDirection, mix); 75 | break; 76 | } 77 | } 78 | 79 | override public String ToString () { 80 | return data.name; 81 | } 82 | 83 | /// Adjusts the bone rotation so the tip is as close to the target position as possible. The target is specified 84 | /// in the world coordinate system. 85 | static public void Apply (Bone bone, float targetX, float targetY, float alpha) { 86 | Bone pp = bone.parent; 87 | float id = 1 / (pp.a * pp.d - pp.b * pp.c); 88 | float x = targetX - pp.worldX, y = targetY - pp.worldY; 89 | float tx = (x * pp.d - y * pp.b) * id - bone.x, ty = (y * pp.a - x * pp.c) * id - bone.y; 90 | float rotationIK = MathUtils.Atan2(ty, tx) * MathUtils.radDeg - bone.shearX - bone.rotation; 91 | if (bone.scaleX < 0) rotationIK += 180; 92 | if (rotationIK > 180) 93 | rotationIK -= 360; 94 | else if (rotationIK < -180) rotationIK += 360; 95 | bone.UpdateWorldTransform(bone.x, bone.y, bone.rotation + rotationIK * alpha, bone.scaleX, bone.scaleY, 96 | bone.shearX, bone.shearY); 97 | } 98 | 99 | /// Adjusts the parent and child bone rotations so the tip of the child is as close to the target position as 100 | /// possible. The target is specified in the world coordinate system. 101 | /// A direct descendant of the parent bone. 102 | static public void Apply (Bone parent, Bone child, float targetX, float targetY, int bendDir, float alpha) { 103 | if (alpha == 0) { 104 | child.UpdateWorldTransform (); 105 | return; 106 | } 107 | float px = parent.x, py = parent.y, psx = parent.scaleX, psy = parent.scaleY, csx = child.scaleX; 108 | int os1, os2, s2; 109 | if (psx < 0) { 110 | psx = -psx; 111 | os1 = 180; 112 | s2 = -1; 113 | } else { 114 | os1 = 0; 115 | s2 = 1; 116 | } 117 | if (psy < 0) { 118 | psy = -psy; 119 | s2 = -s2; 120 | } 121 | if (csx < 0) { 122 | csx = -csx; 123 | os2 = 180; 124 | } else 125 | os2 = 0; 126 | float cx = child.x, cy, cwx, cwy, a = parent.a, b = parent.b, c = parent.c, d = parent.d; 127 | bool u = Math.Abs(psx - psy) <= 0.0001f; 128 | if (!u) { 129 | cy = 0; 130 | cwx = a * cx + parent.worldX; 131 | cwy = c * cx + parent.worldY; 132 | } else { 133 | cy = child.y; 134 | cwx = a * cx + b * cy + parent.worldX; 135 | cwy = c * cx + d * cy + parent.worldY; 136 | } 137 | Bone pp = parent.parent; 138 | a = pp.a; 139 | b = pp.b; 140 | c = pp.c; 141 | d = pp.d; 142 | float id = 1 / (a * d - b * c), x = targetX - pp.worldX, y = targetY - pp.worldY; 143 | float tx = (x * d - y * b) * id - px, ty = (y * a - x * c) * id - py; 144 | x = cwx - pp.worldX; 145 | y = cwy - pp.worldY; 146 | float dx = (x * d - y * b) * id - px, dy = (y * a - x * c) * id - py; 147 | float l1 = (float)Math.Sqrt(dx * dx + dy * dy), l2 = child.data.length * csx, a1, a2; 148 | if (u) { 149 | l2 *= psx; 150 | float cos = (tx * tx + ty * ty - l1 * l1 - l2 * l2) / (2 * l1 * l2); 151 | if (cos < -1) 152 | cos = -1; 153 | else if (cos > 1) cos = 1; 154 | a2 = (float)Math.Acos(cos) * bendDir; 155 | a = l1 + l2 * cos; 156 | b = l2 * MathUtils.Sin(a2); 157 | a1 = MathUtils.Atan2(ty * a - tx * b, tx * a + ty * b); 158 | } else { 159 | a = psx * l2; 160 | b = psy * l2; 161 | float aa = a * a, bb = b * b, dd = tx * tx + ty * ty, ta = MathUtils.Atan2(ty, tx); 162 | c = bb * l1 * l1 + aa * dd - aa * bb; 163 | float c1 = -2 * bb * l1, c2 = bb - aa; 164 | d = c1 * c1 - 4 * c2 * c; 165 | if (d >= 0) { 166 | float q = (float)Math.Sqrt(d); 167 | if (c1 < 0) q = -q; 168 | q = -(c1 + q) / 2; 169 | float r0 = q / c2, r1 = c / q; 170 | float r = Math.Abs(r0) < Math.Abs(r1) ? r0 : r1; 171 | if (r * r <= dd) { 172 | y = (float)Math.Sqrt(dd - r * r) * bendDir; 173 | a1 = ta - MathUtils.Atan2(y, r); 174 | a2 = MathUtils.Atan2(y / psy, (r - l1) / psx); 175 | goto outer; 176 | } 177 | } 178 | float minAngle = 0, minDist = float.MaxValue, minX = 0, minY = 0; 179 | float maxAngle = 0, maxDist = 0, maxX = 0, maxY = 0; 180 | x = l1 + a; 181 | d = x * x; 182 | if (d > maxDist) { 183 | maxAngle = 0; 184 | maxDist = d; 185 | maxX = x; 186 | } 187 | x = l1 - a; 188 | d = x * x; 189 | if (d < minDist) { 190 | minAngle = MathUtils.PI; 191 | minDist = d; 192 | minX = x; 193 | } 194 | float angle = (float)Math.Acos(-a * l1 / (aa - bb)); 195 | x = a * MathUtils.Cos(angle) + l1; 196 | y = b * MathUtils.Sin(angle); 197 | d = x * x + y * y; 198 | if (d < minDist) { 199 | minAngle = angle; 200 | minDist = d; 201 | minX = x; 202 | minY = y; 203 | } 204 | if (d > maxDist) { 205 | maxAngle = angle; 206 | maxDist = d; 207 | maxX = x; 208 | maxY = y; 209 | } 210 | if (dd <= (minDist + maxDist) / 2) { 211 | a1 = ta - MathUtils.Atan2(minY * bendDir, minX); 212 | a2 = minAngle * bendDir; 213 | } else { 214 | a1 = ta - MathUtils.Atan2(maxY * bendDir, maxX); 215 | a2 = maxAngle * bendDir; 216 | } 217 | } 218 | outer: 219 | float os = MathUtils.Atan2(cy, cx) * s2; 220 | float rotation = parent.rotation; 221 | a1 = (a1 - os) * MathUtils.radDeg + os1 - rotation; 222 | if (a1 > 180) 223 | a1 -= 360; 224 | else if (a1 < -180) a1 += 360; 225 | parent.UpdateWorldTransform(px, py, rotation + a1 * alpha, parent.scaleX, parent.scaleY, 0, 0); 226 | rotation = child.rotation; 227 | a2 = ((a2 + os) * MathUtils.radDeg - child.shearX) * s2 + os2 - rotation; 228 | if (a2 > 180) 229 | a2 -= 360; 230 | else if (a2 < -180) a2 += 360; 231 | child.UpdateWorldTransform(cx, cy, rotation + a2 * alpha, child.scaleX, child.scaleY, child.shearX, child.shearY); 232 | } 233 | } 234 | } 235 | -------------------------------------------------------------------------------- /spine-csharp/src/IkConstraintData.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License v2.5 3 | * 4 | * Copyright (c) 2013-2016, Esoteric Software 5 | * All rights reserved. 6 | * 7 | * You are granted a perpetual, non-exclusive, non-sublicensable, and 8 | * non-transferable license to use, install, execute, and perform the Spine 9 | * Runtimes software and derivative works solely for personal or internal 10 | * use. Without the written permission of Esoteric Software (see Section 2 of 11 | * the Spine Software License Agreement), you may not (a) modify, translate, 12 | * adapt, or develop new applications using the Spine Runtimes or otherwise 13 | * create derivative works or improvements of the Spine Runtimes or (b) remove, 14 | * delete, alter, or obscure any trademarks or any copyright, trademark, patent, 15 | * or other intellectual property or proprietary rights notices on or in the 16 | * Software, including any copy thereof. Redistributions in binary or source 17 | * form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF 25 | * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 26 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | using System.Collections.Generic; 33 | 34 | namespace Spine { 35 | public class IkConstraintData { 36 | internal String name; 37 | internal List bones = new List(); 38 | internal BoneData target; 39 | internal int bendDirection = 1; 40 | internal float mix = 1; 41 | 42 | public String Name { get { return name; } } 43 | public List Bones { get { return bones; } } 44 | public BoneData Target { get { return target; } set { target = value; } } 45 | public int BendDirection { get { return bendDirection; } set { bendDirection = value; } } 46 | public float Mix { get { return mix; } set { mix = value; } } 47 | 48 | public IkConstraintData (String name) { 49 | if (name == null) throw new ArgumentNullException("name", "name cannot be null."); 50 | this.name = name; 51 | } 52 | 53 | override public String ToString () { 54 | return name; 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /spine-csharp/src/Json.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License v2.5 3 | * 4 | * Copyright (c) 2013-2016, Esoteric Software 5 | * All rights reserved. 6 | * 7 | * You are granted a perpetual, non-exclusive, non-sublicensable, and 8 | * non-transferable license to use, install, execute, and perform the Spine 9 | * Runtimes software and derivative works solely for personal or internal 10 | * use. Without the written permission of Esoteric Software (see Section 2 of 11 | * the Spine Software License Agreement), you may not (a) modify, translate, 12 | * adapt, or develop new applications using the Spine Runtimes or otherwise 13 | * create derivative works or improvements of the Spine Runtimes or (b) remove, 14 | * delete, alter, or obscure any trademarks or any copyright, trademark, patent, 15 | * or other intellectual property or proprietary rights notices on or in the 16 | * Software, including any copy thereof. Redistributions in binary or source 17 | * form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF 25 | * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 26 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | using System.IO; 33 | using System.Text; 34 | using System.Collections; 35 | using System.Globalization; 36 | using System.Collections.Generic; 37 | 38 | namespace Spine { 39 | public static class Json { 40 | public static object Deserialize (TextReader text) { 41 | var parser = new SharpJson.JsonDecoder(); 42 | parser.parseNumbersAsFloat = true; 43 | return parser.Decode(text.ReadToEnd()); 44 | } 45 | } 46 | } 47 | 48 | /** 49 | * 50 | * Copyright (c) 2016 Adriano Tinoco d'Oliveira Rezende 51 | * 52 | * Based on the JSON parser by Patrick van Bergen 53 | * http://techblog.procurios.nl/k/news/view/14605/14863/how-do-i-write-my-own-parser-(for-json).html 54 | * 55 | * Changes made: 56 | * 57 | * - Optimized parser speed (deserialize roughly near 3x faster than original) 58 | * - Added support to handle lexer/parser error messages with line numbers 59 | * - Added more fine grained control over type conversions during the parsing 60 | * - Refactory API (Separate Lexer code from Parser code and the Encoder from Decoder) 61 | * 62 | * 63 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 64 | * and associated documentation files (the "Software"), to deal in the Software without restriction, 65 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 66 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 67 | * subject to the following conditions: 68 | * The above copyright notice and this permission notice shall be included in all copies or substantial 69 | * portions of the Software. 70 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 71 | * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 72 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 73 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 74 | * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 75 | * 76 | */ 77 | namespace SharpJson 78 | { 79 | class Lexer 80 | { 81 | public enum Token { 82 | None, 83 | Null, 84 | True, 85 | False, 86 | Colon, 87 | Comma, 88 | String, 89 | Number, 90 | CurlyOpen, 91 | CurlyClose, 92 | SquaredOpen, 93 | SquaredClose, 94 | }; 95 | 96 | public bool hasError { 97 | get { 98 | return !success; 99 | } 100 | } 101 | 102 | public int lineNumber { 103 | get; 104 | private set; 105 | } 106 | 107 | public bool parseNumbersAsFloat { 108 | get; 109 | set; 110 | } 111 | 112 | char[] json; 113 | int index = 0; 114 | bool success = true; 115 | char[] stringBuffer = new char[4096]; 116 | 117 | public Lexer(string text) 118 | { 119 | Reset(); 120 | 121 | json = text.ToCharArray(); 122 | parseNumbersAsFloat = false; 123 | } 124 | 125 | public void Reset() 126 | { 127 | index = 0; 128 | lineNumber = 1; 129 | success = true; 130 | } 131 | 132 | public string ParseString() 133 | { 134 | int idx = 0; 135 | StringBuilder builder = null; 136 | 137 | SkipWhiteSpaces(); 138 | 139 | // " 140 | char c = json[index++]; 141 | 142 | bool failed = false; 143 | bool complete = false; 144 | 145 | while (!complete && !failed) { 146 | if (index == json.Length) 147 | break; 148 | 149 | c = json[index++]; 150 | if (c == '"') { 151 | complete = true; 152 | break; 153 | } else if (c == '\\') { 154 | if (index == json.Length) 155 | break; 156 | 157 | c = json[index++]; 158 | 159 | switch (c) { 160 | case '"': 161 | stringBuffer[idx++] = '"'; 162 | break; 163 | case '\\': 164 | stringBuffer[idx++] = '\\'; 165 | break; 166 | case '/': 167 | stringBuffer[idx++] = '/'; 168 | break; 169 | case 'b': 170 | stringBuffer[idx++] = '\b'; 171 | break; 172 | case'f': 173 | stringBuffer[idx++] = '\f'; 174 | break; 175 | case 'n': 176 | stringBuffer[idx++] = '\n'; 177 | break; 178 | case 'r': 179 | stringBuffer[idx++] = '\r'; 180 | break; 181 | case 't': 182 | stringBuffer[idx++] = '\t'; 183 | break; 184 | case 'u': 185 | int remainingLength = json.Length - index; 186 | if (remainingLength >= 4) { 187 | var hex = new string(json, index, 4); 188 | 189 | // XXX: handle UTF 190 | stringBuffer[idx++] = (char) Convert.ToInt32(hex, 16); 191 | 192 | // skip 4 chars 193 | index += 4; 194 | } else { 195 | failed = true; 196 | } 197 | break; 198 | } 199 | } else { 200 | stringBuffer[idx++] = c; 201 | } 202 | 203 | if (idx >= stringBuffer.Length) { 204 | if (builder == null) 205 | builder = new StringBuilder(); 206 | 207 | builder.Append(stringBuffer, 0, idx); 208 | idx = 0; 209 | } 210 | } 211 | 212 | if (!complete) { 213 | success = false; 214 | return null; 215 | } 216 | 217 | if (builder != null) 218 | return builder.ToString (); 219 | else 220 | return new string (stringBuffer, 0, idx); 221 | } 222 | 223 | string GetNumberString() 224 | { 225 | SkipWhiteSpaces(); 226 | 227 | int lastIndex = GetLastIndexOfNumber(index); 228 | int charLength = (lastIndex - index) + 1; 229 | 230 | var result = new string (json, index, charLength); 231 | 232 | index = lastIndex + 1; 233 | 234 | return result; 235 | } 236 | 237 | public float ParseFloatNumber() 238 | { 239 | float number; 240 | var str = GetNumberString (); 241 | 242 | if (!float.TryParse (str, NumberStyles.Float, CultureInfo.InvariantCulture, out number)) 243 | return 0; 244 | 245 | return number; 246 | } 247 | 248 | public double ParseDoubleNumber() 249 | { 250 | double number; 251 | var str = GetNumberString (); 252 | 253 | if (!double.TryParse(str, NumberStyles.Any, CultureInfo.InvariantCulture, out number)) 254 | return 0; 255 | 256 | return number; 257 | } 258 | 259 | int GetLastIndexOfNumber(int index) 260 | { 261 | int lastIndex; 262 | 263 | for (lastIndex = index; lastIndex < json.Length; lastIndex++) { 264 | char ch = json[lastIndex]; 265 | 266 | if ((ch < '0' || ch > '9') && ch != '+' && ch != '-' 267 | && ch != '.' && ch != 'e' && ch != 'E') 268 | break; 269 | } 270 | 271 | return lastIndex - 1; 272 | } 273 | 274 | void SkipWhiteSpaces() 275 | { 276 | for (; index < json.Length; index++) { 277 | char ch = json[index]; 278 | 279 | if (ch == '\n') 280 | lineNumber++; 281 | 282 | if (!char.IsWhiteSpace(json[index])) 283 | break; 284 | } 285 | } 286 | 287 | public Token LookAhead() 288 | { 289 | SkipWhiteSpaces(); 290 | 291 | int savedIndex = index; 292 | return NextToken(json, ref savedIndex); 293 | } 294 | 295 | public Token NextToken() 296 | { 297 | SkipWhiteSpaces(); 298 | return NextToken(json, ref index); 299 | } 300 | 301 | static Token NextToken(char[] json, ref int index) 302 | { 303 | if (index == json.Length) 304 | return Token.None; 305 | 306 | char c = json[index++]; 307 | 308 | switch (c) { 309 | case '{': 310 | return Token.CurlyOpen; 311 | case '}': 312 | return Token.CurlyClose; 313 | case '[': 314 | return Token.SquaredOpen; 315 | case ']': 316 | return Token.SquaredClose; 317 | case ',': 318 | return Token.Comma; 319 | case '"': 320 | return Token.String; 321 | case '0': case '1': case '2': case '3': case '4': 322 | case '5': case '6': case '7': case '8': case '9': 323 | case '-': 324 | return Token.Number; 325 | case ':': 326 | return Token.Colon; 327 | } 328 | 329 | index--; 330 | 331 | int remainingLength = json.Length - index; 332 | 333 | // false 334 | if (remainingLength >= 5) { 335 | if (json[index] == 'f' && 336 | json[index + 1] == 'a' && 337 | json[index + 2] == 'l' && 338 | json[index + 3] == 's' && 339 | json[index + 4] == 'e') { 340 | index += 5; 341 | return Token.False; 342 | } 343 | } 344 | 345 | // true 346 | if (remainingLength >= 4) { 347 | if (json[index] == 't' && 348 | json[index + 1] == 'r' && 349 | json[index + 2] == 'u' && 350 | json[index + 3] == 'e') { 351 | index += 4; 352 | return Token.True; 353 | } 354 | } 355 | 356 | // null 357 | if (remainingLength >= 4) { 358 | if (json[index] == 'n' && 359 | json[index + 1] == 'u' && 360 | json[index + 2] == 'l' && 361 | json[index + 3] == 'l') { 362 | index += 4; 363 | return Token.Null; 364 | } 365 | } 366 | 367 | return Token.None; 368 | } 369 | } 370 | 371 | public class JsonDecoder 372 | { 373 | public string errorMessage { 374 | get; 375 | private set; 376 | } 377 | 378 | public bool parseNumbersAsFloat { 379 | get; 380 | set; 381 | } 382 | 383 | Lexer lexer; 384 | 385 | public JsonDecoder() 386 | { 387 | errorMessage = null; 388 | parseNumbersAsFloat = false; 389 | } 390 | 391 | public object Decode(string text) 392 | { 393 | errorMessage = null; 394 | 395 | lexer = new Lexer(text); 396 | lexer.parseNumbersAsFloat = parseNumbersAsFloat; 397 | 398 | return ParseValue(); 399 | } 400 | 401 | public static object DecodeText(string text) 402 | { 403 | var builder = new JsonDecoder(); 404 | return builder.Decode(text); 405 | } 406 | 407 | IDictionary ParseObject() 408 | { 409 | var table = new Dictionary(); 410 | 411 | // { 412 | lexer.NextToken(); 413 | 414 | while (true) { 415 | var token = lexer.LookAhead(); 416 | 417 | switch (token) { 418 | case Lexer.Token.None: 419 | TriggerError("Invalid token"); 420 | return null; 421 | case Lexer.Token.Comma: 422 | lexer.NextToken(); 423 | break; 424 | case Lexer.Token.CurlyClose: 425 | lexer.NextToken(); 426 | return table; 427 | default: 428 | // name 429 | string name = EvalLexer(lexer.ParseString()); 430 | 431 | if (errorMessage != null) 432 | return null; 433 | 434 | // : 435 | token = lexer.NextToken(); 436 | 437 | if (token != Lexer.Token.Colon) { 438 | TriggerError("Invalid token; expected ':'"); 439 | return null; 440 | } 441 | 442 | // value 443 | object value = ParseValue(); 444 | 445 | if (errorMessage != null) 446 | return null; 447 | 448 | table[name] = value; 449 | break; 450 | } 451 | } 452 | 453 | //return null; // Unreachable code 454 | } 455 | 456 | IList ParseArray() 457 | { 458 | var array = new List(); 459 | 460 | // [ 461 | lexer.NextToken(); 462 | 463 | while (true) { 464 | var token = lexer.LookAhead(); 465 | 466 | switch (token) { 467 | case Lexer.Token.None: 468 | TriggerError("Invalid token"); 469 | return null; 470 | case Lexer.Token.Comma: 471 | lexer.NextToken(); 472 | break; 473 | case Lexer.Token.SquaredClose: 474 | lexer.NextToken(); 475 | return array; 476 | default: 477 | object value = ParseValue(); 478 | 479 | if (errorMessage != null) 480 | return null; 481 | 482 | array.Add(value); 483 | break; 484 | } 485 | } 486 | 487 | //return null; // Unreachable code 488 | } 489 | 490 | object ParseValue() 491 | { 492 | switch (lexer.LookAhead()) { 493 | case Lexer.Token.String: 494 | return EvalLexer(lexer.ParseString()); 495 | case Lexer.Token.Number: 496 | if (parseNumbersAsFloat) 497 | return EvalLexer(lexer.ParseFloatNumber()); 498 | else 499 | return EvalLexer(lexer.ParseDoubleNumber()); 500 | case Lexer.Token.CurlyOpen: 501 | return ParseObject(); 502 | case Lexer.Token.SquaredOpen: 503 | return ParseArray(); 504 | case Lexer.Token.True: 505 | lexer.NextToken(); 506 | return true; 507 | case Lexer.Token.False: 508 | lexer.NextToken(); 509 | return false; 510 | case Lexer.Token.Null: 511 | lexer.NextToken(); 512 | return null; 513 | case Lexer.Token.None: 514 | break; 515 | } 516 | 517 | TriggerError("Unable to parse value"); 518 | return null; 519 | } 520 | 521 | void TriggerError(string message) 522 | { 523 | errorMessage = string.Format("Error: '{0}' at line {1}", 524 | message, lexer.lineNumber); 525 | } 526 | 527 | T EvalLexer(T value) 528 | { 529 | if (lexer.hasError) 530 | TriggerError("Lexical error ocurred"); 531 | 532 | return value; 533 | } 534 | } 535 | } 536 | -------------------------------------------------------------------------------- /spine-csharp/src/MathUtils.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License v2.5 3 | * 4 | * Copyright (c) 2013-2016, Esoteric Software 5 | * All rights reserved. 6 | * 7 | * You are granted a perpetual, non-exclusive, non-sublicensable, and 8 | * non-transferable license to use, install, execute, and perform the Spine 9 | * Runtimes software and derivative works solely for personal or internal 10 | * use. Without the written permission of Esoteric Software (see Section 2 of 11 | * the Spine Software License Agreement), you may not (a) modify, translate, 12 | * adapt, or develop new applications using the Spine Runtimes or otherwise 13 | * create derivative works or improvements of the Spine Runtimes or (b) remove, 14 | * delete, alter, or obscure any trademarks or any copyright, trademark, patent, 15 | * or other intellectual property or proprietary rights notices on or in the 16 | * Software, including any copy thereof. Redistributions in binary or source 17 | * form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF 25 | * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 26 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | 33 | namespace Spine { 34 | public static class MathUtils { 35 | public const float PI = 3.1415927f; 36 | public const float PI2 = PI * 2; 37 | public const float radDeg = 180f / PI; 38 | public const float degRad = PI / 180; 39 | 40 | const int SIN_BITS = 14; // 16KB. Adjust for accuracy. 41 | const int SIN_MASK = ~(-1 << SIN_BITS); 42 | const int SIN_COUNT = SIN_MASK + 1; 43 | const float radFull = PI * 2; 44 | const float degFull = 360; 45 | const float radToIndex = SIN_COUNT / radFull; 46 | const float degToIndex = SIN_COUNT / degFull; 47 | static float[] sin = new float[SIN_COUNT]; 48 | 49 | static MathUtils () { 50 | for (int i = 0; i < SIN_COUNT; i++) 51 | sin[i] = (float)Math.Sin((i + 0.5f) / SIN_COUNT * radFull); 52 | for (int i = 0; i < 360; i += 90) 53 | sin[(int)(i * degToIndex) & SIN_MASK] = (float)Math.Sin(i * degRad); 54 | } 55 | 56 | /// Returns the sine in radians from a lookup table. 57 | static public float Sin (float radians) { 58 | return sin[(int)(radians * radToIndex) & SIN_MASK]; 59 | } 60 | 61 | /// Returns the cosine in radians from a lookup table. 62 | static public float Cos (float radians) { 63 | return sin[(int)((radians + PI / 2) * radToIndex) & SIN_MASK]; 64 | } 65 | 66 | /// Returns the sine in radians from a lookup table. 67 | static public float SinDeg (float degrees) { 68 | return sin[(int)(degrees * degToIndex) & SIN_MASK]; 69 | } 70 | 71 | /// Returns the cosine in radians from a lookup table. 72 | static public float CosDeg (float degrees) { 73 | return sin[(int)((degrees + 90) * degToIndex) & SIN_MASK]; 74 | } 75 | 76 | /// Returns atan2 in radians, faster but less accurate than Math.Atan2. Average error of 0.00231 radians (0.1323 77 | /// degrees), largest error of 0.00488 radians (0.2796 degrees). 78 | static public float Atan2 (float y, float x) { 79 | if (x == 0f) { 80 | if (y > 0f) return PI / 2; 81 | if (y == 0f) return 0f; 82 | return -PI / 2; 83 | } 84 | float atan, z = y / x; 85 | if (Math.Abs(z) < 1f) { 86 | atan = z / (1f + 0.28f * z * z); 87 | if (x < 0f) return atan + (y < 0f ? -PI : PI); 88 | return atan; 89 | } 90 | atan = PI / 2 - z / (z * z + 0.28f); 91 | return y < 0f ? atan - PI : atan; 92 | } 93 | 94 | static public float Clamp (float value, float min, float max) { 95 | if (value < min) return min; 96 | if (value > max) return max; 97 | return value; 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /spine-csharp/src/PathConstraint.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License v2.5 3 | * 4 | * Copyright (c) 2013-2016, Esoteric Software 5 | * All rights reserved. 6 | * 7 | * You are granted a perpetual, non-exclusive, non-sublicensable, and 8 | * non-transferable license to use, install, execute, and perform the Spine 9 | * Runtimes software and derivative works solely for personal or internal 10 | * use. Without the written permission of Esoteric Software (see Section 2 of 11 | * the Spine Software License Agreement), you may not (a) modify, translate, 12 | * adapt, or develop new applications using the Spine Runtimes or otherwise 13 | * create derivative works or improvements of the Spine Runtimes or (b) remove, 14 | * delete, alter, or obscure any trademarks or any copyright, trademark, patent, 15 | * or other intellectual property or proprietary rights notices on or in the 16 | * Software, including any copy thereof. Redistributions in binary or source 17 | * form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF 25 | * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 26 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | 33 | namespace Spine { 34 | public class PathConstraint : IUpdatable { 35 | private const int NONE = -1, BEFORE = -2, AFTER = -3; 36 | 37 | internal PathConstraintData data; 38 | internal ExposedList bones; 39 | internal Slot target; 40 | internal float position, spacing, rotateMix, translateMix; 41 | 42 | internal ExposedList spaces = new ExposedList(), positions = new ExposedList(); 43 | internal ExposedList world = new ExposedList(), curves = new ExposedList(), lengths = new ExposedList(); 44 | internal float[] segments = new float[10]; 45 | 46 | public float Position { get { return position; } set { position = value; } } 47 | public float Spacing { get { return spacing; } set { spacing = value; } } 48 | public float RotateMix { get { return rotateMix; } set { rotateMix = value; } } 49 | public float TranslateMix { get { return translateMix; } set { translateMix = value; } } 50 | public ExposedList Bones { get { return bones; } } 51 | public Slot Target { get { return target; } set { target = value; } } 52 | public PathConstraintData Data { get { return data; } } 53 | 54 | public PathConstraint (PathConstraintData data, Skeleton skeleton) { 55 | if (data == null) throw new ArgumentNullException("data", "data cannot be null."); 56 | if (skeleton == null) throw new ArgumentNullException("skeleton", "skeleton cannot be null."); 57 | this.data = data; 58 | bones = new ExposedList(data.Bones.Count); 59 | foreach (BoneData boneData in data.bones) 60 | bones.Add(skeleton.FindBone(boneData.name)); 61 | target = skeleton.FindSlot(data.target.name); 62 | position = data.position; 63 | spacing = data.spacing; 64 | rotateMix = data.rotateMix; 65 | translateMix = data.translateMix; 66 | } 67 | 68 | public void Apply () { 69 | Update(); 70 | } 71 | 72 | public void Update () { 73 | PathAttachment attachment = target.Attachment as PathAttachment; 74 | if (attachment == null) return; 75 | 76 | float rotateMix = this.rotateMix, translateMix = this.translateMix; 77 | bool translate = translateMix > 0, rotate = rotateMix > 0; 78 | if (!translate && !rotate) return; 79 | 80 | PathConstraintData data = this.data; 81 | SpacingMode spacingMode = data.spacingMode; 82 | bool lengthSpacing = spacingMode == SpacingMode.Length; 83 | RotateMode rotateMode = data.rotateMode; 84 | bool tangents = rotateMode == RotateMode.Tangent, scale = rotateMode == RotateMode.ChainScale; 85 | int boneCount = this.bones.Count, spacesCount = tangents ? boneCount : boneCount + 1; 86 | Bone[] bones = this.bones.Items; 87 | ExposedList spaces = this.spaces.Resize(spacesCount), lengths = null; 88 | float spacing = this.spacing; 89 | if (scale || lengthSpacing) { 90 | if (scale) lengths = this.lengths.Resize(boneCount); 91 | for (int i = 0, n = spacesCount - 1; i < n;) { 92 | Bone bone = bones[i]; 93 | float length = bone.data.length, x = length * bone.a, y = length * bone.c; 94 | length = (float)Math.Sqrt(x * x + y * y); 95 | if (scale) lengths.Items[i] = length; 96 | spaces.Items[++i] = lengthSpacing ? Math.Max(0, length + spacing) : spacing; 97 | } 98 | } else { 99 | for (int i = 1; i < spacesCount; i++) 100 | spaces.Items[i] = spacing; 101 | } 102 | 103 | float[] positions = ComputeWorldPositions(attachment, spacesCount, tangents, 104 | data.positionMode == PositionMode.Percent, spacingMode == SpacingMode.Percent); 105 | Skeleton skeleton = target.Skeleton; 106 | float skeletonX = skeleton.x, skeletonY = skeleton.y; 107 | float boneX = positions[0], boneY = positions[1], offsetRotation = data.offsetRotation; 108 | bool tip = rotateMode == RotateMode.Chain && offsetRotation == 0; 109 | for (int i = 0, p = 3; i < boneCount; i++, p += 3) { 110 | Bone bone = (Bone)bones[i]; 111 | bone.worldX += (boneX - skeletonX - bone.worldX) * translateMix; 112 | bone.worldY += (boneY - skeletonY - bone.worldY) * translateMix; 113 | float x = positions[p], y = positions[p + 1], dx = x - boneX, dy = y - boneY; 114 | if (scale) { 115 | float length = lengths.Items[i]; 116 | if (length != 0) { 117 | float s = ((float)Math.Sqrt(dx * dx + dy * dy) / length - 1) * rotateMix + 1; 118 | bone.a *= s; 119 | bone.c *= s; 120 | } 121 | } 122 | boneX = x; 123 | boneY = y; 124 | if (rotate) { 125 | float a = bone.a, b = bone.b, c = bone.c, d = bone.d, r, cos, sin; 126 | if (tangents) 127 | r = positions[p - 1]; 128 | else if (spaces.Items[i + 1] == 0) 129 | r = positions[p + 2]; 130 | else 131 | r = MathUtils.Atan2(dy, dx); 132 | r -= MathUtils.Atan2(c, a) - offsetRotation * MathUtils.degRad; 133 | if (tip) { 134 | cos = MathUtils.Cos(r); 135 | sin = MathUtils.Sin(r); 136 | float length = bone.data.length; 137 | boneX += (length * (cos * a - sin * c) - dx) * rotateMix; 138 | boneY += (length * (sin * a + cos * c) - dy) * rotateMix; 139 | } 140 | if (r > MathUtils.PI) 141 | r -= MathUtils.PI2; 142 | else if (r < -MathUtils.PI) // 143 | r += MathUtils.PI2; 144 | r *= rotateMix; 145 | cos = MathUtils.Cos(r); 146 | sin = MathUtils.Sin(r); 147 | bone.a = cos * a - sin * c; 148 | bone.b = cos * b - sin * d; 149 | bone.c = sin * a + cos * c; 150 | bone.d = sin * b + cos * d; 151 | } 152 | } 153 | } 154 | 155 | float[] ComputeWorldPositions (PathAttachment path, int spacesCount, bool tangents, bool percentPosition, 156 | bool percentSpacing) { 157 | 158 | Slot target = this.target; 159 | float position = this.position; 160 | float[] spaces = this.spaces.Items, output = this.positions.Resize(spacesCount * 3 + 2).Items, world; 161 | bool closed = path.Closed; 162 | int verticesLength = path.WorldVerticesLength, curveCount = verticesLength / 6, prevCurve = NONE; 163 | 164 | float pathLength; 165 | if (!path.ConstantSpeed) { 166 | float[] lengths = path.Lengths; 167 | curveCount -= closed ? 1 : 2; 168 | pathLength = lengths[curveCount]; 169 | if (percentPosition) position *= pathLength; 170 | if (percentSpacing) { 171 | for (int i = 0; i < spacesCount; i++) 172 | spaces[i] *= pathLength; 173 | } 174 | world = this.world.Resize(8).Items; 175 | for (int i = 0, o = 0, curve = 0; i < spacesCount; i++, o += 3) { 176 | float space = spaces[i]; 177 | position += space; 178 | float p = position; 179 | 180 | if (closed) { 181 | p %= pathLength; 182 | if (p < 0) p += pathLength; 183 | curve = 0; 184 | } else if (p < 0) { 185 | if (prevCurve != BEFORE) { 186 | prevCurve = BEFORE; 187 | path.ComputeWorldVertices(target, 2, 4, world, 0); 188 | } 189 | AddBeforePosition(p, world, 0, output, o); 190 | continue; 191 | } else if (p > pathLength) { 192 | if (prevCurve != AFTER) { 193 | prevCurve = AFTER; 194 | path.ComputeWorldVertices(target, verticesLength - 6, 4, world, 0); 195 | } 196 | AddAfterPosition(p - pathLength, world, 0, output, o); 197 | continue; 198 | } 199 | 200 | // Determine curve containing position. 201 | for (;; curve++) { 202 | float length = lengths[curve]; 203 | if (p > length) continue; 204 | if (curve == 0) 205 | p /= length; 206 | else { 207 | float prev = lengths[curve - 1]; 208 | p = (p - prev) / (length - prev); 209 | } 210 | break; 211 | } 212 | if (curve != prevCurve) { 213 | prevCurve = curve; 214 | if (closed && curve == curveCount) { 215 | path.ComputeWorldVertices(target, verticesLength - 4, 4, world, 0); 216 | path.ComputeWorldVertices(target, 0, 4, world, 4); 217 | } else 218 | path.ComputeWorldVertices(target, curve * 6 + 2, 8, world, 0); 219 | } 220 | AddCurvePosition(p, world[0], world[1], world[2], world[3], world[4], world[5], world[6], world[7], output, o, 221 | tangents || (i > 0 && space == 0)); 222 | } 223 | return output; 224 | } 225 | 226 | // World vertices. 227 | if (closed) { 228 | verticesLength += 2; 229 | world = this.world.Resize(verticesLength).Items; 230 | path.ComputeWorldVertices(target, 2, verticesLength - 4, world, 0); 231 | path.ComputeWorldVertices(target, 0, 2, world, verticesLength - 4); 232 | world[verticesLength - 2] = world[0]; 233 | world[verticesLength - 1] = world[1]; 234 | } else { 235 | curveCount--; 236 | verticesLength -= 4; 237 | world = this.world.Resize(verticesLength).Items; 238 | path.ComputeWorldVertices(target, 2, verticesLength, world, 0); 239 | } 240 | 241 | // Curve lengths. 242 | float[] curves = this.curves.Resize(curveCount).Items; 243 | pathLength = 0; 244 | float x1 = world[0], y1 = world[1], cx1 = 0, cy1 = 0, cx2 = 0, cy2 = 0, x2 = 0, y2 = 0; 245 | float tmpx, tmpy, dddfx, dddfy, ddfx, ddfy, dfx, dfy; 246 | for (int i = 0, w = 2; i < curveCount; i++, w += 6) { 247 | cx1 = world[w]; 248 | cy1 = world[w + 1]; 249 | cx2 = world[w + 2]; 250 | cy2 = world[w + 3]; 251 | x2 = world[w + 4]; 252 | y2 = world[w + 5]; 253 | tmpx = (x1 - cx1 * 2 + cx2) * 0.1875f; 254 | tmpy = (y1 - cy1 * 2 + cy2) * 0.1875f; 255 | dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.09375f; 256 | dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.09375f; 257 | ddfx = tmpx * 2 + dddfx; 258 | ddfy = tmpy * 2 + dddfy; 259 | dfx = (cx1 - x1) * 0.75f + tmpx + dddfx * 0.16666667f; 260 | dfy = (cy1 - y1) * 0.75f + tmpy + dddfy * 0.16666667f; 261 | pathLength += (float)Math.Sqrt(dfx * dfx + dfy * dfy); 262 | dfx += ddfx; 263 | dfy += ddfy; 264 | ddfx += dddfx; 265 | ddfy += dddfy; 266 | pathLength += (float)Math.Sqrt(dfx * dfx + dfy * dfy); 267 | dfx += ddfx; 268 | dfy += ddfy; 269 | pathLength += (float)Math.Sqrt(dfx * dfx + dfy * dfy); 270 | dfx += ddfx + dddfx; 271 | dfy += ddfy + dddfy; 272 | pathLength += (float)Math.Sqrt(dfx * dfx + dfy * dfy); 273 | curves[i] = pathLength; 274 | x1 = x2; 275 | y1 = y2; 276 | } 277 | if (percentPosition) position *= pathLength; 278 | if (percentSpacing) { 279 | for (int i = 0; i < spacesCount; i++) 280 | spaces[i] *= pathLength; 281 | } 282 | 283 | float[] segments = this.segments; 284 | float curveLength = 0; 285 | for (int i = 0, o = 0, curve = 0, segment = 0; i < spacesCount; i++, o += 3) { 286 | float space = spaces[i]; 287 | position += space; 288 | float p = position; 289 | 290 | if (closed) { 291 | p %= pathLength; 292 | if (p < 0) p += pathLength; 293 | curve = 0; 294 | } else if (p < 0) { 295 | AddBeforePosition(p, world, 0, output, o); 296 | continue; 297 | } else if (p > pathLength) { 298 | AddAfterPosition(p - pathLength, world, verticesLength - 4, output, o); 299 | continue; 300 | } 301 | 302 | // Determine curve containing position. 303 | for (;; curve++) { 304 | float length = curves[curve]; 305 | if (p > length) continue; 306 | if (curve == 0) 307 | p /= length; 308 | else { 309 | float prev = curves[curve - 1]; 310 | p = (p - prev) / (length - prev); 311 | } 312 | break; 313 | } 314 | 315 | // Curve segment lengths. 316 | if (curve != prevCurve) { 317 | prevCurve = curve; 318 | int ii = curve * 6; 319 | x1 = world[ii]; 320 | y1 = world[ii + 1]; 321 | cx1 = world[ii + 2]; 322 | cy1 = world[ii + 3]; 323 | cx2 = world[ii + 4]; 324 | cy2 = world[ii + 5]; 325 | x2 = world[ii + 6]; 326 | y2 = world[ii + 7]; 327 | tmpx = (x1 - cx1 * 2 + cx2) * 0.03f; 328 | tmpy = (y1 - cy1 * 2 + cy2) * 0.03f; 329 | dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.006f; 330 | dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.006f; 331 | ddfx = tmpx * 2 + dddfx; 332 | ddfy = tmpy * 2 + dddfy; 333 | dfx = (cx1 - x1) * 0.3f + tmpx + dddfx * 0.16666667f; 334 | dfy = (cy1 - y1) * 0.3f + tmpy + dddfy * 0.16666667f; 335 | curveLength = (float)Math.Sqrt(dfx * dfx + dfy * dfy); 336 | segments[0] = curveLength; 337 | for (ii = 1; ii < 8; ii++) { 338 | dfx += ddfx; 339 | dfy += ddfy; 340 | ddfx += dddfx; 341 | ddfy += dddfy; 342 | curveLength += (float)Math.Sqrt(dfx * dfx + dfy * dfy); 343 | segments[ii] = curveLength; 344 | } 345 | dfx += ddfx; 346 | dfy += ddfy; 347 | curveLength += (float)Math.Sqrt(dfx * dfx + dfy * dfy); 348 | segments[8] = curveLength; 349 | dfx += ddfx + dddfx; 350 | dfy += ddfy + dddfy; 351 | curveLength += (float)Math.Sqrt(dfx * dfx + dfy * dfy); 352 | segments[9] = curveLength; 353 | segment = 0; 354 | } 355 | 356 | // Weight by segment length. 357 | p *= curveLength; 358 | for (;; segment++) { 359 | float length = segments[segment]; 360 | if (p > length) continue; 361 | if (segment == 0) 362 | p /= length; 363 | else { 364 | float prev = segments[segment - 1]; 365 | p = segment + (p - prev) / (length - prev); 366 | } 367 | break; 368 | } 369 | AddCurvePosition(p * 0.1f, x1, y1, cx1, cy1, cx2, cy2, x2, y2, output, o, tangents || (i > 0 && space == 0)); 370 | } 371 | return output; 372 | } 373 | 374 | private void AddBeforePosition (float p, float[] temp, int i, float[] output, int o) { 375 | float x1 = temp[i], y1 = temp[i + 1], dx = temp[i + 2] - x1, dy = temp[i + 3] - y1, r = MathUtils.Atan2(dy, dx); 376 | output[o] = x1 + p * MathUtils.Cos(r); 377 | output[o + 1] = y1 + p * MathUtils.Sin(r); 378 | output[o + 2] = r; 379 | } 380 | 381 | private void AddAfterPosition (float p, float[] temp, int i, float[] output, int o) { 382 | float x1 = temp[i + 2], y1 = temp[i + 3], dx = x1 - temp[i], dy = y1 - temp[i + 1], r = MathUtils.Atan2(dy, dx); 383 | output[o] = x1 + p * MathUtils.Cos(r); 384 | output[o + 1] = y1 + p * MathUtils.Sin(r); 385 | output[o + 2] = r; 386 | } 387 | 388 | private void AddCurvePosition (float p, float x1, float y1, float cx1, float cy1, float cx2, float cy2, float x2, float y2, 389 | float[] output, int o, bool tangents) { 390 | if (p == 0) p = 0.0001f; 391 | float tt = p * p, ttt = tt * p, u = 1 - p, uu = u * u, uuu = uu * u; 392 | float ut = u * p, ut3 = ut * 3, uut3 = u * ut3, utt3 = ut3 * p; 393 | float x = x1 * uuu + cx1 * uut3 + cx2 * utt3 + x2 * ttt, y = y1 * uuu + cy1 * uut3 + cy2 * utt3 + y2 * ttt; 394 | output[o] = x; 395 | output[o + 1] = y; 396 | if (tangents) output[o + 2] = (float)Math.Atan2(y - (y1 * uu + cy1 * ut * 2 + cy2 * tt), x - (x1 * uu + cx1 * ut * 2 + cx2 * tt)); 397 | } 398 | } 399 | } 400 | -------------------------------------------------------------------------------- /spine-csharp/src/PathConstraintData.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License v2.5 3 | * 4 | * Copyright (c) 2013-2016, Esoteric Software 5 | * All rights reserved. 6 | * 7 | * You are granted a perpetual, non-exclusive, non-sublicensable, and 8 | * non-transferable license to use, install, execute, and perform the Spine 9 | * Runtimes software and derivative works solely for personal or internal 10 | * use. Without the written permission of Esoteric Software (see Section 2 of 11 | * the Spine Software License Agreement), you may not (a) modify, translate, 12 | * adapt, or develop new applications using the Spine Runtimes or otherwise 13 | * create derivative works or improvements of the Spine Runtimes or (b) remove, 14 | * delete, alter, or obscure any trademarks or any copyright, trademark, patent, 15 | * or other intellectual property or proprietary rights notices on or in the 16 | * Software, including any copy thereof. Redistributions in binary or source 17 | * form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF 25 | * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 26 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | 33 | namespace Spine { 34 | public class PathConstraintData { 35 | internal String name; 36 | internal ExposedList bones = new ExposedList(); 37 | internal SlotData target; 38 | internal PositionMode positionMode; 39 | internal SpacingMode spacingMode; 40 | internal RotateMode rotateMode; 41 | internal float offsetRotation; 42 | internal float position, spacing, rotateMix, translateMix; 43 | 44 | public ExposedList Bones { get { return bones; } } 45 | public SlotData Target { get { return target; } set { target = value; } } 46 | public PositionMode PositionMode { get { return positionMode; } set { positionMode = value; } } 47 | public SpacingMode SpacingMode { get { return spacingMode; } set { spacingMode = value; } } 48 | public RotateMode RotateMode { get { return rotateMode; } set { rotateMode = value; } } 49 | public float OffsetRotation { get { return offsetRotation; } set { offsetRotation = value; } } 50 | public float Position { get { return position; } set { position = value; } } 51 | public float Spacing { get { return spacing; } set { spacing = value; } } 52 | public float RotateMix { get { return rotateMix; } set { rotateMix = value; } } 53 | public float TranslateMix { get { return translateMix; } set { translateMix = value; } } 54 | public String Name { get { return name; } } 55 | 56 | public PathConstraintData (String name) { 57 | if (name == null) throw new ArgumentNullException("name", "name cannot be null."); 58 | this.name = name; 59 | } 60 | } 61 | 62 | public enum PositionMode { 63 | Fixed, Percent 64 | } 65 | 66 | public enum SpacingMode { 67 | Length, Fixed, Percent 68 | } 69 | 70 | public enum RotateMode { 71 | Tangent, Chain, ChainScale 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /spine-csharp/src/SkeletonBounds.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License v2.5 3 | * 4 | * Copyright (c) 2013-2016, Esoteric Software 5 | * All rights reserved. 6 | * 7 | * You are granted a perpetual, non-exclusive, non-sublicensable, and 8 | * non-transferable license to use, install, execute, and perform the Spine 9 | * Runtimes software and derivative works solely for personal or internal 10 | * use. Without the written permission of Esoteric Software (see Section 2 of 11 | * the Spine Software License Agreement), you may not (a) modify, translate, 12 | * adapt, or develop new applications using the Spine Runtimes or otherwise 13 | * create derivative works or improvements of the Spine Runtimes or (b) remove, 14 | * delete, alter, or obscure any trademarks or any copyright, trademark, patent, 15 | * or other intellectual property or proprietary rights notices on or in the 16 | * Software, including any copy thereof. Redistributions in binary or source 17 | * form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF 25 | * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 26 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | 33 | namespace Spine { 34 | public class SkeletonBounds { 35 | private ExposedList polygonPool = new ExposedList(); 36 | private float minX, minY, maxX, maxY; 37 | 38 | public ExposedList BoundingBoxes { get; private set; } 39 | public ExposedList Polygons { get; private set; } 40 | public float MinX { get { return minX; } set { minX = value; } } 41 | public float MinY { get { return minY; } set { minY = value; } } 42 | public float MaxX { get { return maxX; } set { maxX = value; } } 43 | public float MaxY { get { return maxY; } set { maxY = value; } } 44 | public float Width { get { return maxX - minX; } } 45 | public float Height { get { return maxY - minY; } } 46 | 47 | public SkeletonBounds () { 48 | BoundingBoxes = new ExposedList(); 49 | Polygons = new ExposedList(); 50 | } 51 | 52 | public void Update (Skeleton skeleton, bool updateAabb) { 53 | ExposedList boundingBoxes = BoundingBoxes; 54 | ExposedList polygons = Polygons; 55 | ExposedList slots = skeleton.slots; 56 | int slotCount = slots.Count; 57 | 58 | boundingBoxes.Clear(); 59 | for (int i = 0, n = polygons.Count; i < n; i++) 60 | polygonPool.Add(polygons.Items[i]); 61 | polygons.Clear(); 62 | 63 | for (int i = 0; i < slotCount; i++) { 64 | Slot slot = slots.Items[i]; 65 | BoundingBoxAttachment boundingBox = slot.attachment as BoundingBoxAttachment; 66 | if (boundingBox == null) continue; 67 | boundingBoxes.Add(boundingBox); 68 | 69 | Polygon polygon = null; 70 | int poolCount = polygonPool.Count; 71 | if (poolCount > 0) { 72 | polygon = polygonPool.Items[poolCount - 1]; 73 | polygonPool.RemoveAt(poolCount - 1); 74 | } else 75 | polygon = new Polygon(); 76 | polygons.Add(polygon); 77 | 78 | int count = boundingBox.Vertices.Length; 79 | polygon.Count = count; 80 | if (polygon.Vertices.Length < count) polygon.Vertices = new float[count]; 81 | boundingBox.ComputeWorldVertices(slot, polygon.Vertices); 82 | } 83 | 84 | if (updateAabb) aabbCompute(); 85 | } 86 | 87 | private void aabbCompute () { 88 | float minX = int.MaxValue, minY = int.MaxValue, maxX = int.MinValue, maxY = int.MinValue; 89 | ExposedList polygons = Polygons; 90 | for (int i = 0, n = polygons.Count; i < n; i++) { 91 | Polygon polygon = polygons.Items[i]; 92 | float[] vertices = polygon.Vertices; 93 | for (int ii = 0, nn = polygon.Count; ii < nn; ii += 2) { 94 | float x = vertices[ii]; 95 | float y = vertices[ii + 1]; 96 | minX = Math.Min(minX, x); 97 | minY = Math.Min(minY, y); 98 | maxX = Math.Max(maxX, x); 99 | maxY = Math.Max(maxY, y); 100 | } 101 | } 102 | this.minX = minX; 103 | this.minY = minY; 104 | this.maxX = maxX; 105 | this.maxY = maxY; 106 | } 107 | 108 | 109 | /// Returns true if the axis aligned bounding box contains the point. 110 | public bool AabbContainsPoint (float x, float y) { 111 | return x >= minX && x <= maxX && y >= minY && y <= maxY; 112 | } 113 | 114 | /// Returns true if the axis aligned bounding box intersects the line segment. 115 | public bool AabbIntersectsSegment (float x1, float y1, float x2, float y2) { 116 | float minX = this.minX; 117 | float minY = this.minY; 118 | float maxX = this.maxX; 119 | float maxY = this.maxY; 120 | if ((x1 <= minX && x2 <= minX) || (y1 <= minY && y2 <= minY) || (x1 >= maxX && x2 >= maxX) || (y1 >= maxY && y2 >= maxY)) 121 | return false; 122 | float m = (y2 - y1) / (x2 - x1); 123 | float y = m * (minX - x1) + y1; 124 | if (y > minY && y < maxY) return true; 125 | y = m * (maxX - x1) + y1; 126 | if (y > minY && y < maxY) return true; 127 | float x = (minY - y1) / m + x1; 128 | if (x > minX && x < maxX) return true; 129 | x = (maxY - y1) / m + x1; 130 | if (x > minX && x < maxX) return true; 131 | return false; 132 | } 133 | 134 | /// Returns true if the axis aligned bounding box intersects the axis aligned bounding box of the specified bounds. 135 | public bool AabbIntersectsSkeleton (SkeletonBounds bounds) { 136 | return minX < bounds.maxX && maxX > bounds.minX && minY < bounds.maxY && maxY > bounds.minY; 137 | } 138 | 139 | /// Returns true if the polygon contains the point. 140 | public bool ContainsPoint (Polygon polygon, float x, float y) { 141 | float[] vertices = polygon.Vertices; 142 | int nn = polygon.Count; 143 | 144 | int prevIndex = nn - 2; 145 | bool inside = false; 146 | for (int ii = 0; ii < nn; ii += 2) { 147 | float vertexY = vertices[ii + 1]; 148 | float prevY = vertices[prevIndex + 1]; 149 | if ((vertexY < y && prevY >= y) || (prevY < y && vertexY >= y)) { 150 | float vertexX = vertices[ii]; 151 | if (vertexX + (y - vertexY) / (prevY - vertexY) * (vertices[prevIndex] - vertexX) < x) inside = !inside; 152 | } 153 | prevIndex = ii; 154 | } 155 | return inside; 156 | } 157 | 158 | /// Returns the first bounding box attachment that contains the point, or null. When doing many checks, it is usually more 159 | /// efficient to only call this method if {@link #aabbContainsPoint(float, float)} returns true. 160 | public BoundingBoxAttachment ContainsPoint (float x, float y) { 161 | ExposedList polygons = Polygons; 162 | for (int i = 0, n = polygons.Count; i < n; i++) 163 | if (ContainsPoint(polygons.Items[i], x, y)) return BoundingBoxes.Items[i]; 164 | return null; 165 | } 166 | 167 | /// Returns the first bounding box attachment that contains the line segment, or null. When doing many checks, it is usually 168 | /// more efficient to only call this method if {@link #aabbIntersectsSegment(float, float, float, float)} returns true. 169 | public BoundingBoxAttachment IntersectsSegment (float x1, float y1, float x2, float y2) { 170 | ExposedList polygons = Polygons; 171 | for (int i = 0, n = polygons.Count; i < n; i++) 172 | if (IntersectsSegment(polygons.Items[i], x1, y1, x2, y2)) return BoundingBoxes.Items[i]; 173 | return null; 174 | } 175 | 176 | /// Returns true if the polygon contains the line segment. 177 | public bool IntersectsSegment (Polygon polygon, float x1, float y1, float x2, float y2) { 178 | float[] vertices = polygon.Vertices; 179 | int nn = polygon.Count; 180 | 181 | float width12 = x1 - x2, height12 = y1 - y2; 182 | float det1 = x1 * y2 - y1 * x2; 183 | float x3 = vertices[nn - 2], y3 = vertices[nn - 1]; 184 | for (int ii = 0; ii < nn; ii += 2) { 185 | float x4 = vertices[ii], y4 = vertices[ii + 1]; 186 | float det2 = x3 * y4 - y3 * x4; 187 | float width34 = x3 - x4, height34 = y3 - y4; 188 | float det3 = width12 * height34 - height12 * width34; 189 | float x = (det1 * width34 - width12 * det2) / det3; 190 | if (((x >= x3 && x <= x4) || (x >= x4 && x <= x3)) && ((x >= x1 && x <= x2) || (x >= x2 && x <= x1))) { 191 | float y = (det1 * height34 - height12 * det2) / det3; 192 | if (((y >= y3 && y <= y4) || (y >= y4 && y <= y3)) && ((y >= y1 && y <= y2) || (y >= y2 && y <= y1))) return true; 193 | } 194 | x3 = x4; 195 | y3 = y4; 196 | } 197 | return false; 198 | } 199 | 200 | public Polygon getPolygon (BoundingBoxAttachment attachment) { 201 | int index = BoundingBoxes.IndexOf(attachment); 202 | return index == -1 ? null : Polygons.Items[index]; 203 | } 204 | } 205 | 206 | public class Polygon { 207 | public float[] Vertices { get; set; } 208 | public int Count { get; set; } 209 | 210 | public Polygon () { 211 | Vertices = new float[16]; 212 | } 213 | } 214 | } 215 | -------------------------------------------------------------------------------- /spine-csharp/src/SkeletonData.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License v2.5 3 | * 4 | * Copyright (c) 2013-2016, Esoteric Software 5 | * All rights reserved. 6 | * 7 | * You are granted a perpetual, non-exclusive, non-sublicensable, and 8 | * non-transferable license to use, install, execute, and perform the Spine 9 | * Runtimes software and derivative works solely for personal or internal 10 | * use. Without the written permission of Esoteric Software (see Section 2 of 11 | * the Spine Software License Agreement), you may not (a) modify, translate, 12 | * adapt, or develop new applications using the Spine Runtimes or otherwise 13 | * create derivative works or improvements of the Spine Runtimes or (b) remove, 14 | * delete, alter, or obscure any trademarks or any copyright, trademark, patent, 15 | * or other intellectual property or proprietary rights notices on or in the 16 | * Software, including any copy thereof. Redistributions in binary or source 17 | * form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF 25 | * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 26 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | 33 | namespace Spine { 34 | public class SkeletonData { 35 | internal String name; 36 | internal ExposedList bones = new ExposedList(); 37 | internal ExposedList slots = new ExposedList(); 38 | internal ExposedList skins = new ExposedList(); 39 | internal Skin defaultSkin; 40 | internal ExposedList events = new ExposedList(); 41 | internal ExposedList animations = new ExposedList(); 42 | internal ExposedList ikConstraints = new ExposedList(); 43 | internal ExposedList transformConstraints = new ExposedList(); 44 | internal ExposedList pathConstraints = new ExposedList(); 45 | internal float width, height; 46 | internal String version, hash, imagesPath; 47 | 48 | public String Name { get { return name; } set { name = value; } } 49 | public ExposedList Bones { get { return bones; } } // Ordered parents first. 50 | public ExposedList Slots { get { return slots; } } // Setup pose draw order. 51 | public ExposedList Skins { get { return skins; } set { skins = value; } } 52 | /// May be null. 53 | public Skin DefaultSkin { get { return defaultSkin; } set { defaultSkin = value; } } 54 | public ExposedList Events { get { return events; } set { events = value; } } 55 | public ExposedList Animations { get { return animations; } set { animations = value; } } 56 | public ExposedList IkConstraints { get { return ikConstraints; } set { ikConstraints = value; } } 57 | public ExposedList TransformConstraints { get { return transformConstraints; } set { transformConstraints = value; } } 58 | public ExposedList PathConstraints { get { return pathConstraints; } set { pathConstraints = value; } } 59 | public float Width { get { return width; } set { width = value; } } 60 | public float Height { get { return height; } set { height = value; } } 61 | /// The Spine version used to export this data. 62 | public String Version { get { return version; } set { version = value; } } 63 | public String Hash { get { return hash; } set { hash = value; } } 64 | 65 | // --- Bones. 66 | 67 | /// May be null. 68 | public BoneData FindBone (String boneName) { 69 | if (boneName == null) throw new ArgumentNullException("boneName", "boneName cannot be null."); 70 | ExposedList bones = this.bones; 71 | for (int i = 0, n = bones.Count; i < n; i++) { 72 | BoneData bone = bones.Items[i]; 73 | if (bone.name == boneName) return bone; 74 | } 75 | return null; 76 | } 77 | 78 | /// -1 if the bone was not found. 79 | public int FindBoneIndex (String boneName) { 80 | if (boneName == null) throw new ArgumentNullException("boneName", "boneName cannot be null."); 81 | ExposedList bones = this.bones; 82 | for (int i = 0, n = bones.Count; i < n; i++) 83 | if (bones.Items[i].name == boneName) return i; 84 | return -1; 85 | } 86 | 87 | // --- Slots. 88 | 89 | /// May be null. 90 | public SlotData FindSlot (String slotName) { 91 | if (slotName == null) throw new ArgumentNullException("slotName", "slotName cannot be null."); 92 | ExposedList slots = this.slots; 93 | for (int i = 0, n = slots.Count; i < n; i++) { 94 | SlotData slot = slots.Items[i]; 95 | if (slot.name == slotName) return slot; 96 | } 97 | return null; 98 | } 99 | 100 | /// -1 if the slot was not found. 101 | public int FindSlotIndex (String slotName) { 102 | if (slotName == null) throw new ArgumentNullException("slotName", "slotName cannot be null."); 103 | ExposedList slots = this.slots; 104 | for (int i = 0, n = slots.Count; i < n; i++) 105 | if (slots.Items[i].name == slotName) return i; 106 | return -1; 107 | } 108 | 109 | // --- Skins. 110 | 111 | /// May be null. 112 | public Skin FindSkin (String skinName) { 113 | if (skinName == null) throw new ArgumentNullException("skinName", "skinName cannot be null."); 114 | foreach (Skin skin in skins) 115 | if (skin.name == skinName) return skin; 116 | return null; 117 | } 118 | 119 | // --- Events. 120 | 121 | /// May be null. 122 | public EventData FindEvent (String eventDataName) { 123 | if (eventDataName == null) throw new ArgumentNullException("eventDataName", "eventDataName cannot be null."); 124 | foreach (EventData eventData in events) 125 | if (eventData.name == eventDataName) return eventData; 126 | return null; 127 | } 128 | 129 | // --- Animations. 130 | 131 | /// May be null. 132 | public Animation FindAnimation (String animationName) { 133 | if (animationName == null) throw new ArgumentNullException("animationName", "animationName cannot be null."); 134 | ExposedList animations = this.animations; 135 | for (int i = 0, n = animations.Count; i < n; i++) { 136 | Animation animation = animations.Items[i]; 137 | if (animation.name == animationName) return animation; 138 | } 139 | return null; 140 | } 141 | 142 | // --- IK constraints. 143 | 144 | /// May be null. 145 | public IkConstraintData FindIkConstraint (String constraintName) { 146 | if (constraintName == null) throw new ArgumentNullException("constraintName", "constraintName cannot be null."); 147 | ExposedList ikConstraints = this.ikConstraints; 148 | for (int i = 0, n = ikConstraints.Count; i < n; i++) { 149 | IkConstraintData ikConstraint = ikConstraints.Items[i]; 150 | if (ikConstraint.name == constraintName) return ikConstraint; 151 | } 152 | return null; 153 | } 154 | 155 | // --- Transform constraints. 156 | 157 | /// May be null. 158 | public TransformConstraintData FindTransformConstraint (String constraintName) { 159 | if (constraintName == null) throw new ArgumentNullException("constraintName", "constraintName cannot be null."); 160 | ExposedList transformConstraints = this.transformConstraints; 161 | for (int i = 0, n = transformConstraints.Count; i < n; i++) { 162 | TransformConstraintData transformConstraint = transformConstraints.Items[i]; 163 | if (transformConstraint.name == constraintName) return transformConstraint; 164 | } 165 | return null; 166 | } 167 | 168 | // --- Path constraints. 169 | 170 | /// May be null. 171 | public PathConstraintData FindPathConstraint (String constraintName) { 172 | if (constraintName == null) throw new ArgumentNullException("constraintName", "constraintName cannot be null."); 173 | ExposedList pathConstraints = this.pathConstraints; 174 | for (int i = 0, n = pathConstraints.Count; i < n; i++) { 175 | PathConstraintData constraint = pathConstraints.Items[i]; 176 | if (constraint.name.Equals(constraintName)) return constraint; 177 | } 178 | return null; 179 | } 180 | 181 | /// -1 if the path constraint was not found. 182 | public int FindPathConstraintIndex (String pathConstraintName) { 183 | if (pathConstraintName == null) throw new ArgumentNullException("pathConstraintName", "pathConstraintName cannot be null."); 184 | ExposedList pathConstraints = this.pathConstraints; 185 | for (int i = 0, n = pathConstraints.Count; i < n; i++) 186 | if (pathConstraints.Items[i].name.Equals(pathConstraintName)) return i; 187 | return -1; 188 | } 189 | 190 | // --- 191 | 192 | override public String ToString () { 193 | return name ?? base.ToString(); 194 | } 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /spine-csharp/src/Skin.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License v2.5 3 | * 4 | * Copyright (c) 2013-2016, Esoteric Software 5 | * All rights reserved. 6 | * 7 | * You are granted a perpetual, non-exclusive, non-sublicensable, and 8 | * non-transferable license to use, install, execute, and perform the Spine 9 | * Runtimes software and derivative works solely for personal or internal 10 | * use. Without the written permission of Esoteric Software (see Section 2 of 11 | * the Spine Software License Agreement), you may not (a) modify, translate, 12 | * adapt, or develop new applications using the Spine Runtimes or otherwise 13 | * create derivative works or improvements of the Spine Runtimes or (b) remove, 14 | * delete, alter, or obscure any trademarks or any copyright, trademark, patent, 15 | * or other intellectual property or proprietary rights notices on or in the 16 | * Software, including any copy thereof. Redistributions in binary or source 17 | * form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF 25 | * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 26 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | using System.Collections.Generic; 33 | 34 | namespace Spine { 35 | /// Stores attachments by slot index and attachment name. 36 | public class Skin { 37 | internal String name; 38 | private Dictionary attachments = 39 | new Dictionary(AttachmentKeyTupleComparer.Instance); 40 | 41 | public String Name { get { return name; } } 42 | public Dictionary Attachments { get { return attachments; } } 43 | 44 | public Skin (String name) { 45 | if (name == null) throw new ArgumentNullException("name", "name cannot be null."); 46 | this.name = name; 47 | } 48 | 49 | public void AddAttachment (int slotIndex, String name, Attachment attachment) { 50 | if (attachment == null) throw new ArgumentNullException("attachment", "attachment cannot be null."); 51 | attachments[new AttachmentKeyTuple(slotIndex, name)] = attachment; 52 | } 53 | 54 | /// May be null. 55 | public Attachment GetAttachment (int slotIndex, String name) { 56 | Attachment attachment; 57 | attachments.TryGetValue(new AttachmentKeyTuple(slotIndex, name), out attachment); 58 | return attachment; 59 | } 60 | 61 | public void FindNamesForSlot (int slotIndex, List names) { 62 | if (names == null) throw new ArgumentNullException("names", "names cannot be null."); 63 | foreach (AttachmentKeyTuple key in attachments.Keys) 64 | if (key.slotIndex == slotIndex) names.Add(key.name); 65 | } 66 | 67 | public void FindAttachmentsForSlot (int slotIndex, List attachments) { 68 | if (attachments == null) throw new ArgumentNullException("attachments", "attachments cannot be null."); 69 | foreach (KeyValuePair entry in this.attachments) 70 | if (entry.Key.slotIndex == slotIndex) attachments.Add(entry.Value); 71 | } 72 | 73 | override public String ToString () { 74 | return name; 75 | } 76 | 77 | /// Attach all attachments from this skin if the corresponding attachment from the old skin is currently attached. 78 | internal void AttachAll (Skeleton skeleton, Skin oldSkin) { 79 | foreach (KeyValuePair entry in oldSkin.attachments) { 80 | int slotIndex = entry.Key.slotIndex; 81 | Slot slot = skeleton.slots.Items[slotIndex]; 82 | if (slot.attachment == entry.Value) { 83 | Attachment attachment = GetAttachment(slotIndex, entry.Key.name); 84 | if (attachment != null) slot.Attachment = attachment; 85 | } 86 | } 87 | } 88 | 89 | public struct AttachmentKeyTuple { 90 | public readonly int slotIndex; 91 | public readonly string name; 92 | internal readonly int nameHashCode; 93 | 94 | public AttachmentKeyTuple (int slotIndex, string name) { 95 | this.slotIndex = slotIndex; 96 | this.name = name; 97 | nameHashCode = this.name.GetHashCode(); 98 | } 99 | } 100 | 101 | // Avoids boxing in the dictionary. 102 | class AttachmentKeyTupleComparer : IEqualityComparer { 103 | internal static readonly AttachmentKeyTupleComparer Instance = new AttachmentKeyTupleComparer(); 104 | 105 | bool IEqualityComparer.Equals (AttachmentKeyTuple o1, AttachmentKeyTuple o2) { 106 | return o1.slotIndex == o2.slotIndex && o1.nameHashCode == o2.nameHashCode && o1.name == o2.name; 107 | } 108 | 109 | int IEqualityComparer.GetHashCode (AttachmentKeyTuple o) { 110 | return o.slotIndex; 111 | } 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /spine-csharp/src/Slot.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License v2.5 3 | * 4 | * Copyright (c) 2013-2016, Esoteric Software 5 | * All rights reserved. 6 | * 7 | * You are granted a perpetual, non-exclusive, non-sublicensable, and 8 | * non-transferable license to use, install, execute, and perform the Spine 9 | * Runtimes software and derivative works solely for personal or internal 10 | * use. Without the written permission of Esoteric Software (see Section 2 of 11 | * the Spine Software License Agreement), you may not (a) modify, translate, 12 | * adapt, or develop new applications using the Spine Runtimes or otherwise 13 | * create derivative works or improvements of the Spine Runtimes or (b) remove, 14 | * delete, alter, or obscure any trademarks or any copyright, trademark, patent, 15 | * or other intellectual property or proprietary rights notices on or in the 16 | * Software, including any copy thereof. Redistributions in binary or source 17 | * form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF 25 | * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 26 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | 33 | namespace Spine { 34 | public class Slot { 35 | internal SlotData data; 36 | internal Bone bone; 37 | internal float r, g, b, a; 38 | internal Attachment attachment; 39 | internal float attachmentTime; 40 | internal ExposedList attachmentVertices = new ExposedList(); 41 | 42 | public SlotData Data { get { return data; } } 43 | public Bone Bone { get { return bone; } } 44 | public Skeleton Skeleton { get { return bone.skeleton; } } 45 | public float R { get { return r; } set { r = value; } } 46 | public float G { get { return g; } set { g = value; } } 47 | public float B { get { return b; } set { b = value; } } 48 | public float A { get { return a; } set { a = value; } } 49 | 50 | /// May be null. 51 | public Attachment Attachment { 52 | get { return attachment; } 53 | set { 54 | if (attachment == value) return; 55 | attachment = value; 56 | attachmentTime = bone.skeleton.time; 57 | attachmentVertices.Clear(false); 58 | } 59 | } 60 | 61 | public float AttachmentTime { 62 | get { return bone.skeleton.time - attachmentTime; } 63 | set { attachmentTime = bone.skeleton.time - value; } 64 | } 65 | 66 | public ExposedList AttachmentVertices { get { return attachmentVertices; } set { attachmentVertices = value; } } 67 | 68 | public Slot (SlotData data, Bone bone) { 69 | if (data == null) throw new ArgumentNullException("data", "data cannot be null."); 70 | if (bone == null) throw new ArgumentNullException("bone", "bone cannot be null."); 71 | this.data = data; 72 | this.bone = bone; 73 | SetToSetupPose(); 74 | } 75 | 76 | public void SetToSetupPose () { 77 | r = data.r; 78 | g = data.g; 79 | b = data.b; 80 | a = data.a; 81 | if (data.attachmentName == null) 82 | Attachment = null; 83 | else { 84 | attachment = null; 85 | Attachment = bone.skeleton.GetAttachment(data.index, data.attachmentName); 86 | } 87 | } 88 | 89 | override public String ToString () { 90 | return data.name; 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /spine-csharp/src/SlotData.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License v2.5 3 | * 4 | * Copyright (c) 2013-2016, Esoteric Software 5 | * All rights reserved. 6 | * 7 | * You are granted a perpetual, non-exclusive, non-sublicensable, and 8 | * non-transferable license to use, install, execute, and perform the Spine 9 | * Runtimes software and derivative works solely for personal or internal 10 | * use. Without the written permission of Esoteric Software (see Section 2 of 11 | * the Spine Software License Agreement), you may not (a) modify, translate, 12 | * adapt, or develop new applications using the Spine Runtimes or otherwise 13 | * create derivative works or improvements of the Spine Runtimes or (b) remove, 14 | * delete, alter, or obscure any trademarks or any copyright, trademark, patent, 15 | * or other intellectual property or proprietary rights notices on or in the 16 | * Software, including any copy thereof. Redistributions in binary or source 17 | * form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF 25 | * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 26 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | 33 | namespace Spine { 34 | public class SlotData { 35 | internal int index; 36 | internal String name; 37 | internal BoneData boneData; 38 | internal float r = 1, g = 1, b = 1, a = 1; 39 | internal String attachmentName; 40 | internal BlendMode blendMode; 41 | 42 | public int Index { get { return index; } } 43 | public String Name { get { return name; } } 44 | public BoneData BoneData { get { return boneData; } } 45 | public float R { get { return r; } set { r = value; } } 46 | public float G { get { return g; } set { g = value; } } 47 | public float B { get { return b; } set { b = value; } } 48 | public float A { get { return a; } set { a = value; } } 49 | /// May be null. 50 | public String AttachmentName { get { return attachmentName; } set { attachmentName = value; } } 51 | public BlendMode BlendMode { get { return blendMode; } set { blendMode = value; } } 52 | 53 | public SlotData (int index, String name, BoneData boneData) { 54 | if (index < 0) throw new ArgumentException ("index must be >= 0.", "index"); 55 | if (name == null) throw new ArgumentNullException("name", "name cannot be null."); 56 | if (boneData == null) throw new ArgumentNullException("boneData", "boneData cannot be null."); 57 | this.index = index; 58 | this.name = name; 59 | this.boneData = boneData; 60 | } 61 | 62 | override public String ToString () { 63 | return name; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /spine-csharp/src/TransformConstraint.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License v2.5 3 | * 4 | * Copyright (c) 2013-2016, Esoteric Software 5 | * All rights reserved. 6 | * 7 | * You are granted a perpetual, non-exclusive, non-sublicensable, and 8 | * non-transferable license to use, install, execute, and perform the Spine 9 | * Runtimes software and derivative works solely for personal or internal 10 | * use. Without the written permission of Esoteric Software (see Section 2 of 11 | * the Spine Software License Agreement), you may not (a) modify, translate, 12 | * adapt, or develop new applications using the Spine Runtimes or otherwise 13 | * create derivative works or improvements of the Spine Runtimes or (b) remove, 14 | * delete, alter, or obscure any trademarks or any copyright, trademark, patent, 15 | * or other intellectual property or proprietary rights notices on or in the 16 | * Software, including any copy thereof. Redistributions in binary or source 17 | * form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF 25 | * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 26 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | 33 | namespace Spine { 34 | public class TransformConstraint : IUpdatable { 35 | internal TransformConstraintData data; 36 | internal ExposedList bones; 37 | internal Bone target; 38 | internal float rotateMix, translateMix, scaleMix, shearMix; 39 | 40 | public TransformConstraintData Data { get { return data; } } 41 | public ExposedList Bones { get { return bones; } } 42 | public Bone Target { get { return target; } set { target = value; } } 43 | public float RotateMix { get { return rotateMix; } set { rotateMix = value; } } 44 | public float TranslateMix { get { return translateMix; } set { translateMix = value; } } 45 | public float ScaleMix { get { return scaleMix; } set { scaleMix = value; } } 46 | public float ShearMix { get { return shearMix; } set { shearMix = value; } } 47 | 48 | public TransformConstraint (TransformConstraintData data, Skeleton skeleton) { 49 | if (data == null) throw new ArgumentNullException("data", "data cannot be null."); 50 | if (skeleton == null) throw new ArgumentNullException("skeleton", "skeleton cannot be null."); 51 | this.data = data; 52 | rotateMix = data.rotateMix; 53 | translateMix = data.translateMix; 54 | scaleMix = data.scaleMix; 55 | shearMix = data.shearMix; 56 | 57 | bones = new ExposedList(); 58 | foreach (BoneData boneData in data.bones) 59 | bones.Add (skeleton.FindBone (boneData.name)); 60 | 61 | target = skeleton.FindBone(data.target.name); 62 | } 63 | 64 | public void Apply () { 65 | Update(); 66 | } 67 | 68 | public void Update () { 69 | float rotateMix = this.rotateMix, translateMix = this.translateMix, scaleMix = this.scaleMix, shearMix = this.shearMix; 70 | Bone target = this.target; 71 | float ta = target.a, tb = target.b, tc = target.c, td = target.d; 72 | ExposedList bones = this.bones; 73 | for (int i = 0, n = bones.Count; i < n; i++) { 74 | Bone bone = bones.Items[i]; 75 | 76 | if (rotateMix > 0) { 77 | float a = bone.a, b = bone.b, c = bone.c, d = bone.d; 78 | float r = (float)Math.Atan2(tc, ta) - (float)Math.Atan2(c, a) + data.offsetRotation * MathUtils.degRad; 79 | if (r > MathUtils.PI) 80 | r -= MathUtils.PI2; 81 | else if (r < -MathUtils.PI) r += MathUtils.PI2; 82 | r *= rotateMix; 83 | float cos = MathUtils.Cos(r), sin = MathUtils.Sin(r); 84 | bone.a = cos * a - sin * c; 85 | bone.b = cos * b - sin * d; 86 | bone.c = sin * a + cos * c; 87 | bone.d = sin * b + cos * d; 88 | } 89 | 90 | if (translateMix > 0) { 91 | float tempx, tempy; 92 | target.LocalToWorld(data.offsetX, data.offsetY, out tempx, out tempy); 93 | bone.worldX += (tempx - bone.worldX) * translateMix; 94 | bone.worldY += (tempy - bone.worldY) * translateMix; 95 | } 96 | 97 | if (scaleMix > 0) { 98 | float bs = (float)Math.Sqrt(bone.a * bone.a + bone.c * bone.c); 99 | float ts = (float)Math.Sqrt(ta * ta + tc * tc); 100 | float s = bs > 0.00001f ? (bs + (ts - bs + data.offsetScaleX) * scaleMix) / bs : 0; 101 | bone.a *= s; 102 | bone.c *= s; 103 | bs = (float)Math.Sqrt(bone.b * bone.b + bone.d * bone.d); 104 | ts = (float)Math.Sqrt(tb * tb + td * td); 105 | s = bs > 0.00001f ? (bs + (ts - bs + data.offsetScaleY) * scaleMix) / bs : 0; 106 | bone.b *= s; 107 | bone.d *= s; 108 | } 109 | 110 | if (shearMix > 0) { 111 | float b = bone.b, d = bone.d; 112 | float by = MathUtils.Atan2(d, b); 113 | float r = MathUtils.Atan2(td, tb) - MathUtils.Atan2(tc, ta) - (by - MathUtils.Atan2(bone.c, bone.a)); 114 | if (r > MathUtils.PI) 115 | r -= MathUtils.PI2; 116 | else if (r < -MathUtils.PI) r += MathUtils.PI2; 117 | r = by + (r + data.offsetShearY * MathUtils.degRad) * shearMix; 118 | float s = (float)Math.Sqrt(b * b + d * d); 119 | bone.b = MathUtils.Cos(r) * s; 120 | bone.d = MathUtils.Sin(r) * s; 121 | } 122 | } 123 | } 124 | 125 | override public String ToString () { 126 | return data.name; 127 | } 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /spine-csharp/src/TransformConstraintData.cs: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Spine Runtimes Software License v2.5 3 | * 4 | * Copyright (c) 2013-2016, Esoteric Software 5 | * All rights reserved. 6 | * 7 | * You are granted a perpetual, non-exclusive, non-sublicensable, and 8 | * non-transferable license to use, install, execute, and perform the Spine 9 | * Runtimes software and derivative works solely for personal or internal 10 | * use. Without the written permission of Esoteric Software (see Section 2 of 11 | * the Spine Software License Agreement), you may not (a) modify, translate, 12 | * adapt, or develop new applications using the Spine Runtimes or otherwise 13 | * create derivative works or improvements of the Spine Runtimes or (b) remove, 14 | * delete, alter, or obscure any trademarks or any copyright, trademark, patent, 15 | * or other intellectual property or proprietary rights notices on or in the 16 | * Software, including any copy thereof. Redistributions in binary or source 17 | * form must include this license and terms. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF 25 | * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 26 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | *****************************************************************************/ 30 | 31 | using System; 32 | 33 | namespace Spine { 34 | public class TransformConstraintData { 35 | internal String name; 36 | internal ExposedList bones = new ExposedList(); 37 | internal BoneData target; 38 | internal float rotateMix, translateMix, scaleMix, shearMix; 39 | internal float offsetRotation, offsetX, offsetY, offsetScaleX, offsetScaleY, offsetShearY; 40 | 41 | public String Name { get { return name; } } 42 | public ExposedList Bones { get { return bones; } } 43 | public BoneData Target { get { return target; } set { target = value; } } 44 | public float RotateMix { get { return rotateMix; } set { rotateMix = value; } } 45 | public float TranslateMix { get { return translateMix; } set { translateMix = value; } } 46 | public float ScaleMix { get { return scaleMix; } set { scaleMix = value; } } 47 | public float ShearMix { get { return shearMix; } set { shearMix = value; } } 48 | 49 | public float OffsetRotation { get { return offsetRotation; } set { offsetRotation = value; } } 50 | public float OffsetX { get { return offsetX; } set { offsetX = value; } } 51 | public float OffsetY { get { return offsetY; } set { offsetY = value; } } 52 | public float OffsetScaleX { get { return offsetScaleX; } set { offsetScaleX = value; } } 53 | public float OffsetScaleY { get { return offsetScaleY; } set { offsetScaleY = value; } } 54 | public float OffsetShearY { get { return offsetShearY; } set { offsetShearY = value; } } 55 | 56 | public TransformConstraintData (String name) { 57 | if (name == null) throw new ArgumentNullException("name", "name cannot be null."); 58 | this.name = name; 59 | } 60 | 61 | override public String ToString () { 62 | return name; 63 | } 64 | } 65 | } 66 | --------------------------------------------------------------------------------