mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2025-12-21 09:46:02 +08:00
Merge branch '4.1-beta' of https://github.com/esotericsoftware/spine-runtimes into 4.1-beta
This commit is contained in:
commit
ef5e059ed9
@ -79,6 +79,8 @@
|
|||||||
* Added example component `SkeletonRenderTexture` to render a `SkeletonRenderer` to a `RenderTexture`, mainly for proper transparency. Added an example scene named `RenderTexture FadeOut Transparency` that demonstrates usage for a fadeout transparency effect.
|
* Added example component `SkeletonRenderTexture` to render a `SkeletonRenderer` to a `RenderTexture`, mainly for proper transparency. Added an example scene named `RenderTexture FadeOut Transparency` that demonstrates usage for a fadeout transparency effect.
|
||||||
* Added another fadeout example component named `SkeletonRenderTextureFadeout` which takes over transparency fadeout when enabled. You can use this component as-is, attach it in disabled state and enable it to start a fadeout effect.
|
* Added another fadeout example component named `SkeletonRenderTextureFadeout` which takes over transparency fadeout when enabled. You can use this component as-is, attach it in disabled state and enable it to start a fadeout effect.
|
||||||
* Timeline clips now offer an additional `Alpha` parameter for setting a custom constant mix alpha value other than 1.0, just as `TrackEntry.Alpha`. Defaults to 1.0.
|
* Timeline clips now offer an additional `Alpha` parameter for setting a custom constant mix alpha value other than 1.0, just as `TrackEntry.Alpha`. Defaults to 1.0.
|
||||||
|
* `GetRemappedClone` copying from `Sprite` now provides additional `pmaCloneTextureFormat` and `pmaCloneMipmaps` parameters to explicitly specify the texture format of a newly created PMA texture.
|
||||||
|
* Spine property Inspector fields (`Animation Name`, `Bone Name`, `Slot` and similar) now display the name in red when the respective animation/bone/etc no longer exists at the skeleton data. This may be helpful when such items have been renamed or deleted.
|
||||||
|
|
||||||
* **Breaking changes**
|
* **Breaking changes**
|
||||||
|
|
||||||
|
|||||||
@ -16,7 +16,7 @@ fi
|
|||||||
echo "Spine exe: $SPINE_EXE"
|
echo "Spine exe: $SPINE_EXE"
|
||||||
|
|
||||||
if [ "$#" -eq 0 ]; then
|
if [ "$#" -eq 0 ]; then
|
||||||
echo "Enter the Spine editor version to use for the export (eg 3.8.99):"
|
echo "Enter the Spine editor version to use for the export (eg 4.1.xx):"
|
||||||
read version
|
read version
|
||||||
else
|
else
|
||||||
version=${1%/}
|
version=${1%/}
|
||||||
@ -79,6 +79,11 @@ echo "Exporting assets..."
|
|||||||
-i ../mix-and-match/images -o ../mix-and-match/export -n mix-and-match -p atlas-0.5.json \
|
-i ../mix-and-match/images -o ../mix-and-match/export -n mix-and-match -p atlas-0.5.json \
|
||||||
-i ../mix-and-match/images -o ../mix-and-match/export -n mix-and-match-pma -p atlas-0.5-pma.json \
|
-i ../mix-and-match/images -o ../mix-and-match/export -n mix-and-match-pma -p atlas-0.5-pma.json \
|
||||||
\
|
\
|
||||||
|
-i ../owl/owl-pro.spine -o ../owl/export -e json.json \
|
||||||
|
-i ../owl/owl-pro.spine -o ../owl/export -e binary.json \
|
||||||
|
-i ../owl/images -o ../owl/export -n owl -p atlas-0.5.json \
|
||||||
|
-i ../owl/images -o ../owl/export -n owl-pma -p atlas-0.5-pma.json \
|
||||||
|
\
|
||||||
-i ../powerup/powerup-ess.spine -o ../powerup/export -e json.json \
|
-i ../powerup/powerup-ess.spine -o ../powerup/export -e json.json \
|
||||||
-i ../powerup/powerup-ess.spine -o ../powerup/export -e binary.json \
|
-i ../powerup/powerup-ess.spine -o ../powerup/export -e binary.json \
|
||||||
-i ../powerup/powerup-pro.spine -o ../powerup/export -e json.json \
|
-i ../powerup/powerup-pro.spine -o ../powerup/export -e json.json \
|
||||||
@ -100,6 +105,7 @@ echo "Exporting assets..."
|
|||||||
-i ../spineboy/spineboy-ess.spine -o ../spineboy/export -e binary.json \
|
-i ../spineboy/spineboy-ess.spine -o ../spineboy/export -e binary.json \
|
||||||
-i ../spineboy/spineboy-pro.spine -o ../spineboy/export -e json.json \
|
-i ../spineboy/spineboy-pro.spine -o ../spineboy/export -e json.json \
|
||||||
-i ../spineboy/spineboy-pro.spine -o ../spineboy/export -e binary.json \
|
-i ../spineboy/spineboy-pro.spine -o ../spineboy/export -e binary.json \
|
||||||
|
-i ../spineboy/spineboy-pro.spine -o ../spineboy/export/spineboy-run.atlas -e png-0.5-frame-by-frame.json \
|
||||||
-i ../spineboy/images -o ../spineboy/export -n spineboy -p atlas-0.5.json \
|
-i ../spineboy/images -o ../spineboy/export -n spineboy -p atlas-0.5.json \
|
||||||
-i ../spineboy/images -o ../spineboy/export -n spineboy-pma -p atlas-0.5-pma.json \
|
-i ../spineboy/images -o ../spineboy/export -n spineboy-pma -p atlas-0.5-pma.json \
|
||||||
\
|
\
|
||||||
@ -126,14 +132,10 @@ echo "Exporting assets..."
|
|||||||
-i ../windmill/images -o ../windmill/export -n windmill -p atlas-0.5.json \
|
-i ../windmill/images -o ../windmill/export -n windmill -p atlas-0.5.json \
|
||||||
-i ../windmill/images -o ../windmill/export -n windmill-pma -p atlas-0.5-pma.json
|
-i ../windmill/images -o ../windmill/export -n windmill-pma -p atlas-0.5-pma.json
|
||||||
|
|
||||||
# Owl needs separate export, as cleaning would kill keys in idle animation, which
|
# spineboy-old.spine needs separate export, as its images are in an atlas.
|
||||||
# would lead to incorrect additive animation blending.
|
|
||||||
"$SPINE_EXE" \
|
"$SPINE_EXE" \
|
||||||
-u $version ${@:2} \
|
-u $version ${@:2} \
|
||||||
-i ../owl/owl-pro.spine -o ../owl/export -e json.json \
|
-i ../../spine-libgdx/spine-libgdx-tests/assets/spineboy-old/spineboy-old.spine -o ../../spine-libgdx/spine-libgdx-tests/assets/spineboy-old -e json.json
|
||||||
-i ../owl/owl-pro.spine -o ../owl/export -e binary.json \
|
|
||||||
-i ../owl/images -o ../owl/export -n owl -p atlas-0.5.json \
|
|
||||||
-i ../owl/images -o ../owl/export -n owl-pma -p atlas-0.5-pma.json \
|
|
||||||
|
|
||||||
# Export Unity Assets
|
# Export Unity Assets
|
||||||
UNITY_BASE_DIR=../spine-unity
|
UNITY_BASE_DIR=../spine-unity
|
||||||
|
|||||||
87
examples/export/png-0.5-frame-by-frame.json
Normal file
87
examples/export/png-0.5-frame-by-frame.json
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
{
|
||||||
|
"class": "export-png",
|
||||||
|
"exportType": "animation",
|
||||||
|
"skeletonType": "single",
|
||||||
|
"skeleton": "spineboy-pro",
|
||||||
|
"animationType": "single",
|
||||||
|
"animation": "run",
|
||||||
|
"skinType": "current",
|
||||||
|
"skinNone": false,
|
||||||
|
"skin": null,
|
||||||
|
"maxBounds": false,
|
||||||
|
"renderImages": true,
|
||||||
|
"renderBones": false,
|
||||||
|
"renderOthers": false,
|
||||||
|
"scale": 50,
|
||||||
|
"fitWidth": 0,
|
||||||
|
"fitHeight": 0,
|
||||||
|
"enlarge": false,
|
||||||
|
"background": null,
|
||||||
|
"fps": 15,
|
||||||
|
"lastFrame": false,
|
||||||
|
"cropWidth": 0,
|
||||||
|
"cropHeight": 0,
|
||||||
|
"rangeStart": -1,
|
||||||
|
"rangeEnd": -1,
|
||||||
|
"packAtlas": {
|
||||||
|
"stripWhitespaceX": true,
|
||||||
|
"stripWhitespaceY": true,
|
||||||
|
"rotation": true,
|
||||||
|
"alias": true,
|
||||||
|
"ignoreBlankImages": false,
|
||||||
|
"alphaThreshold": 3,
|
||||||
|
"minWidth": 16,
|
||||||
|
"minHeight": 16,
|
||||||
|
"maxWidth": 2048,
|
||||||
|
"maxHeight": 2048,
|
||||||
|
"pot": false,
|
||||||
|
"multipleOfFour": false,
|
||||||
|
"square": false,
|
||||||
|
"outputFormat": "png",
|
||||||
|
"jpegQuality": 0.9,
|
||||||
|
"premultiplyAlpha": true,
|
||||||
|
"bleed": false,
|
||||||
|
"scale": [ 1 ],
|
||||||
|
"scaleSuffix": [ "" ],
|
||||||
|
"scaleResampling": [ "bicubic" ],
|
||||||
|
"paddingX": 2,
|
||||||
|
"paddingY": 2,
|
||||||
|
"edgePadding": true,
|
||||||
|
"duplicatePadding": false,
|
||||||
|
"filterMin": "Linear",
|
||||||
|
"filterMag": "Linear",
|
||||||
|
"wrapX": "ClampToEdge",
|
||||||
|
"wrapY": "ClampToEdge",
|
||||||
|
"format": "RGBA8888",
|
||||||
|
"atlasExtension": ".atlas",
|
||||||
|
"combineSubdirectories": false,
|
||||||
|
"flattenPaths": false,
|
||||||
|
"useIndexes": true,
|
||||||
|
"debug": false,
|
||||||
|
"fast": false,
|
||||||
|
"limitMemory": true,
|
||||||
|
"currentProject": true,
|
||||||
|
"packing": "rectangles",
|
||||||
|
"prettyPrint": true,
|
||||||
|
"legacyOutput": false,
|
||||||
|
"webp": null,
|
||||||
|
"bleedIterations": 2,
|
||||||
|
"ignore": false,
|
||||||
|
"separator": "_",
|
||||||
|
"silent": false
|
||||||
|
},
|
||||||
|
"compression": 9,
|
||||||
|
"bruteForce": true,
|
||||||
|
"quantize": true,
|
||||||
|
"quality": 100,
|
||||||
|
"speed": 1,
|
||||||
|
"dither": 0,
|
||||||
|
"maxColors": 256,
|
||||||
|
"pad": false,
|
||||||
|
"msaa": 4,
|
||||||
|
"smoothing": 8,
|
||||||
|
"renderSelection": false,
|
||||||
|
"cropX": 0,
|
||||||
|
"cropY": 0,
|
||||||
|
"open": false
|
||||||
|
}
|
||||||
Binary file not shown.
60
examples/spineboy/export/spineboy-run.atlas
Normal file
60
examples/spineboy/export/spineboy-run.atlas
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
spineboy-run.png
|
||||||
|
size: 1181, 687
|
||||||
|
filter: Linear, Linear
|
||||||
|
pma: true
|
||||||
|
spineboy-pro-run
|
||||||
|
index: 8
|
||||||
|
bounds: 2, 371, 303, 314
|
||||||
|
offsets: 11, 22, 316, 341
|
||||||
|
origin: 142, 3
|
||||||
|
spineboy-pro-run
|
||||||
|
index: 9
|
||||||
|
bounds: 2, 44, 278, 325
|
||||||
|
offsets: 30, 2, 316, 341
|
||||||
|
origin: 142, 3
|
||||||
|
spineboy-pro-run
|
||||||
|
index: 0
|
||||||
|
bounds: 307, 439, 246, 320
|
||||||
|
offsets: 67, 1, 316, 341
|
||||||
|
rotate: 90
|
||||||
|
origin: 142, 3
|
||||||
|
spineboy-pro-run
|
||||||
|
index: 3
|
||||||
|
bounds: 629, 443, 242, 320
|
||||||
|
offsets: 12, 20, 316, 341
|
||||||
|
rotate: 90
|
||||||
|
origin: 142, 3
|
||||||
|
spineboy-pro-run
|
||||||
|
index: 7
|
||||||
|
bounds: 951, 389, 228, 296
|
||||||
|
offsets: 36, 33, 316, 341
|
||||||
|
origin: 142, 3
|
||||||
|
spineboy-pro-run
|
||||||
|
index: 4
|
||||||
|
bounds: 307, 195, 242, 320
|
||||||
|
offsets: 2, 4, 316, 341
|
||||||
|
rotate: 90
|
||||||
|
origin: 142, 3
|
||||||
|
spineboy-pro-run
|
||||||
|
index: 5
|
||||||
|
bounds: 629, 200, 241, 316
|
||||||
|
offsets: 8, 3, 316, 341
|
||||||
|
rotate: 90
|
||||||
|
origin: 142, 3
|
||||||
|
spineboy-pro-run
|
||||||
|
index: 1
|
||||||
|
bounds: 282, 2, 191, 318
|
||||||
|
offsets: 70, 3, 316, 341
|
||||||
|
rotate: 90
|
||||||
|
origin: 142, 3
|
||||||
|
spineboy-pro-run
|
||||||
|
index: 2
|
||||||
|
bounds: 947, 81, 226, 306
|
||||||
|
offsets: 34, 26, 316, 341
|
||||||
|
origin: 142, 3
|
||||||
|
spineboy-pro-run
|
||||||
|
index: 6
|
||||||
|
bounds: 629, 4, 194, 316
|
||||||
|
offsets: 68, 4, 316, 341
|
||||||
|
rotate: 90
|
||||||
|
origin: 142, 3
|
||||||
BIN
examples/spineboy/export/spineboy-run.png
Normal file
BIN
examples/spineboy/export/spineboy-run.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 336 KiB |
@ -0,0 +1,2 @@
|
|||||||
|
eclipse.preferences.version=1
|
||||||
|
encoding/<project>=Cp1252
|
||||||
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
com.badlogic.gdx.graphics.g2d.BitmapFont: { default-font: { file: com/badlogic/gdx/utils/arial-15.fnt } },
|
com.badlogic.gdx.graphics.g2d.BitmapFont: { default-font: { file: com/badlogic/gdx/utils/lsans-15.fnt } },
|
||||||
com.badlogic.gdx.graphics.Color: {
|
com.badlogic.gdx.graphics.Color: {
|
||||||
green: { a: 1, b: 0, g: 1, r: 0 },
|
green: { a: 1, b: 0, g: 1, r: 0 },
|
||||||
white: { a: 1, b: 1, g: 1, r: 1 },
|
white: { a: 1, b: 1, g: 1, r: 1 },
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,60 @@
|
|||||||
|
spineboy-run.png
|
||||||
|
size: 1181, 687
|
||||||
|
filter: Linear, Linear
|
||||||
|
pma: true
|
||||||
|
spineboy-pro-run
|
||||||
|
index: 8
|
||||||
|
bounds: 2, 371, 303, 314
|
||||||
|
offsets: 11, 22, 316, 341
|
||||||
|
origin: 142, 3
|
||||||
|
spineboy-pro-run
|
||||||
|
index: 9
|
||||||
|
bounds: 2, 44, 278, 325
|
||||||
|
offsets: 30, 2, 316, 341
|
||||||
|
origin: 142, 3
|
||||||
|
spineboy-pro-run
|
||||||
|
index: 0
|
||||||
|
bounds: 307, 439, 246, 320
|
||||||
|
offsets: 67, 1, 316, 341
|
||||||
|
rotate: 90
|
||||||
|
origin: 142, 3
|
||||||
|
spineboy-pro-run
|
||||||
|
index: 3
|
||||||
|
bounds: 629, 443, 242, 320
|
||||||
|
offsets: 12, 20, 316, 341
|
||||||
|
rotate: 90
|
||||||
|
origin: 142, 3
|
||||||
|
spineboy-pro-run
|
||||||
|
index: 7
|
||||||
|
bounds: 951, 389, 228, 296
|
||||||
|
offsets: 36, 33, 316, 341
|
||||||
|
origin: 142, 3
|
||||||
|
spineboy-pro-run
|
||||||
|
index: 4
|
||||||
|
bounds: 307, 195, 242, 320
|
||||||
|
offsets: 2, 4, 316, 341
|
||||||
|
rotate: 90
|
||||||
|
origin: 142, 3
|
||||||
|
spineboy-pro-run
|
||||||
|
index: 5
|
||||||
|
bounds: 629, 200, 241, 316
|
||||||
|
offsets: 8, 3, 316, 341
|
||||||
|
rotate: 90
|
||||||
|
origin: 142, 3
|
||||||
|
spineboy-pro-run
|
||||||
|
index: 1
|
||||||
|
bounds: 282, 2, 191, 318
|
||||||
|
offsets: 70, 3, 316, 341
|
||||||
|
rotate: 90
|
||||||
|
origin: 142, 3
|
||||||
|
spineboy-pro-run
|
||||||
|
index: 2
|
||||||
|
bounds: 947, 81, 226, 306
|
||||||
|
offsets: 34, 26, 316, 341
|
||||||
|
origin: 142, 3
|
||||||
|
spineboy-pro-run
|
||||||
|
index: 6
|
||||||
|
bounds: 629, 4, 194, 316
|
||||||
|
offsets: 68, 4, 316, 341
|
||||||
|
rotate: 90
|
||||||
|
origin: 142, 3
|
||||||
BIN
spine-libgdx/spine-libgdx-tests/assets/spineboy/spineboy-run.png
Normal file
BIN
spine-libgdx/spine-libgdx-tests/assets/spineboy/spineboy-run.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 336 KiB |
@ -50,6 +50,7 @@ import com.esotericsoftware.spine.attachments.PointAttachment;
|
|||||||
import com.esotericsoftware.spine.attachments.RegionAttachment;
|
import com.esotericsoftware.spine.attachments.RegionAttachment;
|
||||||
import com.esotericsoftware.spine.attachments.Sequence;
|
import com.esotericsoftware.spine.attachments.Sequence;
|
||||||
|
|
||||||
|
/** Unit tests to ensure {@link AnimationState} is working as expected. */
|
||||||
public class AnimationStateTests {
|
public class AnimationStateTests {
|
||||||
final SkeletonJson json = new SkeletonJson(new AttachmentLoader() {
|
final SkeletonJson json = new SkeletonJson(new AttachmentLoader() {
|
||||||
public RegionAttachment newRegionAttachment (Skin skin, String name, String path, @Null Sequence sequence) {
|
public RegionAttachment newRegionAttachment (Skin skin, String name, String path, @Null Sequence sequence) {
|
||||||
|
|||||||
@ -35,7 +35,7 @@ import com.esotericsoftware.spine.Animation.AttachmentTimeline;
|
|||||||
import com.esotericsoftware.spine.Animation.Timeline;
|
import com.esotericsoftware.spine.Animation.Timeline;
|
||||||
import com.esotericsoftware.spine.attachments.Attachment;
|
import com.esotericsoftware.spine.attachments.Attachment;
|
||||||
|
|
||||||
/** Unit tests for {@link AttachmentTimeline}. */
|
/** Unit tests to ensure {@link AttachmentTimeline} is working as expected. */
|
||||||
public class AttachmentTimelineTests {
|
public class AttachmentTimelineTests {
|
||||||
private final SkeletonData skeletonData;
|
private final SkeletonData skeletonData;
|
||||||
private final Skeleton skeleton;
|
private final Skeleton skeleton;
|
||||||
|
|||||||
@ -43,9 +43,10 @@ import com.esotericsoftware.spine.attachments.PointAttachment;
|
|||||||
import com.esotericsoftware.spine.attachments.RegionAttachment;
|
import com.esotericsoftware.spine.attachments.RegionAttachment;
|
||||||
import com.esotericsoftware.spine.attachments.Sequence;
|
import com.esotericsoftware.spine.attachments.Sequence;
|
||||||
|
|
||||||
|
/** Demonstrates loading skeleton data without an atlas and plotting bone transform for each animation. */
|
||||||
public class BonePlotting {
|
public class BonePlotting {
|
||||||
static public void main (String[] args) throws Exception {
|
static public void main (String[] args) throws Exception {
|
||||||
// This example shows how to load skeleton data and plot a bone transform for each animation.
|
// Create a skeleton loader that doesn't use an atlas and doesn't create any attachments.
|
||||||
SkeletonJson json = new SkeletonJson(new AttachmentLoader() {
|
SkeletonJson json = new SkeletonJson(new AttachmentLoader() {
|
||||||
public RegionAttachment newRegionAttachment (Skin skin, String name, String path, @Null Sequence sequence) {
|
public RegionAttachment newRegionAttachment (Skin skin, String name, String path, @Null Sequence sequence) {
|
||||||
return null;
|
return null;
|
||||||
@ -71,17 +72,22 @@ public class BonePlotting {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
SkeletonData skeletonData = json.readSkeletonData(new FileHandle("assets/spineboy/spineboy-ess.json"));
|
SkeletonData skeletonData = json.readSkeletonData(new FileHandle("assets/spineboy/spineboy-ess.json"));
|
||||||
Skeleton skeleton = new Skeleton(skeletonData);
|
Skeleton skeleton = new Skeleton(skeletonData);
|
||||||
Bone bone = skeleton.findBone("gun-tip");
|
Bone bone = skeleton.findBone("gun-tip");
|
||||||
|
|
||||||
|
// Pose the skeleton at regular intervals throughout each animation.
|
||||||
float fps = 1 / 15f;
|
float fps = 1 / 15f;
|
||||||
for (Animation animation : skeletonData.getAnimations()) {
|
for (Animation animation : skeletonData.getAnimations()) {
|
||||||
float time = 0;
|
float time = 0;
|
||||||
while (time < animation.getDuration()) {
|
while (time < animation.getDuration()) {
|
||||||
animation.apply(skeleton, time, time, false, null, 1, MixBlend.first, MixDirection.in);
|
animation.apply(skeleton, time, time, false, null, 1, MixBlend.first, MixDirection.in);
|
||||||
skeleton.updateWorldTransform();
|
skeleton.updateWorldTransform();
|
||||||
System.out
|
|
||||||
.println(animation.getName() + "," + bone.getWorldX() + "," + bone.getWorldY() + "," + bone.getWorldRotationX());
|
System.out.println(animation.getName() + "," //
|
||||||
|
+ bone.getWorldX() + "," + bone.getWorldY() + "," + bone.getWorldRotationX());
|
||||||
|
|
||||||
time += fps;
|
time += fps;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -58,6 +58,7 @@ import com.esotericsoftware.spine.attachments.AtlasAttachmentLoader;
|
|||||||
import com.esotericsoftware.spine.attachments.RegionAttachment;
|
import com.esotericsoftware.spine.attachments.RegionAttachment;
|
||||||
import com.esotericsoftware.spine.attachments.Sequence;
|
import com.esotericsoftware.spine.attachments.Sequence;
|
||||||
|
|
||||||
|
/** Demonstrates positioning physics bodies for a skeleton. */
|
||||||
public class Box2DExample extends ApplicationAdapter {
|
public class Box2DExample extends ApplicationAdapter {
|
||||||
SpriteBatch batch;
|
SpriteBatch batch;
|
||||||
ShapeRenderer renderer;
|
ShapeRenderer renderer;
|
||||||
@ -84,8 +85,8 @@ public class Box2DExample extends ApplicationAdapter {
|
|||||||
|
|
||||||
atlas = new TextureAtlas(Gdx.files.internal("spineboy/spineboy-pma.atlas"));
|
atlas = new TextureAtlas(Gdx.files.internal("spineboy/spineboy-pma.atlas"));
|
||||||
|
|
||||||
// This loader creates Box2dAttachments instead of RegionAttachments for an easy way to keep
|
// This loader creates Box2dAttachments instead of RegionAttachments for an easy way to keep track of the Box2D body for
|
||||||
// track of the Box2D body for each attachment.
|
// each attachment.
|
||||||
AtlasAttachmentLoader atlasLoader = new AtlasAttachmentLoader(atlas) {
|
AtlasAttachmentLoader atlasLoader = new AtlasAttachmentLoader(atlas) {
|
||||||
public RegionAttachment newRegionAttachment (Skin skin, String name, String path, @Null Sequence sequence) {
|
public RegionAttachment newRegionAttachment (Skin skin, String name, String path, @Null Sequence sequence) {
|
||||||
Box2dAttachment attachment = new Box2dAttachment(name);
|
Box2dAttachment attachment = new Box2dAttachment(name);
|
||||||
@ -154,7 +155,7 @@ public class Box2DExample extends ApplicationAdapter {
|
|||||||
|
|
||||||
batch.end();
|
batch.end();
|
||||||
|
|
||||||
// Position each attachment body.
|
// Position the physics body for each attachment.
|
||||||
for (Slot slot : skeleton.getSlots()) {
|
for (Slot slot : skeleton.getSlots()) {
|
||||||
if (!(slot.getAttachment() instanceof Box2dAttachment)) continue;
|
if (!(slot.getAttachment() instanceof Box2dAttachment)) continue;
|
||||||
Box2dAttachment attachment = (Box2dAttachment)slot.getAttachment();
|
Box2dAttachment attachment = (Box2dAttachment)slot.getAttachment();
|
||||||
@ -182,25 +183,19 @@ public class Box2DExample extends ApplicationAdapter {
|
|||||||
PolygonShape shape = new PolygonShape();
|
PolygonShape shape = new PolygonShape();
|
||||||
shape.set(vertices);
|
shape.set(vertices);
|
||||||
|
|
||||||
// next we create a static ground platform. This platform
|
// Next we create a static ground platform. This platform is not moveable and will not react to any outside influences. It
|
||||||
// is not moveable and will not react to any influences from
|
// will however influence other bodies. First we create a PolygonShape that holds the form of the platform. It will be
|
||||||
// outside. It will however influence other bodies. First we
|
// 100 meters wide and 2 meters high, centered around the origin.
|
||||||
// create a PolygonShape that holds the form of the platform.
|
|
||||||
// it will be 100 meters wide and 2 meters high, centered
|
|
||||||
// around the origin
|
|
||||||
PolygonShape groundPoly = new PolygonShape();
|
PolygonShape groundPoly = new PolygonShape();
|
||||||
groundPoly.setAsBox(50, 1);
|
groundPoly.setAsBox(50, 1);
|
||||||
|
|
||||||
// next we create the body for the ground platform. It's
|
// Next we create the body for the ground platform. It's simply a static body.
|
||||||
// simply a static body.
|
|
||||||
BodyDef groundBodyDef = new BodyDef();
|
BodyDef groundBodyDef = new BodyDef();
|
||||||
groundBodyDef.type = BodyType.StaticBody;
|
groundBodyDef.type = BodyType.StaticBody;
|
||||||
groundBody = world.createBody(groundBodyDef);
|
groundBody = world.createBody(groundBodyDef);
|
||||||
|
|
||||||
// finally we add a fixture to the body using the polygon
|
// Finally we add a fixture to the body using the polygon defined above. Note that we have to dispose PolygonShapes and
|
||||||
// defined above. Note that we have to dispose PolygonShapes
|
// CircleShapes once they are no longer used. This is the only time you have to care explicitely for memomry managment.
|
||||||
// and CircleShapes once they are no longer used. This is the
|
|
||||||
// only time you have to care explicitely for memomry managment.
|
|
||||||
FixtureDef fixtureDef = new FixtureDef();
|
FixtureDef fixtureDef = new FixtureDef();
|
||||||
fixtureDef.shape = groundPoly;
|
fixtureDef.shape = groundPoly;
|
||||||
fixtureDef.filter.groupIndex = 0;
|
fixtureDef.filter.groupIndex = 0;
|
||||||
@ -210,12 +205,10 @@ public class Box2DExample extends ApplicationAdapter {
|
|||||||
PolygonShape boxPoly = new PolygonShape();
|
PolygonShape boxPoly = new PolygonShape();
|
||||||
boxPoly.setAsBox(1, 1);
|
boxPoly.setAsBox(1, 1);
|
||||||
|
|
||||||
// Next we create the 50 box bodies using the PolygonShape we just
|
// Next we create the 50 box bodies using the PolygonShape we just defined. This process is similar to the one we used for
|
||||||
// defined. This process is similar to the one we used for the ground
|
// the ground body. Note that we reuse the polygon for each body fixture.
|
||||||
// body. Note that we reuse the polygon for each body fixture.
|
|
||||||
for (int i = 0; i < 45; i++) {
|
for (int i = 0; i < 45; i++) {
|
||||||
// Create the BodyDef, set a random position above the
|
// Create the BodyDef, set a random position above the ground and create a new body.
|
||||||
// ground and create a new body
|
|
||||||
BodyDef boxBodyDef = new BodyDef();
|
BodyDef boxBodyDef = new BodyDef();
|
||||||
boxBodyDef.type = BodyType.DynamicBody;
|
boxBodyDef.type = BodyType.DynamicBody;
|
||||||
boxBodyDef.position.x = -24 + (float)(Math.random() * 48);
|
boxBodyDef.position.x = -24 + (float)(Math.random() * 48);
|
||||||
@ -225,7 +218,7 @@ public class Box2DExample extends ApplicationAdapter {
|
|||||||
boxBody.createFixture(boxPoly, 1);
|
boxBody.createFixture(boxPoly, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// we are done, all that's left is disposing the boxPoly
|
// We are done, all that's left is disposing the boxPoly.
|
||||||
boxPoly.dispose();
|
boxPoly.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -38,7 +38,7 @@ import com.esotericsoftware.spine.Animation.EventTimeline;
|
|||||||
import com.esotericsoftware.spine.Animation.MixBlend;
|
import com.esotericsoftware.spine.Animation.MixBlend;
|
||||||
import com.esotericsoftware.spine.Animation.MixDirection;
|
import com.esotericsoftware.spine.Animation.MixDirection;
|
||||||
|
|
||||||
/** Unit tests for {@link EventTimeline}. */
|
/** Unit tests to ensure {@link EventTimeline} is working as expected. */
|
||||||
public class EventTimelineTests {
|
public class EventTimelineTests {
|
||||||
private final SkeletonData skeletonData;
|
private final SkeletonData skeletonData;
|
||||||
private final Skeleton skeleton;
|
private final Skeleton skeleton;
|
||||||
|
|||||||
@ -44,6 +44,7 @@ import com.badlogic.gdx.utils.ScreenUtils;
|
|||||||
|
|
||||||
import com.esotericsoftware.spine.utils.TwoColorPolygonBatch;
|
import com.esotericsoftware.spine.utils.TwoColorPolygonBatch;
|
||||||
|
|
||||||
|
/** Demonstrates rendering an animation to a frame buffer (FBO) and then rendering the FBO to the screen. */
|
||||||
public class FboTest extends ApplicationAdapter {
|
public class FboTest extends ApplicationAdapter {
|
||||||
OrthographicCamera camera;
|
OrthographicCamera camera;
|
||||||
TwoColorPolygonBatch batch;
|
TwoColorPolygonBatch batch;
|
||||||
|
|||||||
@ -46,32 +46,22 @@ public class FrameByFrameTest extends ApplicationAdapter {
|
|||||||
|
|
||||||
TextureAtlas atlas;
|
TextureAtlas atlas;
|
||||||
float time;
|
float time;
|
||||||
Animation<AtlasSprite> walkAnimation, deathAnimation, current;
|
Animation<AtlasSprite> walkAnimation, current;
|
||||||
|
|
||||||
public void create () {
|
public void create () {
|
||||||
camera = new OrthographicCamera();
|
camera = new OrthographicCamera();
|
||||||
batch = new PolygonSpriteBatch();
|
batch = new PolygonSpriteBatch();
|
||||||
|
|
||||||
atlas = new TextureAtlas("spineboy/frame-by-frame.atlas");
|
atlas = new TextureAtlas("spineboy/spineboy-run.atlas");
|
||||||
|
|
||||||
walkAnimation = new Animation(1 / 20f, atlas.createSprites("spineboy-pro-walk"));
|
walkAnimation = new Animation(1 / 15f, atlas.createSprites("spineboy-pro-run"));
|
||||||
walkAnimation.setPlayMode(PlayMode.LOOP);
|
walkAnimation.setPlayMode(PlayMode.LOOP);
|
||||||
|
|
||||||
deathAnimation = new Animation(1 / 20f, atlas.createSprites("spineboy-pro-death"));
|
|
||||||
|
|
||||||
current = walkAnimation;
|
current = walkAnimation;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void render () {
|
public void render () {
|
||||||
time += Gdx.graphics.getDeltaTime();
|
time += Gdx.graphics.getDeltaTime();
|
||||||
if (current == deathAnimation && current.isAnimationFinished(time)) {
|
|
||||||
current = walkAnimation;
|
|
||||||
time = 0;
|
|
||||||
}
|
|
||||||
if (Gdx.input.justTouched()) {
|
|
||||||
current = deathAnimation;
|
|
||||||
time = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
AtlasSprite frame = current.getKeyFrame(time);
|
AtlasSprite frame = current.getKeyFrame(time);
|
||||||
float x = Math.round(Gdx.graphics.getWidth() / 2), y = 25;
|
float x = Math.round(Gdx.graphics.getWidth() / 2), y = 25;
|
||||||
|
|||||||
@ -37,7 +37,8 @@ import com.badlogic.gdx.graphics.g2d.PolygonSpriteBatch;
|
|||||||
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
||||||
import com.badlogic.gdx.utils.ScreenUtils;
|
import com.badlogic.gdx.utils.ScreenUtils;
|
||||||
|
|
||||||
public class SkinBonesMixAndMatchTest extends ApplicationAdapter {
|
/** Demonstrates creating and configuring a new skin at runtime. */
|
||||||
|
public class MixAndMatchTest extends ApplicationAdapter {
|
||||||
OrthographicCamera camera;
|
OrthographicCamera camera;
|
||||||
PolygonSpriteBatch batch;
|
PolygonSpriteBatch batch;
|
||||||
SkeletonRenderer renderer;
|
SkeletonRenderer renderer;
|
||||||
@ -67,13 +68,11 @@ public class SkinBonesMixAndMatchTest extends ApplicationAdapter {
|
|||||||
AnimationStateData stateData = new AnimationStateData(skeletonData); // Defines mixing (crossfading) between animations.
|
AnimationStateData stateData = new AnimationStateData(skeletonData); // Defines mixing (crossfading) between animations.
|
||||||
state = new AnimationState(stateData); // Holds the animation state for a skeleton (current animation, time, etc).
|
state = new AnimationState(stateData); // Holds the animation state for a skeleton (current animation, time, etc).
|
||||||
|
|
||||||
// Queue animations on track 0.
|
// Set animations on track 0.
|
||||||
state.setAnimation(0, "dance", true);
|
state.setAnimation(0, "dance", true);
|
||||||
|
|
||||||
// Create a new skin, by mixing and matching other skins
|
// Create a new skin, by mixing and matching other skins that fit together. Items making up the girl are individual skins.
|
||||||
// that fit together. Items making up the girl are individual
|
// Using the skin API, a new skin is created which is a combination of all these individual item skins.
|
||||||
// skins. Using the skin API, a new skin is created which is
|
|
||||||
// a combination of all these individual item skins.
|
|
||||||
Skin mixAndMatchSkin = new Skin("custom-girl");
|
Skin mixAndMatchSkin = new Skin("custom-girl");
|
||||||
mixAndMatchSkin.addSkin(skeletonData.findSkin("skin-base"));
|
mixAndMatchSkin.addSkin(skeletonData.findSkin("skin-base"));
|
||||||
mixAndMatchSkin.addSkin(skeletonData.findSkin("nose/short"));
|
mixAndMatchSkin.addSkin(skeletonData.findSkin("nose/short"));
|
||||||
@ -113,6 +112,6 @@ public class SkinBonesMixAndMatchTest extends ApplicationAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void main (String[] args) throws Exception {
|
public static void main (String[] args) throws Exception {
|
||||||
new Lwjgl3Application(new SkinBonesMixAndMatchTest());
|
new Lwjgl3Application(new MixAndMatchTest());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -59,6 +59,9 @@ import com.badlogic.gdx.utils.ScreenUtils;
|
|||||||
import com.esotericsoftware.spine.Animation.MixBlend;
|
import com.esotericsoftware.spine.Animation.MixBlend;
|
||||||
import com.esotericsoftware.spine.Animation.MixDirection;
|
import com.esotericsoftware.spine.Animation.MixDirection;
|
||||||
|
|
||||||
|
/** Demonstrates simplistic usage of lighting with normal maps.
|
||||||
|
* <p>
|
||||||
|
* Note the normals are not rotated when bones are rotated, making lighting incorrect. */
|
||||||
public class NormalMapTest extends ApplicationAdapter {
|
public class NormalMapTest extends ApplicationAdapter {
|
||||||
String skeletonPath, animationName;
|
String skeletonPath, animationName;
|
||||||
SpriteBatch batch;
|
SpriteBatch batch;
|
||||||
|
|||||||
@ -0,0 +1,138 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* Spine Runtimes License Agreement
|
||||||
|
* Last updated September 24, 2021. Replaces all prior versions.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013-2021, 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 com.esotericsoftware.spine;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.ApplicationAdapter;
|
||||||
|
import com.badlogic.gdx.Gdx;
|
||||||
|
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application;
|
||||||
|
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration;
|
||||||
|
import com.badlogic.gdx.files.FileHandle;
|
||||||
|
import com.badlogic.gdx.graphics.Color;
|
||||||
|
import com.badlogic.gdx.graphics.GL20;
|
||||||
|
import com.badlogic.gdx.graphics.OrthographicCamera;
|
||||||
|
import com.badlogic.gdx.graphics.Pixmap;
|
||||||
|
import com.badlogic.gdx.graphics.Pixmap.Format;
|
||||||
|
import com.badlogic.gdx.graphics.PixmapIO;
|
||||||
|
import com.badlogic.gdx.graphics.g2d.BitmapFont;
|
||||||
|
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
||||||
|
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||||
|
import com.badlogic.gdx.graphics.glutils.FrameBuffer;
|
||||||
|
import com.badlogic.gdx.utils.ScreenUtils;
|
||||||
|
|
||||||
|
import com.esotericsoftware.spine.Animation.MixBlend;
|
||||||
|
import com.esotericsoftware.spine.Animation.MixDirection;
|
||||||
|
import com.esotericsoftware.spine.utils.TwoColorPolygonBatch;
|
||||||
|
|
||||||
|
/** Demonstrates rendering an animation to a frame buffer (FBO) and then writing each frame as a PNG. */
|
||||||
|
public class PngExportTest extends ApplicationAdapter {
|
||||||
|
OrthographicCamera camera;
|
||||||
|
TwoColorPolygonBatch batch;
|
||||||
|
SkeletonRenderer renderer;
|
||||||
|
BitmapFont font;
|
||||||
|
|
||||||
|
TextureAtlas atlas;
|
||||||
|
Skeleton skeleton;
|
||||||
|
|
||||||
|
FrameBuffer fbo;
|
||||||
|
TextureRegion fboRegion;
|
||||||
|
boolean drawFbo = true;
|
||||||
|
|
||||||
|
public void create () {
|
||||||
|
camera = new OrthographicCamera();
|
||||||
|
batch = new TwoColorPolygonBatch();
|
||||||
|
renderer = new SkeletonRenderer();
|
||||||
|
renderer.setPremultipliedAlpha(true);
|
||||||
|
font = new BitmapFont();
|
||||||
|
font.setColor(Color.BLACK);
|
||||||
|
|
||||||
|
// Load the atlas and skeleton.
|
||||||
|
atlas = new TextureAtlas(Gdx.files.internal("spineboy/spineboy-pma.atlas"));
|
||||||
|
SkeletonJson json = new SkeletonJson(atlas);
|
||||||
|
json.setScale(0.66f);
|
||||||
|
SkeletonData skeletonData = json.readSkeletonData(Gdx.files.internal("spineboy/spineboy-ess.json"));
|
||||||
|
|
||||||
|
// Create a skeleton instance, set the position of its root bone, and update its world transform.
|
||||||
|
skeleton = new Skeleton(skeletonData);
|
||||||
|
skeleton.setPosition(250, 20);
|
||||||
|
skeleton.updateWorldTransform();
|
||||||
|
|
||||||
|
// Create an FBO and a texture region.
|
||||||
|
fbo = new FrameBuffer(Pixmap.Format.RGBA8888, 512, 512, false);
|
||||||
|
fboRegion = new TextureRegion(fbo.getColorBufferTexture());
|
||||||
|
|
||||||
|
// Create a pixmap of the same size.
|
||||||
|
Pixmap pixmap = new Pixmap(fbo.getWidth(), fbo.getHeight(), Format.RGBA8888);
|
||||||
|
|
||||||
|
// Configure the camera and batch for rendering to the FBO's size.
|
||||||
|
camera.setToOrtho(true, fbo.getWidth(), fbo.getHeight());
|
||||||
|
camera.update();
|
||||||
|
batch.getProjectionMatrix().set(camera.combined);
|
||||||
|
|
||||||
|
// Start rendering to the FBO.
|
||||||
|
fbo.begin();
|
||||||
|
|
||||||
|
// Pose the skeleton at regular intervals throughout the animation.
|
||||||
|
Animation animation = skeletonData.findAnimation("run");
|
||||||
|
float fps = 1 / 15f, time = 0;
|
||||||
|
int frame = 1;
|
||||||
|
while (time < animation.getDuration()) {
|
||||||
|
animation.apply(skeleton, time, time, false, null, 1, MixBlend.first, MixDirection.in);
|
||||||
|
skeleton.updateWorldTransform();
|
||||||
|
|
||||||
|
// Render the skeleton to the FBO.
|
||||||
|
ScreenUtils.clear(0, 0, 0, 0);
|
||||||
|
batch.begin();
|
||||||
|
renderer.draw(batch, skeleton);
|
||||||
|
batch.end();
|
||||||
|
|
||||||
|
// Copy the FBO to the pixmap and write it to a PNG file.
|
||||||
|
String name = animation.getName() + "_" + frame + ".png";
|
||||||
|
System.out.println(name);
|
||||||
|
Gdx.gl.glPixelStorei(GL20.GL_PACK_ALIGNMENT, 1); // Have glReadPixels use byte alignment for each pixel row.
|
||||||
|
Gdx.gl.glReadPixels(0, 0, fbo.getWidth(), fbo.getHeight(), GL20.GL_RGBA, GL20.GL_UNSIGNED_BYTE, pixmap.getPixels());
|
||||||
|
PixmapIO.writePNG(new FileHandle(name), pixmap);
|
||||||
|
|
||||||
|
frame++;
|
||||||
|
time += fps;
|
||||||
|
}
|
||||||
|
|
||||||
|
pixmap.dispose();
|
||||||
|
fbo.end();
|
||||||
|
|
||||||
|
// Terminate without showing a window.
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static public void main (String[] args) throws Exception {
|
||||||
|
Lwjgl3ApplicationConfiguration config = new Lwjgl3ApplicationConfiguration();
|
||||||
|
config.setInitialVisible(false);
|
||||||
|
new Lwjgl3Application(new PngExportTest(), config);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -35,8 +35,11 @@ import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application;
|
|||||||
import com.badlogic.gdx.graphics.GL20;
|
import com.badlogic.gdx.graphics.GL20;
|
||||||
import com.badlogic.gdx.graphics.OrthographicCamera;
|
import com.badlogic.gdx.graphics.OrthographicCamera;
|
||||||
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
||||||
|
|
||||||
import com.esotericsoftware.spine.utils.TwoColorPolygonBatch;
|
import com.esotericsoftware.spine.utils.TwoColorPolygonBatch;
|
||||||
|
|
||||||
|
/** Demonstrates loading, animating, and rendering a skeleton.
|
||||||
|
* @see SkeletonAssetManagerTest */
|
||||||
public class SimpleTest1 extends ApplicationAdapter {
|
public class SimpleTest1 extends ApplicationAdapter {
|
||||||
OrthographicCamera camera;
|
OrthographicCamera camera;
|
||||||
TwoColorPolygonBatch batch;
|
TwoColorPolygonBatch batch;
|
||||||
|
|||||||
@ -38,11 +38,13 @@ import com.badlogic.gdx.graphics.GL20;
|
|||||||
import com.badlogic.gdx.graphics.OrthographicCamera;
|
import com.badlogic.gdx.graphics.OrthographicCamera;
|
||||||
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
||||||
import com.badlogic.gdx.math.Vector3;
|
import com.badlogic.gdx.math.Vector3;
|
||||||
|
|
||||||
import com.esotericsoftware.spine.AnimationState.AnimationStateListener;
|
import com.esotericsoftware.spine.AnimationState.AnimationStateListener;
|
||||||
import com.esotericsoftware.spine.AnimationState.TrackEntry;
|
import com.esotericsoftware.spine.AnimationState.TrackEntry;
|
||||||
import com.esotericsoftware.spine.attachments.BoundingBoxAttachment;
|
import com.esotericsoftware.spine.attachments.BoundingBoxAttachment;
|
||||||
import com.esotericsoftware.spine.utils.TwoColorPolygonBatch;
|
import com.esotericsoftware.spine.utils.TwoColorPolygonBatch;
|
||||||
|
|
||||||
|
/** Demonstrates loading, animating, and rendering a skeleton with hit detectiong using a bounding box attachment. */
|
||||||
public class SimpleTest2 extends ApplicationAdapter {
|
public class SimpleTest2 extends ApplicationAdapter {
|
||||||
OrthographicCamera camera;
|
OrthographicCamera camera;
|
||||||
TwoColorPolygonBatch batch;
|
TwoColorPolygonBatch batch;
|
||||||
|
|||||||
@ -37,6 +37,7 @@ import com.badlogic.gdx.graphics.g2d.PolygonSpriteBatch;
|
|||||||
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
||||||
import com.badlogic.gdx.utils.ScreenUtils;
|
import com.badlogic.gdx.utils.ScreenUtils;
|
||||||
|
|
||||||
|
/** Demonstrates applying multiple animations at once using {@link AnimationState} tracks. */
|
||||||
public class SimpleTest3 extends ApplicationAdapter {
|
public class SimpleTest3 extends ApplicationAdapter {
|
||||||
OrthographicCamera camera;
|
OrthographicCamera camera;
|
||||||
PolygonSpriteBatch batch;
|
PolygonSpriteBatch batch;
|
||||||
@ -61,7 +62,7 @@ public class SimpleTest3 extends ApplicationAdapter {
|
|||||||
|
|
||||||
SkeletonJson loader = new SkeletonJson(atlas); // This loads skeleton JSON data, which is stateless.
|
SkeletonJson loader = new SkeletonJson(atlas); // This loads skeleton JSON data, which is stateless.
|
||||||
// SkeletonLoader loader = new SkeletonBinary(atlas); // Or use SkeletonBinary to load binary data.
|
// SkeletonLoader loader = new SkeletonBinary(atlas); // Or use SkeletonBinary to load binary data.
|
||||||
loader.setScale(0.1f); // Load the skeleton at 50% the size it was in Spine.
|
loader.setScale(0.5f); // Load the skeleton at 50% the size it was in Spine.
|
||||||
SkeletonData skeletonData = loader.readSkeletonData(Gdx.files.internal("raptor/raptor-pro.json"));
|
SkeletonData skeletonData = loader.readSkeletonData(Gdx.files.internal("raptor/raptor-pro.json"));
|
||||||
|
|
||||||
skeleton = new Skeleton(skeletonData); // Skeleton holds skeleton state (bone positions, slot attachments, etc).
|
skeleton = new Skeleton(skeletonData); // Skeleton holds skeleton state (bone positions, slot attachments, etc).
|
||||||
|
|||||||
@ -1,116 +0,0 @@
|
|||||||
/******************************************************************************
|
|
||||||
* Spine Runtimes License Agreement
|
|
||||||
* Last updated September 24, 2021. Replaces all prior versions.
|
|
||||||
*
|
|
||||||
* Copyright (c) 2013-2021, 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 com.esotericsoftware.spine;
|
|
||||||
|
|
||||||
import com.badlogic.gdx.ApplicationAdapter;
|
|
||||||
import com.badlogic.gdx.Gdx;
|
|
||||||
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application;
|
|
||||||
import com.badlogic.gdx.graphics.OrthographicCamera;
|
|
||||||
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
|
||||||
import com.badlogic.gdx.utils.ScreenUtils;
|
|
||||||
|
|
||||||
import com.esotericsoftware.spine.utils.TwoColorPolygonBatch;
|
|
||||||
|
|
||||||
public class SimpleTest4 extends ApplicationAdapter {
|
|
||||||
OrthographicCamera camera;
|
|
||||||
TwoColorPolygonBatch batch;
|
|
||||||
SkeletonRenderer renderer;
|
|
||||||
SkeletonRendererDebug debugRenderer;
|
|
||||||
|
|
||||||
TextureAtlas atlas;
|
|
||||||
Skeleton skeleton;
|
|
||||||
AnimationState state;
|
|
||||||
|
|
||||||
public void create () {
|
|
||||||
camera = new OrthographicCamera();
|
|
||||||
batch = new TwoColorPolygonBatch();
|
|
||||||
renderer = new SkeletonRenderer();
|
|
||||||
renderer.setPremultipliedAlpha(true); // PMA results in correct blending without outlines.
|
|
||||||
debugRenderer = new SkeletonRendererDebug();
|
|
||||||
debugRenderer.setBoundingBoxes(false);
|
|
||||||
debugRenderer.setRegionAttachments(false);
|
|
||||||
|
|
||||||
atlas = new TextureAtlas(Gdx.files.internal("goblins/goblins-pma.atlas"));
|
|
||||||
|
|
||||||
SkeletonJson loader = new SkeletonJson(atlas); // This loads skeleton JSON data, which is stateless.
|
|
||||||
// SkeletonLoader loader = new SkeletonBinary(atlas); // Or use SkeletonBinary to load binary data.
|
|
||||||
loader.setScale(1.3f); // Load the skeleton at 130% the size it was in Spine.
|
|
||||||
SkeletonData skeletonData = loader.readSkeletonData(Gdx.files.internal("goblins/goblins-pro.json"));
|
|
||||||
|
|
||||||
skeleton = new Skeleton(skeletonData); // Skeleton holds skeleton state (bone positions, slot attachments, etc).
|
|
||||||
skeleton.setPosition(250, 20);
|
|
||||||
|
|
||||||
AnimationStateData stateData = new AnimationStateData(skeletonData); // Defines mixing (crossfading) between animations.
|
|
||||||
|
|
||||||
state = new AnimationState(stateData); // Holds the animation state for a skeleton (current animation, time, etc).
|
|
||||||
state.setTimeScale(0.5f); // Slow all animations down to 50% speed.
|
|
||||||
|
|
||||||
// Queue animations on track 0.
|
|
||||||
state.setAnimation(0, "walk", true);
|
|
||||||
|
|
||||||
// Create an empty skin and copy the goblingirl skin into it.
|
|
||||||
Skin skin = new Skin("test");
|
|
||||||
skin.copySkin(skeletonData.findSkin("goblingirl"));
|
|
||||||
skeleton.setSkin(skin);
|
|
||||||
skeleton.setSlotsToSetupPose();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void render () {
|
|
||||||
state.update(Gdx.graphics.getDeltaTime()); // Update the animation time.
|
|
||||||
|
|
||||||
ScreenUtils.clear(0, 0, 0, 0);
|
|
||||||
|
|
||||||
state.apply(skeleton); // Poses skeleton using current animations. This sets the bones' local SRT.
|
|
||||||
skeleton.updateWorldTransform(); // Uses the bones' local SRT to compute their world SRT.
|
|
||||||
|
|
||||||
// Configure the camera, SpriteBatch, and SkeletonRendererDebug.
|
|
||||||
camera.update();
|
|
||||||
batch.getProjectionMatrix().set(camera.combined);
|
|
||||||
debugRenderer.getShapeRenderer().setProjectionMatrix(camera.combined);
|
|
||||||
|
|
||||||
batch.begin();
|
|
||||||
renderer.draw(batch, skeleton); // Draw the skeleton images.
|
|
||||||
batch.end();
|
|
||||||
|
|
||||||
debugRenderer.draw(skeleton); // Draw debug lines.
|
|
||||||
}
|
|
||||||
|
|
||||||
public void resize (int width, int height) {
|
|
||||||
camera.setToOrtho(false); // Update camera with new size.
|
|
||||||
}
|
|
||||||
|
|
||||||
public void dispose () {
|
|
||||||
atlas.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main (String[] args) throws Exception {
|
|
||||||
new Lwjgl3Application(new SimpleTest4());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -41,7 +41,7 @@ import com.badlogic.gdx.utils.ScreenUtils;
|
|||||||
import com.esotericsoftware.spine.utils.SkeletonDataLoader;
|
import com.esotericsoftware.spine.utils.SkeletonDataLoader;
|
||||||
import com.esotericsoftware.spine.utils.SkeletonDataLoader.SkeletonDataParameter;
|
import com.esotericsoftware.spine.utils.SkeletonDataLoader.SkeletonDataParameter;
|
||||||
|
|
||||||
/** Like {@link SimpleTest1}, but using {@link AssetManager} to load the atlas and skeleton data. */
|
/** Demonstrates loading an atlas and skeleton using {@link AssetManager}. */
|
||||||
public class SkeletonAssetManagerTest extends ApplicationAdapter {
|
public class SkeletonAssetManagerTest extends ApplicationAdapter {
|
||||||
OrthographicCamera camera;
|
OrthographicCamera camera;
|
||||||
PolygonSpriteBatch batch;
|
PolygonSpriteBatch batch;
|
||||||
@ -85,8 +85,8 @@ public class SkeletonAssetManagerTest extends ApplicationAdapter {
|
|||||||
skeleton = new Skeleton(skeletonData); // Skeleton holds skeleton state (bone positions, slot attachments, etc).
|
skeleton = new Skeleton(skeletonData); // Skeleton holds skeleton state (bone positions, slot attachments, etc).
|
||||||
skeleton.setPosition(250, 20);
|
skeleton.setPosition(250, 20);
|
||||||
|
|
||||||
AnimationStateData stateData = new AnimationStateData(skeletonData); // Defines mixing (crossfading) between
|
// Define the default mixing (crossfading) between animations.
|
||||||
// animations.
|
AnimationStateData stateData = new AnimationStateData(skeletonData);
|
||||||
stateData.setMix("run", "jump", 0.2f);
|
stateData.setMix("run", "jump", 0.2f);
|
||||||
stateData.setMix("jump", "run", 0.2f);
|
stateData.setMix("jump", "run", 0.2f);
|
||||||
|
|
||||||
|
|||||||
@ -39,6 +39,7 @@ import com.badlogic.gdx.utils.ScreenUtils;
|
|||||||
|
|
||||||
import com.esotericsoftware.spine.attachments.SkeletonAttachment;
|
import com.esotericsoftware.spine.attachments.SkeletonAttachment;
|
||||||
|
|
||||||
|
/** Demonstrates using {@link SkeletonAttachment} to use an entire skeleton as an attachment. */
|
||||||
public class SkeletonAttachmentTest extends ApplicationAdapter {
|
public class SkeletonAttachmentTest extends ApplicationAdapter {
|
||||||
OrthographicCamera camera;
|
OrthographicCamera camera;
|
||||||
PolygonSpriteBatch batch;
|
PolygonSpriteBatch batch;
|
||||||
|
|||||||
@ -42,6 +42,7 @@ import com.badlogic.gdx.utils.ScreenUtils;
|
|||||||
|
|
||||||
import com.esotericsoftware.spine.vertexeffects.SwirlEffect;
|
import com.esotericsoftware.spine.vertexeffects.SwirlEffect;
|
||||||
|
|
||||||
|
/** Boilerplate for basic skeleton rendering, used for various testing. */
|
||||||
public class TestHarness extends ApplicationAdapter {
|
public class TestHarness extends ApplicationAdapter {
|
||||||
// static String JSON = "coin/coin-pro.json";
|
// static String JSON = "coin/coin-pro.json";
|
||||||
// static String ATLAS = "coin/coin-pma.atlas";
|
// static String ATLAS = "coin/coin-pma.atlas";
|
||||||
|
|||||||
@ -40,7 +40,10 @@ import com.badlogic.gdx.utils.ScreenUtils;
|
|||||||
import com.esotericsoftware.spine.Animation.MixBlend;
|
import com.esotericsoftware.spine.Animation.MixBlend;
|
||||||
import com.esotericsoftware.spine.Animation.MixDirection;
|
import com.esotericsoftware.spine.Animation.MixDirection;
|
||||||
|
|
||||||
public class MixTest extends ApplicationAdapter {
|
/** Demonstrates using the timeline API. See {@link SimpleTest1} for a higher level API using {@link AnimationState}.
|
||||||
|
* <p>
|
||||||
|
* See: http://esotericsoftware.com/spine-applying-animations */
|
||||||
|
public class TimelineApiTest extends ApplicationAdapter {
|
||||||
SpriteBatch batch;
|
SpriteBatch batch;
|
||||||
float time;
|
float time;
|
||||||
Array<Event> events = new Array();
|
Array<Event> events = new Array();
|
||||||
@ -139,6 +142,6 @@ public class MixTest extends ApplicationAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void main (String[] args) throws Exception {
|
public static void main (String[] args) throws Exception {
|
||||||
new Lwjgl3Application(new MixTest());
|
new Lwjgl3Application(new TimelineApiTest());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -39,8 +39,10 @@ import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
|||||||
import com.badlogic.gdx.math.Interpolation;
|
import com.badlogic.gdx.math.Interpolation;
|
||||||
import com.badlogic.gdx.utils.ScreenUtils;
|
import com.badlogic.gdx.utils.ScreenUtils;
|
||||||
|
|
||||||
|
import com.esotericsoftware.spine.SkeletonRenderer.VertexEffect;
|
||||||
import com.esotericsoftware.spine.vertexeffects.SwirlEffect;
|
import com.esotericsoftware.spine.vertexeffects.SwirlEffect;
|
||||||
|
|
||||||
|
/** Demonstrates applying a {@link VertexEffect}. */
|
||||||
public class VertexEffectTest extends ApplicationAdapter {
|
public class VertexEffectTest extends ApplicationAdapter {
|
||||||
OrthographicCamera camera;
|
OrthographicCamera camera;
|
||||||
PolygonSpriteBatch batch;
|
PolygonSpriteBatch batch;
|
||||||
|
|||||||
@ -0,0 +1,2 @@
|
|||||||
|
eclipse.preferences.version=1
|
||||||
|
encoding/<project>=Cp1252
|
||||||
@ -364,6 +364,18 @@ public class Skeleton {
|
|||||||
public void updateWorldTransform (Bone parent) {
|
public void updateWorldTransform (Bone parent) {
|
||||||
if (parent == null) throw new IllegalArgumentException("parent cannot be null.");
|
if (parent == null) throw new IllegalArgumentException("parent cannot be null.");
|
||||||
|
|
||||||
|
Object[] bones = this.bones.items;
|
||||||
|
for (int i = 1, n = this.bones.size; i < n; i++) { // Skip root bone.
|
||||||
|
Bone bone = (Bone)bones[i];
|
||||||
|
bone.ax = bone.x;
|
||||||
|
bone.ay = bone.y;
|
||||||
|
bone.arotation = bone.rotation;
|
||||||
|
bone.ascaleX = bone.scaleX;
|
||||||
|
bone.ascaleY = bone.scaleY;
|
||||||
|
bone.ashearX = bone.shearX;
|
||||||
|
bone.ashearY = bone.shearY;
|
||||||
|
}
|
||||||
|
|
||||||
// Apply the parent bone transform to the root bone. The root bone always inherits scale, rotation and reflection.
|
// Apply the parent bone transform to the root bone. The root bone always inherits scale, rotation and reflection.
|
||||||
Bone rootBone = getRootBone();
|
Bone rootBone = getRootBone();
|
||||||
float pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d;
|
float pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d;
|
||||||
|
|||||||
@ -0,0 +1,2 @@
|
|||||||
|
eclipse.preferences.version=1
|
||||||
|
encoding/<project>=Cp1252
|
||||||
@ -455,7 +455,7 @@ namespace Spine.Unity.Editor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (cc.changed) {
|
if (cc.changed) {
|
||||||
targetSkeletonDataAsset.FillStateData();
|
targetSkeletonDataAsset.FillStateData(quiet: true);
|
||||||
EditorUtility.SetDirty(targetSkeletonDataAsset);
|
EditorUtility.SetDirty(targetSkeletonDataAsset);
|
||||||
serializedObject.ApplyModifiedProperties();
|
serializedObject.ApplyModifiedProperties();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -61,11 +61,34 @@ namespace Spine.Unity.Editor {
|
|||||||
return noneLabel;
|
return noneLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GUIStyle errorPopupStyle;
|
||||||
|
GUIStyle ErrorPopupStyle {
|
||||||
|
get {
|
||||||
|
if (errorPopupStyle == null) errorPopupStyle = new GUIStyle(EditorStyles.popup);
|
||||||
|
errorPopupStyle.normal.textColor = Color.red;
|
||||||
|
errorPopupStyle.hover.textColor = Color.red;
|
||||||
|
errorPopupStyle.focused.textColor = Color.red;
|
||||||
|
errorPopupStyle.active.textColor = Color.red;
|
||||||
|
return errorPopupStyle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected T TargetAttribute { get { return (T)attribute; } }
|
protected T TargetAttribute { get { return (T)attribute; } }
|
||||||
protected SerializedProperty SerializedProperty { get; private set; }
|
protected SerializedProperty SerializedProperty { get; private set; }
|
||||||
|
|
||||||
protected abstract Texture2D Icon { get; }
|
protected abstract Texture2D Icon { get; }
|
||||||
|
|
||||||
|
protected bool IsValueValid (SerializedProperty property) {
|
||||||
|
if (skeletonDataAsset != null) {
|
||||||
|
SkeletonData skeletonData = skeletonDataAsset.GetSkeletonData(true);
|
||||||
|
if (skeletonData != null && !string.IsNullOrEmpty(property.stringValue))
|
||||||
|
return IsValueValid(skeletonData, property);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual bool IsValueValid (SkeletonData skeletonData, SerializedProperty property) { return true; }
|
||||||
|
|
||||||
public override void OnGUI (Rect position, SerializedProperty property, GUIContent label) {
|
public override void OnGUI (Rect position, SerializedProperty property, GUIContent label) {
|
||||||
SerializedProperty = property;
|
SerializedProperty = property;
|
||||||
|
|
||||||
@ -123,8 +146,10 @@ namespace Spine.Unity.Editor {
|
|||||||
position = EditorGUI.PrefixLabel(position, label);
|
position = EditorGUI.PrefixLabel(position, label);
|
||||||
|
|
||||||
Texture2D image = Icon;
|
Texture2D image = Icon;
|
||||||
|
GUIStyle usedStyle = IsValueValid(property) ? EditorStyles.popup : ErrorPopupStyle;
|
||||||
string propertyStringValue = (property.hasMultipleDifferentValues) ? SpineInspectorUtility.EmDash : property.stringValue;
|
string propertyStringValue = (property.hasMultipleDifferentValues) ? SpineInspectorUtility.EmDash : property.stringValue;
|
||||||
if (GUI.Button(position, string.IsNullOrEmpty(propertyStringValue) ? NoneLabel(image) : SpineInspectorUtility.TempContent(propertyStringValue, image), EditorStyles.popup))
|
if (GUI.Button(position, string.IsNullOrEmpty(propertyStringValue) ? NoneLabel(image) :
|
||||||
|
SpineInspectorUtility.TempContent(propertyStringValue, image), usedStyle))
|
||||||
Selector(property);
|
Selector(property);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,6 +199,10 @@ namespace Spine.Unity.Editor {
|
|||||||
|
|
||||||
protected override Texture2D Icon { get { return SpineEditorUtilities.Icons.slot; } }
|
protected override Texture2D Icon { get { return SpineEditorUtilities.Icons.slot; } }
|
||||||
|
|
||||||
|
protected override bool IsValueValid (SkeletonData skeletonData, SerializedProperty property) {
|
||||||
|
return skeletonData.FindSlot(property.stringValue) != null;
|
||||||
|
}
|
||||||
|
|
||||||
protected override void PopulateMenu (GenericMenu menu, SerializedProperty property, SpineSlot targetAttribute, SkeletonData data) {
|
protected override void PopulateMenu (GenericMenu menu, SerializedProperty property, SpineSlot targetAttribute, SkeletonData data) {
|
||||||
if (TargetAttribute.includeNone)
|
if (TargetAttribute.includeNone)
|
||||||
menu.AddItem(new GUIContent(NoneString), !property.hasMultipleDifferentValues && string.IsNullOrEmpty(property.stringValue), HandleSelect, new SpineDrawerValuePair(string.Empty, property));
|
menu.AddItem(new GUIContent(NoneString), !property.hasMultipleDifferentValues && string.IsNullOrEmpty(property.stringValue), HandleSelect, new SpineDrawerValuePair(string.Empty, property));
|
||||||
@ -223,6 +252,10 @@ namespace Spine.Unity.Editor {
|
|||||||
|
|
||||||
internal override string NoneString { get { return TargetAttribute.defaultAsEmptyString ? DefaultSkinName : NoneStringConstant; } }
|
internal override string NoneString { get { return TargetAttribute.defaultAsEmptyString ? DefaultSkinName : NoneStringConstant; } }
|
||||||
|
|
||||||
|
protected override bool IsValueValid (SkeletonData skeletonData, SerializedProperty property) {
|
||||||
|
return skeletonData.FindSkin(property.stringValue) != null;
|
||||||
|
}
|
||||||
|
|
||||||
public static void GetSkinMenuItems (SkeletonData data, List<string> outputNames, List<GUIContent> outputMenuItems, bool includeNone = true) {
|
public static void GetSkinMenuItems (SkeletonData data, List<string> outputNames, List<GUIContent> outputMenuItems, bool includeNone = true) {
|
||||||
if (data == null) return;
|
if (data == null) return;
|
||||||
if (outputNames == null) return;
|
if (outputNames == null) return;
|
||||||
@ -269,6 +302,10 @@ namespace Spine.Unity.Editor {
|
|||||||
|
|
||||||
protected override Texture2D Icon { get { return SpineEditorUtilities.Icons.animation; } }
|
protected override Texture2D Icon { get { return SpineEditorUtilities.Icons.animation; } }
|
||||||
|
|
||||||
|
protected override bool IsValueValid (SkeletonData skeletonData, SerializedProperty property) {
|
||||||
|
return skeletonData.FindAnimation(property.stringValue) != null;
|
||||||
|
}
|
||||||
|
|
||||||
public static void GetAnimationMenuItems (SkeletonData data, List<string> outputNames, List<GUIContent> outputMenuItems, bool includeNone = true) {
|
public static void GetAnimationMenuItems (SkeletonData data, List<string> outputNames, List<GUIContent> outputMenuItems, bool includeNone = true) {
|
||||||
if (data == null) return;
|
if (data == null) return;
|
||||||
if (outputNames == null) return;
|
if (outputNames == null) return;
|
||||||
@ -311,6 +348,10 @@ namespace Spine.Unity.Editor {
|
|||||||
|
|
||||||
protected override Texture2D Icon { get { return SpineEditorUtilities.Icons.userEvent; } }
|
protected override Texture2D Icon { get { return SpineEditorUtilities.Icons.userEvent; } }
|
||||||
|
|
||||||
|
protected override bool IsValueValid (SkeletonData skeletonData, SerializedProperty property) {
|
||||||
|
return skeletonData.FindEvent(property.stringValue) != null;
|
||||||
|
}
|
||||||
|
|
||||||
public static void GetEventMenuItems (SkeletonData data, List<string> eventNames, List<GUIContent> menuItems, bool includeNone = true) {
|
public static void GetEventMenuItems (SkeletonData data, List<string> eventNames, List<GUIContent> menuItems, bool includeNone = true) {
|
||||||
if (data == null) return;
|
if (data == null) return;
|
||||||
|
|
||||||
@ -356,6 +397,10 @@ namespace Spine.Unity.Editor {
|
|||||||
|
|
||||||
protected override Texture2D Icon { get { return SpineEditorUtilities.Icons.constraintIK; } }
|
protected override Texture2D Icon { get { return SpineEditorUtilities.Icons.constraintIK; } }
|
||||||
|
|
||||||
|
protected override bool IsValueValid (SkeletonData skeletonData, SerializedProperty property) {
|
||||||
|
return skeletonData.FindIkConstraint(property.stringValue) != null;
|
||||||
|
}
|
||||||
|
|
||||||
protected override void PopulateMenu (GenericMenu menu, SerializedProperty property, SpineIkConstraint targetAttribute, SkeletonData data) {
|
protected override void PopulateMenu (GenericMenu menu, SerializedProperty property, SpineIkConstraint targetAttribute, SkeletonData data) {
|
||||||
var constraints = skeletonDataAsset.GetSkeletonData(false).IkConstraints;
|
var constraints = skeletonDataAsset.GetSkeletonData(false).IkConstraints;
|
||||||
|
|
||||||
@ -376,6 +421,10 @@ namespace Spine.Unity.Editor {
|
|||||||
|
|
||||||
protected override Texture2D Icon { get { return SpineEditorUtilities.Icons.constraintTransform; } }
|
protected override Texture2D Icon { get { return SpineEditorUtilities.Icons.constraintTransform; } }
|
||||||
|
|
||||||
|
protected override bool IsValueValid (SkeletonData skeletonData, SerializedProperty property) {
|
||||||
|
return skeletonData.FindTransformConstraint(property.stringValue) != null;
|
||||||
|
}
|
||||||
|
|
||||||
protected override void PopulateMenu (GenericMenu menu, SerializedProperty property, SpineTransformConstraint targetAttribute, SkeletonData data) {
|
protected override void PopulateMenu (GenericMenu menu, SerializedProperty property, SpineTransformConstraint targetAttribute, SkeletonData data) {
|
||||||
var constraints = skeletonDataAsset.GetSkeletonData(false).TransformConstraints;
|
var constraints = skeletonDataAsset.GetSkeletonData(false).TransformConstraints;
|
||||||
|
|
||||||
@ -395,6 +444,10 @@ namespace Spine.Unity.Editor {
|
|||||||
|
|
||||||
protected override Texture2D Icon { get { return SpineEditorUtilities.Icons.constraintPath; } }
|
protected override Texture2D Icon { get { return SpineEditorUtilities.Icons.constraintPath; } }
|
||||||
|
|
||||||
|
protected override bool IsValueValid (SkeletonData skeletonData, SerializedProperty property) {
|
||||||
|
return skeletonData.FindPathConstraint(property.stringValue) != null;
|
||||||
|
}
|
||||||
|
|
||||||
protected override void PopulateMenu (GenericMenu menu, SerializedProperty property, SpinePathConstraint targetAttribute, SkeletonData data) {
|
protected override void PopulateMenu (GenericMenu menu, SerializedProperty property, SpinePathConstraint targetAttribute, SkeletonData data) {
|
||||||
var constraints = skeletonDataAsset.GetSkeletonData(false).PathConstraints;
|
var constraints = skeletonDataAsset.GetSkeletonData(false).PathConstraints;
|
||||||
|
|
||||||
@ -516,6 +569,10 @@ namespace Spine.Unity.Editor {
|
|||||||
|
|
||||||
protected override Texture2D Icon { get { return SpineEditorUtilities.Icons.bone; } }
|
protected override Texture2D Icon { get { return SpineEditorUtilities.Icons.bone; } }
|
||||||
|
|
||||||
|
protected override bool IsValueValid (SkeletonData skeletonData, SerializedProperty property) {
|
||||||
|
return skeletonData.FindBone(property.stringValue) != null;
|
||||||
|
}
|
||||||
|
|
||||||
protected override void PopulateMenu (GenericMenu menu, SerializedProperty property, SpineBone targetAttribute, SkeletonData data) {
|
protected override void PopulateMenu (GenericMenu menu, SerializedProperty property, SpineBone targetAttribute, SkeletonData data) {
|
||||||
menu.AddDisabledItem(new GUIContent(skeletonDataAsset.name));
|
menu.AddDisabledItem(new GUIContent(skeletonDataAsset.name));
|
||||||
menu.AddSeparator("");
|
menu.AddSeparator("");
|
||||||
|
|||||||
@ -349,6 +349,8 @@ namespace Spine.Unity.Editor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AddDependentAtlasIfImageChanged(atlasPaths, imagePaths);
|
||||||
|
|
||||||
// Import atlases first.
|
// Import atlases first.
|
||||||
var newAtlases = new List<AtlasAssetBase>();
|
var newAtlases = new List<AtlasAssetBase>();
|
||||||
foreach (string ap in atlasPaths) {
|
foreach (string ap in atlasPaths) {
|
||||||
@ -453,6 +455,18 @@ namespace Spine.Unity.Editor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void AddDependentAtlasIfImageChanged (List<string> atlasPaths, List<string> imagePaths) {
|
||||||
|
foreach (var imagePath in imagePaths) {
|
||||||
|
string atlasPath = imagePath.Replace(".png", ".atlas.txt");
|
||||||
|
if (!System.IO.File.Exists(atlasPath))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!atlasPaths.Contains(atlasPath)) {
|
||||||
|
atlasPaths.Add(atlasPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void AddDependentSkeletonIfAtlasChanged (List<PathAndProblemInfo> skeletonPaths, List<string> atlasPaths) {
|
static void AddDependentSkeletonIfAtlasChanged (List<PathAndProblemInfo> skeletonPaths, List<string> atlasPaths) {
|
||||||
foreach (var atlasPath in atlasPaths) {
|
foreach (var atlasPath in atlasPaths) {
|
||||||
string skeletonPathJson = atlasPath.Replace(".atlas.txt", ".json");
|
string skeletonPathJson = atlasPath.Replace(".atlas.txt", ".json");
|
||||||
|
|||||||
@ -217,14 +217,30 @@ namespace Spine.Unity {
|
|||||||
FillStateData();
|
FillStateData();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void FillStateData () {
|
public void FillStateData (bool quiet = false) {
|
||||||
if (stateData != null) {
|
if (stateData != null) {
|
||||||
stateData.DefaultMix = defaultMix;
|
stateData.DefaultMix = defaultMix;
|
||||||
|
|
||||||
for (int i = 0, n = fromAnimation.Length; i < n; i++) {
|
for (int i = 0, n = fromAnimation.Length; i < n; i++) {
|
||||||
if (fromAnimation[i].Length == 0 || toAnimation[i].Length == 0)
|
string fromAnimationName = fromAnimation[i];
|
||||||
|
string toAnimationName = toAnimation[i];
|
||||||
|
if (fromAnimationName.Length == 0 || toAnimationName.Length == 0)
|
||||||
continue;
|
continue;
|
||||||
stateData.SetMix(fromAnimation[i], toAnimation[i], duration[i]);
|
#if UNITY_EDITOR
|
||||||
|
if (skeletonData.FindAnimation(fromAnimationName) == null) {
|
||||||
|
if (!quiet) Debug.LogError(
|
||||||
|
string.Format("Custom Mix Durations: Animation '{0}' not found, was it renamed?",
|
||||||
|
fromAnimationName), this);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (skeletonData.FindAnimation(toAnimationName) == null) {
|
||||||
|
if (!quiet) Debug.LogError(
|
||||||
|
string.Format("Custom Mix Durations: Animation '{0}' not found, was it renamed?",
|
||||||
|
toAnimationName), this);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
stateData.SetMix(fromAnimationName, toAnimationName, duration[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -52,14 +52,23 @@ namespace Spine.Unity.AttachmentTools {
|
|||||||
/// <param name="useOriginalRegionScale">If <c>true</c> and the original Attachment is a RegionAttachment, then
|
/// <param name="useOriginalRegionScale">If <c>true</c> and the original Attachment is a RegionAttachment, then
|
||||||
/// the original region's scale value is used instead of the Sprite's pixels per unit property. Since uniform scale is used,
|
/// the original region's scale value is used instead of the Sprite's pixels per unit property. Since uniform scale is used,
|
||||||
/// x scale of the original attachment (width scale) is used, scale in y direction (height scale) is ignored.</param>
|
/// x scale of the original attachment (width scale) is used, scale in y direction (height scale) is ignored.</param>
|
||||||
|
/// <param name="pmaCloneTextureFormat">If <c>premultiplyAlpha</c> is <c>true></c>, the TextureFormat of the
|
||||||
|
/// newly created PMA attachment Texture.</param>
|
||||||
|
/// <param name="pmaCloneMipmaps">If <c>premultiplyAlpha</c> is <ctrue></c>, whether the newly created
|
||||||
|
/// PMA attachment Texture has mipmaps enabled.</param>
|
||||||
/// <remarks>When parameter <c>premultiplyAlpha</c> is set to <c>true</c>, a premultiply alpha clone of the
|
/// <remarks>When parameter <c>premultiplyAlpha</c> is set to <c>true</c>, a premultiply alpha clone of the
|
||||||
/// original texture will be created. Additionally, this PMA Texture clone is cached for later re-use,
|
/// original texture will be created. Additionally, this PMA Texture clone is cached for later re-use,
|
||||||
/// which might steadily increase the Texture memory footprint when used excessively.
|
/// which might steadily increase the Texture memory footprint when used excessively.
|
||||||
/// See <see cref="AtlasUtilities.ClearCache()"/> on how to clear these cached textures.</remarks>
|
/// See <see cref="AtlasUtilities.ClearCache()"/> on how to clear these cached textures.</remarks>
|
||||||
public static Attachment GetRemappedClone (this Attachment o, Sprite sprite, Material sourceMaterial,
|
public static Attachment GetRemappedClone (this Attachment o, Sprite sprite, Material sourceMaterial,
|
||||||
bool premultiplyAlpha = true, bool cloneMeshAsLinked = true, bool useOriginalRegionSize = false,
|
bool premultiplyAlpha = true, bool cloneMeshAsLinked = true, bool useOriginalRegionSize = false,
|
||||||
bool pivotShiftsMeshUVCoords = true, bool useOriginalRegionScale = false) {
|
bool pivotShiftsMeshUVCoords = true, bool useOriginalRegionScale = false,
|
||||||
var atlasRegion = premultiplyAlpha ? sprite.ToAtlasRegionPMAClone(sourceMaterial) : sprite.ToAtlasRegion(new Material(sourceMaterial) { mainTexture = sprite.texture });
|
TextureFormat pmaCloneTextureFormat = AtlasUtilities.SpineTextureFormat,
|
||||||
|
bool pmaCloneMipmaps = AtlasUtilities.UseMipMaps) {
|
||||||
|
|
||||||
|
var atlasRegion = premultiplyAlpha ?
|
||||||
|
sprite.ToAtlasRegionPMAClone(sourceMaterial, pmaCloneTextureFormat, pmaCloneMipmaps) :
|
||||||
|
sprite.ToAtlasRegion(new Material(sourceMaterial) { mainTexture = sprite.texture });
|
||||||
if (!pivotShiftsMeshUVCoords && o is MeshAttachment) {
|
if (!pivotShiftsMeshUVCoords && o is MeshAttachment) {
|
||||||
// prevent non-central sprite pivot setting offsetX/Y and shifting uv coords out of mesh bounds
|
// prevent non-central sprite pivot setting offsetX/Y and shifting uv coords out of mesh bounds
|
||||||
atlasRegion.offsetX = 0;
|
atlasRegion.offsetX = 0;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user