mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-04 14:24:53 +08:00
Add spine-android to formatter
This commit is contained in:
parent
5de003cb8f
commit
12f11cbbf9
@ -8,7 +8,8 @@ spotless {
|
|||||||
lineEndings 'UNIX'
|
lineEndings 'UNIX'
|
||||||
|
|
||||||
java {
|
java {
|
||||||
target 'spine-libgdx/**/*.java'
|
target 'spine-libgdx/**/*.java',
|
||||||
|
'spine-android/**/*.java'
|
||||||
eclipse().configFile('formatters/eclipse-formatter.xml')
|
eclipse().configFile('formatters/eclipse-formatter.xml')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -39,13 +39,13 @@ import com.esotericsoftware.spine.android.SpineController;
|
|||||||
import com.esotericsoftware.spine.android.SpineView;
|
import com.esotericsoftware.spine.android.SpineView;
|
||||||
|
|
||||||
public class SimpleAnimationActivity extends AppCompatActivity {
|
public class SimpleAnimationActivity extends AppCompatActivity {
|
||||||
/** @noinspection FieldCanBeLocal*/
|
/** @noinspection FieldCanBeLocal */
|
||||||
private SpineView spineView;
|
private SpineView spineView;
|
||||||
/** @noinspection FieldCanBeLocal*/
|
/** @noinspection FieldCanBeLocal */
|
||||||
private SpineController spineController;
|
private SpineController spineController;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate (Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_simple_animation);
|
setContentView(R.layout.activity_simple_animation);
|
||||||
|
|
||||||
@ -59,16 +59,14 @@ public class SimpleAnimationActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
spineView = findViewById(R.id.spineView);
|
spineView = findViewById(R.id.spineView);
|
||||||
spineController = new SpineController( controller ->
|
spineController = new SpineController(controller -> controller.getAnimationState().setAnimation(0, "walk", true));
|
||||||
controller.getAnimationState().setAnimation(0, "walk", true)
|
|
||||||
);
|
|
||||||
|
|
||||||
spineView.setController(spineController);
|
spineView.setController(spineController);
|
||||||
spineView.loadFromAsset("spineboy.atlas","spineboy-pro.json");
|
spineView.loadFromAsset("spineboy.atlas", "spineboy-pro.json");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public boolean onOptionsItemSelected (MenuItem item) {
|
||||||
if (item.getItemId() == android.R.id.home) {
|
if (item.getItemId() == android.R.id.home) {
|
||||||
finish();
|
finish();
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
14
spine-android/publish.sh
Executable file
14
spine-android/publish.sh
Executable file
@ -0,0 +1,14 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
#
|
||||||
|
# 1. Set up PGP key for signing
|
||||||
|
# 2. Create ~/.gradle/gradle.properties
|
||||||
|
# 3. Add
|
||||||
|
# ossrhUsername=<sonatype-token-user-name>
|
||||||
|
# ossrhPassword=<sonatype-token>
|
||||||
|
# signing.gnupg.passphrase=<pgp-key-passphrase>
|
||||||
|
#
|
||||||
|
# After publishing via this script, log into https://oss.sonatype.org and release it manually after
|
||||||
|
# checks pass ("Release & Drop").
|
||||||
|
set -e
|
||||||
|
./gradlew publishReleasePublicationToSonaTypeRepository --info
|
||||||
@ -40,7 +40,7 @@ dependencies {
|
|||||||
androidTestImplementation(libs.androidx.espresso.core)
|
androidTestImplementation(libs.androidx.espresso.core)
|
||||||
}
|
}
|
||||||
|
|
||||||
val libraryVersion = "4.2.2-SNAPSHOT" // Update this as needed
|
val libraryVersion = "4.2.3-SNAPSHOT" // Update this as needed
|
||||||
|
|
||||||
tasks.register<Jar>("sourceJar") {
|
tasks.register<Jar>("sourceJar") {
|
||||||
archiveClassifier.set("sources")
|
archiveClassifier.set("sources")
|
||||||
@ -125,5 +125,6 @@ afterEvaluate {
|
|||||||
signing {
|
signing {
|
||||||
useGpgCmd()
|
useGpgCmd()
|
||||||
sign(publishing.publications["release"])
|
sign(publishing.publications["release"])
|
||||||
|
sign(tasks.getByName("sourceJar"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
package com.esotericsoftware.android;
|
package com.esotericsoftware.android;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@ -10,15 +11,13 @@ import org.junit.runner.RunWith;
|
|||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
/**
|
/** Instrumented test, which will execute on an Android device.
|
||||||
* Instrumented test, which will execute on an Android device.
|
|
||||||
*
|
*
|
||||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a> */
|
||||||
*/
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class ExampleInstrumentedTest {
|
public class ExampleInstrumentedTest {
|
||||||
@Test
|
@Test
|
||||||
public void useAppContext() {
|
public void useAppContext () {
|
||||||
// Context of the app under test.
|
// Context of the app under test.
|
||||||
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||||
assertEquals("com.esotericsoftware.spine.test", appContext.getPackageName());
|
assertEquals("com.esotericsoftware.spine.test", appContext.getPackageName());
|
||||||
|
|||||||
@ -48,25 +48,26 @@ import com.esotericsoftware.spine.android.utils.SkeletonDataUtils;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
/**
|
/** A {@link AndroidSkeletonDrawable} bundles loading updating updating an {@link AndroidTextureAtlas}, {@link Skeleton}, and
|
||||||
* A {@link AndroidSkeletonDrawable} bundles loading updating updating an {@link AndroidTextureAtlas}, {@link Skeleton}, and {@link AnimationState}
|
* {@link AnimationState} into a single easy-to-use class.
|
||||||
* into a single easy-to-use class.
|
|
||||||
*
|
*
|
||||||
* Use the {@link AndroidSkeletonDrawable#fromAsset(String, String, Context)}, {@link AndroidSkeletonDrawable#fromFile(File, File)},
|
* Use the {@link AndroidSkeletonDrawable#fromAsset(String, String, Context)},
|
||||||
* or {@link AndroidSkeletonDrawable#fromHttp(URL, URL, File)} methods to construct a {@link AndroidSkeletonDrawable}. To have
|
* {@link AndroidSkeletonDrawable#fromFile(File, File)}, or {@link AndroidSkeletonDrawable#fromHttp(URL, URL, File)} methods to
|
||||||
* multiple skeleton drawable instances share the same {@link AndroidTextureAtlas} and {@link SkeletonData}, use the constructor.
|
* construct a {@link AndroidSkeletonDrawable}. To have multiple skeleton drawable instances share the same
|
||||||
|
* {@link AndroidTextureAtlas} and {@link SkeletonData}, use the constructor.
|
||||||
*
|
*
|
||||||
* You can then directly access the {@link AndroidSkeletonDrawable#getAtlas()}, {@link AndroidSkeletonDrawable#getSkeletonData()},
|
* You can then directly access the {@link AndroidSkeletonDrawable#getAtlas()}, {@link AndroidSkeletonDrawable#getSkeletonData()},
|
||||||
* {@link AndroidSkeletonDrawable#getSkeleton()}, {@link AndroidSkeletonDrawable#getAnimationStateData()}, and {@link AndroidSkeletonDrawable#getAnimationState()}
|
* {@link AndroidSkeletonDrawable#getSkeleton()}, {@link AndroidSkeletonDrawable#getAnimationStateData()}, and
|
||||||
* to query and animate the skeleton. Use the {@link AnimationState} to queue animations on one or more tracks
|
* {@link AndroidSkeletonDrawable#getAnimationState()} to query and animate the skeleton. Use the {@link AnimationState} to queue
|
||||||
* via {@link AnimationState#setAnimation(int, Animation, boolean)} or {@link AnimationState#addAnimation(int, Animation, boolean, float)}.
|
* animations on one or more tracks via {@link AnimationState#setAnimation(int, Animation, boolean)} or
|
||||||
|
* {@link AnimationState#addAnimation(int, Animation, boolean, float)}.
|
||||||
*
|
*
|
||||||
* To update the {@link AnimationState} and apply it to the {@link Skeleton}, call the {@link AndroidSkeletonDrawable#update(float)} function, providing it
|
* To update the {@link AnimationState} and apply it to the {@link Skeleton}, call the
|
||||||
* a delta time in seconds to advance the animations.
|
* {@link AndroidSkeletonDrawable#update(float)} function, providing it a delta time in seconds to advance the animations.
|
||||||
*
|
*
|
||||||
* To render the current pose of the {@link Skeleton}, use {@link SkeletonRenderer#render(Skeleton)}, {@link SkeletonRenderer#renderToCanvas(Canvas, Array)},
|
* To render the current pose of the {@link Skeleton}, use {@link SkeletonRenderer#render(Skeleton)},
|
||||||
* {@link SkeletonRenderer#renderToBitmap(float, float, int, Skeleton)}, depending on your needs.
|
* {@link SkeletonRenderer#renderToCanvas(Canvas, Array)}, {@link SkeletonRenderer#renderToBitmap(float, float, int, Skeleton)},
|
||||||
*/
|
* depending on your needs. */
|
||||||
public class AndroidSkeletonDrawable {
|
public class AndroidSkeletonDrawable {
|
||||||
|
|
||||||
private final AndroidTextureAtlas atlas;
|
private final AndroidTextureAtlas atlas;
|
||||||
@ -79,10 +80,9 @@ public class AndroidSkeletonDrawable {
|
|||||||
|
|
||||||
private final AnimationState animationState;
|
private final AnimationState animationState;
|
||||||
|
|
||||||
/**
|
/** Constructs a new skeleton drawable from the given (possibly shared) {@link AndroidTextureAtlas} and
|
||||||
* Constructs a new skeleton drawable from the given (possibly shared) {@link AndroidTextureAtlas} and {@link SkeletonData}.
|
* {@link SkeletonData}. */
|
||||||
*/
|
public AndroidSkeletonDrawable (AndroidTextureAtlas atlas, SkeletonData skeletonData) {
|
||||||
public AndroidSkeletonDrawable(AndroidTextureAtlas atlas, SkeletonData skeletonData) {
|
|
||||||
this.atlas = atlas;
|
this.atlas = atlas;
|
||||||
this.skeletonData = skeletonData;
|
this.skeletonData = skeletonData;
|
||||||
|
|
||||||
@ -93,12 +93,9 @@ public class AndroidSkeletonDrawable {
|
|||||||
skeleton.updateWorldTransform(Skeleton.Physics.none);
|
skeleton.updateWorldTransform(Skeleton.Physics.none);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Updates the {@link AnimationState} using the {@code delta} time given in seconds, applies the animation state to the
|
||||||
* Updates the {@link AnimationState} using the {@code delta} time given in seconds, applies the
|
* {@link Skeleton} and updates the world transforms of the skeleton to calculate its current pose. */
|
||||||
* animation state to the {@link Skeleton} and updates the world transforms of the skeleton
|
public void update (float delta) {
|
||||||
* to calculate its current pose.
|
|
||||||
*/
|
|
||||||
public void update(float delta) {
|
|
||||||
animationState.update(delta);
|
animationState.update(delta);
|
||||||
animationState.apply(skeleton);
|
animationState.apply(skeleton);
|
||||||
|
|
||||||
@ -106,68 +103,53 @@ public class AndroidSkeletonDrawable {
|
|||||||
skeleton.updateWorldTransform(Skeleton.Physics.update);
|
skeleton.updateWorldTransform(Skeleton.Physics.update);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Get the {@link AndroidTextureAtlas} */
|
||||||
* Get the {@link AndroidTextureAtlas}
|
public AndroidTextureAtlas getAtlas () {
|
||||||
*/
|
|
||||||
public AndroidTextureAtlas getAtlas() {
|
|
||||||
return atlas;
|
return atlas;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Get the {@link Skeleton} */
|
||||||
* Get the {@link Skeleton}
|
public Skeleton getSkeleton () {
|
||||||
*/
|
|
||||||
public Skeleton getSkeleton() {
|
|
||||||
return skeleton;
|
return skeleton;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Get the {@link SkeletonData} */
|
||||||
* Get the {@link SkeletonData}
|
public SkeletonData getSkeletonData () {
|
||||||
*/
|
|
||||||
public SkeletonData getSkeletonData() {
|
|
||||||
return skeletonData;
|
return skeletonData;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Get the {@link AnimationStateData} */
|
||||||
* Get the {@link AnimationStateData}
|
public AnimationStateData getAnimationStateData () {
|
||||||
*/
|
|
||||||
public AnimationStateData getAnimationStateData() {
|
|
||||||
return animationStateData;
|
return animationStateData;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Get the {@link AnimationState} */
|
||||||
* Get the {@link AnimationState}
|
public AnimationState getAnimationState () {
|
||||||
*/
|
|
||||||
public AnimationState getAnimationState() {
|
|
||||||
return animationState;
|
return animationState;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Constructs a new skeleton drawable from the {@code atlasFileName} and {@code skeletonFileName} from the the apps resources
|
||||||
* Constructs a new skeleton drawable from the {@code atlasFileName} and {@code skeletonFileName} from the the apps resources using {@link Context}.
|
* using {@link Context}.
|
||||||
*
|
*
|
||||||
* Throws an exception in case the data could not be loaded.
|
* Throws an exception in case the data could not be loaded. */
|
||||||
*/
|
|
||||||
public static AndroidSkeletonDrawable fromAsset (String atlasFileName, String skeletonFileName, Context context) {
|
public static AndroidSkeletonDrawable fromAsset (String atlasFileName, String skeletonFileName, Context context) {
|
||||||
AndroidTextureAtlas atlas = AndroidTextureAtlas.fromAsset(atlasFileName, context);
|
AndroidTextureAtlas atlas = AndroidTextureAtlas.fromAsset(atlasFileName, context);
|
||||||
SkeletonData skeletonData = SkeletonDataUtils.fromAsset(atlas, skeletonFileName, context);
|
SkeletonData skeletonData = SkeletonDataUtils.fromAsset(atlas, skeletonFileName, context);
|
||||||
return new AndroidSkeletonDrawable(atlas, skeletonData);
|
return new AndroidSkeletonDrawable(atlas, skeletonData);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Constructs a new skeleton drawable from the {@code atlasFile} and {@code skeletonFile}.
|
||||||
* Constructs a new skeleton drawable from the {@code atlasFile} and {@code skeletonFile}.
|
|
||||||
*
|
*
|
||||||
* Throws an exception in case the data could not be loaded.
|
* Throws an exception in case the data could not be loaded. */
|
||||||
*/
|
|
||||||
public static AndroidSkeletonDrawable fromFile (File atlasFile, File skeletonFile) {
|
public static AndroidSkeletonDrawable fromFile (File atlasFile, File skeletonFile) {
|
||||||
AndroidTextureAtlas atlas = AndroidTextureAtlas.fromFile(atlasFile);
|
AndroidTextureAtlas atlas = AndroidTextureAtlas.fromFile(atlasFile);
|
||||||
SkeletonData skeletonData = SkeletonDataUtils.fromFile(atlas, skeletonFile);
|
SkeletonData skeletonData = SkeletonDataUtils.fromFile(atlas, skeletonFile);
|
||||||
return new AndroidSkeletonDrawable(atlas, skeletonData);
|
return new AndroidSkeletonDrawable(atlas, skeletonData);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Constructs a new skeleton drawable from the {@code atlasUrl} and {@code skeletonUrl}.
|
||||||
* Constructs a new skeleton drawable from the {@code atlasUrl} and {@code skeletonUrl}.
|
|
||||||
*
|
*
|
||||||
* Throws an exception in case the data could not be loaded.
|
* Throws an exception in case the data could not be loaded. */
|
||||||
*/
|
|
||||||
public static AndroidSkeletonDrawable fromHttp (URL atlasUrl, URL skeletonUrl, File targetDirectory) {
|
public static AndroidSkeletonDrawable fromHttp (URL atlasUrl, URL skeletonUrl, File targetDirectory) {
|
||||||
AndroidTextureAtlas atlas = AndroidTextureAtlas.fromHttp(atlasUrl, targetDirectory);
|
AndroidTextureAtlas atlas = AndroidTextureAtlas.fromHttp(atlasUrl, targetDirectory);
|
||||||
SkeletonData skeletonData = SkeletonDataUtils.fromHttp(atlas, skeletonUrl, targetDirectory);
|
SkeletonData skeletonData = SkeletonDataUtils.fromHttp(atlas, skeletonUrl, targetDirectory);
|
||||||
|
|||||||
@ -40,10 +40,7 @@ import android.graphics.PorterDuff;
|
|||||||
import android.graphics.PorterDuffXfermode;
|
import android.graphics.PorterDuffXfermode;
|
||||||
import android.graphics.Shader;
|
import android.graphics.Shader;
|
||||||
|
|
||||||
/**
|
/** A class holding an {@link Bitmap} of an {@link AndroidTextureAtlas} page image with it's associated blend modes and paints. */
|
||||||
* A class holding an {@link Bitmap} of an {@link AndroidTextureAtlas} page image with it's associated
|
|
||||||
* blend modes and paints.
|
|
||||||
*/
|
|
||||||
public class AndroidTexture extends Texture {
|
public class AndroidTexture extends Texture {
|
||||||
private Bitmap bitmap;
|
private Bitmap bitmap;
|
||||||
private ObjectMap<BlendMode, Paint> paints = new ObjectMap<>();
|
private ObjectMap<BlendMode, Paint> paints = new ObjectMap<>();
|
||||||
|
|||||||
@ -53,14 +53,11 @@ import android.graphics.Paint;
|
|||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
|
||||||
/**
|
/** Atlas data loaded from a `.atlas` file and its corresponding `.png` files. For each atlas image, a corresponding
|
||||||
* Atlas data loaded from a `.atlas` file and its corresponding `.png` files. For each atlas image,
|
* {@link Bitmap} and {@link Paint} is constructed, which are used when rendering a skeleton that uses this atlas.
|
||||||
* a corresponding {@link Bitmap} and {@link Paint} is constructed, which are used when rendering a skeleton
|
|
||||||
* that uses this atlas.
|
|
||||||
*
|
*
|
||||||
* Use the static methods {@link AndroidTextureAtlas#fromAsset(String, Context)}, {@link AndroidTextureAtlas#fromFile(File)},
|
* Use the static methods {@link AndroidTextureAtlas#fromAsset(String, Context)}, {@link AndroidTextureAtlas#fromFile(File)}, and
|
||||||
* and {@link AndroidTextureAtlas#fromHttp(URL, File)} to load an atlas.
|
* {@link AndroidTextureAtlas#fromHttp(URL, File)} to load an atlas. */
|
||||||
*/
|
|
||||||
public class AndroidTextureAtlas {
|
public class AndroidTextureAtlas {
|
||||||
private interface BitmapLoader {
|
private interface BitmapLoader {
|
||||||
Bitmap load (String path);
|
Bitmap load (String path);
|
||||||
@ -94,10 +91,8 @@ public class AndroidTextureAtlas {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Returns the first region found with the specified name. This method uses string comparison to find the region, so the
|
||||||
* Returns the first region found with the specified name. This method uses string comparison to find the region, so the
|
* result should be cached rather than calling this method multiple times. */
|
||||||
* result should be cached rather than calling this method multiple times.
|
|
||||||
*/
|
|
||||||
public @Null AtlasRegion findRegion (String name) {
|
public @Null AtlasRegion findRegion (String name) {
|
||||||
for (int i = 0, n = regions.size; i < n; i++)
|
for (int i = 0, n = regions.size; i < n; i++)
|
||||||
if (regions.get(i).name.equals(name)) return regions.get(i);
|
if (regions.get(i).name.equals(name)) return regions.get(i);
|
||||||
@ -112,12 +107,10 @@ public class AndroidTextureAtlas {
|
|||||||
return regions;
|
return regions;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Loads an {@link AndroidTextureAtlas} from the file {@code atlasFileName} from assets using {@link Context}.
|
||||||
* Loads an {@link AndroidTextureAtlas} from the file {@code atlasFileName} from assets using {@link Context}.
|
|
||||||
*
|
*
|
||||||
* Throws a {@link RuntimeException} in case the atlas could not be loaded.
|
* Throws a {@link RuntimeException} in case the atlas could not be loaded. */
|
||||||
*/
|
public static AndroidTextureAtlas fromAsset (String atlasFileName, Context context) {
|
||||||
public static AndroidTextureAtlas fromAsset(String atlasFileName, Context context) {
|
|
||||||
TextureAtlasData data = new TextureAtlasData();
|
TextureAtlasData data = new TextureAtlasData();
|
||||||
AssetManager assetManager = context.getAssets();
|
AssetManager assetManager = context.getAssets();
|
||||||
|
|
||||||
@ -147,12 +140,10 @@ public class AndroidTextureAtlas {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Loads an {@link AndroidTextureAtlas} from the file {@code atlasFileName}.
|
||||||
* Loads an {@link AndroidTextureAtlas} from the file {@code atlasFileName}.
|
|
||||||
*
|
*
|
||||||
* Throws a {@link RuntimeException} in case the atlas could not be loaded.
|
* Throws a {@link RuntimeException} in case the atlas could not be loaded. */
|
||||||
*/
|
public static AndroidTextureAtlas fromFile (File atlasFile) {
|
||||||
public static AndroidTextureAtlas fromFile(File atlasFile) {
|
|
||||||
TextureAtlasData data;
|
TextureAtlasData data;
|
||||||
try {
|
try {
|
||||||
data = loadTextureAtlasData(atlasFile);
|
data = loadTextureAtlasData(atlasFile);
|
||||||
@ -169,12 +160,10 @@ public class AndroidTextureAtlas {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Loads an {@link AndroidTextureAtlas} from the URL {@code atlasURL}.
|
||||||
* Loads an {@link AndroidTextureAtlas} from the URL {@code atlasURL}.
|
|
||||||
*
|
*
|
||||||
* Throws a {@link Exception} in case the atlas could not be loaded.
|
* Throws a {@link Exception} in case the atlas could not be loaded. */
|
||||||
*/
|
public static AndroidTextureAtlas fromHttp (URL atlasUrl, File targetDirectory) {
|
||||||
public static AndroidTextureAtlas fromHttp(URL atlasUrl, File targetDirectory) {
|
|
||||||
File atlasFile = HttpUtils.downloadFrom(atlasUrl, targetDirectory);
|
File atlasFile = HttpUtils.downloadFrom(atlasUrl, targetDirectory);
|
||||||
TextureAtlasData data;
|
TextureAtlasData data;
|
||||||
try {
|
try {
|
||||||
@ -205,20 +194,20 @@ public class AndroidTextureAtlas {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static InputStream inputStream(File file) throws Exception {
|
private static InputStream inputStream (File file) throws Exception {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
return Files.newInputStream(file.toPath());
|
return Files.newInputStream(file.toPath());
|
||||||
} else {
|
} else {
|
||||||
//noinspection IOStreamConstructor
|
// noinspection IOStreamConstructor
|
||||||
return new FileInputStream(file);
|
return new FileInputStream(file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TextureAtlasData loadTextureAtlasData(File atlasFile) {
|
private static TextureAtlasData loadTextureAtlasData (File atlasFile) {
|
||||||
TextureAtlasData data = new TextureAtlasData();
|
TextureAtlasData data = new TextureAtlasData();
|
||||||
FileHandle inputFile = new FileHandle() {
|
FileHandle inputFile = new FileHandle() {
|
||||||
@Override
|
@Override
|
||||||
public InputStream read() {
|
public InputStream read () {
|
||||||
try {
|
try {
|
||||||
return new FileInputStream(atlasFile);
|
return new FileInputStream(atlasFile);
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
|
|||||||
@ -36,13 +36,11 @@ import android.graphics.RectF;
|
|||||||
import com.badlogic.gdx.utils.Array;
|
import com.badlogic.gdx.utils.Array;
|
||||||
import com.esotericsoftware.spine.Bone;
|
import com.esotericsoftware.spine.Bone;
|
||||||
|
|
||||||
/**
|
/** Renders debug information for a {@link AndroidSkeletonDrawable}, like bone locations, to a {@link Canvas}. See
|
||||||
* Renders debug information for a {@link AndroidSkeletonDrawable}, like bone locations, to a {@link Canvas}.
|
* {@link DebugRenderer#render}. */
|
||||||
* See {@link DebugRenderer#render}.
|
|
||||||
*/
|
|
||||||
public class DebugRenderer {
|
public class DebugRenderer {
|
||||||
|
|
||||||
public void render(AndroidSkeletonDrawable drawable, Canvas canvas, Array<SkeletonRenderer.RenderCommand> commands) {
|
public void render (AndroidSkeletonDrawable drawable, Canvas canvas, Array<SkeletonRenderer.RenderCommand> commands) {
|
||||||
Paint bonePaint = new Paint();
|
Paint bonePaint = new Paint();
|
||||||
bonePaint.setColor(android.graphics.Color.BLUE);
|
bonePaint.setColor(android.graphics.Color.BLUE);
|
||||||
bonePaint.setStyle(Paint.Style.FILL);
|
bonePaint.setStyle(Paint.Style.FILL);
|
||||||
|
|||||||
@ -50,17 +50,13 @@ import android.graphics.Canvas;
|
|||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.RectF;
|
import android.graphics.RectF;
|
||||||
|
|
||||||
/**
|
/** Is responsible to transform the {@link Skeleton} with its current pose to {@link SkeletonRenderer.RenderCommand} commands and
|
||||||
* Is responsible to transform the {@link Skeleton} with its current pose to {@link SkeletonRenderer.RenderCommand} commands
|
* render them to a {@link Canvas}. */
|
||||||
* and render them to a {@link Canvas}.
|
|
||||||
*/
|
|
||||||
public class SkeletonRenderer {
|
public class SkeletonRenderer {
|
||||||
|
|
||||||
/**
|
/** Stores the vertices, indices, and atlas page index to be used for rendering one or more attachments of a {@link Skeleton}
|
||||||
* Stores the vertices, indices, and atlas page index to be used for rendering one or more attachments
|
* to a {@link Canvas}. See the implementation of {@link SkeletonRenderer#render(Skeleton)} and
|
||||||
* of a {@link Skeleton} to a {@link Canvas}. See the implementation of {@link SkeletonRenderer#render(Skeleton)} and
|
* {@link SkeletonRenderer#renderToCanvas(Canvas, Array)} on how to use this data to render it to a {@link Canvas}. */
|
||||||
* {@link SkeletonRenderer#renderToCanvas(Canvas, Array)} on how to use this data to render it to a {@link Canvas}.
|
|
||||||
*/
|
|
||||||
public static class RenderCommand implements Pool.Poolable {
|
public static class RenderCommand implements Pool.Poolable {
|
||||||
FloatArray vertices = new FloatArray(32);
|
FloatArray vertices = new FloatArray(32);
|
||||||
FloatArray uvs = new FloatArray(32);
|
FloatArray uvs = new FloatArray(32);
|
||||||
@ -90,10 +86,8 @@ public class SkeletonRenderer {
|
|||||||
};
|
};
|
||||||
private final Array<RenderCommand> commandList = new Array<RenderCommand>();
|
private final Array<RenderCommand> commandList = new Array<RenderCommand>();
|
||||||
|
|
||||||
/**
|
/** Created the {@link RenderCommand} commands from the skeletons current pose. */
|
||||||
* Created the {@link RenderCommand} commands from the skeletons current pose.
|
public Array<RenderCommand> render (Skeleton skeleton) {
|
||||||
*/
|
|
||||||
public Array<RenderCommand> render(Skeleton skeleton) {
|
|
||||||
Color color = null, skeletonColor = skeleton.getColor();
|
Color color = null, skeletonColor = skeleton.getColor();
|
||||||
float r = skeletonColor.r, g = skeletonColor.g, b = skeletonColor.b, a = skeletonColor.a;
|
float r = skeletonColor.r, g = skeletonColor.g, b = skeletonColor.b, a = skeletonColor.a;
|
||||||
|
|
||||||
@ -228,11 +222,9 @@ public class SkeletonRenderer {
|
|||||||
return commandList;
|
return commandList;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Renders the {@link RenderCommand} commands created from the skeleton current pose to the given {@link Canvas}. Does not
|
||||||
* Renders the {@link RenderCommand} commands created from the skeleton current pose to the given {@link Canvas}.
|
* perform any scaling or fitting. */
|
||||||
* Does not perform any scaling or fitting.
|
public void renderToCanvas (Canvas canvas, Array<RenderCommand> commands) {
|
||||||
*/
|
|
||||||
public void renderToCanvas(Canvas canvas, Array<RenderCommand> commands) {
|
|
||||||
for (int i = 0; i < commands.size; i++) {
|
for (int i = 0; i < commands.size; i++) {
|
||||||
RenderCommand command = commands.get(i);
|
RenderCommand command = commands.get(i);
|
||||||
|
|
||||||
@ -241,15 +233,13 @@ public class SkeletonRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Renders the {@link Skeleton} with its current pose to a {@link Bitmap}.
|
||||||
* Renders the {@link Skeleton} with its current pose to a {@link Bitmap}.
|
|
||||||
*
|
*
|
||||||
* @param width The width of the bitmap in pixels.
|
* @param width The width of the bitmap in pixels.
|
||||||
* @param height The height of the bitmap in pixels.
|
* @param height The height of the bitmap in pixels.
|
||||||
* @param bgColor The background color.
|
* @param bgColor The background color.
|
||||||
* @param skeleton The skeleton to render.
|
* @param skeleton The skeleton to render. */
|
||||||
*/
|
public Bitmap renderToBitmap (float width, float height, int bgColor, Skeleton skeleton) {
|
||||||
public Bitmap renderToBitmap(float width, float height, int bgColor, Skeleton skeleton) {
|
|
||||||
Vector2 offset = new Vector2(0, 0);
|
Vector2 offset = new Vector2(0, 0);
|
||||||
Vector2 size = new Vector2(0, 0);
|
Vector2 size = new Vector2(0, 0);
|
||||||
FloatArray floatArray = new FloatArray();
|
FloatArray floatArray = new FloatArray();
|
||||||
@ -259,7 +249,7 @@ public class SkeletonRenderer {
|
|||||||
RectF bounds = new RectF(offset.x, offset.y, offset.x + size.x, offset.y + size.y);
|
RectF bounds = new RectF(offset.x, offset.y, offset.x + size.x, offset.y + size.y);
|
||||||
float scale = (1 / (bounds.width() > bounds.height() ? bounds.width() / width : bounds.height() / height));
|
float scale = (1 / (bounds.width() > bounds.height() ? bounds.width() / width : bounds.height() / height));
|
||||||
|
|
||||||
Bitmap bitmap = Bitmap.createBitmap((int) width, (int) height, Bitmap.Config.ARGB_8888);
|
Bitmap bitmap = Bitmap.createBitmap((int)width, (int)height, Bitmap.Config.ARGB_8888);
|
||||||
Canvas canvas = new Canvas(bitmap);
|
Canvas canvas = new Canvas(bitmap);
|
||||||
|
|
||||||
Paint paint = new Paint();
|
Paint paint = new Paint();
|
||||||
|
|||||||
@ -43,37 +43,34 @@ import com.esotericsoftware.spine.android.callbacks.SpineControllerAfterPaintCal
|
|||||||
import com.esotericsoftware.spine.android.callbacks.SpineControllerBeforePaintCallback;
|
import com.esotericsoftware.spine.android.callbacks.SpineControllerBeforePaintCallback;
|
||||||
import com.esotericsoftware.spine.android.callbacks.SpineControllerCallback;
|
import com.esotericsoftware.spine.android.callbacks.SpineControllerCallback;
|
||||||
|
|
||||||
/**
|
/** Controls how the skeleton of a {@link SpineView} is animated and rendered.
|
||||||
* Controls how the skeleton of a {@link SpineView} is animated and rendered.
|
|
||||||
*
|
*
|
||||||
* Upon initialization of a {@link SpineView}, the provided {@code onInitialized} callback method is called once. This method can be used
|
* Upon initialization of a {@link SpineView}, the provided {@code onInitialized} callback method is called once. This method can
|
||||||
* to set up the initial animation(s) of the skeleton, among other things.
|
* be used to set up the initial animation(s) of the skeleton, among other things.
|
||||||
*
|
*
|
||||||
* After initialization is complete, the {@link SpineView} is rendered at the screen refresh rate. In each frame,
|
* After initialization is complete, the {@link SpineView} is rendered at the screen refresh rate. In each frame, the
|
||||||
* the {@link AnimationState} is updated and applied to the {@link Skeleton}.
|
* {@link AnimationState} is updated and applied to the {@link Skeleton}.
|
||||||
*
|
*
|
||||||
* Next, the optionally provided method {@code onBeforeUpdateWorldTransforms} is called, which can modify the
|
* Next, the optionally provided method {@code onBeforeUpdateWorldTransforms} is called, which can modify the skeleton before its
|
||||||
* skeleton before its current pose is calculated using {@link Skeleton#updateWorldTransform(Skeleton.Physics)}. After
|
* current pose is calculated using {@link Skeleton#updateWorldTransform(Skeleton.Physics)}. After
|
||||||
* {@link Skeleton#updateWorldTransform(Skeleton.Physics)} has completed, the optional {@code onAfterUpdateWorldTransforms} method is
|
* {@link Skeleton#updateWorldTransform(Skeleton.Physics)} has completed, the optional {@code onAfterUpdateWorldTransforms} method
|
||||||
* called, which can modify the current pose before rendering the skeleton.
|
* is called, which can modify the current pose before rendering the skeleton.
|
||||||
*
|
*
|
||||||
* Before the skeleton's current pose is rendered by the {@link SpineView}, the optional {@code onBeforePaint} is called,
|
* Before the skeleton's current pose is rendered by the {@link SpineView}, the optional {@code onBeforePaint} is called, which
|
||||||
* which allows rendering backgrounds or other objects that should go behind the skeleton on the {@link Canvas}. The
|
* allows rendering backgrounds or other objects that should go behind the skeleton on the {@link Canvas}. The {@link SpineView}
|
||||||
* {@link SpineView} then renders the skeleton's current pose and finally calls the optional {@code onAfterPaint}, which
|
* then renders the skeleton's current pose and finally calls the optional {@code onAfterPaint}, which can render additional
|
||||||
* can render additional objects on top of the skeleton.
|
* objects on top of the skeleton.
|
||||||
*
|
*
|
||||||
* The underlying {@link AndroidTextureAtlas}, {@link SkeletonData}, {@link Skeleton}, {@link AnimationStateData}, {@link AnimationState}, and {@link AndroidSkeletonDrawable}
|
* The underlying {@link AndroidTextureAtlas}, {@link SkeletonData}, {@link Skeleton}, {@link AnimationStateData},
|
||||||
* can be accessed through their respective getters to inspect and/or modify the skeleton and its associated data. Accessing
|
* {@link AnimationState}, and {@link AndroidSkeletonDrawable} can be accessed through their respective getters to inspect and/or
|
||||||
* this data is only allowed if the {@link SpineView} and its data have been initialized and have not been disposed of yet.
|
* modify the skeleton and its associated data. Accessing this data is only allowed if the {@link SpineView} and its data have
|
||||||
|
* been initialized and have not been disposed of yet.
|
||||||
*
|
*
|
||||||
* By default, the widget updates and renders the skeleton every frame. The {@code pause} method can be used to pause updating
|
* By default, the widget updates and renders the skeleton every frame. The {@code pause} method can be used to pause updating and
|
||||||
* and rendering the skeleton. The {@link SpineController#resume()} method resumes updating and rendering the skeleton. The {@link SpineController#isPlaying()} getter
|
* rendering the skeleton. The {@link SpineController#resume()} method resumes updating and rendering the skeleton. The
|
||||||
* reports the current state.
|
* {@link SpineController#isPlaying()} getter reports the current state. */
|
||||||
*/
|
|
||||||
public class SpineController {
|
public class SpineController {
|
||||||
/**
|
/** Used to build {@link SpineController} instances. */
|
||||||
* Used to build {@link SpineController} instances.
|
|
||||||
* */
|
|
||||||
public static class Builder {
|
public static class Builder {
|
||||||
private final SpineControllerCallback onInitialized;
|
private final SpineControllerCallback onInitialized;
|
||||||
private SpineControllerCallback onBeforeUpdateWorldTransforms;
|
private SpineControllerCallback onBeforeUpdateWorldTransforms;
|
||||||
@ -81,57 +78,49 @@ public class SpineController {
|
|||||||
private SpineControllerBeforePaintCallback onBeforePaint;
|
private SpineControllerBeforePaintCallback onBeforePaint;
|
||||||
private SpineControllerAfterPaintCallback onAfterPaint;
|
private SpineControllerAfterPaintCallback onAfterPaint;
|
||||||
|
|
||||||
/**
|
/** Instantiate a {@link Builder} used to build a {@link SpineController}, which controls how the skeleton of a
|
||||||
* Instantiate a {@link Builder} used to build a {@link SpineController}, which controls how the skeleton of a {@link SpineView}
|
* {@link SpineView} is animated and rendered. Upon initialization of a {@link SpineView}, the provided
|
||||||
* is animated and rendered. Upon initialization of a {@link SpineView}, the provided {@code onInitialized} callback
|
* {@code onInitialized} callback method is called once. This method can be used to set up the initial animation(s) of the
|
||||||
* method is called once. This method can be used to set up the initial animation(s) of the skeleton, among other things.
|
* skeleton, among other things.
|
||||||
*
|
*
|
||||||
* @param onInitialized Upon initialization of a {@link SpineView}, the provided {@code onInitialized} callback
|
* @param onInitialized Upon initialization of a {@link SpineView}, the provided {@code onInitialized} callback method is
|
||||||
* method is called once. This method can be used to set up the initial animation(s) of the skeleton,
|
* called once. This method can be used to set up the initial animation(s) of the skeleton, among other things. */
|
||||||
* among other things.
|
public Builder (SpineControllerCallback onInitialized) {
|
||||||
*/
|
|
||||||
public Builder(SpineControllerCallback onInitialized) {
|
|
||||||
this.onInitialized = onInitialized;
|
this.onInitialized = onInitialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Sets the {@code onBeforeUpdateWorldTransforms} callback. It is called before the skeleton's current pose is calculated
|
||||||
* Sets the {@code onBeforeUpdateWorldTransforms} callback. It is called before the skeleton's current pose is calculated
|
* using {@link Skeleton#updateWorldTransform(Skeleton.Physics)}. It can be used to modify the skeleton before the pose
|
||||||
* using {@link Skeleton#updateWorldTransform(Skeleton.Physics)}. It can be used to modify the skeleton before the pose calculation.
|
* calculation. */
|
||||||
*/
|
public Builder setOnBeforeUpdateWorldTransforms (SpineControllerCallback onBeforeUpdateWorldTransforms) {
|
||||||
public Builder setOnBeforeUpdateWorldTransforms(SpineControllerCallback onBeforeUpdateWorldTransforms) {
|
|
||||||
this.onBeforeUpdateWorldTransforms = onBeforeUpdateWorldTransforms;
|
this.onBeforeUpdateWorldTransforms = onBeforeUpdateWorldTransforms;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Sets the {@code onAfterUpdateWorldTransforms} callback. This method is called after the skeleton's current pose is
|
||||||
* Sets the {@code onAfterUpdateWorldTransforms} callback. This method is called after the skeleton's current pose is calculated using
|
* calculated using {@link Skeleton#updateWorldTransform(Skeleton.Physics)}. It can be used to modify the current pose
|
||||||
* {@link Skeleton#updateWorldTransform(Skeleton.Physics)}. It can be used to modify the current pose before rendering the skeleton.
|
* before rendering the skeleton. */
|
||||||
*/
|
public Builder setOnAfterUpdateWorldTransforms (SpineControllerCallback onAfterUpdateWorldTransforms) {
|
||||||
public Builder setOnAfterUpdateWorldTransforms(SpineControllerCallback onAfterUpdateWorldTransforms) {
|
|
||||||
this.onAfterUpdateWorldTransforms = onAfterUpdateWorldTransforms;
|
this.onAfterUpdateWorldTransforms = onAfterUpdateWorldTransforms;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Sets the {@code onBeforePaint} callback. It is called before the skeleton's current pose is rendered by the
|
||||||
* Sets the {@code onBeforePaint} callback. It is called before the skeleton's current pose is rendered by the
|
|
||||||
* {@link SpineView}. It allows rendering backgrounds or other objects that should go behind the skeleton on the
|
* {@link SpineView}. It allows rendering backgrounds or other objects that should go behind the skeleton on the
|
||||||
* {@link Canvas}.
|
* {@link Canvas}. */
|
||||||
*/
|
public Builder setOnBeforePaint (SpineControllerBeforePaintCallback onBeforePaint) {
|
||||||
public Builder setOnBeforePaint(SpineControllerBeforePaintCallback onBeforePaint) {
|
|
||||||
this.onBeforePaint = onBeforePaint;
|
this.onBeforePaint = onBeforePaint;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Sets the {@code onAfterPaint} callback. It is called after the skeleton's current pose is rendered by the
|
||||||
* Sets the {@code onAfterPaint} callback. It is called after the skeleton's current pose is rendered by the
|
* {@link SpineView}. It allows rendering additional objects on top of the skeleton. */
|
||||||
* {@link SpineView}. It allows rendering additional objects on top of the skeleton.
|
public Builder setOnAfterPaint (SpineControllerAfterPaintCallback onAfterPaint) {
|
||||||
*/
|
|
||||||
public Builder setOnAfterPaint(SpineControllerAfterPaintCallback onAfterPaint) {
|
|
||||||
this.onAfterPaint = onAfterPaint;
|
this.onAfterPaint = onAfterPaint;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SpineController build() {
|
public SpineController build () {
|
||||||
SpineController spineController = new SpineController(onInitialized);
|
SpineController spineController = new SpineController(onInitialized);
|
||||||
spineController.onBeforeUpdateWorldTransforms = onBeforeUpdateWorldTransforms;
|
spineController.onBeforeUpdateWorldTransforms = onBeforeUpdateWorldTransforms;
|
||||||
spineController.onAfterUpdateWorldTransforms = onAfterUpdateWorldTransforms;
|
spineController.onAfterUpdateWorldTransforms = onAfterUpdateWorldTransforms;
|
||||||
@ -153,177 +142,144 @@ public class SpineController {
|
|||||||
private double scaleX = 1;
|
private double scaleX = 1;
|
||||||
private double scaleY = 1;
|
private double scaleY = 1;
|
||||||
|
|
||||||
/**
|
/** Instantiate a {@link SpineController}, which controls how the skeleton of a {@link SpineView} is animated and rendered.
|
||||||
* Instantiate a {@link SpineController}, which controls how the skeleton of a {@link SpineView} is animated and rendered.
|
* Upon initialization of a {@link SpineView}, the provided {@code onInitialized} callback method is called once. This method
|
||||||
* Upon initialization of a {@link SpineView}, the provided {@code onInitialized} callback method is called once.
|
* can be used to set up the initial animation(s) of the skeleton, among other things.
|
||||||
* This method can be used to set up the initial animation(s) of the skeleton, among other things.
|
|
||||||
*
|
*
|
||||||
* @param onInitialized Upon initialization of a {@link SpineView}, the provided {@code onInitialized} callback
|
* @param onInitialized Upon initialization of a {@link SpineView}, the provided {@code onInitialized} callback method is
|
||||||
* method is called once. This method can be used to set up the initial animation(s) of the skeleton,
|
* called once. This method can be used to set up the initial animation(s) of the skeleton, among other things. */
|
||||||
* among other things.
|
public SpineController (SpineControllerCallback onInitialized) {
|
||||||
*/
|
|
||||||
public SpineController(SpineControllerCallback onInitialized) {
|
|
||||||
this.onInitialized = onInitialized;
|
this.onInitialized = onInitialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void init(AndroidSkeletonDrawable drawable) {
|
protected void init (AndroidSkeletonDrawable drawable) {
|
||||||
this.drawable = drawable;
|
this.drawable = drawable;
|
||||||
if (onInitialized != null) {
|
if (onInitialized != null) {
|
||||||
onInitialized.execute(this);
|
onInitialized.execute(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** The {@link AndroidTextureAtlas} from which images to render the skeleton are sourced. */
|
||||||
* The {@link AndroidTextureAtlas} from which images to render the skeleton are sourced.
|
public AndroidTextureAtlas getAtlas () {
|
||||||
*/
|
|
||||||
public AndroidTextureAtlas getAtlas() {
|
|
||||||
if (drawable == null) throw new RuntimeException("Controller is not initialized yet.");
|
if (drawable == null) throw new RuntimeException("Controller is not initialized yet.");
|
||||||
return drawable.getAtlas();
|
return drawable.getAtlas();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** The setup-pose data used by the skeleton. */
|
||||||
* The setup-pose data used by the skeleton.
|
public SkeletonData getSkeletonDate () {
|
||||||
*/
|
|
||||||
public SkeletonData getSkeletonDate() {
|
|
||||||
if (drawable == null) throw new RuntimeException("Controller is not initialized yet.");
|
if (drawable == null) throw new RuntimeException("Controller is not initialized yet.");
|
||||||
return drawable.getSkeletonData();
|
return drawable.getSkeletonData();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** The {@link Skeleton}. */
|
||||||
* The {@link Skeleton}.
|
public Skeleton getSkeleton () {
|
||||||
*/
|
|
||||||
public Skeleton getSkeleton() {
|
|
||||||
if (drawable == null) throw new RuntimeException("Controller is not initialized yet.");
|
if (drawable == null) throw new RuntimeException("Controller is not initialized yet.");
|
||||||
return drawable.getSkeleton();
|
return drawable.getSkeleton();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** The mixing information used by the {@link AnimationState}. */
|
||||||
* The mixing information used by the {@link AnimationState}.
|
public AnimationStateData getAnimationStateData () {
|
||||||
*/
|
|
||||||
public AnimationStateData getAnimationStateData() {
|
|
||||||
if (drawable == null) throw new RuntimeException("Controller is not initialized yet.");
|
if (drawable == null) throw new RuntimeException("Controller is not initialized yet.");
|
||||||
return drawable.getAnimationStateData();
|
return drawable.getAnimationStateData();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** The {@link AnimationState} used to manage animations that are being applied to the skeleton. */
|
||||||
* The {@link AnimationState} used to manage animations that are being applied to the
|
public AnimationState getAnimationState () {
|
||||||
* skeleton.
|
|
||||||
*/
|
|
||||||
public AnimationState getAnimationState() {
|
|
||||||
if (drawable == null) throw new RuntimeException("Controller is not initialized yet.");
|
if (drawable == null) throw new RuntimeException("Controller is not initialized yet.");
|
||||||
return drawable.getAnimationState();
|
return drawable.getAnimationState();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** The {@link AndroidSkeletonDrawable}. */
|
||||||
* The {@link AndroidSkeletonDrawable}.
|
public AndroidSkeletonDrawable getDrawable () {
|
||||||
*/
|
|
||||||
public AndroidSkeletonDrawable getDrawable() {
|
|
||||||
if (drawable == null) throw new RuntimeException("Controller is not initialized yet.");
|
if (drawable == null) throw new RuntimeException("Controller is not initialized yet.");
|
||||||
return drawable;
|
return drawable;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Checks if the {@link SpineView} is initialized. */
|
||||||
* Checks if the {@link SpineView} is initialized.
|
public boolean isInitialized () {
|
||||||
*/
|
|
||||||
public boolean isInitialized() {
|
|
||||||
return drawable != null;
|
return drawable != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Checks if the animation is currently playing. */
|
||||||
* Checks if the animation is currently playing.
|
public boolean isPlaying () {
|
||||||
*/
|
|
||||||
public boolean isPlaying() {
|
|
||||||
return playing;
|
return playing;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Pauses updating and rendering the skeleton. */
|
||||||
* Pauses updating and rendering the skeleton.
|
public void pause () {
|
||||||
*/
|
|
||||||
public void pause() {
|
|
||||||
if (playing) {
|
if (playing) {
|
||||||
playing = false;
|
playing = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Resumes updating and rendering the skeleton. */
|
||||||
* Resumes updating and rendering the skeleton.
|
public void resume () {
|
||||||
*/
|
|
||||||
public void resume() {
|
|
||||||
if (!playing) {
|
if (!playing) {
|
||||||
playing = true;
|
playing = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Transforms the coordinates given in the {@link SpineView} coordinate system in {@code position} to the skeleton coordinate
|
||||||
* Transforms the coordinates given in the {@link SpineView} coordinate system in {@code position} to
|
* system. See the {@code IKFollowing.kt} example for how to use this to move a bone based on user touch input. */
|
||||||
* the skeleton coordinate system. See the {@code IKFollowing.kt} example for how to use this
|
public Point toSkeletonCoordinates (Point position) {
|
||||||
* to move a bone based on user touch input.
|
|
||||||
*/
|
|
||||||
public Point toSkeletonCoordinates(Point position) {
|
|
||||||
int x = position.x;
|
int x = position.x;
|
||||||
int y = position.y;
|
int y = position.y;
|
||||||
return new Point((int) (x / scaleX - offsetX), (int) (y / scaleY - offsetY));
|
return new Point((int)(x / scaleX - offsetX), (int)(y / scaleY - offsetY));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Sets the {@code onBeforeUpdateWorldTransforms} callback. It is called before the skeleton's current pose is calculated
|
||||||
* Sets the {@code onBeforeUpdateWorldTransforms} callback. It is called before the skeleton's current pose is calculated
|
* using {@link Skeleton#updateWorldTransform(Skeleton.Physics)}. It can be used to modify the skeleton before the pose
|
||||||
* using {@link Skeleton#updateWorldTransform(Skeleton.Physics)}. It can be used to modify the skeleton before the pose calculation.
|
* calculation. */
|
||||||
*/
|
public void setOnBeforeUpdateWorldTransforms (@Nullable SpineControllerCallback onBeforeUpdateWorldTransforms) {
|
||||||
public void setOnBeforeUpdateWorldTransforms(@Nullable SpineControllerCallback onBeforeUpdateWorldTransforms) {
|
|
||||||
this.onBeforeUpdateWorldTransforms = onBeforeUpdateWorldTransforms;
|
this.onBeforeUpdateWorldTransforms = onBeforeUpdateWorldTransforms;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Sets the {@code onAfterUpdateWorldTransforms} callback. This method is called after the skeleton's current pose is
|
||||||
* Sets the {@code onAfterUpdateWorldTransforms} callback. This method is called after the skeleton's current pose is calculated using
|
* calculated using {@link Skeleton#updateWorldTransform(Skeleton.Physics)}. It can be used to modify the current pose before
|
||||||
* {@link Skeleton#updateWorldTransform(Skeleton.Physics)}. It can be used to modify the current pose before rendering the skeleton.
|
* rendering the skeleton. */
|
||||||
*/
|
public void setOnAfterUpdateWorldTransforms (@Nullable SpineControllerCallback onAfterUpdateWorldTransforms) {
|
||||||
public void setOnAfterUpdateWorldTransforms(@Nullable SpineControllerCallback onAfterUpdateWorldTransforms) {
|
|
||||||
this.onAfterUpdateWorldTransforms = onAfterUpdateWorldTransforms;
|
this.onAfterUpdateWorldTransforms = onAfterUpdateWorldTransforms;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Sets the {@code onBeforePaint} callback. It is called before the skeleton's current pose is rendered by the
|
||||||
* Sets the {@code onBeforePaint} callback. It is called before the skeleton's current pose is rendered by the
|
|
||||||
* {@link SpineView}. It allows rendering backgrounds or other objects that should go behind the skeleton on the
|
* {@link SpineView}. It allows rendering backgrounds or other objects that should go behind the skeleton on the
|
||||||
* {@link Canvas}.
|
* {@link Canvas}. */
|
||||||
*/
|
public void setOnBeforePaint (@Nullable SpineControllerBeforePaintCallback onBeforePaint) {
|
||||||
public void setOnBeforePaint(@Nullable SpineControllerBeforePaintCallback onBeforePaint) {
|
|
||||||
this.onBeforePaint = onBeforePaint;
|
this.onBeforePaint = onBeforePaint;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Sets the {@code onAfterPaint} callback. It is called after the skeleton's current pose is rendered by the
|
||||||
* Sets the {@code onAfterPaint} callback. It is called after the skeleton's current pose is rendered by the
|
* {@link SpineView}. It allows rendering additional objects on top of the skeleton. */
|
||||||
* {@link SpineView}. It allows rendering additional objects on top of the skeleton.
|
public void setOnAfterPaint (@Nullable SpineControllerAfterPaintCallback onAfterPaint) {
|
||||||
*/
|
|
||||||
public void setOnAfterPaint(@Nullable SpineControllerAfterPaintCallback onAfterPaint) {
|
|
||||||
this.onAfterPaint = onAfterPaint;
|
this.onAfterPaint = onAfterPaint;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setCoordinateTransform(double offsetX, double offsetY, double scaleX, double scaleY) {
|
protected void setCoordinateTransform (double offsetX, double offsetY, double scaleX, double scaleY) {
|
||||||
this.offsetX = offsetX;
|
this.offsetX = offsetX;
|
||||||
this.offsetY = offsetY;
|
this.offsetY = offsetY;
|
||||||
this.scaleX = scaleX;
|
this.scaleX = scaleX;
|
||||||
this.scaleY = scaleY;
|
this.scaleY = scaleY;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void callOnBeforeUpdateWorldTransforms() {
|
protected void callOnBeforeUpdateWorldTransforms () {
|
||||||
if (onBeforeUpdateWorldTransforms != null) {
|
if (onBeforeUpdateWorldTransforms != null) {
|
||||||
onBeforeUpdateWorldTransforms.execute(this);
|
onBeforeUpdateWorldTransforms.execute(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void callOnAfterUpdateWorldTransforms() {
|
protected void callOnAfterUpdateWorldTransforms () {
|
||||||
if (onAfterUpdateWorldTransforms != null) {
|
if (onAfterUpdateWorldTransforms != null) {
|
||||||
onAfterUpdateWorldTransforms.execute(this);
|
onAfterUpdateWorldTransforms.execute(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void callOnBeforePaint(Canvas canvas) {
|
protected void callOnBeforePaint (Canvas canvas) {
|
||||||
if (onBeforePaint != null) {
|
if (onBeforePaint != null) {
|
||||||
onBeforePaint.execute(this, canvas);
|
onBeforePaint.execute(this, canvas);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void callOnAfterPaint(Canvas canvas, Array<SkeletonRenderer.RenderCommand> renderCommands) {
|
protected void callOnAfterPaint (Canvas canvas, Array<SkeletonRenderer.RenderCommand> renderCommands) {
|
||||||
if (onAfterPaint != null) {
|
if (onAfterPaint != null) {
|
||||||
onAfterPaint.execute(this, canvas, renderCommands);
|
onAfterPaint.execute(this, canvas, renderCommands);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -51,20 +51,20 @@ import androidx.annotation.NonNull;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
/**
|
/** A {@link View} to display a Spine skeleton. The skeleton can be loaded from an asset bundle
|
||||||
* A {@link View} to display a Spine skeleton. The skeleton can be loaded from an asset bundle ({@link SpineView#loadFromAssets(String, String, Context, SpineController)}),
|
* ({@link SpineView#loadFromAssets(String, String, Context, SpineController)}), local files
|
||||||
* local files ({@link SpineView#loadFromFile(File, File, Context, SpineController)}), URLs ({@link SpineView#loadFromHttp(URL, URL, File, Context, SpineController)}), or a pre-loaded {@link AndroidSkeletonDrawable} using ({@link SpineView#loadFromDrawable(AndroidSkeletonDrawable, Context, SpineController)}).
|
* ({@link SpineView#loadFromFile(File, File, Context, SpineController)}), URLs
|
||||||
|
* ({@link SpineView#loadFromHttp(URL, URL, File, Context, SpineController)}), or a pre-loaded {@link AndroidSkeletonDrawable}
|
||||||
|
* using ({@link SpineView#loadFromDrawable(AndroidSkeletonDrawable, Context, SpineController)}).
|
||||||
*
|
*
|
||||||
* The skeleton displayed by a {@link SpineView} can be controlled via a {@link SpineController}.
|
* The skeleton displayed by a {@link SpineView} can be controlled via a {@link SpineController}.
|
||||||
*
|
*
|
||||||
* The size of the widget can be derived from the bounds provided by a {@link BoundsProvider}. If the widget is not sized by the bounds
|
* The size of the widget can be derived from the bounds provided by a {@link BoundsProvider}. If the widget is not sized by the
|
||||||
* computed by the {@link BoundsProvider}, the widget will use the computed bounds to fit the skeleton inside the widget's dimensions.
|
* bounds computed by the {@link BoundsProvider}, the widget will use the computed bounds to fit the skeleton inside the widget's
|
||||||
*/
|
* dimensions. */
|
||||||
public class SpineView extends View implements Choreographer.FrameCallback {
|
public class SpineView extends View implements Choreographer.FrameCallback {
|
||||||
|
|
||||||
/**
|
/** Used to build {@link SpineView} instances. */
|
||||||
* Used to build {@link SpineView} instances.
|
|
||||||
* */
|
|
||||||
public static class Builder {
|
public static class Builder {
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final SpineController controller;
|
private final SpineController controller;
|
||||||
@ -80,90 +80,72 @@ public class SpineView extends View implements Choreographer.FrameCallback {
|
|||||||
private Alignment alignment = Alignment.CENTER;
|
private Alignment alignment = Alignment.CENTER;
|
||||||
private ContentMode contentMode = ContentMode.FIT;
|
private ContentMode contentMode = ContentMode.FIT;
|
||||||
|
|
||||||
/**
|
/** Instantiate a {@link Builder} used to build a {@link SpineView}, which is a {@link View} to display a Spine skeleton.
|
||||||
* Instantiate a {@link Builder} used to build a {@link SpineView}, which is a {@link View} to display a Spine skeleton.
|
|
||||||
*
|
*
|
||||||
* @param controller The skeleton displayed by a {@link SpineView} can be controlled via a {@link SpineController}.
|
* @param controller The skeleton displayed by a {@link SpineView} can be controlled via a {@link SpineController}. */
|
||||||
*/
|
public Builder (Context context, SpineController controller) {
|
||||||
public Builder(Context context, SpineController controller) {
|
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.controller = controller;
|
this.controller = controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Loads assets from your app assets for the {@link SpineView} if set. The {@code atlasFileName} specifies the `.atlas`
|
||||||
* Loads assets from your app assets for the {@link SpineView} if set. The {@code atlasFileName} specifies the
|
* file to be loaded for the images used to render the skeleton. The {@code skeletonFileName} specifies either a Skeleton
|
||||||
* `.atlas` file to be loaded for the images used to render the skeleton. The {@code skeletonFileName} specifies either a Skeleton `.json` or
|
* `.json` or `.skel` file containing the skeleton data. */
|
||||||
* `.skel` file containing the skeleton data.
|
public Builder setLoadFromAssets (String atlasFileName, String skeletonFileName) {
|
||||||
*/
|
|
||||||
public Builder setLoadFromAssets(String atlasFileName, String skeletonFileName) {
|
|
||||||
this.atlasFileName = atlasFileName;
|
this.atlasFileName = atlasFileName;
|
||||||
this.skeletonFileName = skeletonFileName;
|
this.skeletonFileName = skeletonFileName;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Loads assets from files for the {@link SpineView} if set. The {@code atlasFile} specifies the `.atlas` file to be loaded
|
||||||
* Loads assets from files for the {@link SpineView} if set. The {@code atlasFile} specifies the `.atlas` file to be loaded for the images used to render
|
* for the images used to render the skeleton. The {@code skeletonFile} specifies either a Skeleton `.json` or `.skel` file
|
||||||
* the skeleton. The {@code skeletonFile} specifies either a Skeleton `.json` or `.skel` file containing the skeleton data.
|
* containing the skeleton data. */
|
||||||
*/
|
public Builder setLoadFromFile (File atlasFile, File skeletonFile) {
|
||||||
public Builder setLoadFromFile(File atlasFile, File skeletonFile) {
|
|
||||||
this.atlasFile = atlasFile;
|
this.atlasFile = atlasFile;
|
||||||
this.skeletonFile = skeletonFile;
|
this.skeletonFile = skeletonFile;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Loads assets from http for the {@link SpineView} if set. The {@code atlasUrl} specifies the `.atlas` url to be loaded
|
||||||
* Loads assets from http for the {@link SpineView} if set. The {@code atlasUrl} specifies the `.atlas` url to be loaded for the images used to render
|
* for the images used to render the skeleton. The {@code skeletonUrl} specifies either a Skeleton `.json` or `.skel` url
|
||||||
* the skeleton. The {@code skeletonUrl} specifies either a Skeleton `.json` or `.skel` url containing the skeleton data.
|
* containing the skeleton data. */
|
||||||
*/
|
public Builder setLoadFromHttp (URL atlasUrl, URL skeletonUrl, File targetDirectory) {
|
||||||
public Builder setLoadFromHttp(URL atlasUrl, URL skeletonUrl, File targetDirectory) {
|
|
||||||
this.atlasUrl = atlasUrl;
|
this.atlasUrl = atlasUrl;
|
||||||
this.skeletonUrl = skeletonUrl;
|
this.skeletonUrl = skeletonUrl;
|
||||||
this.targetDirectory = targetDirectory;
|
this.targetDirectory = targetDirectory;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Uses the {@link AndroidSkeletonDrawable} for the {@link SpineView} if set. */
|
||||||
* Uses the {@link AndroidSkeletonDrawable} for the {@link SpineView} if set.
|
public Builder setLoadFromDrawable (AndroidSkeletonDrawable drawable) {
|
||||||
*/
|
|
||||||
public Builder setLoadFromDrawable(AndroidSkeletonDrawable drawable) {
|
|
||||||
this.drawable = drawable;
|
this.drawable = drawable;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Get the {@link BoundsProvider} used to compute the bounds of the {@link Skeleton} inside the view. The default is
|
||||||
* Get the {@link BoundsProvider} used to compute the bounds of the {@link Skeleton} inside the view.
|
* {@link SetupPoseBounds}. */
|
||||||
* The default is {@link SetupPoseBounds}.
|
public Builder setBoundsProvider (BoundsProvider boundsProvider) {
|
||||||
*/
|
|
||||||
public Builder setBoundsProvider(BoundsProvider boundsProvider) {
|
|
||||||
this.boundsProvider = boundsProvider;
|
this.boundsProvider = boundsProvider;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Get the {@link ContentMode} used to fit the {@link Skeleton} inside the view. The default is {@link ContentMode#FIT}. */
|
||||||
* Get the {@link ContentMode} used to fit the {@link Skeleton} inside the view.
|
public Builder setContentMode (ContentMode contentMode) {
|
||||||
* The default is {@link ContentMode#FIT}.
|
|
||||||
*/
|
|
||||||
public Builder setContentMode(ContentMode contentMode) {
|
|
||||||
this.contentMode = contentMode;
|
this.contentMode = contentMode;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Set the {@link Alignment} used to align the {@link Skeleton} inside the view. The default is {@link Alignment#CENTER} */
|
||||||
* Set the {@link Alignment} used to align the {@link Skeleton} inside the view.
|
public Builder setAlignment (Alignment alignment) {
|
||||||
* The default is {@link Alignment#CENTER}
|
|
||||||
*/
|
|
||||||
public Builder setAlignment(Alignment alignment) {
|
|
||||||
this.alignment = alignment;
|
this.alignment = alignment;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Builds a new {@link SpineView}.
|
||||||
* Builds a new {@link SpineView}.
|
|
||||||
*
|
*
|
||||||
* After initialization is complete, the provided {@code SpineController} is invoked as per the {@link SpineController} semantics, to allow
|
* After initialization is complete, the provided {@code SpineController} is invoked as per the {@link SpineController}
|
||||||
* modifying how the skeleton inside the widget is animated and rendered.
|
* semantics, to allow modifying how the skeleton inside the widget is animated and rendered. */
|
||||||
*/
|
public SpineView build () {
|
||||||
public SpineView build() {
|
|
||||||
SpineView spineView = new SpineView(context, controller);
|
SpineView spineView = new SpineView(context, controller);
|
||||||
spineView.boundsProvider = boundsProvider;
|
spineView.boundsProvider = boundsProvider;
|
||||||
spineView.alignment = alignment;
|
spineView.alignment = alignment;
|
||||||
@ -198,201 +180,162 @@ public class SpineView extends View implements Choreographer.FrameCallback {
|
|||||||
private Alignment alignment = Alignment.CENTER;
|
private Alignment alignment = Alignment.CENTER;
|
||||||
private ContentMode contentMode = ContentMode.FIT;
|
private ContentMode contentMode = ContentMode.FIT;
|
||||||
|
|
||||||
/**
|
/** Constructs a new {@link SpineView}.
|
||||||
* Constructs a new {@link SpineView}.
|
|
||||||
*
|
*
|
||||||
* After initialization is complete, the provided {@code SpineController} is invoked as per the {@link SpineController} semantics, to allow
|
* After initialization is complete, the provided {@code SpineController} is invoked as per the {@link SpineController}
|
||||||
* modifying how the skeleton inside the widget is animated and rendered.
|
* semantics, to allow modifying how the skeleton inside the widget is animated and rendered. */
|
||||||
*/
|
|
||||||
public SpineView (Context context, SpineController controller) {
|
public SpineView (Context context, SpineController controller) {
|
||||||
super(context);
|
super(context);
|
||||||
this.controller = controller;
|
this.controller = controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Constructs a new {@link SpineView} without providing a {@link SpineController}, which you need to provide using
|
||||||
* Constructs a new {@link SpineView} without providing a {@link SpineController}, which you need to provide using
|
* {@link SpineView#setController(SpineController)}. */
|
||||||
* {@link SpineView#setController(SpineController)}.
|
|
||||||
*/
|
|
||||||
public SpineView (Context context, AttributeSet attrs) {
|
public SpineView (Context context, AttributeSet attrs) {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
// Set properties by view id
|
// Set properties by view id
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Constructs a new {@link SpineView} without providing a {@link SpineController}, which you need to provide using
|
||||||
* Constructs a new {@link SpineView} without providing a {@link SpineController}, which you need to provide using
|
* {@link SpineView#setController(SpineController)}. */
|
||||||
* {@link SpineView#setController(SpineController)}.
|
|
||||||
*/
|
|
||||||
public SpineView (Context context, AttributeSet attrs, int defStyle) {
|
public SpineView (Context context, AttributeSet attrs, int defStyle) {
|
||||||
super(context, attrs, defStyle);
|
super(context, attrs, defStyle);
|
||||||
// Set properties by view id
|
// Set properties by view id
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Constructs a new {@link SpineView} from files in your app assets. The {@code atlasFileName} specifies the `.atlas` file to
|
||||||
* Constructs a new {@link SpineView} from files in your app assets. The {@code atlasFileName} specifies the
|
* be loaded for the images used to render the skeleton. The {@code skeletonFileName} specifies either a Skeleton `.json` or
|
||||||
* `.atlas` file to be loaded for the images used to render the skeleton. The {@code skeletonFileName} specifies either a Skeleton `.json` or
|
|
||||||
* `.skel` file containing the skeleton data.
|
* `.skel` file containing the skeleton data.
|
||||||
*
|
*
|
||||||
* After initialization is complete, the provided {@code controller} is invoked as per the {@link SpineController} semantics, to allow
|
* After initialization is complete, the provided {@code controller} is invoked as per the {@link SpineController} semantics,
|
||||||
* modifying how the skeleton inside the widget is animated and rendered.
|
* to allow modifying how the skeleton inside the widget is animated and rendered. */
|
||||||
*/
|
public static SpineView loadFromAssets (String atlasFileName, String skeletonFileName, Context context,
|
||||||
public static SpineView loadFromAssets(String atlasFileName, String skeletonFileName, Context context, SpineController controller) {
|
SpineController controller) {
|
||||||
SpineView spineView = new SpineView(context, controller);
|
SpineView spineView = new SpineView(context, controller);
|
||||||
spineView.loadFromAsset(atlasFileName, skeletonFileName);
|
spineView.loadFromAsset(atlasFileName, skeletonFileName);
|
||||||
return spineView;
|
return spineView;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Constructs a new {@link SpineView} from files. The {@code atlasFile} specifies the `.atlas` file to be loaded for the
|
||||||
* Constructs a new {@link SpineView} from files. The {@code atlasFile} specifies the `.atlas` file to be loaded for the images used to render
|
* images used to render the skeleton. The {@code skeletonFile} specifies either a Skeleton `.json` or `.skel` file containing
|
||||||
* the skeleton. The {@code skeletonFile} specifies either a Skeleton `.json` or `.skel` file containing the skeleton data.
|
* the skeleton data.
|
||||||
*
|
*
|
||||||
* After initialization is complete, the provided {@code SpineController} is invoked as per the {@link SpineController} semantics, to allow
|
* After initialization is complete, the provided {@code SpineController} is invoked as per the {@link SpineController}
|
||||||
* modifying how the skeleton inside the widget is animated and rendered.
|
* semantics, to allow modifying how the skeleton inside the widget is animated and rendered. */
|
||||||
*/
|
public static SpineView loadFromFile (File atlasFile, File skeletonFile, Context context, SpineController controller) {
|
||||||
public static SpineView loadFromFile(File atlasFile, File skeletonFile, Context context, SpineController controller) {
|
|
||||||
SpineView spineView = new SpineView(context, controller);
|
SpineView spineView = new SpineView(context, controller);
|
||||||
spineView.loadFromFile(atlasFile, skeletonFile);
|
spineView.loadFromFile(atlasFile, skeletonFile);
|
||||||
return spineView;
|
return spineView;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Constructs a new {@link SpineView} from HTTP URLs. The {@code atlasUrl} specifies the `.atlas` url to be loaded for the
|
||||||
* Constructs a new {@link SpineView} from HTTP URLs. The {@code atlasUrl} specifies the `.atlas` url to be loaded for the images used to render
|
* images used to render the skeleton. The {@code skeletonUrl} specifies either a Skeleton `.json` or `.skel` url containing
|
||||||
* the skeleton. The {@code skeletonUrl} specifies either a Skeleton `.json` or `.skel` url containing the skeleton data.
|
* the skeleton data.
|
||||||
*
|
*
|
||||||
* After initialization is complete, the provided {@code SpineController} is invoked as per the {@link SpineController} semantics, to allow
|
* After initialization is complete, the provided {@code SpineController} is invoked as per the {@link SpineController}
|
||||||
* modifying how the skeleton inside the widget is animated and rendered.
|
* semantics, to allow modifying how the skeleton inside the widget is animated and rendered. */
|
||||||
*/
|
public static SpineView loadFromHttp (URL atlasUrl, URL skeletonUrl, File targetDirectory, Context context,
|
||||||
public static SpineView loadFromHttp(URL atlasUrl, URL skeletonUrl, File targetDirectory, Context context, SpineController controller) {
|
SpineController controller) {
|
||||||
SpineView spineView = new SpineView(context, controller);
|
SpineView spineView = new SpineView(context, controller);
|
||||||
spineView.loadFromHttp(atlasUrl, skeletonUrl, targetDirectory);
|
spineView.loadFromHttp(atlasUrl, skeletonUrl, targetDirectory);
|
||||||
return spineView;
|
return spineView;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Constructs a new {@link SpineView} from a {@link AndroidSkeletonDrawable}.
|
||||||
* Constructs a new {@link SpineView} from a {@link AndroidSkeletonDrawable}.
|
|
||||||
*
|
*
|
||||||
* After initialization is complete, the provided {@code SpineController} is invoked as per the {@link SpineController} semantics, to allow
|
* After initialization is complete, the provided {@code SpineController} is invoked as per the {@link SpineController}
|
||||||
* modifying how the skeleton inside the widget is animated and rendered.
|
* semantics, to allow modifying how the skeleton inside the widget is animated and rendered. */
|
||||||
*/
|
public static SpineView loadFromDrawable (AndroidSkeletonDrawable drawable, Context context, SpineController controller) {
|
||||||
public static SpineView loadFromDrawable(AndroidSkeletonDrawable drawable, Context context, SpineController controller) {
|
|
||||||
SpineView spineView = new SpineView(context, controller);
|
SpineView spineView = new SpineView(context, controller);
|
||||||
spineView.loadFromDrawable(drawable);
|
spineView.loadFromDrawable(drawable);
|
||||||
return spineView;
|
return spineView;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** The same as {@link SpineView#loadFromAssets(String, String, Context, SpineController)}, but can be used after instantiating
|
||||||
* The same as {@link SpineView#loadFromAssets(String, String, Context, SpineController)}, but can be used after
|
* the view via {@link SpineView#SpineView(Context, SpineController)}. */
|
||||||
* instantiating the view via {@link SpineView#SpineView(Context, SpineController)}.
|
public void loadFromAsset (String atlasFileName, String skeletonFileName) {
|
||||||
*/
|
loadFrom( () -> AndroidSkeletonDrawable.fromAsset(atlasFileName, skeletonFileName, getContext()));
|
||||||
public void loadFromAsset(String atlasFileName, String skeletonFileName) {
|
|
||||||
loadFrom(() -> AndroidSkeletonDrawable.fromAsset(atlasFileName, skeletonFileName, getContext()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** The same as {@link SpineView#loadFromFile(File, File, Context, SpineController)}, but can be used after instantiating the
|
||||||
* The same as {@link SpineView#loadFromFile(File, File, Context, SpineController)}, but can be used after
|
* view via {@link SpineView#SpineView(Context, SpineController)}. */
|
||||||
* instantiating the view via {@link SpineView#SpineView(Context, SpineController)}.
|
public void loadFromFile (File atlasFile, File skeletonFile) {
|
||||||
*/
|
loadFrom( () -> AndroidSkeletonDrawable.fromFile(atlasFile, skeletonFile));
|
||||||
public void loadFromFile(File atlasFile, File skeletonFile) {
|
|
||||||
loadFrom(() -> AndroidSkeletonDrawable.fromFile(atlasFile, skeletonFile));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** The same as {@link SpineView#loadFromHttp(URL, URL, File, Context, SpineController)}, but can be used after instantiating
|
||||||
* The same as {@link SpineView#loadFromHttp(URL, URL, File, Context, SpineController)}, but can be used after
|
* the view via {@link SpineView#SpineView(Context, SpineController)}. */
|
||||||
* instantiating the view via {@link SpineView#SpineView(Context, SpineController)}.
|
public void loadFromHttp (URL atlasUrl, URL skeletonUrl, File targetDirectory) {
|
||||||
*/
|
loadFrom( () -> AndroidSkeletonDrawable.fromHttp(atlasUrl, skeletonUrl, targetDirectory));
|
||||||
public void loadFromHttp(URL atlasUrl, URL skeletonUrl, File targetDirectory) {
|
|
||||||
loadFrom(() -> AndroidSkeletonDrawable.fromHttp(atlasUrl, skeletonUrl, targetDirectory));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** The same as {@link SpineView#loadFromDrawable(AndroidSkeletonDrawable, Context, SpineController)}, but can be used after
|
||||||
* The same as {@link SpineView#loadFromDrawable(AndroidSkeletonDrawable, Context, SpineController)}, but can be used after
|
* instantiating the view via {@link SpineView#SpineView(Context, SpineController)}. */
|
||||||
* instantiating the view via {@link SpineView#SpineView(Context, SpineController)}.
|
public void loadFromDrawable (AndroidSkeletonDrawable drawable) {
|
||||||
*/
|
loadFrom( () -> drawable);
|
||||||
public void loadFromDrawable(AndroidSkeletonDrawable drawable) {
|
|
||||||
loadFrom(() -> drawable);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Get the {@link SpineController} */
|
||||||
* Get the {@link SpineController}
|
public SpineController getController () {
|
||||||
*/
|
|
||||||
public SpineController getController() {
|
|
||||||
return controller;
|
return controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Set the {@link SpineController}. Only do this if you use {@link SpineView#SpineView(Context, AttributeSet)},
|
||||||
* Set the {@link SpineController}. Only do this if you use {@link SpineView#SpineView(Context, AttributeSet)},
|
* {@link SpineView#SpineView(Context, AttributeSet, int)}, or create the {@link SpineView} in an XML layout. */
|
||||||
* {@link SpineView#SpineView(Context, AttributeSet, int)}, or create the {@link SpineView} in an XML layout.
|
public void setController (SpineController controller) {
|
||||||
*/
|
|
||||||
public void setController(SpineController controller) {
|
|
||||||
this.controller = controller;
|
this.controller = controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Get the {@link Alignment} used to align the {@link Skeleton} inside the view. The default is {@link Alignment#CENTER} */
|
||||||
* Get the {@link Alignment} used to align the {@link Skeleton} inside the view.
|
public Alignment getAlignment () {
|
||||||
* The default is {@link Alignment#CENTER}
|
|
||||||
*/
|
|
||||||
public Alignment getAlignment() {
|
|
||||||
return alignment;
|
return alignment;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Set the {@link Alignment}. */
|
||||||
* Set the {@link Alignment}.
|
public void setAlignment (Alignment alignment) {
|
||||||
*/
|
|
||||||
public void setAlignment(Alignment alignment) {
|
|
||||||
this.alignment = alignment;
|
this.alignment = alignment;
|
||||||
updateCanvasTransform();
|
updateCanvasTransform();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Get the {@link ContentMode} used to fit the {@link Skeleton} inside the view. The default is {@link ContentMode#FIT}. */
|
||||||
* Get the {@link ContentMode} used to fit the {@link Skeleton} inside the view.
|
public ContentMode getContentMode () {
|
||||||
* The default is {@link ContentMode#FIT}.
|
|
||||||
*/
|
|
||||||
public ContentMode getContentMode() {
|
|
||||||
return contentMode;
|
return contentMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Set the {@link ContentMode}. */
|
||||||
* Set the {@link ContentMode}.
|
public void setContentMode (ContentMode contentMode) {
|
||||||
*/
|
|
||||||
public void setContentMode(ContentMode contentMode) {
|
|
||||||
this.contentMode = contentMode;
|
this.contentMode = contentMode;
|
||||||
updateCanvasTransform();
|
updateCanvasTransform();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Get the {@link BoundsProvider} used to compute the bounds of the {@link Skeleton} inside the view. The default is
|
||||||
* Get the {@link BoundsProvider} used to compute the bounds of the {@link Skeleton} inside the view.
|
* {@link SetupPoseBounds}. */
|
||||||
* The default is {@link SetupPoseBounds}.
|
public BoundsProvider getBoundsProvider () {
|
||||||
*/
|
|
||||||
public BoundsProvider getBoundsProvider() {
|
|
||||||
return boundsProvider;
|
return boundsProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Set the {@link BoundsProvider}. */
|
||||||
* Set the {@link BoundsProvider}.
|
public void setBoundsProvider (BoundsProvider boundsProvider) {
|
||||||
*/
|
|
||||||
public void setBoundsProvider(BoundsProvider boundsProvider) {
|
|
||||||
this.boundsProvider = boundsProvider;
|
this.boundsProvider = boundsProvider;
|
||||||
updateCanvasTransform();
|
updateCanvasTransform();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Check if rendering is enabled. */
|
||||||
* Check if rendering is enabled.
|
public Boolean isRendering () {
|
||||||
*/
|
|
||||||
public Boolean isRendering() {
|
|
||||||
return rendering;
|
return rendering;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Set to disable or enable rendering. Disable it when the spine view is out of bounds and you want to preserve CPU/GPU
|
||||||
* Set to disable or enable rendering. Disable it when the spine view is out of bounds and you want to preserve CPU/GPU resources.
|
* resources. */
|
||||||
*/
|
public void setRendering (Boolean rendering) {
|
||||||
public void setRendering(Boolean rendering) {
|
|
||||||
this.rendering = rendering;
|
this.rendering = rendering;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadFrom(AndroidSkeletonDrawableLoader loader) {
|
private void loadFrom (AndroidSkeletonDrawableLoader loader) {
|
||||||
Handler mainHandler = new Handler(Looper.getMainLooper());
|
Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||||
Thread backgroundThread = new Thread(() -> {
|
Thread backgroundThread = new Thread( () -> {
|
||||||
final AndroidSkeletonDrawable skeletonDrawable = loader.load();
|
final AndroidSkeletonDrawable skeletonDrawable = loader.load();
|
||||||
mainHandler.post(() -> {
|
mainHandler.post( () -> {
|
||||||
computedBounds = boundsProvider.computeBounds(skeletonDrawable);
|
computedBounds = boundsProvider.computeBounds(skeletonDrawable);
|
||||||
updateCanvasTransform();
|
updateCanvasTransform();
|
||||||
|
|
||||||
@ -431,28 +374,30 @@ public class SpineView extends View implements Choreographer.FrameCallback {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
protected void onSizeChanged (int w, int h, int oldw, int oldh) {
|
||||||
super.onSizeChanged(w, h, oldw, oldh);
|
super.onSizeChanged(w, h, oldw, oldh);
|
||||||
updateCanvasTransform();
|
updateCanvasTransform();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateCanvasTransform() {
|
private void updateCanvasTransform () {
|
||||||
if (controller == null) {
|
if (controller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
x = (float) (-computedBounds.getX() - computedBounds.getWidth() / 2.0 - (alignment.getX() * computedBounds.getWidth() / 2.0));
|
x = (float)(-computedBounds.getX() - computedBounds.getWidth() / 2.0
|
||||||
y = (float) (-computedBounds.getY() - computedBounds.getHeight() / 2.0 - (alignment.getY() * computedBounds.getHeight() / 2.0));
|
- (alignment.getX() * computedBounds.getWidth() / 2.0));
|
||||||
|
y = (float)(-computedBounds.getY() - computedBounds.getHeight() / 2.0
|
||||||
|
- (alignment.getY() * computedBounds.getHeight() / 2.0));
|
||||||
|
|
||||||
switch (contentMode) {
|
switch (contentMode) {
|
||||||
case FIT:
|
case FIT:
|
||||||
scaleX = scaleY = (float) Math.min(getWidth() / computedBounds.getWidth(), getHeight() / computedBounds.getHeight());
|
scaleX = scaleY = (float)Math.min(getWidth() / computedBounds.getWidth(), getHeight() / computedBounds.getHeight());
|
||||||
break;
|
break;
|
||||||
case FILL:
|
case FILL:
|
||||||
scaleX = scaleY = (float) Math.max(getWidth() / computedBounds.getWidth(), getHeight() / computedBounds.getHeight());
|
scaleX = scaleY = (float)Math.max(getWidth() / computedBounds.getWidth(), getHeight() / computedBounds.getHeight());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
offsetX = (float) (getWidth() / 2.0 + (alignment.getX() * getWidth() / 2.0));
|
offsetX = (float)(getWidth() / 2.0 + (alignment.getX() * getWidth() / 2.0));
|
||||||
offsetY = (float) (getHeight() / 2.0 + (alignment.getY() * getHeight() / 2.0));
|
offsetY = (float)(getHeight() / 2.0 + (alignment.getY() * getHeight() / 2.0));
|
||||||
|
|
||||||
controller.setCoordinateTransform(x + offsetX / scaleX, y + offsetY / scaleY, scaleX, scaleY);
|
controller.setCoordinateTransform(x + offsetX / scaleX, y + offsetY / scaleY, scaleX, scaleY);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,33 +29,24 @@
|
|||||||
|
|
||||||
package com.esotericsoftware.spine.android.bounds;
|
package com.esotericsoftware.spine.android.bounds;
|
||||||
|
|
||||||
/**
|
/** How a view should be aligned within another view. */
|
||||||
* How a view should be aligned within another view.
|
|
||||||
*/
|
|
||||||
public enum Alignment {
|
public enum Alignment {
|
||||||
TOP_LEFT(-1.0f, -1.0f),
|
TOP_LEFT(-1.0f, -1.0f), TOP_CENTER(0.0f, -1.0f), TOP_RIGHT(1.0f, -1.0f), CENTER_LEFT(-1.0f, 0.0f), CENTER(0.0f,
|
||||||
TOP_CENTER(0.0f, -1.0f),
|
0.0f), CENTER_RIGHT(1.0f, 0.0f), BOTTOM_LEFT(-1.0f, 1.0f), BOTTOM_CENTER(0.0f, 1.0f), BOTTOM_RIGHT(1.0f, 1.0f);
|
||||||
TOP_RIGHT(1.0f, -1.0f),
|
|
||||||
CENTER_LEFT(-1.0f, 0.0f),
|
|
||||||
CENTER(0.0f, 0.0f),
|
|
||||||
CENTER_RIGHT(1.0f, 0.0f),
|
|
||||||
BOTTOM_LEFT(-1.0f, 1.0f),
|
|
||||||
BOTTOM_CENTER(0.0f, 1.0f),
|
|
||||||
BOTTOM_RIGHT(1.0f, 1.0f);
|
|
||||||
|
|
||||||
private final float x;
|
private final float x;
|
||||||
private final float y;
|
private final float y;
|
||||||
|
|
||||||
Alignment(float x, float y) {
|
Alignment (float x, float y) {
|
||||||
this.x = x;
|
this.x = x;
|
||||||
this.y = y;
|
this.y = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getX() {
|
public float getX () {
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getY() {
|
public float getY () {
|
||||||
return y;
|
return y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,31 +33,28 @@ import com.badlogic.gdx.math.Vector2;
|
|||||||
import com.badlogic.gdx.utils.FloatArray;
|
import com.badlogic.gdx.utils.FloatArray;
|
||||||
import com.esotericsoftware.spine.Skeleton;
|
import com.esotericsoftware.spine.Skeleton;
|
||||||
|
|
||||||
/**
|
/** Bounds denoted by the top left corner coordinates {@code x} and {@code y} and the {@code width} and {@code height}. */
|
||||||
* Bounds denoted by the top left corner coordinates {@code x} and {@code y}
|
|
||||||
* and the {@code width} and {@code height}.
|
|
||||||
*/
|
|
||||||
public class Bounds {
|
public class Bounds {
|
||||||
private double x;
|
private double x;
|
||||||
private double y;
|
private double y;
|
||||||
private double width;
|
private double width;
|
||||||
private double height;
|
private double height;
|
||||||
|
|
||||||
public Bounds() {
|
public Bounds () {
|
||||||
this.x = 0;
|
this.x = 0;
|
||||||
this.y = 0;
|
this.y = 0;
|
||||||
this.width = 0;
|
this.width = 0;
|
||||||
this.height = 0;
|
this.height = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Bounds(double x, double y, double width, double height) {
|
public Bounds (double x, double y, double width, double height) {
|
||||||
this.x = x;
|
this.x = x;
|
||||||
this.y = y;
|
this.y = y;
|
||||||
this.width = width;
|
this.width = width;
|
||||||
this.height = height;
|
this.height = height;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Bounds(Skeleton skeleton) {
|
public Bounds (Skeleton skeleton) {
|
||||||
Vector2 offset = new Vector2(0, 0);
|
Vector2 offset = new Vector2(0, 0);
|
||||||
Vector2 size = new Vector2(0, 0);
|
Vector2 size = new Vector2(0, 0);
|
||||||
FloatArray floatArray = new FloatArray();
|
FloatArray floatArray = new FloatArray();
|
||||||
@ -70,35 +67,35 @@ public class Bounds {
|
|||||||
height = size.y;
|
height = size.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getX() {
|
public double getX () {
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setX(double x) {
|
public void setX (double x) {
|
||||||
this.x = x;
|
this.x = x;
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getY() {
|
public double getY () {
|
||||||
return y;
|
return y;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setY(double y) {
|
public void setY (double y) {
|
||||||
this.y = y;
|
this.y = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getWidth() {
|
public double getWidth () {
|
||||||
return width;
|
return width;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setWidth(double width) {
|
public void setWidth (double width) {
|
||||||
this.width = width;
|
this.width = width;
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getHeight() {
|
public double getHeight () {
|
||||||
return height;
|
return height;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setHeight(double height) {
|
public void setHeight (double height) {
|
||||||
this.height = height;
|
this.height = height;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,10 +31,8 @@ package com.esotericsoftware.spine.android.bounds;
|
|||||||
|
|
||||||
import com.esotericsoftware.spine.android.AndroidSkeletonDrawable;
|
import com.esotericsoftware.spine.android.AndroidSkeletonDrawable;
|
||||||
|
|
||||||
/**
|
/** A {@link BoundsProvider} that calculates the bounding box of the skeleton based on the visible attachments in the setup
|
||||||
* A {@link BoundsProvider} that calculates the bounding box of the skeleton based on the visible
|
* pose. */
|
||||||
* attachments in the setup pose.
|
|
||||||
*/
|
|
||||||
public interface BoundsProvider {
|
public interface BoundsProvider {
|
||||||
Bounds computeBounds(AndroidSkeletonDrawable drawable);
|
Bounds computeBounds (AndroidSkeletonDrawable drawable);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,16 +29,10 @@
|
|||||||
|
|
||||||
package com.esotericsoftware.spine.android.bounds;
|
package com.esotericsoftware.spine.android.bounds;
|
||||||
|
|
||||||
/**
|
/** How a view should be inscribed into another view. */
|
||||||
* How a view should be inscribed into another view.
|
|
||||||
*/
|
|
||||||
public enum ContentMode {
|
public enum ContentMode {
|
||||||
/**
|
/** As large as possible while still containing the source view entirely within the target view. */
|
||||||
* As large as possible while still containing the source view entirely within the target view.
|
|
||||||
*/
|
|
||||||
FIT,
|
FIT,
|
||||||
/**
|
/** Fill the target view by distorting the source's aspect ratio. */
|
||||||
* Fill the target view by distorting the source's aspect ratio.
|
|
||||||
*/
|
|
||||||
FILL
|
FILL
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,16 +31,14 @@ package com.esotericsoftware.spine.android.bounds;
|
|||||||
|
|
||||||
import com.esotericsoftware.spine.android.AndroidSkeletonDrawable;
|
import com.esotericsoftware.spine.android.AndroidSkeletonDrawable;
|
||||||
|
|
||||||
/**
|
/** A {@link BoundsProvider} that returns fixed bounds. */
|
||||||
* A {@link BoundsProvider} that returns fixed bounds.
|
|
||||||
*/
|
|
||||||
public class RawBounds implements BoundsProvider {
|
public class RawBounds implements BoundsProvider {
|
||||||
final Double x;
|
final Double x;
|
||||||
final Double y;
|
final Double y;
|
||||||
final Double width;
|
final Double width;
|
||||||
final Double height;
|
final Double height;
|
||||||
|
|
||||||
public RawBounds(Double x, Double y, Double width, Double height) {
|
public RawBounds (Double x, Double y, Double width, Double height) {
|
||||||
this.x = x;
|
this.x = x;
|
||||||
this.y = y;
|
this.y = y;
|
||||||
this.width = width;
|
this.width = width;
|
||||||
@ -48,7 +46,7 @@ public class RawBounds implements BoundsProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Bounds computeBounds(AndroidSkeletonDrawable drawable) {
|
public Bounds computeBounds (AndroidSkeletonDrawable drawable) {
|
||||||
return new Bounds(x, y, width, height);
|
return new Bounds(x, y, width, height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,14 +31,12 @@ package com.esotericsoftware.spine.android.bounds;
|
|||||||
|
|
||||||
import com.esotericsoftware.spine.android.AndroidSkeletonDrawable;
|
import com.esotericsoftware.spine.android.AndroidSkeletonDrawable;
|
||||||
|
|
||||||
/**
|
/** A {@link BoundsProvider} that calculates the bounding box of the skeleton based on the visible attachments in the setup
|
||||||
* A {@link BoundsProvider} that calculates the bounding box of the skeleton based on the visible
|
* pose. */
|
||||||
* attachments in the setup pose.
|
|
||||||
*/
|
|
||||||
public class SetupPoseBounds implements BoundsProvider {
|
public class SetupPoseBounds implements BoundsProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Bounds computeBounds(AndroidSkeletonDrawable drawable) {
|
public Bounds computeBounds (AndroidSkeletonDrawable drawable) {
|
||||||
return new Bounds(drawable.getSkeleton());
|
return new Bounds(drawable.getSkeleton());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,46 +37,35 @@ import com.esotericsoftware.spine.android.AndroidSkeletonDrawable;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/** A {@link BoundsProvider} that calculates the bounding box needed for a combination of skins and an animation. */
|
||||||
* A {@link BoundsProvider} that calculates the bounding box needed for a combination of skins
|
|
||||||
* and an animation.
|
|
||||||
*/
|
|
||||||
public class SkinAndAnimationBounds implements BoundsProvider {
|
public class SkinAndAnimationBounds implements BoundsProvider {
|
||||||
private final List<String> skins;
|
private final List<String> skins;
|
||||||
private final String animation;
|
private final String animation;
|
||||||
private final double stepTime;
|
private final double stepTime;
|
||||||
|
|
||||||
/**
|
/** Constructs a new provider that will use the given {@code skins} and {@code animation} to calculate the bounding box of the
|
||||||
* Constructs a new provider that will use the given {@code skins} and {@code animation} to calculate
|
* skeleton. If no skins are given, the default skin is used. The {@code stepTime}, given in seconds, defines at what interval
|
||||||
* the bounding box of the skeleton. If no skins are given, the default skin is used.
|
* the bounds should be sampled across the entire animation. */
|
||||||
* The {@code stepTime}, given in seconds, defines at what interval the bounds should be sampled
|
public SkinAndAnimationBounds (List<String> skins, String animation, double stepTime) {
|
||||||
* across the entire animation.
|
|
||||||
*/
|
|
||||||
public SkinAndAnimationBounds(List<String> skins, String animation, double stepTime) {
|
|
||||||
this.skins = (skins == null || skins.isEmpty()) ? Collections.singletonList("default") : skins;
|
this.skins = (skins == null || skins.isEmpty()) ? Collections.singletonList("default") : skins;
|
||||||
this.animation = animation;
|
this.animation = animation;
|
||||||
this.stepTime = stepTime;
|
this.stepTime = stepTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Constructs a new provider that will use the given {@code skins} and {@code animation} to calculate the bounding box of the
|
||||||
* Constructs a new provider that will use the given {@code skins} and {@code animation} to calculate
|
* skeleton. If no skins are given, the default skin is used. The {@code stepTime} has default value 0.1. */
|
||||||
* the bounding box of the skeleton. If no skins are given, the default skin is used.
|
public SkinAndAnimationBounds (List<String> skins, String animation) {
|
||||||
* The {@code stepTime} has default value 0.1.
|
|
||||||
*/
|
|
||||||
public SkinAndAnimationBounds(List<String> skins, String animation) {
|
|
||||||
this(skins, animation, 0.1);
|
this(skins, animation, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Constructs a new provider that will use the given {@code skins} and {@code animation} to calculate the bounding box of the
|
||||||
* Constructs a new provider that will use the given {@code skins} and {@code animation} to calculate
|
* skeleton. The default skin is used. The {@code stepTime} has default value 0.1. */
|
||||||
* the bounding box of the skeleton. The default skin is used. The {@code stepTime} has default value 0.1.
|
public SkinAndAnimationBounds (String animation) {
|
||||||
*/
|
|
||||||
public SkinAndAnimationBounds(String animation) {
|
|
||||||
this(Collections.emptyList(), animation, 0.1);
|
this(Collections.emptyList(), animation, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Bounds computeBounds(AndroidSkeletonDrawable drawable) {
|
public Bounds computeBounds (AndroidSkeletonDrawable drawable) {
|
||||||
SkeletonData data = drawable.getSkeletonData();
|
SkeletonData data = drawable.getSkeletonData();
|
||||||
Skin oldSkin = drawable.getSkeleton().getSkin();
|
Skin oldSkin = drawable.getSkeleton().getSkin();
|
||||||
Skin customSkin = new Skin("custom-skin");
|
Skin customSkin = new Skin("custom-skin");
|
||||||
@ -101,9 +90,9 @@ public class SkinAndAnimationBounds implements BoundsProvider {
|
|||||||
maxY = minY + bounds.getHeight();
|
maxY = minY + bounds.getHeight();
|
||||||
} else {
|
} else {
|
||||||
drawable.getAnimationState().setAnimation(0, animation, false);
|
drawable.getAnimationState().setAnimation(0, animation, false);
|
||||||
int steps = (int) Math.max( (animation.getDuration() / stepTime), 1.0);
|
int steps = (int)Math.max((animation.getDuration() / stepTime), 1.0);
|
||||||
for (int i = 0; i < steps; i++) {
|
for (int i = 0; i < steps; i++) {
|
||||||
drawable.update(i > 0 ? (float) stepTime : 0);
|
drawable.update(i > 0 ? (float)stepTime : 0);
|
||||||
Bounds bounds = new Bounds(drawable.getSkeleton());
|
Bounds bounds = new Bounds(drawable.getSkeleton());
|
||||||
minX = Math.min(minX, bounds.getX());
|
minX = Math.min(minX, bounds.getX());
|
||||||
minY = Math.min(minY, bounds.getY());
|
minY = Math.min(minY, bounds.getY());
|
||||||
|
|||||||
@ -33,5 +33,5 @@ import com.esotericsoftware.spine.android.AndroidSkeletonDrawable;
|
|||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface AndroidSkeletonDrawableLoader {
|
public interface AndroidSkeletonDrawableLoader {
|
||||||
AndroidSkeletonDrawable load();
|
AndroidSkeletonDrawable load ();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -41,21 +41,17 @@ import java.net.HttpURLConnection;
|
|||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
|
|
||||||
/**
|
/** Helper to load http resources. */
|
||||||
* Helper to load http resources.
|
|
||||||
*/
|
|
||||||
public class HttpUtils {
|
public class HttpUtils {
|
||||||
/**
|
/** Download a file from an url into a target directory. It keeps the name from the {@code url}. This should NOT be executed on
|
||||||
* Download a file from an url into a target directory. It keeps the name from the {@code url}.
|
* the main run loop. */
|
||||||
* This should NOT be executed on the main run loop.
|
public static File downloadFrom (URL url, File targetDirectory) throws RuntimeException {
|
||||||
*/
|
|
||||||
public static File downloadFrom(URL url, File targetDirectory) throws RuntimeException {
|
|
||||||
HttpURLConnection urlConnection = null;
|
HttpURLConnection urlConnection = null;
|
||||||
InputStream inputStream = null;
|
InputStream inputStream = null;
|
||||||
OutputStream outputStream = null;
|
OutputStream outputStream = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
urlConnection = (HttpURLConnection) url.openConnection();
|
urlConnection = (HttpURLConnection)url.openConnection();
|
||||||
urlConnection.connect();
|
urlConnection.connect();
|
||||||
|
|
||||||
if (urlConnection.getResponseCode() != HttpURLConnection.HTTP_OK) {
|
if (urlConnection.getResponseCode() != HttpURLConnection.HTTP_OK) {
|
||||||
@ -72,7 +68,7 @@ public class HttpUtils {
|
|||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
outputStream = Files.newOutputStream(file.toPath());
|
outputStream = Files.newOutputStream(file.toPath());
|
||||||
} else {
|
} else {
|
||||||
//noinspection IOStreamConstructor
|
// noinspection IOStreamConstructor
|
||||||
outputStream = new FileOutputStream(file);
|
outputStream = new FileOutputStream(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,4 +106,3 @@ public class HttpUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -46,18 +46,14 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
/**
|
/** Helper to load {@link SkeletonData} from assets. */
|
||||||
* Helper to load {@link SkeletonData} from assets.
|
|
||||||
*/
|
|
||||||
public class SkeletonDataUtils {
|
public class SkeletonDataUtils {
|
||||||
|
|
||||||
/**
|
/** Loads a {@link SkeletonData} from the file {@code skeletonFile} in assets using {@link Context}. Uses the provided
|
||||||
* Loads a {@link SkeletonData} from the file {@code skeletonFile} in assets using {@link Context}.
|
* {@link AndroidTextureAtlas} to resolve attachment images.
|
||||||
* Uses the provided {@link AndroidTextureAtlas} to resolve attachment images.
|
|
||||||
*
|
*
|
||||||
* Throws a {@link RuntimeException} in case the skeleton data could not be loaded.
|
* Throws a {@link RuntimeException} in case the skeleton data could not be loaded. */
|
||||||
*/
|
public static SkeletonData fromAsset (AndroidTextureAtlas atlas, String skeletonFileName, Context context) {
|
||||||
public static SkeletonData fromAsset(AndroidTextureAtlas atlas, String skeletonFileName, Context context) {
|
|
||||||
AndroidAtlasAttachmentLoader attachmentLoader = new AndroidAtlasAttachmentLoader(atlas);
|
AndroidAtlasAttachmentLoader attachmentLoader = new AndroidAtlasAttachmentLoader(atlas);
|
||||||
|
|
||||||
SkeletonLoader skeletonLoader;
|
SkeletonLoader skeletonLoader;
|
||||||
@ -78,12 +74,11 @@ public class SkeletonDataUtils {
|
|||||||
return skeletonData;
|
return skeletonData;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Loads a {@link SkeletonData} from the file {@code skeletonFile}. Uses the provided {@link AndroidTextureAtlas} to resolve
|
||||||
* Loads a {@link SkeletonData} from the file {@code skeletonFile}. Uses the provided {@link AndroidTextureAtlas} to resolve attachment images.
|
* attachment images.
|
||||||
*
|
*
|
||||||
* Throws a {@link RuntimeException} in case the skeleton data could not be loaded.
|
* Throws a {@link RuntimeException} in case the skeleton data could not be loaded. */
|
||||||
*/
|
public static SkeletonData fromFile (AndroidTextureAtlas atlas, File skeletonFile) {
|
||||||
public static SkeletonData fromFile(AndroidTextureAtlas atlas, File skeletonFile) {
|
|
||||||
AndroidAtlasAttachmentLoader attachmentLoader = new AndroidAtlasAttachmentLoader(atlas);
|
AndroidAtlasAttachmentLoader attachmentLoader = new AndroidAtlasAttachmentLoader(atlas);
|
||||||
|
|
||||||
SkeletonLoader skeletonLoader;
|
SkeletonLoader skeletonLoader;
|
||||||
@ -96,12 +91,11 @@ public class SkeletonDataUtils {
|
|||||||
return skeletonLoader.readSkeletonData(new FileHandle(skeletonFile));
|
return skeletonLoader.readSkeletonData(new FileHandle(skeletonFile));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Loads a {@link SkeletonData} from the URL {@code skeletonURL}. Uses the provided {@link AndroidTextureAtlas} to resolve
|
||||||
* Loads a {@link SkeletonData} from the URL {@code skeletonURL}. Uses the provided {@link AndroidTextureAtlas} to resolve attachment images.
|
* attachment images.
|
||||||
*
|
*
|
||||||
* Throws a {@link RuntimeException} in case the skeleton data could not be loaded.
|
* Throws a {@link RuntimeException} in case the skeleton data could not be loaded. */
|
||||||
*/
|
public static SkeletonData fromHttp (AndroidTextureAtlas atlas, URL skeletonUrl, File targetDirectory) {
|
||||||
public static SkeletonData fromHttp(AndroidTextureAtlas atlas, URL skeletonUrl, File targetDirectory) {
|
|
||||||
File skeletonFile = HttpUtils.downloadFrom(skeletonUrl, targetDirectory);
|
File skeletonFile = HttpUtils.downloadFrom(skeletonUrl, targetDirectory);
|
||||||
return fromFile(atlas, skeletonFile);
|
return fromFile(atlas, skeletonFile);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,17 +1,16 @@
|
|||||||
|
|
||||||
package com.esotericsoftware.android;
|
package com.esotericsoftware.android;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
/**
|
/** Example local unit test, which will execute on the development machine (host).
|
||||||
* Example local unit test, which will execute on the development machine (host).
|
|
||||||
*
|
*
|
||||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a> */
|
||||||
*/
|
|
||||||
public class ExampleUnitTest {
|
public class ExampleUnitTest {
|
||||||
@Test
|
@Test
|
||||||
public void addition_isCorrect() {
|
public void addition_isCorrect () {
|
||||||
assertEquals(4, 2 + 2);
|
assertEquals(4, 2 + 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -95,7 +95,7 @@ public class Slot {
|
|||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setColor(Color color) {
|
public void setColor (Color color) {
|
||||||
this.color = color;
|
this.color = color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user