mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2025-12-20 09:16:01 +08:00
Implement loadFromHttp
This commit is contained in:
parent
e30dd8956e
commit
6729f8bbce
@ -2,6 +2,8 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
|
||||
@ -15,6 +15,8 @@ import androidx.compose.ui.viewinterop.AndroidView
|
||||
import androidx.navigation.NavHostController
|
||||
import com.esotericsoftware.spine.android.SpineController
|
||||
import com.esotericsoftware.spine.android.SpineView
|
||||
import java.io.File
|
||||
import java.net.URL
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
@ -44,6 +46,15 @@ fun SimpleAnimation(nav: NavHostController) {
|
||||
it.animationState.setAnimation(0, "walk", true)
|
||||
}
|
||||
)
|
||||
// SpineView.loadFromHttp(
|
||||
// URL("https://raw.githubusercontent.com/EsotericSoftware/spine-runtimes/4.2/examples/spineboy/export/spineboy.atlas"),
|
||||
// URL("https://raw.githubusercontent.com/EsotericSoftware/spine-runtimes/4.2/examples/spineboy/export/spineboy-pro.skel"),
|
||||
// context.filesDir,
|
||||
// context,
|
||||
// SpineController {
|
||||
// it.animationState.setAnimation(0, "walk", true)
|
||||
// }
|
||||
// )
|
||||
},
|
||||
modifier = Modifier.padding(paddingValues)
|
||||
)
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
</manifest>
|
||||
@ -80,9 +80,9 @@ public class AndroidSkeletonDrawable {
|
||||
return new AndroidSkeletonDrawable(atlas, skeletonData);
|
||||
}
|
||||
|
||||
public static AndroidSkeletonDrawable fromHttp (URL atlasUrl, URL skeletonUrl) {
|
||||
AndroidTextureAtlas atlas = AndroidTextureAtlas.fromHttp(atlasUrl);
|
||||
SkeletonData skeletonData = SkeletonDataUtils.fromHttp(atlas, skeletonUrl);
|
||||
public static AndroidSkeletonDrawable fromHttp (URL atlasUrl, URL skeletonUrl, File targetDirectory) {
|
||||
AndroidTextureAtlas atlas = AndroidTextureAtlas.fromHttp(atlasUrl, targetDirectory);
|
||||
SkeletonData skeletonData = SkeletonDataUtils.fromHttp(atlas, skeletonUrl, targetDirectory);
|
||||
return new AndroidSkeletonDrawable(atlas, skeletonData);
|
||||
}
|
||||
|
||||
|
||||
@ -35,21 +35,22 @@ import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
import java.nio.file.Files;
|
||||
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion;
|
||||
import com.badlogic.gdx.graphics.g2d.TextureAtlas.TextureAtlasData;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import com.badlogic.gdx.utils.Null;
|
||||
import com.esotericsoftware.spine.android.utils.SpineHttpUtils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.AssetManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
|
||||
import kotlin.NotImplementedError;
|
||||
import android.os.Build;
|
||||
|
||||
public class AndroidTextureAtlas {
|
||||
private static interface BitmapLoader {
|
||||
@ -131,9 +132,64 @@ public class AndroidTextureAtlas {
|
||||
}
|
||||
|
||||
static public AndroidTextureAtlas fromFile(File atlasFile) {
|
||||
TextureAtlasData data = new TextureAtlasData();
|
||||
|
||||
TextureAtlasData data;
|
||||
try {
|
||||
data = loadTextureAtlasData(atlasFile);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return new AndroidTextureAtlas(data, path -> {
|
||||
File imageFile = new File(path);
|
||||
try (InputStream in = new BufferedInputStream(inputStream(imageFile))) {
|
||||
return BitmapFactory.decodeStream(in);
|
||||
} catch (Throwable t) {
|
||||
throw new RuntimeException(t);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static public AndroidTextureAtlas fromHttp(URL atlasUrl, File targetDirectory) {
|
||||
File atlasFile = SpineHttpUtils.downloadFrom(atlasUrl, targetDirectory);
|
||||
TextureAtlasData data;
|
||||
try {
|
||||
data = loadTextureAtlasData(atlasFile);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return new AndroidTextureAtlas(data, path -> {
|
||||
String fileName = path.substring(path.lastIndexOf('/') + 1);
|
||||
|
||||
String atlasUrlPath = atlasUrl.getPath();
|
||||
int lastSlashIndex = atlasUrlPath.lastIndexOf('/');
|
||||
String imagePath = atlasUrlPath.substring(0, lastSlashIndex + 1) + fileName;
|
||||
|
||||
File imageFile;
|
||||
try {
|
||||
URL imageUrl = new URL(atlasUrl.getProtocol(), atlasUrl.getHost(), atlasUrl.getPort(), imagePath);
|
||||
imageFile = SpineHttpUtils.downloadFrom(imageUrl, targetDirectory);
|
||||
} catch (MalformedURLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
try (InputStream in = new BufferedInputStream(inputStream(imageFile))) {
|
||||
return BitmapFactory.decodeStream(in);
|
||||
} catch (Throwable t) {
|
||||
throw new RuntimeException(t);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static InputStream inputStream(File file) throws Exception {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
return Files.newInputStream(file.toPath());
|
||||
} else {
|
||||
//noinspection IOStreamConstructor
|
||||
return new FileInputStream(file);
|
||||
}
|
||||
}
|
||||
|
||||
static private TextureAtlasData loadTextureAtlasData(File atlasFile) {
|
||||
TextureAtlasData data = new TextureAtlasData();
|
||||
FileHandle inputFile = new FileHandle() {
|
||||
@Override
|
||||
public InputStream read() {
|
||||
@ -145,21 +201,6 @@ public class AndroidTextureAtlas {
|
||||
}
|
||||
};
|
||||
data.load(inputFile, new FileHandle(atlasFile).parent(), false);
|
||||
} catch (Throwable t) {
|
||||
throw new RuntimeException(t);
|
||||
}
|
||||
|
||||
return new AndroidTextureAtlas(data, path -> {
|
||||
File imageFile = new File(path);
|
||||
try (InputStream in = new BufferedInputStream(new FileInputStream(imageFile))) {
|
||||
return BitmapFactory.decodeStream(in);
|
||||
} catch (Throwable t) {
|
||||
throw new RuntimeException(t);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static public AndroidTextureAtlas fromHttp(URL atlasUrl) {
|
||||
throw new NotImplementedError("TODO");
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
@ -146,6 +146,12 @@ public class SpineView extends View implements Choreographer.FrameCallback {
|
||||
return spineView;
|
||||
}
|
||||
|
||||
public static SpineView loadFromHttp(URL atlasUrl, URL skeletonUrl, File targetDirectory, Context context, SpineController controller) {
|
||||
SpineView spineView = new SpineView(context, controller);
|
||||
spineView.loadFromHttp(atlasUrl, skeletonUrl, targetDirectory);
|
||||
return spineView;
|
||||
}
|
||||
|
||||
public static SpineView loadFromDrawable(AndroidSkeletonDrawable drawable, Context context, SpineController controller) {
|
||||
SpineView spineView = new SpineView(context, controller);
|
||||
spineView.loadFromDrawable(drawable);
|
||||
@ -164,8 +170,8 @@ public class SpineView extends View implements Choreographer.FrameCallback {
|
||||
loadFrom(() -> AndroidSkeletonDrawable.fromFile(atlasFile, skeletonFile));
|
||||
}
|
||||
|
||||
public void loadFromHttp(URL atlasUrl, URL skeletonUrl) {
|
||||
loadFrom(() -> AndroidSkeletonDrawable.fromHttp(atlasUrl, skeletonUrl));
|
||||
public void loadFromHttp(URL atlasUrl, URL skeletonUrl, File targetDirectory) {
|
||||
loadFrom(() -> AndroidSkeletonDrawable.fromHttp(atlasUrl, skeletonUrl, targetDirectory));
|
||||
}
|
||||
|
||||
public void loadFromDrawable(AndroidSkeletonDrawable drawable) {
|
||||
|
||||
@ -55,7 +55,8 @@ public class SkeletonDataUtils {
|
||||
return skeletonLoader.readSkeletonData(new FileHandle(skeletonFile));
|
||||
}
|
||||
|
||||
public static SkeletonData fromHttp(AndroidTextureAtlas atlas, URL skeletonUrl) {
|
||||
throw new NotImplementedError("TODO");
|
||||
public static SkeletonData fromHttp(AndroidTextureAtlas atlas, URL skeletonUrl, File targetDirectory) {
|
||||
File skeletonFile = SpineHttpUtils.downloadFrom(skeletonUrl, targetDirectory);
|
||||
return fromFile(atlas, skeletonFile);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,80 @@
|
||||
package com.esotericsoftware.spine.android.utils;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
import com.esotericsoftware.spine.android.AndroidTextureAtlas;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
|
||||
public class SpineHttpUtils {
|
||||
|
||||
public static File downloadFrom(URL url, File targetDirectory) throws RuntimeException {
|
||||
HttpURLConnection urlConnection = null;
|
||||
InputStream inputStream = null;
|
||||
OutputStream outputStream = null;
|
||||
|
||||
try {
|
||||
urlConnection = (HttpURLConnection) url.openConnection();
|
||||
urlConnection.connect();
|
||||
|
||||
if (urlConnection.getResponseCode() != HttpURLConnection.HTTP_OK) {
|
||||
throw new RuntimeException("Failed to connect: HTTP response code " + urlConnection.getResponseCode());
|
||||
}
|
||||
|
||||
inputStream = new BufferedInputStream(urlConnection.getInputStream());
|
||||
|
||||
String atlasUrlPath = url.getPath();
|
||||
String fileName = atlasUrlPath.substring(atlasUrlPath.lastIndexOf('/') + 1);
|
||||
File file = new File(targetDirectory, fileName);
|
||||
|
||||
// Create an OutputStream to write to the file
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
outputStream = Files.newOutputStream(file.toPath());
|
||||
} else {
|
||||
//noinspection IOStreamConstructor
|
||||
outputStream = new FileOutputStream(file);
|
||||
}
|
||||
|
||||
byte[] buffer = new byte[1024];
|
||||
int bytesRead;
|
||||
|
||||
// Write the input stream to the output stream
|
||||
while ((bytesRead = inputStream.read(buffer)) != -1) {
|
||||
outputStream.write(buffer, 0, bytesRead);
|
||||
}
|
||||
return file;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
if (outputStream != null) {
|
||||
try {
|
||||
outputStream.flush();
|
||||
outputStream.close();
|
||||
} catch (IOException e) {
|
||||
// Nothing we can do
|
||||
}
|
||||
}
|
||||
|
||||
if (inputStream != null) {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (IOException e) {
|
||||
// Nothing we can do
|
||||
}
|
||||
}
|
||||
|
||||
if (urlConnection != null) {
|
||||
urlConnection.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user