mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-04 14:24:53 +08:00
[ts] Refactor how textures are stored in texture regions, fix renderers, add custom attachment WebGL example.
This commit is contained in:
parent
6ec6c4c21c
commit
98f060b435
@ -32,6 +32,7 @@
|
||||
<li><a href="/spine-webgl/example">Example</a></li>
|
||||
<li><a href="/spine-webgl/example/barebones.html">Barebones</a></li>
|
||||
<li><a href="/spine-webgl/example/mix-and-match.html">Mix & match</a></li>
|
||||
<li><a href="/spine-webgl/example/custom-attachment.html">Custom attachment</a></li>
|
||||
<li><a href="/spine-webgl/example/drag-and-drop.html">Drag & drop</a></li>
|
||||
<li><a href="/spine-webgl/example/dress-up.html">Dress-up</a></li>
|
||||
<li><a href="/spine-webgl/example/bone-dragging.html">Bone dragging</a></li>
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
canvas = document.getElementById("canvas");
|
||||
context = canvas.getContext("2d");
|
||||
skeletonRenderer = new spine.SkeletonRenderer(context);
|
||||
// skeletonRenderer.triangleRendering = true;
|
||||
|
||||
// Load the assets.
|
||||
assetManager = new spine.AssetManager("https://esotericsoftware.com/files/examples/4.0/spineboy/export/");
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import { Utils, Color, Skeleton, RegionAttachment, TextureAtlasRegion, BlendMode, MeshAttachment, Slot } from "@esotericsoftware/spine-core";
|
||||
import { Utils, Color, Skeleton, RegionAttachment, BlendMode, MeshAttachment, Slot, TextureRegion, TextureAtlasRegion } from "@esotericsoftware/spine-core";
|
||||
import { CanvasTexture } from "./CanvasTexture";
|
||||
|
||||
const worldVertices = Utils.newFloatArray(8);
|
||||
@ -68,8 +68,9 @@ export class SkeletonRenderer {
|
||||
let attachment = slot.getAttachment();
|
||||
if (!(attachment instanceof RegionAttachment)) continue;
|
||||
attachment.computeWorldVertices(slot, worldVertices, 0, 2);
|
||||
let region: TextureAtlasRegion = <TextureAtlasRegion>attachment.region;
|
||||
let image: HTMLImageElement = (<CanvasTexture>region.page.texture).getImage() as HTMLImageElement;
|
||||
let region: TextureRegion = <TextureRegion>attachment.region;
|
||||
|
||||
let image: HTMLImageElement = (<CanvasTexture>region.texture).getImage() as HTMLImageElement;
|
||||
|
||||
let slotColor = slot.color;
|
||||
let regionColor = attachment.color;
|
||||
@ -98,7 +99,7 @@ export class SkeletonRenderer {
|
||||
ctx.translate(-w / 2, -h / 2);
|
||||
|
||||
ctx.globalAlpha = color.a;
|
||||
ctx.drawImage(image, region.x, region.y, w, h, 0, 0, w, h);
|
||||
ctx.drawImage(image, image.width * region.u, image.height * region.v, w, h, 0, 0, w, h);
|
||||
if (this.debugRendering) ctx.strokeRect(0, 0, w, h);
|
||||
ctx.restore();
|
||||
}
|
||||
@ -123,15 +124,13 @@ export class SkeletonRenderer {
|
||||
if (attachment instanceof RegionAttachment) {
|
||||
let regionAttachment = <RegionAttachment>attachment;
|
||||
vertices = this.computeRegionVertices(slot, regionAttachment, false);
|
||||
triangles = SkeletonRenderer.QUAD_TRIANGLES;
|
||||
region = <TextureAtlasRegion>regionAttachment.region;
|
||||
texture = (<CanvasTexture>region.page.texture).getImage() as HTMLImageElement;
|
||||
triangles = SkeletonRenderer.QUAD_TRIANGLES;
|
||||
texture = (<CanvasTexture>regionAttachment.region!.texture).getImage() as HTMLImageElement;
|
||||
} else if (attachment instanceof MeshAttachment) {
|
||||
let mesh = <MeshAttachment>attachment;
|
||||
vertices = this.computeMeshVertices(slot, mesh, false);
|
||||
triangles = mesh.triangles;
|
||||
let region = (<TextureAtlasRegion>mesh.region!.renderObject);
|
||||
texture = region.page.texture!.getImage() as HTMLImageElement;
|
||||
triangles = mesh.triangles;
|
||||
texture = (<CanvasTexture>mesh.region!.texture).getImage() as HTMLImageElement;
|
||||
} else
|
||||
continue;
|
||||
|
||||
|
||||
@ -55,8 +55,7 @@ export class AtlasAttachmentLoader implements AttachmentLoader {
|
||||
let path = sequence.getPath(basePath, i);
|
||||
let region = this.atlas.findRegion(path);
|
||||
if (region == null) throw new Error("Region not found in atlas: " + path + " (sequence: " + name + ")");
|
||||
regions[i] = region;
|
||||
regions[i].renderObject = regions[i];
|
||||
regions[i] = region;
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,8 +65,7 @@ export class AtlasAttachmentLoader implements AttachmentLoader {
|
||||
this.loadSequence(name, path, sequence);
|
||||
} else {
|
||||
let region = this.atlas.findRegion(path);
|
||||
if (!region) throw new Error("Region not found in atlas: " + path + " (region attachment: " + name + ")");
|
||||
region.renderObject = region;
|
||||
if (!region) throw new Error("Region not found in atlas: " + path + " (region attachment: " + name + ")");
|
||||
attachment.region = region;
|
||||
}
|
||||
return attachment;
|
||||
@ -79,8 +77,7 @@ export class AtlasAttachmentLoader implements AttachmentLoader {
|
||||
this.loadSequence(name, path, sequence);
|
||||
} else {
|
||||
let region = this.atlas.findRegion(path);
|
||||
if (!region) throw new Error("Region not found in atlas: " + path + " (mesh attachment: " + name + ")");
|
||||
region.renderObject = region;
|
||||
if (!region) throw new Error("Region not found in atlas: " + path + " (mesh attachment: " + name + ")");
|
||||
attachment.region = region;
|
||||
}
|
||||
return attachment;
|
||||
|
||||
@ -60,7 +60,7 @@ export enum TextureWrap {
|
||||
}
|
||||
|
||||
export class TextureRegion {
|
||||
renderObject: any;
|
||||
texture: any;
|
||||
u = 0; v = 0;
|
||||
u2 = 0; v2 = 0;
|
||||
width = 0; height = 0;
|
||||
|
||||
@ -236,6 +236,7 @@ export class TextureAtlasPage {
|
||||
width: number = 0;
|
||||
height: number = 0;
|
||||
pma: boolean = false;
|
||||
regions = new Array<TextureAtlasRegion>();
|
||||
|
||||
constructor (name: string) {
|
||||
this.name = name;
|
||||
@ -245,6 +246,8 @@ export class TextureAtlasPage {
|
||||
this.texture = texture;
|
||||
texture.setFilters(this.minFilter, this.magFilter);
|
||||
texture.setWraps(this.uWrap, this.vWrap);
|
||||
for (let region of this.regions)
|
||||
region.texture = texture;
|
||||
}
|
||||
}
|
||||
|
||||
@ -266,5 +269,6 @@ export class TextureAtlasRegion extends TextureRegion {
|
||||
super();
|
||||
this.page = page;
|
||||
this.name = name;
|
||||
page.regions.push(this);
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,8 +65,7 @@ export class RegionAttachment extends Attachment implements HasTextureRegion {
|
||||
|
||||
/** The name of the texture region for this attachment. */
|
||||
path: string;
|
||||
|
||||
private rendererObject: any = null;
|
||||
|
||||
region: TextureRegion | null = null;
|
||||
sequence: Sequence | null = null;
|
||||
|
||||
@ -195,8 +194,7 @@ export class RegionAttachment extends Attachment implements HasTextureRegion {
|
||||
|
||||
copy (): Attachment {
|
||||
let copy = new RegionAttachment(this.name, this.path);
|
||||
copy.region = this.region;
|
||||
copy.rendererObject = this.rendererObject;
|
||||
copy.region = this.region;
|
||||
copy.x = this.x;
|
||||
copy.y = this.y;
|
||||
copy.scaleX = this.scaleX;
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 563 B |
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.4 KiB |
@ -181,7 +181,7 @@ export class SkeletonMesh extends THREE.Object3D {
|
||||
region.computeWorldVertices(slot, vertices, 0, vertexSize);
|
||||
triangles = SkeletonMesh.QUAD_TRIANGLES;
|
||||
uvs = region.uvs;
|
||||
texture = <ThreeJsTexture>(<TextureAtlasRegion>region.region!.renderObject).page.texture;
|
||||
texture = <ThreeJsTexture>region.region!.texture;
|
||||
} else if (attachment instanceof MeshAttachment) {
|
||||
let mesh = <MeshAttachment>attachment;
|
||||
attachmentColor = mesh.color;
|
||||
@ -193,7 +193,7 @@ export class SkeletonMesh extends THREE.Object3D {
|
||||
mesh.computeWorldVertices(slot, 0, mesh.worldVerticesLength, vertices, 0, vertexSize);
|
||||
triangles = mesh.triangles;
|
||||
uvs = mesh.uvs;
|
||||
texture = <ThreeJsTexture>(<TextureAtlasRegion>mesh.region!.renderObject).page.texture;
|
||||
texture = <ThreeJsTexture>mesh.region!.texture;
|
||||
} else if (attachment instanceof ClippingAttachment) {
|
||||
let clip = <ClippingAttachment>(attachment);
|
||||
clipper.clipStart(slot, clip);
|
||||
|
||||
97
spine-ts/spine-webgl/example/custom-attachment.html
Normal file
97
spine-ts/spine-webgl/example/custom-attachment.html
Normal file
@ -0,0 +1,97 @@
|
||||
<html>
|
||||
<script src="../dist/iife/spine-webgl.js"></script>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body>
|
||||
<canvas id="canvas" style="position: absolute; width: 100%; height: 100%;"></canvas>
|
||||
<script>
|
||||
class App {
|
||||
constructor() {
|
||||
this.skeleton = null;
|
||||
this.animationState = null;
|
||||
}
|
||||
|
||||
loadAssets(canvas) {
|
||||
canvas.assetManager.loadBinary("assets/spineboy-pro.skel");
|
||||
canvas.assetManager.loadTextureAtlas("assets/spineboy-pma.atlas");
|
||||
canvas.assetManager.loadTexture("head.png");
|
||||
}
|
||||
|
||||
initialize(canvas) {
|
||||
let assetManager = canvas.assetManager;
|
||||
|
||||
// Create the texture atlas.
|
||||
let atlas = assetManager.require("assets/spineboy-pma.atlas");
|
||||
|
||||
// Create a AtlasAttachmentLoader that resolves region, mesh, boundingbox and path attachments
|
||||
let atlasLoader = new spine.AtlasAttachmentLoader(atlas);
|
||||
|
||||
// Create a SkeletonBinary instance for parsing the .skel file.
|
||||
let skeletonBinary = new spine.SkeletonBinary(atlasLoader);
|
||||
|
||||
// Set the scale to apply during parsing, parse the file, and create a new skeleton.
|
||||
skeletonBinary.scale = 1;
|
||||
let skeletonData = skeletonBinary.readSkeletonData(assetManager.require("assets/spineboy-pro.skel"));
|
||||
this.skeleton = new spine.Skeleton(skeletonData);
|
||||
|
||||
// Create an AnimationState, and set the "run" animation in looping mode.
|
||||
let animationStateData = new spine.AnimationStateData(skeletonData);
|
||||
this.animationState = new spine.AnimationState(animationStateData);
|
||||
this.animationState.setAnimation(0, "run", true);
|
||||
|
||||
// Get the custom head image from the asset manager and create an
|
||||
// attachment from it.
|
||||
let texture = assetManager.require("head.png");
|
||||
let textureRegion = {
|
||||
texture: texture,
|
||||
u: 0, v: 0, u2: 1, v2: 1,
|
||||
width: texture.getImage().width, height: texture.getImage().height,
|
||||
degrees: 0,
|
||||
offsetX: 0, offsetY: 0,
|
||||
originalWidth: texture.getImage().width, originalHeight: texture.getImage().height
|
||||
};
|
||||
let headSlot = this.skeleton.findSlot("head");
|
||||
let newHeadAttachment = headSlot.getAttachment().copy();
|
||||
newHeadAttachment.region = textureRegion;
|
||||
newHeadAttachment.updateRegion();
|
||||
headSlot.setAttachment(newHeadAttachment);
|
||||
}
|
||||
|
||||
update(canvas, delta) {
|
||||
// Update the animation state using the delta time.
|
||||
this.animationState.update(delta);
|
||||
// Apply the animation state to the skeleton.
|
||||
this.animationState.apply(this.skeleton);
|
||||
// Let the skeleton update the transforms of its bones.
|
||||
this.skeleton.updateWorldTransform();
|
||||
}
|
||||
|
||||
render(canvas) {
|
||||
let renderer = canvas.renderer;
|
||||
// Resize the viewport to the full canvas.
|
||||
renderer.resize(spine.ResizeMode.Expand);
|
||||
|
||||
// Clear the canvas with a light gray color.
|
||||
canvas.clear(0.2, 0.2, 0.2, 1);
|
||||
|
||||
// Begin rendering.
|
||||
renderer.begin();
|
||||
// Draw the skeleton
|
||||
renderer.drawSkeleton(this.skeleton, false);
|
||||
// Complete rendering.
|
||||
renderer.end();
|
||||
}
|
||||
}
|
||||
|
||||
new spine.SpineCanvas(document.getElementById("canvas"), {
|
||||
app: new App()
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
BIN
spine-ts/spine-webgl/example/head.png
Normal file
BIN
spine-ts/spine-webgl/example/head.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 62 KiB |
@ -113,7 +113,7 @@ export class SkeletonRenderer {
|
||||
region.computeWorldVertices(slot, renderable.vertices, 0, clippedVertexSize);
|
||||
triangles = SkeletonRenderer.QUAD_TRIANGLES;
|
||||
uvs = region.uvs;
|
||||
texture = <GLTexture>(<TextureAtlasRegion>region.region!.renderObject).page.texture;
|
||||
texture = <GLTexture>region.region!.texture;
|
||||
attachmentColor = region.color;
|
||||
} else if (attachment instanceof MeshAttachment) {
|
||||
let mesh = <MeshAttachment>attachment;
|
||||
@ -125,7 +125,7 @@ export class SkeletonRenderer {
|
||||
}
|
||||
mesh.computeWorldVertices(slot, 0, mesh.worldVerticesLength, renderable.vertices, 0, clippedVertexSize);
|
||||
triangles = mesh.triangles;
|
||||
texture = <GLTexture>(<TextureAtlasRegion>mesh.region!.renderObject).page.texture;
|
||||
texture = <GLTexture>mesh.region!.texture;
|
||||
uvs = mesh.uvs;
|
||||
attachmentColor = mesh.color;
|
||||
} else if (attachment instanceof ClippingAttachment) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user