mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-03-26 22:49:01 +08:00
Refactored skeleton renderer, added two color tint polygon renderer.
This commit is contained in:
parent
e595bc6e4b
commit
77099330ad
@ -41,7 +41,7 @@ import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
|||||||
public class SimpleTest3 extends ApplicationAdapter {
|
public class SimpleTest3 extends ApplicationAdapter {
|
||||||
OrthographicCamera camera;
|
OrthographicCamera camera;
|
||||||
PolygonSpriteBatch batch;
|
PolygonSpriteBatch batch;
|
||||||
SkeletonMeshRenderer renderer;
|
SkeletonRenderer renderer;
|
||||||
SkeletonRendererDebug debugRenderer;
|
SkeletonRendererDebug debugRenderer;
|
||||||
|
|
||||||
TextureAtlas atlas;
|
TextureAtlas atlas;
|
||||||
@ -51,7 +51,7 @@ public class SimpleTest3 extends ApplicationAdapter {
|
|||||||
public void create () {
|
public void create () {
|
||||||
camera = new OrthographicCamera();
|
camera = new OrthographicCamera();
|
||||||
batch = new PolygonSpriteBatch(); // Required to render meshes. SpriteBatch can't render meshes.
|
batch = new PolygonSpriteBatch(); // Required to render meshes. SpriteBatch can't render meshes.
|
||||||
renderer = new SkeletonMeshRenderer();
|
renderer = new SkeletonRenderer();
|
||||||
renderer.setPremultipliedAlpha(true);
|
renderer.setPremultipliedAlpha(true);
|
||||||
debugRenderer = new SkeletonRendererDebug();
|
debugRenderer = new SkeletonRendererDebug();
|
||||||
debugRenderer.setMeshTriangles(false);
|
debugRenderer.setMeshTriangles(false);
|
||||||
|
|||||||
@ -42,7 +42,7 @@ import com.esotericsoftware.spine.attachments.SkeletonAttachment;
|
|||||||
public class SkeletonAttachmentTest extends ApplicationAdapter {
|
public class SkeletonAttachmentTest extends ApplicationAdapter {
|
||||||
OrthographicCamera camera;
|
OrthographicCamera camera;
|
||||||
PolygonSpriteBatch batch;
|
PolygonSpriteBatch batch;
|
||||||
SkeletonMeshRenderer renderer;
|
SkeletonRenderer renderer;
|
||||||
|
|
||||||
Skeleton spineboy, goblin;
|
Skeleton spineboy, goblin;
|
||||||
AnimationState spineboyState, goblinState;
|
AnimationState spineboyState, goblinState;
|
||||||
@ -50,7 +50,7 @@ public class SkeletonAttachmentTest extends ApplicationAdapter {
|
|||||||
public void create () {
|
public void create () {
|
||||||
camera = new OrthographicCamera();
|
camera = new OrthographicCamera();
|
||||||
batch = new PolygonSpriteBatch();
|
batch = new PolygonSpriteBatch();
|
||||||
renderer = new SkeletonMeshRenderer();
|
renderer = new SkeletonRenderer();
|
||||||
renderer.setPremultipliedAlpha(true);
|
renderer.setPremultipliedAlpha(true);
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,128 +0,0 @@
|
|||||||
/******************************************************************************
|
|
||||||
* Spine Runtimes Software License v2.5
|
|
||||||
*
|
|
||||||
* Copyright (c) 2013-2016, Esoteric Software
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* You are granted a perpetual, non-exclusive, non-sublicensable, and
|
|
||||||
* non-transferable license to use, install, execute, and perform the Spine
|
|
||||||
* Runtimes software and derivative works solely for personal or internal
|
|
||||||
* use. Without the written permission of Esoteric Software (see Section 2 of
|
|
||||||
* the Spine Software License Agreement), you may not (a) modify, translate,
|
|
||||||
* adapt, or develop new applications using the Spine Runtimes or otherwise
|
|
||||||
* create derivative works or improvements of the Spine Runtimes or (b) remove,
|
|
||||||
* delete, alter, or obscure any trademarks or any copyright, trademark, patent,
|
|
||||||
* or other intellectual property or proprietary rights notices on or in the
|
|
||||||
* Software, including any copy thereof. Redistributions in binary or source
|
|
||||||
* form must include this license and terms.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
|
|
||||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
|
||||||
* EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF
|
|
||||||
* USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
|
||||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
package com.esotericsoftware.spine;
|
|
||||||
|
|
||||||
import com.badlogic.gdx.graphics.Color;
|
|
||||||
import com.badlogic.gdx.graphics.Texture;
|
|
||||||
import com.badlogic.gdx.graphics.g2d.PolygonSpriteBatch;
|
|
||||||
import com.badlogic.gdx.utils.Array;
|
|
||||||
import com.badlogic.gdx.utils.FloatArray;
|
|
||||||
import com.badlogic.gdx.utils.NumberUtils;
|
|
||||||
import com.esotericsoftware.spine.attachments.Attachment;
|
|
||||||
import com.esotericsoftware.spine.attachments.RegionAttachment;
|
|
||||||
import com.esotericsoftware.spine.attachments.SkeletonAttachment;
|
|
||||||
import com.esotericsoftware.spine.attachments.MeshAttachment;
|
|
||||||
|
|
||||||
public class SkeletonMeshRenderer extends SkeletonRenderer<PolygonSpriteBatch> {
|
|
||||||
static private final short[] quadTriangles = {0, 1, 2, 2, 3, 0};
|
|
||||||
|
|
||||||
private final FloatArray vertices = new FloatArray(32);
|
|
||||||
|
|
||||||
@SuppressWarnings("null")
|
|
||||||
public void draw (PolygonSpriteBatch batch, Skeleton skeleton) {
|
|
||||||
boolean premultipliedAlpha = this.premultipliedAlpha;
|
|
||||||
BlendMode blendMode = null;
|
|
||||||
|
|
||||||
int verticesLength = 0;
|
|
||||||
float[] vertices = null, uvs = null;
|
|
||||||
short[] triangles = null;
|
|
||||||
Texture texture = null;
|
|
||||||
Color color = null, skeletonColor = skeleton.color;
|
|
||||||
Array<Slot> drawOrder = skeleton.drawOrder;
|
|
||||||
for (int i = 0, n = drawOrder.size; i < n; i++) {
|
|
||||||
Slot slot = drawOrder.get(i);
|
|
||||||
Attachment attachment = slot.attachment;
|
|
||||||
if (attachment instanceof RegionAttachment) {
|
|
||||||
RegionAttachment region = (RegionAttachment)attachment;
|
|
||||||
verticesLength = 20;
|
|
||||||
vertices = this.vertices.items;
|
|
||||||
region.computeWorldVertices(slot, vertices, 0, 5);
|
|
||||||
triangles = quadTriangles;
|
|
||||||
texture = region.getRegion().getTexture();
|
|
||||||
uvs = region.getUVs();
|
|
||||||
color = region.getColor();
|
|
||||||
|
|
||||||
} else if (attachment instanceof MeshAttachment) {
|
|
||||||
MeshAttachment mesh = (MeshAttachment)attachment;
|
|
||||||
verticesLength = (mesh.getWorldVerticesLength() >> 1) * 5;
|
|
||||||
vertices = this.vertices.setSize(verticesLength);
|
|
||||||
mesh.computeWorldVertices(slot, 0, mesh.getWorldVerticesLength(), vertices, 0, 5);
|
|
||||||
triangles = mesh.getTriangles();
|
|
||||||
texture = mesh.getRegion().getTexture();
|
|
||||||
uvs = mesh.getUVs();
|
|
||||||
color = mesh.getColor();
|
|
||||||
|
|
||||||
} else if (attachment instanceof SkeletonAttachment) {
|
|
||||||
Skeleton attachmentSkeleton = ((SkeletonAttachment)attachment).getSkeleton();
|
|
||||||
if (attachmentSkeleton == null) continue;
|
|
||||||
Bone bone = slot.getBone();
|
|
||||||
Bone rootBone = attachmentSkeleton.getRootBone();
|
|
||||||
float oldScaleX = rootBone.getScaleX();
|
|
||||||
float oldScaleY = rootBone.getScaleY();
|
|
||||||
float oldRotation = rootBone.getRotation();
|
|
||||||
attachmentSkeleton.setPosition(bone.getWorldX(), bone.getWorldY());
|
|
||||||
// rootBone.setScaleX(1 + bone.getWorldScaleX() - oldScaleX);
|
|
||||||
// rootBone.setScaleY(1 + bone.getWorldScaleY() - oldScaleY);
|
|
||||||
// Also set shear.
|
|
||||||
rootBone.setRotation(oldRotation + bone.getWorldRotationX());
|
|
||||||
attachmentSkeleton.updateWorldTransform();
|
|
||||||
|
|
||||||
draw(batch, attachmentSkeleton);
|
|
||||||
|
|
||||||
attachmentSkeleton.setPosition(0, 0);
|
|
||||||
rootBone.setScaleX(oldScaleX);
|
|
||||||
rootBone.setScaleY(oldScaleY);
|
|
||||||
rootBone.setRotation(oldRotation);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (texture != null) {
|
|
||||||
Color slotColor = slot.getColor();
|
|
||||||
float alpha = skeletonColor.a * slotColor.a * color.a * 255;
|
|
||||||
float c = NumberUtils.intToFloatColor(((int)alpha << 24) //
|
|
||||||
| ((int)(skeletonColor.b * slotColor.b * color.b * alpha) << 16) //
|
|
||||||
| ((int)(skeletonColor.g * slotColor.g * color.g * alpha) << 8) //
|
|
||||||
| (int)(skeletonColor.r * slotColor.r * color.r * alpha));
|
|
||||||
for (int v = 2, u = 0; v < verticesLength; v += 5, u += 2) {
|
|
||||||
vertices[v] = c;
|
|
||||||
vertices[v + 1] = uvs[u];
|
|
||||||
vertices[v + 2] = uvs[u + 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
BlendMode slotBlendMode = slot.data.getBlendMode();
|
|
||||||
if (slotBlendMode != blendMode) {
|
|
||||||
blendMode = slotBlendMode;
|
|
||||||
batch.setBlendFunction(blendMode.getSource(premultipliedAlpha), blendMode.getDest());
|
|
||||||
}
|
|
||||||
batch.draw(texture, vertices, 0, vertices.length, triangles, 0, triangles.length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -30,24 +30,32 @@
|
|||||||
|
|
||||||
package com.esotericsoftware.spine;
|
package com.esotericsoftware.spine;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.Gdx;
|
||||||
import com.badlogic.gdx.graphics.Color;
|
import com.badlogic.gdx.graphics.Color;
|
||||||
|
import com.badlogic.gdx.graphics.GL20;
|
||||||
|
import com.badlogic.gdx.graphics.Texture;
|
||||||
import com.badlogic.gdx.graphics.g2d.Batch;
|
import com.badlogic.gdx.graphics.g2d.Batch;
|
||||||
|
import com.badlogic.gdx.graphics.g2d.PolygonSpriteBatch;
|
||||||
import com.badlogic.gdx.utils.Array;
|
import com.badlogic.gdx.utils.Array;
|
||||||
|
import com.badlogic.gdx.utils.FloatArray;
|
||||||
import com.badlogic.gdx.utils.NumberUtils;
|
import com.badlogic.gdx.utils.NumberUtils;
|
||||||
import com.esotericsoftware.spine.attachments.Attachment;
|
import com.esotericsoftware.spine.attachments.Attachment;
|
||||||
import com.esotericsoftware.spine.attachments.MeshAttachment;
|
import com.esotericsoftware.spine.attachments.MeshAttachment;
|
||||||
import com.esotericsoftware.spine.attachments.RegionAttachment;
|
import com.esotericsoftware.spine.attachments.RegionAttachment;
|
||||||
import com.esotericsoftware.spine.attachments.SkeletonAttachment;
|
import com.esotericsoftware.spine.attachments.SkeletonAttachment;
|
||||||
|
import com.esotericsoftware.spine.utils.TwoColorPolygonBatch;
|
||||||
|
|
||||||
public class SkeletonRenderer<T extends Batch> {
|
public class SkeletonRenderer {
|
||||||
boolean premultipliedAlpha;
|
static private final short[] quadTriangles = {0, 1, 2, 2, 3, 0};
|
||||||
private final float[] vertices = new float[20];
|
|
||||||
|
|
||||||
public void draw (T batch, Skeleton skeleton) {
|
private boolean premultipliedAlpha;
|
||||||
|
private final FloatArray vertices = new FloatArray(32);
|
||||||
|
|
||||||
|
public void draw (Batch batch, Skeleton skeleton) {
|
||||||
boolean premultipliedAlpha = this.premultipliedAlpha;
|
boolean premultipliedAlpha = this.premultipliedAlpha;
|
||||||
|
float[] vertices = this.vertices.items;
|
||||||
float[] vertices = this.vertices;
|
|
||||||
Color skeletonColor = skeleton.color;
|
Color skeletonColor = skeleton.color;
|
||||||
|
float r = skeletonColor.r, g = skeletonColor.g, b = skeletonColor.b, a = skeletonColor.a;
|
||||||
Array<Slot> drawOrder = skeleton.drawOrder;
|
Array<Slot> drawOrder = skeleton.drawOrder;
|
||||||
for (int i = 0, n = drawOrder.size; i < n; i++) {
|
for (int i = 0, n = drawOrder.size; i < n; i++) {
|
||||||
Slot slot = drawOrder.get(i);
|
Slot slot = drawOrder.get(i);
|
||||||
@ -56,11 +64,11 @@ public class SkeletonRenderer<T extends Batch> {
|
|||||||
RegionAttachment region = (RegionAttachment)attachment;
|
RegionAttachment region = (RegionAttachment)attachment;
|
||||||
region.computeWorldVertices(slot, vertices, 0, 5);
|
region.computeWorldVertices(slot, vertices, 0, 5);
|
||||||
Color color = region.getColor(), slotColor = slot.getColor();
|
Color color = region.getColor(), slotColor = slot.getColor();
|
||||||
float alpha = skeletonColor.a * slotColor.a * color.a * 255;
|
float alpha = a * slotColor.a * color.a * 255;
|
||||||
float c = NumberUtils.intToFloatColor(((int)alpha << 24) //
|
float c = NumberUtils.intToFloatColor(((int)alpha << 24) //
|
||||||
| ((int)(skeletonColor.b * slotColor.b * color.b * alpha) << 16) //
|
| ((int)(b * slotColor.b * color.b * alpha) << 16) //
|
||||||
| ((int)(skeletonColor.g * slotColor.g * color.g * alpha) << 8) //
|
| ((int)(g * slotColor.g * color.g * alpha) << 8) //
|
||||||
| (int)(skeletonColor.r * slotColor.r * color.r * alpha));
|
| (int)(r * slotColor.r * color.r * alpha));
|
||||||
float[] uvs = region.getUVs();
|
float[] uvs = region.getUVs();
|
||||||
for (int u = 0, v = 2; u < 8; u += 2, v += 5) {
|
for (int u = 0, v = 2; u < 8; u += 2, v += 5) {
|
||||||
vertices[v] = c;
|
vertices[v] = c;
|
||||||
@ -101,6 +109,178 @@ public class SkeletonRenderer<T extends Batch> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("null")
|
||||||
|
public void draw (PolygonSpriteBatch batch, Skeleton skeleton) {
|
||||||
|
boolean premultipliedAlpha = this.premultipliedAlpha;
|
||||||
|
BlendMode blendMode = null;
|
||||||
|
int verticesLength = 0;
|
||||||
|
float[] vertices = null, uvs = null;
|
||||||
|
short[] triangles = null;
|
||||||
|
Texture texture = null;
|
||||||
|
Color color = null, skeletonColor = skeleton.color;
|
||||||
|
float r = skeletonColor.r, g = skeletonColor.g, b = skeletonColor.b, a = skeletonColor.a;
|
||||||
|
Array<Slot> drawOrder = skeleton.drawOrder;
|
||||||
|
for (int i = 0, n = drawOrder.size; i < n; i++) {
|
||||||
|
Slot slot = drawOrder.get(i);
|
||||||
|
Attachment attachment = slot.attachment;
|
||||||
|
if (attachment instanceof RegionAttachment) {
|
||||||
|
RegionAttachment region = (RegionAttachment)attachment;
|
||||||
|
verticesLength = 20;
|
||||||
|
vertices = this.vertices.items;
|
||||||
|
region.computeWorldVertices(slot, vertices, 0, 5);
|
||||||
|
triangles = quadTriangles;
|
||||||
|
texture = region.getRegion().getTexture();
|
||||||
|
uvs = region.getUVs();
|
||||||
|
color = region.getColor();
|
||||||
|
|
||||||
|
} else if (attachment instanceof MeshAttachment) {
|
||||||
|
MeshAttachment mesh = (MeshAttachment)attachment;
|
||||||
|
int count = mesh.getWorldVerticesLength();
|
||||||
|
verticesLength = (count >> 1) * 5;
|
||||||
|
vertices = this.vertices.setSize(verticesLength);
|
||||||
|
mesh.computeWorldVertices(slot, 0, count, vertices, 0, 5);
|
||||||
|
triangles = mesh.getTriangles();
|
||||||
|
texture = mesh.getRegion().getTexture();
|
||||||
|
uvs = mesh.getUVs();
|
||||||
|
color = mesh.getColor();
|
||||||
|
|
||||||
|
} else if (attachment instanceof SkeletonAttachment) {
|
||||||
|
Skeleton attachmentSkeleton = ((SkeletonAttachment)attachment).getSkeleton();
|
||||||
|
if (attachmentSkeleton == null) continue;
|
||||||
|
Bone bone = slot.getBone();
|
||||||
|
Bone rootBone = attachmentSkeleton.getRootBone();
|
||||||
|
float oldScaleX = rootBone.getScaleX();
|
||||||
|
float oldScaleY = rootBone.getScaleY();
|
||||||
|
float oldRotation = rootBone.getRotation();
|
||||||
|
attachmentSkeleton.setPosition(bone.getWorldX(), bone.getWorldY());
|
||||||
|
// rootBone.setScaleX(1 + bone.getWorldScaleX() - oldScaleX);
|
||||||
|
// rootBone.setScaleY(1 + bone.getWorldScaleY() - oldScaleY);
|
||||||
|
// Also set shear.
|
||||||
|
rootBone.setRotation(oldRotation + bone.getWorldRotationX());
|
||||||
|
attachmentSkeleton.updateWorldTransform();
|
||||||
|
|
||||||
|
draw(batch, attachmentSkeleton);
|
||||||
|
|
||||||
|
attachmentSkeleton.setPosition(0, 0);
|
||||||
|
rootBone.setScaleX(oldScaleX);
|
||||||
|
rootBone.setScaleY(oldScaleY);
|
||||||
|
rootBone.setRotation(oldRotation);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (texture != null) {
|
||||||
|
Color slotColor = slot.getColor();
|
||||||
|
float alpha = a * slotColor.a * color.a * 255;
|
||||||
|
float c = NumberUtils.intToFloatColor(((int)alpha << 24) //
|
||||||
|
| ((int)(b * slotColor.b * color.b * alpha) << 16) //
|
||||||
|
| ((int)(g * slotColor.g * color.g * alpha) << 8) //
|
||||||
|
| (int)(r * slotColor.r * color.r * alpha));
|
||||||
|
for (int v = 2, u = 0; v < verticesLength; v += 5, u += 2) {
|
||||||
|
vertices[v] = c;
|
||||||
|
vertices[v + 1] = uvs[u];
|
||||||
|
vertices[v + 2] = uvs[u + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
BlendMode slotBlendMode = slot.data.getBlendMode();
|
||||||
|
if (slotBlendMode != blendMode) {
|
||||||
|
blendMode = slotBlendMode;
|
||||||
|
batch.setBlendFunction(blendMode.getSource(premultipliedAlpha), blendMode.getDest());
|
||||||
|
}
|
||||||
|
batch.draw(texture, vertices, 0, verticesLength, triangles, 0, triangles.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("null")
|
||||||
|
public void draw (TwoColorPolygonBatch batch, Skeleton skeleton) {
|
||||||
|
boolean premultipliedAlpha = this.premultipliedAlpha;
|
||||||
|
BlendMode blendMode = null;
|
||||||
|
int verticesLength = 0;
|
||||||
|
float[] vertices = null, uvs = null;
|
||||||
|
short[] triangles = null;
|
||||||
|
Texture texture = null;
|
||||||
|
Color color = null, skeletonColor = skeleton.color;
|
||||||
|
float r = skeletonColor.r, g = skeletonColor.g, b = skeletonColor.b, a = skeletonColor.a;
|
||||||
|
Array<Slot> drawOrder = skeleton.drawOrder;
|
||||||
|
for (int i = 0, n = drawOrder.size; i < n; i++) {
|
||||||
|
Slot slot = drawOrder.get(i);
|
||||||
|
Attachment attachment = slot.attachment;
|
||||||
|
if (attachment instanceof RegionAttachment) {
|
||||||
|
RegionAttachment region = (RegionAttachment)attachment;
|
||||||
|
verticesLength = 24;
|
||||||
|
vertices = this.vertices.items;
|
||||||
|
region.computeWorldVertices(slot, vertices, 0, 6);
|
||||||
|
triangles = quadTriangles;
|
||||||
|
texture = region.getRegion().getTexture();
|
||||||
|
uvs = region.getUVs();
|
||||||
|
color = region.getColor();
|
||||||
|
|
||||||
|
} else if (attachment instanceof MeshAttachment) {
|
||||||
|
MeshAttachment mesh = (MeshAttachment)attachment;
|
||||||
|
int count = mesh.getWorldVerticesLength();
|
||||||
|
verticesLength = count * 3;
|
||||||
|
vertices = this.vertices.setSize(verticesLength);
|
||||||
|
mesh.computeWorldVertices(slot, 0, count, vertices, 0, 6);
|
||||||
|
triangles = mesh.getTriangles();
|
||||||
|
texture = mesh.getRegion().getTexture();
|
||||||
|
uvs = mesh.getUVs();
|
||||||
|
color = mesh.getColor();
|
||||||
|
|
||||||
|
} else if (attachment instanceof SkeletonAttachment) {
|
||||||
|
Skeleton attachmentSkeleton = ((SkeletonAttachment)attachment).getSkeleton();
|
||||||
|
if (attachmentSkeleton == null) continue;
|
||||||
|
Bone bone = slot.getBone();
|
||||||
|
Bone rootBone = attachmentSkeleton.getRootBone();
|
||||||
|
float oldScaleX = rootBone.getScaleX();
|
||||||
|
float oldScaleY = rootBone.getScaleY();
|
||||||
|
float oldRotation = rootBone.getRotation();
|
||||||
|
attachmentSkeleton.setPosition(bone.getWorldX(), bone.getWorldY());
|
||||||
|
// rootBone.setScaleX(1 + bone.getWorldScaleX() - oldScaleX);
|
||||||
|
// rootBone.setScaleY(1 + bone.getWorldScaleY() - oldScaleY);
|
||||||
|
// Also set shear.
|
||||||
|
rootBone.setRotation(oldRotation + bone.getWorldRotationX());
|
||||||
|
attachmentSkeleton.updateWorldTransform();
|
||||||
|
|
||||||
|
draw(batch, attachmentSkeleton);
|
||||||
|
|
||||||
|
attachmentSkeleton.setPosition(0, 0);
|
||||||
|
rootBone.setScaleX(oldScaleX);
|
||||||
|
rootBone.setScaleY(oldScaleY);
|
||||||
|
rootBone.setRotation(oldRotation);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (texture != null) {
|
||||||
|
Color lightColor = slot.getColor();
|
||||||
|
float alpha = a * lightColor.a * color.a * 255;
|
||||||
|
float light = NumberUtils.intToFloatColor(((int)alpha << 24) //
|
||||||
|
| ((int)(b * lightColor.b * color.b * alpha) << 16) //
|
||||||
|
| ((int)(g * lightColor.g * color.g * alpha) << 8) //
|
||||||
|
| (int)(r * lightColor.r * color.r * alpha));
|
||||||
|
Color darkColor = slot.getDarkColor();
|
||||||
|
if (darkColor == null) darkColor = Color.BLACK;
|
||||||
|
float dark = NumberUtils.intToFloatColor( //
|
||||||
|
((int)(b * darkColor.b * color.b * 255) << 16) //
|
||||||
|
| ((int)(g * darkColor.g * color.g * 255) << 8) //
|
||||||
|
| (int)(r * darkColor.r * color.r * 255));
|
||||||
|
for (int v = 2, u = 0; v < verticesLength; v += 6, u += 2) {
|
||||||
|
vertices[v] = light;
|
||||||
|
vertices[v + 1] = dark;
|
||||||
|
vertices[v + 2] = uvs[u];
|
||||||
|
vertices[v + 3] = uvs[u + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
BlendMode slotBlendMode = slot.data.getBlendMode();
|
||||||
|
if (slotBlendMode != blendMode) {
|
||||||
|
blendMode = slotBlendMode;
|
||||||
|
Gdx.gl.glEnable(GL20.GL_BLEND);
|
||||||
|
Gdx.gl.glBlendFunc(blendMode.getSource(premultipliedAlpha), blendMode.getDest());
|
||||||
|
}
|
||||||
|
batch.draw(texture, vertices, 0, verticesLength, triangles, 0, triangles.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void setPremultipliedAlpha (boolean premultipliedAlpha) {
|
public void setPremultipliedAlpha (boolean premultipliedAlpha) {
|
||||||
this.premultipliedAlpha = premultipliedAlpha;
|
this.premultipliedAlpha = premultipliedAlpha;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,220 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* Spine Runtimes Software License v2.5
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013-2016, Esoteric Software
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* You are granted a perpetual, non-exclusive, non-sublicensable, and
|
||||||
|
* non-transferable license to use, install, execute, and perform the Spine
|
||||||
|
* Runtimes software and derivative works solely for personal or internal
|
||||||
|
* use. Without the written permission of Esoteric Software (see Section 2 of
|
||||||
|
* the Spine Software License Agreement), you may not (a) modify, translate,
|
||||||
|
* adapt, or develop new applications using the Spine Runtimes or otherwise
|
||||||
|
* create derivative works or improvements of the Spine Runtimes or (b) remove,
|
||||||
|
* delete, alter, or obscure any trademarks or any copyright, trademark, patent,
|
||||||
|
* or other intellectual property or proprietary rights notices on or in the
|
||||||
|
* Software, including any copy thereof. Redistributions in binary or source
|
||||||
|
* form must include this license and terms.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||||
|
* EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF
|
||||||
|
* USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||||
|
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
package com.esotericsoftware.spine.utils;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.Gdx;
|
||||||
|
import com.badlogic.gdx.graphics.GL20;
|
||||||
|
import com.badlogic.gdx.graphics.Mesh;
|
||||||
|
import com.badlogic.gdx.graphics.Mesh.VertexDataType;
|
||||||
|
import com.badlogic.gdx.graphics.Texture;
|
||||||
|
import com.badlogic.gdx.graphics.VertexAttribute;
|
||||||
|
import com.badlogic.gdx.graphics.VertexAttributes.Usage;
|
||||||
|
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
|
||||||
|
import com.badlogic.gdx.math.Matrix4;
|
||||||
|
|
||||||
|
public class TwoColorPolygonBatch {
|
||||||
|
private final Mesh mesh;
|
||||||
|
private final float[] vertices;
|
||||||
|
private final short[] triangles;
|
||||||
|
private final Matrix4 transformMatrix = new Matrix4();
|
||||||
|
private final Matrix4 projectionMatrix = new Matrix4();
|
||||||
|
private final Matrix4 combinedMatrix = new Matrix4();
|
||||||
|
private final ShaderProgram defaultShader;
|
||||||
|
private ShaderProgram shader;
|
||||||
|
private int vertexIndex, triangleIndex;
|
||||||
|
private Texture lastTexture;
|
||||||
|
private boolean drawing;
|
||||||
|
|
||||||
|
public TwoColorPolygonBatch (int size) {
|
||||||
|
this(size, size * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TwoColorPolygonBatch (int maxVertices, int maxTriangles) {
|
||||||
|
// 32767 is max vertex index.
|
||||||
|
if (maxVertices > 32767)
|
||||||
|
throw new IllegalArgumentException("Can't have more than 32767 vertices per batch: " + maxTriangles);
|
||||||
|
|
||||||
|
Mesh.VertexDataType vertexDataType = Mesh.VertexDataType.VertexArray;
|
||||||
|
if (Gdx.gl30 != null) vertexDataType = VertexDataType.VertexBufferObjectWithVAO;
|
||||||
|
mesh = new Mesh(vertexDataType, false, maxVertices, maxTriangles * 3, //
|
||||||
|
new VertexAttribute(Usage.Position, 2, "a_position"), //
|
||||||
|
new VertexAttribute(Usage.ColorPacked, 4, "a_light"), //
|
||||||
|
new VertexAttribute(Usage.ColorPacked, 3, "a_dark"), //
|
||||||
|
new VertexAttribute(Usage.TextureCoordinates, 2, "a_texCoord0"));
|
||||||
|
|
||||||
|
vertices = new float[maxVertices * 6];
|
||||||
|
triangles = new short[maxTriangles * 3];
|
||||||
|
defaultShader = createDefaultShader();
|
||||||
|
shader = defaultShader;
|
||||||
|
projectionMatrix.setToOrtho2D(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void begin () {
|
||||||
|
if (drawing) throw new IllegalStateException("end must be called before begin.");
|
||||||
|
Gdx.gl.glDepthMask(false);
|
||||||
|
shader.begin();
|
||||||
|
setupMatrices();
|
||||||
|
drawing = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void end () {
|
||||||
|
if (!drawing) throw new IllegalStateException("begin must be called before end.");
|
||||||
|
if (vertexIndex > 0) flush();
|
||||||
|
shader.end();
|
||||||
|
Gdx.gl.glDepthMask(true);
|
||||||
|
Gdx.gl.glDisable(GL20.GL_BLEND);
|
||||||
|
lastTexture = null;
|
||||||
|
drawing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void draw (Texture texture, float[] polygonVertices, int verticesOffset, int verticesCount, short[] polygonTriangles,
|
||||||
|
int trianglesOffset, int trianglesCount) {
|
||||||
|
if (!drawing) throw new IllegalStateException("begin must be called before draw.");
|
||||||
|
|
||||||
|
final short[] triangles = this.triangles;
|
||||||
|
final float[] vertices = this.vertices;
|
||||||
|
|
||||||
|
if (texture != lastTexture) {
|
||||||
|
flush();
|
||||||
|
lastTexture = texture;
|
||||||
|
} else if (triangleIndex + trianglesCount > triangles.length || vertexIndex + verticesCount > vertices.length) //
|
||||||
|
flush();
|
||||||
|
|
||||||
|
int triangleIndex = this.triangleIndex;
|
||||||
|
final int vertexIndex = this.vertexIndex;
|
||||||
|
final int startVertex = vertexIndex / 6;
|
||||||
|
|
||||||
|
for (int i = trianglesOffset, n = i + trianglesCount; i < n; i++)
|
||||||
|
triangles[triangleIndex++] = (short)(polygonTriangles[i] + startVertex);
|
||||||
|
this.triangleIndex = triangleIndex;
|
||||||
|
|
||||||
|
System.arraycopy(polygonVertices, verticesOffset, vertices, vertexIndex, verticesCount);
|
||||||
|
this.vertexIndex += verticesCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void flush () {
|
||||||
|
if (vertexIndex == 0) return;
|
||||||
|
|
||||||
|
lastTexture.bind();
|
||||||
|
Mesh mesh = this.mesh;
|
||||||
|
mesh.setVertices(vertices, 0, vertexIndex);
|
||||||
|
mesh.setIndices(triangles, 0, triangleIndex);
|
||||||
|
Gdx.gl.glEnable(GL20.GL_BLEND);
|
||||||
|
|
||||||
|
mesh.render(shader, GL20.GL_TRIANGLES, 0, triangleIndex);
|
||||||
|
|
||||||
|
vertexIndex = 0;
|
||||||
|
triangleIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dispose () {
|
||||||
|
mesh.dispose();
|
||||||
|
shader.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Matrix4 getProjectionMatrix () {
|
||||||
|
return projectionMatrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Matrix4 getTransformMatrix () {
|
||||||
|
return transformMatrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProjectionMatrix (Matrix4 projection) {
|
||||||
|
if (drawing) flush();
|
||||||
|
projectionMatrix.set(projection);
|
||||||
|
if (drawing) setupMatrices();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTransformMatrix (Matrix4 transform) {
|
||||||
|
if (drawing) flush();
|
||||||
|
transformMatrix.set(transform);
|
||||||
|
if (drawing) setupMatrices();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupMatrices () {
|
||||||
|
combinedMatrix.set(projectionMatrix).mul(transformMatrix);
|
||||||
|
shader.setUniformMatrix("u_projTrans", combinedMatrix);
|
||||||
|
shader.setUniformi("u_texture", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setShader (ShaderProgram newShader) {
|
||||||
|
if (drawing) {
|
||||||
|
flush();
|
||||||
|
shader.end();
|
||||||
|
}
|
||||||
|
shader = newShader == null ? defaultShader : newShader;
|
||||||
|
if (drawing) {
|
||||||
|
shader.begin();
|
||||||
|
setupMatrices();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ShaderProgram createDefaultShader () {
|
||||||
|
String vertexShader = "attribute vec4 a_position;\n" //
|
||||||
|
+ "attribute vec4 a_light;\n" //
|
||||||
|
+ "attribute vec4 a_dark;\n" //
|
||||||
|
+ "attribute vec2 a_texCoord0;\n" //
|
||||||
|
+ "uniform mat4 u_projTrans;\n" //
|
||||||
|
+ "varying vec4 v_light;\n" //
|
||||||
|
+ "varying vec4 v_dark;\n" //
|
||||||
|
+ "varying vec2 v_texCoords;\n" //
|
||||||
|
+ "\n" //
|
||||||
|
+ "void main()\n" //
|
||||||
|
+ "{\n" //
|
||||||
|
+ " v_light = a_light;\n" //
|
||||||
|
+ " v_light.a = v_light.a * (255.0/254.0);\n" //
|
||||||
|
+ " v_dark = a_dark;\n" //
|
||||||
|
+ " v_texCoords = a_texCoord0;\n" //
|
||||||
|
+ " gl_Position = u_projTrans * a_position;\n" //
|
||||||
|
+ "}\n";
|
||||||
|
String fragmentShader = "#ifdef GL_ES\n" //
|
||||||
|
+ "#define LOWP lowp\n" //
|
||||||
|
+ "precision mediump float;\n" //
|
||||||
|
+ "#else\n" //
|
||||||
|
+ "#define LOWP \n" //
|
||||||
|
+ "#endif\n" //
|
||||||
|
+ "varying LOWP vec4 v_light;\n" //
|
||||||
|
+ "varying LOWP vec4 v_dark;\n" //
|
||||||
|
+ "varying vec2 v_texCoords;\n" //
|
||||||
|
+ "uniform sampler2D u_texture;\n" //
|
||||||
|
+ "void main()\n"//
|
||||||
|
+ "{\n" //
|
||||||
|
+ " vec4 texColor = texture2D(u_texture, v_texCoords);\n" //
|
||||||
|
+ " gl_FragColor.a = texColor.a * v_light.a;\n" //
|
||||||
|
+ " gl_FragColor.rgb = (1 - texColor.rgb) * v_dark * gl_FragColor.a + texColor.rgb * v_light.rgb;\n" //
|
||||||
|
+ "}";
|
||||||
|
|
||||||
|
ShaderProgram shader = new ShaderProgram(vertexShader, fragmentShader);
|
||||||
|
if (shader.isCompiled() == false) throw new IllegalArgumentException("Error compiling shader: " + shader.getLog());
|
||||||
|
return shader;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -51,7 +51,6 @@ import com.badlogic.gdx.graphics.Pixmap;
|
|||||||
import com.badlogic.gdx.graphics.Pixmap.Format;
|
import com.badlogic.gdx.graphics.Pixmap.Format;
|
||||||
import com.badlogic.gdx.graphics.Texture;
|
import com.badlogic.gdx.graphics.Texture;
|
||||||
import com.badlogic.gdx.graphics.Texture.TextureFilter;
|
import com.badlogic.gdx.graphics.Texture.TextureFilter;
|
||||||
import com.badlogic.gdx.graphics.g2d.PolygonSpriteBatch;
|
|
||||||
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
||||||
import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion;
|
import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion;
|
||||||
import com.badlogic.gdx.graphics.g2d.TextureAtlas.TextureAtlasData;
|
import com.badlogic.gdx.graphics.g2d.TextureAtlas.TextureAtlasData;
|
||||||
@ -81,6 +80,7 @@ import com.badlogic.gdx.utils.StringBuilder;
|
|||||||
import com.badlogic.gdx.utils.viewport.ScreenViewport;
|
import com.badlogic.gdx.utils.viewport.ScreenViewport;
|
||||||
import com.esotericsoftware.spine.AnimationState.AnimationStateAdapter;
|
import com.esotericsoftware.spine.AnimationState.AnimationStateAdapter;
|
||||||
import com.esotericsoftware.spine.AnimationState.TrackEntry;
|
import com.esotericsoftware.spine.AnimationState.TrackEntry;
|
||||||
|
import com.esotericsoftware.spine.utils.TwoColorPolygonBatch;
|
||||||
|
|
||||||
public class SkeletonViewer extends ApplicationAdapter {
|
public class SkeletonViewer extends ApplicationAdapter {
|
||||||
static final float checkModifiedInterval = 0.250f;
|
static final float checkModifiedInterval = 0.250f;
|
||||||
@ -88,8 +88,8 @@ public class SkeletonViewer extends ApplicationAdapter {
|
|||||||
|
|
||||||
UI ui;
|
UI ui;
|
||||||
|
|
||||||
PolygonSpriteBatch batch;
|
TwoColorPolygonBatch batch;
|
||||||
SkeletonMeshRenderer renderer;
|
SkeletonRenderer renderer;
|
||||||
SkeletonRendererDebug debugRenderer;
|
SkeletonRendererDebug debugRenderer;
|
||||||
SkeletonData skeletonData;
|
SkeletonData skeletonData;
|
||||||
Skeleton skeleton;
|
Skeleton skeleton;
|
||||||
@ -111,8 +111,8 @@ public class SkeletonViewer extends ApplicationAdapter {
|
|||||||
|
|
||||||
prefs = Gdx.app.getPreferences("spine-skeletonviewer");
|
prefs = Gdx.app.getPreferences("spine-skeletonviewer");
|
||||||
ui = new UI();
|
ui = new UI();
|
||||||
batch = new PolygonSpriteBatch();
|
batch = new TwoColorPolygonBatch(3100);
|
||||||
renderer = new SkeletonMeshRenderer();
|
renderer = new SkeletonRenderer();
|
||||||
debugRenderer = new SkeletonRendererDebug();
|
debugRenderer = new SkeletonRendererDebug();
|
||||||
skeletonX = (int)(ui.window.getWidth() + (Gdx.graphics.getWidth() - ui.window.getWidth()) / 2);
|
skeletonX = (int)(ui.window.getWidth() + (Gdx.graphics.getWidth() - ui.window.getWidth()) / 2);
|
||||||
skeletonY = Gdx.graphics.getHeight() / 4;
|
skeletonY = Gdx.graphics.getHeight() / 4;
|
||||||
@ -278,7 +278,6 @@ public class SkeletonViewer extends ApplicationAdapter {
|
|||||||
state.apply(skeleton);
|
state.apply(skeleton);
|
||||||
skeleton.updateWorldTransform();
|
skeleton.updateWorldTransform();
|
||||||
|
|
||||||
batch.setColor(Color.WHITE);
|
|
||||||
batch.begin();
|
batch.begin();
|
||||||
renderer.draw(batch, skeleton);
|
renderer.draw(batch, skeleton);
|
||||||
batch.end();
|
batch.end();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user