mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-03-26 22:49:01 +08:00
Merge branch '4.2' into 4.3
This commit is contained in:
commit
7a50323479
@ -169,6 +169,12 @@
|
||||
- SkeletonMecanim: Added `Scene Preview` option to preview an Animation Clip for e.g. easier event placement. When enabled, the Animation Clip selected in the Animation window is previewed in the Scene and Game views. Lock the `SkeletonMecanim` Inspector window, open the Animation window and select the Animation Clip. Then in the Animation window scrub through the timeline to see the current animation frame previewed.
|
||||
- `Universal Render Pipeline/Spine/Skeleton Lit` shader now supports [Adaptive Probe Volumes (APV)](https://docs.unity3d.com/6000.0/Documentation/Manual/urp/probevolumes-concept.html) introduced in Unity 6. The shader also provides a new material property `APV per Pixel` to either calculate APV lighting contribution per pixel (the default) or per vertex.
|
||||
- `Universal Render Pipeline/Spine/Sprite` shader now also supports [Adaptive Probe Volumes (APV)](https://docs.unity3d.com/6000.0/Documentation/Manual/urp/probevolumes-concept.html) introduced in Unity 6. APV lighting contribution is automatically calculated per pixel.
|
||||
- All Spine Outline shaders, including the URP outline shaders, now provide an additional parameter `Fill`. Enable it to also fill the opaque area inside the outline with the outline color. Prevents a semi-transparent gap between outline and skeleton. Defaults to `disabled` to maintain existing behaviour.
|
||||
- Added example component `RenderExistingMeshGraphic` (similar to `RenderExistingMesh`) to render a `SkeletonGraphic` mesh again with different materials. This might be required by e.g. URP and SkeletonGraphic outline shaders skipping additional render passes. To add a second outline variant of your SkeletonGraphic:
|
||||
1. Add a GameObject at the same hierarchy level as the reference SkeletonGraphic and move it before the reference SkeletonGraphic to render behind.
|
||||
2. Add a `RenderExistingMeshGraphic` component.
|
||||
3. In the `RenderExistingMeshGraphic` component Inspector at `Reference Skeleton Graphic` assign the original `SkeletonGraphic` object.
|
||||
4. At `Replacement Material` assign e.g. the included _SkeletonGraphicDefaultOutline_ material to replace all materials with this material. Alternatively, if `Multiple CanvasRenderers` is enabled at the reference SkeletonGraphic, you can add entries to the `Replacement Materials` list and at each entry assign the original SkeletonGraphic material (e.g. _SkeletonGraphicDefault_) to be replaced and the respective `Replacement Material` (e.g. _SkeletonGraphicDefaultOutline_).
|
||||
|
||||
- **Breaking changes**
|
||||
|
||||
|
||||
@ -1341,9 +1341,9 @@ spSkeletonData *spSkeletonBinary_readSkeletonData(spSkeletonBinary *self, const
|
||||
} else {
|
||||
if (!string_starts_with(skeletonData->version, SPINE_VERSION_STRING)) {
|
||||
FREE(input);
|
||||
spSkeletonData_dispose(skeletonData);
|
||||
char errorMsg[255];
|
||||
snprintf(errorMsg, 255, "Skeleton version %s does not match runtime version %s", skeletonData->version, SPINE_VERSION_STRING);
|
||||
spSkeletonData_dispose(skeletonData);
|
||||
_spSkeletonBinary_setError(self, errorMsg, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -217,8 +217,6 @@ void SpineAtlasResource::_bind_methods() {
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING, "source_path"), "", "get_source_path");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "textures"), "", "get_textures");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "normal_maps"), "", "get_normal_maps");
|
||||
|
||||
ADD_SIGNAL(MethodInfo("skeleton_atlas_changed"));
|
||||
}
|
||||
|
||||
SpineAtlasResource::SpineAtlasResource() : atlas(nullptr), texture_loader(nullptr), normal_map_prefix("n") {
|
||||
|
||||
@ -32,10 +32,26 @@
|
||||
|
||||
#ifdef SPINE_GODOT_EXTENSION
|
||||
#include <godot_cpp/classes/encoded_object_as_id.hpp>
|
||||
#include <godot_cpp/classes/engine.hpp>
|
||||
#include <godot_cpp/classes/editor_interface.hpp>
|
||||
#else
|
||||
#if VERSION_MAJOR > 3
|
||||
#include "core/config/engine.h"
|
||||
#include "editor/editor_interface.h"
|
||||
#else
|
||||
#include "core/engine.h"
|
||||
#endif
|
||||
#include <core/io/marshalls.h>
|
||||
#endif
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
#ifdef SPINE_GODOT_EXTENSION
|
||||
#include <godot_cpp/classes/editor_file_system.hpp>
|
||||
#else
|
||||
#include "editor/editor_file_system.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void SpineAnimationMix::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_from", "from"),
|
||||
&SpineAnimationMix::set_from);
|
||||
@ -175,16 +191,113 @@ void SpineSkeletonDataResource::_bind_methods() {
|
||||
#endif
|
||||
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "animation_mixes"),
|
||||
"set_animation_mixes", "get_animation_mixes");
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
#if VERSION_MAJOR > 3
|
||||
ClassDB::bind_method(D_METHOD("_on_resources_reimported", "resources"),
|
||||
&SpineSkeletonDataResource::_on_resources_reimported);
|
||||
#else
|
||||
ClassDB::bind_method(D_METHOD("_on_resources_reimported", "resources"),
|
||||
&SpineSkeletonDataResource::_on_resources_reimported);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
EditorFileSystem *get_editor_file_system() {
|
||||
#ifdef SPINE_GODOT_EXTENSION
|
||||
EditorInterface *editor_interface = EditorInterface::get_singleton();
|
||||
if (editor_interface) {
|
||||
return editor_interface->get_resource_filesystem();
|
||||
}
|
||||
return nullptr;
|
||||
#else
|
||||
return EditorFileSystem::get_singleton();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
SpineSkeletonDataResource::SpineSkeletonDataResource()
|
||||
: default_mix(0), skeleton_data(nullptr), animation_state_data(nullptr) {}
|
||||
: default_mix(0), skeleton_data(nullptr), animation_state_data(nullptr) {
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
#if VERSION_MAJOR > 3
|
||||
if (Engine::get_singleton()->is_editor_hint()) {
|
||||
EditorFileSystem *efs = get_editor_file_system();
|
||||
if (efs) {
|
||||
efs->connect("resources_reimported", callable_mp(this, &SpineSkeletonDataResource::_on_resources_reimported));
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (Engine::get_singleton()->is_editor_hint()) {
|
||||
EditorFileSystem *efs = EditorFileSystem::get_singleton();
|
||||
if (efs) {
|
||||
efs->connect("resources_reimported", this, "_on_resources_reimported");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
SpineSkeletonDataResource::~SpineSkeletonDataResource() {
|
||||
#ifdef TOOLS_ENABLED
|
||||
#if VERSION_MAJOR > 3
|
||||
if (Engine::get_singleton()->is_editor_hint()) {
|
||||
EditorFileSystem *efs = get_editor_file_system();
|
||||
if (efs && efs->is_connected("resources_reimported", callable_mp(this, &SpineSkeletonDataResource::_on_resources_reimported))) {
|
||||
efs->disconnect("resources_reimported", callable_mp(this, &SpineSkeletonDataResource::_on_resources_reimported));
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (Engine::get_singleton()->is_editor_hint()) {
|
||||
EditorFileSystem *efs = EditorFileSystem::get_singleton();
|
||||
if (efs && efs->is_connected("resources_reimported", this, "_on_resources_reimported")) {
|
||||
efs->disconnect("resources_reimported", this, "_on_resources_reimported");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
delete skeleton_data;
|
||||
delete animation_state_data;
|
||||
}
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
#if VERSION_MAJOR > 3
|
||||
void SpineSkeletonDataResource::_on_resources_reimported(const PackedStringArray &resources) {
|
||||
for (int i = 0; i < resources.size(); i++) {
|
||||
if (atlas_res.is_valid() && atlas_res->get_path() == resources[i]) {
|
||||
#ifdef SPINE_GODOT_EXTENSION
|
||||
atlas_res = ResourceLoader::get_singleton()->load(resources[i], "SpineAtlasResource", ResourceLoader::CACHE_MODE_IGNORE);
|
||||
#else
|
||||
atlas_res = ResourceLoader::load(resources[i], "SpineAtlasResource", ResourceFormatLoader::CACHE_MODE_IGNORE);
|
||||
#endif
|
||||
update_skeleton_data();
|
||||
} else if (skeleton_file_res.is_valid() && skeleton_file_res->get_path() == resources[i]) {
|
||||
#ifdef SPINE_GODOT_EXTENSION
|
||||
skeleton_file_res = ResourceLoader::get_singleton()->load(resources[i], "SpineSkeletonFileResource", ResourceLoader::CACHE_MODE_IGNORE);
|
||||
#else
|
||||
skeleton_file_res = ResourceLoader::load(resources[i], "SpineSkeletonFileResource", ResourceFormatLoader::CACHE_MODE_IGNORE);
|
||||
#endif
|
||||
update_skeleton_data();
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
void SpineSkeletonDataResource::_on_resources_reimported(const PoolStringArray &resources) {
|
||||
for (int i = 0; i < resources.size(); i++) {
|
||||
if (atlas_res.is_valid() && atlas_res->get_path() == resources[i]) {
|
||||
atlas_res = ResourceLoader::load(resources[i]);
|
||||
update_skeleton_data();
|
||||
} else if (skeleton_file_res.is_valid() && skeleton_file_res->get_path() == resources[i]) {
|
||||
skeleton_file_res = ResourceLoader::load(resources[i]);
|
||||
update_skeleton_data();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void SpineSkeletonDataResource::update_skeleton_data() {
|
||||
if (skeleton_data) {
|
||||
delete skeleton_data;
|
||||
@ -249,22 +362,6 @@ bool SpineSkeletonDataResource::is_skeleton_data_loaded() const {
|
||||
void SpineSkeletonDataResource::set_atlas_res(
|
||||
const Ref<SpineAtlasResource> &atlas) {
|
||||
atlas_res = atlas;
|
||||
if (atlas_res.is_valid()) {
|
||||
#if VERSION_MAJOR > 3
|
||||
if (!atlas_res->is_connected(
|
||||
SNAME("skeleton_atlas_changed"),
|
||||
callable_mp(this,
|
||||
&SpineSkeletonDataResource::update_skeleton_data)))
|
||||
atlas_res->connect(
|
||||
SNAME("skeleton_atlas_changed"),
|
||||
callable_mp(this, &SpineSkeletonDataResource::update_skeleton_data));
|
||||
#else
|
||||
if (!atlas_res->is_connected(SNAME("skeleton_atlas_changed"), this,
|
||||
SNAME("update_skeleton_data")))
|
||||
atlas_res->connect(SNAME("skeleton_atlas_changed"), this,
|
||||
SNAME("update_skeleton_data"));
|
||||
#endif
|
||||
}
|
||||
update_skeleton_data();
|
||||
}
|
||||
|
||||
@ -275,22 +372,6 @@ Ref<SpineAtlasResource> SpineSkeletonDataResource::get_atlas_res() {
|
||||
void SpineSkeletonDataResource::set_skeleton_file_res(
|
||||
const Ref<SpineSkeletonFileResource> &skeleton_file) {
|
||||
skeleton_file_res = skeleton_file;
|
||||
if (skeleton_file_res.is_valid()) {
|
||||
#if VERSION_MAJOR > 3
|
||||
if (!skeleton_file_res->is_connected(
|
||||
SNAME("skeleton_file_changed"),
|
||||
callable_mp(this,
|
||||
&SpineSkeletonDataResource::update_skeleton_data)))
|
||||
skeleton_file_res->connect(
|
||||
SNAME("skeleton_file_changed"),
|
||||
callable_mp(this, &SpineSkeletonDataResource::update_skeleton_data));
|
||||
#else
|
||||
if (!skeleton_file_res->is_connected(SNAME("skeleton_file_changed"), this,
|
||||
SNAME("update_skeleton_data")))
|
||||
skeleton_file_res->connect(SNAME("skeleton_file_changed"), this,
|
||||
SNAME("update_skeleton_data"));
|
||||
#endif
|
||||
}
|
||||
update_skeleton_data();
|
||||
}
|
||||
|
||||
|
||||
@ -209,4 +209,12 @@ public:
|
||||
float get_reference_scale() const;
|
||||
|
||||
void set_reference_scale(float reference_scale);
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
#if VERSION_MAJOR > 3
|
||||
void _on_resources_reimported(const PackedStringArray &resources);
|
||||
#else
|
||||
void _on_resources_reimported(const PoolStringArray &resources);
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -95,7 +95,6 @@ static char *readString(BinaryInput *input) {
|
||||
|
||||
void SpineSkeletonFileResource::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("load_from_file", "path"), &SpineSkeletonFileResource::load_from_file);
|
||||
ADD_SIGNAL(MethodInfo("skeleton_file_changed"));
|
||||
}
|
||||
|
||||
static bool checkVersion(const char *version) {
|
||||
|
||||
@ -1216,8 +1216,9 @@ void SpineSprite::draw() {
|
||||
}
|
||||
|
||||
#if TOOLS_ENABLED
|
||||
float editor_scale = 1.0;
|
||||
if (Engine::get_singleton()->is_editor_hint()) editor_scale = EditorInterface::get_singleton()->get_editor_scale();
|
||||
|
||||
float editor_scale = EditorInterface::get_singleton()->get_editor_scale();
|
||||
float inverse_zoom = 1 / get_viewport()->get_global_canvas_transform().get_scale().x * editor_scale;
|
||||
Vector<String> hover_text_lines;
|
||||
if (hovered_slot) {
|
||||
|
||||
@ -1,18 +0,0 @@
|
||||
[configuration]
|
||||
|
||||
entry_symbol = "spine_godot_library_init"
|
||||
compatibility_minimum = "4.1"
|
||||
|
||||
[libraries]
|
||||
|
||||
macos.editor = "res://bin/macos/macos.framework/libspine_godot.macos.dev.editor"
|
||||
macos.debug = "res://bin/macos/macos.framework/libspine_godot.macos.dev.template_debug"
|
||||
macos.release = "res://bin/macos/macos.framework/libspine_godot.macos.template_release"
|
||||
|
||||
windows.editor.x86_64 = "res://bin/windows/libspine_godot.windows.editor.dev.x86_64.dll"
|
||||
windows.debug.x86_64 = "res://bin/windows/libspine_godot.windows.template_debug.dev.x86_64.dll"
|
||||
windows.release.x86_64 = "res://bin/windows/libspine_godot.windows.template_release.dev.x86_64.dll"
|
||||
|
||||
linux.editor.x86_64 = "res://bin/linux/libspine_godot.linux.editor.dev.x86_64.so"
|
||||
linux.debug.x86_64 = "res://bin/linux/libspine_godot.linux.template_debug.dev.x86_64.so"
|
||||
linux.release.x86_64 = "res://bin/linux/libspine_godot.linux.template_release.dev.x86_64.so"
|
||||
@ -23,12 +23,17 @@ spine-haxe works with data exported from Spine 4.2.xx.
|
||||
spine-haxe supports all Spine features except premultiplied alpha atlases and two color tinting.
|
||||
|
||||
## Setup
|
||||
The core module of spine-haxe has zero dependencies. The rendering implementation through Starling has two dependencies: openfl and starling.
|
||||
The spine-haxe runtime is composed of a core module, that is a Haxe implementation of the renderer-agnostic Spine Runtimes core APIs, and the following specific renderer implementations:
|
||||
- [Starling](https://lib.haxe.org/p/starling/)
|
||||
- [HaxeFlixel](https://lib.haxe.org/p/flixel/) (minimum supported version 5.9.0)
|
||||
|
||||
The core module of spine-haxe has zero dependencies. The rendering implementation depends on: openfl, starling, and flixel.
|
||||
To use spine-haxe you have first to install all the necessary dependencies:
|
||||
|
||||
```
|
||||
haxelib install openfl
|
||||
haxelib install starling
|
||||
haxelib install flixel
|
||||
```
|
||||
|
||||
Once you have installed the dependencies, you can [download the latest version of spine-haxe](https://esotericsoftware.com/files/spine-haxe/4.2/spine-haxe-latest.zip) and install it:
|
||||
@ -60,6 +65,7 @@ To setup the development environment install the following:
|
||||
haxelib install openfl
|
||||
haxelib run openfl setup
|
||||
haxelib install starling
|
||||
haxelib install flixel
|
||||
```
|
||||
3. Clone the `spine-runtimes` repository, and use `haxelib` to setup a dev library:
|
||||
```
|
||||
|
||||
@ -27,24 +27,145 @@
|
||||
* SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import Scene.SceneManager;
|
||||
import openfl.display.Sprite;
|
||||
import openfl.geom.Rectangle;
|
||||
package;
|
||||
|
||||
import flixelExamples.FlixelState;
|
||||
import starlingExamples.BasicExample;
|
||||
import starlingExamples.Scene.SceneManager;
|
||||
import starling.core.Starling;
|
||||
import flixel.FlxG;
|
||||
import flixel.FlxGame;
|
||||
|
||||
import openfl.display.Sprite;
|
||||
import openfl.text.TextField;
|
||||
import openfl.text.TextFormat;
|
||||
import openfl.events.MouseEvent;
|
||||
|
||||
import openfl.geom.Rectangle;
|
||||
import starling.events.Event;
|
||||
|
||||
class Main extends Sprite {
|
||||
private var background:Sprite;
|
||||
private var flixelButton:Sprite;
|
||||
private var starlingButton:Sprite;
|
||||
private var uiContainer:Sprite;
|
||||
|
||||
private static inline var ratio = 4;
|
||||
private static inline var STAGE_WIDTH:Int = 100 * ratio;
|
||||
private static inline var STAGE_HEIGHT:Int = 200 * ratio;
|
||||
private static inline var BUTTON_WIDTH:Int = 80 * ratio;
|
||||
private static inline var BUTTON_HEIGHT:Int = 40 * ratio;
|
||||
private static inline var BUTTON_SPACING:Int = 20 * ratio;
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
|
||||
}
|
||||
|
||||
private function onAddedToStage(e:Event):Void {
|
||||
removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
|
||||
createUI();
|
||||
centerUI();
|
||||
stage.addEventListener(Event.RESIZE, onResize);
|
||||
}
|
||||
|
||||
private function createUI():Void {
|
||||
uiContainer = new Sprite();
|
||||
addChild(uiContainer);
|
||||
|
||||
background = new Sprite();
|
||||
background.graphics.beginFill(0xA2A2A2);
|
||||
background.graphics.drawRect(0, 0, STAGE_WIDTH, STAGE_HEIGHT);
|
||||
background.graphics.endFill();
|
||||
uiContainer.addChild(background);
|
||||
|
||||
flixelButton = createButton("Flixel", 0xFF0000);
|
||||
uiContainer.addChild(flixelButton);
|
||||
|
||||
starlingButton = createButton("Starling", 0x00FF00);
|
||||
uiContainer.addChild(starlingButton);
|
||||
|
||||
positionButtons();
|
||||
|
||||
flixelButton.addEventListener(MouseEvent.CLICK, onFlixelClick);
|
||||
starlingButton.addEventListener(MouseEvent.CLICK, onStarlingClick);
|
||||
}
|
||||
|
||||
private function createButton(label:String, color:Int):Sprite {
|
||||
var button = new Sprite();
|
||||
var g = button.graphics;
|
||||
|
||||
g.beginFill(color);
|
||||
g.drawRoundRect(0, 0, BUTTON_WIDTH, BUTTON_HEIGHT, 10, 10);
|
||||
g.endFill();
|
||||
|
||||
// Add button text
|
||||
var tf = new TextField();
|
||||
var format = new TextFormat("_sans", 14 * ratio, 0x000000, true, null, null, null, null, "center");
|
||||
tf.defaultTextFormat = format;
|
||||
tf.text = label;
|
||||
tf.width = BUTTON_WIDTH;
|
||||
tf.height = BUTTON_HEIGHT;
|
||||
tf.mouseEnabled = false;
|
||||
tf.selectable = false;
|
||||
|
||||
tf.y = (BUTTON_HEIGHT - tf.textHeight) / 2;
|
||||
|
||||
button.addChild(tf);
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
private function positionButtons():Void {
|
||||
var totalHeight = (BUTTON_HEIGHT * 2) + BUTTON_SPACING;
|
||||
var startY = (STAGE_HEIGHT - totalHeight) / 2;
|
||||
|
||||
flixelButton.x = (STAGE_WIDTH - BUTTON_WIDTH) / 2;
|
||||
flixelButton.y = startY + BUTTON_HEIGHT + BUTTON_SPACING;
|
||||
|
||||
starlingButton.x = (STAGE_WIDTH - BUTTON_WIDTH) / 2;
|
||||
starlingButton.y = startY;
|
||||
}
|
||||
|
||||
private function centerUI():Void {
|
||||
uiContainer.x = (stage.stageWidth - STAGE_WIDTH) / 2;
|
||||
uiContainer.y = (stage.stageHeight - STAGE_HEIGHT) / 2;
|
||||
}
|
||||
|
||||
private function onResize(e:Event):Void {
|
||||
centerUI();
|
||||
}
|
||||
|
||||
private function onFlixelClick(e:MouseEvent):Void {
|
||||
trace("Launching Flixel game");
|
||||
destroyUI();
|
||||
addChild(new FlxGame(640, 480, FlixelState));
|
||||
FlxG.autoPause = false;
|
||||
}
|
||||
|
||||
private function destroyUI():Void {
|
||||
flixelButton.removeEventListener(MouseEvent.CLICK, onFlixelClick);
|
||||
starlingButton.removeEventListener(MouseEvent.CLICK, onStarlingClick);
|
||||
stage.removeEventListener(Event.RESIZE, onResize);
|
||||
|
||||
removeChild(uiContainer);
|
||||
|
||||
background = null;
|
||||
flixelButton = null;
|
||||
starlingButton = null;
|
||||
uiContainer = null;
|
||||
}
|
||||
|
||||
private var starlingSingleton:Starling;
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
|
||||
private function onStarlingClick(e:MouseEvent):Void {
|
||||
trace("Launching Starling game");
|
||||
starlingSingleton = new Starling(starling.display.Sprite, stage, new Rectangle(0, 0, 800, 600));
|
||||
starlingSingleton.supportHighResolutions = true;
|
||||
starlingSingleton.addEventListener(Event.ROOT_CREATED, onStarlingRootCreated);
|
||||
}
|
||||
}
|
||||
|
||||
private function onStarlingRootCreated(event:Event):Void {
|
||||
destroyUI();
|
||||
starlingSingleton.removeEventListener(Event.ROOT_CREATED, onStarlingRootCreated);
|
||||
starlingSingleton.start();
|
||||
Starling.current.stage.color = 0x000000;
|
||||
|
||||
45
spine-haxe/example/src/MainFlixel.hx
Normal file
45
spine-haxe/example/src/MainFlixel.hx
Normal file
@ -0,0 +1,45 @@
|
||||
/******************************************************************************
|
||||
* Spine Runtimes License Agreement
|
||||
* Last updated July 28, 2023. Replaces all prior versions.
|
||||
*
|
||||
* Copyright (c) 2013-2023, Esoteric Software LLC
|
||||
*
|
||||
* Integration of the Spine Runtimes into software or otherwise creating
|
||||
* derivative works of the Spine Runtimes is permitted under the terms and
|
||||
* conditions of Section 2 of the Spine Editor License Agreement:
|
||||
* http://esotericsoftware.com/spine-editor-license
|
||||
*
|
||||
* Otherwise, it is permitted to integrate the Spine Runtimes into software or
|
||||
* otherwise create derivative works of the Spine Runtimes (collectively,
|
||||
* "Products"), provided that each user of the Products must obtain their own
|
||||
* Spine Editor license and redistribution of the Products in any form must
|
||||
* include this license and copyright notice.
|
||||
*
|
||||
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
|
||||
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
|
||||
* SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
package;
|
||||
|
||||
import flixelExamples.FlixelState;
|
||||
import flixel.FlxG;
|
||||
import flixel.FlxGame;
|
||||
import openfl.display.Sprite;
|
||||
|
||||
class MainFlixel extends Sprite
|
||||
{
|
||||
public function new()
|
||||
{
|
||||
super();
|
||||
addChild(new FlxGame(640, 480, FlixelState));
|
||||
FlxG.autoPause = false;
|
||||
}
|
||||
}
|
||||
57
spine-haxe/example/src/MainStarling.hx
Normal file
57
spine-haxe/example/src/MainStarling.hx
Normal file
@ -0,0 +1,57 @@
|
||||
/******************************************************************************
|
||||
* Spine Runtimes License Agreement
|
||||
* Last updated July 28, 2023. Replaces all prior versions.
|
||||
*
|
||||
* Copyright (c) 2013-2023, Esoteric Software LLC
|
||||
*
|
||||
* Integration of the Spine Runtimes into software or otherwise creating
|
||||
* derivative works of the Spine Runtimes is permitted under the terms and
|
||||
* conditions of Section 2 of the Spine Editor License Agreement:
|
||||
* http://esotericsoftware.com/spine-editor-license
|
||||
*
|
||||
* Otherwise, it is permitted to integrate the Spine Runtimes into software or
|
||||
* otherwise create derivative works of the Spine Runtimes (collectively,
|
||||
* "Products"), provided that each user of the Products must obtain their own
|
||||
* Spine Editor license and redistribution of the Products in any form must
|
||||
* include this license and copyright notice.
|
||||
*
|
||||
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
|
||||
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
|
||||
* SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
package;
|
||||
|
||||
import starlingExamples.BasicExample;
|
||||
import starlingExamples.Scene.SceneManager;
|
||||
import openfl.display.Sprite;
|
||||
import openfl.geom.Rectangle;
|
||||
import starling.core.Starling;
|
||||
import starling.events.Event;
|
||||
|
||||
class MainStarling extends Sprite {
|
||||
private var starlingSingleton:Starling;
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
|
||||
starlingSingleton = new Starling(starling.display.Sprite, stage, new Rectangle(0, 0, 800, 600));
|
||||
starlingSingleton.supportHighResolutions = true;
|
||||
starlingSingleton.addEventListener(Event.ROOT_CREATED, onStarlingRootCreated);
|
||||
}
|
||||
|
||||
private function onStarlingRootCreated(event:Event):Void {
|
||||
starlingSingleton.removeEventListener(Event.ROOT_CREATED, onStarlingRootCreated);
|
||||
starlingSingleton.start();
|
||||
Starling.current.stage.color = 0x000000;
|
||||
|
||||
SceneManager.getInstance().switchScene(new BasicExample());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,77 @@
|
||||
package flixelExamples;
|
||||
|
||||
|
||||
import flixel.util.FlxColor;
|
||||
import flixel.text.FlxText;
|
||||
import spine.Skin;
|
||||
import flixel.ui.FlxButton;
|
||||
import flixel.FlxG;
|
||||
import spine.flixel.SkeletonSprite;
|
||||
import spine.flixel.FlixelTextureLoader;
|
||||
import flixel.FlxState;
|
||||
import openfl.utils.Assets;
|
||||
import spine.SkeletonData;
|
||||
import spine.animation.AnimationStateData;
|
||||
import spine.atlas.TextureAtlas;
|
||||
|
||||
class AnimationBoundExample extends FlxState {
|
||||
var loadBinary = true;
|
||||
|
||||
override public function create():Void {
|
||||
FlxG.cameras.bgColor = 0xffa1b2b0;
|
||||
|
||||
var button = new FlxButton(0, 0, "Next scene", () -> {
|
||||
FlxG.debugger.drawDebug = false;
|
||||
FlxG.switchState(() -> new ControlBonesExample());
|
||||
});
|
||||
button.setPosition(FlxG.width * .75, FlxG.height / 10);
|
||||
add(button);
|
||||
|
||||
var atlas = new TextureAtlas(Assets.getText("assets/spineboy.atlas"), new FlixelTextureLoader("assets/spineboy.atlas"));
|
||||
var data = SkeletonData.from(loadBinary ? Assets.getBytes("assets/spineboy-pro.skel") : Assets.getText("assets/spineboy-pro.json"), atlas, .2);
|
||||
var animationStateData = new AnimationStateData(data);
|
||||
animationStateData.defaultMix = 0.25;
|
||||
|
||||
var skeletonSpriteClipping = new SkeletonSprite(data, animationStateData);
|
||||
var animationClipping = skeletonSpriteClipping.state.setAnimationByName(0, "portal", true).animation;
|
||||
skeletonSpriteClipping.update(0);
|
||||
skeletonSpriteClipping.setBoundingBox(animationClipping, true);
|
||||
skeletonSpriteClipping.screenCenter();
|
||||
skeletonSpriteClipping.x = FlxG.width / 4 - skeletonSpriteClipping.width / 2;
|
||||
add(skeletonSpriteClipping);
|
||||
var textClipping = new FlxText();
|
||||
textClipping.text = "Animation bound with clipping";
|
||||
textClipping.size = 12;
|
||||
textClipping.x = skeletonSpriteClipping.x + skeletonSpriteClipping.width / 2 - textClipping.width / 2;
|
||||
textClipping.y = skeletonSpriteClipping.y + skeletonSpriteClipping.height + 20;
|
||||
textClipping.setBorderStyle(FlxTextBorderStyle.OUTLINE, FlxColor.RED, 2);
|
||||
add(textClipping);
|
||||
|
||||
var skeletonSpriteNoClipping = new SkeletonSprite(data, animationStateData);
|
||||
var animationClipping = skeletonSpriteNoClipping.state.setAnimationByName(0, "portal", true).animation;
|
||||
skeletonSpriteNoClipping.update(0);
|
||||
skeletonSpriteNoClipping.setBoundingBox(animationClipping, false);
|
||||
skeletonSpriteNoClipping.screenCenter();
|
||||
skeletonSpriteNoClipping.x = FlxG.width / 4 * 3 - skeletonSpriteClipping.width / 2 - 50;
|
||||
add(skeletonSpriteNoClipping);
|
||||
var textNoClipping = new FlxText();
|
||||
textNoClipping.text = "Animation bound without clipping";
|
||||
textNoClipping.size = 12;
|
||||
textNoClipping.x = skeletonSpriteNoClipping.x + skeletonSpriteNoClipping.width / 2 - textNoClipping.width / 2;
|
||||
textNoClipping.y = skeletonSpriteNoClipping.y + skeletonSpriteNoClipping.height + 20;
|
||||
textNoClipping.setBorderStyle(FlxTextBorderStyle.OUTLINE, FlxColor.RED, 2);
|
||||
add(textNoClipping);
|
||||
|
||||
var textInstruction = new FlxText();
|
||||
textInstruction.text = "Red rectangle is the animation bound";
|
||||
textInstruction.size = 12;
|
||||
textInstruction.screenCenter();
|
||||
textInstruction.y = textNoClipping.y + 40;
|
||||
textInstruction.setBorderStyle(FlxTextBorderStyle.OUTLINE, FlxColor.RED, 2);
|
||||
add(textInstruction);
|
||||
|
||||
FlxG.debugger.drawDebug = true;
|
||||
|
||||
super.create();
|
||||
}
|
||||
}
|
||||
87
spine-haxe/example/src/flixelExamples/BasicExample.hx
Normal file
87
spine-haxe/example/src/flixelExamples/BasicExample.hx
Normal file
@ -0,0 +1,87 @@
|
||||
/******************************************************************************
|
||||
* Spine Runtimes License Agreement
|
||||
* Last updated July 28, 2023. Replaces all prior versions.
|
||||
*
|
||||
* Copyright (c) 2013-2023, Esoteric Software LLC
|
||||
*
|
||||
* Integration of the Spine Runtimes into software or otherwise creating
|
||||
* derivative works of the Spine Runtimes is permitted under the terms and
|
||||
* conditions of Section 2 of the Spine Editor License Agreement:
|
||||
* http://esotericsoftware.com/spine-editor-license
|
||||
*
|
||||
* Otherwise, it is permitted to integrate the Spine Runtimes into software or
|
||||
* otherwise create derivative works of the Spine Runtimes (collectively,
|
||||
* "Products"), provided that each user of the Products must obtain their own
|
||||
* Spine Editor license and redistribution of the Products in any form must
|
||||
* include this license and copyright notice.
|
||||
*
|
||||
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
|
||||
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
|
||||
* SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
package flixelExamples;
|
||||
|
||||
import flixel.ui.FlxButton;
|
||||
import flixel.FlxG;
|
||||
import spine.flixel.SkeletonSprite;
|
||||
import spine.flixel.FlixelTextureLoader;
|
||||
import flixel.FlxState;
|
||||
import openfl.utils.Assets;
|
||||
import spine.SkeletonData;
|
||||
import spine.animation.AnimationStateData;
|
||||
import spine.atlas.TextureAtlas;
|
||||
|
||||
class BasicExample extends FlxState {
|
||||
var loadBinary = true;
|
||||
|
||||
var skeletonSprite:SkeletonSprite;
|
||||
override public function create():Void {
|
||||
FlxG.cameras.bgColor = 0xffa1b2b0;
|
||||
|
||||
var button = new FlxButton(0, 0, "Next scene", () -> FlxG.switchState(() -> new SequenceExample()));
|
||||
button.setPosition(FlxG.width * .75, FlxG.height / 10);
|
||||
add(button);
|
||||
|
||||
var atlas = new TextureAtlas(Assets.getText("assets/raptor.atlas"), new FlixelTextureLoader("assets/raptor-pro.atlas"));
|
||||
var skeletondata = SkeletonData.from(loadBinary ? Assets.getBytes("assets/raptor-pro.skel") : Assets.getText("assets/raptor-pro.json"), atlas, .25);
|
||||
var animationStateData = new AnimationStateData(skeletondata);
|
||||
animationStateData.defaultMix = 0.25;
|
||||
|
||||
skeletonSprite = new SkeletonSprite(skeletondata, animationStateData);
|
||||
var animation = skeletonSprite.state.setAnimationByName(0, "walk", true).animation;
|
||||
skeletonSprite.setBoundingBox(animation);
|
||||
skeletonSprite.screenCenter();
|
||||
add(skeletonSprite);
|
||||
|
||||
super.create();
|
||||
|
||||
trace("loaded");
|
||||
}
|
||||
|
||||
override public function update(elapsed:Float):Void
|
||||
{
|
||||
if (FlxG.keys.anyPressed([RIGHT])) {
|
||||
skeletonSprite.x += 15;
|
||||
}
|
||||
if (FlxG.keys.anyPressed([LEFT])) {
|
||||
skeletonSprite.x -= 15;
|
||||
}
|
||||
if (FlxG.keys.anyPressed([DOWN])) {
|
||||
skeletonSprite.y += 15;
|
||||
}
|
||||
if (FlxG.keys.anyPressed([UP])) {
|
||||
skeletonSprite.y -= 15;
|
||||
}
|
||||
|
||||
super.update(elapsed);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,75 @@
|
||||
package flixelExamples;
|
||||
|
||||
|
||||
import flixel.text.FlxText;
|
||||
import flixel.math.FlxPoint;
|
||||
import spine.Skin;
|
||||
import flixel.ui.FlxButton;
|
||||
import flixel.FlxG;
|
||||
import spine.flixel.SkeletonSprite;
|
||||
import spine.flixel.FlixelTextureLoader;
|
||||
import flixel.FlxState;
|
||||
import openfl.utils.Assets;
|
||||
import spine.SkeletonData;
|
||||
import spine.animation.AnimationStateData;
|
||||
import spine.atlas.TextureAtlas;
|
||||
|
||||
class CelestialCircusExample extends FlxState {
|
||||
var loadBinary = true;
|
||||
|
||||
var skeletonSprite:SkeletonSprite;
|
||||
override public function create():Void {
|
||||
FlxG.cameras.bgColor = 0xffa1b2b0;
|
||||
|
||||
var button = new FlxButton(0, 0, "Next scene", () -> FlxG.switchState(() -> new SnowglobeExample()));
|
||||
button.setPosition(FlxG.width * .75, FlxG.height / 10);
|
||||
add(button);
|
||||
|
||||
var atlas = new TextureAtlas(Assets.getText("assets/celestial-circus.atlas"), new FlixelTextureLoader("assets/celestial-circus.atlas"));
|
||||
var data = SkeletonData.from(loadBinary ? Assets.getBytes("assets/celestial-circus-pro.skel") : Assets.getText("assets/celestial-circus-pro.json"), atlas, .15);
|
||||
var animationStateData = new AnimationStateData(data);
|
||||
animationStateData.defaultMix = 0.25;
|
||||
|
||||
skeletonSprite = new SkeletonSprite(data, animationStateData);
|
||||
skeletonSprite.screenCenter();
|
||||
skeletonSprite.state.setAnimationByName(0, "eyeblink-long", true);
|
||||
add(skeletonSprite);
|
||||
|
||||
add(new FlxText(50, 50, 200, "Drag Celeste to move her around", 16));
|
||||
|
||||
super.create();
|
||||
}
|
||||
|
||||
var mousePosition = FlxPoint.get();
|
||||
var dragging:Bool = false;
|
||||
var lastX:Float = 0;
|
||||
var lastY:Float = 0;
|
||||
override public function update(elapsed:Float):Void
|
||||
{
|
||||
super.update(elapsed);
|
||||
|
||||
mousePosition = FlxG.mouse.getPosition();
|
||||
|
||||
if (FlxG.mouse.justPressed && skeletonSprite.overlapsPoint(mousePosition))
|
||||
{
|
||||
dragging = true;
|
||||
lastX = mousePosition.x;
|
||||
lastY = mousePosition.y;
|
||||
}
|
||||
|
||||
if (FlxG.mouse.justReleased) dragging = false;
|
||||
|
||||
if (dragging)
|
||||
{
|
||||
skeletonSprite.x += mousePosition.x - lastX;
|
||||
skeletonSprite.y += mousePosition.y - lastY;
|
||||
skeletonSprite.skeleton.physicsTranslate(
|
||||
mousePosition.x - lastX,
|
||||
mousePosition.y - lastY,
|
||||
);
|
||||
lastX = mousePosition.x;
|
||||
lastY = mousePosition.y;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
37
spine-haxe/example/src/flixelExamples/CloudPotExample.hx
Normal file
37
spine-haxe/example/src/flixelExamples/CloudPotExample.hx
Normal file
@ -0,0 +1,37 @@
|
||||
package flixelExamples;
|
||||
|
||||
|
||||
import spine.Skin;
|
||||
import flixel.ui.FlxButton;
|
||||
import flixel.FlxG;
|
||||
import spine.flixel.SkeletonSprite;
|
||||
import spine.flixel.FlixelTextureLoader;
|
||||
import flixel.FlxState;
|
||||
import openfl.utils.Assets;
|
||||
import spine.SkeletonData;
|
||||
import spine.animation.AnimationStateData;
|
||||
import spine.atlas.TextureAtlas;
|
||||
|
||||
class CloudPotExample extends FlxState {
|
||||
var loadBinary = true;
|
||||
|
||||
override public function create():Void {
|
||||
FlxG.cameras.bgColor = 0xffa1b2b0;
|
||||
|
||||
var button = new FlxButton(0, 0, "Next scene", () -> FlxG.switchState(() -> new AnimationBoundExample()));
|
||||
button.setPosition(FlxG.width * .75, FlxG.height / 10);
|
||||
add(button);
|
||||
|
||||
var atlas = new TextureAtlas(Assets.getText("assets/cloud-pot.atlas"), new FlixelTextureLoader("assets/cloud-pot.atlas"));
|
||||
var data = SkeletonData.from(loadBinary ? Assets.getBytes("assets/cloud-pot.skel") : Assets.getText("assets/cloud-pot.json"), atlas, .25);
|
||||
var animationStateData = new AnimationStateData(data);
|
||||
animationStateData.defaultMix = 0.25;
|
||||
|
||||
var skeletonSprite = new SkeletonSprite(data, animationStateData);
|
||||
skeletonSprite.screenCenter();
|
||||
skeletonSprite.state.setAnimationByName(0, "playing-in-the-rain", true);
|
||||
add(skeletonSprite);
|
||||
|
||||
super.create();
|
||||
}
|
||||
}
|
||||
108
spine-haxe/example/src/flixelExamples/ControlBonesExample.hx
Normal file
108
spine-haxe/example/src/flixelExamples/ControlBonesExample.hx
Normal file
@ -0,0 +1,108 @@
|
||||
package flixelExamples;
|
||||
|
||||
|
||||
import flixel.util.FlxSave;
|
||||
import flixel.math.FlxPoint;
|
||||
import flixel.util.FlxColor;
|
||||
import flixel.util.FlxSpriteUtil;
|
||||
import flixel.FlxSprite;
|
||||
import flixel.ui.FlxButton;
|
||||
import flixel.FlxG;
|
||||
import spine.flixel.SkeletonSprite;
|
||||
import spine.flixel.FlixelTextureLoader;
|
||||
import flixel.FlxState;
|
||||
import openfl.utils.Assets;
|
||||
import spine.SkeletonData;
|
||||
import spine.animation.AnimationStateData;
|
||||
import spine.atlas.TextureAtlas;
|
||||
|
||||
class ControlBonesExample extends FlxState {
|
||||
var loadBinary = true;
|
||||
|
||||
private var controlBones = [];
|
||||
private var controls:Array<FlxSprite> = [];
|
||||
override public function create():Void {
|
||||
FlxG.cameras.bgColor = 0xffa1b2b0;
|
||||
|
||||
var button = new FlxButton(0, 0, "Next scene", () -> FlxG.switchState(() -> new EventsExample()));
|
||||
button.setPosition(FlxG.width * .75, FlxG.height / 10);
|
||||
add(button);
|
||||
|
||||
var atlas = new TextureAtlas(Assets.getText("assets/stretchyman.atlas"), new FlixelTextureLoader("assets/stretchyman.atlas"));
|
||||
var data = SkeletonData.from(loadBinary ? Assets.getBytes("assets/stretchyman-pro.skel") : Assets.getText("assets/stretchyman-pro.json"), atlas);
|
||||
var animationStateData = new AnimationStateData(data);
|
||||
animationStateData.defaultMix = 0.25;
|
||||
|
||||
var skeletonSprite = new SkeletonSprite(data, animationStateData);
|
||||
skeletonSprite.scaleX = .5;
|
||||
skeletonSprite.scaleY = .5;
|
||||
var animation = skeletonSprite.state.setAnimationByName(0, "idle", true).animation;
|
||||
skeletonSprite.setBoundingBox(animation);
|
||||
skeletonSprite.screenCenter();
|
||||
add(skeletonSprite);
|
||||
|
||||
var controlBoneNames = [
|
||||
"back-arm-ik-target",
|
||||
"back-leg-ik-target",
|
||||
"front-arm-ik-target",
|
||||
"front-leg-ik-target",
|
||||
];
|
||||
|
||||
var radius = 6;
|
||||
for (boneName in controlBoneNames) {
|
||||
var bone = skeletonSprite.skeleton.findBone(boneName);
|
||||
var point = [bone.worldX, bone.worldY];
|
||||
skeletonSprite.skeletonToHaxeWorldCoordinates(point);
|
||||
var control = new FlxSprite();
|
||||
control.makeGraphic(radius * 2, radius * 2, FlxColor.TRANSPARENT, true);
|
||||
FlxSpriteUtil.drawCircle(control, radius, radius, radius, 0xffff00ff);
|
||||
control.setPosition(point[0] - radius, point[1] - radius);
|
||||
controlBones.push(bone);
|
||||
controls.push(control);
|
||||
add(control);
|
||||
}
|
||||
|
||||
var point = [.0, .0];
|
||||
skeletonSprite.beforeUpdateWorldTransforms = function (go) {
|
||||
for (i in 0...controls.length) {
|
||||
var bone = controlBones[i];
|
||||
var control = controls[i];
|
||||
point[0] = control.x + radius;
|
||||
point[1] = control.y + radius;
|
||||
go.haxeWorldCoordinatesToBone(point, bone);
|
||||
bone.x = point[0];
|
||||
bone.y = point[1];
|
||||
}
|
||||
};
|
||||
|
||||
super.create();
|
||||
}
|
||||
|
||||
var mousePosition = FlxPoint.get();
|
||||
var offsetX:Float = 0;
|
||||
var offsetY:Float = 0;
|
||||
var sprite:FlxSprite;
|
||||
override public function update(elapsed:Float):Void
|
||||
{
|
||||
super.update(elapsed);
|
||||
|
||||
mousePosition = FlxG.mouse.getPosition();
|
||||
|
||||
for (control in controls) {
|
||||
if (FlxG.mouse.justPressed && control.overlapsPoint(mousePosition))
|
||||
{
|
||||
sprite = control;
|
||||
offsetX = mousePosition.x - sprite.x;
|
||||
offsetY = mousePosition.y - sprite.y;
|
||||
}
|
||||
}
|
||||
|
||||
if (FlxG.mouse.justReleased) sprite = null;
|
||||
|
||||
if (sprite != null)
|
||||
{
|
||||
sprite.x = mousePosition.x - offsetX;
|
||||
sprite.y = mousePosition.y - offsetY;
|
||||
}
|
||||
}
|
||||
}
|
||||
77
spine-haxe/example/src/flixelExamples/EventsExample.hx
Normal file
77
spine-haxe/example/src/flixelExamples/EventsExample.hx
Normal file
@ -0,0 +1,77 @@
|
||||
package flixelExamples;
|
||||
|
||||
|
||||
import flixel.text.FlxText;
|
||||
import flixel.ui.FlxButton;
|
||||
import flixel.FlxG;
|
||||
import flixel.group.FlxSpriteGroup;
|
||||
import spine.flixel.SkeletonSprite;
|
||||
import spine.flixel.FlixelTextureLoader;
|
||||
import flixel.FlxState;
|
||||
import openfl.utils.Assets;
|
||||
import spine.SkeletonData;
|
||||
import spine.animation.AnimationStateData;
|
||||
import spine.atlas.TextureAtlas;
|
||||
|
||||
class EventsExample extends FlxState {
|
||||
var loadBinary = true;
|
||||
|
||||
override public function create():Void {
|
||||
FlxG.cameras.bgColor = 0xffa1b2b0;
|
||||
|
||||
var button = new FlxButton(0, 0, "Next scene", () -> FlxG.switchState(() -> new FlixelState()));
|
||||
button.setPosition(FlxG.width * .75, FlxG.height / 10);
|
||||
add(button);
|
||||
|
||||
var atlas = new TextureAtlas(Assets.getText("assets/spineboy.atlas"), new FlixelTextureLoader("assets/spineboy.atlas"));
|
||||
var data = SkeletonData.from(loadBinary ? Assets.getBytes("assets/spineboy-pro.skel") : Assets.getText("assets/spineboy-pro.json"), atlas, .25);
|
||||
var animationStateData = new AnimationStateData(data);
|
||||
animationStateData.defaultMix = 0.25;
|
||||
|
||||
var skeletonSprite = new SkeletonSprite(data, animationStateData);
|
||||
|
||||
// add callback to the AnimationState
|
||||
skeletonSprite.state.onStart.add(entry -> log('Started animation ${entry.animation.name}'));
|
||||
skeletonSprite.state.onInterrupt.add(entry -> log('Interrupted animation ${entry.animation.name}'));
|
||||
skeletonSprite.state.onEnd.add(entry -> log('Ended animation ${entry.animation.name}'));
|
||||
skeletonSprite.state.onDispose.add(entry -> log('Disposed animation ${entry.animation.name}'));
|
||||
skeletonSprite.state.onComplete.add(entry -> log('Completed animation ${entry.animation.name}'));
|
||||
|
||||
skeletonSprite.state.setAnimationByName(0, "walk", true);
|
||||
|
||||
var trackEntry = skeletonSprite.state.addAnimationByName(0, "run", true, 3);
|
||||
skeletonSprite.setBoundingBox(trackEntry.animation);
|
||||
|
||||
skeletonSprite.setBoundingBox();
|
||||
skeletonSprite.screenCenter();
|
||||
skeletonSprite.skeleton.setBonesToSetupPose();
|
||||
add(skeletonSprite);
|
||||
|
||||
trackEntry.onEvent.add(
|
||||
(entry, event) -> log('Custom event for ${entry.animation.name}: ${event.data.name}'));
|
||||
|
||||
|
||||
add(textContainer);
|
||||
super.create();
|
||||
}
|
||||
|
||||
private var textContainer = new FlxSpriteGroup();
|
||||
private var logs = new Array<FlxText>();
|
||||
private var logsNumber = 0;
|
||||
private var yOffset = 12;
|
||||
private function log(text:String) {
|
||||
var length = logs.length;
|
||||
var newLog = new FlxText(250, 30, text);
|
||||
newLog.x = 50;
|
||||
newLog.y = 20 + yOffset * logsNumber++;
|
||||
newLog.color = 0xffffffff;
|
||||
textContainer.add(newLog);
|
||||
if (logs.length < 35) {
|
||||
logs.push(newLog);
|
||||
} else {
|
||||
logs.shift().destroy();
|
||||
logs.push(newLog);
|
||||
textContainer.y -= yOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
195
spine-haxe/example/src/flixelExamples/FlixelState.hx
Normal file
195
spine-haxe/example/src/flixelExamples/FlixelState.hx
Normal file
@ -0,0 +1,195 @@
|
||||
package flixelExamples;
|
||||
|
||||
import flixel.ui.FlxButton;
|
||||
import flixel.group.FlxSpriteGroup;
|
||||
import flixel.FlxSprite;
|
||||
import flixel.graphics.FlxGraphic;
|
||||
import spine.animation.AnimationStateData;
|
||||
import openfl.Assets;
|
||||
import spine.atlas.TextureAtlas;
|
||||
import spine.SkeletonData;
|
||||
import spine.flixel.SkeletonSprite;
|
||||
import spine.flixel.FlixelTextureLoader;
|
||||
import flixel.FlxG;
|
||||
import flixel.FlxState;
|
||||
import flixel.text.FlxText;
|
||||
|
||||
class FlixelState extends FlxState
|
||||
{
|
||||
var spineSprite:SkeletonSprite;
|
||||
var sprite:FlxSprite;
|
||||
var sprite2:FlxSprite;
|
||||
var myText:FlxText;
|
||||
var group:FlxSpriteGroup;
|
||||
var justSetWalking = false;
|
||||
|
||||
var jumping = false;
|
||||
|
||||
var scale = 4;
|
||||
var speed:Float;
|
||||
|
||||
override public function create():Void
|
||||
{
|
||||
FlxG.cameras.bgColor = 0xffa1b2b0;
|
||||
|
||||
// setting speed of spineboy (450 is the speed to not let him slide)
|
||||
speed = 450 / scale;
|
||||
|
||||
// creating a group
|
||||
group = new FlxSpriteGroup();
|
||||
group.setPosition(50, 50);
|
||||
add(group);
|
||||
|
||||
// creating the sprite to check overlapping
|
||||
sprite = new FlxSprite();
|
||||
sprite.loadGraphic(FlxGraphic.fromRectangle(150, 100, 0xff8d008d));
|
||||
group.add(sprite);
|
||||
|
||||
// creating the text to display overlapping state
|
||||
myText = new FlxText(0, 25, 150, "", 16);
|
||||
myText.alignment = CENTER;
|
||||
group.add(myText);
|
||||
|
||||
var button = new FlxButton(0, 0, "Next scene", () -> FlxG.switchState(() -> new BasicExample()));
|
||||
button.setPosition(FlxG.width * .75, FlxG.height / 10);
|
||||
add(button);
|
||||
|
||||
// creating a sprite for the floor
|
||||
var floor = new FlxSprite();
|
||||
floor.loadGraphic(FlxGraphic.fromRectangle(FlxG.width, FlxG.height - 100, 0xff822f02));
|
||||
floor.y = FlxG.height - 100;
|
||||
add(floor);
|
||||
|
||||
// instructions
|
||||
var groupInstructions = new FlxSpriteGroup();
|
||||
groupInstructions.setPosition(50, 405);
|
||||
groupInstructions.add(new FlxText(0, 0, 200, "Left/Right - Move", 16));
|
||||
groupInstructions.add(new FlxText(0, 25, 150, "Space - Jump", 16));
|
||||
groupInstructions.add(new FlxText(200, 25, 400, "Click the button for the next example", 16));
|
||||
add(groupInstructions);
|
||||
|
||||
// loading spineboy
|
||||
var atlas = new TextureAtlas(Assets.getText("assets/spineboy.atlas"), new FlixelTextureLoader("assets/spineboy.atlas"));
|
||||
var skeletondata = SkeletonData.from(Assets.getText("assets/spineboy-pro.json"), atlas, 1/scale);
|
||||
var animationStateData = new AnimationStateData(skeletondata);
|
||||
spineSprite = new SkeletonSprite(skeletondata, animationStateData);
|
||||
|
||||
// positioning spineboy
|
||||
spineSprite.setPosition(.5 * FlxG.width, .5 * FlxG.height);
|
||||
|
||||
// setting mix times
|
||||
animationStateData.defaultMix = 0.5;
|
||||
animationStateData.setMixByName("idle", "walk", 0.1);
|
||||
animationStateData.setMixByName("walk", "idle", 0.1);
|
||||
animationStateData.setMixByName("idle", "idle-turn", 0.05);
|
||||
animationStateData.setMixByName("idle-turn", "idle", 0.05);
|
||||
animationStateData.setMixByName("idle-turn", "walk", 0.3);
|
||||
animationStateData.setMixByName("idle", "jump", 0);
|
||||
animationStateData.setMixByName("jump", "idle", 0.05);
|
||||
animationStateData.setMixByName("jump", "walk", 0.05);
|
||||
animationStateData.setMixByName("walk", "jump", 0.05);
|
||||
|
||||
// setting idle animation
|
||||
spineSprite.state.setAnimationByName(0, "idle", true);
|
||||
|
||||
// setting y offset function to move object body while jumping
|
||||
var hip = spineSprite.skeleton.findBone("hip");
|
||||
var initialY = 0.;
|
||||
var initialOffsetY = 0.;
|
||||
spineSprite.state.onStart.add(entry -> {
|
||||
if (entry.animation.name == "jump") {
|
||||
initialY = spineSprite.y;
|
||||
initialOffsetY = spineSprite.offsetY;
|
||||
}
|
||||
});
|
||||
spineSprite.state.onComplete.add(entry -> {
|
||||
if (entry.animation.name == "jump") {
|
||||
jumping = false;
|
||||
spineSprite.y = initialY;
|
||||
spineSprite.offsetY = initialOffsetY;
|
||||
}
|
||||
});
|
||||
var diff = .0;
|
||||
spineSprite.afterUpdateWorldTransforms = spineSprite -> {
|
||||
if (jumping) {
|
||||
diff -= hip.y;
|
||||
spineSprite.offsetY -= diff;
|
||||
spineSprite.y += diff;
|
||||
}
|
||||
diff = hip.y;
|
||||
}
|
||||
|
||||
// adding spineboy to the stage
|
||||
add(spineSprite);
|
||||
|
||||
// FlxG.debugger.visible = !FlxG.debugger.visible;
|
||||
// debug ui
|
||||
// FlxG.debugger.visible = true;
|
||||
// FlxG.debugger.drawDebug = true;
|
||||
// FlxG.log.redirectTraces = true;
|
||||
|
||||
// FlxG.debugger.track(spineSprite);
|
||||
// FlxG.watch.add(spineSprite, "width");
|
||||
// FlxG.watch.add(spineSprite, "offsetY");
|
||||
// FlxG.watch.add(spineSprite, "y");
|
||||
// FlxG.watch.add(this, "jumping");
|
||||
super.create();
|
||||
}
|
||||
|
||||
var justSetIdle = true;
|
||||
override public function update(elapsed:Float):Void
|
||||
{
|
||||
if (FlxG.overlap(spineSprite, group)) {
|
||||
myText.text = "Overlapping";
|
||||
} else {
|
||||
myText.text = "Non overlapping";
|
||||
}
|
||||
|
||||
if (!jumping && FlxG.keys.anyJustPressed([SPACE])) {
|
||||
spineSprite.state.setAnimationByName(0, "jump", false);
|
||||
jumping = true;
|
||||
justSetIdle = false;
|
||||
justSetWalking = false;
|
||||
}
|
||||
|
||||
if (FlxG.keys.anyJustPressed([J])) {
|
||||
// spineSprite.antialiasing = !spineSprite.antialiasing;
|
||||
FlxG.debugger.visible = !FlxG.debugger.visible;
|
||||
}
|
||||
|
||||
if (FlxG.keys.anyPressed([RIGHT, LEFT])) {
|
||||
justSetIdle = false;
|
||||
var flipped = false;
|
||||
var deltaX;
|
||||
if (FlxG.keys.anyPressed([RIGHT])) {
|
||||
if (spineSprite.flipX == true) flipped = true;
|
||||
spineSprite.flipX = false;
|
||||
}
|
||||
if (FlxG.keys.anyPressed([LEFT])) {
|
||||
if (spineSprite.flipX == false) flipped = true;
|
||||
spineSprite.flipX = true;
|
||||
}
|
||||
|
||||
deltaX = (spineSprite.flipX == false ? 1 : -1) * speed * elapsed;
|
||||
spineSprite.x += deltaX;
|
||||
|
||||
if (!jumping && !justSetWalking) {
|
||||
justSetWalking = true;
|
||||
if (flipped) {
|
||||
spineSprite.state.setAnimationByName(0, "idle-turn", false);
|
||||
spineSprite.state.addAnimationByName(0, "walk", true, 0);
|
||||
} else {
|
||||
spineSprite.state.setAnimationByName(0, "walk", true);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (!jumping && !justSetIdle) {
|
||||
justSetWalking = false;
|
||||
justSetIdle = true;
|
||||
spineSprite.state.setAnimationByName(0, "idle", true);
|
||||
}
|
||||
|
||||
|
||||
super.update(elapsed);
|
||||
}
|
||||
}
|
||||
55
spine-haxe/example/src/flixelExamples/MixAndMatchExample.hx
Normal file
55
spine-haxe/example/src/flixelExamples/MixAndMatchExample.hx
Normal file
@ -0,0 +1,55 @@
|
||||
package flixelExamples;
|
||||
|
||||
|
||||
import spine.Skin;
|
||||
import flixel.ui.FlxButton;
|
||||
import flixel.FlxG;
|
||||
import spine.flixel.SkeletonSprite;
|
||||
import spine.flixel.FlixelTextureLoader;
|
||||
import flixel.FlxState;
|
||||
import openfl.utils.Assets;
|
||||
import spine.SkeletonData;
|
||||
import spine.animation.AnimationStateData;
|
||||
import spine.atlas.TextureAtlas;
|
||||
|
||||
class MixAndMatchExample extends FlxState {
|
||||
var loadBinary = false;
|
||||
// var loadBinary = true;
|
||||
|
||||
var skeletonSprite:SkeletonSprite;
|
||||
override public function create():Void {
|
||||
FlxG.cameras.bgColor = 0xffa1b2b0;
|
||||
|
||||
var button = new FlxButton(0, 0, "Next scene", () -> FlxG.switchState(() -> new TankExample()));
|
||||
button.setPosition(FlxG.width * .75, FlxG.height / 10);
|
||||
add(button);
|
||||
|
||||
var atlas = new TextureAtlas(Assets.getText("assets/mix-and-match.atlas"), new FlixelTextureLoader("assets/mix-and-match.atlas"));
|
||||
var data = SkeletonData.from(loadBinary ? Assets.getBytes("assets/mix-and-match-pro.skel") : Assets.getText("assets/mix-and-match-pro.json"), atlas, .5);
|
||||
var animationStateData = new AnimationStateData(data);
|
||||
animationStateData.defaultMix = 0.25;
|
||||
|
||||
skeletonSprite = new SkeletonSprite(data, animationStateData);
|
||||
var customSkin = new Skin("custom");
|
||||
var skinBase = data.findSkin("skin-base");
|
||||
customSkin.addSkin(skinBase);
|
||||
customSkin.addSkin(data.findSkin("nose/short"));
|
||||
customSkin.addSkin(data.findSkin("eyelids/girly"));
|
||||
customSkin.addSkin(data.findSkin("eyes/violet"));
|
||||
customSkin.addSkin(data.findSkin("hair/brown"));
|
||||
customSkin.addSkin(data.findSkin("clothes/hoodie-orange"));
|
||||
customSkin.addSkin(data.findSkin("legs/pants-jeans"));
|
||||
customSkin.addSkin(data.findSkin("accessories/bag"));
|
||||
customSkin.addSkin(data.findSkin("accessories/hat-red-yellow"));
|
||||
skeletonSprite.skeleton.skin = customSkin;
|
||||
|
||||
skeletonSprite.state.update(0);
|
||||
var animation = skeletonSprite.state.setAnimationByName(0, "dance", true).animation;
|
||||
skeletonSprite.setBoundingBox(animation);
|
||||
skeletonSprite.screenCenter();
|
||||
add(skeletonSprite);
|
||||
|
||||
super.create();
|
||||
}
|
||||
|
||||
}
|
||||
38
spine-haxe/example/src/flixelExamples/SackExample.hx
Normal file
38
spine-haxe/example/src/flixelExamples/SackExample.hx
Normal file
@ -0,0 +1,38 @@
|
||||
package flixelExamples;
|
||||
|
||||
|
||||
import spine.Skin;
|
||||
import flixel.ui.FlxButton;
|
||||
import flixel.FlxG;
|
||||
import spine.flixel.SkeletonSprite;
|
||||
import spine.flixel.FlixelTextureLoader;
|
||||
import flixel.FlxState;
|
||||
import openfl.utils.Assets;
|
||||
import spine.SkeletonData;
|
||||
import spine.animation.AnimationStateData;
|
||||
import spine.atlas.TextureAtlas;
|
||||
|
||||
class SackExample extends FlxState {
|
||||
var loadBinary = false;
|
||||
|
||||
override public function create():Void {
|
||||
FlxG.cameras.bgColor = 0xffa1b2b0;
|
||||
|
||||
var button = new FlxButton(0, 0, "Next scene", () -> FlxG.switchState(() -> new CelestialCircusExample()));
|
||||
button.setPosition(FlxG.width * .75, FlxG.height / 10);
|
||||
add(button);
|
||||
|
||||
var atlas = new TextureAtlas(Assets.getText("assets/sack.atlas"), new FlixelTextureLoader("assets/sack.atlas"));
|
||||
var data = SkeletonData.from(loadBinary ? Assets.getBytes("assets/sack-pro.skel") : Assets.getText("assets/sack-pro.json"), atlas, .25);
|
||||
var animationStateData = new AnimationStateData(data);
|
||||
animationStateData.defaultMix = 0.25;
|
||||
|
||||
var skeletonSprite = new SkeletonSprite(data, animationStateData);
|
||||
skeletonSprite.screenCenter();
|
||||
skeletonSprite.x -= 100;
|
||||
skeletonSprite.state.setAnimationByName(0, "cape-follow-example", true);
|
||||
add(skeletonSprite);
|
||||
|
||||
super.create();
|
||||
}
|
||||
}
|
||||
39
spine-haxe/example/src/flixelExamples/SequenceExample.hx
Normal file
39
spine-haxe/example/src/flixelExamples/SequenceExample.hx
Normal file
@ -0,0 +1,39 @@
|
||||
package flixelExamples;
|
||||
|
||||
|
||||
import flixel.ui.FlxButton;
|
||||
import flixel.FlxG;
|
||||
import spine.flixel.SkeletonSprite;
|
||||
import spine.flixel.FlixelTextureLoader;
|
||||
import flixel.FlxState;
|
||||
import openfl.utils.Assets;
|
||||
import spine.SkeletonData;
|
||||
import spine.animation.AnimationStateData;
|
||||
import spine.atlas.TextureAtlas;
|
||||
|
||||
class SequenceExample extends FlxState {
|
||||
var loadBinary = true;
|
||||
|
||||
var skeletonSprite:SkeletonSprite;
|
||||
override public function create():Void {
|
||||
FlxG.cameras.bgColor = 0xffa1b2b0;
|
||||
|
||||
var button = new FlxButton(0, 0, "Next scene", () -> FlxG.switchState(() -> new MixAndMatchExample()));
|
||||
button.setPosition(FlxG.width * .75, FlxG.height / 10);
|
||||
add(button);
|
||||
|
||||
var atlas = new TextureAtlas(Assets.getText("assets/dragon.atlas"), new FlixelTextureLoader("assets/dragon.atlas"));
|
||||
var skeletondata = SkeletonData.from(loadBinary ? Assets.getBytes("assets/dragon-ess.skel") : Assets.getText("assets/dragon-.json"), atlas, .5);
|
||||
var animationStateData = new AnimationStateData(skeletondata);
|
||||
animationStateData.defaultMix = 0.25;
|
||||
|
||||
skeletonSprite = new SkeletonSprite(skeletondata, animationStateData);
|
||||
|
||||
var animation = skeletonSprite.state.setAnimationByName(0, "flying", true).animation;
|
||||
skeletonSprite.setBoundingBox(animation);
|
||||
skeletonSprite.screenCenter();
|
||||
add(skeletonSprite);
|
||||
super.create();
|
||||
}
|
||||
|
||||
}
|
||||
37
spine-haxe/example/src/flixelExamples/SnowglobeExample.hx
Normal file
37
spine-haxe/example/src/flixelExamples/SnowglobeExample.hx
Normal file
@ -0,0 +1,37 @@
|
||||
package flixelExamples;
|
||||
|
||||
|
||||
import spine.Skin;
|
||||
import flixel.ui.FlxButton;
|
||||
import flixel.FlxG;
|
||||
import spine.flixel.SkeletonSprite;
|
||||
import spine.flixel.FlixelTextureLoader;
|
||||
import flixel.FlxState;
|
||||
import openfl.utils.Assets;
|
||||
import spine.SkeletonData;
|
||||
import spine.animation.AnimationStateData;
|
||||
import spine.atlas.TextureAtlas;
|
||||
|
||||
class SnowglobeExample extends FlxState {
|
||||
var loadBinary = false;
|
||||
|
||||
override public function create():Void {
|
||||
FlxG.cameras.bgColor = 0xffa1b2b0;
|
||||
|
||||
var button = new FlxButton(0, 0, "Next scene", () -> FlxG.switchState(() -> new CloudPotExample()));
|
||||
button.setPosition(FlxG.width * .75, FlxG.height / 10);
|
||||
add(button);
|
||||
|
||||
var atlas = new TextureAtlas(Assets.getText("assets/snowglobe.atlas"), new FlixelTextureLoader("assets/snowglobe.atlas"));
|
||||
var data = SkeletonData.from(loadBinary ? Assets.getBytes("assets/snowglobe-pro.skel") : Assets.getText("assets/snowglobe-pro.json"), atlas, .125);
|
||||
var animationStateData = new AnimationStateData(data);
|
||||
animationStateData.defaultMix = 0.25;
|
||||
|
||||
var skeletonSprite = new SkeletonSprite(data, animationStateData);
|
||||
skeletonSprite.screenCenter();
|
||||
skeletonSprite.state.setAnimationByName(0, "shake", true);
|
||||
add(skeletonSprite);
|
||||
|
||||
super.create();
|
||||
}
|
||||
}
|
||||
38
spine-haxe/example/src/flixelExamples/TankExample.hx
Normal file
38
spine-haxe/example/src/flixelExamples/TankExample.hx
Normal file
@ -0,0 +1,38 @@
|
||||
package flixelExamples;
|
||||
|
||||
|
||||
import spine.Skin;
|
||||
import flixel.ui.FlxButton;
|
||||
import flixel.FlxG;
|
||||
import spine.flixel.SkeletonSprite;
|
||||
import spine.flixel.FlixelTextureLoader;
|
||||
import flixel.FlxState;
|
||||
import openfl.utils.Assets;
|
||||
import spine.SkeletonData;
|
||||
import spine.animation.AnimationStateData;
|
||||
import spine.atlas.TextureAtlas;
|
||||
|
||||
class TankExample extends FlxState {
|
||||
var loadBinary = true;
|
||||
|
||||
override public function create():Void {
|
||||
FlxG.cameras.bgColor = 0xffa1b2b0;
|
||||
|
||||
var button = new FlxButton(0, 0, "Next scene", () -> FlxG.switchState(() -> new VineExample()));
|
||||
button.setPosition(FlxG.width * .75, FlxG.height / 10);
|
||||
add(button);
|
||||
|
||||
var atlas = new TextureAtlas(Assets.getText("assets/tank.atlas"), new FlixelTextureLoader("assets/tank.atlas"));
|
||||
var data = SkeletonData.from(loadBinary ? Assets.getBytes("assets/tank-pro.skel") : Assets.getText("assets/tank-pro.json"), atlas, .125);
|
||||
var animationStateData = new AnimationStateData(data);
|
||||
animationStateData.defaultMix = 0.25;
|
||||
|
||||
var skeletonSprite = new SkeletonSprite(data, animationStateData);
|
||||
var animation = skeletonSprite.state.setAnimationByName(0, "drive", true).animation;
|
||||
skeletonSprite.setBoundingBox(animation);
|
||||
skeletonSprite.screenCenter();
|
||||
add(skeletonSprite);
|
||||
|
||||
super.create();
|
||||
}
|
||||
}
|
||||
38
spine-haxe/example/src/flixelExamples/VineExample.hx
Normal file
38
spine-haxe/example/src/flixelExamples/VineExample.hx
Normal file
@ -0,0 +1,38 @@
|
||||
package flixelExamples;
|
||||
|
||||
|
||||
import spine.Skin;
|
||||
import flixel.ui.FlxButton;
|
||||
import flixel.FlxG;
|
||||
import spine.flixel.SkeletonSprite;
|
||||
import spine.flixel.FlixelTextureLoader;
|
||||
import flixel.FlxState;
|
||||
import openfl.utils.Assets;
|
||||
import spine.SkeletonData;
|
||||
import spine.animation.AnimationStateData;
|
||||
import spine.atlas.TextureAtlas;
|
||||
|
||||
class VineExample extends FlxState {
|
||||
var loadBinary = true;
|
||||
|
||||
override public function create():Void {
|
||||
FlxG.cameras.bgColor = 0xffa1b2b0;
|
||||
|
||||
var button = new FlxButton(0, 0, "Next scene", () -> FlxG.switchState(() -> new SackExample()));
|
||||
button.setPosition(FlxG.width * .75, FlxG.height / 10);
|
||||
add(button);
|
||||
|
||||
var atlas = new TextureAtlas(Assets.getText("assets/vine.atlas"), new FlixelTextureLoader("assets/vine.atlas"));
|
||||
var data = SkeletonData.from(loadBinary ? Assets.getBytes("assets/vine-pro.skel") : Assets.getText("assets/vine-pro.json"), atlas, .4);
|
||||
var animationStateData = new AnimationStateData(data);
|
||||
animationStateData.defaultMix = 0.25;
|
||||
|
||||
var skeletonSprite = new SkeletonSprite(data, animationStateData);
|
||||
var animation = skeletonSprite.state.setAnimationByName(0, "grow", true).animation;
|
||||
skeletonSprite.setBoundingBox(animation);
|
||||
skeletonSprite.screenCenter();
|
||||
add(skeletonSprite);
|
||||
|
||||
super.create();
|
||||
}
|
||||
}
|
||||
@ -27,7 +27,9 @@
|
||||
* SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import Scene.SceneManager;
|
||||
package starlingExamples;
|
||||
|
||||
import starlingExamples.Scene.SceneManager;
|
||||
import openfl.utils.Assets;
|
||||
import spine.SkeletonData;
|
||||
import spine.Physics;
|
||||
@ -56,17 +58,17 @@ class AnimationBoundExample extends Scene {
|
||||
|
||||
skeletonSpriteClipping = new SkeletonSprite(skeletondata, animationStateDataClipping);
|
||||
skeletonSpriteClipping.skeleton.updateWorldTransform(Physics.update);
|
||||
|
||||
|
||||
skeletonSpriteClipping.scale = scale;
|
||||
skeletonSpriteClipping.x = Starling.current.stage.stageWidth / 3 * 2;
|
||||
skeletonSpriteClipping.y = Starling.current.stage.stageHeight / 2;
|
||||
|
||||
|
||||
var animationClipping = skeletonSpriteClipping.state.setAnimationByName(0, "portal", true).animation;
|
||||
var animationBoundClipping = skeletonSpriteClipping.getAnimationBounds(animationClipping, true);
|
||||
var quad:Quad = new Quad(animationBoundClipping.width * scale, animationBoundClipping.height * scale, 0xc70000);
|
||||
quad.x = skeletonSpriteClipping.x + animationBoundClipping.x * scale;
|
||||
quad.y = skeletonSpriteClipping.y + animationBoundClipping.y * scale;
|
||||
|
||||
|
||||
var animationStateDataNoClipping = new AnimationStateData(skeletondata);
|
||||
animationStateDataNoClipping.defaultMix = 0.25;
|
||||
skeletonSpriteNoClipping = new SkeletonSprite(skeletondata, animationStateDataNoClipping);
|
||||
@ -83,7 +85,7 @@ class AnimationBoundExample extends Scene {
|
||||
|
||||
addChild(quad);
|
||||
addChild(quadNoClipping);
|
||||
addChild(skeletonSpriteClipping);
|
||||
addChild(skeletonSpriteClipping);
|
||||
addChild(skeletonSpriteNoClipping);
|
||||
addText("Animation bound without clipping", 75, 350);
|
||||
addText("Animation bound with clipping", 370, 350);
|
||||
@ -27,7 +27,9 @@
|
||||
* SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import Scene.SceneManager;
|
||||
package starlingExamples;
|
||||
|
||||
import starlingExamples.Scene.SceneManager;
|
||||
import openfl.utils.Assets;
|
||||
import spine.SkeletonData;
|
||||
import spine.animation.AnimationStateData;
|
||||
@ -27,8 +27,10 @@
|
||||
* SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
package starlingExamples;
|
||||
|
||||
import spine.BlendMode;
|
||||
import Scene.SceneManager;
|
||||
import starlingExamples.Scene.SceneManager;
|
||||
import openfl.utils.Assets;
|
||||
import spine.SkeletonData;
|
||||
import spine.Physics;
|
||||
@ -27,8 +27,10 @@
|
||||
* SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
package starlingExamples;
|
||||
|
||||
import spine.BlendMode;
|
||||
import Scene.SceneManager;
|
||||
import starlingExamples.Scene.SceneManager;
|
||||
import openfl.utils.Assets;
|
||||
import spine.SkeletonData;
|
||||
import spine.Physics;
|
||||
@ -56,11 +58,11 @@ class CloudPotExample extends Scene {
|
||||
skeletonSprite.skeleton.updateWorldTransform(Physics.update);
|
||||
var bounds = skeletonSprite.skeleton.getBounds();
|
||||
|
||||
|
||||
|
||||
skeletonSprite.scale = 0.2;
|
||||
skeletonSprite.x = Starling.current.stage.stageWidth / 2;
|
||||
skeletonSprite.y = Starling.current.stage.stageHeight / 2;
|
||||
|
||||
|
||||
skeletonSprite.state.setAnimationByName(0, "playing-in-the-rain", true);
|
||||
|
||||
addChild(skeletonSprite);
|
||||
@ -27,8 +27,10 @@
|
||||
* SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
package starlingExamples;
|
||||
|
||||
import openfl.geom.Point;
|
||||
import Scene.SceneManager;
|
||||
import starlingExamples.Scene.SceneManager;
|
||||
import openfl.utils.Assets;
|
||||
import spine.SkeletonData;
|
||||
import spine.animation.AnimationStateData;
|
||||
@ -42,7 +44,7 @@ import starling.display.Canvas;
|
||||
|
||||
class ControlBonesExample extends Scene {
|
||||
var loadBinary = true;
|
||||
|
||||
|
||||
var skeletonSprite:SkeletonSprite;
|
||||
private var movement = new openfl.geom.Point();
|
||||
private var controlBones = [];
|
||||
@ -133,7 +135,7 @@ class ControlBonesExample extends Scene {
|
||||
skeletonSprite.skeleton.y += movement.y / skeletonSprite.scale;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (touchBackground) {
|
||||
var sceneTouch = e.getTouch(this);
|
||||
if (sceneTouch != null && sceneTouch.phase == TouchPhase.ENDED) {
|
||||
@ -27,8 +27,10 @@
|
||||
* SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
package starlingExamples;
|
||||
|
||||
import spine.animation.TrackEntry;
|
||||
import Scene.SceneManager;
|
||||
import starlingExamples.Scene.SceneManager;
|
||||
import openfl.utils.Assets;
|
||||
import spine.SkeletonData;
|
||||
import spine.animation.AnimationStateData;
|
||||
@ -27,8 +27,10 @@
|
||||
* SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
package starlingExamples;
|
||||
|
||||
import spine.Skin;
|
||||
import Scene.SceneManager;
|
||||
import starlingExamples.Scene.SceneManager;
|
||||
import openfl.utils.Assets;
|
||||
import spine.SkeletonData;
|
||||
import spine.animation.AnimationStateData;
|
||||
@ -27,7 +27,9 @@
|
||||
* SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import Scene.SceneManager;
|
||||
package starlingExamples;
|
||||
|
||||
import starlingExamples.Scene.SceneManager;
|
||||
import openfl.utils.Assets;
|
||||
import spine.SkeletonData;
|
||||
import spine.Physics;
|
||||
@ -53,11 +55,11 @@ class SackExample extends Scene {
|
||||
|
||||
var skeletonSprite = new SkeletonSprite(skeletondata, animationStateData);
|
||||
skeletonSprite.skeleton.updateWorldTransform(Physics.update);
|
||||
|
||||
|
||||
skeletonSprite.scale = 0.2;
|
||||
skeletonSprite.x = Starling.current.stage.stageWidth / 2;
|
||||
skeletonSprite.y = Starling.current.stage.stageHeight/ 2;
|
||||
|
||||
|
||||
skeletonSprite.state.setAnimationByName(0, "cape-follow-example", true);
|
||||
|
||||
addChild(skeletonSprite);
|
||||
@ -27,6 +27,8 @@
|
||||
* SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
package starlingExamples;
|
||||
|
||||
import starling.display.Quad;
|
||||
import starling.text.TextField;
|
||||
import starling.core.Starling;
|
||||
@ -27,7 +27,9 @@
|
||||
* SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import Scene.SceneManager;
|
||||
package starlingExamples;
|
||||
|
||||
import starlingExamples.Scene.SceneManager;
|
||||
import openfl.utils.Assets;
|
||||
import spine.SkeletonData;
|
||||
import spine.animation.AnimationStateData;
|
||||
@ -27,7 +27,9 @@
|
||||
* SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import Scene.SceneManager;
|
||||
package starlingExamples;
|
||||
|
||||
import starlingExamples.Scene.SceneManager;
|
||||
import openfl.utils.Assets;
|
||||
import spine.SkeletonData;
|
||||
import spine.Physics;
|
||||
@ -55,11 +57,11 @@ class SnowglobeExample extends Scene {
|
||||
skeletonSprite.skeleton.updateWorldTransform(Physics.update);
|
||||
var bounds = skeletonSprite.skeleton.getBounds();
|
||||
|
||||
|
||||
|
||||
skeletonSprite.scale = 0.15;
|
||||
skeletonSprite.x = Starling.current.stage.stageWidth / 2;
|
||||
skeletonSprite.y = Starling.current.stage.stageHeight/ 1.5;
|
||||
|
||||
|
||||
skeletonSprite.state.setAnimationByName(0, "shake", true);
|
||||
|
||||
addChild(skeletonSprite);
|
||||
@ -27,7 +27,9 @@
|
||||
* SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import Scene.SceneManager;
|
||||
package starlingExamples;
|
||||
|
||||
import starlingExamples.Scene.SceneManager;
|
||||
import openfl.utils.Assets;
|
||||
import spine.SkeletonData;
|
||||
import spine.animation.AnimationStateData;
|
||||
@ -27,7 +27,9 @@
|
||||
* SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import Scene.SceneManager;
|
||||
package starlingExamples;
|
||||
|
||||
import starlingExamples.Scene.SceneManager;
|
||||
import openfl.utils.Assets;
|
||||
import spine.SkeletonData;
|
||||
import spine.animation.AnimationStateData;
|
||||
@ -27,7 +27,9 @@
|
||||
* SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import Scene.SceneManager;
|
||||
package starlingExamples;
|
||||
|
||||
import starlingExamples.Scene.SceneManager;
|
||||
import openfl.utils.Assets;
|
||||
import spine.SkeletonData;
|
||||
import spine.Physics;
|
||||
@ -17,8 +17,8 @@
|
||||
"cpp"
|
||||
],
|
||||
"description": "The official Spine Runtime for Haxe",
|
||||
"version": "4.2.3",
|
||||
"releasenote": "Update to 4.2.3",
|
||||
"version": "4.2.5",
|
||||
"releasenote": "Update to 4.2.5",
|
||||
"contributors": [
|
||||
"esotericsoftware"
|
||||
],
|
||||
|
||||
@ -3,10 +3,13 @@
|
||||
|
||||
<meta title="spine-haxe-example" package="spine" version="4.2.0" company="Esoteric Software" />
|
||||
<app main="Main" path="export" file="SpineHaxeExample" />
|
||||
<!-- <app main="MainStarling" path="export" file="SpineHaxeExample" /> -->
|
||||
<!-- <app main="MainFlixel" path="export" file="SpineHaxeExample" /> -->
|
||||
<window allow-high-dpi="true" />
|
||||
|
||||
<haxelib name="openfl" />
|
||||
<haxelib name="starling" />
|
||||
<haxelib name="flixel" />
|
||||
<haxelib name="spine-haxe" />
|
||||
|
||||
<source path="example/src" />
|
||||
|
||||
@ -228,13 +228,15 @@ class Skin {
|
||||
var slotAttachment:Attachment = slot.attachment;
|
||||
if (slotAttachment != null && slotIndex < oldSkin.attachments.length) {
|
||||
var dictionary:StringMap<Attachment> = oldSkin.attachments[slotIndex];
|
||||
for (name in dictionary.keys()) {
|
||||
var skinAttachment:Attachment = dictionary.get(name);
|
||||
if (slotAttachment == skinAttachment) {
|
||||
var attachment:Attachment = getAttachment(slotIndex, name);
|
||||
if (attachment != null)
|
||||
slot.attachment = attachment;
|
||||
break;
|
||||
if (null != dictionary) {
|
||||
for (name in dictionary.keys()) {
|
||||
var skinAttachment:Attachment = dictionary.get(name);
|
||||
if (slotAttachment == skinAttachment) {
|
||||
var attachment:Attachment = getAttachment(slotIndex, name);
|
||||
if (attachment != null)
|
||||
slot.attachment = attachment;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
72
spine-haxe/spine-haxe/spine/flixel/FlixelTextureLoader.hx
Normal file
72
spine-haxe/spine-haxe/spine/flixel/FlixelTextureLoader.hx
Normal file
@ -0,0 +1,72 @@
|
||||
/******************************************************************************
|
||||
* Spine Runtimes License Agreement
|
||||
* Last updated July 28, 2023. Replaces all prior versions.
|
||||
*
|
||||
* Copyright (c) 2013-2023, Esoteric Software LLC
|
||||
*
|
||||
* Integration of the Spine Runtimes into software or otherwise creating
|
||||
* derivative works of the Spine Runtimes is permitted under the terms and
|
||||
* conditions of Section 2 of the Spine Editor License Agreement:
|
||||
* http://esotericsoftware.com/spine-editor-license
|
||||
*
|
||||
* Otherwise, it is permitted to integrate the Spine Runtimes into software or
|
||||
* otherwise create derivative works of the Spine Runtimes (collectively,
|
||||
* "Products"), provided that each user of the Products must obtain their own
|
||||
* Spine Editor license and redistribution of the Products in any form must
|
||||
* include this license and copyright notice.
|
||||
*
|
||||
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
|
||||
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
|
||||
* SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.flixel;
|
||||
|
||||
import flixel.graphics.FlxGraphic;
|
||||
import flixel.FlxG;
|
||||
import spine.atlas.TextureAtlasPage;
|
||||
import spine.atlas.TextureAtlasRegion;
|
||||
import spine.atlas.TextureLoader;
|
||||
import spine.flixel.SpineTexture;
|
||||
|
||||
class FlixelTextureLoader implements TextureLoader
|
||||
{
|
||||
private var basePath:String;
|
||||
|
||||
public function new(prefix:String) {
|
||||
basePath = "";
|
||||
var slashIndex = prefix.lastIndexOf("/");
|
||||
if (slashIndex != -1) {
|
||||
basePath = prefix.substring(0, slashIndex);
|
||||
}
|
||||
}
|
||||
|
||||
public function loadPage(page:TextureAtlasPage, path:String):Void
|
||||
{
|
||||
var bitmapData = openfl.utils.Assets.getBitmapData(basePath + "/" + path);
|
||||
if (bitmapData == null) {
|
||||
throw new SpineException("Could not load atlas page texture " + basePath + "/" + path);
|
||||
}
|
||||
var texture:FlxGraphic = SpineTexture.from(bitmapData);
|
||||
// TODO: reset this value to true when destroy skeleton
|
||||
// this is needed for sequence, otherwise the previous texture would be detroyed
|
||||
texture.destroyOnNoUse = false;
|
||||
page.texture = texture;
|
||||
}
|
||||
|
||||
public function loadRegion(region:TextureAtlasRegion):Void {
|
||||
region.texture = region.page.texture;
|
||||
}
|
||||
|
||||
public function unloadPage(page:TextureAtlasPage):Void
|
||||
{
|
||||
FlxG.bitmap.remove(cast page.texture);
|
||||
}
|
||||
}
|
||||
40
spine-haxe/spine-haxe/spine/flixel/SkeletonMesh.hx
Normal file
40
spine-haxe/spine-haxe/spine/flixel/SkeletonMesh.hx
Normal file
@ -0,0 +1,40 @@
|
||||
/******************************************************************************
|
||||
* Spine Runtimes License Agreement
|
||||
* Last updated July 28, 2023. Replaces all prior versions.
|
||||
*
|
||||
* Copyright (c) 2013-2023, Esoteric Software LLC
|
||||
*
|
||||
* Integration of the Spine Runtimes into software or otherwise creating
|
||||
* derivative works of the Spine Runtimes is permitted under the terms and
|
||||
* conditions of Section 2 of the Spine Editor License Agreement:
|
||||
* http://esotericsoftware.com/spine-editor-license
|
||||
*
|
||||
* Otherwise, it is permitted to integrate the Spine Runtimes into software or
|
||||
* otherwise create derivative works of the Spine Runtimes (collectively,
|
||||
* "Products"), provided that each user of the Products must obtain their own
|
||||
* Spine Editor license and redistribution of the Products in any form must
|
||||
* include this license and copyright notice.
|
||||
*
|
||||
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
|
||||
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
|
||||
* SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.flixel;
|
||||
|
||||
import flixel.FlxStrip;
|
||||
|
||||
// this class is just to make the implementation coherent with the starling implementation
|
||||
class SkeletonMesh extends FlxStrip {
|
||||
public function new(/*texture:FlxGraphicAsset*/) {
|
||||
super();
|
||||
// graphic = texture;
|
||||
}
|
||||
}
|
||||
382
spine-haxe/spine-haxe/spine/flixel/SkeletonSprite.hx
Normal file
382
spine-haxe/spine-haxe/spine/flixel/SkeletonSprite.hx
Normal file
@ -0,0 +1,382 @@
|
||||
package spine.flixel;
|
||||
|
||||
import openfl.geom.Point;
|
||||
import flixel.math.FlxPoint;
|
||||
import flixel.math.FlxMatrix;
|
||||
import spine.animation.MixDirection;
|
||||
import spine.animation.MixBlend;
|
||||
import spine.animation.Animation;
|
||||
import spine.TextureRegion;
|
||||
import haxe.extern.EitherType;
|
||||
import spine.attachments.Attachment;
|
||||
import flixel.util.typeLimit.OneOfTwo;
|
||||
import flixel.FlxCamera;
|
||||
import flixel.math.FlxRect;
|
||||
import flixel.FlxG;
|
||||
import flixel.FlxObject;
|
||||
import flixel.FlxSprite;
|
||||
import flixel.FlxStrip;
|
||||
import flixel.group.FlxSpriteGroup;
|
||||
import flixel.graphics.FlxGraphic;
|
||||
import flixel.util.FlxColor;
|
||||
import openfl.Vector;
|
||||
import openfl.display.BlendMode;
|
||||
import spine.Bone;
|
||||
import spine.Skeleton;
|
||||
import spine.SkeletonData;
|
||||
import spine.Slot;
|
||||
import spine.animation.AnimationState;
|
||||
import spine.animation.AnimationStateData;
|
||||
import spine.atlas.TextureAtlasRegion;
|
||||
import spine.attachments.MeshAttachment;
|
||||
import spine.attachments.RegionAttachment;
|
||||
import spine.attachments.ClippingAttachment;
|
||||
import spine.flixel.SkeletonMesh;
|
||||
|
||||
class SkeletonSprite extends FlxObject
|
||||
{
|
||||
public var skeleton(default, null):Skeleton;
|
||||
public var state(default, null):AnimationState;
|
||||
public var stateData(default, null):AnimationStateData;
|
||||
public var beforeUpdateWorldTransforms: SkeletonSprite -> Void = function(_) {};
|
||||
public var afterUpdateWorldTransforms: SkeletonSprite -> Void = function(_) {};
|
||||
public static var clipper(default, never):SkeletonClipping = new SkeletonClipping();
|
||||
|
||||
public var offsetX = .0;
|
||||
public var offsetY = .0;
|
||||
public var alpha = 1.; // TODO: clamp
|
||||
public var color:FlxColor = 0xffffff;
|
||||
public var flipX(default, set):Bool = false;
|
||||
public var flipY(default, set):Bool = false;
|
||||
public var antialiasing:Bool = true;
|
||||
|
||||
@:isVar
|
||||
public var scaleX(get, set):Float = 1;
|
||||
@:isVar
|
||||
public var scaleY(get, set):Float = 1;
|
||||
|
||||
var _tempVertices:Array<Float> = new Array<Float>();
|
||||
var _quadTriangles:Array<Int>;
|
||||
var _meshes(default, null):Array<SkeletonMesh> = new Array<SkeletonMesh>();
|
||||
|
||||
private var _tempMatrix = new FlxMatrix();
|
||||
private var _tempPoint = new Point();
|
||||
|
||||
private static var QUAD_INDICES:Array<Int> = [0, 1, 2, 2, 3, 0];
|
||||
public function new(skeletonData:SkeletonData, animationStateData:AnimationStateData = null)
|
||||
{
|
||||
super(0, 0);
|
||||
Bone.yDown = true;
|
||||
skeleton = new Skeleton(skeletonData);
|
||||
skeleton.updateWorldTransform(Physics.update);
|
||||
state = new AnimationState(animationStateData != null ? animationStateData : new AnimationStateData(skeletonData));
|
||||
setBoundingBox();
|
||||
}
|
||||
|
||||
public function setBoundingBox(?animation:Animation, ?clip:Bool = true) {
|
||||
var bounds = animation == null ? skeleton.getBounds() : getAnimationBounds(animation, clip);
|
||||
if (bounds.width > 0 && bounds.height > 0) {
|
||||
width = bounds.width;
|
||||
height = bounds.height;
|
||||
offsetX = -bounds.x;
|
||||
offsetY = -bounds.y;
|
||||
}
|
||||
}
|
||||
|
||||
public function getAnimationBounds(animation:Animation, clip:Bool = true): lime.math.Rectangle {
|
||||
var clipper = clip ? SkeletonSprite.clipper : null;
|
||||
skeleton.setToSetupPose();
|
||||
|
||||
var steps = 100, time = 0.;
|
||||
var stepTime = animation.duration != 0 ? animation.duration / steps : 0;
|
||||
var minX = 100000000., maxX = -100000000., minY = 100000000., maxY = -100000000.;
|
||||
|
||||
var bounds = new lime.math.Rectangle();
|
||||
for (i in 0...steps) {
|
||||
animation.apply(skeleton, time , time, false, [], 1, MixBlend.setup, MixDirection.mixIn);
|
||||
skeleton.updateWorldTransform(Physics.update);
|
||||
bounds = skeleton.getBounds(clipper);
|
||||
|
||||
if (!Math.isNaN(bounds.x) && !Math.isNaN(bounds.y) && !Math.isNaN(bounds.width) && !Math.isNaN(bounds.height)) {
|
||||
minX = Math.min(bounds.x, minX);
|
||||
minY = Math.min(bounds.y, minY);
|
||||
maxX = Math.max(bounds.right, maxX);
|
||||
maxY = Math.max(bounds.bottom, maxY);
|
||||
} else
|
||||
trace("ERROR");
|
||||
|
||||
time += stepTime;
|
||||
}
|
||||
bounds.x = minX;
|
||||
bounds.y = minY;
|
||||
bounds.width = maxX - minX;
|
||||
bounds.height = maxY - minY;
|
||||
return bounds;
|
||||
}
|
||||
|
||||
override public function destroy():Void
|
||||
{
|
||||
skeleton = null;
|
||||
state = null;
|
||||
stateData = null;
|
||||
|
||||
_tempVertices = null;
|
||||
_quadTriangles = null;
|
||||
_tempMatrix = null;
|
||||
_tempPoint = null;
|
||||
|
||||
if (_meshes != null) {
|
||||
for (mesh in _meshes) mesh.destroy();
|
||||
_meshes = null;
|
||||
}
|
||||
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
override public function update(elapsed:Float):Void
|
||||
{
|
||||
super.update(elapsed);
|
||||
state.update(elapsed);
|
||||
state.apply(skeleton);
|
||||
this.beforeUpdateWorldTransforms(this);
|
||||
skeleton.update(elapsed);
|
||||
skeleton.updateWorldTransform(Physics.update);
|
||||
this.afterUpdateWorldTransforms(this);
|
||||
}
|
||||
|
||||
override public function draw():Void
|
||||
{
|
||||
if (alpha == 0) return;
|
||||
|
||||
renderMeshes();
|
||||
|
||||
#if FLX_DEBUG
|
||||
if (FlxG.debugger.drawDebug) drawDebug();
|
||||
#end
|
||||
}
|
||||
|
||||
function renderMeshes():Void {
|
||||
var clipper:SkeletonClipping = SkeletonSprite.clipper;
|
||||
var drawOrder:Array<Slot> = skeleton.drawOrder;
|
||||
var attachmentColor:spine.Color;
|
||||
var mesh:SkeletonMesh = null;
|
||||
var numVertices:Int;
|
||||
var numFloats:Int;
|
||||
var triangles:Array<Int> = null;
|
||||
var uvs:Array<Float>;
|
||||
var twoColorTint:Bool = false;
|
||||
var vertexSize:Int = twoColorTint ? 12 : 8;
|
||||
_tempMatrix = getTransformMatrix();
|
||||
for (slot in drawOrder) {
|
||||
var clippedVertexSize:Int = clipper.isClipping() ? 2 : vertexSize;
|
||||
if (!slot.bone.active) {
|
||||
clipper.clipEndWithSlot(slot);
|
||||
continue;
|
||||
}
|
||||
|
||||
var worldVertices:Array<Float> = _tempVertices;
|
||||
if (Std.isOfType(slot.attachment, RegionAttachment)) {
|
||||
var region:RegionAttachment = cast(slot.attachment, RegionAttachment);
|
||||
numVertices = 4;
|
||||
numFloats = clippedVertexSize << 2;
|
||||
if (numFloats > worldVertices.length) {
|
||||
worldVertices.resize(numFloats);
|
||||
}
|
||||
region.computeWorldVertices(slot, worldVertices, 0, clippedVertexSize);
|
||||
|
||||
mesh = getFlixelMeshFromRendererAttachment(region);
|
||||
mesh.graphic = region.region.texture;
|
||||
triangles = QUAD_INDICES;
|
||||
uvs = region.uvs;
|
||||
attachmentColor = region.color;
|
||||
} else if (Std.isOfType(slot.attachment, MeshAttachment)) {
|
||||
var meshAttachment:MeshAttachment = cast(slot.attachment, MeshAttachment);
|
||||
numVertices = meshAttachment.worldVerticesLength >> 1;
|
||||
numFloats = numVertices * clippedVertexSize; // 8 for now because I'm excluding clipping
|
||||
if (numFloats > worldVertices.length) {
|
||||
worldVertices.resize(numFloats);
|
||||
}
|
||||
meshAttachment.computeWorldVertices(slot, 0, meshAttachment.worldVerticesLength, worldVertices, 0, clippedVertexSize);
|
||||
|
||||
mesh = getFlixelMeshFromRendererAttachment(meshAttachment);
|
||||
mesh.graphic = meshAttachment.region.texture;
|
||||
triangles = meshAttachment.triangles;
|
||||
uvs = meshAttachment.uvs;
|
||||
attachmentColor = meshAttachment.color;
|
||||
} else if (Std.isOfType(slot.attachment, ClippingAttachment)) {
|
||||
var clip:ClippingAttachment = cast(slot.attachment, ClippingAttachment);
|
||||
clipper.clipStart(slot, clip);
|
||||
continue;
|
||||
} else {
|
||||
clipper.clipEndWithSlot(slot);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mesh != null) {
|
||||
|
||||
// cannot use directly mesh.color.setRGBFloat otherwise the setter won't be called and transfor color not set
|
||||
mesh.color = FlxColor.fromRGBFloat(
|
||||
skeleton.color.r * slot.color.r * attachmentColor.r * color.redFloat,
|
||||
skeleton.color.g * slot.color.g * attachmentColor.g * color.greenFloat,
|
||||
skeleton.color.b * slot.color.b * attachmentColor.b * color.blueFloat,
|
||||
1
|
||||
);
|
||||
mesh.alpha = skeleton.color.a * slot.color.a * attachmentColor.a * alpha;
|
||||
|
||||
if (clipper.isClipping()) {
|
||||
clipper.clipTriangles(worldVertices, triangles, triangles.length, uvs);
|
||||
|
||||
mesh.indices = Vector.ofArray(clipper.clippedTriangles);
|
||||
mesh.uvtData = Vector.ofArray(clipper.clippedUvs);
|
||||
|
||||
if (angle == 0) {
|
||||
mesh.vertices = Vector.ofArray(clipper.clippedVertices);
|
||||
mesh.x = x + offsetX;
|
||||
mesh.y = y + offsetY;
|
||||
} else {
|
||||
var i = 0;
|
||||
mesh.vertices.length = clipper.clippedVertices.length;
|
||||
while (i < mesh.vertices.length) {
|
||||
_tempPoint.setTo(clipper.clippedVertices[i], clipper.clippedVertices[i + 1]);
|
||||
_tempPoint = _tempMatrix.transformPoint(_tempPoint);
|
||||
mesh.vertices[i] = _tempPoint.x;
|
||||
mesh.vertices[i + 1] = _tempPoint.y;
|
||||
i+=2;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var v = 0;
|
||||
var n = numFloats;
|
||||
var i = 0;
|
||||
mesh.vertices.length = numVertices;
|
||||
while (v < n) {
|
||||
if (angle == 0) {
|
||||
mesh.vertices[i] = worldVertices[v];
|
||||
mesh.vertices[i + 1] = worldVertices[v + 1];
|
||||
} else {
|
||||
_tempPoint.setTo(worldVertices[v], worldVertices[v + 1]);
|
||||
_tempPoint = _tempMatrix.transformPoint(_tempPoint);
|
||||
mesh.vertices[i] = _tempPoint.x;
|
||||
mesh.vertices[i + 1] = _tempPoint.y;
|
||||
}
|
||||
v += 8;
|
||||
i += 2;
|
||||
}
|
||||
if (angle == 0) {
|
||||
mesh.x = x + offsetX;
|
||||
mesh.y = y + offsetY;
|
||||
}
|
||||
mesh.indices = Vector.ofArray(triangles);
|
||||
mesh.uvtData = Vector.ofArray(uvs);
|
||||
}
|
||||
|
||||
mesh.antialiasing = antialiasing;
|
||||
mesh.blend = SpineTexture.toFlixelBlending(slot.data.blendMode);
|
||||
// x/y position works for mesh, but angle does not work.
|
||||
// if the transformation matrix is moved into the FlxStrip draw and used there
|
||||
// we can just put vertices without doing any transformation
|
||||
// mesh.x = x + offsetX;
|
||||
// mesh.y = y + offsetY;
|
||||
// mesh.angle = angle;
|
||||
mesh.draw();
|
||||
}
|
||||
|
||||
clipper.clipEndWithSlot(slot);
|
||||
}
|
||||
clipper.clipEnd();
|
||||
}
|
||||
|
||||
private function getTransformMatrix():FlxMatrix {
|
||||
_tempMatrix.identity();
|
||||
// scale is connected to the skeleton scale - no need to rescale
|
||||
_tempMatrix.scale(1, 1);
|
||||
_tempMatrix.rotate(angle * Math.PI / 180);
|
||||
_tempMatrix.translate(x + offsetX, y + offsetY);
|
||||
return _tempMatrix;
|
||||
}
|
||||
|
||||
public function skeletonToHaxeWorldCoordinates(point:Array<Float>):Void {
|
||||
var transform = getTransformMatrix();
|
||||
var a = transform.a,
|
||||
b = transform.b,
|
||||
c = transform.c,
|
||||
d = transform.d,
|
||||
tx = transform.tx,
|
||||
ty = transform.ty;
|
||||
var x = point[0];
|
||||
var y = point[1];
|
||||
point[0] = x * a + y * c + tx;
|
||||
point[1] = x * b + y * d + ty;
|
||||
}
|
||||
|
||||
public function haxeWorldCoordinatesToSkeleton(point:Array<Float>):Void {
|
||||
var transform = getTransformMatrix().invert();
|
||||
var a = transform.a,
|
||||
b = transform.b,
|
||||
c = transform.c,
|
||||
d = transform.d,
|
||||
tx = transform.tx,
|
||||
ty = transform.ty;
|
||||
var x = point[0];
|
||||
var y = point[1];
|
||||
point[0] = x * a + y * c + tx;
|
||||
point[1] = x * b + y * d + ty;
|
||||
}
|
||||
|
||||
public function haxeWorldCoordinatesToBone(point:Array<Float>, bone: Bone):Void {
|
||||
this.haxeWorldCoordinatesToSkeleton(point);
|
||||
if (bone.parent != null) {
|
||||
bone.parent.worldToLocal(point);
|
||||
} else {
|
||||
bone.worldToLocal(point);
|
||||
}
|
||||
}
|
||||
|
||||
private function getFlixelMeshFromRendererAttachment(region: RenderedAttachment) {
|
||||
if (region.rendererObject == null) {
|
||||
var skeletonMesh = new SkeletonMesh();
|
||||
region.rendererObject = skeletonMesh;
|
||||
skeletonMesh.exists = false;
|
||||
_meshes.push(skeletonMesh);
|
||||
}
|
||||
return region.rendererObject;
|
||||
}
|
||||
|
||||
function set_flipX(value:Bool):Bool
|
||||
{
|
||||
if (value != flipX) skeleton.scaleX = -skeleton.scaleX;
|
||||
return flipX = value;
|
||||
}
|
||||
|
||||
function set_flipY(value:Bool):Bool
|
||||
{
|
||||
if (value != flipY) skeleton.scaleY = -skeleton.scaleY;
|
||||
return flipY = value;
|
||||
}
|
||||
|
||||
function set_scale(value:FlxPoint):FlxPoint {
|
||||
return value;
|
||||
}
|
||||
|
||||
function get_scaleX():Float {
|
||||
return skeleton.scaleX;
|
||||
}
|
||||
|
||||
function set_scaleX(value:Float):Float {
|
||||
return skeleton.scaleX = value;
|
||||
}
|
||||
|
||||
function get_scaleY():Float {
|
||||
return skeleton.scaleY;
|
||||
}
|
||||
|
||||
function set_scaleY(value:Float):Float {
|
||||
return skeleton.scaleY = value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
typedef RenderedAttachment = {
|
||||
var rendererObject:Dynamic;
|
||||
var region:TextureRegion;
|
||||
}
|
||||
30
spine-haxe/spine-haxe/spine/flixel/SpineTexture.hx
Normal file
30
spine-haxe/spine-haxe/spine/flixel/SpineTexture.hx
Normal file
@ -0,0 +1,30 @@
|
||||
package spine.flixel;
|
||||
|
||||
import flixel.FlxG;
|
||||
import flixel.graphics.FlxGraphic;
|
||||
import openfl.display.BlendMode;
|
||||
|
||||
class SpineTexture extends FlxGraphic
|
||||
{
|
||||
public static function from(bitmapData: openfl.display.BitmapData): FlxGraphic {
|
||||
return FlxG.bitmap.add(bitmapData);
|
||||
}
|
||||
|
||||
public static function toFlixelBlending (blend: spine.BlendMode): BlendMode {
|
||||
switch (blend) {
|
||||
case spine.BlendMode.normal:
|
||||
return BlendMode.NORMAL;
|
||||
|
||||
case spine.BlendMode.additive:
|
||||
return BlendMode.ADD;
|
||||
|
||||
case spine.BlendMode.multiply:
|
||||
return BlendMode.MULTIPLY;
|
||||
|
||||
case spine.BlendMode.screen:
|
||||
return BlendMode.SCREEN;
|
||||
}
|
||||
return BlendMode.NORMAL;
|
||||
}
|
||||
|
||||
}
|
||||
@ -59,7 +59,7 @@ public final class SkinAndAnimationBounds: NSObject, BoundsProvider {
|
||||
/// the bounding box of the skeleton. If no skins are given, the default skin is used.
|
||||
/// The `stepTime`, given in seconds, defines at what interval the bounds should be sampled
|
||||
/// across the entire animation.
|
||||
public init(animation: String? = nil, skins: [String]? = nil, let stepTime: TimeInterval = 0.1) {
|
||||
public init(animation: String? = nil, skins: [String]? = nil, stepTime: TimeInterval = 0.1) {
|
||||
self.animation = animation
|
||||
if let skins, !skins.isEmpty {
|
||||
self.skins = skins
|
||||
|
||||
@ -27,7 +27,7 @@ public extension SkeletonDrawableWrapper {
|
||||
spineView.delegate?.draw(in: spineView)
|
||||
|
||||
guard let texture = spineView.currentDrawable?.texture else {
|
||||
throw "Could not read texture."
|
||||
throw SpineError("Could not read texture.")
|
||||
}
|
||||
let width = texture.width
|
||||
let height = texture.height
|
||||
@ -47,7 +47,7 @@ public extension SkeletonDrawableWrapper {
|
||||
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
||||
guard let context = CGContext(data: data, width: width, height: height, bitsPerComponent: 8, bytesPerRow: rowBytes, space: colorSpace, bitmapInfo: bitmapInfo.rawValue),
|
||||
let cgImage = context.makeImage() else {
|
||||
throw "Could not create image."
|
||||
throw SpineError("Could not create image.")
|
||||
}
|
||||
return cgImage
|
||||
}
|
||||
|
||||
@ -94,22 +94,22 @@ public final class SkeletonDrawableWrapper: NSObject {
|
||||
self.skeletonData = skeletonData
|
||||
|
||||
guard let nativeSkeletonDrawable = spine_skeleton_drawable_create(skeletonData.wrappee) else {
|
||||
throw "Could not load native skeleton drawable"
|
||||
throw SpineError("Could not load native skeleton drawable")
|
||||
}
|
||||
skeletonDrawable = SkeletonDrawable(nativeSkeletonDrawable)
|
||||
|
||||
guard let nativeSkeleton = spine_skeleton_drawable_get_skeleton(skeletonDrawable.wrappee) else {
|
||||
throw "Could not load native skeleton"
|
||||
throw SpineError("Could not load native skeleton")
|
||||
}
|
||||
skeleton = Skeleton(nativeSkeleton)
|
||||
|
||||
guard let nativeAnimationStateData = spine_skeleton_drawable_get_animation_state_data(skeletonDrawable.wrappee) else {
|
||||
throw "Could not load native animation state data"
|
||||
throw SpineError("Could not load native animation state data")
|
||||
}
|
||||
animationStateData = AnimationStateData(nativeAnimationStateData)
|
||||
|
||||
guard let nativeAnimationState = spine_skeleton_drawable_get_animation_state(skeletonDrawable.wrappee) else {
|
||||
throw "Could not load native animation state"
|
||||
throw SpineError("Could not load native animation state")
|
||||
}
|
||||
animationState = AnimationState(nativeAnimationState)
|
||||
animationStateWrapper = AnimationStateWrapper(
|
||||
|
||||
@ -57,18 +57,19 @@ public extension Atlas {
|
||||
}
|
||||
|
||||
private static func fromData(data: Data, loadFile: (_ name: String) async throws -> Data) async throws -> (Atlas, [UIImage]) {
|
||||
guard let atlasData = String(data: data, encoding: .utf8) as? NSString else {
|
||||
throw "Couldn't read atlas bytes as utf8 string"
|
||||
guard let atlasData = String(data: data, encoding: .utf8) else {
|
||||
throw SpineError("Couldn't read atlas bytes as utf8 string")
|
||||
}
|
||||
let atlasDataNative = UnsafeMutablePointer<CChar>(mutating: atlasData.utf8String)
|
||||
guard let atlas = spine_atlas_load(atlasDataNative) else {
|
||||
throw "Couldn't load atlas data"
|
||||
let atlas = try atlasData.utf8CString.withUnsafeBufferPointer {
|
||||
guard let atlas = spine_atlas_load($0.baseAddress) else {
|
||||
throw SpineError("Couldn't load atlas data")
|
||||
}
|
||||
return atlas
|
||||
}
|
||||
|
||||
if let error = spine_atlas_get_error(atlas) {
|
||||
let message = String(cString: error)
|
||||
spine_atlas_dispose(atlas)
|
||||
throw "Couldn't load atlas: \(message)"
|
||||
throw SpineError("Couldn't load atlas: \(message)")
|
||||
}
|
||||
|
||||
var atlasPages = [UIImage]()
|
||||
@ -130,26 +131,31 @@ public extension SkeletonData {
|
||||
///
|
||||
/// Throws an `Error` in case the skeleton data could not be loaded.
|
||||
static func fromData(atlas: Atlas, data: Data) throws -> SkeletonData {
|
||||
let binaryNative = try data.withUnsafeBytes { unsafeBytes in
|
||||
guard let bytes = unsafeBytes.bindMemory(to: UInt8.self).baseAddress else {
|
||||
throw "Couldn't read atlas binary"
|
||||
let result = try data.withUnsafeBytes{
|
||||
try $0.withMemoryRebound(to: UInt8.self) { buffer in
|
||||
guard let ptr = buffer.baseAddress else {
|
||||
throw SpineError("Couldn't read atlas binary")
|
||||
}
|
||||
return spine_skeleton_data_load_binary(
|
||||
atlas.wrappee,
|
||||
ptr,
|
||||
Int32(buffer.count)
|
||||
)
|
||||
}
|
||||
return (data: bytes, length: Int32(unsafeBytes.count))
|
||||
}
|
||||
let result = spine_skeleton_data_load_binary(
|
||||
atlas.wrappee,
|
||||
binaryNative.data,
|
||||
binaryNative.length
|
||||
)
|
||||
guard let result else {
|
||||
throw SpineError("Couldn't load skeleton data")
|
||||
}
|
||||
defer {
|
||||
spine_skeleton_data_result_dispose(result)
|
||||
}
|
||||
if let error = spine_skeleton_data_result_get_error(result) {
|
||||
let message = String(cString: error)
|
||||
spine_skeleton_data_result_dispose(result)
|
||||
throw "Couldn't load skeleton data: \(message)"
|
||||
throw SpineError("Couldn't load skeleton data: \(message)")
|
||||
}
|
||||
guard let data = spine_skeleton_data_result_get_data(result) else {
|
||||
throw "Couldn't load skeleton data from result"
|
||||
throw SpineError("Couldn't load skeleton data from result")
|
||||
}
|
||||
spine_skeleton_data_result_dispose(result)
|
||||
return SkeletonData(data)
|
||||
}
|
||||
|
||||
@ -158,26 +164,31 @@ public extension SkeletonData {
|
||||
///
|
||||
/// Throws an `Error` in case the atlas could not be loaded.
|
||||
static func fromJson(atlas: Atlas, json: String) throws -> SkeletonData {
|
||||
let jsonNative = UnsafeMutablePointer<CChar>(mutating: (json as NSString).utf8String)
|
||||
guard let result = spine_skeleton_data_load_json(atlas.wrappee, jsonNative) else {
|
||||
throw "Couldn't load skeleton data json"
|
||||
let result = try json.utf8CString.withUnsafeBufferPointer { buffer in
|
||||
guard
|
||||
let basePtr = buffer.baseAddress,
|
||||
let result = spine_skeleton_data_load_json(atlas.wrappee, basePtr) else {
|
||||
throw SpineError("Couldn't load skeleton data json")
|
||||
}
|
||||
return result
|
||||
}
|
||||
defer {
|
||||
spine_skeleton_data_result_dispose(result)
|
||||
}
|
||||
if let error = spine_skeleton_data_result_get_error(result) {
|
||||
let message = String(cString: error)
|
||||
spine_skeleton_data_result_dispose(result)
|
||||
throw "Couldn't load skeleton data: \(message)"
|
||||
throw SpineError("Couldn't load skeleton data: \(message)")
|
||||
}
|
||||
guard let data = spine_skeleton_data_result_get_data(result) else {
|
||||
throw "Couldn't load skeleton data from result"
|
||||
throw SpineError("Couldn't load skeleton data from result")
|
||||
}
|
||||
spine_skeleton_data_result_dispose(result)
|
||||
return SkeletonData(data)
|
||||
}
|
||||
|
||||
private static func fromData(atlas: Atlas, data: Data, isJson: Bool) throws -> SkeletonData {
|
||||
if isJson {
|
||||
guard let json = String(data: data, encoding: .utf8) else {
|
||||
throw "Couldn't read skeleton data json string"
|
||||
throw SpineError("Couldn't read skeleton data json string")
|
||||
}
|
||||
return try fromJson(atlas: atlas, json: json)
|
||||
} else {
|
||||
@ -271,12 +282,12 @@ internal enum FileSource {
|
||||
case .bundle(let fileName, let bundle):
|
||||
let components = fileName.split(separator: ".")
|
||||
guard components.count > 1, let ext = components.last else {
|
||||
throw "Provide both file name and file extension"
|
||||
throw SpineError("Provide both file name and file extension")
|
||||
}
|
||||
let name = components.dropLast(1).joined(separator: ".")
|
||||
|
||||
guard let fileUrl = bundle.url(forResource: name, withExtension: String(ext)) else {
|
||||
throw "Could not load file with name \(name) from bundle"
|
||||
throw SpineError("Could not load file with name \(name) from bundle")
|
||||
}
|
||||
return try Data(contentsOf: fileUrl, options: [])
|
||||
case .file(let fileUrl):
|
||||
@ -289,34 +300,63 @@ internal enum FileSource {
|
||||
}
|
||||
return try Data(contentsOf: temp, options: [])
|
||||
} else {
|
||||
return try await withCheckedThrowingContinuation { continuation in
|
||||
let task = URLSession.shared.downloadTask(with: url) { temp, response, error in
|
||||
if let error {
|
||||
continuation.resume(throwing: error)
|
||||
} else {
|
||||
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
|
||||
continuation.resume(throwing: URLError(.badServerResponse))
|
||||
return
|
||||
}
|
||||
guard let temp else {
|
||||
continuation.resume(throwing: "Could not download file.")
|
||||
return
|
||||
}
|
||||
do {
|
||||
continuation.resume(returning: try Data(contentsOf: temp, options: []))
|
||||
} catch {
|
||||
let lock = NSRecursiveLock()
|
||||
nonisolated(unsafe)
|
||||
var isCancelled = false
|
||||
nonisolated(unsafe)
|
||||
var taskHolder:URLSessionDownloadTask? = nil
|
||||
return try await withTaskCancellationHandler {
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
let task = URLSession.shared.downloadTask(with: url) { temp, response, error in
|
||||
if let error {
|
||||
continuation.resume(throwing: error)
|
||||
} else {
|
||||
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
|
||||
continuation.resume(throwing: URLError(.badServerResponse))
|
||||
return
|
||||
}
|
||||
guard let temp else {
|
||||
continuation.resume(throwing: SpineError("Could not download file."))
|
||||
return
|
||||
}
|
||||
do {
|
||||
continuation.resume(returning: try Data(contentsOf: temp, options: []))
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
}
|
||||
task.resume()
|
||||
let shouldCancel = lock.withLock {
|
||||
if !isCancelled {
|
||||
taskHolder = task
|
||||
}
|
||||
return isCancelled
|
||||
}
|
||||
if shouldCancel {
|
||||
task.cancel()
|
||||
}
|
||||
}
|
||||
task.resume()
|
||||
} onCancel: {
|
||||
lock.withLock {
|
||||
isCancelled = true
|
||||
let value = taskHolder
|
||||
taskHolder = nil
|
||||
return value
|
||||
}?.cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension String: Error {
|
||||
public struct SpineError: Error, CustomStringConvertible {
|
||||
|
||||
public let description: String
|
||||
|
||||
internal init(_ description: String) {
|
||||
self.description = description
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -180,18 +180,16 @@ public class AnimationState {
|
||||
from.animationLast = from.nextAnimationLast;
|
||||
from.trackLast = from.nextTrackLast;
|
||||
|
||||
if (to.nextTrackLast != -1) { // The from entry was applied at least once.
|
||||
boolean discard = to.mixTime == 0 && from.mixTime == 0; // Discard the from entry when neither have advanced yet.
|
||||
if (to.mixTime >= to.mixDuration || discard) {
|
||||
// Require totalAlpha == 0 to ensure mixing is complete or the transition is a single frame or discarded.
|
||||
if (from.totalAlpha == 0 || to.mixDuration == 0 || discard) {
|
||||
to.mixingFrom = from.mixingFrom;
|
||||
if (from.mixingFrom != null) from.mixingFrom.mixingTo = to;
|
||||
to.interruptAlpha = from.interruptAlpha;
|
||||
queue.end(from);
|
||||
}
|
||||
return finished;
|
||||
// The from entry was applied at least once and the mix is complete.
|
||||
if (to.nextTrackLast != -1 && to.mixTime >= to.mixDuration) {
|
||||
// Mixing is complete for all entries before the from entry or the mix is instantaneous.
|
||||
if (from.totalAlpha == 0 || to.mixDuration == 0) {
|
||||
to.mixingFrom = from.mixingFrom;
|
||||
if (from.mixingFrom != null) from.mixingFrom.mixingTo = to;
|
||||
to.interruptAlpha = from.interruptAlpha;
|
||||
queue.end(from);
|
||||
}
|
||||
return finished;
|
||||
}
|
||||
|
||||
from.trackTime += delta * from.timeScale;
|
||||
|
||||
42
spine-ts/package-lock.json
generated
42
spine-ts/package-lock.json
generated
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@esotericsoftware/spine-ts",
|
||||
"version": "4.2.73",
|
||||
"version": "4.2.76",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@esotericsoftware/spine-ts",
|
||||
"version": "4.2.73",
|
||||
"version": "4.2.76",
|
||||
"license": "LicenseRef-LICENSE",
|
||||
"workspaces": [
|
||||
"spine-core",
|
||||
@ -3142,18 +3142,18 @@
|
||||
},
|
||||
"spine-canvas": {
|
||||
"name": "@esotericsoftware/spine-canvas",
|
||||
"version": "4.2.73",
|
||||
"version": "4.2.76",
|
||||
"license": "LicenseRef-LICENSE",
|
||||
"dependencies": {
|
||||
"@esotericsoftware/spine-core": "4.2.73"
|
||||
"@esotericsoftware/spine-core": "4.2.76"
|
||||
}
|
||||
},
|
||||
"spine-canvaskit": {
|
||||
"name": "@esotericsoftware/spine-canvaskit",
|
||||
"version": "4.2.73",
|
||||
"version": "4.2.76",
|
||||
"license": "LicenseRef-LICENSE",
|
||||
"dependencies": {
|
||||
"@esotericsoftware/spine-core": "4.2.73",
|
||||
"@esotericsoftware/spine-core": "4.2.76",
|
||||
"canvaskit-wasm": "0.39.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -3163,17 +3163,17 @@
|
||||
},
|
||||
"spine-core": {
|
||||
"name": "@esotericsoftware/spine-core",
|
||||
"version": "4.2.73",
|
||||
"version": "4.2.76",
|
||||
"license": "LicenseRef-LICENSE"
|
||||
},
|
||||
"spine-phaser": {
|
||||
"name": "@esotericsoftware/spine-phaser",
|
||||
"version": "4.2.73",
|
||||
"version": "4.2.76",
|
||||
"license": "LicenseRef-LICENSE",
|
||||
"dependencies": {
|
||||
"@esotericsoftware/spine-canvas": "4.2.73",
|
||||
"@esotericsoftware/spine-core": "4.2.73",
|
||||
"@esotericsoftware/spine-webgl": "4.2.73"
|
||||
"@esotericsoftware/spine-canvas": "4.2.76",
|
||||
"@esotericsoftware/spine-core": "4.2.76",
|
||||
"@esotericsoftware/spine-webgl": "4.2.76"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"phaser": "^3.60.0"
|
||||
@ -3181,10 +3181,10 @@
|
||||
},
|
||||
"spine-pixi-v7": {
|
||||
"name": "@esotericsoftware/spine-pixi-v7",
|
||||
"version": "4.2.73",
|
||||
"version": "4.2.76",
|
||||
"license": "LicenseRef-LICENSE",
|
||||
"dependencies": {
|
||||
"@esotericsoftware/spine-core": "4.2.73"
|
||||
"@esotericsoftware/spine-core": "4.2.76"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@pixi/assets": "^7.2.4",
|
||||
@ -3198,10 +3198,10 @@
|
||||
},
|
||||
"spine-pixi-v8": {
|
||||
"name": "@esotericsoftware/spine-pixi-v8",
|
||||
"version": "4.2.73",
|
||||
"version": "4.2.76",
|
||||
"license": "LicenseRef-LICENSE",
|
||||
"dependencies": {
|
||||
"@esotericsoftware/spine-core": "4.2.73"
|
||||
"@esotericsoftware/spine-core": "4.2.76"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"pixi.js": "^8.4.0"
|
||||
@ -3209,18 +3209,18 @@
|
||||
},
|
||||
"spine-player": {
|
||||
"name": "@esotericsoftware/spine-player",
|
||||
"version": "4.2.73",
|
||||
"version": "4.2.76",
|
||||
"license": "LicenseRef-LICENSE",
|
||||
"dependencies": {
|
||||
"@esotericsoftware/spine-webgl": "4.2.73"
|
||||
"@esotericsoftware/spine-webgl": "4.2.76"
|
||||
}
|
||||
},
|
||||
"spine-threejs": {
|
||||
"name": "@esotericsoftware/spine-threejs",
|
||||
"version": "4.2.73",
|
||||
"version": "4.2.76",
|
||||
"license": "LicenseRef-LICENSE",
|
||||
"dependencies": {
|
||||
"@esotericsoftware/spine-core": "4.2.73"
|
||||
"@esotericsoftware/spine-core": "4.2.76"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/three": "0.162.0"
|
||||
@ -3231,10 +3231,10 @@
|
||||
},
|
||||
"spine-webgl": {
|
||||
"name": "@esotericsoftware/spine-webgl",
|
||||
"version": "4.2.73",
|
||||
"version": "4.2.76",
|
||||
"license": "LicenseRef-LICENSE",
|
||||
"dependencies": {
|
||||
"@esotericsoftware/spine-core": "4.2.73"
|
||||
"@esotericsoftware/spine-core": "4.2.76"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@esotericsoftware/spine-ts",
|
||||
"version": "4.2.73",
|
||||
"version": "4.2.76",
|
||||
"description": "The official Spine Runtimes for the web.",
|
||||
"type": "module",
|
||||
"files": [
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@esotericsoftware/spine-canvas",
|
||||
"version": "4.2.73",
|
||||
"version": "4.2.76",
|
||||
"description": "The official Spine Runtimes for the web.",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
@ -31,6 +31,6 @@
|
||||
},
|
||||
"homepage": "https://github.com/esotericsoftware/spine-runtimes#readme",
|
||||
"dependencies": {
|
||||
"@esotericsoftware/spine-core": "4.2.73"
|
||||
"@esotericsoftware/spine-core": "4.2.76"
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@esotericsoftware/spine-canvaskit",
|
||||
"version": "4.2.73",
|
||||
"version": "4.2.76",
|
||||
"description": "The official Spine Runtimes for CanvasKit for NodeJS",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
@ -31,7 +31,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/esotericsoftware/spine-runtimes#readme",
|
||||
"dependencies": {
|
||||
"@esotericsoftware/spine-core": "4.2.73",
|
||||
"@esotericsoftware/spine-core": "4.2.76",
|
||||
"canvaskit-wasm": "0.39.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@esotericsoftware/spine-core",
|
||||
"version": "4.2.73",
|
||||
"version": "4.2.76",
|
||||
"description": "The official Spine Runtimes for the web.",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@esotericsoftware/spine-phaser",
|
||||
"version": "4.2.73",
|
||||
"version": "4.2.76",
|
||||
"description": "The official Spine Runtimes for the Phaser.",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
@ -31,9 +31,9 @@
|
||||
},
|
||||
"homepage": "https://github.com/esotericsoftware/spine-runtimes#readme",
|
||||
"dependencies": {
|
||||
"@esotericsoftware/spine-core": "4.2.73",
|
||||
"@esotericsoftware/spine-webgl": "4.2.73",
|
||||
"@esotericsoftware/spine-canvas": "4.2.73"
|
||||
"@esotericsoftware/spine-core": "4.2.76",
|
||||
"@esotericsoftware/spine-webgl": "4.2.76",
|
||||
"@esotericsoftware/spine-canvas": "4.2.76"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"phaser": "^3.60.0"
|
||||
|
||||
@ -122,22 +122,42 @@ export class SpinePlugin extends Phaser.Plugins.ScenePlugin {
|
||||
};
|
||||
pluginManager.registerFileType("spineAtlas", atlasFileCallback, scene);
|
||||
|
||||
let self = this;
|
||||
let addSpineGameObject = function (this: Phaser.GameObjects.GameObjectFactory, x: number, y: number, dataKey: string, atlasKey: string, boundsProvider: SpineGameObjectBoundsProvider) {
|
||||
let gameObject = new SpineGameObject(this.scene, self, x, y, dataKey, atlasKey, boundsProvider);
|
||||
if (this.scene.sys.renderer instanceof Phaser.Renderer.WebGL.WebGLRenderer) {
|
||||
this.scene.sys.renderer.pipelines.clear();
|
||||
}
|
||||
|
||||
const spinePlugin = (this.scene.sys as any)[pluginKey] as SpinePlugin;
|
||||
let gameObject = new SpineGameObject(this.scene, spinePlugin, x, y, dataKey, atlasKey, boundsProvider);
|
||||
this.displayList.add(gameObject);
|
||||
this.updateList.add(gameObject);
|
||||
|
||||
if (this.scene.sys.renderer instanceof Phaser.Renderer.WebGL.WebGLRenderer) {
|
||||
this.scene.sys.renderer.pipelines.rebind();
|
||||
}
|
||||
|
||||
return gameObject;
|
||||
};
|
||||
|
||||
let makeSpineGameObject = function (this: Phaser.GameObjects.GameObjectFactory, config: SpineGameObjectConfig, addToScene: boolean = false) {
|
||||
if (this.scene.sys.renderer instanceof Phaser.Renderer.WebGL.WebGLRenderer) {
|
||||
this.scene.sys.renderer.pipelines.clear();
|
||||
}
|
||||
|
||||
let x = config.x ? config.x : 0;
|
||||
let y = config.y ? config.y : 0;
|
||||
let boundsProvider = config.boundsProvider ? config.boundsProvider : undefined;
|
||||
let gameObject = new SpineGameObject(this.scene, self, x, y, config.dataKey, config.atlasKey, boundsProvider);
|
||||
|
||||
const spinePlugin = (this.scene.sys as any)[pluginKey] as SpinePlugin;
|
||||
let gameObject = new SpineGameObject(this.scene, spinePlugin, x, y, config.dataKey, config.atlasKey, boundsProvider);
|
||||
if (addToScene !== undefined) {
|
||||
config.add = addToScene;
|
||||
}
|
||||
|
||||
if (this.scene.sys.renderer instanceof Phaser.Renderer.WebGL.WebGLRenderer) {
|
||||
this.scene.sys.renderer.pipelines.rebind();
|
||||
}
|
||||
|
||||
return Phaser.GameObjects.BuildGameObject(this.scene, gameObject, config);
|
||||
}
|
||||
pluginManager.registerGameObject((window as any).SPINE_GAME_OBJECT_TYPE ? (window as any).SPINE_GAME_OBJECT_TYPE : SPINE_GAME_OBJECT_TYPE, addSpineGameObject, makeSpineGameObject);
|
||||
|
||||
@ -59,7 +59,7 @@ export function createMixin<
|
||||
};
|
||||
}
|
||||
|
||||
type ComputedSizeMixin = Mixin<Phaser.GameObjects.Components.Transform, Phaser.GameObjects.GameObject>;
|
||||
type ComputedSizeMixin = Mixin<Phaser.GameObjects.Components.ComputedSize, Phaser.GameObjects.GameObject>;
|
||||
export const ComputedSizeMixin: ComputedSizeMixin = createMixin<Phaser.GameObjects.Components.ComputedSize>(ComputedSize);
|
||||
|
||||
type DepthMixin = Mixin<Phaser.GameObjects.Components.Depth, Phaser.GameObjects.GameObject>;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@esotericsoftware/spine-pixi-v7",
|
||||
"version": "4.2.73",
|
||||
"version": "4.2.76",
|
||||
"description": "The official Spine Runtimes for the web PixiJS v7.",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
@ -31,7 +31,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/esotericsoftware/spine-runtimes#readme",
|
||||
"dependencies": {
|
||||
"@esotericsoftware/spine-core": "4.2.73"
|
||||
"@esotericsoftware/spine-core": "4.2.76"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@pixi/core": "^7.2.4",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@esotericsoftware/spine-pixi-v8",
|
||||
"version": "4.2.73",
|
||||
"version": "4.2.76",
|
||||
"description": "The official Spine Runtimes for PixiJS v8.",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
@ -31,7 +31,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/esotericsoftware/spine-runtimes#readme",
|
||||
"dependencies": {
|
||||
"@esotericsoftware/spine-core": "4.2.73"
|
||||
"@esotericsoftware/spine-core": "4.2.76"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"pixi.js": "^8.4.0"
|
||||
|
||||
@ -560,6 +560,7 @@ export class Spine extends ViewContainer {
|
||||
this.spineAttachmentsDirty ||= spineAttachmentsDirty;
|
||||
}
|
||||
|
||||
private currentClippingSlot: SlotsToClipping | undefined;
|
||||
private updateAndSetPixiMask (slot: Slot, last: boolean) {
|
||||
// assign/create the currentClippingSlot
|
||||
const attachment = slot.attachment;
|
||||
@ -614,10 +615,10 @@ export class Spine extends ViewContainer {
|
||||
clippingSlotToPixiMask.mask = undefined;
|
||||
}
|
||||
}
|
||||
this.currentClippingSlot = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
private currentClippingSlot: SlotsToClipping | undefined;
|
||||
private transformAttachments () {
|
||||
const currentDrawOrder = this.skeleton.drawOrder;
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@esotericsoftware/spine-player",
|
||||
"version": "4.2.73",
|
||||
"version": "4.2.76",
|
||||
"description": "The official Spine Runtimes for the web.",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
@ -31,6 +31,6 @@
|
||||
},
|
||||
"homepage": "https://github.com/esotericsoftware/spine-runtimes#readme",
|
||||
"dependencies": {
|
||||
"@esotericsoftware/spine-webgl": "4.2.73"
|
||||
"@esotericsoftware/spine-webgl": "4.2.76"
|
||||
}
|
||||
}
|
||||
@ -347,7 +347,7 @@ export class SpinePlayer implements Disposable {
|
||||
this.sceneRenderer = new SceneRenderer(this.canvas, this.context, true);
|
||||
if (config.showLoading) this.loadingScreen = new LoadingScreen(this.sceneRenderer);
|
||||
} catch (e) {
|
||||
this.showError("Sorry, your browser does not support WebG, or you have disabled WebGL in your browser settings.\nPlease use the latest version of Firefox, Chrome, Edge, or Safari.", e as any);
|
||||
this.showError("Sorry, your browser does not support WebGL, or you have disabled WebGL in your browser settings.\nPlease use the latest version of Firefox, Chrome, Edge, or Safari.", e as any);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@esotericsoftware/spine-threejs",
|
||||
"version": "4.2.73",
|
||||
"version": "4.2.76",
|
||||
"description": "The official Spine Runtimes for the web.",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
@ -31,7 +31,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/esotericsoftware/spine-runtimes#readme",
|
||||
"dependencies": {
|
||||
"@esotericsoftware/spine-core": "4.2.73"
|
||||
"@esotericsoftware/spine-core": "4.2.76"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/three": "0.162.0"
|
||||
|
||||
@ -309,7 +309,7 @@ const spineOnBeforeCompile = (shader: THREE.WebGLProgramParametersWithUniforms)
|
||||
#ifdef USE_SPINE_DARK_TINT
|
||||
#ifdef USE_COLOR_ALPHA
|
||||
diffuseColor.a *= vColor.a;
|
||||
diffuseColor.rgb *= (1.0 - diffuseColor.rgb) * v_dark.rgb + diffuseColor.rgb * vColor.rgb;
|
||||
diffuseColor.rgb = (diffuseColor.a - diffuseColor.rgb) * v_dark.rgb + diffuseColor.rgb * vColor.rgb;
|
||||
#endif
|
||||
#else
|
||||
#ifdef USE_COLOR_ALPHA
|
||||
|
||||
@ -294,7 +294,7 @@ export class SkeletonMesh extends THREE.Object3D {
|
||||
|
||||
let darkColor = this.tempDarkColor;
|
||||
if (!slot.darkColor)
|
||||
darkColor.set(1, 1, 1, 0);
|
||||
darkColor.set(0, 0, 0, 1);
|
||||
else {
|
||||
darkColor.r = slot.darkColor.r * alpha;
|
||||
darkColor.g = slot.darkColor.g * alpha;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@esotericsoftware/spine-webgl",
|
||||
"version": "4.2.73",
|
||||
"version": "4.2.76",
|
||||
"description": "The official Spine Runtimes for the web.",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
@ -31,6 +31,6 @@
|
||||
},
|
||||
"homepage": "https://github.com/esotericsoftware/spine-runtimes#readme",
|
||||
"dependencies": {
|
||||
"@esotericsoftware/spine-core": "4.2.73"
|
||||
"@esotericsoftware/spine-core": "4.2.76"
|
||||
}
|
||||
}
|
||||
@ -98,7 +98,7 @@
|
||||
function render() {
|
||||
var start = Date.now()
|
||||
timeKeeper.update();
|
||||
var delta = 0.016; // timeKeeper.delta;
|
||||
var delta = timeKeeper.delta;
|
||||
|
||||
for (var i = 0; i < skeletons.length; i++) {
|
||||
var state = skeletons[i].state;
|
||||
|
||||
@ -0,0 +1,224 @@
|
||||
/******************************************************************************
|
||||
* Spine Runtimes License Agreement
|
||||
* Last updated July 28, 2023. Replaces all prior versions.
|
||||
*
|
||||
* Copyright (c) 2013-2025, Esoteric Software LLC
|
||||
*
|
||||
* Integration of the Spine Runtimes into software or otherwise creating
|
||||
* derivative works of the Spine Runtimes is permitted under the terms and
|
||||
* conditions of Section 2 of the Spine Editor License Agreement:
|
||||
* http://esotericsoftware.com/spine-editor-license
|
||||
*
|
||||
* Otherwise, it is permitted to integrate the Spine Runtimes into software or
|
||||
* otherwise create derivative works of the Spine Runtimes (collectively,
|
||||
* "Products"), provided that each user of the Products must obtain their own
|
||||
* Spine Editor license and redistribution of the Products in any form must
|
||||
* include this license and copyright notice.
|
||||
*
|
||||
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
|
||||
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
|
||||
* SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
#if UNITY_2018_3 || UNITY_2019 || UNITY_2018_3_OR_NEWER
|
||||
#define NEW_PREFAB_SYSTEM
|
||||
#endif
|
||||
|
||||
#if UNITY_2018_2_OR_NEWER
|
||||
#define HAS_CULL_TRANSPARENT_MESH
|
||||
#endif
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Spine.Unity.Examples {
|
||||
using MaterialReplacement = RenderExistingMesh.MaterialReplacement;
|
||||
|
||||
#if NEW_PREFAB_SYSTEM
|
||||
[ExecuteAlways]
|
||||
#else
|
||||
[ExecuteInEditMode]
|
||||
#endif
|
||||
public class RenderExistingMeshGraphic : MonoBehaviour {
|
||||
public SkeletonGraphic referenceSkeletonGraphic;
|
||||
public Material replacementMaterial;
|
||||
|
||||
public MaterialReplacement[] replacementMaterials = new MaterialReplacement[0];
|
||||
|
||||
SkeletonSubmeshGraphic ownGraphic;
|
||||
public List<SkeletonSubmeshGraphic> ownSubmeshGraphics;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private void Reset () {
|
||||
Awake();
|
||||
LateUpdate();
|
||||
}
|
||||
#endif
|
||||
|
||||
void Awake () {
|
||||
// subscribe to OnMeshAndMaterialsUpdated
|
||||
if (referenceSkeletonGraphic) {
|
||||
referenceSkeletonGraphic.OnMeshAndMaterialsUpdated -= UpdateOnCallback;
|
||||
referenceSkeletonGraphic.OnMeshAndMaterialsUpdated += UpdateOnCallback;
|
||||
}
|
||||
|
||||
ownGraphic = this.GetComponent<SkeletonSubmeshGraphic>();
|
||||
if (referenceSkeletonGraphic) {
|
||||
if (referenceSkeletonGraphic.allowMultipleCanvasRenderers)
|
||||
EnsureCanvasRendererCount(referenceSkeletonGraphic.canvasRenderers.Count);
|
||||
else
|
||||
SetupSubmeshGraphic();
|
||||
}
|
||||
}
|
||||
|
||||
protected void OnDisable () {
|
||||
if (referenceSkeletonGraphic) {
|
||||
referenceSkeletonGraphic.OnMeshAndMaterialsUpdated -= UpdateOnCallback;
|
||||
}
|
||||
}
|
||||
|
||||
protected void OnEnable () {
|
||||
#if UNITY_EDITOR
|
||||
// handle disabled scene reload
|
||||
if (Application.isPlaying) {
|
||||
Awake();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (referenceSkeletonGraphic) {
|
||||
referenceSkeletonGraphic.OnMeshAndMaterialsUpdated -= UpdateOnCallback;
|
||||
referenceSkeletonGraphic.OnMeshAndMaterialsUpdated += UpdateOnCallback;
|
||||
}
|
||||
}
|
||||
|
||||
void SetupSubmeshGraphic () {
|
||||
if (ownGraphic == null)
|
||||
ownGraphic = this.gameObject.AddComponent<SkeletonSubmeshGraphic>();
|
||||
|
||||
ownGraphic.maskable = referenceSkeletonGraphic.maskable;
|
||||
#if HAS_CULL_TRANSPARENT_MESH
|
||||
ownGraphic.canvasRenderer.cullTransparentMesh = referenceSkeletonGraphic.canvasRenderer.cullTransparentMesh;
|
||||
#endif
|
||||
ownGraphic.canvasRenderer.SetMaterial(replacementMaterial, referenceSkeletonGraphic.mainTexture);
|
||||
}
|
||||
|
||||
protected void EnsureCanvasRendererCount (int targetCount) {
|
||||
if (ownSubmeshGraphics == null)
|
||||
ownSubmeshGraphics = new List<SkeletonSubmeshGraphic>();
|
||||
|
||||
#if HAS_CULL_TRANSPARENT_MESH
|
||||
bool cullTransparentMesh = referenceSkeletonGraphic.canvasRenderer.cullTransparentMesh;
|
||||
#endif
|
||||
Vector2 pivot = referenceSkeletonGraphic.rectTransform.pivot;
|
||||
|
||||
int currentCount = ownSubmeshGraphics.Count;
|
||||
for (int i = currentCount; i < targetCount; ++i) {
|
||||
GameObject go = new GameObject(string.Format("Renderer{0}", i), typeof(RectTransform));
|
||||
go.transform.SetParent(this.transform, false);
|
||||
go.transform.localPosition = Vector3.zero;
|
||||
CanvasRenderer canvasRenderer = go.AddComponent<CanvasRenderer>();
|
||||
#if HAS_CULL_TRANSPARENT_MESH
|
||||
canvasRenderer.cullTransparentMesh = cullTransparentMesh;
|
||||
#endif
|
||||
SkeletonSubmeshGraphic submeshGraphic = go.AddComponent<SkeletonSubmeshGraphic>();
|
||||
ownSubmeshGraphics.Add(submeshGraphic);
|
||||
submeshGraphic.maskable = referenceSkeletonGraphic.maskable;
|
||||
submeshGraphic.raycastTarget = false;
|
||||
submeshGraphic.rectTransform.pivot = pivot;
|
||||
submeshGraphic.rectTransform.anchorMin = Vector2.zero;
|
||||
submeshGraphic.rectTransform.anchorMax = Vector2.one;
|
||||
submeshGraphic.rectTransform.sizeDelta = Vector2.zero;
|
||||
}
|
||||
}
|
||||
|
||||
protected void UpdateCanvasRenderers () {
|
||||
Mesh[] referenceMeshes = referenceSkeletonGraphic.MeshesMultipleCanvasRenderers.Items;
|
||||
Material[] referenceMaterials = referenceSkeletonGraphic.MaterialsMultipleCanvasRenderers.Items;
|
||||
Texture[] referenceTextures = referenceSkeletonGraphic.TexturesMultipleCanvasRenderers.Items;
|
||||
|
||||
int end = Math.Min(ownSubmeshGraphics.Count, referenceSkeletonGraphic.TexturesMultipleCanvasRenderers.Count);
|
||||
|
||||
for (int i = 0; i < end; i++) {
|
||||
SkeletonSubmeshGraphic submeshGraphic = ownSubmeshGraphics[i];
|
||||
CanvasRenderer reference = referenceSkeletonGraphic.canvasRenderers[i];
|
||||
|
||||
if (reference.gameObject.activeInHierarchy) {
|
||||
Material usedMaterial = replacementMaterial != null ?
|
||||
replacementMaterial : GetReplacementMaterialFor(referenceMaterials[i]);
|
||||
if (usedMaterial == null)
|
||||
usedMaterial = referenceMaterials[i];
|
||||
usedMaterial = referenceSkeletonGraphic.GetModifiedMaterial(usedMaterial);
|
||||
submeshGraphic.canvasRenderer.SetMaterial(usedMaterial, referenceTextures[i]);
|
||||
submeshGraphic.canvasRenderer.SetMesh(referenceMeshes[i]);
|
||||
submeshGraphic.gameObject.SetActive(true);
|
||||
} else {
|
||||
submeshGraphic.canvasRenderer.Clear();
|
||||
submeshGraphic.gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void DisableCanvasRenderers () {
|
||||
for (int i = 0; i < ownSubmeshGraphics.Count; i++) {
|
||||
SkeletonSubmeshGraphic submeshGraphic = ownSubmeshGraphics[i];
|
||||
submeshGraphic.canvasRenderer.Clear();
|
||||
submeshGraphic.gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
protected Material GetReplacementMaterialFor (Material originalMaterial) {
|
||||
for (int i = 0; i < replacementMaterials.Length; ++i) {
|
||||
MaterialReplacement entry = replacementMaterials[i];
|
||||
if (entry.originalMaterial != null && entry.originalMaterial.shader == originalMaterial.shader)
|
||||
return entry.replacementMaterial;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
void LateUpdate () {
|
||||
if (!Application.isPlaying) {
|
||||
UpdateMesh();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void UpdateOnCallback (SkeletonGraphic g) {
|
||||
UpdateMesh();
|
||||
}
|
||||
|
||||
void UpdateMesh () {
|
||||
if (!referenceSkeletonGraphic) return;
|
||||
|
||||
if (referenceSkeletonGraphic.allowMultipleCanvasRenderers) {
|
||||
EnsureCanvasRendererCount(referenceSkeletonGraphic.canvasRenderers.Count);
|
||||
UpdateCanvasRenderers();
|
||||
if (ownGraphic)
|
||||
ownGraphic.canvasRenderer.Clear();
|
||||
} else {
|
||||
if (ownGraphic == null)
|
||||
ownGraphic = this.gameObject.AddComponent<SkeletonSubmeshGraphic>();
|
||||
|
||||
DisableCanvasRenderers();
|
||||
|
||||
Material referenceMaterial = referenceSkeletonGraphic.materialForRendering;
|
||||
Material usedMaterial = replacementMaterial != null ? replacementMaterial : GetReplacementMaterialFor(referenceMaterial);
|
||||
if (usedMaterial == null)
|
||||
usedMaterial = referenceMaterial;
|
||||
usedMaterial = referenceSkeletonGraphic.GetModifiedMaterial(usedMaterial);
|
||||
ownGraphic.canvasRenderer.SetMaterial(usedMaterial, referenceSkeletonGraphic.mainTexture);
|
||||
Mesh mesh = referenceSkeletonGraphic.GetLastMesh();
|
||||
ownGraphic.canvasRenderer.SetMesh(mesh);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ff6ce4ce6b9336a479c6bf5af81fa80a
|
||||
@ -2,7 +2,7 @@
|
||||
"name": "com.esotericsoftware.spine.spine-unity-examples",
|
||||
"displayName": "spine-unity Runtime Examples",
|
||||
"description": "This plugin provides example scenes and scripts for the spine-unity runtime.",
|
||||
"version": "4.2.37",
|
||||
"version": "4.2.38",
|
||||
"unity": "2018.3",
|
||||
"author": {
|
||||
"name": "Esoteric Software",
|
||||
|
||||
@ -41,6 +41,7 @@ public class SpineShaderWithOutlineGUI : ShaderGUI {
|
||||
MaterialProperty _OutlineWidth = null;
|
||||
MaterialProperty _UseScreenSpaceOutlineWidth = null;
|
||||
MaterialProperty _OutlineColor = null;
|
||||
MaterialProperty _Fill = null;
|
||||
MaterialProperty _OutlineReferenceTexWidth = null;
|
||||
MaterialProperty _ThresholdEnd = null;
|
||||
MaterialProperty _OutlineSmoothness = null;
|
||||
@ -54,6 +55,7 @@ public class SpineShaderWithOutlineGUI : ShaderGUI {
|
||||
static GUIContent _OutlineWidthText = new GUIContent("Outline Width", "");
|
||||
static GUIContent _UseScreenSpaceOutlineWidthText = new GUIContent("Width in Screen Space", "Enable to keep the outline width constant in screen space instead of texture space. Requires more expensive computations.");
|
||||
static GUIContent _OutlineColorText = new GUIContent("Outline Color", "");
|
||||
static GUIContent _FillText = new GUIContent("Fill", "Enable to also fill the opaque area inside the outline with the outline color. Prevents a semi-transparent gap between outline and skeleton.");
|
||||
static GUIContent _OutlineReferenceTexWidthText = new GUIContent("Reference Texture Width", "");
|
||||
static GUIContent _ThresholdEndText = new GUIContent("Outline Threshold", "");
|
||||
static GUIContent _OutlineSmoothnessText = new GUIContent("Outline Smoothness", "");
|
||||
@ -92,6 +94,7 @@ public class SpineShaderWithOutlineGUI : ShaderGUI {
|
||||
_UseScreenSpaceOutlineWidth = FindProperty("_UseScreenSpaceOutlineWidth", props, false);
|
||||
_OutlineReferenceTexWidth = FindProperty("_OutlineReferenceTexWidth", props, false);
|
||||
_OutlineColor = FindProperty("_OutlineColor", props, false);
|
||||
_Fill = FindProperty("_Fill", props, false);
|
||||
_ThresholdEnd = FindProperty("_ThresholdEnd", props, false);
|
||||
_OutlineSmoothness = FindProperty("_OutlineSmoothness", props, false);
|
||||
_Use8Neighbourhood = FindProperty("_Use8Neighbourhood", props, false);
|
||||
@ -157,6 +160,8 @@ public class SpineShaderWithOutlineGUI : ShaderGUI {
|
||||
if (_UseScreenSpaceOutlineWidth != null)
|
||||
_materialEditor.ShaderProperty(_UseScreenSpaceOutlineWidth, _UseScreenSpaceOutlineWidthText);
|
||||
_materialEditor.ShaderProperty(_OutlineColor, _OutlineColorText);
|
||||
if (_Fill != null)
|
||||
_materialEditor.ShaderProperty(_Fill, _FillText);
|
||||
|
||||
_showAdvancedOutlineSettings = EditorGUILayout.Foldout(_showAdvancedOutlineSettings, _OutlineAdvancedText);
|
||||
if (_showAdvancedOutlineSettings) {
|
||||
|
||||
@ -18,6 +18,7 @@ Shader "Spine/Blend Modes/Skeleton PMA Additive" {
|
||||
[HideInInspector] _OutlineWidth("Outline Width", Range(0,8)) = 3.0
|
||||
[HideInInspector][MaterialToggle(_USE_SCREENSPACE_OUTLINE_WIDTH)] _UseScreenSpaceOutlineWidth("Width in Screen Space", Float) = 0
|
||||
[HideInInspector] _OutlineColor("Outline Color", Color) = (1,1,0,1)
|
||||
[HideInInspector][MaterialToggle(_OUTLINE_FILL_INSIDE)]_Fill("Fill", Float) = 0
|
||||
[HideInInspector] _OutlineReferenceTexWidth("Reference Texture Width", Int) = 1024
|
||||
[HideInInspector] _ThresholdEnd("Outline Threshold", Range(0,1)) = 0.25
|
||||
[HideInInspector] _OutlineSmoothness("Outline Smoothness", Range(0,1)) = 1.0
|
||||
|
||||
@ -18,6 +18,7 @@ Shader "Spine/Blend Modes/Skeleton PMA Multiply" {
|
||||
[HideInInspector] _OutlineWidth("Outline Width", Range(0,8)) = 3.0
|
||||
[HideInInspector][MaterialToggle(_USE_SCREENSPACE_OUTLINE_WIDTH)] _UseScreenSpaceOutlineWidth("Width in Screen Space", Float) = 0
|
||||
[HideInInspector] _OutlineColor("Outline Color", Color) = (1,1,0,1)
|
||||
[HideInInspector][MaterialToggle(_OUTLINE_FILL_INSIDE)]_Fill("Fill", Float) = 0
|
||||
[HideInInspector] _OutlineReferenceTexWidth("Reference Texture Width", Int) = 1024
|
||||
[HideInInspector] _ThresholdEnd("Outline Threshold", Range(0,1)) = 0.25
|
||||
[HideInInspector] _OutlineSmoothness("Outline Smoothness", Range(0,1)) = 1.0
|
||||
|
||||
@ -18,6 +18,7 @@ Shader "Spine/Blend Modes/Skeleton PMA Screen" {
|
||||
[HideInInspector] _OutlineWidth("Outline Width", Range(0,8)) = 3.0
|
||||
[HideInInspector][MaterialToggle(_USE_SCREENSPACE_OUTLINE_WIDTH)] _UseScreenSpaceOutlineWidth("Width in Screen Space", Float) = 0
|
||||
[HideInInspector] _OutlineColor("Outline Color", Color) = (1,1,0,1)
|
||||
[HideInInspector][MaterialToggle(_OUTLINE_FILL_INSIDE)]_Fill("Fill", Float) = 0
|
||||
[HideInInspector] _OutlineReferenceTexWidth("Reference Texture Width", Int) = 1024
|
||||
[HideInInspector] _ThresholdEnd("Outline Threshold", Range(0,1)) = 0.25
|
||||
[HideInInspector] _OutlineSmoothness("Outline Smoothness", Range(0,1)) = 1.0
|
||||
|
||||
@ -46,8 +46,13 @@ float4 computeOutlinePixel(sampler2D mainTexture, float2 mainTextureTexelSize,
|
||||
float average = (pixelTop + pixelBottom + pixelLeft + pixelRight) * vertexColorAlpha / numSamples;
|
||||
#endif
|
||||
float thresholdStart = ThresholdEnd * (1.0 - OutlineSmoothness);
|
||||
float outlineAlpha = saturate(saturate((average - thresholdStart) / (ThresholdEnd - thresholdStart)) - pixelCenter);
|
||||
outlineAlpha = pixelCenter > OutlineOpaqueAlpha ? 0 : outlineAlpha;
|
||||
float outlineAlpha = saturate((average - thresholdStart) / (ThresholdEnd - thresholdStart));
|
||||
#if !_OUTLINE_FILL_INSIDE
|
||||
outlineAlpha = saturate(outlineAlpha - pixelCenter);
|
||||
outlineAlpha = pixelCenter > OutlineOpaqueAlpha ? 0.0 : outlineAlpha;
|
||||
#else
|
||||
outlineAlpha = pixelCenter > OutlineOpaqueAlpha ? 1.0 : outlineAlpha;
|
||||
#endif
|
||||
return lerp(texColor, OutlineColor, outlineAlpha);
|
||||
}
|
||||
|
||||
|
||||
@ -13,6 +13,7 @@ Shader "Spine/Outline/Blend Modes/Skeleton PMA Additive" {
|
||||
[HideInInspector] _OutlineWidth("Outline Width", Range(0,8)) = 3.0
|
||||
[HideInInspector][MaterialToggle(_USE_SCREENSPACE_OUTLINE_WIDTH)] _UseScreenSpaceOutlineWidth("Width in Screen Space", Float) = 0
|
||||
[HideInInspector] _OutlineColor("Outline Color", Color) = (1,1,0,1)
|
||||
[HideInInspector][MaterialToggle(_OUTLINE_FILL_INSIDE)]_Fill("Fill", Float) = 0
|
||||
[HideInInspector] _OutlineReferenceTexWidth("Reference Texture Width", Int) = 1024
|
||||
[HideInInspector] _ThresholdEnd("Outline Threshold", Range(0,1)) = 0.25
|
||||
[HideInInspector] _OutlineSmoothness("Outline Smoothness", Range(0,1)) = 1.0
|
||||
|
||||
@ -13,6 +13,7 @@ Shader "Spine/Outline/Blend Modes/Skeleton PMA Multiply" {
|
||||
[HideInInspector] _OutlineWidth("Outline Width", Range(0,8)) = 3.0
|
||||
[HideInInspector][MaterialToggle(_USE_SCREENSPACE_OUTLINE_WIDTH)] _UseScreenSpaceOutlineWidth("Width in Screen Space", Float) = 0
|
||||
[HideInInspector] _OutlineColor("Outline Color", Color) = (1,1,0,1)
|
||||
[HideInInspector][MaterialToggle(_OUTLINE_FILL_INSIDE)]_Fill("Fill", Float) = 0
|
||||
[HideInInspector] _OutlineReferenceTexWidth("Reference Texture Width", Int) = 1024
|
||||
[HideInInspector] _ThresholdEnd("Outline Threshold", Range(0,1)) = 0.25
|
||||
[HideInInspector] _OutlineSmoothness("Outline Smoothness", Range(0,1)) = 1.0
|
||||
|
||||
@ -13,6 +13,7 @@ Shader "Spine/Outline/Blend Modes/Skeleton PMA Screen" {
|
||||
[HideInInspector] _OutlineWidth("Outline Width", Range(0,8)) = 3.0
|
||||
[HideInInspector][MaterialToggle(_USE_SCREENSPACE_OUTLINE_WIDTH)] _UseScreenSpaceOutlineWidth("Width in Screen Space", Float) = 0
|
||||
[HideInInspector] _OutlineColor("Outline Color", Color) = (1,1,0,1)
|
||||
[HideInInspector][MaterialToggle(_OUTLINE_FILL_INSIDE)]_Fill("Fill", Float) = 0
|
||||
[HideInInspector] _OutlineReferenceTexWidth("Reference Texture Width", Int) = 1024
|
||||
[HideInInspector] _ThresholdEnd("Outline Threshold", Range(0,1)) = 0.25
|
||||
[HideInInspector] _OutlineSmoothness("Outline Smoothness", Range(0,1)) = 1.0
|
||||
|
||||
@ -23,6 +23,7 @@ Shader "Spine/Outline/SkeletonGraphic"
|
||||
[HideInInspector] _OutlineWidth("Outline Width", Range(0,8)) = 3.0
|
||||
[HideInInspector][MaterialToggle(_USE_SCREENSPACE_OUTLINE_WIDTH)] _UseScreenSpaceOutlineWidth("Width in Screen Space", Float) = 0
|
||||
[HideInInspector] _OutlineColor("Outline Color", Color) = (1,1,0,1)
|
||||
[HideInInspector][MaterialToggle(_OUTLINE_FILL_INSIDE)]_Fill("Fill", Float) = 0
|
||||
[HideInInspector] _OutlineReferenceTexWidth("Reference Texture Width", Int) = 1024
|
||||
[HideInInspector] _ThresholdEnd("Outline Threshold", Range(0,1)) = 0.25
|
||||
[HideInInspector] _OutlineSmoothness("Outline Smoothness", Range(0,1)) = 1.0
|
||||
|
||||
@ -25,6 +25,7 @@ Shader "Spine/Outline/SkeletonGraphic Tint Black"
|
||||
[HideInInspector] _OutlineWidth("Outline Width", Range(0,8)) = 3.0
|
||||
[HideInInspector][MaterialToggle(_USE_SCREENSPACE_OUTLINE_WIDTH)] _UseScreenSpaceOutlineWidth("Width in Screen Space", Float) = 0
|
||||
[HideInInspector] _OutlineColor("Outline Color", Color) = (1,1,0,1)
|
||||
[HideInInspector][MaterialToggle(_OUTLINE_FILL_INSIDE)]_Fill("Fill", Float) = 0
|
||||
[HideInInspector] _OutlineReferenceTexWidth("Reference Texture Width", Int) = 1024
|
||||
[HideInInspector] _ThresholdEnd("Outline Threshold", Range(0,1)) = 0.25
|
||||
[HideInInspector] _OutlineSmoothness("Outline Smoothness", Range(0,1)) = 1.0
|
||||
|
||||
@ -14,6 +14,7 @@ Shader "Spine/Outline/Skeleton Fill" {
|
||||
[HideInInspector] _OutlineWidth("Outline Width", Range(0,8)) = 3.0
|
||||
[HideInInspector][MaterialToggle(_USE_SCREENSPACE_OUTLINE_WIDTH)] _UseScreenSpaceOutlineWidth("Width in Screen Space", Float) = 0
|
||||
[HideInInspector] _OutlineColor("Outline Color", Color) = (1,1,0,1)
|
||||
[HideInInspector][MaterialToggle(_OUTLINE_FILL_INSIDE)]_Fill("Fill", Float) = 0
|
||||
[HideInInspector] _OutlineReferenceTexWidth("Reference Texture Width", Int) = 1024
|
||||
[HideInInspector] _ThresholdEnd("Outline Threshold", Range(0,1)) = 0.25
|
||||
[HideInInspector] _OutlineSmoothness("Outline Smoothness", Range(0,1)) = 1.0
|
||||
|
||||
@ -13,6 +13,7 @@ Shader "Spine/Outline/Skeleton Lit" {
|
||||
[HideInInspector] _OutlineWidth("Outline Width", Range(0,8)) = 3.0
|
||||
[HideInInspector][MaterialToggle(_USE_SCREENSPACE_OUTLINE_WIDTH)] _UseScreenSpaceOutlineWidth("Width in Screen Space", Float) = 0
|
||||
[HideInInspector] _OutlineColor("Outline Color", Color) = (1,1,0,1)
|
||||
[HideInInspector][MaterialToggle(_OUTLINE_FILL_INSIDE)]_Fill("Fill", Float) = 0
|
||||
[HideInInspector] _OutlineReferenceTexWidth("Reference Texture Width", Int) = 1024
|
||||
[HideInInspector] _ThresholdEnd("Outline Threshold", Range(0,1)) = 0.25
|
||||
[HideInInspector] _OutlineSmoothness("Outline Smoothness", Range(0,1)) = 1.0
|
||||
|
||||
@ -14,6 +14,7 @@ Shader "Spine/Outline/Skeleton Lit ZWrite" {
|
||||
[HideInInspector] _OutlineWidth("Outline Width", Range(0,8)) = 3.0
|
||||
[HideInInspector][MaterialToggle(_USE_SCREENSPACE_OUTLINE_WIDTH)] _UseScreenSpaceOutlineWidth("Width in Screen Space", Float) = 0
|
||||
[HideInInspector] _OutlineColor("Outline Color", Color) = (1,1,0,1)
|
||||
[HideInInspector][MaterialToggle(_OUTLINE_FILL_INSIDE)]_Fill("Fill", Float) = 0
|
||||
[HideInInspector] _OutlineReferenceTexWidth("Reference Texture Width", Int) = 1024
|
||||
[HideInInspector] _ThresholdEnd("Outline Threshold", Range(0,1)) = 0.25
|
||||
[HideInInspector] _OutlineSmoothness("Outline Smoothness", Range(0,1)) = 1.0
|
||||
|
||||
@ -12,6 +12,7 @@ Shader "Spine/Outline/Skeleton" {
|
||||
[HideInInspector] _OutlineWidth("Outline Width", Range(0,8)) = 3.0
|
||||
[HideInInspector][MaterialToggle(_USE_SCREENSPACE_OUTLINE_WIDTH)] _UseScreenSpaceOutlineWidth("Width in Screen Space", Float) = 0
|
||||
[HideInInspector] _OutlineColor("Outline Color", Color) = (1,1,0,1)
|
||||
[HideInInspector][MaterialToggle(_OUTLINE_FILL_INSIDE)]_Fill("Fill", Float) = 0
|
||||
[HideInInspector] _OutlineReferenceTexWidth("Reference Texture Width", Int) = 1024
|
||||
[HideInInspector] _ThresholdEnd("Outline Threshold", Range(0,1)) = 0.25
|
||||
[HideInInspector] _OutlineSmoothness("Outline Smoothness", Range(0,1)) = 1.0
|
||||
@ -42,6 +43,7 @@ Shader "Spine/Outline/Skeleton" {
|
||||
#pragma fragment fragOutline
|
||||
#pragma shader_feature _ _USE8NEIGHBOURHOOD_ON
|
||||
#pragma shader_feature _ _USE_SCREENSPACE_OUTLINE_WIDTH
|
||||
#pragma shader_feature _ _OUTLINE_FILL_INSIDE
|
||||
#include "CGIncludes/Spine-Outline-Pass.cginc"
|
||||
ENDCG
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@ Shader "Spine/Outline/OutlineOnly-ZWrite" {
|
||||
[HideInInspector] _OutlineWidth("Outline Width", Range(0,8)) = 3.0
|
||||
[HideInInspector][MaterialToggle(_USE_SCREENSPACE_OUTLINE_WIDTH)] _UseScreenSpaceOutlineWidth("Width in Screen Space", Float) = 0
|
||||
[HideInInspector] _OutlineColor("Outline Color", Color) = (1,1,0,1)
|
||||
[HideInInspector][MaterialToggle(_OUTLINE_FILL_INSIDE)]_Fill("Fill", Float) = 0
|
||||
[HideInInspector] _OutlineReferenceTexWidth("Reference Texture Width", Int) = 1024
|
||||
[HideInInspector] _ThresholdEnd("Outline Threshold", Range(0,1)) = 0.25
|
||||
[HideInInspector] _OutlineSmoothness("Outline Smoothness", Range(0,1)) = 1.0
|
||||
@ -56,6 +57,7 @@ Shader "Spine/Outline/OutlineOnly-ZWrite" {
|
||||
#pragma fragment fragOutline
|
||||
#pragma shader_feature _ _USE8NEIGHBOURHOOD_ON
|
||||
#pragma shader_feature _ _USE_SCREENSPACE_OUTLINE_WIDTH
|
||||
#pragma shader_feature _ _OUTLINE_FILL_INSIDE
|
||||
#include "CGIncludes/Spine-Outline-Pass.cginc"
|
||||
ENDCG
|
||||
}
|
||||
|
||||
@ -14,6 +14,7 @@ Shader "Spine/Outline/Skeleton Tint" {
|
||||
[HideInInspector] _OutlineWidth("Outline Width", Range(0,8)) = 3.0
|
||||
[HideInInspector][MaterialToggle(_USE_SCREENSPACE_OUTLINE_WIDTH)] _UseScreenSpaceOutlineWidth("Width in Screen Space", Float) = 0
|
||||
[HideInInspector] _OutlineColor("Outline Color", Color) = (1,1,0,1)
|
||||
[HideInInspector][MaterialToggle(_OUTLINE_FILL_INSIDE)]_Fill("Fill", Float) = 0
|
||||
[HideInInspector] _OutlineReferenceTexWidth("Reference Texture Width", Int) = 1024
|
||||
[HideInInspector] _ThresholdEnd("Outline Threshold", Range(0,1)) = 0.25
|
||||
[HideInInspector] _OutlineSmoothness("Outline Smoothness", Range(0,1)) = 1.0
|
||||
|
||||
@ -14,6 +14,7 @@ Shader "Spine/Outline/Skeleton Tint Black" {
|
||||
[HideInInspector] _OutlineWidth("Outline Width", Range(0,8)) = 3.0
|
||||
[HideInInspector][MaterialToggle(_USE_SCREENSPACE_OUTLINE_WIDTH)] _UseScreenSpaceOutlineWidth("Width in Screen Space", Float) = 0
|
||||
[HideInInspector] _OutlineColor("Outline Color", Color) = (1,1,0,1)
|
||||
[HideInInspector][MaterialToggle(_OUTLINE_FILL_INSIDE)]_Fill("Fill", Float) = 0
|
||||
[HideInInspector] _OutlineReferenceTexWidth("Reference Texture Width", Int) = 1024
|
||||
[HideInInspector] _ThresholdEnd("Outline Threshold", Range(0,1)) = 0.25
|
||||
[HideInInspector] _OutlineSmoothness("Outline Smoothness", Range(0,1)) = 1.0
|
||||
|
||||
@ -13,6 +13,7 @@ Shader "Spine/Outline/Special/Skeleton Grayscale" {
|
||||
[HideInInspector] _OutlineWidth("Outline Width", Range(0,8)) = 3.0
|
||||
[HideInInspector][MaterialToggle(_USE_SCREENSPACE_OUTLINE_WIDTH)] _UseScreenSpaceOutlineWidth("Width in Screen Space", Float) = 0
|
||||
[HideInInspector] _OutlineColor("Outline Color", Color) = (1,1,0,1)
|
||||
[HideInInspector][MaterialToggle(_OUTLINE_FILL_INSIDE)]_Fill("Fill", Float) = 0
|
||||
[HideInInspector] _OutlineReferenceTexWidth("Reference Texture Width", Int) = 1024
|
||||
[HideInInspector] _ThresholdEnd("Outline Threshold", Range(0,1)) = 0.25
|
||||
[HideInInspector] _OutlineSmoothness("Outline Smoothness", Range(0,1)) = 1.0
|
||||
|
||||
@ -50,6 +50,7 @@ Shader "Spine/Outline/Sprite/Pixel Lit"
|
||||
[HideInInspector] _OutlineWidth("Outline Width", Range(0,8)) = 3.0
|
||||
[HideInInspector][MaterialToggle(_USE_SCREENSPACE_OUTLINE_WIDTH)] _UseScreenSpaceOutlineWidth("Width in Screen Space", Float) = 0
|
||||
[HideInInspector] _OutlineColor("Outline Color", Color) = (1,1,0,1)
|
||||
[HideInInspector][MaterialToggle(_OUTLINE_FILL_INSIDE)]_Fill("Fill", Float) = 0
|
||||
[HideInInspector] _OutlineReferenceTexWidth("Reference Texture Width", Int) = 1024
|
||||
[HideInInspector] _ThresholdEnd("Outline Threshold", Range(0,1)) = 0.25
|
||||
[HideInInspector] _OutlineSmoothness("Outline Smoothness", Range(0,1)) = 1.0
|
||||
|
||||
@ -33,6 +33,7 @@ Shader "Spine/Outline/Sprite/Unlit"
|
||||
[HideInInspector] _OutlineWidth("Outline Width", Range(0,8)) = 3.0
|
||||
[HideInInspector][MaterialToggle(_USE_SCREENSPACE_OUTLINE_WIDTH)] _UseScreenSpaceOutlineWidth("Width in Screen Space", Float) = 0
|
||||
[HideInInspector] _OutlineColor("Outline Color", Color) = (1,1,0,1)
|
||||
[HideInInspector][MaterialToggle(_OUTLINE_FILL_INSIDE)]_Fill("Fill", Float) = 0
|
||||
[HideInInspector] _OutlineReferenceTexWidth("Reference Texture Width", Int) = 1024
|
||||
[HideInInspector] _ThresholdEnd("Outline Threshold", Range(0,1)) = 0.25
|
||||
[HideInInspector] _OutlineSmoothness("Outline Smoothness", Range(0,1)) = 1.0
|
||||
|
||||
@ -51,6 +51,7 @@ Shader "Spine/Outline/Sprite/Vertex Lit"
|
||||
[HideInInspector] _OutlineWidth("Outline Width", Range(0,8)) = 3.0
|
||||
[HideInInspector][MaterialToggle(_USE_SCREENSPACE_OUTLINE_WIDTH)] _UseScreenSpaceOutlineWidth("Width in Screen Space", Float) = 0
|
||||
[HideInInspector] _OutlineColor("Outline Color", Color) = (1,1,0,1)
|
||||
[HideInInspector][MaterialToggle(_OUTLINE_FILL_INSIDE)]_Fill("Fill", Float) = 0
|
||||
[HideInInspector] _OutlineReferenceTexWidth("Reference Texture Width", Int) = 1024
|
||||
[HideInInspector] _ThresholdEnd("Outline Threshold", Range(0,1)) = 0.25
|
||||
[HideInInspector] _OutlineSmoothness("Outline Smoothness", Range(0,1)) = 1.0
|
||||
|
||||
@ -23,6 +23,7 @@ Shader "Spine/SkeletonGraphic Additive"
|
||||
[HideInInspector] _OutlineWidth("Outline Width", Range(0,8)) = 3.0
|
||||
[HideInInspector][MaterialToggle(_USE_SCREENSPACE_OUTLINE_WIDTH)] _UseScreenSpaceOutlineWidth("Width in Screen Space", Float) = 0
|
||||
[HideInInspector] _OutlineColor("Outline Color", Color) = (1,1,0,1)
|
||||
[HideInInspector][MaterialToggle(_OUTLINE_FILL_INSIDE)]_Fill("Fill", Float) = 0
|
||||
[HideInInspector] _OutlineReferenceTexWidth("Reference Texture Width", Int) = 1024
|
||||
[HideInInspector] _ThresholdEnd("Outline Threshold", Range(0,1)) = 0.25
|
||||
[HideInInspector] _OutlineSmoothness("Outline Smoothness", Range(0,1)) = 1.0
|
||||
|
||||
@ -23,6 +23,7 @@ Shader "Spine/SkeletonGraphic Fill"
|
||||
[HideInInspector] _OutlineWidth("Outline Width", Range(0,8)) = 3.0
|
||||
[HideInInspector][MaterialToggle(_USE_SCREENSPACE_OUTLINE_WIDTH)] _UseScreenSpaceOutlineWidth("Width in Screen Space", Float) = 0
|
||||
[HideInInspector] _OutlineColor("Outline Color", Color) = (1,1,0,1)
|
||||
[HideInInspector][MaterialToggle(_OUTLINE_FILL_INSIDE)]_Fill("Fill", Float) = 0
|
||||
[HideInInspector] _OutlineReferenceTexWidth("Reference Texture Width", Int) = 1024
|
||||
[HideInInspector] _ThresholdEnd("Outline Threshold", Range(0,1)) = 0.25
|
||||
[HideInInspector] _OutlineSmoothness("Outline Smoothness", Range(0,1)) = 1.0
|
||||
|
||||
@ -21,6 +21,7 @@ Shader "Spine/SkeletonGraphic Grayscale"
|
||||
[HideInInspector] _OutlineWidth("Outline Width", Range(0,8)) = 3.0
|
||||
[HideInInspector][MaterialToggle(_USE_SCREENSPACE_OUTLINE_WIDTH)] _UseScreenSpaceOutlineWidth("Width in Screen Space", Float) = 0
|
||||
[HideInInspector] _OutlineColor("Outline Color", Color) = (1,1,0,1)
|
||||
[HideInInspector][MaterialToggle(_OUTLINE_FILL_INSIDE)]_Fill("Fill", Float) = 0
|
||||
[HideInInspector] _OutlineReferenceTexWidth("Reference Texture Width", Int) = 1024
|
||||
[HideInInspector] _ThresholdEnd("Outline Threshold", Range(0,1)) = 0.25
|
||||
[HideInInspector] _OutlineSmoothness("Outline Smoothness", Range(0,1)) = 1.0
|
||||
|
||||
@ -23,6 +23,7 @@ Shader "Spine/SkeletonGraphic Multiply"
|
||||
[HideInInspector] _OutlineWidth("Outline Width", Range(0,8)) = 3.0
|
||||
[HideInInspector][MaterialToggle(_USE_SCREENSPACE_OUTLINE_WIDTH)] _UseScreenSpaceOutlineWidth("Width in Screen Space", Float) = 0
|
||||
[HideInInspector] _OutlineColor("Outline Color", Color) = (1,1,0,1)
|
||||
[HideInInspector][MaterialToggle(_OUTLINE_FILL_INSIDE)]_Fill("Fill", Float) = 0
|
||||
[HideInInspector] _OutlineReferenceTexWidth("Reference Texture Width", Int) = 1024
|
||||
[HideInInspector] _ThresholdEnd("Outline Threshold", Range(0,1)) = 0.25
|
||||
[HideInInspector] _OutlineSmoothness("Outline Smoothness", Range(0,1)) = 1.0
|
||||
|
||||
@ -23,6 +23,7 @@ Shader "Spine/SkeletonGraphic Screen"
|
||||
[HideInInspector] _OutlineWidth("Outline Width", Range(0,8)) = 3.0
|
||||
[HideInInspector][MaterialToggle(_USE_SCREENSPACE_OUTLINE_WIDTH)] _UseScreenSpaceOutlineWidth("Width in Screen Space", Float) = 0
|
||||
[HideInInspector] _OutlineColor("Outline Color", Color) = (1,1,0,1)
|
||||
[HideInInspector][MaterialToggle(_OUTLINE_FILL_INSIDE)]_Fill("Fill", Float) = 0
|
||||
[HideInInspector] _OutlineReferenceTexWidth("Reference Texture Width", Int) = 1024
|
||||
[HideInInspector] _ThresholdEnd("Outline Threshold", Range(0,1)) = 0.25
|
||||
[HideInInspector] _OutlineSmoothness("Outline Smoothness", Range(0,1)) = 1.0
|
||||
|
||||
@ -23,6 +23,7 @@ Shader "Spine/SkeletonGraphic"
|
||||
[HideInInspector] _OutlineWidth("Outline Width", Range(0,8)) = 3.0
|
||||
[HideInInspector][MaterialToggle(_USE_SCREENSPACE_OUTLINE_WIDTH)] _UseScreenSpaceOutlineWidth("Width in Screen Space", Float) = 0
|
||||
[HideInInspector] _OutlineColor("Outline Color", Color) = (1,1,0,1)
|
||||
[HideInInspector][MaterialToggle(_OUTLINE_FILL_INSIDE)]_Fill("Fill", Float) = 0
|
||||
[HideInInspector] _OutlineReferenceTexWidth("Reference Texture Width", Int) = 1024
|
||||
[HideInInspector] _ThresholdEnd("Outline Threshold", Range(0,1)) = 0.25
|
||||
[HideInInspector] _OutlineSmoothness("Outline Smoothness", Range(0,1)) = 1.0
|
||||
|
||||
@ -24,6 +24,7 @@ Shader "Spine/SkeletonGraphic Tint Black Additive"
|
||||
[HideInInspector] _OutlineWidth("Outline Width", Range(0,8)) = 3.0
|
||||
[HideInInspector][MaterialToggle(_USE_SCREENSPACE_OUTLINE_WIDTH)] _UseScreenSpaceOutlineWidth("Width in Screen Space", Float) = 0
|
||||
[HideInInspector] _OutlineColor("Outline Color", Color) = (1,1,0,1)
|
||||
[HideInInspector][MaterialToggle(_OUTLINE_FILL_INSIDE)]_Fill("Fill", Float) = 0
|
||||
[HideInInspector] _OutlineReferenceTexWidth("Reference Texture Width", Int) = 1024
|
||||
[HideInInspector] _ThresholdEnd("Outline Threshold", Range(0,1)) = 0.25
|
||||
[HideInInspector] _OutlineSmoothness("Outline Smoothness", Range(0,1)) = 1.0
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user