Skip to content

Commit

Permalink
Merge pull request #163 from defold/blend-support
Browse files Browse the repository at this point in the history
Add blending option to use blend factor from the spine file
  • Loading branch information
Jhonnyg authored Apr 4, 2024
2 parents a0c82cc + 804740f commit a408656
Show file tree
Hide file tree
Showing 14 changed files with 239 additions and 108 deletions.
1 change: 1 addition & 0 deletions defold-spine/commonsrc/spine_ddf.proto
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ message SpineModelDesc
BLEND_MODE_ADD = 1 [(displayName) = "Add"];
BLEND_MODE_MULT = 3 [(displayName) = "Multiply"];
BLEND_MODE_SCREEN = 4 [(displayName) = "Screen"];
BLEND_MODE_INHERIT = 5 [(displayName) = "Inherit"];
}

required string spine_scene = 1 [(resource)=true];
Expand Down
75 changes: 52 additions & 23 deletions defold-spine/commonsrc/vertices.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,23 @@ uint32_t CalcVertexBufferSize(const spSkeleton* skeleton, uint32_t* out_max_tria
return count;
}

uint32_t CalcDrawDescCount(const spSkeleton* skeleton)
{
uint32_t count = 0;
for (int s = 0; s < skeleton->slotsCount; ++s)
{
spSlot* slot = skeleton->drawOrder[s];
spAttachment* attachment = slot->attachment;
if (!attachment)
{
continue;
}
count++;
}
return count;
}

uint32_t GenerateVertexData(dmArray<SpineVertex>& vertex_buffer, const spSkeleton* skeleton, const dmVMath::Matrix4& world)
uint32_t GenerateVertexData(dmArray<SpineVertex>& vertex_buffer, const spSkeleton* skeleton, const dmVMath::Matrix4& world, dmArray<SpineDrawDesc>* draw_descs_out)
{
dmArray<float> scratch; // scratch buffer

Expand All @@ -170,28 +185,7 @@ uint32_t GenerateVertexData(dmArray<SpineVertex>& vertex_buffer, const spSkeleto
continue;
}

// We let the user override the blend mode for the whole spine scene at the .spinemodel level
// // Fetch the blend mode from the slot and
// // translate it to the engine blend mode
// BlendMode engineBlendMode;
// switch (slot->data->blendMode) {
// case SP_BLEND_MODE_NORMAL:
// engineBlendMode = BLEND_NORMAL;
// break;
// case SP_BLEND_MODE_ADDITIVE:
// engineBlendMode = BLEND_ADDITIVE;
// break;
// case SP_BLEND_MODE_MULTIPLY:
// engineBlendMode = BLEND_MULTIPLY;
// break;
// case SP_BLEND_MODE_SCREEN:
// engineBlendMode = BLEND_SCREEN;
// break;
// default:
// // unknown Spine blend mode, fall back to
// // normal blend mode
// engineBlendMode = BLEND_NORMAL;
// }
uint32_t batch_vindex_start = vindex;

// Calculate the tinting color based on the skeleton's color
// and the slot's color. Each color channel is given in the
Expand Down Expand Up @@ -271,6 +265,15 @@ uint32_t GenerateVertexData(dmArray<SpineVertex>& vertex_buffer, const spSkeleto
addVertex(&vertex_buffer[vindex++], scratch[index], scratch[index + 1], uvs[index], uvs[index + 1], colorR, colorG, colorB, colorA, page_index);
}
}

if (draw_descs_out)
{
SpineDrawDesc desc;
desc.m_VertexStart = batch_vindex_start;
desc.m_BlendMode = (uint32_t) slot->data->blendMode;
desc.m_VertexCount = vindex - batch_vindex_start;
draw_descs_out->Push(desc);
}
}
scratch.SetSize(0);

Expand All @@ -295,4 +298,30 @@ uint32_t GenerateVertexData(dmArray<SpineVertex>& vertex_buffer, const spSkeleto
return vcount;
}

void MergeDrawDescs(const dmArray<SpineDrawDesc>& src, dmArray<SpineDrawDesc>& dst)
{
dst.SetCapacity(src.Size());
dst.SetSize(src.Size());

SpineDrawDesc* current_draw_desc = dst.Begin();
*current_draw_desc = src[0];

// If we are using "inherit" blending mode, we need to produce render objects based
// on the blend mode. If two consecutive draws have the same blend mode, we can merge them.
for (int i = 1; i < src.Size(); ++i)
{
if (current_draw_desc->m_BlendMode == src[i].m_BlendMode)
{
current_draw_desc->m_VertexCount += src[i].m_VertexCount;
}
else
{
current_draw_desc++;
*current_draw_desc = src[i];
}
}
uint32_t trimmed_size = current_draw_desc - dst.Begin() + 1;
dst.SetSize(trimmed_size);
}

} // dmSpine
52 changes: 31 additions & 21 deletions defold-spine/editor/src/spineext.clj
Original file line number Diff line number Diff line change
Expand Up @@ -346,9 +346,22 @@
(defn- set-constants! [^GL2 gl shader ro]
(doall (map (fn [constant] (set-constant! gl shader constant)) (.m_Constants ro))))

(defn- blend-factor-value-to-blend-mode [blend-factor-value]
(case blend-factor-value
0 :blend-mode-alpha
1 :blend-mode-add
2 :blend-mode-mult
3 :blend-mode-screen
:blend-mode-alpha))

(defn- do-render-object! [^GL2 gl render-args shader renderable ro]
(let [start (.m_VertexStart ro) ; the name is from the engine, but in this case refers to the index
count (.m_VertexCount ro)
renderable-user-data (:user-data renderable)
renderable-blend-mode (:blend-mode renderable-user-data)
blend-mode (if (= renderable-blend-mode :blend-mode-inherit)
(blend-factor-value-to-blend-mode (.m_BlendFactor ro))
renderable-blend-mode)
face-winding (if (not= (.m_FaceWindingCCW ro) 0) GL/GL_CCW GL/GL_CW)
_ (set-constants! gl shader ro)
ro-transform (double-array (.m (.m_WorldTransform ro)))
Expand All @@ -363,7 +376,7 @@
(:view render-args)
(:projection render-args)
(:texture render-args)))]

(gl/set-blend-mode gl blend-mode)
(shader/set-uniform shader gl "world_view_proj" (:world-view-proj render-args))
(when (not= (.m_SetFaceWinding ro) 0)
(gl/gl-front-face gl face-winding))
Expand All @@ -373,8 +386,7 @@
(gl/gl-draw-arrays gl triangle-mode start count))
(when use-index-buffer
(gl/gl-draw-elements gl triangle-mode start count))
; reset blend state
(.glBlendFunc gl GL/GL_SRC_ALPHA GL/GL_ONE_MINUS_SRC_ALPHA)))
(gl/set-blend-mode gl :blend-mode-alpha)))

(set! *warn-on-reflection* true)

Expand All @@ -391,15 +403,13 @@
(defn- render-group-transparent [^GL2 gl render-args override-shader group]
(let [renderable (:renderable group)
user-data (:user-data renderable)
blend-mode (:blend-mode user-data)
gpu-texture (or (get user-data :gpu-texture) texture/white-pixel)
shader (if (not= override-shader nil) override-shader (:shader user-data))
vb (:vertex-buffer group)
render-objects (:render-objects group)
vertex-binding (vtx/use-with ::spine-trans vb shader)]
(gl/with-gl-bindings gl render-args [gpu-texture shader vertex-binding]
(setup-gl gl)
(gl/set-blend-mode gl blend-mode)
(doall (map (fn [ro] (do-render-object! gl render-args shader renderable ro)) render-objects))
(restore-gl gl))))

Expand Down Expand Up @@ -428,20 +438,19 @@

(g/defnk produce-main-scene [_node-id aabb material-shader gpu-texture default-tex-params aabb spine-scene-pb spine-data-handle]
(when (and gpu-texture)
(let [blend-mode :blend-mode-alpha]
(assoc {:node-id _node-id :aabb aabb}
:renderable {:render-fn render-spine-scenes
:tags #{:spine}
:batch-key [gpu-texture material-shader]
:select-batch-key _node-id
:user-data {:aabb aabb
:spine-scene-pb spine-scene-pb
:spine-data-handle spine-data-handle
:shader material-shader
:gpu-texture gpu-texture
:tex-params default-tex-params
:blend-mode blend-mode}
:passes [pass/transparent pass/selection]}))))
(assoc {:node-id _node-id :aabb aabb}
:renderable {:render-fn render-spine-scenes
:tags #{:spine}
:batch-key [gpu-texture material-shader]
:select-batch-key _node-id
:user-data {:aabb aabb
:spine-scene-pb spine-scene-pb
:spine-data-handle spine-data-handle
:shader material-shader
:gpu-texture gpu-texture
:tex-params default-tex-params
:blend-mode :blend-mode-alpha}
:passes [pass/transparent pass/selection]})))

(defn- make-spine-outline-scene [_node-id aabb]
{:aabb aabb
Expand Down Expand Up @@ -776,7 +785,7 @@

;;//////////////////////////////////////////////////////////////////////////////////////////////

(g/defnk produce-model-pb [spine-scene-resource default-animation skin material-resource blend-mode create-go-bones playback-rate offset]
(g/defnk produce-model-pb [spine-scene-resource blend-mode default-animation skin material-resource create-go-bones playback-rate offset]
(cond-> {:spine-scene (resource/resource->proj-path spine-scene-resource)
:default-animation default-animation
:skin skin
Expand Down Expand Up @@ -953,13 +962,14 @@

(output updatable g/Any :cached produce-spine-data-handle-updatable)

(output scene g/Any :cached (g/fnk [_node-id spine-main-scene aabb material-shader tex-params spine-data-handle default-animation skin updatable]
(output scene g/Any :cached (g/fnk [_node-id spine-main-scene aabb blend-mode material-shader tex-params spine-data-handle default-animation skin updatable]
(if (and (some? material-shader) (some? (:renderable spine-main-scene)))
(let [aabb aabb
spine-scene-node-id (:node-id spine-main-scene)]
(-> spine-main-scene
(assoc-in [:renderable :user-data :shader] material-shader)
(update-in [:renderable :user-data :gpu-texture] texture/set-params tex-params)
(assoc-in [:renderable :user-data :blend-mode] blend-mode)
(assoc-in [:renderable :user-data :skin] skin)
(assoc-in [:renderable :user-data :animation] default-animation)
(assoc-in [:renderable :user-data :spine-data-handle] spine-data-handle)
Expand Down
12 changes: 10 additions & 2 deletions defold-spine/include/common/vertices.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

struct spSkeleton;


namespace dmSpine
{

Expand All @@ -27,8 +26,17 @@ struct SpineModelBounds
float maxY;
};

struct SpineDrawDesc
{
uint32_t m_VertexStart;
uint32_t m_VertexCount;
uint32_t m_BlendMode; // spBlendMode
};

uint32_t CalcVertexBufferSize(const spSkeleton* skeleton, uint32_t* out_max_triangle_count);
uint32_t GenerateVertexData(dmArray<SpineVertex>& vertex_buffer, const spSkeleton* skeleton, const dmVMath::Matrix4& world);
uint32_t CalcDrawDescCount(const spSkeleton* skeleton);
uint32_t GenerateVertexData(dmArray<SpineVertex>& vertex_buffer, const spSkeleton* skeleton, const dmVMath::Matrix4& world, dmArray<SpineDrawDesc>* draw_descs);
void GetSkeletonBounds(const spSkeleton* skeleton, SpineModelBounds& bounds);
void MergeDrawDescs(const dmArray<SpineDrawDesc>& src, dmArray<SpineDrawDesc>& dst);

} // dmSpine
Binary file modified defold-spine/plugins/lib/arm64-osx/libSpineExt.dylib
Binary file not shown.
Binary file modified defold-spine/plugins/lib/x86_64-linux/libSpineExt.so
Binary file not shown.
Binary file modified defold-spine/plugins/lib/x86_64-osx/libSpineExt.dylib
Binary file not shown.
Binary file modified defold-spine/plugins/lib/x86_64-win32/libSpineExt.dll
Binary file not shown.
Binary file modified defold-spine/plugins/share/pluginSpineExt.jar
Binary file not shown.
4 changes: 2 additions & 2 deletions defold-spine/pluginsrc/com/defold/bob/pipeline/Spine.java
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ static public class RenderObject extends Structure {
public int m_NumConstants;
public int m_VertexStart;
public int m_VertexCount;
public int pad1;
public int m_BlendFactor;
public byte m_SetBlendFactors;
public byte m_SetStencilTest;
public byte m_SetFaceWinding;
Expand All @@ -268,7 +268,7 @@ static public class RenderObject extends Structure {
protected List getFieldOrder() {
return Arrays.asList(new String[] {
"m_StencilTestParams", "m_WorldTransform", "m_Constants",
"m_NumConstants", "m_VertexStart", "m_VertexCount", "pad1",
"m_NumConstants", "m_VertexStart", "m_VertexCount", "m_BlendFactor",
"m_SetBlendFactors", "m_SetStencilTest", "m_SetFaceWinding", "m_FaceWindingCCW", "m_UseIndexBuffer", "m_IsTriangleStrip", "pad2"});
}

Expand Down
37 changes: 24 additions & 13 deletions defold-spine/pluginsrc/plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -676,24 +676,35 @@ static void UpdateRenderData(SpineFile* file)
file->m_RenderObjects.SetSize(0);
file->m_VertexBuffer.SetSize(0);

uint32_t ro_count = 1;
uint32_t ro_count = dmSpine::CalcDrawDescCount(file->m_SkeletonInstance);
AdjustArraySize(file->m_RenderObjects, ro_count);

dmArray<dmSpine::SpineDrawDesc> draw_descs;
draw_descs.SetCapacity(ro_count);

dmVMath::Matrix4 transform = dmVMath::Matrix4::identity();
dmSpine::GenerateVertexData(file->m_VertexBuffer, file->m_SkeletonInstance, transform);
dmSpine::GenerateVertexData(file->m_VertexBuffer, file->m_SkeletonInstance, transform, &draw_descs);

dmArray<dmSpine::SpineDrawDesc> merged_draw_descs;
MergeDrawDescs(draw_descs, merged_draw_descs);

dmSpinePlugin::RenderObject& ro = file->m_RenderObjects[0];
ro.Init();
ro.m_VertexStart = 0; // byte offset
ro.m_VertexCount = file->m_VertexBuffer.Size();
ro.m_SetStencilTest = 0;
ro.m_UseIndexBuffer = 0;
ro.m_IsTriangleStrip = 0; // 0 == GL_TRIANGLES, 1 == GL_TRIANGLE_STRIP
file->m_RenderObjects.SetSize(merged_draw_descs.Size());

ro.m_SetFaceWinding = 0;
ro.m_FaceWindingCCW = dmGraphics::FACE_WINDING_CCW;
for (int i = 0; i < merged_draw_descs.Size(); ++i)
{
dmSpinePlugin::RenderObject& ro = file->m_RenderObjects[i];
ro.Init();
ro.m_VertexStart = merged_draw_descs[i].m_VertexStart; // byte offset
ro.m_VertexCount = merged_draw_descs[i].m_VertexCount;
ro.m_SetStencilTest = 0;
ro.m_UseIndexBuffer = 0;
ro.m_IsTriangleStrip = 0; // 0 == GL_TRIANGLES, 1 == GL_TRIANGLE_STRIP
ro.m_BlendFactor = merged_draw_descs[i].m_BlendMode;
ro.m_SetFaceWinding = 0;
ro.m_FaceWindingCCW = dmGraphics::FACE_WINDING_CCW;

//ro.AddConstant(UNIFORM_TINT, dmVMath::Vector4(1.0f, 1.0f, 1.0f, 1.0f));
//ro.AddConstant(UNIFORM_TINT, dmVMath::Vector4(1.0f, 1.0f, 1.0f, 1.0f));

ro.m_WorldTransform = transform;
ro.m_WorldTransform = transform;
}
}
2 changes: 1 addition & 1 deletion defold-spine/pluginsrc/renderobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ namespace dmSpinePlugin
uint32_t m_NumConstants;
uint32_t m_VertexStart;
uint32_t m_VertexCount;
uint32_t : 32;
uint32_t m_BlendFactor;

bool m_SetBlendFactors;
bool m_SetStencilTest;
Expand Down
Loading

0 comments on commit a408656

Please sign in to comment.