UNPKG

@pixi-spine/runtime-3.8

Version:

Pixi runtime for spine 3.8 models

435 lines (431 loc) 14.2 kB
'use strict'; require('./attachments/Attachment.js'); var base = require('@pixi-spine/base'); var PathAttachment = require('./attachments/PathAttachment.js'); require('./attachments/RegionAttachment.js'); var PathConstraintData = require('./PathConstraintData.js'); const _PathConstraint = class { constructor(data, skeleton) { this.position = 0; this.spacing = 0; this.rotateMix = 0; this.translateMix = 0; this.spaces = new Array(); this.positions = new Array(); this.world = new Array(); this.curves = new Array(); this.lengths = new Array(); this.segments = new Array(); this.active = false; if (data == null) throw new Error("data cannot be null."); if (skeleton == null) throw new Error("skeleton cannot be null."); this.data = data; this.bones = new Array(); for (let i = 0, n = data.bones.length; i < n; i++) this.bones.push(skeleton.findBone(data.bones[i].name)); this.target = skeleton.findSlot(data.target.name); this.position = data.position; this.spacing = data.spacing; this.rotateMix = data.rotateMix; this.translateMix = data.translateMix; } isActive() { return this.active; } apply() { this.update(); } update() { const attachment = this.target.getAttachment(); if (!(attachment instanceof PathAttachment.PathAttachment)) return; const rotateMix = this.rotateMix; const translateMix = this.translateMix; const translate = translateMix > 0; const rotate = rotateMix > 0; if (!translate && !rotate) return; const data = this.data; const spacingMode = data.spacingMode; const lengthSpacing = spacingMode == PathConstraintData.SpacingMode.Length; const rotateMode = data.rotateMode; const tangents = rotateMode == base.RotateMode.Tangent; const scale = rotateMode == base.RotateMode.ChainScale; const boneCount = this.bones.length; const spacesCount = tangents ? boneCount : boneCount + 1; const bones = this.bones; const spaces = base.Utils.setArraySize(this.spaces, spacesCount); let lengths = null; const spacing = this.spacing; if (scale || lengthSpacing) { if (scale) lengths = base.Utils.setArraySize(this.lengths, boneCount); for (let i = 0, n = spacesCount - 1; i < n; ) { const bone = bones[i]; const setupLength = bone.data.length; if (setupLength < _PathConstraint.epsilon) { if (scale) lengths[i] = 0; spaces[++i] = 0; } else { const x = setupLength * bone.matrix.a; const y = setupLength * bone.matrix.b; const length = Math.sqrt(x * x + y * y); if (scale) lengths[i] = length; spaces[++i] = (lengthSpacing ? setupLength + spacing : spacing) * length / setupLength; } } } else { for (let i = 1; i < spacesCount; i++) spaces[i] = spacing; } const positions = this.computeWorldPositions( attachment, spacesCount, tangents, data.positionMode == base.PositionMode.Percent, spacingMode == PathConstraintData.SpacingMode.Percent ); let boneX = positions[0]; let boneY = positions[1]; let offsetRotation = data.offsetRotation; let tip = false; if (offsetRotation == 0) tip = rotateMode == base.RotateMode.Chain; else { tip = false; const p = this.target.bone.matrix; offsetRotation *= p.a * p.d - p.b * p.c > 0 ? base.MathUtils.degRad : -base.MathUtils.degRad; } for (let i = 0, p = 3; i < boneCount; i++, p += 3) { const bone = bones[i]; const mat = bone.matrix; mat.tx += (boneX - mat.tx) * translateMix; mat.ty += (boneY - mat.ty) * translateMix; const x = positions[p]; const y = positions[p + 1]; const dx = x - boneX; const dy = y - boneY; if (scale) { const length = lengths[i]; if (length != 0) { const s = (Math.sqrt(dx * dx + dy * dy) / length - 1) * rotateMix + 1; mat.a *= s; mat.b *= s; } } boneX = x; boneY = y; if (rotate) { const a = mat.a; const b = mat.c; const c = mat.b; const d = mat.d; let r = 0; let cos = 0; let sin = 0; if (tangents) if (tangents) r = positions[p - 1]; else if (spaces[i + 1] == 0) r = positions[p + 2]; else r = Math.atan2(dy, dx); r -= Math.atan2(c, a); if (tip) { cos = Math.cos(r); sin = Math.sin(r); const length = bone.data.length; boneX += (length * (cos * a - sin * c) - dx) * rotateMix; boneY += (length * (sin * a + cos * c) - dy) * rotateMix; } else { r += offsetRotation; } if (r > base.MathUtils.PI) r -= base.MathUtils.PI2; else if (r < -base.MathUtils.PI) r += base.MathUtils.PI2; r *= rotateMix; cos = Math.cos(r); sin = Math.sin(r); mat.a = cos * a - sin * c; mat.c = cos * b - sin * d; mat.b = sin * a + cos * c; mat.d = sin * b + cos * d; } bone.appliedValid = false; } } computeWorldPositions(path, spacesCount, tangents, percentPosition, percentSpacing) { const target = this.target; let position = this.position; const spaces = this.spaces; const out = base.Utils.setArraySize(this.positions, spacesCount * 3 + 2); let world = null; const closed = path.closed; let verticesLength = path.worldVerticesLength; let curveCount = verticesLength / 6; let prevCurve = _PathConstraint.NONE; if (!path.constantSpeed) { const lengths = path.lengths; curveCount -= closed ? 1 : 2; const pathLength2 = lengths[curveCount]; if (percentPosition) position *= pathLength2; if (percentSpacing) { for (let i = 0; i < spacesCount; i++) spaces[i] *= pathLength2; } world = base.Utils.setArraySize(this.world, 8); for (let i = 0, o = 0, curve = 0; i < spacesCount; i++, o += 3) { const space = spaces[i]; position += space; let p = position; if (closed) { p %= pathLength2; if (p < 0) p += pathLength2; curve = 0; } else if (p < 0) { if (prevCurve != _PathConstraint.BEFORE) { prevCurve = _PathConstraint.BEFORE; path.computeWorldVertices(target, 2, 4, world, 0, 2); } this.addBeforePosition(p, world, 0, out, o); continue; } else if (p > pathLength2) { if (prevCurve != _PathConstraint.AFTER) { prevCurve = _PathConstraint.AFTER; path.computeWorldVertices(target, verticesLength - 6, 4, world, 0, 2); } this.addAfterPosition(p - pathLength2, world, 0, out, o); continue; } for (; ; curve++) { const length = lengths[curve]; if (p > length) continue; if (curve == 0) p /= length; else { const prev = lengths[curve - 1]; p = (p - prev) / (length - prev); } break; } if (curve != prevCurve) { prevCurve = curve; if (closed && curve == curveCount) { path.computeWorldVertices(target, verticesLength - 4, 4, world, 0, 2); path.computeWorldVertices(target, 0, 4, world, 4, 2); } else path.computeWorldVertices(target, curve * 6 + 2, 8, world, 0, 2); } this.addCurvePosition(p, world[0], world[1], world[2], world[3], world[4], world[5], world[6], world[7], out, o, tangents || i > 0 && space == 0); } return out; } if (closed) { verticesLength += 2; world = base.Utils.setArraySize(this.world, verticesLength); path.computeWorldVertices(target, 2, verticesLength - 4, world, 0, 2); path.computeWorldVertices(target, 0, 2, world, verticesLength - 4, 2); world[verticesLength - 2] = world[0]; world[verticesLength - 1] = world[1]; } else { curveCount--; verticesLength -= 4; world = base.Utils.setArraySize(this.world, verticesLength); path.computeWorldVertices(target, 2, verticesLength, world, 0, 2); } const curves = base.Utils.setArraySize(this.curves, curveCount); let pathLength = 0; let x1 = world[0]; let y1 = world[1]; let cx1 = 0; let cy1 = 0; let cx2 = 0; let cy2 = 0; let x2 = 0; let y2 = 0; let tmpx = 0; let tmpy = 0; let dddfx = 0; let dddfy = 0; let ddfx = 0; let ddfy = 0; let dfx = 0; let dfy = 0; for (let i = 0, w = 2; i < curveCount; i++, w += 6) { cx1 = world[w]; cy1 = world[w + 1]; cx2 = world[w + 2]; cy2 = world[w + 3]; x2 = world[w + 4]; y2 = world[w + 5]; tmpx = (x1 - cx1 * 2 + cx2) * 0.1875; tmpy = (y1 - cy1 * 2 + cy2) * 0.1875; dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.09375; dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.09375; ddfx = tmpx * 2 + dddfx; ddfy = tmpy * 2 + dddfy; dfx = (cx1 - x1) * 0.75 + tmpx + dddfx * 0.16666667; dfy = (cy1 - y1) * 0.75 + tmpy + dddfy * 0.16666667; pathLength += Math.sqrt(dfx * dfx + dfy * dfy); dfx += ddfx; dfy += ddfy; ddfx += dddfx; ddfy += dddfy; pathLength += Math.sqrt(dfx * dfx + dfy * dfy); dfx += ddfx; dfy += ddfy; pathLength += Math.sqrt(dfx * dfx + dfy * dfy); dfx += ddfx + dddfx; dfy += ddfy + dddfy; pathLength += Math.sqrt(dfx * dfx + dfy * dfy); curves[i] = pathLength; x1 = x2; y1 = y2; } if (percentPosition) position *= pathLength; if (percentSpacing) { for (let i = 0; i < spacesCount; i++) spaces[i] *= pathLength; } const segments = this.segments; let curveLength = 0; for (let i = 0, o = 0, curve = 0, segment = 0; i < spacesCount; i++, o += 3) { const space = spaces[i]; position += space; let p = position; if (closed) { p %= pathLength; if (p < 0) p += pathLength; curve = 0; } else if (p < 0) { this.addBeforePosition(p, world, 0, out, o); continue; } else if (p > pathLength) { this.addAfterPosition(p - pathLength, world, verticesLength - 4, out, o); continue; } for (; ; curve++) { const length = curves[curve]; if (p > length) continue; if (curve == 0) p /= length; else { const prev = curves[curve - 1]; p = (p - prev) / (length - prev); } break; } if (curve != prevCurve) { prevCurve = curve; let ii = curve * 6; x1 = world[ii]; y1 = world[ii + 1]; cx1 = world[ii + 2]; cy1 = world[ii + 3]; cx2 = world[ii + 4]; cy2 = world[ii + 5]; x2 = world[ii + 6]; y2 = world[ii + 7]; tmpx = (x1 - cx1 * 2 + cx2) * 0.03; tmpy = (y1 - cy1 * 2 + cy2) * 0.03; dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 6e-3; dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 6e-3; ddfx = tmpx * 2 + dddfx; ddfy = tmpy * 2 + dddfy; dfx = (cx1 - x1) * 0.3 + tmpx + dddfx * 0.16666667; dfy = (cy1 - y1) * 0.3 + tmpy + dddfy * 0.16666667; curveLength = Math.sqrt(dfx * dfx + dfy * dfy); segments[0] = curveLength; for (ii = 1; ii < 8; ii++) { dfx += ddfx; dfy += ddfy; ddfx += dddfx; ddfy += dddfy; curveLength += Math.sqrt(dfx * dfx + dfy * dfy); segments[ii] = curveLength; } dfx += ddfx; dfy += ddfy; curveLength += Math.sqrt(dfx * dfx + dfy * dfy); segments[8] = curveLength; dfx += ddfx + dddfx; dfy += ddfy + dddfy; curveLength += Math.sqrt(dfx * dfx + dfy * dfy); segments[9] = curveLength; segment = 0; } p *= curveLength; for (; ; segment++) { const length = segments[segment]; if (p > length) continue; if (segment == 0) p /= length; else { const prev = segments[segment - 1]; p = segment + (p - prev) / (length - prev); } break; } this.addCurvePosition(p * 0.1, x1, y1, cx1, cy1, cx2, cy2, x2, y2, out, o, tangents || i > 0 && space == 0); } return out; } addBeforePosition(p, temp, i, out, o) { const x1 = temp[i]; const y1 = temp[i + 1]; const dx = temp[i + 2] - x1; const dy = temp[i + 3] - y1; const r = Math.atan2(dy, dx); out[o] = x1 + p * Math.cos(r); out[o + 1] = y1 + p * Math.sin(r); out[o + 2] = r; } addAfterPosition(p, temp, i, out, o) { const x1 = temp[i + 2]; const y1 = temp[i + 3]; const dx = x1 - temp[i]; const dy = y1 - temp[i + 1]; const r = Math.atan2(dy, dx); out[o] = x1 + p * Math.cos(r); out[o + 1] = y1 + p * Math.sin(r); out[o + 2] = r; } addCurvePosition(p, x1, y1, cx1, cy1, cx2, cy2, x2, y2, out, o, tangents) { if (p == 0 || isNaN(p)) p = 1e-4; const tt = p * p; const ttt = tt * p; const u = 1 - p; const uu = u * u; const uuu = uu * u; const ut = u * p; const ut3 = ut * 3; const uut3 = u * ut3; const utt3 = ut3 * p; const x = x1 * uuu + cx1 * uut3 + cx2 * utt3 + x2 * ttt; const y = y1 * uuu + cy1 * uut3 + cy2 * utt3 + y2 * ttt; out[o] = x; out[o + 1] = y; if (tangents) out[o + 2] = Math.atan2(y - (y1 * uu + cy1 * ut * 2 + cy2 * tt), x - (x1 * uu + cx1 * ut * 2 + cx2 * tt)); } }; let PathConstraint = _PathConstraint; PathConstraint.NONE = -1; PathConstraint.BEFORE = -2; PathConstraint.AFTER = -3; PathConstraint.epsilon = 1e-5; exports.PathConstraint = PathConstraint; //# sourceMappingURL=PathConstraint.js.map