mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-12 18:18:43 +08:00
[ts] Skeleton.getBounds() applies clipping, see #2515. Port of commits b043e5c, 637321a and 2049bed.
This commit is contained in:
parent
b3435430b8
commit
f3097222f9
@ -28,6 +28,7 @@
|
||||
*****************************************************************************/
|
||||
|
||||
import { Attachment } from "./attachments/Attachment.js";
|
||||
import { ClippingAttachment } from "./attachments/ClippingAttachment.js";
|
||||
import { MeshAttachment } from "./attachments/MeshAttachment.js";
|
||||
import { PathAttachment } from "./attachments/PathAttachment.js";
|
||||
import { RegionAttachment } from "./attachments/RegionAttachment.js";
|
||||
@ -35,6 +36,7 @@ import { Bone } from "./Bone.js";
|
||||
import { IkConstraint } from "./IkConstraint.js";
|
||||
import { PathConstraint } from "./PathConstraint.js";
|
||||
import { PhysicsConstraint } from "./PhysicsConstraint.js";
|
||||
import { SkeletonClipping } from "./SkeletonClipping.js";
|
||||
import { SkeletonData } from "./SkeletonData.js";
|
||||
import { Skin } from "./Skin.js";
|
||||
import { Slot } from "./Slot.js";
|
||||
@ -46,6 +48,7 @@ import { Color, Utils, MathUtils, Vector2, NumberArrayLike } from "./Utils.js";
|
||||
*
|
||||
* See [Instance objects](http://esotericsoftware.com/spine-runtime-architecture#Instance-objects) in the Spine Runtimes Guide. */
|
||||
export class Skeleton {
|
||||
private static quadTriangles = [0, 1, 2, 2, 3, 0];
|
||||
static yDown = false;
|
||||
|
||||
/** The skeleton's setup pose data. */
|
||||
@ -606,8 +609,9 @@ export class Skeleton {
|
||||
/** Returns the axis aligned bounding box (AABB) of the region and mesh attachments for the current pose.
|
||||
* @param offset An output value, the distance from the skeleton origin to the bottom left corner of the AABB.
|
||||
* @param size An output value, the width and height of the AABB.
|
||||
* @param temp Working memory to temporarily store attachments' computed world vertices. */
|
||||
getBounds (offset: Vector2, size: Vector2, temp: Array<number> = new Array<number>(2)) {
|
||||
* @param temp Working memory to temporarily store attachments' computed world vertices.
|
||||
* @param clipper {@link SkeletonClipping} to use. If <code>null</code>, no clipping is applied. */
|
||||
getBounds (offset: Vector2, size: Vector2, temp: Array<number> = new Array<number>(2), clipper: SkeletonClipping | null = null) {
|
||||
if (!offset) throw new Error("offset cannot be null.");
|
||||
if (!size) throw new Error("size cannot be null.");
|
||||
let drawOrder = this.drawOrder;
|
||||
@ -617,18 +621,29 @@ export class Skeleton {
|
||||
if (!slot.bone.active) continue;
|
||||
let verticesLength = 0;
|
||||
let vertices: NumberArrayLike | null = null;
|
||||
let triangles: NumberArrayLike | null = null;
|
||||
let attachment = slot.getAttachment();
|
||||
if (attachment instanceof RegionAttachment) {
|
||||
verticesLength = 8;
|
||||
vertices = Utils.setArraySize(temp, verticesLength, 0);
|
||||
(<RegionAttachment>attachment).computeWorldVertices(slot, vertices, 0, 2);
|
||||
attachment.computeWorldVertices(slot, vertices, 0, 2);
|
||||
triangles = Skeleton.quadTriangles;
|
||||
} else if (attachment instanceof MeshAttachment) {
|
||||
let mesh = (<MeshAttachment>attachment);
|
||||
verticesLength = mesh.worldVerticesLength;
|
||||
vertices = Utils.setArraySize(temp, verticesLength, 0);
|
||||
mesh.computeWorldVertices(slot, 0, verticesLength, vertices, 0, 2);
|
||||
triangles = mesh.triangles;
|
||||
} else if (attachment instanceof ClippingAttachment && clipper != null) {
|
||||
clipper.clipStart(slot, attachment);
|
||||
continue;
|
||||
}
|
||||
if (vertices) {
|
||||
if (vertices && triangles) {
|
||||
if (clipper != null && clipper.isClipping()) {
|
||||
clipper.clipTriangles(vertices, verticesLength, triangles, triangles.length);
|
||||
vertices = clipper.clippedVertices;
|
||||
verticesLength = clipper.clippedVertices.length;
|
||||
}
|
||||
for (let ii = 0, nn = vertices.length; ii < nn; ii += 2) {
|
||||
let x = vertices[ii], y = vertices[ii + 1];
|
||||
minX = Math.min(minX, x);
|
||||
@ -637,7 +652,9 @@ export class Skeleton {
|
||||
maxY = Math.max(maxY, y);
|
||||
}
|
||||
}
|
||||
if (clipper != null) clipper.clipEndWithSlot(slot);
|
||||
}
|
||||
if (clipper != null) clipper.clipEnd();
|
||||
offset.set(minX, minY);
|
||||
size.set(maxX - minX, maxY - minY);
|
||||
}
|
||||
|
||||
@ -80,7 +80,90 @@ export class SkeletonClipping {
|
||||
return this.clipAttachment != null;
|
||||
}
|
||||
|
||||
clipTriangles (vertices: NumberArrayLike, verticesLength: number, triangles: NumberArrayLike, trianglesLength: number, uvs: NumberArrayLike,
|
||||
clipTriangles(vertices: NumberArrayLike, verticesLength: number, triangles: NumberArrayLike, trianglesLength: number): void;
|
||||
clipTriangles(vertices: NumberArrayLike, verticesLength: number, triangles: NumberArrayLike, trianglesLength: number, uvs: NumberArrayLike,
|
||||
light: Color, dark: Color, twoColor: boolean): void;
|
||||
clipTriangles(vertices: NumberArrayLike, verticesLength: number, triangles: NumberArrayLike, trianglesLength: number, uvs?: NumberArrayLike,
|
||||
light?: Color, dark?: Color, twoColor?: boolean): void {
|
||||
|
||||
if (uvs && light && dark && typeof twoColor === 'boolean')
|
||||
this.clipTrianglesRender(vertices, verticesLength, triangles, trianglesLength, uvs, light, dark, twoColor);
|
||||
else
|
||||
this.clipTrianglesNoRender(vertices, verticesLength, triangles, trianglesLength);
|
||||
}
|
||||
private clipTrianglesNoRender (vertices: NumberArrayLike, verticesLength: number, triangles: NumberArrayLike, trianglesLength: number) {
|
||||
|
||||
let clipOutput = this.clipOutput, clippedVertices = this.clippedVertices;
|
||||
let clippedTriangles = this.clippedTriangles;
|
||||
let polygons = this.clippingPolygons!;
|
||||
let polygonsCount = polygons.length;
|
||||
let vertexSize = 2;
|
||||
|
||||
let index = 0;
|
||||
clippedVertices.length = 0;
|
||||
clippedTriangles.length = 0;
|
||||
outer:
|
||||
for (let i = 0; i < trianglesLength; i += 3) {
|
||||
let vertexOffset = triangles[i] << 1;
|
||||
let x1 = vertices[vertexOffset], y1 = vertices[vertexOffset + 1];
|
||||
|
||||
vertexOffset = triangles[i + 1] << 1;
|
||||
let x2 = vertices[vertexOffset], y2 = vertices[vertexOffset + 1];
|
||||
|
||||
vertexOffset = triangles[i + 2] << 1;
|
||||
let x3 = vertices[vertexOffset], y3 = vertices[vertexOffset + 1];
|
||||
|
||||
for (let p = 0; p < polygonsCount; p++) {
|
||||
let s = clippedVertices.length;
|
||||
if (this.clip(x1, y1, x2, y2, x3, y3, polygons[p], clipOutput)) {
|
||||
let clipOutputLength = clipOutput.length;
|
||||
if (clipOutputLength == 0) continue;
|
||||
|
||||
let clipOutputCount = clipOutputLength >> 1;
|
||||
let clipOutputItems = this.clipOutput;
|
||||
let clippedVerticesItems = Utils.setArraySize(clippedVertices, s + clipOutputCount * vertexSize);
|
||||
for (let ii = 0; ii < clipOutputLength; ii += 2) {
|
||||
let x = clipOutputItems[ii], y = clipOutputItems[ii + 1];
|
||||
clippedVerticesItems[s] = x;
|
||||
clippedVerticesItems[s + 1] = y;
|
||||
s += 2;
|
||||
}
|
||||
|
||||
s = clippedTriangles.length;
|
||||
let clippedTrianglesItems = Utils.setArraySize(clippedTriangles, s + 3 * (clipOutputCount - 2));
|
||||
clipOutputCount--;
|
||||
for (let ii = 1; ii < clipOutputCount; ii++) {
|
||||
clippedTrianglesItems[s] = index;
|
||||
clippedTrianglesItems[s + 1] = (index + ii);
|
||||
clippedTrianglesItems[s + 2] = (index + ii + 1);
|
||||
s += 3;
|
||||
}
|
||||
index += clipOutputCount + 1;
|
||||
|
||||
} else {
|
||||
let clippedVerticesItems = Utils.setArraySize(clippedVertices, s + 3 * vertexSize);
|
||||
clippedVerticesItems[s] = x1;
|
||||
clippedVerticesItems[s + 1] = y1;
|
||||
|
||||
clippedVerticesItems[s + 2] = x2;
|
||||
clippedVerticesItems[s + 3] = y2;
|
||||
|
||||
clippedVerticesItems[s + 4] = x3;
|
||||
clippedVerticesItems[s + 5] = y3;
|
||||
|
||||
s = clippedTriangles.length;
|
||||
let clippedTrianglesItems = Utils.setArraySize(clippedTriangles, s + 3);
|
||||
clippedTrianglesItems[s] = index;
|
||||
clippedTrianglesItems[s + 1] = (index + 1);
|
||||
clippedTrianglesItems[s + 2] = (index + 2);
|
||||
index += 3;
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private clipTrianglesRender (vertices: NumberArrayLike, verticesLength: number, triangles: NumberArrayLike, trianglesLength: number, uvs: NumberArrayLike,
|
||||
light: Color, dark: Color, twoColor: boolean) {
|
||||
|
||||
let clipOutput = this.clipOutput, clippedVertices = this.clippedVertices;
|
||||
|
||||
@ -205,4 +205,9 @@ export class SkeletonRenderer {
|
||||
}
|
||||
clipper.clipEnd();
|
||||
}
|
||||
|
||||
/** Returns the {@link SkeletonClipping} used by this renderer for use with e.g. {@link Skeleton.getBounds} **/
|
||||
public getSkeletonClipping (): SkeletonClipping {
|
||||
return this.clipper;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user