Skip to content

Commit

Permalink
Blend modes for all runtimes.
Browse files Browse the repository at this point in the history
  • Loading branch information
NathanSweet committed Apr 2, 2015
1 parent 142e770 commit f8a76c6
Show file tree
Hide file tree
Showing 38 changed files with 386 additions and 132 deletions.
2 changes: 1 addition & 1 deletion spine-as3/spine-as3-example/src/spineboy.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
{ "name": "goggles", "bone": "head", "attachment": "goggles" },
{ "name": "front_bracer", "bone": "front_bracer", "attachment": "front_bracer" },
{ "name": "front_fist", "bone": "front_fist", "attachment": "front_fist_closed" },
{ "name": "muzzle", "bone": "gunTip", "additive": true },
{ "name": "muzzle", "bone": "gunTip", "blend": "additive" },
{ "name": "head-bb", "bone": "head" }
],
"skins": {
Expand Down
46 changes: 46 additions & 0 deletions spine-as3/spine-as3/src/spine/BlendMode.as
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/******************************************************************************
* Spine Runtimes Software License
* Version 2.1
*
* Copyright (c) 2013, Esoteric Software
* All rights reserved.
*
* You are granted a perpetual, non-exclusive, non-sublicensable and
* non-transferable license to install, execute and perform the Spine Runtimes
* Software (the "Software") solely for internal use. Without the written
* permission of Esoteric Software (typically granted by licensing Spine), you
* may not (a) modify, translate, adapt or otherwise create derivative works,
* improvements of the Software or develop new applications using the Software
* 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 SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) 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 spine {

public class BlendMode {
public static const normal:BlendMode = new BlendMode(0);
public static const additive:BlendMode = new BlendMode(1);
public static const multiply:BlendMode = new BlendMode(2);
public static const screen:BlendMode = new BlendMode(3);

public var ordinal:int;

public function BlendMode (ordinal:int) {
this.ordinal = ordinal;
}
}

}
2 changes: 1 addition & 1 deletion spine-as3/spine-as3/src/spine/SkeletonJson.as
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ public class SkeletonJson {
}

slotData.attachmentName = slotMap["attachment"];
slotData.additiveBlending = slotMap["additive"];
slotData.blendMode = BlendMode[slotMap["blend"] || "normal"];

skeletonData.slots[skeletonData.slots.length] = slotData;
}
Expand Down
2 changes: 1 addition & 1 deletion spine-as3/spine-as3/src/spine/SlotData.as
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public class SlotData {
public var b:Number = 1;
public var a:Number = 1;
public var attachmentName:String;
public var additiveBlending:Boolean;
public var blendMode:BlendMode;

public function SlotData (name:String, boneData:BoneData) {
if (name == null) throw new ArgumentError("name cannot be null.");
Expand Down
4 changes: 3 additions & 1 deletion spine-as3/spine-as3/src/spine/flash/SkeletonSprite.as
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ import spine.attachments.RegionAttachment;
public class SkeletonSprite extends Sprite {
static private var tempPoint:Point = new Point();
static private var tempMatrix:Matrix = new Matrix();
static private var blendModes:Vector.<String> = new <String>[
BlendMode.NORMAL, BlendMode.ADD, BlendMode.MULTIPLY, BlendMode.SCREEN];

private var _skeleton:Skeleton;
public var timeScale:Number = 1;
Expand Down Expand Up @@ -119,7 +121,7 @@ public class SkeletonSprite extends Sprite {
regionAttachment["wrapper"] = wrapper;
}

wrapper.blendMode = slot.data.additiveBlending ? BlendMode.ADD : BlendMode.NORMAL;
wrapper.blendMode = blendModes[slot.data.blendMode.ordinal];

var colorTransform:ColorTransform = wrapper.transform.colorTransform;
colorTransform.redMultiplier = skeleton.r * slot.r * regionAttachment.r;
Expand Down
2 changes: 1 addition & 1 deletion spine-c/include/spine/Slot.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ typedef struct spSlot {
spSlot() :
data(0),
bone(0),
r(0), b(0), g(0), a(0),
r(0), g(0), b(0), a(0),
attachment(0),
attachmentVerticesCapacity(0),
attachmentVerticesCount(0),
Expand Down
13 changes: 11 additions & 2 deletions spine-c/include/spine/SlotData.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,20 +37,24 @@
extern "C" {
#endif

typedef enum {
SP_BLEND_MODE_NORMAL, SP_BLEND_MODE_ADDITIVE, SP_BLEND_MODE_MULTIPLY, SP_BLEND_MODE_SCREEN
} spBlendMode;

typedef struct spSlotData {
const char* const name;
const spBoneData* const boneData;
const char* attachmentName;
float r, g, b, a;
int/*bool*/additiveBlending;
spBlendMode blendMode;

#ifdef __cplusplus
spSlotData() :
name(0),
boneData(0),
attachmentName(0),
r(0), g(0), b(0), a(0),
additiveBlending(0) {
blendMode(SP_BLEND_MODE_NORMAL) {
}
#endif
} spSlotData;
Expand All @@ -62,6 +66,11 @@ void spSlotData_dispose (spSlotData* self);
void spSlotData_setAttachmentName (spSlotData* self, const char* attachmentName);

#ifdef SPINE_SHORT_NAMES
typedef spBlendMode BlendMode;
#define BLEND_MODE_NORMAL SP_BLEND_MODE_NORMAL
#define BLEND_MODE_ADDITIVE SP_BLEND_MODE_ADDITIVE
#define BLEND_MODE_MULTIPLY SP_BLEND_MODE_MULTIPLY
#define BLEND_MODE_SCREEN SP_BLEND_MODE_SCREEN
typedef spSlotData SlotData;
#define SlotData_create(...) spSlotData_create(__VA_ARGS__)
#define SlotData_dispose(...) spSlotData_dispose(__VA_ARGS__)
Expand Down
18 changes: 13 additions & 5 deletions spine-c/src/spine/SkeletonJson.c
Original file line number Diff line number Diff line change
Expand Up @@ -519,7 +519,7 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha
for (slotMap = slots->child, i = 0; slotMap; slotMap = slotMap->next, ++i) {
spSlotData* slotData;
const char* color;
Json *attachmentItem;
Json *item;

const char* boneName = Json_getString(slotMap, "bone", 0);
spBoneData* boneData = spSkeletonData_findBone(skeletonData, boneName);
Expand All @@ -539,10 +539,18 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha
slotData->a = toColor(color, 3);
}

attachmentItem = Json_getItem(slotMap, "attachment");
if (attachmentItem) spSlotData_setAttachmentName(slotData, attachmentItem->valueString);

slotData->additiveBlending = Json_getInt(slotMap, "additive", 0);
item = Json_getItem(slotMap, "attachment");
if (item) spSlotData_setAttachmentName(slotData, item->valueString);

item = Json_getItem(slotMap, "blend");
if (item) {
if (strcmp(item->valueString, "additive") == 0)
slotData->blendMode = SP_BLEND_MODE_ADDITIVE;
else if (strcmp(item->valueString, "multiply") == 0)
slotData->blendMode = SP_BLEND_MODE_MULTIPLY;
else if (strcmp(item->valueString, "screen") == 0)
slotData->blendMode = SP_BLEND_MODE_SCREEN;
}

skeletonData->slots[i] = slotData;
}
Expand Down
20 changes: 16 additions & 4 deletions spine-cocos2d-iphone/2/src/spine/SkeletonRenderer.m
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ - (void) draw {
_skeleton->b = nodeColor.b / (float)255;
_skeleton->a = self.opacity / (float)255;

int additive = -1;
int blendMode = -1;
ccColor4B color;
const float* uvs = 0;
int verticesCount = 0;
Expand Down Expand Up @@ -199,10 +199,22 @@ - (void) draw {
default: ;
}
if (texture) {
if (slot->data->additiveBlending != additive) {
if (slot->data->blendMode != blendMode) {
[batch flush];
ccGLBlendFunc(_blendFunc.src, slot->data->additiveBlending ? GL_ONE : _blendFunc.dst);
additive = slot->data->additiveBlending;
blendMode = slot->data->blendMode;
switch (slot->data->blendMode) {
case SP_BLEND_MODE_ADDITIVE:
ccGLBlendFunc(_premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA, GL_ONE);
break;
case SP_BLEND_MODE_MULTIPLY:
ccGLBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA);
break;
case SP_BLEND_MODE_SCREEN:
ccGLBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR);
break;
default:
ccGLBlendFunc(_premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
}
color.a = _skeleton->a * slot->a * a * 255;
float multiplier = _premultipliedAlpha ? color.a : 255;
Expand Down
5 changes: 3 additions & 2 deletions spine-cocos2d-iphone/3/src/spine/SkeletonRenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,11 @@
bool _debugBones;
bool _premultipliedAlpha;
ccBlendFunc _blendFunc;
CCDrawNode *_drawNode;
CCDrawNode* _drawNode;
bool _ownsSkeletonData;
spAtlas* _atlas;
float* worldVertices;
float* _worldVertices;
CCBlendMode* screenMode;
}

+ (id) skeletonWithData:(spSkeletonData*)skeletonData ownsSkeletonData:(bool)ownsSkeletonData;
Expand Down
76 changes: 47 additions & 29 deletions spine-cocos2d-iphone/3/src/spine/SkeletonRenderer.m
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ + (id) skeletonWithFile:(NSString*)skeletonDataFile atlasFile:(NSString*)atlasFi
- (void) initialize:(spSkeletonData*)skeletonData ownsSkeletonData:(bool)ownsSkeletonData {
_ownsSkeletonData = ownsSkeletonData;

worldVertices = MALLOC(float, 1000); // Max number of vertices per mesh.
_worldVertices = MALLOC(float, 1000); // Max number of vertices per mesh.

_skeleton = spSkeleton_create(skeletonData);
_rootBone = _skeleton->bones[0];
Expand All @@ -74,6 +74,12 @@ - (void) initialize:(spSkeletonData*)skeletonData ownsSkeletonData:(bool)ownsSke
[self addChild:_drawNode];

[self setShader:[CCShader positionTextureColorShader]];

_premultipliedAlpha = true;
screenMode = [CCBlendMode blendModeWithOptions:@{
CCBlendFuncSrcColor: @(GL_ONE),
CCBlendFuncDstColor: @(GL_ONE_MINUS_SRC_COLOR)}
];
}

- (id) initWithData:(spSkeletonData*)skeletonData ownsSkeletonData:(bool)ownsSkeletonData {
Expand Down Expand Up @@ -127,7 +133,7 @@ - (void) dealloc {
if (_ownsSkeletonData) spSkeletonData_dispose(_skeleton->data);
if (_atlas) spAtlas_dispose(_atlas);
spSkeleton_dispose(_skeleton);
FREE(worldVertices);
FREE(_worldVertices);
[super dealloc];
}

Expand All @@ -138,7 +144,7 @@ -(void)draw:(CCRenderer *)renderer transform:(const GLKMatrix4 *)transform {
_skeleton->b = nodeColor.blue;
_skeleton->a = self.displayedOpacity;

int additive = -1;
int blendMode = -1;
const float* uvs = 0;
int verticesCount = 0;
const int* triangles = 0;
Expand All @@ -151,7 +157,7 @@ -(void)draw:(CCRenderer *)renderer transform:(const GLKMatrix4 *)transform {
switch (slot->attachment->type) {
case SP_ATTACHMENT_REGION: {
spRegionAttachment* attachment = (spRegionAttachment*)slot->attachment;
spRegionAttachment_computeWorldVertices(attachment, slot->bone, worldVertices);
spRegionAttachment_computeWorldVertices(attachment, slot->bone, _worldVertices);
texture = [self getTextureForRegion:attachment];
uvs = attachment->uvs;
verticesCount = 8;
Expand All @@ -165,7 +171,7 @@ -(void)draw:(CCRenderer *)renderer transform:(const GLKMatrix4 *)transform {
}
case SP_ATTACHMENT_MESH: {
spMeshAttachment* attachment = (spMeshAttachment*)slot->attachment;
spMeshAttachment_computeWorldVertices(attachment, slot, worldVertices);
spMeshAttachment_computeWorldVertices(attachment, slot, _worldVertices);
texture = [self getTextureForMesh:attachment];
uvs = attachment->uvs;
verticesCount = attachment->verticesCount;
Expand All @@ -179,7 +185,7 @@ -(void)draw:(CCRenderer *)renderer transform:(const GLKMatrix4 *)transform {
}
case SP_ATTACHMENT_SKINNED_MESH: {
spSkinnedMeshAttachment* attachment = (spSkinnedMeshAttachment*)slot->attachment;
spSkinnedMeshAttachment_computeWorldVertices(attachment, slot, worldVertices);
spSkinnedMeshAttachment_computeWorldVertices(attachment, slot, _worldVertices);
texture = [self getTextureForSkinnedMesh:attachment];
uvs = attachment->uvs;
verticesCount = attachment->uvsCount;
Expand All @@ -194,30 +200,42 @@ -(void)draw:(CCRenderer *)renderer transform:(const GLKMatrix4 *)transform {
default: ;
}
if (texture) {
if (slot->data->additiveBlending != additive) {
[self setBlendMode:[CCBlendMode blendModeWithOptions:@{CCBlendFuncSrcColor: @(_blendFunc.src),CCBlendFuncDstColor: @(slot->data->additiveBlending ? GL_ONE : _blendFunc.dst)}]];
additive = slot->data->additiveBlending;
if (slot->data->blendMode != blendMode) {
blendMode = slot->data->blendMode;
switch (slot->data->blendMode) {
case SP_BLEND_MODE_ADDITIVE:
[self setBlendMode:[CCBlendMode addMode]];
break;
case SP_BLEND_MODE_MULTIPLY:
[self setBlendMode:[CCBlendMode multiplyMode]];
break;
case SP_BLEND_MODE_SCREEN:
[self setBlendMode:screenMode];
break;
default:
[self setBlendMode:_premultipliedAlpha ? [CCBlendMode premultipliedAlphaMode] : [CCBlendMode alphaMode]];
}
}
if (_premultipliedAlpha) {
a *= _skeleton->a * slot->a;
r *= _skeleton->r * slot->r * a;
g *= _skeleton->g * slot->g * a;
b *= _skeleton->b * slot->b * a;
} else {
a *= _skeleton->a * slot->a;
r *= _skeleton->r * slot->r;
g *= _skeleton->g * slot->g;
b *= _skeleton->b * slot->b;
a *= _skeleton->a * slot->a;
r *= _skeleton->r * slot->r * a;
g *= _skeleton->g * slot->g * a;
b *= _skeleton->b * slot->b * a;
} else {
a *= _skeleton->a * slot->a;
r *= _skeleton->r * slot->r;
g *= _skeleton->g * slot->g;
b *= _skeleton->b * slot->b;
}
self.texture = texture;
self.texture = texture;
CGSize size = texture.contentSize;
GLKVector2 center = GLKVector2Make(size.width / 2.0, size.height / 2.0);
GLKVector2 extents = GLKVector2Make(size.width / 2.0, size.height / 2.0);
if (CCRenderCheckVisbility(transform, center, extents)) {
CCRenderBuffer buffer = [renderer enqueueTriangles:(trianglesCount / 3) andVertexes:verticesCount withState:self.renderState globalSortOrder:0];
for (int i = 0; i * 2 < verticesCount; ++i) {
CCVertex vertex;
vertex.position = GLKVector4Make(worldVertices[i * 2], worldVertices[i * 2 + 1], 0.0, 1.0);
vertex.position = GLKVector4Make(_worldVertices[i * 2], _worldVertices[i * 2 + 1], 0.0, 1.0);
vertex.color = GLKVector4Make(r, g, b, a);
vertex.texCoord1 = GLKVector2Make(uvs[i * 2], 1 - uvs[i * 2 + 1]);
CCRenderBufferSetVertex(buffer, i, CCVertexApplyTransform(vertex, transform));
Expand All @@ -236,11 +254,11 @@ -(void)draw:(CCRenderer *)renderer transform:(const GLKMatrix4 *)transform {
spSlot* slot = _skeleton->drawOrder[i];
if (!slot->attachment || slot->attachment->type != SP_ATTACHMENT_REGION) continue;
spRegionAttachment* attachment = (spRegionAttachment*)slot->attachment;
spRegionAttachment_computeWorldVertices(attachment, slot->bone, worldVertices);
points[0] = ccp(worldVertices[0], worldVertices[1]);
points[1] = ccp(worldVertices[2], worldVertices[3]);
points[2] = ccp(worldVertices[4], worldVertices[5]);
points[3] = ccp(worldVertices[6], worldVertices[7]);
spRegionAttachment_computeWorldVertices(attachment, slot->bone, _worldVertices);
points[0] = ccp(_worldVertices[0], _worldVertices[1]);
points[1] = ccp(_worldVertices[2], _worldVertices[3]);
points[2] = ccp(_worldVertices[4], _worldVertices[5]);
points[3] = ccp(_worldVertices[6], _worldVertices[7]);
[_drawNode drawPolyWithVerts:points count:4 fillColor:[CCColor clearColor] borderWidth:1 borderColor:[CCColor blueColor]];
}
}
Expand Down Expand Up @@ -283,20 +301,20 @@ - (CGRect) boundingBox {
int verticesCount;
if (slot->attachment->type == SP_ATTACHMENT_REGION) {
spRegionAttachment* attachment = (spRegionAttachment*)slot->attachment;
spRegionAttachment_computeWorldVertices(attachment, slot->bone, worldVertices);
spRegionAttachment_computeWorldVertices(attachment, slot->bone, _worldVertices);
verticesCount = 8;
} else if (slot->attachment->type == SP_ATTACHMENT_MESH) {
spMeshAttachment* mesh = (spMeshAttachment*)slot->attachment;
spMeshAttachment_computeWorldVertices(mesh, slot, worldVertices);
spMeshAttachment_computeWorldVertices(mesh, slot, _worldVertices);
verticesCount = mesh->verticesCount;
} else if (slot->attachment->type == SP_ATTACHMENT_SKINNED_MESH) {
spSkinnedMeshAttachment* mesh = (spSkinnedMeshAttachment*)slot->attachment;
spSkinnedMeshAttachment_computeWorldVertices(mesh, slot, worldVertices);
spSkinnedMeshAttachment_computeWorldVertices(mesh, slot, _worldVertices);
verticesCount = mesh->uvsCount;
} else
continue;
for (int ii = 0; ii < verticesCount; ii += 2) {
float x = worldVertices[ii] * scaleX, y = worldVertices[ii + 1] * scaleY;
float x = _worldVertices[ii] * scaleX, y = _worldVertices[ii + 1] * scaleY;
minX = fmin(minX, x);
minY = fmin(minY, y);
maxX = fmax(maxX, x);
Expand Down
Loading

0 comments on commit f8a76c6

Please sign in to comment.