diff --git a/spine-sdl/CMakeLists.txt b/spine-sdl/CMakeLists.txt index bd84feea2..85cfae127 100644 --- a/spine-sdl/CMakeLists.txt +++ b/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) diff --git a/spine-sdl/src/spine-sdl-c.c b/spine-sdl/src/spine-sdl-c.c index e69de29bb..af3cf3875 100644 --- a/spine-sdl/src/spine-sdl-c.c +++ b/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 +#include +#include + +#define STB_IMAGE_IMPLEMENTATION + +#include + +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 = ®ion->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 = ®ion->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); +} \ No newline at end of file diff --git a/spine-sdl/src/spine-sdl-c.h b/spine-sdl/src/spine-sdl-c.h index e69de29bb..77c30ecf4 100644 --- a/spine-sdl/src/spine-sdl-c.h +++ b/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 + +#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 diff --git a/spine-sdl/src/spine-sdl-cpp.cpp b/spine-sdl/src/spine-sdl-cpp.cpp index 6a48c8e56..321aad8af 100644 --- a/spine-sdl/src/spine-sdl-cpp.cpp +++ b/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 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) { diff --git a/spine-sdl/src/spine-sdl-cpp.h b/spine-sdl/src/spine-sdl-cpp.h index 97d34bd23..a2843f5d4 100644 --- a/spine-sdl/src/spine-sdl-cpp.h +++ b/spine-sdl/src/spine-sdl-cpp.h @@ -53,7 +53,6 @@ namespace spine { bool ownsAnimationStateData; SkeletonClipping clipper; Vector worldVertices; - Vector quadIndices; Vector sdlVertices; Vector sdlIndices; };