mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-03-01 13:19:08 +08:00
Bit of reorganization.
It's pretty now!
This commit is contained in:
parent
8d9d46ca56
commit
ff98e136a1
@ -1,178 +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.ApplicationAdapter;
|
|
||||||
import com.badlogic.gdx.Gdx;
|
|
||||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
|
|
||||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
|
|
||||||
import com.badlogic.gdx.graphics.GL20;
|
|
||||||
import com.badlogic.gdx.graphics.OrthographicCamera;
|
|
||||||
import com.badlogic.gdx.graphics.g2d.BitmapFont;
|
|
||||||
import com.badlogic.gdx.graphics.g2d.PolygonSpriteBatch;
|
|
||||||
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
|
||||||
import com.badlogic.gdx.math.WindowedMean;
|
|
||||||
import com.esotericsoftware.spine.attachments.ClippingAttachment;
|
|
||||||
|
|
||||||
public class ClippingTest extends ApplicationAdapter {
|
|
||||||
OrthographicCamera camera;
|
|
||||||
PolygonSpriteBatch batch;
|
|
||||||
SkeletonRenderer renderer;
|
|
||||||
SkeletonRendererDebug debugRenderer;
|
|
||||||
BitmapFont font;
|
|
||||||
|
|
||||||
TextureAtlas atlas;
|
|
||||||
Skeleton skeleton;
|
|
||||||
AnimationState state;
|
|
||||||
|
|
||||||
WindowedMean mean = new WindowedMean(30);
|
|
||||||
|
|
||||||
public void create () {
|
|
||||||
camera = new OrthographicCamera();
|
|
||||||
batch = new PolygonSpriteBatch(2048);
|
|
||||||
renderer = new SkeletonRenderer();
|
|
||||||
renderer.setPremultipliedAlpha(true);
|
|
||||||
debugRenderer = new SkeletonRendererDebug();
|
|
||||||
debugRenderer.setBoundingBoxes(false);
|
|
||||||
debugRenderer.setRegionAttachments(false);
|
|
||||||
font = new BitmapFont();
|
|
||||||
|
|
||||||
atlas = new TextureAtlas(Gdx.files.internal("raptor/raptor-pma.atlas"));
|
|
||||||
SkeletonJson json = new SkeletonJson(atlas);
|
|
||||||
json.setScale(0.6f);
|
|
||||||
SkeletonData skeletonData = json.readSkeletonData(Gdx.files.internal("raptor/raptor.json"));
|
|
||||||
|
|
||||||
skeleton = new Skeleton(skeletonData);
|
|
||||||
skeleton.setPosition(250, 20);
|
|
||||||
|
|
||||||
AnimationStateData stateData = new AnimationStateData(skeletonData);
|
|
||||||
// stateData.setMix("run", "jump", 0.2f);
|
|
||||||
// stateData.setMix("jump", "run", 0.2f);
|
|
||||||
|
|
||||||
state = new AnimationState(stateData);
|
|
||||||
state.setTimeScale(0.5f);
|
|
||||||
|
|
||||||
state.setAnimation(0, "walk", true);
|
|
||||||
state.addAnimation(0, "Jump", false, 2);
|
|
||||||
state.addAnimation(0, "walk", true, 0);
|
|
||||||
|
|
||||||
// Create a clipping attachment, slot data, and slot.
|
|
||||||
ClippingAttachment clip = new ClippingAttachment("clip");
|
|
||||||
|
|
||||||
// Spiral.
|
|
||||||
clip.setVertices(new float[] {430.90802f, 278.212f, 72.164f, 361.816f, 31.143997f, 128.804f, 191.896f, 61.0f, 291.312f,
|
|
||||||
175.73201f, 143.956f, 207.408f, 161.4f, 145.628f, 227.456f, 160.61601f, 224.392f, 126.535995f, 188.264f, 113.144f,
|
|
||||||
147.13199f, 108.87601f, 77.035995f, 158.212f, 86.15199f, 220.676f, 102.77199f, 240.716f, 174.74399f, 243.20801f,
|
|
||||||
250.572f, 216.74802f, 324.772f, 200.33202f, 309.388f, 124.968f, 258.168f, 60.503998f, 199.696f, 42.872f, 116.951996f,
|
|
||||||
6.7400017f, 11.332001f, 72.48f, -6.708008f, 143.136f, 1.0679932f, 239.92801f, 26.5f, 355.6f, -47.380005f, 377.52798f,
|
|
||||||
-40.608f, 303.1f, -53.584015f, 77.316f, 5.4600067f, 8.728001f, 113.343994f, -56.04f, 192.42801f, -45.112f, 274.564f,
|
|
||||||
-38.784f, 322.592f, -10.604f, 371.98f, 21.920002f, 405.16f, 60.896004f, 428.68f, 104.852005f, 406.996f, 188.976f,
|
|
||||||
364.58398f, 220.14401f, 309.3f, 238.788f, 263.232f, 244.75201f, 219.468f, 271.58002f, 210.824f, 294.176f, 250.664f,
|
|
||||||
295.2f, 295.972f, 276.02f, 357.46f, 269.172f, 420.008f, 242.37201f, 466.63602f, 207.648f, 437.516f, -10.579998f,
|
|
||||||
378.05603f, -64.624f, 465.24f, -104.992f, 554.11206f, 95.43199f, 514.89197f, 259.02f});
|
|
||||||
|
|
||||||
// Polygon:
|
|
||||||
// clip.setVertices(
|
|
||||||
// new float[] { 94.0f, 84.0f, 45.0f, 165.0f, 218.0f, 292.0f, 476.0f, 227.0f, 480.0f, 125.0f, 325.0f, 191.0f, 333.0f, 77.0f,
|
|
||||||
// 302.0f, 30.0f, 175.0f, 140.0f });
|
|
||||||
|
|
||||||
// Rectangle:
|
|
||||||
// new float[] { //
|
|
||||||
// -140, 50, //
|
|
||||||
// 250, 50, //
|
|
||||||
// 250, 350, //
|
|
||||||
// -140, 350, //
|
|
||||||
// });
|
|
||||||
|
|
||||||
// Self intersection:
|
|
||||||
// clip.setVertices(new float[] { //
|
|
||||||
// -140, -50, //
|
|
||||||
// 120, 50, //
|
|
||||||
// 120, -50, //
|
|
||||||
// -140, 50, //
|
|
||||||
// });
|
|
||||||
|
|
||||||
for (int j = 0; j < clip.getVertices().length; j += 2) {
|
|
||||||
clip.getVertices()[j] = (clip.getVertices()[j] - 150f);
|
|
||||||
clip.getVertices()[j + 1] = (clip.getVertices()[j + 1] + 100);
|
|
||||||
}
|
|
||||||
clip.setWorldVerticesLength(clip.getVertices().length);
|
|
||||||
clip.setEndSlot(skeleton.findSlot("front_hand").data.index);
|
|
||||||
|
|
||||||
SlotData clipSlotData = new SlotData(skeletonData.getSlots().size, "clip slot", skeletonData.getBones().first());
|
|
||||||
skeletonData.getSlots().add(clipSlotData);
|
|
||||||
|
|
||||||
Slot clipSlot = new Slot(clipSlotData, skeleton.getRootBone());
|
|
||||||
clipSlot.setAttachment(clip);
|
|
||||||
skeleton.getSlots().add(clipSlot);
|
|
||||||
skeleton.getDrawOrder().insert(skeletonData.findSlot("back_hand").getIndex(), clipSlot);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void render () {
|
|
||||||
state.update(Gdx.graphics.getDeltaTime() * 0.3f);
|
|
||||||
state.update(0);
|
|
||||||
|
|
||||||
Gdx.gl.glClearColor(0.3f, 0.3f, 0.3f, 1);
|
|
||||||
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
|
|
||||||
|
|
||||||
state.apply(skeleton);
|
|
||||||
skeleton.updateWorldTransform();
|
|
||||||
|
|
||||||
camera.update();
|
|
||||||
batch.getProjectionMatrix().set(camera.combined);
|
|
||||||
debugRenderer.getShapeRenderer().setProjectionMatrix(camera.combined);
|
|
||||||
|
|
||||||
batch.begin();
|
|
||||||
long start = System.nanoTime();
|
|
||||||
renderer.draw(batch, skeleton);
|
|
||||||
mean.addValue((System.nanoTime() - start) / 1000000.0f);
|
|
||||||
renderer.setPremultipliedAlpha(false);
|
|
||||||
font.draw(batch, "Time: " + mean.getMean() + "ms", 10, Gdx.graphics.getHeight() - font.getLineHeight());
|
|
||||||
batch.end();
|
|
||||||
|
|
||||||
debugRenderer.draw(skeleton);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void resize (int width, int height) {
|
|
||||||
camera.setToOrtho(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void dispose () {
|
|
||||||
atlas.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main (String[] args) throws Exception {
|
|
||||||
LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
|
|
||||||
config.width = 800;
|
|
||||||
config.height = 600;
|
|
||||||
new LwjglApplication(new ClippingTest(), config);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,274 +0,0 @@
|
|||||||
|
|
||||||
package com.esotericsoftware.spine;
|
|
||||||
|
|
||||||
import com.badlogic.gdx.ApplicationAdapter;
|
|
||||||
import com.badlogic.gdx.Gdx;
|
|
||||||
import com.badlogic.gdx.Input.Buttons;
|
|
||||||
import com.badlogic.gdx.Input.Keys;
|
|
||||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
|
|
||||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
|
|
||||||
import com.badlogic.gdx.graphics.Color;
|
|
||||||
import com.badlogic.gdx.graphics.GL20;
|
|
||||||
import com.badlogic.gdx.graphics.OrthographicCamera;
|
|
||||||
import com.badlogic.gdx.graphics.Texture;
|
|
||||||
import com.badlogic.gdx.graphics.g2d.BitmapFont;
|
|
||||||
import com.badlogic.gdx.graphics.g2d.PolygonSpriteBatch;
|
|
||||||
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
|
|
||||||
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
|
|
||||||
import com.badlogic.gdx.math.Intersector;
|
|
||||||
import com.badlogic.gdx.math.MathUtils;
|
|
||||||
import com.badlogic.gdx.math.Vector2;
|
|
||||||
import com.badlogic.gdx.math.Vector3;
|
|
||||||
import com.badlogic.gdx.utils.Array;
|
|
||||||
import com.badlogic.gdx.utils.FloatArray;
|
|
||||||
import com.esotericsoftware.spine.utils.Clipper;
|
|
||||||
import com.esotericsoftware.spine.utils.ConvexDecomposer;
|
|
||||||
|
|
||||||
public class ConvexDecomposerTest extends ApplicationAdapter {
|
|
||||||
OrthographicCamera sceneCamera;
|
|
||||||
ShapeRenderer shapes;
|
|
||||||
PolygonSpriteBatch polyBatcher;
|
|
||||||
Texture image;
|
|
||||||
ConvexDecomposer decomposer = new ConvexDecomposer();
|
|
||||||
FloatArray polygon = new FloatArray();
|
|
||||||
Array<FloatArray> convexPolygons = new Array<FloatArray>();
|
|
||||||
boolean isCreatingPolygon = false;
|
|
||||||
Vector3 tmp = new Vector3();
|
|
||||||
Array<Color> colors = new Array<Color>();
|
|
||||||
BitmapFont font;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void create () {
|
|
||||||
sceneCamera = new OrthographicCamera();
|
|
||||||
shapes = new ShapeRenderer();
|
|
||||||
polyBatcher = new PolygonSpriteBatch();
|
|
||||||
image = new Texture("skin/skin.png");
|
|
||||||
font = new BitmapFont();
|
|
||||||
|
|
||||||
float[] v = new float[] {430.90802f, 278.212f, 72.164f, 361.816f, 31.143997f, 128.804f, 191.896f, 61.0f, 291.312f,
|
|
||||||
175.73201f, 143.956f, 207.408f, 161.4f, 145.628f, 227.456f, 160.61601f, 224.392f, 126.535995f, 188.264f, 113.144f,
|
|
||||||
147.13199f, 108.87601f, 77.035995f, 158.212f, 86.15199f, 220.676f, 102.77199f, 240.716f, 174.74399f, 243.20801f,
|
|
||||||
250.572f, 216.74802f, 324.772f, 200.33202f, 309.388f, 124.968f, 258.168f, 60.503998f, 199.696f, 42.872f, 116.951996f,
|
|
||||||
6.7400017f, 11.332001f, 72.48f, -6.708008f, 143.136f, 1.0679932f, 239.92801f, 26.5f, 355.6f, -47.380005f, 377.52798f,
|
|
||||||
-40.608f, 303.1f, -53.584015f, 77.316f, 5.4600067f, 8.728001f, 113.343994f, -56.04f, 192.42801f, -45.112f, 274.564f,
|
|
||||||
-38.784f, 322.592f, -10.604f, 371.98f, 21.920002f, 405.16f, 60.896004f, 428.68f, 104.852005f, 406.996f, 188.976f,
|
|
||||||
364.58398f, 220.14401f, 309.3f, 238.788f, 263.232f, 244.75201f, 219.468f, 271.58002f, 210.824f, 294.176f, 250.664f,
|
|
||||||
295.2f, 295.972f, 276.02f, 357.46f, 269.172f, 420.008f, 242.37201f, 466.63602f, 207.648f, 437.516f, -10.579998f,
|
|
||||||
378.05603f, -64.624f, 465.24f, -104.992f, 554.11206f, 95.43199f, 514.89197f, 259.02f};
|
|
||||||
for (int i = 0, n = v.length; i < n; i++)
|
|
||||||
v[i] += 200;
|
|
||||||
|
|
||||||
// float[] v = new float[] { 94.0f, 84.0f, 45.0f, 165.0f, 218.0f, 292.0f, 476.0f, 227.0f, 480.0f, 125.0f, 325.0f, 191.0f,
|
|
||||||
// 333.0f, 77.0f, 302.0f, 30.0f, 175.0f, 140.0f };
|
|
||||||
// float[] v = {87, 288, 217, 371, 456, 361, 539, 175, 304, 194, 392, 290, 193, 214, 123, 15, 14, 137};
|
|
||||||
// float[] v = { 336, 153, 207, 184, 364, 333, 529, 326, 584, 130, 438, 224 };
|
|
||||||
polygon.addAll(v);
|
|
||||||
triangulate();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void resize (int width, int height) {
|
|
||||||
sceneCamera.setToOrtho(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void render () {
|
|
||||||
Gdx.gl.glClearColor(0.3f, 0.3f, 0.3f, 1);
|
|
||||||
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
|
|
||||||
|
|
||||||
processInput();
|
|
||||||
renderScene();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void processInput () {
|
|
||||||
tmp.set(Gdx.input.getX(), Gdx.input.getY(), 0);
|
|
||||||
sceneCamera.unproject(tmp);
|
|
||||||
|
|
||||||
if (Gdx.input.justTouched()) {
|
|
||||||
if (!isCreatingPolygon) {
|
|
||||||
polygon.clear();
|
|
||||||
convexPolygons = null;
|
|
||||||
isCreatingPolygon = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
polygon.add((int)tmp.x);
|
|
||||||
polygon.add((int)tmp.y);
|
|
||||||
|
|
||||||
if (Gdx.input.isButtonPressed(Buttons.RIGHT)) {
|
|
||||||
isCreatingPolygon = false;
|
|
||||||
System.out.print("float[] v = { ");
|
|
||||||
for (int i = 0; i < polygon.size; i++) {
|
|
||||||
System.out.print(polygon.get(i));
|
|
||||||
if (i != polygon.size - 1) System.out.print(", ");
|
|
||||||
}
|
|
||||||
System.out.println("};");
|
|
||||||
triangulate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Gdx.input.isKeyJustPressed(Keys.R)) {
|
|
||||||
long start = System.nanoTime();
|
|
||||||
generateRandomPolygon();
|
|
||||||
System.out.println("Took: " + (System.nanoTime() - start) / 1000000000.0f + " secs");
|
|
||||||
System.out.print("float[] v = { ");
|
|
||||||
for (int i = 0; i < polygon.size; i++) {
|
|
||||||
System.out.print(polygon.get(i));
|
|
||||||
if (i != polygon.size - 1) System.out.print(", ");
|
|
||||||
}
|
|
||||||
System.out.println("};");
|
|
||||||
triangulate();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Gdx.input.isKeyJustPressed(Keys.T)) {
|
|
||||||
triangulate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void generateRandomPolygon () {
|
|
||||||
polygon.clear();
|
|
||||||
convexPolygons.clear();
|
|
||||||
|
|
||||||
int numVertices = MathUtils.random(3, 30);
|
|
||||||
for (int i = 0; i < numVertices; i++) {
|
|
||||||
float x = (float)(50 + Math.random() * (Gdx.graphics.getWidth() - 50));
|
|
||||||
float y = (float)(50 + Math.random() * (Gdx.graphics.getHeight() - 50));
|
|
||||||
|
|
||||||
polygon.add(x);
|
|
||||||
polygon.add(y);
|
|
||||||
System.out.println(polygon.toString(","));
|
|
||||||
if (selfIntersects(polygon)) {
|
|
||||||
polygon.size -= 2;
|
|
||||||
i--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean selfIntersects (FloatArray polygon) {
|
|
||||||
Vector2 tmp = new Vector2();
|
|
||||||
if (polygon.size == 6) return false;
|
|
||||||
for (int i = 0, n = polygon.size; i <= n; i += 2) {
|
|
||||||
float x1 = polygon.get(i % n);
|
|
||||||
float y1 = polygon.get((i + 1) % n);
|
|
||||||
float x2 = polygon.get((i + 2) % n);
|
|
||||||
float y2 = polygon.get((i + 3) % n);
|
|
||||||
|
|
||||||
for (int j = 0; j <= n; j += 2) {
|
|
||||||
float x3 = polygon.get(j % n);
|
|
||||||
float y3 = polygon.get((j + 1) % n);
|
|
||||||
float x4 = polygon.get((j + 2) % n);
|
|
||||||
float y4 = polygon.get((j + 3) % n);
|
|
||||||
if (x1 == x3 && y1 == y3) continue;
|
|
||||||
if (x1 == x4 && y1 == y4) continue;
|
|
||||||
if (x2 == x3 && y2 == y3) continue;
|
|
||||||
if (x2 == x4 && y2 == y4) continue;
|
|
||||||
if (Intersector.intersectSegments(x1, y1, x2, y2, x3, y3, x4, y4, tmp)) return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void renderScene () {
|
|
||||||
sceneCamera.update();
|
|
||||||
shapes.setProjectionMatrix(sceneCamera.combined);
|
|
||||||
polyBatcher.setProjectionMatrix(sceneCamera.combined);
|
|
||||||
|
|
||||||
polyBatcher.begin();
|
|
||||||
polyBatcher.disableBlending();
|
|
||||||
|
|
||||||
polyBatcher.end();
|
|
||||||
|
|
||||||
// polygon
|
|
||||||
shapes.setColor(Color.RED);
|
|
||||||
shapes.begin(ShapeType.Line);
|
|
||||||
if (isCreatingPolygon) {
|
|
||||||
tmp.set(Gdx.input.getX(), Gdx.input.getY(), 0);
|
|
||||||
sceneCamera.unproject(tmp);
|
|
||||||
polygon.add(tmp.x);
|
|
||||||
polygon.add(tmp.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
// polygon while drawing
|
|
||||||
// switch (polygon.size) {
|
|
||||||
// case 0:
|
|
||||||
// break;
|
|
||||||
// case 2:
|
|
||||||
// shapes.end();
|
|
||||||
// shapes.begin(ShapeType.Point);
|
|
||||||
// GL11.glPointSize(4);
|
|
||||||
// shapes.point(polygon.get(0), polygon.get(1), 0);
|
|
||||||
// shapes.end();
|
|
||||||
// shapes.begin(ShapeType.Line);
|
|
||||||
// break;
|
|
||||||
// case 4:
|
|
||||||
// shapes.line(polygon.get(0), polygon.get(1), polygon.get(2), polygon.get(3));
|
|
||||||
// break;
|
|
||||||
// default:
|
|
||||||
// shapes.polygon(polygon.items, 0, polygon.size);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// edge normals
|
|
||||||
// shapes.setColor(Color.YELLOW);
|
|
||||||
// if (polygon.size > 2) {
|
|
||||||
// boolean clockwise = Clipper.isClockwise(polygon);
|
|
||||||
// for (int i = 0; i < polygon.size; i += 2) {
|
|
||||||
// float x = polygon.get(i);
|
|
||||||
// float y = polygon.get(i + 1);
|
|
||||||
// float x2 = polygon.get((i + 2) % polygon.size);
|
|
||||||
// float y2 = polygon.get((i + 3) % polygon.size);
|
|
||||||
//
|
|
||||||
// float mx = x + (x2 - x) / 2;
|
|
||||||
// float my = y + (y2 - y) / 2;
|
|
||||||
// float nx = (y2 - y);
|
|
||||||
// float ny = -(x2 - x);
|
|
||||||
// if (!clockwise) {
|
|
||||||
// nx = -nx;
|
|
||||||
// ny = -ny;
|
|
||||||
// }
|
|
||||||
// float l = 1 / (float)Math.sqrt(nx * nx + ny * ny);
|
|
||||||
// nx *= l * 20;
|
|
||||||
// ny *= l * 20;
|
|
||||||
//
|
|
||||||
// shapes.line(mx, my, mx + nx, my + ny);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// decomposition
|
|
||||||
if (convexPolygons != null) {
|
|
||||||
for (int i = 0, n = convexPolygons.size; i < n; i++) {
|
|
||||||
if (colors.size <= i) {
|
|
||||||
colors.add(new Color(MathUtils.random(), MathUtils.random(), MathUtils.random(), 1));
|
|
||||||
}
|
|
||||||
shapes.setColor(colors.get(i));
|
|
||||||
shapes.polygon(convexPolygons.get(i).items, 0, convexPolygons.get(i).size);
|
|
||||||
if (i == 29) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isCreatingPolygon) {
|
|
||||||
polygon.setSize(polygon.size - 2);
|
|
||||||
}
|
|
||||||
shapes.end();
|
|
||||||
|
|
||||||
polyBatcher.begin();
|
|
||||||
polyBatcher.enableBlending();
|
|
||||||
for (int i = 0; i < polygon.size; i += 2) {
|
|
||||||
float x = polygon.get(i);
|
|
||||||
float y = polygon.get(i + 1);
|
|
||||||
font.draw(polyBatcher, "" + (i >> 1), x, y); // + ", " + x + ", " + y, x, y);
|
|
||||||
}
|
|
||||||
font.draw(polyBatcher, Gdx.input.getX() + ", " + (Gdx.graphics.getHeight() - Gdx.input.getY()), 0, 20);
|
|
||||||
polyBatcher.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void triangulate () {
|
|
||||||
Clipper.makeClockwise(polygon);
|
|
||||||
convexPolygons = decomposer.decompose(polygon);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main (String[] args) {
|
|
||||||
LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
|
|
||||||
config.width = 800;
|
|
||||||
config.height = 600;
|
|
||||||
new LwjglApplication(new ConvexDecomposerTest(), config);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,265 +0,0 @@
|
|||||||
|
|
||||||
package com.esotericsoftware.spine;
|
|
||||||
|
|
||||||
import org.lwjgl.opengl.GL11;
|
|
||||||
|
|
||||||
import com.badlogic.gdx.ApplicationAdapter;
|
|
||||||
import com.badlogic.gdx.Gdx;
|
|
||||||
import com.badlogic.gdx.Input.Buttons;
|
|
||||||
import com.badlogic.gdx.Input.Keys;
|
|
||||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
|
|
||||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
|
|
||||||
import com.badlogic.gdx.graphics.Color;
|
|
||||||
import com.badlogic.gdx.graphics.GL20;
|
|
||||||
import com.badlogic.gdx.graphics.OrthographicCamera;
|
|
||||||
import com.badlogic.gdx.graphics.Texture;
|
|
||||||
import com.badlogic.gdx.graphics.g2d.PolygonSpriteBatch;
|
|
||||||
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
|
|
||||||
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
|
|
||||||
import com.badlogic.gdx.math.Vector3;
|
|
||||||
import com.badlogic.gdx.utils.Array;
|
|
||||||
import com.badlogic.gdx.utils.FloatArray;
|
|
||||||
import com.badlogic.gdx.utils.ShortArray;
|
|
||||||
import com.esotericsoftware.spine.utils.Clipper;
|
|
||||||
import com.esotericsoftware.spine.utils.ConvexDecomposer;
|
|
||||||
|
|
||||||
public class SoftwareClippingTest extends ApplicationAdapter {
|
|
||||||
OrthographicCamera sceneCamera;
|
|
||||||
ShapeRenderer shapes;
|
|
||||||
PolygonSpriteBatch polyBatcher;
|
|
||||||
Texture image;
|
|
||||||
|
|
||||||
float[] triangleOutline = {100, 100, 300, 100, 200, 300};
|
|
||||||
float[] triangle = {100, 100, Color.WHITE.toFloatBits(), 0, 1, 300, 100, Color.WHITE.toFloatBits(), 1, 1, 200, 300,
|
|
||||||
Color.WHITE.toFloatBits(), 0.5f, 0};
|
|
||||||
short[] triangleIndices = {0, 1, 2};
|
|
||||||
FloatArray clippingPolygon = new FloatArray();
|
|
||||||
FloatArray clippedPolygon = new FloatArray();
|
|
||||||
|
|
||||||
FloatArray clippedPolygonVertices = new FloatArray();
|
|
||||||
ShortArray clippedPolygonIndices = new ShortArray();
|
|
||||||
|
|
||||||
boolean isCreatingClippingArea = false;
|
|
||||||
Vector3 tmp = new Vector3();
|
|
||||||
Clipper clipper;
|
|
||||||
ConvexDecomposer decomposer;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void create () {
|
|
||||||
sceneCamera = new OrthographicCamera();
|
|
||||||
shapes = new ShapeRenderer();
|
|
||||||
polyBatcher = new PolygonSpriteBatch();
|
|
||||||
clipper = new Clipper();
|
|
||||||
decomposer = new ConvexDecomposer();
|
|
||||||
image = new Texture("skin/skin.png");
|
|
||||||
|
|
||||||
float[] v = new float[] {430.90802f, 278.212f, 72.164f, 361.816f, 31.143997f, 128.804f, 191.896f, 61.0f, 291.312f,
|
|
||||||
175.73201f, 143.956f, 207.408f, 161.4f, 145.628f, 227.456f, 160.61601f, 224.392f, 126.535995f, 188.264f, 113.144f,
|
|
||||||
147.13199f, 108.87601f, 77.035995f, 158.212f, 86.15199f, 220.676f, 102.77199f, 240.716f, 174.74399f, 243.20801f,
|
|
||||||
250.572f, 216.74802f, 324.772f, 200.33202f, 309.388f, 124.968f, 258.168f, 60.503998f, 199.696f, 42.872f, 116.951996f,
|
|
||||||
6.7400017f, 11.332001f, 72.48f, -6.708008f, 143.136f, 1.0679932f, 239.92801f, 26.5f, 355.6f, -47.380005f, 377.52798f,
|
|
||||||
-40.608f, 303.1f, -53.584015f, 77.316f, 5.4600067f, 8.728001f, 113.343994f, -56.04f, 192.42801f, -45.112f, 274.564f,
|
|
||||||
-38.784f, 322.592f, -10.604f, 371.98f, 21.920002f, 405.16f, 60.896004f, 428.68f, 104.852005f, 406.996f, 188.976f,
|
|
||||||
364.58398f, 220.14401f, 309.3f, 238.788f, 263.232f, 244.75201f, 219.468f, 271.58002f, 210.824f, 294.176f, 250.664f,
|
|
||||||
295.2f, 295.972f, 276.02f, 357.46f, 269.172f, 420.008f, 242.37201f, 466.63602f, 207.648f, 437.516f, -10.579998f,
|
|
||||||
378.05603f, -64.624f, 465.24f, -104.992f, 554.11206f, 95.43199f, 514.89197f, 259.02f};
|
|
||||||
for (int i = 0, n = v.length; i < n; i++)
|
|
||||||
v[i] = v[i] * 0.5f + 70;
|
|
||||||
clippingPolygon.addAll(v);
|
|
||||||
clip();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void resize (int width, int height) {
|
|
||||||
sceneCamera.setToOrtho(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void render () {
|
|
||||||
Gdx.gl.glClearColor(0.3f, 0.3f, 0.3f, 1);
|
|
||||||
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
|
|
||||||
|
|
||||||
processInput();
|
|
||||||
renderScene();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void processInput () {
|
|
||||||
tmp.set(Gdx.input.getX(), Gdx.input.getY(), 0);
|
|
||||||
sceneCamera.unproject(tmp);
|
|
||||||
|
|
||||||
if (Gdx.input.justTouched()) {
|
|
||||||
if (!isCreatingClippingArea) {
|
|
||||||
clippingPolygon.clear();
|
|
||||||
isCreatingClippingArea = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
clippingPolygon.add((int)tmp.x);
|
|
||||||
clippingPolygon.add((int)tmp.y);
|
|
||||||
|
|
||||||
if (Gdx.input.isButtonPressed(Buttons.RIGHT)) {
|
|
||||||
isCreatingClippingArea = false;
|
|
||||||
clip();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Gdx.input.isKeyJustPressed(Keys.T)) {
|
|
||||||
clip();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void renderScene () {
|
|
||||||
sceneCamera.update();
|
|
||||||
shapes.setProjectionMatrix(sceneCamera.combined);
|
|
||||||
polyBatcher.setProjectionMatrix(sceneCamera.combined);
|
|
||||||
|
|
||||||
polyBatcher.begin();
|
|
||||||
polyBatcher.disableBlending();
|
|
||||||
|
|
||||||
// clipped polygon
|
|
||||||
if (clippedPolygonVertices.size == 0) {
|
|
||||||
polyBatcher.draw(image, triangle, 0, 15, triangleIndices, 0, 3);
|
|
||||||
} else {
|
|
||||||
polyBatcher.draw(image, clippedPolygonVertices.items, 0, clippedPolygonVertices.size, clippedPolygonIndices.items, 0,
|
|
||||||
clippedPolygonIndices.size);
|
|
||||||
}
|
|
||||||
polyBatcher.end();
|
|
||||||
|
|
||||||
shapes.begin(ShapeType.Line);
|
|
||||||
|
|
||||||
// triangle
|
|
||||||
shapes.setColor(Color.GREEN);
|
|
||||||
shapes.polygon(triangleOutline);
|
|
||||||
|
|
||||||
// clipping area
|
|
||||||
shapes.setColor(Color.RED);
|
|
||||||
if (isCreatingClippingArea) {
|
|
||||||
tmp.set(Gdx.input.getX(), Gdx.input.getY(), 0);
|
|
||||||
sceneCamera.unproject(tmp);
|
|
||||||
clippingPolygon.add(tmp.x);
|
|
||||||
clippingPolygon.add(tmp.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (clippingPolygon.size) {
|
|
||||||
case 0:
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
shapes.end();
|
|
||||||
shapes.begin(ShapeType.Point);
|
|
||||||
GL11.glPointSize(4);
|
|
||||||
shapes.point(clippingPolygon.get(0), clippingPolygon.get(1), 0);
|
|
||||||
shapes.end();
|
|
||||||
shapes.begin(ShapeType.Line);
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
shapes.line(clippingPolygon.get(0), clippingPolygon.get(1), clippingPolygon.get(2), clippingPolygon.get(3));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
shapes.polygon(clippingPolygon.items, 0, clippingPolygon.size);
|
|
||||||
}
|
|
||||||
|
|
||||||
// // edge normals
|
|
||||||
// shapes.setColor(Color.YELLOW);
|
|
||||||
// if (clippingPolygon.size > 2) {
|
|
||||||
// boolean clockwise = Clipper.isClockwise(clippingPolygon);
|
|
||||||
// for (int i = 0; i < clippingPolygon.size; i += 2) {
|
|
||||||
// float x = clippingPolygon.get(i);
|
|
||||||
// float y = clippingPolygon.get(i + 1);
|
|
||||||
// float x2 = clippingPolygon.get((i + 2) % clippingPolygon.size);
|
|
||||||
// float y2 = clippingPolygon.get((i + 3) % clippingPolygon.size);
|
|
||||||
//
|
|
||||||
// float mx = x + (x2 - x) / 2;
|
|
||||||
// float my = y + (y2 - y) / 2;
|
|
||||||
// float nx = (y2 - y);
|
|
||||||
// float ny = -(x2 - x);
|
|
||||||
// if (!clockwise) {
|
|
||||||
// nx = -nx;
|
|
||||||
// ny = -ny;
|
|
||||||
// }
|
|
||||||
// float l = 1 / (float)Math.sqrt(nx * nx + ny * ny);
|
|
||||||
// nx *= l * 20;
|
|
||||||
// ny *= l * 20;
|
|
||||||
//
|
|
||||||
// shapes.line(mx, my, mx + nx, my + ny);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (isCreatingClippingArea) {
|
|
||||||
clippingPolygon.setSize(clippingPolygon.size - 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// // clipped polygon
|
|
||||||
// shapes.setColor(Color.PINK);
|
|
||||||
// if (clippedPolygon.size > 0) {
|
|
||||||
// shapes.polygon(clippedPolygon.items, 0, clippedPolygon.size);
|
|
||||||
// }
|
|
||||||
|
|
||||||
shapes.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void clip () {
|
|
||||||
float x1 = triangle[0];
|
|
||||||
float y1 = triangle[1];
|
|
||||||
float x2 = triangle[5];
|
|
||||||
float y2 = triangle[6];
|
|
||||||
float x3 = triangle[10];
|
|
||||||
float y3 = triangle[11];
|
|
||||||
|
|
||||||
Clipper.makeClockwise(clippingPolygon);
|
|
||||||
Array<FloatArray> clippingPolygons = decomposer.decompose(clippingPolygon);
|
|
||||||
clippedPolygonVertices.clear();
|
|
||||||
clippedPolygonIndices.clear();
|
|
||||||
|
|
||||||
for (FloatArray poly : clippingPolygons) {
|
|
||||||
Clipper.makeClockwise(poly);
|
|
||||||
poly.add(poly.get(0));
|
|
||||||
poly.add(poly.get(1));
|
|
||||||
|
|
||||||
boolean clipped = clipper.clip(x1, y1, x2, y2, x3, y3, poly, clippedPolygon);
|
|
||||||
System.out.println("Clipped: " + clipped);
|
|
||||||
if (clipped) {
|
|
||||||
float d0 = y2 - y3;
|
|
||||||
float d1 = x3 - x2;
|
|
||||||
float d2 = x1 - x3;
|
|
||||||
float d3 = y1 - y3;
|
|
||||||
float d4 = y3 - y1;
|
|
||||||
|
|
||||||
float denom = 1 / (d0 * d2 + d1 * d3);
|
|
||||||
|
|
||||||
// triangulate by creating a triangle fan, duplicate vertices
|
|
||||||
int o = clippedPolygonVertices.size / 5;
|
|
||||||
float color = Color.WHITE.toFloatBits();
|
|
||||||
for (int i = 0; i < clippedPolygon.size; i += 2) {
|
|
||||||
float x = clippedPolygon.get(i);
|
|
||||||
float y = clippedPolygon.get(i + 1);
|
|
||||||
|
|
||||||
float a = (d0 * (x - x3) + d1 * (y - y3)) * denom;
|
|
||||||
float b = (d4 * (x - x3) + d2 * (y - y3)) * denom;
|
|
||||||
float c = 1.0f - a - b;
|
|
||||||
|
|
||||||
float u = triangle[3] * a + triangle[8] * b + triangle[13] * c;
|
|
||||||
float v = triangle[4] * a + triangle[9] * b + triangle[14] * c;
|
|
||||||
clippedPolygonVertices.add(x);
|
|
||||||
clippedPolygonVertices.add(y);
|
|
||||||
clippedPolygonVertices.add(color);
|
|
||||||
clippedPolygonVertices.add(u);
|
|
||||||
clippedPolygonVertices.add(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 1; i < (clippedPolygon.size >> 1) - 1; i++) {
|
|
||||||
clippedPolygonIndices.add(o);
|
|
||||||
clippedPolygonIndices.add(o + i);
|
|
||||||
clippedPolygonIndices.add(o + i + 1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
clippedPolygon.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
poly.setSize(poly.size - 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main (String[] args) {
|
|
||||||
LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
|
|
||||||
new LwjglApplication(new SoftwareClippingTest(), config);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,146 +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.utils;
|
|
||||||
|
|
||||||
import com.badlogic.gdx.utils.FloatArray;
|
|
||||||
|
|
||||||
public class Clipper {
|
|
||||||
private final FloatArray scratch = new FloatArray();
|
|
||||||
|
|
||||||
/** Clips the input triangle against the convex clipping area, which needs to be clockwise. If the triangle lies entirely
|
|
||||||
* within the clipping area, false is returned. The clipping area must duplicate the first vertex at the end of the vertices
|
|
||||||
* list. */
|
|
||||||
public boolean clip (float x1, float y1, float x2, float y2, float x3, float y3, FloatArray clippingArea, FloatArray output) {
|
|
||||||
FloatArray originalOutput = output;
|
|
||||||
boolean clipped = false;
|
|
||||||
|
|
||||||
// Avoid copy at the end.
|
|
||||||
FloatArray input = null;
|
|
||||||
if (clippingArea.size % 4 >= 2) {
|
|
||||||
input = output;
|
|
||||||
output = scratch;
|
|
||||||
} else
|
|
||||||
input = scratch;
|
|
||||||
|
|
||||||
input.clear();
|
|
||||||
input.add(x1);
|
|
||||||
input.add(y1);
|
|
||||||
input.add(x2);
|
|
||||||
input.add(y2);
|
|
||||||
input.add(x3);
|
|
||||||
input.add(y3);
|
|
||||||
input.add(x1);
|
|
||||||
input.add(y1);
|
|
||||||
output.clear();
|
|
||||||
|
|
||||||
float[] clippingVertices = clippingArea.items;
|
|
||||||
int clippingVerticesLast = clippingArea.size - 4;
|
|
||||||
for (int i = 0;; i += 2) {
|
|
||||||
float edgeX = clippingVertices[i], edgeY = clippingVertices[i + 1];
|
|
||||||
float edgeX2 = clippingVertices[i + 2], edgeY2 = clippingVertices[i + 3];
|
|
||||||
float deltaX = edgeX - edgeX2, deltaY = edgeY - edgeY2;
|
|
||||||
|
|
||||||
float[] inputVertices = input.items;
|
|
||||||
int inputVerticesLength = input.size - 2, outputStart = output.size;
|
|
||||||
for (int ii = 0; ii < inputVerticesLength; ii += 2) {
|
|
||||||
float inputX = inputVertices[ii], inputY = inputVertices[ii + 1];
|
|
||||||
float inputX2 = inputVertices[ii + 2], inputY2 = inputVertices[ii + 3];
|
|
||||||
boolean side2 = deltaX * (inputY2 - edgeY2) - deltaY * (inputX2 - edgeX2) > 0;
|
|
||||||
if (deltaX * (inputY - edgeY2) - deltaY * (inputX - edgeX2) > 0) {
|
|
||||||
if (side2) { // v1 inside, v2 inside
|
|
||||||
output.add(inputX2);
|
|
||||||
output.add(inputY2);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// v1 inside, v2 outside
|
|
||||||
float c0 = inputY2 - inputY, c2 = inputX2 - inputX;
|
|
||||||
float ua = (c2 * (edgeY - inputY) - c0 * (edgeX - inputX)) / (c0 * (edgeX2 - edgeX) - c2 * (edgeY2 - edgeY));
|
|
||||||
output.add(edgeX + (edgeX2 - edgeX) * ua);
|
|
||||||
output.add(edgeY + (edgeY2 - edgeY) * ua);
|
|
||||||
} else if (side2) { // v1 outside, v2 inside
|
|
||||||
float c0 = inputY2 - inputY, c2 = inputX2 - inputX;
|
|
||||||
float ua = (c2 * (edgeY - inputY) - c0 * (edgeX - inputX)) / (c0 * (edgeX2 - edgeX) - c2 * (edgeY2 - edgeY));
|
|
||||||
output.add(edgeX + (edgeX2 - edgeX) * ua);
|
|
||||||
output.add(edgeY + (edgeY2 - edgeY) * ua);
|
|
||||||
output.add(inputX2);
|
|
||||||
output.add(inputY2);
|
|
||||||
}
|
|
||||||
clipped = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (outputStart == output.size) { // All edges outside.
|
|
||||||
originalOutput.clear();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
output.add(output.items[0]);
|
|
||||||
output.add(output.items[1]);
|
|
||||||
|
|
||||||
if (i == clippingVerticesLast) break;
|
|
||||||
FloatArray temp = output;
|
|
||||||
output = input;
|
|
||||||
output.clear();
|
|
||||||
input = temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (originalOutput != output) {
|
|
||||||
originalOutput.clear();
|
|
||||||
originalOutput.addAll(output.items, 0, output.size - 2);
|
|
||||||
} else
|
|
||||||
originalOutput.setSize(originalOutput.size - 2);
|
|
||||||
|
|
||||||
return clipped;
|
|
||||||
}
|
|
||||||
|
|
||||||
static public void makeClockwise (FloatArray polygon) {
|
|
||||||
float[] vertices = polygon.items;
|
|
||||||
int verticeslength = polygon.size;
|
|
||||||
|
|
||||||
float area = vertices[verticeslength - 2] * vertices[1] - vertices[0] * vertices[verticeslength - 1], p1x, p1y, p2x, p2y;
|
|
||||||
for (int i = 0, n = verticeslength - 3; i < n; i += 2) {
|
|
||||||
p1x = vertices[i];
|
|
||||||
p1y = vertices[i + 1];
|
|
||||||
p2x = vertices[i + 2];
|
|
||||||
p2y = vertices[i + 3];
|
|
||||||
area += p1x * p2y - p2x * p1y;
|
|
||||||
}
|
|
||||||
if (area < 0) return;
|
|
||||||
|
|
||||||
for (int i = 0, lastX = verticeslength - 2, n = verticeslength >> 1; i < n; i += 2) {
|
|
||||||
float x = vertices[i], y = vertices[i + 1];
|
|
||||||
int other = lastX - i;
|
|
||||||
vertices[i] = vertices[other];
|
|
||||||
vertices[i + 1] = vertices[other + 1];
|
|
||||||
vertices[other] = x;
|
|
||||||
vertices[other + 1] = y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -36,7 +36,7 @@ import com.badlogic.gdx.utils.FloatArray;
|
|||||||
import com.badlogic.gdx.utils.Pool;
|
import com.badlogic.gdx.utils.Pool;
|
||||||
import com.badlogic.gdx.utils.ShortArray;
|
import com.badlogic.gdx.utils.ShortArray;
|
||||||
|
|
||||||
public class ConvexDecomposer {
|
class ConvexDecomposer {
|
||||||
private final Array<FloatArray> convexPolygons = new Array();
|
private final Array<FloatArray> convexPolygons = new Array();
|
||||||
private final Array<ShortArray> convexPolygonsIndices = new Array();
|
private final Array<ShortArray> convexPolygonsIndices = new Array();
|
||||||
|
|
||||||
@ -75,40 +75,60 @@ public class ConvexDecomposer {
|
|||||||
triangles.clear();
|
triangles.clear();
|
||||||
triangles.ensureCapacity(Math.max(0, vertexCount - 2) << 2);
|
triangles.ensureCapacity(Math.max(0, vertexCount - 2) << 2);
|
||||||
|
|
||||||
// Triangulate.
|
|
||||||
while (vertexCount > 3) {
|
while (vertexCount > 3) {
|
||||||
// Find ear tip.
|
// Find ear tip.
|
||||||
int i = 0;
|
int previous = vertexCount - 1, i = 0, next = 1;
|
||||||
while (true) {
|
while (true) {
|
||||||
if (!isConcave[i] && isEarTip(i, vertexCount, vertices, indices)) break;
|
outer:
|
||||||
i++;
|
if (!isConcave[i]) {
|
||||||
if (i == vertexCount) {
|
int p1 = indices[previous] << 1, p2 = indices[i] << 1, p3 = indices[next] << 1;
|
||||||
|
float p1x = vertices[p1], p1y = vertices[p1 + 1];
|
||||||
|
float p2x = vertices[p2], p2y = vertices[p2 + 1];
|
||||||
|
float p3x = vertices[p3], p3y = vertices[p3 + 1];
|
||||||
|
for (int ii = (next + 1) % vertexCount; ii != previous; ii = (ii + 1) % vertexCount) {
|
||||||
|
if (!isConcave[ii]) continue;
|
||||||
|
int v = indices[ii] << 1;
|
||||||
|
float vx = vertices[v], vy = vertices[v + 1];
|
||||||
|
if (positiveArea(p3x, p3y, p1x, p1y, vx, vy)) {
|
||||||
|
if (positiveArea(p1x, p1y, p2x, p2y, vx, vy)) {
|
||||||
|
if (positiveArea(p2x, p2y, p3x, p3y, vx, vy)) break outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (next == 0) {
|
||||||
do {
|
do {
|
||||||
i--;
|
|
||||||
if (!isConcave[i]) break;
|
if (!isConcave[i]) break;
|
||||||
|
i--;
|
||||||
} while (i > 0);
|
} while (i > 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
previous = i;
|
||||||
|
i = next;
|
||||||
|
next = (next + 1) % vertexCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cut ear tip.
|
// Cut ear tip.
|
||||||
triangles.add(indices[previousIndex(i, vertexCount)]);
|
triangles.add(indices[(vertexCount + i - 1) % vertexCount]);
|
||||||
triangles.add(indices[i]);
|
triangles.add(indices[i]);
|
||||||
triangles.add(indices[nextIndex(i, vertexCount)]);
|
triangles.add(indices[(i + 1) % vertexCount]);
|
||||||
indicesArray.removeIndex(i);
|
indicesArray.removeIndex(i);
|
||||||
isConcaveArray.removeIndex(i);
|
isConcaveArray.removeIndex(i);
|
||||||
vertexCount--;
|
vertexCount--;
|
||||||
|
|
||||||
int previousIndex = previousIndex(i, vertexCount);
|
int previousIndex = (vertexCount + i - 1) % vertexCount;
|
||||||
int nextIndex = i == vertexCount ? 0 : i;
|
int nextIndex = i == vertexCount ? 0 : i;
|
||||||
isConcave[previousIndex] = isConcave(previousIndex, vertexCount, vertices, indices);
|
isConcave[previousIndex] = isConcave(previousIndex, vertexCount, vertices, indices);
|
||||||
isConcave[nextIndex] = isConcave(nextIndex, vertexCount, vertices, indices);
|
isConcave[nextIndex] = isConcave(nextIndex, vertexCount, vertices, indices);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vertexCount == 3) {
|
if (vertexCount == 3) {
|
||||||
triangles.add(indicesArray.get(2));
|
triangles.add(indices[2]);
|
||||||
triangles.add(indicesArray.get(0));
|
triangles.add(indices[0]);
|
||||||
triangles.add(indicesArray.get(1));
|
triangles.add(indices[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Array<FloatArray> convexPolygons = this.convexPolygons;
|
Array<FloatArray> convexPolygons = this.convexPolygons;
|
||||||
@ -127,18 +147,20 @@ public class ConvexDecomposer {
|
|||||||
|
|
||||||
// Merge subsequent triangles if they form a triangle fan.
|
// Merge subsequent triangles if they form a triangle fan.
|
||||||
int fanBaseIndex = -1, lastWinding = 0;
|
int fanBaseIndex = -1, lastWinding = 0;
|
||||||
|
short[] trianglesItems = triangles.items;
|
||||||
for (int i = 0, n = triangles.size; i < n; i += 3) {
|
for (int i = 0, n = triangles.size; i < n; i += 3) {
|
||||||
int t1 = triangles.get(i) << 1, t2 = triangles.get(i + 1) << 1, t3 = triangles.get(i + 2) << 1;
|
int t1 = trianglesItems[i] << 1, t2 = trianglesItems[i + 1] << 1, t3 = trianglesItems[i + 2] << 1;
|
||||||
float x1 = input.get(t1), y1 = input.get(t1 + 1);
|
float x1 = vertices[t1], y1 = vertices[t1 + 1];
|
||||||
float x2 = input.get(t2), y2 = input.get(t2 + 1);
|
float x2 = vertices[t2], y2 = vertices[t2 + 1];
|
||||||
float x3 = input.get(t3), y3 = input.get(t3 + 1);
|
float x3 = vertices[t3], y3 = vertices[t3 + 1];
|
||||||
|
|
||||||
// If the base of the last triangle is the same as this triangle, check if they form a convex polygon (triangle fan).
|
// If the base of the last triangle is the same as this triangle, check if they form a convex polygon (triangle fan).
|
||||||
boolean merged = false;
|
boolean merged = false;
|
||||||
if (fanBaseIndex == t1) {
|
if (fanBaseIndex == t1) {
|
||||||
int o = polygon.size - 4;
|
int o = polygon.size - 4;
|
||||||
int winding1 = winding(polygon.get(o), polygon.get(o + 1), polygon.get(o + 2), polygon.get(o + 3), x3, y3);
|
float[] p = polygon.items;
|
||||||
int winding2 = winding(x3, y3, polygon.get(0), polygon.get(1), polygon.get(2), polygon.get(3));
|
int winding1 = winding(p[o], p[o + 1], p[o + 2], p[o + 3], x3, y3);
|
||||||
|
int winding2 = winding(x3, y3, p[0], p[1], p[2], p[3]);
|
||||||
if (winding1 == lastWinding && winding2 == lastWinding) {
|
if (winding1 == lastWinding && winding2 == lastWinding) {
|
||||||
polygon.add(x3);
|
polygon.add(x3);
|
||||||
polygon.add(y3);
|
polygon.add(y3);
|
||||||
@ -185,10 +207,11 @@ public class ConvexDecomposer {
|
|||||||
|
|
||||||
polygon = convexPolygons.get(i);
|
polygon = convexPolygons.get(i);
|
||||||
int o = polygon.size - 4;
|
int o = polygon.size - 4;
|
||||||
float prevPrevX = polygon.get(o), prevPrevY = polygon.get(o + 1);
|
float[] p = polygon.items;
|
||||||
float prevX = polygon.get(o + 2), prevY = polygon.get(o + 3);
|
float prevPrevX = p[o], prevPrevY = p[o + 1];
|
||||||
float firstX = polygon.get(0), firstY = polygon.get(1);
|
float prevX = p[o + 2], prevY = p[o + 3];
|
||||||
float secondX = polygon.get(2), secondY = polygon.get(3);
|
float firstX = p[0], firstY = p[1];
|
||||||
|
float secondX = p[2], secondY = p[3];
|
||||||
int winding = winding(prevPrevX, prevPrevY, prevX, prevY, firstX, firstY);
|
int winding = winding(prevPrevX, prevPrevY, prevX, prevY, firstX, firstY);
|
||||||
|
|
||||||
for (int ii = 0; ii < n; ii++) {
|
for (int ii = 0; ii < n; ii++) {
|
||||||
@ -200,8 +223,7 @@ public class ConvexDecomposer {
|
|||||||
int otherLastIndex = otherIndices.get(2);
|
int otherLastIndex = otherIndices.get(2);
|
||||||
|
|
||||||
FloatArray otherPoly = convexPolygons.get(ii);
|
FloatArray otherPoly = convexPolygons.get(ii);
|
||||||
float x3 = otherPoly.get(otherPoly.size - 2);
|
float x3 = otherPoly.get(otherPoly.size - 2), y3 = otherPoly.get(otherPoly.size - 1);
|
||||||
float y3 = otherPoly.get(otherPoly.size - 1);
|
|
||||||
|
|
||||||
if (otherFirstIndex != firstIndex || otherSecondIndex != lastIndex) continue;
|
if (otherFirstIndex != firstIndex || otherSecondIndex != lastIndex) continue;
|
||||||
int winding1 = winding(prevPrevX, prevPrevY, prevX, prevY, x3, y3);
|
int winding1 = winding(prevPrevX, prevPrevY, prevX, prevY, x3, y3);
|
||||||
@ -233,47 +255,14 @@ public class ConvexDecomposer {
|
|||||||
return convexPolygons;
|
return convexPolygons;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isEarTip (int earTipIndex, int vertexCount, float[] vertices, short[] indices) {
|
|
||||||
int previousIndex = previousIndex(earTipIndex, vertexCount);
|
|
||||||
int nextIndex = nextIndex(earTipIndex, vertexCount);
|
|
||||||
int p1 = indices[previousIndex] << 1;
|
|
||||||
int p2 = indices[earTipIndex] << 1;
|
|
||||||
int p3 = indices[nextIndex] << 1;
|
|
||||||
float p1x = vertices[p1], p1y = vertices[p1 + 1];
|
|
||||||
float p2x = vertices[p2], p2y = vertices[p2 + 1];
|
|
||||||
float p3x = vertices[p3], p3y = vertices[p3 + 1];
|
|
||||||
boolean[] isConcave = this.isConcaveArray.items;
|
|
||||||
|
|
||||||
for (int i = nextIndex(nextIndex, vertexCount); i != previousIndex; i = nextIndex(i, vertexCount)) {
|
|
||||||
if (isConcave[i]) {
|
|
||||||
int v = indices[i] << 1;
|
|
||||||
float vx = vertices[v], vy = vertices[v + 1];
|
|
||||||
if (positiveArea(p3x, p3y, p1x, p1y, vx, vy)) {
|
|
||||||
if (positiveArea(p1x, p1y, p2x, p2y, vx, vy)) {
|
|
||||||
if (positiveArea(p2x, p2y, p3x, p3y, vx, vy)) return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static private boolean isConcave (int index, int vertexCount, float[] vertices, short[] indices) {
|
static private boolean isConcave (int index, int vertexCount, float[] vertices, short[] indices) {
|
||||||
int previous = indices[previousIndex(index, vertexCount)] << 1;
|
int previous = indices[(vertexCount + index - 1) % vertexCount] << 1;
|
||||||
int current = indices[index] << 1;
|
int current = indices[index] << 1;
|
||||||
int next = indices[nextIndex(index, vertexCount)] << 1;
|
int next = indices[(index + 1) % vertexCount] << 1;
|
||||||
return !positiveArea(vertices[previous], vertices[previous + 1], vertices[current], vertices[current + 1], vertices[next],
|
return !positiveArea(vertices[previous], vertices[previous + 1], vertices[current], vertices[current + 1], vertices[next],
|
||||||
vertices[next + 1]);
|
vertices[next + 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static private int previousIndex (int index, int vertexCount) {
|
|
||||||
return (index == 0 ? vertexCount : index) - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static private int nextIndex (int index, int vertexCount) {
|
|
||||||
return (index + 1) % vertexCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
static private boolean positiveArea (float p1x, float p1y, float p2x, float p2y, float p3x, float p3y) {
|
static private boolean positiveArea (float p1x, float p1y, float p2x, float p2y, float p3x, float p3y) {
|
||||||
return p1x * (p3y - p2y) + p2x * (p1y - p3y) + p3x * (p2y - p1y) >= 0;
|
return p1x * (p3y - p2y) + p2x * (p1y - p3y) + p3x * (p2y - p1y) >= 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,12 +37,12 @@ import com.esotericsoftware.spine.Slot;
|
|||||||
import com.esotericsoftware.spine.attachments.ClippingAttachment;
|
import com.esotericsoftware.spine.attachments.ClippingAttachment;
|
||||||
|
|
||||||
public class SkeletonClipping {
|
public class SkeletonClipping {
|
||||||
private final Clipper clipper = new Clipper();
|
|
||||||
private final ConvexDecomposer decomposer = new ConvexDecomposer();
|
private final ConvexDecomposer decomposer = new ConvexDecomposer();
|
||||||
private final FloatArray clippingPolygon = new FloatArray();
|
private final FloatArray clippingPolygon = new FloatArray();
|
||||||
private final FloatArray clipOutput = new FloatArray(400);
|
private final FloatArray clipOutput = new FloatArray(128);
|
||||||
private final FloatArray clippedVertices = new FloatArray(400);
|
private final FloatArray clippedVertices = new FloatArray(128);
|
||||||
private final ShortArray clippedTriangles = new ShortArray(400);
|
private final ShortArray clippedTriangles = new ShortArray(128);
|
||||||
|
private final FloatArray scratch = new FloatArray();
|
||||||
|
|
||||||
private ClippingAttachment clipAttachment;
|
private ClippingAttachment clipAttachment;
|
||||||
private Array<FloatArray> clippingPolygons;
|
private Array<FloatArray> clippingPolygons;
|
||||||
@ -54,10 +54,10 @@ public class SkeletonClipping {
|
|||||||
int n = clip.getWorldVerticesLength();
|
int n = clip.getWorldVerticesLength();
|
||||||
float[] vertices = clippingPolygon.setSize(n);
|
float[] vertices = clippingPolygon.setSize(n);
|
||||||
clip.computeWorldVertices(slot, 0, n, vertices, 0, 2);
|
clip.computeWorldVertices(slot, 0, n, vertices, 0, 2);
|
||||||
Clipper.makeClockwise(clippingPolygon);
|
makeClockwise(clippingPolygon);
|
||||||
clippingPolygons = decomposer.decompose(clippingPolygon);
|
clippingPolygons = decomposer.decompose(clippingPolygon);
|
||||||
for (FloatArray polygon : clippingPolygons) {
|
for (FloatArray polygon : clippingPolygons) {
|
||||||
Clipper.makeClockwise(polygon);
|
makeClockwise(polygon);
|
||||||
polygon.add(polygon.items[0]);
|
polygon.add(polygon.items[0]);
|
||||||
polygon.add(polygon.items[1]);
|
polygon.add(polygon.items[1]);
|
||||||
}
|
}
|
||||||
@ -79,7 +79,6 @@ public class SkeletonClipping {
|
|||||||
public void clipTriangles (float[] vertices, int verticesLength, short[] triangles, int trianglesLength, float[] uvs,
|
public void clipTriangles (float[] vertices, int verticesLength, short[] triangles, int trianglesLength, float[] uvs,
|
||||||
float light, float dark, boolean twoColor) {
|
float light, float dark, boolean twoColor) {
|
||||||
|
|
||||||
Clipper clipper = this.clipper;
|
|
||||||
FloatArray clipOutput = this.clipOutput, clippedVertices = this.clippedVertices;
|
FloatArray clipOutput = this.clipOutput, clippedVertices = this.clippedVertices;
|
||||||
ShortArray clippedTriangles = this.clippedTriangles;
|
ShortArray clippedTriangles = this.clippedTriangles;
|
||||||
Object[] polygons = clippingPolygons.items;
|
Object[] polygons = clippingPolygons.items;
|
||||||
@ -105,7 +104,7 @@ public class SkeletonClipping {
|
|||||||
|
|
||||||
for (int p = 0; p < polygonsCount; p++) {
|
for (int p = 0; p < polygonsCount; p++) {
|
||||||
int s = clippedVertices.size;
|
int s = clippedVertices.size;
|
||||||
if (clipper.clip(x1, y1, x2, y2, x3, y3, (FloatArray)polygons[p], clipOutput)) {
|
if (clip(x1, y1, x2, y2, x3, y3, (FloatArray)polygons[p], clipOutput)) {
|
||||||
int clipOutputLength = clipOutput.size;
|
int clipOutputLength = clipOutput.size;
|
||||||
if (clipOutputLength == 0) continue;
|
if (clipOutputLength == 0) continue;
|
||||||
float d0 = y2 - y3, d1 = x3 - x2, d2 = x1 - x3, d4 = y3 - y1;
|
float d0 = y2 - y3, d1 = x3 - x2, d2 = x1 - x3, d4 = y3 - y1;
|
||||||
@ -196,6 +195,90 @@ public class SkeletonClipping {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Clips the input triangle against the convex, clockwise clipping area. If the triangle lies entirely within the clipping
|
||||||
|
* area, false is returned. The clipping area must duplicate the first vertex at the end of the vertices list. */
|
||||||
|
boolean clip (float x1, float y1, float x2, float y2, float x3, float y3, FloatArray clippingArea, FloatArray output) {
|
||||||
|
FloatArray originalOutput = output;
|
||||||
|
boolean clipped = false;
|
||||||
|
|
||||||
|
// Avoid copy at the end.
|
||||||
|
FloatArray input = null;
|
||||||
|
if (clippingArea.size % 4 >= 2) {
|
||||||
|
input = output;
|
||||||
|
output = scratch;
|
||||||
|
} else
|
||||||
|
input = scratch;
|
||||||
|
|
||||||
|
input.clear();
|
||||||
|
input.add(x1);
|
||||||
|
input.add(y1);
|
||||||
|
input.add(x2);
|
||||||
|
input.add(y2);
|
||||||
|
input.add(x3);
|
||||||
|
input.add(y3);
|
||||||
|
input.add(x1);
|
||||||
|
input.add(y1);
|
||||||
|
output.clear();
|
||||||
|
|
||||||
|
float[] clippingVertices = clippingArea.items;
|
||||||
|
int clippingVerticesLast = clippingArea.size - 4;
|
||||||
|
for (int i = 0;; i += 2) {
|
||||||
|
float edgeX = clippingVertices[i], edgeY = clippingVertices[i + 1];
|
||||||
|
float edgeX2 = clippingVertices[i + 2], edgeY2 = clippingVertices[i + 3];
|
||||||
|
float deltaX = edgeX - edgeX2, deltaY = edgeY - edgeY2;
|
||||||
|
|
||||||
|
float[] inputVertices = input.items;
|
||||||
|
int inputVerticesLength = input.size - 2, outputStart = output.size;
|
||||||
|
for (int ii = 0; ii < inputVerticesLength; ii += 2) {
|
||||||
|
float inputX = inputVertices[ii], inputY = inputVertices[ii + 1];
|
||||||
|
float inputX2 = inputVertices[ii + 2], inputY2 = inputVertices[ii + 3];
|
||||||
|
boolean side2 = deltaX * (inputY2 - edgeY2) - deltaY * (inputX2 - edgeX2) > 0;
|
||||||
|
if (deltaX * (inputY - edgeY2) - deltaY * (inputX - edgeX2) > 0) {
|
||||||
|
if (side2) { // v1 inside, v2 inside
|
||||||
|
output.add(inputX2);
|
||||||
|
output.add(inputY2);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// v1 inside, v2 outside
|
||||||
|
float c0 = inputY2 - inputY, c2 = inputX2 - inputX;
|
||||||
|
float ua = (c2 * (edgeY - inputY) - c0 * (edgeX - inputX)) / (c0 * (edgeX2 - edgeX) - c2 * (edgeY2 - edgeY));
|
||||||
|
output.add(edgeX + (edgeX2 - edgeX) * ua);
|
||||||
|
output.add(edgeY + (edgeY2 - edgeY) * ua);
|
||||||
|
} else if (side2) { // v1 outside, v2 inside
|
||||||
|
float c0 = inputY2 - inputY, c2 = inputX2 - inputX;
|
||||||
|
float ua = (c2 * (edgeY - inputY) - c0 * (edgeX - inputX)) / (c0 * (edgeX2 - edgeX) - c2 * (edgeY2 - edgeY));
|
||||||
|
output.add(edgeX + (edgeX2 - edgeX) * ua);
|
||||||
|
output.add(edgeY + (edgeY2 - edgeY) * ua);
|
||||||
|
output.add(inputX2);
|
||||||
|
output.add(inputY2);
|
||||||
|
}
|
||||||
|
clipped = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outputStart == output.size) { // All edges outside.
|
||||||
|
originalOutput.clear();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
output.add(output.items[0]);
|
||||||
|
output.add(output.items[1]);
|
||||||
|
|
||||||
|
if (i == clippingVerticesLast) break;
|
||||||
|
FloatArray temp = output;
|
||||||
|
output = input;
|
||||||
|
output.clear();
|
||||||
|
input = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (originalOutput != output) {
|
||||||
|
originalOutput.clear();
|
||||||
|
originalOutput.addAll(output.items, 0, output.size - 2);
|
||||||
|
} else
|
||||||
|
originalOutput.setSize(originalOutput.size - 2);
|
||||||
|
|
||||||
|
return clipped;
|
||||||
|
}
|
||||||
|
|
||||||
public FloatArray getClippedVertices () {
|
public FloatArray getClippedVertices () {
|
||||||
return clippedVertices;
|
return clippedVertices;
|
||||||
}
|
}
|
||||||
@ -203,4 +286,28 @@ public class SkeletonClipping {
|
|||||||
public ShortArray getClippedTriangles () {
|
public ShortArray getClippedTriangles () {
|
||||||
return clippedTriangles;
|
return clippedTriangles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void makeClockwise (FloatArray polygon) {
|
||||||
|
float[] vertices = polygon.items;
|
||||||
|
int verticeslength = polygon.size;
|
||||||
|
|
||||||
|
float area = vertices[verticeslength - 2] * vertices[1] - vertices[0] * vertices[verticeslength - 1], p1x, p1y, p2x, p2y;
|
||||||
|
for (int i = 0, n = verticeslength - 3; i < n; i += 2) {
|
||||||
|
p1x = vertices[i];
|
||||||
|
p1y = vertices[i + 1];
|
||||||
|
p2x = vertices[i + 2];
|
||||||
|
p2y = vertices[i + 3];
|
||||||
|
area += p1x * p2y - p2x * p1y;
|
||||||
|
}
|
||||||
|
if (area < 0) return;
|
||||||
|
|
||||||
|
for (int i = 0, lastX = verticeslength - 2, n = verticeslength >> 1; i < n; i += 2) {
|
||||||
|
float x = vertices[i], y = vertices[i + 1];
|
||||||
|
int other = lastX - i;
|
||||||
|
vertices[i] = vertices[other];
|
||||||
|
vertices[i + 1] = vertices[other + 1];
|
||||||
|
vertices[other] = x;
|
||||||
|
vertices[other + 1] = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user