浏览代码

[sdl] C implementation. Atlas page loading incomplete.

Mario Zechner 3 年之前
父节点
当前提交
6fb0ebdc7a
共有 5 个文件被更改,包括 281 次插入8 次删除
  1. 1 1
      spine-sdl/CMakeLists.txt
  2. 207 0
      spine-sdl/src/spine-sdl-c.c
  3. 66 0
      spine-sdl/src/spine-sdl-c.h
  4. 7 6
      spine-sdl/src/spine-sdl-cpp.cpp
  5. 0 1
      spine-sdl/src/spine-sdl-cpp.h

+ 1 - 1
spine-sdl/CMakeLists.txt

@@ -16,7 +16,7 @@ FetchContent_MakeAvailable(SDL)
 include_directories(src)
 
 add_library(spine-sdl-c STATIC src/spine-sdl-c.c src/spine-sdl-c.h src/stb_image.h)
-target_link_libraries(spine-sdl-c LINK_PUBLIC spine-c)
+target_link_libraries(spine-sdl-c LINK_PUBLIC SDL2 spine-c)
 install(TARGETS spine-sdl-c DESTINATION dist/lib)
 install(FILES src/spine-sdl-c.h src/stb_image.h DESTINATION dist/include)
 

+ 207 - 0
spine-sdl/src/spine-sdl-c.c

@@ -0,0 +1,207 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated September 24, 2021. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2021, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "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 SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) 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
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "spine-sdl-c.h"
+#include <spine/spine.h>
+#include <spine/extension.h>
+#include <SDL.h>
+
+#define STB_IMAGE_IMPLEMENTATION
+
+#include <stb_image.h>
+
+spSkeletonDrawable *spSkeletonDrawable_create(spSkeletonData *skeletonData, spAnimationStateData *animationStateData) {
+    spSkeletonDrawable *self = NEW(spSkeletonDrawable);
+    self->skeleton = spSkeleton_create(skeletonData);
+    self->animationState = spAnimationState_create(animationStateData);
+    self->sdlIndices = spIntArray_create(12);
+    self->sdlVertices = spSdlVertexArray_create(12);
+    self->worldVertices = spFloatArray_create(12);
+    self->clipper = spSkeletonClipping_create();
+    return self;
+}
+
+void spSkeletonDrawable_dispose(spSkeletonDrawable *self) {
+    spSkeleton_dispose(self->skeleton);
+    spAnimationState_dispose(self->animationState);
+    spIntArray_dispose(self->sdlIndices);
+    spSdlVertexArray_dispose(self->sdlVertices);
+    spFloatArray_dispose(self->worldVertices);
+    spSkeletonClipping_dispose(self->clipper);
+    FREE(self);
+}
+
+void spSkeletonDrawable_update(spSkeletonDrawable *self, float delta) {
+    spAnimationState_update(self->animationState, delta);
+    spAnimationState_apply(self->animationState, self->skeleton);
+    spSkeleton_updateWorldTransform(self->skeleton);
+}
+
+void spSkeletonDrawable_draw(spSkeletonDrawable *self, struct SDL_Renderer *renderer) {
+    static unsigned short quadIndices[] = { 0, 1, 2, 2, 3, 0 };
+    spSkeleton *skeleton = self->skeleton;
+    spSkeletonClipping *clipper = self->clipper;
+    SDL_Texture *texture;
+    SDL_Vertex sdlVertex;
+    for (unsigned i = 0; i < skeleton->slotsCount; ++i) {
+        spSlot *slot = skeleton->drawOrder[i];
+        spAttachment *attachment = slot->attachment;
+        if (!attachment) continue;
+
+        // Early out if the slot color is 0 or the bone is not active
+        if (slot->color.a == 0 || !slot->bone->active) {
+            spSkeletonClipping_clipEnd(clipper, slot);
+            continue;
+        }
+
+        spFloatArray *vertices = self->worldVertices;
+        int verticesCount = 0;
+        float *uvs = NULL;
+        unsigned short *indices;
+        int indicesCount = 0;
+        spColor *attachmentColor = NULL;
+
+        if (attachment->type == SP_ATTACHMENT_REGION) {
+            spRegionAttachment *region = (spRegionAttachment *) attachment;
+            attachmentColor = &region->color;
+
+            // Early out if the slot color is 0
+            if (attachmentColor->a == 0) {
+                spSkeletonClipping_clipEnd(clipper, slot);
+                continue;
+            }
+
+            spFloatArray_setSize(vertices, 8);
+            spRegionAttachment_computeWorldVertices(region, slot, vertices->items, 0, 2);
+            verticesCount = 4;
+            uvs = &region->uvs;
+            indices = &quadIndices;
+            indicesCount = 6;
+            texture = (SDL_Texture *) ((spAtlasRegion*)region->rendererObject)->page->rendererObject;
+        } else if (attachment->type == SP_ATTACHMENT_MESH) {
+            spMeshAttachment *mesh = (spMeshAttachment *) attachment;
+            attachmentColor = &mesh->color;
+
+            // Early out if the slot color is 0
+            if (attachmentColor->a == 0) {
+                spSkeletonClipping_clipEnd(clipper, slot);
+                continue;
+            }
+
+            spFloatArray_setSize(vertices, mesh->super.worldVerticesLength);
+            spVertexAttachment_computeWorldVertices(SUPER(mesh), slot, 0, mesh->super.worldVerticesLength, vertices, 0, 2);
+            verticesCount = mesh->super.worldVerticesLength >> 1;
+            uvs = mesh->uvs;
+            indices = mesh->triangles;
+            indicesCount = mesh->trianglesCount;
+            texture = (SDL_Texture *) ((spAtlasRegion*)mesh->rendererObject)->page->rendererObject;
+        } else if (attachment->type == SP_ATTACHMENT_CLIPPING) {
+            spClippingAttachment *clip = (spClippingAttachment *) slot->attachment;
+            spSkeletonClipping_clipStart(clipper, slot, clip);
+            continue;
+        } else
+            continue;
+
+        Uint8 r = (Uint8)(skeleton->color.r * slot->color.r * attachmentColor->r * 255);
+        Uint8 g = (Uint8)(skeleton->color.g * slot->color.g * attachmentColor->g * 255);
+        Uint8 b = (Uint8)(skeleton->color.b * slot->color.b * attachmentColor->b * 255);
+        Uint8 a = (Uint8)(skeleton->color.a * slot->color.a * attachmentColor->a * 255);
+        sdlVertex.color.r = r;
+        sdlVertex.color.g = g;
+        sdlVertex.color.b = b;
+        sdlVertex.color.a = a;
+
+        if (spSkeletonClipping_isClipping(clipper)) {
+            spSkeletonClipping_clipTriangles(clipper, vertices, verticesCount << 1, indices, indicesCount, uvs, 2);
+            vertices = clipper->clippedVertices->items;
+            verticesCount = clipper->clippedVertices->size >> 1;
+            uvs = clipper->clippedUVs->items;
+            indices = clipper->clippedTriangles->items;
+            indicesCount = clipper->clippedTriangles->size;
+        }
+
+        spSdlVertexArray_clear(self->sdlVertices);
+        for (int ii = 0; ii < verticesCount << 1; ii += 2) {
+            sdlVertex.position.x = vertices->items[ii];
+            sdlVertex.position.y = vertices->items[ii + 1];
+            sdlVertex.tex_coord.x = uvs[ii];
+            sdlVertex.tex_coord.y = uvs[ii + 1];
+            spSdlVertexArray_add(self->sdlVertices, sdlVertex);
+        }
+        spIntArray_clear(self->sdlIndices);
+        for (int ii = 0; ii < (int) indicesCount; ii++)
+            spIntArray_add(self->sdlIndices, indices[ii]);
+
+        switch (slot->data->blendMode) {
+            case SP_BLEND_MODE_NORMAL:
+                SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
+                break;
+            case SP_BLEND_MODE_MULTIPLY:
+                SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_MOD);
+                break;
+            case SP_BLEND_MODE_ADDITIVE:
+                SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_ADD);
+                break;
+            case SP_BLEND_MODE_SCREEN:
+                SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
+                break;
+        }
+
+        SDL_RenderGeometry(renderer, texture, self->sdlVertices->items, self->sdlVertices->size, self->sdlIndices->items,
+                           indicesCount);
+        spSkeletonClipping_clipEnd(clipper, slot);
+    }
+    spSkeletonClipping_clipEnd2(clipper);
+}
+
+void _spAtlasPage_createTexture(spAtlasPage *self, const char *path) {
+    int width, height, components;
+    stbi_uc *imageData = stbi_load(path, &width, &height, &components, 4);
+    if (!imageData) return;
+    SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STATIC, width,
+                                             height);
+    if (!texture) {
+        stbi_image_free(imageData);
+        return;
+    }
+    if (SDL_UpdateTexture(texture, NULL, imageData, width * 4)) {
+        stbi_image_free(imageData);
+        return;
+    }
+    stbi_image_free(imageData);
+    return;
+}
+
+void _spAtlasPage_disposeTexture(spAtlasPage *self) {
+    SDL_DestroyTexture((SDL_Texture *) self->rendererObject);
+}
+
+char *_spUtil_readFile(const char *path, int *length) {
+    return _spReadFile(path, length);
+}

+ 66 - 0
spine-sdl/src/spine-sdl-c.h

@@ -0,0 +1,66 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated September 24, 2021. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2021, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "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 SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) 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
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef SPINE_SDL
+#define SPINE_SDL
+
+#include <spine/spine.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct SDL_Renderer;
+struct SDL_Texture;
+struct SDL_Vertex;
+_SP_ARRAY_DECLARE_TYPE(spSdlVertexArray, struct SDL_Vertex);
+
+typedef struct spSkeletonDrawable {
+    spSkeleton *skeleton;
+    spAnimationState *animationState;
+
+    spSkeletonClipping *clipper;
+    spFloatArray *worldVertices;
+    spSdlVertexArray *sdlVertices;
+    spIntArray *sdlIndices;
+} spSkeletonDrawable;
+
+SP_API spSkeletonDrawable *spSkeletonDrawable_create(spSkeletonData *skeletonData, spAnimationStateData *animationStateData);
+
+SP_API void spSkeletonDrawable_destroy(spSkeletonDrawable *self);
+
+SP_API void spSkeletonDrawable_update(spSkeletonDrawable *self, float delta);
+
+SP_API void spSkeletonDrawable_draw(spSkeletonDrawable *self, struct SDL_Renderer *renderer);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 7 - 6
spine-sdl/src/spine-sdl-cpp.cpp

@@ -43,12 +43,6 @@ SkeletonDrawable::SkeletonDrawable(SkeletonData *skeletonData, AnimationStateDat
 	ownsAnimationStateData = animationStateData == 0;
 	if (ownsAnimationStateData) animationStateData = new (__FILE__, __LINE__) AnimationStateData(skeletonData);
 	animationState = new (__FILE__, __LINE__) AnimationState(animationStateData);
-	quadIndices.add(0);
-	quadIndices.add(1);
-	quadIndices.add(2);
-	quadIndices.add(2);
-	quadIndices.add(3);
-	quadIndices.add(0);
 }
 
 SkeletonDrawable::~SkeletonDrawable() {
@@ -64,6 +58,13 @@ void SkeletonDrawable::update(float delta) {
 }
 
 void SkeletonDrawable::draw(SDL_Renderer *renderer) {
+    Vector<unsigned short> quadIndices;
+    quadIndices.add(0);
+    quadIndices.add(1);
+    quadIndices.add(2);
+    quadIndices.add(2);
+    quadIndices.add(3);
+    quadIndices.add(0);
 	SDL_Texture *texture;
 	SDL_Vertex sdlVertex;
 	for (unsigned i = 0; i < skeleton->getSlots().size(); ++i) {

+ 0 - 1
spine-sdl/src/spine-sdl-cpp.h

@@ -53,7 +53,6 @@ namespace spine {
 		bool ownsAnimationStateData;
 		SkeletonClipping clipper;
 		Vector<float> worldVertices;
-		Vector<unsigned short> quadIndices;
 		Vector<SDL_Vertex> sdlVertices;
 		Vector<int> sdlIndices;
 	};