mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2025-12-21 01:36:02 +08:00
MeshAttachment support.
This commit is contained in:
parent
f087d56da6
commit
1c9973ef1d
@ -47,6 +47,7 @@ import com.esotericsoftware.spine.attachments.Attachment;
|
||||
import com.esotericsoftware.spine.attachments.AttachmentLoader;
|
||||
import com.esotericsoftware.spine.attachments.AttachmentType;
|
||||
import com.esotericsoftware.spine.attachments.BoundingBoxAttachment;
|
||||
import com.esotericsoftware.spine.attachments.MeshAttachment;
|
||||
import com.esotericsoftware.spine.attachments.RegionAttachment;
|
||||
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
@ -188,7 +189,7 @@ public class SkeletonBinary {
|
||||
if (name == null) name = attachmentName;
|
||||
|
||||
switch (AttachmentType.values()[input.readByte()]) {
|
||||
case region:
|
||||
case region: {
|
||||
String path = input.readString();
|
||||
if (path == null) path = name;
|
||||
RegionAttachment region = attachmentLoader.newRegionAttachment(skin, name, path);
|
||||
@ -203,19 +204,58 @@ public class SkeletonBinary {
|
||||
Color.rgba8888ToColor(region.getColor(), input.readInt());
|
||||
region.updateOffset();
|
||||
return region;
|
||||
case boundingbox:
|
||||
}
|
||||
case boundingbox: {
|
||||
BoundingBoxAttachment box = attachmentLoader.newBoundingBoxAttachment(skin, name);
|
||||
if (box == null) return null;
|
||||
int n = input.readInt(true);
|
||||
float[] points = new float[n];
|
||||
for (int i = 0; i < n; i++)
|
||||
points[i] = input.readFloat();
|
||||
box.setVertices(points);
|
||||
box.setVertices(readFloatArray(input, scale));
|
||||
return box;
|
||||
}
|
||||
case mesh: {
|
||||
String path = input.readString();
|
||||
if (path == null) path = name;
|
||||
MeshAttachment mesh = attachmentLoader.newMeshAttachment(skin, name, path);
|
||||
float[] vertices = readFloatArray(input, scale);
|
||||
short[] triangles = readShortArray(input);
|
||||
float[] uvs = readFloatArray(input, 1);
|
||||
Color.rgba8888ToColor(mesh.getColor(), input.readInt());
|
||||
mesh.setEdges(readIntArray(input));
|
||||
if (mesh.getEdges().length > 0) {
|
||||
mesh.setHullLength(input.readInt(true));
|
||||
mesh.setWidth(input.readFloat() * scale);
|
||||
mesh.setHeight(input.readFloat() * scale);
|
||||
}
|
||||
mesh.setMesh(vertices, triangles, uvs);
|
||||
return mesh;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private float[] readFloatArray (DataInput input, float scale) throws IOException {
|
||||
int n = input.readInt(true);
|
||||
float[] array = new float[n];
|
||||
for (int i = 0; i < n; i++)
|
||||
array[i] = input.readFloat() * scale;
|
||||
return array;
|
||||
}
|
||||
|
||||
private short[] readShortArray (DataInput input) throws IOException {
|
||||
int n = input.readInt(true);
|
||||
short[] array = new short[n];
|
||||
for (int i = 0; i < n; i++)
|
||||
array[i] = input.readShort();
|
||||
return array;
|
||||
}
|
||||
|
||||
private int[] readIntArray (DataInput input) throws IOException {
|
||||
int n = input.readInt(true);
|
||||
int[] array = new int[n];
|
||||
for (int i = 0; i < n; i++)
|
||||
array[i] = input.readInt(true);
|
||||
return array;
|
||||
}
|
||||
|
||||
private void readAnimation (String name, DataInput input, SkeletonData skeletonData) {
|
||||
Array<Timeline> timelines = new Array();
|
||||
float duration = 0;
|
||||
|
||||
@ -47,6 +47,7 @@ import com.esotericsoftware.spine.attachments.Attachment;
|
||||
import com.esotericsoftware.spine.attachments.AttachmentLoader;
|
||||
import com.esotericsoftware.spine.attachments.AttachmentType;
|
||||
import com.esotericsoftware.spine.attachments.BoundingBoxAttachment;
|
||||
import com.esotericsoftware.spine.attachments.MeshAttachment;
|
||||
import com.esotericsoftware.spine.attachments.RegionAttachment;
|
||||
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
@ -184,16 +185,24 @@ public class SkeletonJson {
|
||||
|
||||
region.updateOffset();
|
||||
return region;
|
||||
case boundingbox:
|
||||
case boundingbox: {
|
||||
BoundingBoxAttachment box = attachmentLoader.newBoundingBoxAttachment(skin, name);
|
||||
JsonValue verticesArray = map.require("vertices");
|
||||
float[] vertices = new float[verticesArray.size];
|
||||
int i = 0;
|
||||
for (JsonValue point = verticesArray.child; point != null; point = point.next())
|
||||
vertices[i++] = point.asFloat() * scale;
|
||||
box.setVertices(vertices);
|
||||
box.setVertices(readFloatArray(map.require("vertices"), scale));
|
||||
return box;
|
||||
}
|
||||
case mesh: {
|
||||
MeshAttachment mesh = attachmentLoader.newMeshAttachment(skin, name, map.getString("path", name));
|
||||
float[] vertices = readFloatArray(map.require("vertices"), scale);
|
||||
short[] triangles = readShortArray(map.require("triangles"));
|
||||
float[] uvs = readFloatArray(map.require("uvs"), 1);
|
||||
mesh.setMesh(vertices, triangles, uvs);
|
||||
if (map.has("hull")) mesh.setHullLength(map.require("hull").asInt());
|
||||
if (map.has("edges")) mesh.setEdges(readIntArray(map.require("edges")));
|
||||
mesh.setWidth(map.getFloat("width", 0) * scale);
|
||||
mesh.setHeight(map.getFloat("height", 0) * scale);
|
||||
return mesh;
|
||||
}
|
||||
}
|
||||
|
||||
// RegionSequenceAttachment regionSequenceAttachment = (RegionSequenceAttachment)attachment;
|
||||
//
|
||||
@ -206,6 +215,30 @@ public class SkeletonJson {
|
||||
return null;
|
||||
}
|
||||
|
||||
private float[] readFloatArray (JsonValue jsonArray, float scale) {
|
||||
float[] array = new float[jsonArray.size];
|
||||
int i = 0;
|
||||
for (JsonValue point = jsonArray.child; point != null; point = point.next())
|
||||
array[i++] = point.asFloat() * scale;
|
||||
return array;
|
||||
}
|
||||
|
||||
private short[] readShortArray (JsonValue jsonArray) {
|
||||
short[] array = new short[jsonArray.size];
|
||||
int i = 0;
|
||||
for (JsonValue point = jsonArray.child; point != null; point = point.next())
|
||||
array[i++] = (short)point.asInt();
|
||||
return array;
|
||||
}
|
||||
|
||||
private int[] readIntArray (JsonValue jsonArray) {
|
||||
int[] array = new int[jsonArray.size];
|
||||
int i = 0;
|
||||
for (JsonValue point = jsonArray.child; point != null; point = point.next())
|
||||
array[i++] = point.asInt();
|
||||
return array;
|
||||
}
|
||||
|
||||
private void readAnimation (String name, JsonValue map, SkeletonData skeletonData) {
|
||||
Array<Timeline> timelines = new Array();
|
||||
float duration = 0;
|
||||
|
||||
@ -34,6 +34,7 @@
|
||||
package com.esotericsoftware.spine;
|
||||
|
||||
import com.esotericsoftware.spine.attachments.Attachment;
|
||||
import com.esotericsoftware.spine.attachments.MeshAttachment;
|
||||
import com.esotericsoftware.spine.attachments.RegionAttachment;
|
||||
import com.esotericsoftware.spine.attachments.SkeletonAttachment;
|
||||
|
||||
@ -78,6 +79,15 @@ public class SkeletonRenderer {
|
||||
}
|
||||
|
||||
batch.draw(texture, vertices, 0, vertices.length, triangles, 0, triangles.length);
|
||||
|
||||
} else if (attachment instanceof MeshAttachment) {
|
||||
MeshAttachment mesh = (MeshAttachment)attachment;
|
||||
mesh.updateWorldVertices(slot, true);
|
||||
vertices = mesh.getWorldVertices();
|
||||
triangles = mesh.getTriangles();
|
||||
texture = mesh.getRegion().getTexture();
|
||||
batch.draw(texture, vertices, 0, vertices.length, triangles, 0, triangles.length);
|
||||
|
||||
} else if (attachment instanceof SkeletonAttachment) {
|
||||
Skeleton attachmentSkeleton = ((SkeletonAttachment)attachment).getSkeleton();
|
||||
if (attachmentSkeleton == null) continue;
|
||||
|
||||
@ -56,6 +56,16 @@ public class AtlasAttachmentLoader implements AttachmentLoader {
|
||||
return attachment;
|
||||
}
|
||||
|
||||
public MeshAttachment newMeshAttachment (Skin skin, String name, String path) {
|
||||
MeshAttachment attachment = new MeshAttachment(name);
|
||||
attachment.setPath(path);
|
||||
AtlasRegion region = atlas.findRegion(path);
|
||||
if (region == null)
|
||||
throw new RuntimeException("Region not found in atlas: " + attachment + " (region attachment: " + name + ")");
|
||||
attachment.setRegion(region);
|
||||
return attachment;
|
||||
}
|
||||
|
||||
public BoundingBoxAttachment newBoundingBoxAttachment (Skin skin, String name) {
|
||||
return new BoundingBoxAttachment(name);
|
||||
}
|
||||
|
||||
@ -39,6 +39,9 @@ public interface AttachmentLoader {
|
||||
/** @return May be null to not load any attachment. */
|
||||
public RegionAttachment newRegionAttachment (Skin skin, String name, String path);
|
||||
|
||||
/** @return May be null to not load any attachment. */
|
||||
public MeshAttachment newMeshAttachment (Skin skin, String name, String path);
|
||||
|
||||
/** @return May be null to not load any attachment. */
|
||||
public BoundingBoxAttachment newBoundingBoxAttachment (Skin skin, String name);
|
||||
}
|
||||
|
||||
@ -34,5 +34,5 @@
|
||||
package com.esotericsoftware.spine.attachments;
|
||||
|
||||
public enum AttachmentType {
|
||||
region, boundingbox
|
||||
region, boundingbox, mesh
|
||||
}
|
||||
|
||||
@ -0,0 +1,186 @@
|
||||
/******************************************************************************
|
||||
* Spine Runtime Software License - Version 1.1
|
||||
*
|
||||
* Copyright (c) 2013, Esoteric Software
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms in whole or in part, with
|
||||
* or without modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. A Spine Essential, Professional, Enterprise, or Education License must
|
||||
* be purchased from Esoteric Software and the license must remain valid:
|
||||
* http://esotericsoftware.com/
|
||||
* 2. Redistributions of source code must retain this license, which is the
|
||||
* above copyright notice, this declaration of conditions and the following
|
||||
* disclaimer.
|
||||
* 3. Redistributions in binary form must reproduce this license, which is the
|
||||
* above copyright notice, this declaration of conditions and the following
|
||||
* disclaimer, in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
package com.esotericsoftware.spine.attachments;
|
||||
|
||||
import com.esotericsoftware.spine.Bone;
|
||||
import com.esotericsoftware.spine.Skeleton;
|
||||
import com.esotericsoftware.spine.Slot;
|
||||
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||
import com.badlogic.gdx.utils.NumberUtils;
|
||||
|
||||
/** Attachment that displays a texture region. */
|
||||
public class MeshAttachment extends Attachment {
|
||||
private TextureRegion region;
|
||||
private String path;
|
||||
private int hullLength;
|
||||
private float[] vertices;
|
||||
private short[] triangles;
|
||||
private int[] edges;
|
||||
private float[] worldVertices;
|
||||
private final Color color = new Color(1, 1, 1, 1);
|
||||
private float width, height;
|
||||
|
||||
public MeshAttachment (String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public void setRegion (TextureRegion region) {
|
||||
if (region == null) throw new IllegalArgumentException("region cannot be null.");
|
||||
this.region = region;
|
||||
}
|
||||
|
||||
public TextureRegion getRegion () {
|
||||
if (region == null) throw new IllegalStateException("Region has not been set: " + this);
|
||||
return region;
|
||||
}
|
||||
|
||||
public void updateWorldVertices (Slot slot, boolean premultipliedAlpha) {
|
||||
Skeleton skeleton = slot.getSkeleton();
|
||||
Color skeletonColor = skeleton.getColor();
|
||||
Color slotColor = slot.getColor();
|
||||
Color regionColor = color;
|
||||
float r = skeletonColor.r * slotColor.r * regionColor.r;
|
||||
float g = skeletonColor.g * slotColor.g * regionColor.g;
|
||||
float b = skeletonColor.b * slotColor.b * regionColor.b;
|
||||
float a = skeletonColor.a * slotColor.a * regionColor.a * 255;
|
||||
float color;
|
||||
if (premultipliedAlpha) {
|
||||
r *= a;
|
||||
g *= a;
|
||||
b *= a;
|
||||
} else {
|
||||
r *= 255;
|
||||
g *= 255;
|
||||
b *= 255;
|
||||
}
|
||||
color = NumberUtils.intToFloatColor( //
|
||||
((int)(a) << 24) //
|
||||
| ((int)(b) << 16) //
|
||||
| ((int)(g) << 8) //
|
||||
| ((int)(r)));
|
||||
|
||||
float[] worldVertices = this.worldVertices;
|
||||
float[] vertices = this.vertices;
|
||||
Bone bone1 = slot.getBone();
|
||||
float x = skeleton.getX();
|
||||
float y = skeleton.getY();
|
||||
float m00 = bone1.getM00();
|
||||
float m01 = bone1.getM01();
|
||||
float m10 = bone1.getM10();
|
||||
float m11 = bone1.getM11();
|
||||
|
||||
float vx, vy;
|
||||
for (int v = 0, w = 0, n = vertices.length; v < n; v += 2, w += 5) {
|
||||
vx = vertices[v];
|
||||
vy = vertices[v + 1];
|
||||
float wx1 = vx * m00 + vy * m01 + x + bone1.getWorldX();
|
||||
float wy1 = vx * m10 + vy * m11 + y + bone1.getWorldY();
|
||||
worldVertices[w] = wx1;
|
||||
worldVertices[w + 1] = wy1;
|
||||
worldVertices[w + 2] = Color.WHITE.toFloatBits();
|
||||
worldVertices[w + 2] = color;
|
||||
}
|
||||
}
|
||||
|
||||
public float[] getWorldVertices () {
|
||||
return worldVertices;
|
||||
}
|
||||
|
||||
public float[] getVertices () {
|
||||
return vertices;
|
||||
}
|
||||
|
||||
public short[] getTriangles () {
|
||||
return triangles;
|
||||
}
|
||||
|
||||
public Color getColor () {
|
||||
return color;
|
||||
}
|
||||
|
||||
public String getPath () {
|
||||
return path;
|
||||
}
|
||||
|
||||
public void setPath (String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public int getHullLength () {
|
||||
return hullLength;
|
||||
}
|
||||
|
||||
public void setHullLength (int hullLength) {
|
||||
this.hullLength = hullLength;
|
||||
}
|
||||
|
||||
public int[] getEdges () {
|
||||
return edges;
|
||||
}
|
||||
|
||||
public void setEdges (int[] edges) {
|
||||
this.edges = edges;
|
||||
}
|
||||
|
||||
public float getWidth () {
|
||||
return width;
|
||||
}
|
||||
|
||||
public void setWidth (float width) {
|
||||
this.width = width;
|
||||
}
|
||||
|
||||
public float getHeight () {
|
||||
return height;
|
||||
}
|
||||
|
||||
public void setHeight (float height) {
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
public void setMesh (float[] vertices, short[] triangles, float[] uvs) {
|
||||
this.vertices = vertices;
|
||||
this.triangles = triangles;
|
||||
|
||||
int worldVerticesLength = vertices.length / 2 * 5;
|
||||
if (worldVertices == null || worldVertices.length != worldVerticesLength) worldVertices = new float[worldVerticesLength];
|
||||
|
||||
for (int i = 0, w = 3, n = vertices.length; i < n; i += 2, w += 5) {
|
||||
worldVertices[w] = uvs[i];
|
||||
worldVertices[w + 1] = uvs[i + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user