Skip to content

Commit

Permalink
proper support for negative scale
Browse files Browse the repository at this point in the history
  • Loading branch information
flyover committed Apr 13, 2016
1 parent 713c26e commit a1a85d5
Show file tree
Hide file tree
Showing 3 changed files with 571 additions and 192 deletions.
80 changes: 55 additions & 25 deletions demo/render-ctx2d.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ RenderCtx2D.prototype.loadData = function(spine_data, atlas_data, images) {
var weight = attachment.vertices[index++];
var bone_key = spine_data.bone_keys[bone_index];
var bone = spine_data.bones[bone_key];
spine.Space.transform(bone.world_space, position, position);
spine.Affine.transform(bone.world_affine, position, position);
setup_position_x += position.x * weight;
setup_position_y += position.y * weight;
}
Expand Down Expand Up @@ -180,7 +180,7 @@ RenderCtx2D.prototype.updatePose = function(spine_pose, atlas_data) {
var v1 = ffd_keyframe1.vertices[ffd_index - ffd_keyframe1.offset] || 0;
position.y += spine.tween(v0, v1, pct);
++ffd_index;
spine.Space.transform(bone.world_space, position, position);
spine.Affine.transform(bone.world_affine, position, position);
blend_position_x += position.x * weight;
blend_position_y += position.y * weight;
}
Expand All @@ -204,7 +204,7 @@ RenderCtx2D.prototype.updatePose = function(spine_pose, atlas_data) {
var weight = attachment.vertices[index++];
var bone_key = spine_pose.bone_keys[bone_index];
var bone = spine_pose.bones[bone_key];
spine.Space.transform(bone.world_space, position, position);
spine.Affine.transform(bone.world_affine, position, position);
blend_position_x += position.x * weight;
blend_position_y += position.y * weight;
}
Expand Down Expand Up @@ -270,7 +270,7 @@ RenderCtx2D.prototype.drawPose = function(spine_pose, atlas_data) {
switch (attachment.type) {
case 'region':
var bone = spine_pose.bones[slot.bone_key];
ctxApplySpace(ctx, bone.world_space);
ctxApplyAffine(ctx, bone.world_affine);
ctxApplySpace(ctx, attachment.local_space);
ctxApplyAtlasSitePosition(ctx, site);
ctx.scale(attachment.width / 2, attachment.height / 2);
Expand All @@ -282,7 +282,7 @@ RenderCtx2D.prototype.drawPose = function(spine_pose, atlas_data) {
var slot_info = skin_info.slot_info_map[slot_key] || default_skin_info.slot_info_map[slot_key];
var attachment_info = slot_info.attachment_info_map[attachment_key];
var bone = spine_pose.bones[slot.bone_key];
ctxApplySpace(ctx, bone.world_space);
ctxApplyAffine(ctx, bone.world_affine);
ctxApplyAtlasSitePosition(ctx, site);
ctxDrawImageMesh(ctx, attachment_info.vertex_triangle, attachment_info.vertex_position, attachment_info.vertex_texcoord, image, site, page);
break;
Expand Down Expand Up @@ -323,7 +323,7 @@ RenderCtx2D.prototype.drawDebugPose = function(spine_pose, atlas_data) {
switch (attachment.type) {
case 'region':
var bone = spine_pose.bones[slot.bone_key];
ctxApplySpace(ctx, bone.world_space);
ctxApplyAffine(ctx, bone.world_affine);
ctxApplySpace(ctx, attachment.local_space);
ctxApplyAtlasSitePosition(ctx, site);
ctx.beginPath();
Expand All @@ -335,7 +335,7 @@ RenderCtx2D.prototype.drawDebugPose = function(spine_pose, atlas_data) {
break;
case 'boundingbox':
var bone = spine_pose.bones[slot.bone_key];
ctxApplySpace(ctx, bone.world_space);
ctxApplyAffine(ctx, bone.world_affine);
ctx.beginPath();
var x = 0;
attachment.vertices.forEach(function(value, index) {
Expand All @@ -346,7 +346,7 @@ RenderCtx2D.prototype.drawDebugPose = function(spine_pose, atlas_data) {
}
});
ctx.closePath();
ctx.strokeStyle = 'yellow';
ctx.strokeStyle = 'cyan';
ctx.stroke();
break;
case 'mesh':
Expand All @@ -355,7 +355,7 @@ RenderCtx2D.prototype.drawDebugPose = function(spine_pose, atlas_data) {
var slot_info = skin_info.slot_info_map[slot_key] || default_skin_info.slot_info_map[slot_key];
var attachment_info = slot_info.attachment_info_map[attachment_key];
var bone = spine_pose.bones[slot.bone_key];
ctxApplySpace(ctx, bone.world_space);
ctxApplyAffine(ctx, bone.world_affine);
ctxApplyAtlasSitePosition(ctx, site);
ctxDrawMesh(ctx, attachment_info.vertex_triangle, attachment_info.vertex_position, 'rgba(127,127,127,1.0)', 'rgba(127,127,127,0.25)');
break;
Expand All @@ -374,8 +374,18 @@ RenderCtx2D.prototype.drawDebugPose = function(spine_pose, atlas_data) {

spine_pose.iterateBones(function(bone_key, bone) {
ctx.save();
ctxApplySpace(ctx, bone.world_space);
ctxApplyAffine(ctx, bone.world_affine);
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(0.1 * bone.length, -0.1 * bone.length);
ctx.lineTo(bone.length, 0);
ctx.lineTo(0.1 * bone.length, 0.1 * bone.length);
ctx.closePath();
ctx.strokeStyle = 'white';
ctx.stroke();
ctxDrawPoint(ctx);
ctx.scale(1, -1);
ctx.fillText(bone_key, 0, 0);
ctx.restore();
});

Expand Down Expand Up @@ -403,7 +413,7 @@ RenderCtx2D.prototype.drawDebugData = function(spine_pose, atlas_data) {
switch (attachment.type) {
case 'region':
var bone = spine_pose.data.bones[slot.bone_key];
ctxApplySpace(ctx, bone.world_space);
ctxApplyAffine(ctx, bone.world_affine);
ctxApplySpace(ctx, attachment.local_space);
ctxApplyAtlasSitePosition(ctx, site);
ctx.beginPath();
Expand All @@ -415,7 +425,7 @@ RenderCtx2D.prototype.drawDebugData = function(spine_pose, atlas_data) {
break;
case 'boundingbox':
var bone = spine_pose.data.bones[slot.bone_key];
ctxApplySpace(ctx, bone.world_space);
ctxApplyAffine(ctx, bone.world_affine);
ctx.beginPath();
var x = 0;
attachment.vertices.forEach(function(value, index) {
Expand All @@ -426,7 +436,7 @@ RenderCtx2D.prototype.drawDebugData = function(spine_pose, atlas_data) {
}
});
ctx.closePath();
ctx.strokeStyle = 'yellow';
ctx.strokeStyle = 'cyan';
ctx.stroke();
break;
case 'mesh':
Expand All @@ -435,7 +445,7 @@ RenderCtx2D.prototype.drawDebugData = function(spine_pose, atlas_data) {
var slot_info = skin_info.slot_info_map[slot_key] || default_skin_info.slot_info_map[slot_key];
var attachment_info = slot_info.attachment_info_map[attachment_key];
var bone = spine_pose.data.bones[slot.bone_key];
ctxApplySpace(ctx, bone.world_space);
ctxApplyAffine(ctx, bone.world_affine);
ctxApplyAtlasSitePosition(ctx, site);
ctxDrawMesh(ctx, attachment_info.vertex_triangle, attachment_info.vertex_position, 'rgba(127,127,127,1.0)', 'rgba(127,127,127,0.25)');
break;
Expand All @@ -454,14 +464,30 @@ RenderCtx2D.prototype.drawDebugData = function(spine_pose, atlas_data) {

spine_pose.data.iterateBones(function(bone_key, bone) {
ctx.save();
ctxApplySpace(ctx, bone.world_space);
ctxApplyAffine(ctx, bone.world_affine);
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(0.1 * bone.length, -0.1 * bone.length);
ctx.lineTo(bone.length, 0);
ctx.lineTo(0.1 * bone.length, 0.1 * bone.length);
ctx.closePath();
ctx.strokeStyle = 'white';
ctx.stroke();
ctxDrawPoint(ctx);
ctx.scale(1, -1);
ctx.fillText(bone_key, 0, 0);
ctx.restore();
});

ctxDrawIkConstraints(ctx, spine_pose.data, spine_pose.data.bones);
}

function ctxApplyAffine(ctx, affine) {
if (affine) {
ctx.transform(affine.matrix.a, affine.matrix.c, affine.matrix.b, affine.matrix.d, affine.vector.x, affine.vector.y);
}
}

function ctxApplySpace(ctx, space) {
if (space) {
ctx.translate(space.position.x, space.position.y);
Expand Down Expand Up @@ -600,44 +626,48 @@ function ctxDrawIkConstraints(ctx, data, bones) {
var bone = bones[ikc.bone_keys[0]];

ctx.beginPath();
ctx.moveTo(target.world_space.position.x, target.world_space.position.y);
ctx.lineTo(bone.world_space.position.x, bone.world_space.position.y);
ctx.moveTo(target.world_affine.vector.x, target.world_affine.vector.y);
ctx.lineTo(bone.world_affine.vector.x, bone.world_affine.vector.y);
ctx.strokeStyle = 'yellow';
ctx.stroke();

ctx.save();
ctxApplySpace(ctx, target.world_space);
ctxApplyAffine(ctx, target.world_affine);
ctxDrawCircle(ctx, 'yellow', 1.5);
ctx.restore();

ctx.save();
ctxApplySpace(ctx, bone.world_space);
ctxApplyAffine(ctx, bone.world_affine);
ctxDrawCircle(ctx, 'yellow', 0.5);
ctx.translate(bone.length, 0);
ctxDrawCircle(ctx, 'yellow', 1.5);
ctx.restore();
break;
case 2:
var parent = bones[ikc.bone_keys[0]];
var child = bones[ikc.bone_keys[1]];

ctx.beginPath();
ctx.moveTo(target.world_space.position.x, target.world_space.position.y);
ctx.lineTo(child.world_space.position.x, child.world_space.position.y);
ctx.lineTo(parent.world_space.position.x, parent.world_space.position.y);
ctx.moveTo(target.world_affine.vector.x, target.world_affine.vector.y);
ctx.lineTo(child.world_affine.vector.x, child.world_affine.vector.y);
ctx.lineTo(parent.world_affine.vector.x, parent.world_affine.vector.y);
ctx.strokeStyle = 'yellow';
ctx.stroke();

ctx.save();
ctxApplySpace(ctx, target.world_space);
ctxApplyAffine(ctx, target.world_affine);
ctxDrawCircle(ctx, 'yellow', 1.5);
ctx.restore();

ctx.save();
ctxApplySpace(ctx, child.world_space);
ctxApplyAffine(ctx, child.world_affine);
ctxDrawCircle(ctx, 'yellow', 0.75);
ctx.translate(child.length, 0);
ctxDrawCircle(ctx, 'yellow', 1.5);
ctx.restore();

ctx.save();
ctxApplySpace(ctx, parent.world_space);
ctxApplyAffine(ctx, parent.world_affine);
ctxDrawCircle(ctx, 'yellow', 0.5);
ctx.restore();
break;
Expand Down
31 changes: 25 additions & 6 deletions demo/render-webgl.js
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ RenderWebGL.prototype.loadData = function(spine_data, atlas_data, images) {

spine_data.iterateBones(function(bone_key, bone) {
var bone_info = render.bone_info_map[bone_key] = {};
bone_info.setup_space = spine.Space.invert(bone.world_space, new spine.Space());
bone_info.setup_affine = spine.Affine.invert(bone.world_affine, new spine.Affine());
});

spine_data.iterateSkins(function(skin_key, skin) {
Expand Down Expand Up @@ -312,7 +312,7 @@ RenderWebGL.prototype.loadData = function(spine_data, atlas_data, images) {
}
var bone_key = spine_data.bone_keys[blend.bone_index];
var bone = spine_data.bones[bone_key];
spine.Space.transform(bone.world_space, blend.position, blend_position);
spine.Affine.transform(bone.world_affine, blend.position, blend_position);
position_x += blend_position.x * blend.weight;
position_y += blend_position.y * blend.weight;
// index into gl_skin_shader_modelview_array, not spine_pose.data.bone_keys
Expand Down Expand Up @@ -543,7 +543,7 @@ RenderWebGL.prototype.drawPose = function(spine_pose, atlas_data) {
switch (attachment.type) {
case 'region':
var bone = spine_pose.bones[slot.bone_key];
mat3x3ApplySpace(gl_modelview, bone.world_space);
mat3x3ApplyAffine(gl_modelview, bone.world_affine);
mat3x3ApplySpace(gl_modelview, attachment.local_space);
mat3x3Scale(gl_modelview, attachment.width / 2, attachment.height / 2);
mat3x3ApplyAtlasSitePosition(gl_modelview, site);
Expand Down Expand Up @@ -580,7 +580,7 @@ RenderWebGL.prototype.drawPose = function(spine_pose, atlas_data) {
var slot_info = skin_info.slot_info_map[slot_key] || default_skin_info.slot_info_map[slot_key];
var attachment_info = slot_info.attachment_info_map[attachment_key];
var bone = spine_pose.bones[slot.bone_key];
mat3x3ApplySpace(gl_modelview, bone.world_space);
mat3x3ApplyAffine(gl_modelview, bone.world_affine);
mat3x3ApplyAtlasSitePosition(gl_modelview, site);

var anim = spine_pose.data.anims[spine_pose.anim_key];
Expand Down Expand Up @@ -686,8 +686,8 @@ RenderWebGL.prototype.drawPose = function(spine_pose, atlas_data) {
if (index < render.gl_skin_shader_modelview_count) {
var modelview = render.gl_skin_shader_modelview_array.subarray(index * 9, (index + 1) * 9);
mat3x3Copy(modelview, gl_modelview);
mat3x3ApplySpace(modelview, bone.world_space);
mat3x3ApplySpace(modelview, bone_info.setup_space);
mat3x3ApplyAffine(modelview, bone.world_affine);
mat3x3ApplyAffine(modelview, bone_info.setup_affine);
mat3x3ApplyAtlasSitePosition(modelview, site);
}
}
Expand Down Expand Up @@ -875,6 +875,25 @@ function mat3x3Transform(m, v, out) {
return out;
}

function mat3x3ApplyAffine(m, affine) {
if (affine) {
var a = affine.matrix.a, b = affine.matrix.b, x = affine.vector.x;
var c = affine.matrix.c, d = affine.matrix.d, y = affine.vector.y;
var m00 = m[0], m01 = m[1], m02 = m[2];
var m10 = m[3], m11 = m[4], m12 = m[5];
m[0] = a * m00 + c * m10;
m[1] = a * m01 + c * m11;
m[2] = a * m02 + c * m12;
m[3] = b * m00 + d * m10;
m[4] = b * m01 + d * m11;
m[5] = b * m02 + d * m12;
m[6] += x * m00 + y * m10;
m[7] += x * m01 + y * m11;
m[8] += x * m02 + y * m12;
}
return m;
}

function mat3x3ApplySpace(m, space) {
if (space) {
mat3x3Translate(m, space.position.x, space.position.y);
Expand Down
Loading

0 comments on commit a1a85d5

Please sign in to comment.