mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-03-26 22:49:01 +08:00
[sdl] C++ runtime complete.
Unsupported: - premultiplied alpha - screen blend mode - two color tint
This commit is contained in:
parent
af9561de19
commit
5cd5a26186
@ -21,6 +21,9 @@ spotless {
|
|||||||
'spine-cocos2dx/src/**/*.h',
|
'spine-cocos2dx/src/**/*.h',
|
||||||
'spine-cocos2dx/example/Classes/**/*.cpp',
|
'spine-cocos2dx/example/Classes/**/*.cpp',
|
||||||
'spine-cocos2dx/example/Classes/**/*.h',
|
'spine-cocos2dx/example/Classes/**/*.h',
|
||||||
|
'spine-sdl/**/*.c',
|
||||||
|
'spine-sdl/**/*.cpp',
|
||||||
|
'spine-sdl/**/*.h',
|
||||||
'spine-sfml/**/*.c',
|
'spine-sfml/**/*.c',
|
||||||
'spine-sfml/**/*.cpp',
|
'spine-sfml/**/*.cpp',
|
||||||
'spine-sfml/**/*.h',
|
'spine-sfml/**/*.h',
|
||||||
|
|||||||
@ -21,7 +21,7 @@ install(TARGETS spine-sdl-c DESTINATION dist/lib)
|
|||||||
install(FILES src/spine-sdl-c.h src/stb_image.h DESTINATION dist/include)
|
install(FILES src/spine-sdl-c.h src/stb_image.h DESTINATION dist/include)
|
||||||
|
|
||||||
add_library(spine-sdl-cpp STATIC src/spine-sdl-cpp.cpp src/spine-sdl-cpp.h src/stb_image.h)
|
add_library(spine-sdl-cpp STATIC src/spine-sdl-cpp.cpp src/spine-sdl-cpp.h src/stb_image.h)
|
||||||
target_link_libraries(spine-sdl-cpp LINK_PUBLIC spine-cpp)
|
target_link_libraries(spine-sdl-cpp LINK_PUBLIC SDL2 spine-cpp)
|
||||||
install(TARGETS spine-sdl-cpp DESTINATION dist/lib)
|
install(TARGETS spine-sdl-cpp DESTINATION dist/lib)
|
||||||
install(FILES src/spine-sdl-cpp.h src/stb_image.h DESTINATION dist/include)
|
install(FILES src/spine-sdl-cpp.h src/stb_image.h DESTINATION dist/include)
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
int main() {
|
int main() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1,249 +1,59 @@
|
|||||||
#include <SDL.h>
|
|
||||||
#include <spine-sdl-cpp.h>
|
#include <spine-sdl-cpp.h>
|
||||||
#include <spine/spine.h>
|
#include <SDL.h>
|
||||||
|
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
|
||||||
|
|
||||||
#include <stb_image.h>
|
|
||||||
|
|
||||||
namespace spine {
|
|
||||||
struct SkeletonDrawable {
|
|
||||||
Skeleton *skeleton;
|
|
||||||
bool ownsAnimationStateData;
|
|
||||||
AnimationState *animationState;
|
|
||||||
SkeletonClipping clipper;
|
|
||||||
Vector<float> worldVertices;
|
|
||||||
Vector<unsigned short> quadIndices;
|
|
||||||
|
|
||||||
SkeletonDrawable(SkeletonData *skeletonData, AnimationStateData *animationStateData = nullptr) {
|
|
||||||
Bone::setYDown(true);
|
|
||||||
skeleton = new(__FILE__, __LINE__) Skeleton(skeletonData);
|
|
||||||
|
|
||||||
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() {
|
|
||||||
if (ownsAnimationStateData) delete animationState->getData();
|
|
||||||
delete animationState;
|
|
||||||
delete skeleton;
|
|
||||||
}
|
|
||||||
|
|
||||||
void update(float delta) {
|
|
||||||
animationState->update(delta);
|
|
||||||
animationState->apply(*skeleton);
|
|
||||||
skeleton->updateWorldTransform();
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw(SDL_Renderer *renderer) {
|
|
||||||
SDL_Texture *texture;
|
|
||||||
spine::Vector<SDL_Vertex> sdlVertices;
|
|
||||||
SDL_Vertex sdlVertex;
|
|
||||||
Vector<int> sdlIndices;
|
|
||||||
for (unsigned i = 0; i < skeleton->getSlots().size(); ++i) {
|
|
||||||
Slot &slot = *skeleton->getDrawOrder()[i];
|
|
||||||
Attachment *attachment = slot.getAttachment();
|
|
||||||
if (!attachment) continue;
|
|
||||||
|
|
||||||
// Early out if the slot color is 0 or the bone is not active
|
|
||||||
if (slot.getColor().a == 0 || !slot.getBone().isActive()) {
|
|
||||||
clipper.clipEnd(slot);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector<float> *vertices = &worldVertices;
|
|
||||||
int verticesCount = 0;
|
|
||||||
Vector<float> *uvs = NULL;
|
|
||||||
Vector<unsigned short> *indices;
|
|
||||||
int indicesCount = 0;
|
|
||||||
Color *attachmentColor;
|
|
||||||
|
|
||||||
if (attachment->getRTTI().isExactly(RegionAttachment::rtti)) {
|
|
||||||
RegionAttachment *regionAttachment = (RegionAttachment *) attachment;
|
|
||||||
attachmentColor = ®ionAttachment->getColor();
|
|
||||||
|
|
||||||
// Early out if the slot color is 0
|
|
||||||
if (attachmentColor->a == 0) {
|
|
||||||
clipper.clipEnd(slot);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
worldVertices.setSize(8, 0);
|
|
||||||
regionAttachment->computeWorldVertices(slot, worldVertices, 0, 2);
|
|
||||||
verticesCount = 4;
|
|
||||||
uvs = ®ionAttachment->getUVs();
|
|
||||||
indices = &quadIndices;
|
|
||||||
indicesCount = 6;
|
|
||||||
texture = (SDL_Texture *) ((AtlasRegion *) regionAttachment->getRendererObject())->page->getRendererObject();
|
|
||||||
|
|
||||||
} else if (attachment->getRTTI().isExactly(MeshAttachment::rtti)) {
|
|
||||||
MeshAttachment *mesh = (MeshAttachment *) attachment;
|
|
||||||
attachmentColor = &mesh->getColor();
|
|
||||||
|
|
||||||
// Early out if the slot color is 0
|
|
||||||
if (attachmentColor->a == 0) {
|
|
||||||
clipper.clipEnd(slot);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
worldVertices.setSize(mesh->getWorldVerticesLength(), 0);
|
|
||||||
texture = (SDL_Texture *) ((AtlasRegion *) mesh->getRendererObject())->page->getRendererObject();
|
|
||||||
mesh->computeWorldVertices(slot, 0, mesh->getWorldVerticesLength(), worldVertices.buffer(), 0, 2);
|
|
||||||
verticesCount = mesh->getWorldVerticesLength() >> 1;
|
|
||||||
uvs = &mesh->getUVs();
|
|
||||||
indices = &mesh->getTriangles();
|
|
||||||
indicesCount = indices->size();
|
|
||||||
|
|
||||||
} else if (attachment->getRTTI().isExactly(ClippingAttachment::rtti)) {
|
|
||||||
ClippingAttachment *clip = (ClippingAttachment *) slot.getAttachment();
|
|
||||||
clipper.clipStart(slot, clip);
|
|
||||||
continue;
|
|
||||||
} else
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Uint8 r = static_cast<Uint8>(skeleton->getColor().r * slot.getColor().r * attachmentColor->r * 255);
|
|
||||||
Uint8 g = static_cast<Uint8>(skeleton->getColor().g * slot.getColor().g * attachmentColor->g * 255);
|
|
||||||
Uint8 b = static_cast<Uint8>(skeleton->getColor().b * slot.getColor().b * attachmentColor->b * 255);
|
|
||||||
Uint8 a = static_cast<Uint8>(skeleton->getColor().a * slot.getColor().a * attachmentColor->a * 255);
|
|
||||||
sdlVertex.color.r = r;
|
|
||||||
sdlVertex.color.g = g;
|
|
||||||
sdlVertex.color.b = b;
|
|
||||||
sdlVertex.color.a = a;
|
|
||||||
|
|
||||||
Color light;
|
|
||||||
light.r = r / 255.0f;
|
|
||||||
light.g = g / 255.0f;
|
|
||||||
light.b = b / 255.0f;
|
|
||||||
light.a = a / 255.0f;
|
|
||||||
|
|
||||||
if (clipper.isClipping()) {
|
|
||||||
clipper.clipTriangles(worldVertices, *indices, *uvs, 2);
|
|
||||||
vertices = &clipper.getClippedVertices();
|
|
||||||
verticesCount = clipper.getClippedVertices().size() >> 1;
|
|
||||||
uvs = &clipper.getClippedUVs();
|
|
||||||
indices = &clipper.getClippedTriangles();
|
|
||||||
indicesCount = clipper.getClippedTriangles().size();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
sdlVertices.clear();
|
|
||||||
for (int ii = 0; ii < verticesCount; ++ii) {
|
|
||||||
sdlVertex.position.x = (*vertices)[ii];
|
|
||||||
sdlVertex.position.y = (*vertices)[ii + 1];
|
|
||||||
sdlVertex.tex_coord.x = (*uvs)[ii];
|
|
||||||
sdlVertex.tex_coord.y = (*uvs)[ii + 1];
|
|
||||||
sdlVertices.add(sdlVertex);
|
|
||||||
}
|
|
||||||
sdlIndices.clear();
|
|
||||||
for (int ii = 0; ii < indices->size(); ii++)
|
|
||||||
sdlIndices.add((*indices)[ii]);
|
|
||||||
|
|
||||||
SDL_RenderGeometry(renderer, texture, sdlVertices.buffer(), sdlVertices.size(), sdlIndices.buffer(), indicesCount);
|
|
||||||
clipper.clipEnd(slot);
|
|
||||||
}
|
|
||||||
clipper.clipEnd();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class SDLTextureLoader : public spine::TextureLoader {
|
|
||||||
SDL_Renderer *renderer;
|
|
||||||
|
|
||||||
public:
|
|
||||||
SDLTextureLoader(SDL_Renderer *renderer): renderer(renderer) {
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_Texture *loadTexture(const spine::String &path) {
|
|
||||||
int width, height, components;
|
|
||||||
stbi_uc *imageData = stbi_load(path.buffer(), &width, &height, &components, 4);
|
|
||||||
if (!imageData) return nullptr;
|
|
||||||
SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STATIC, width, height);
|
|
||||||
if (!texture) {
|
|
||||||
stbi_image_free(imageData);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
if (SDL_UpdateTexture(texture, nullptr, imageData, width * 4)) {
|
|
||||||
stbi_image_free(imageData);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
stbi_image_free(imageData);
|
|
||||||
return texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
void load(AtlasPage &page, const String &path) {
|
|
||||||
SDL_Texture *texture = loadTexture(path);
|
|
||||||
if (!texture) return;
|
|
||||||
page.setRendererObject(texture);
|
|
||||||
SDL_QueryTexture(texture, nullptr, nullptr, &page.width, &page.height);
|
|
||||||
|
|
||||||
/*if (page.magFilter == TextureFilter_Linear) texture->setSmooth(true);
|
|
||||||
if (page.uWrap == TextureWrap_Repeat && page.vWrap == TextureWrap_Repeat) texture->setRepeated(true);*/
|
|
||||||
}
|
|
||||||
|
|
||||||
void unload(void *texture) {
|
|
||||||
SDL_DestroyTexture((SDL_Texture*)texture);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
SpineExtension *getDefaultExtension() {
|
|
||||||
return new DefaultSpineExtension();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
spine::SkeletonDrawable *loadSkeleton(const char *json, const char *skel, const char *atlas) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
if (SDL_Init(SDL_INIT_VIDEO)) {
|
if (SDL_Init(SDL_INIT_VIDEO)) {
|
||||||
printf("Error: %s", SDL_GetError());
|
printf("Error: %s", SDL_GetError());
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
SDL_Window *window = SDL_CreateWindow("Spine SDL", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 800, 600, 0);
|
SDL_Window *window = SDL_CreateWindow("Spine SDL", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 800, 600, 0);
|
||||||
if (!window) {
|
if (!window) {
|
||||||
printf("Error: %s", SDL_GetError());
|
printf("Error: %s", SDL_GetError());
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
|
SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
|
||||||
if (!renderer) {
|
if (!renderer) {
|
||||||
printf("Error: %s", SDL_GetError());
|
printf("Error: %s", SDL_GetError());
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
spine::SDLTextureLoader textureLoader(renderer);
|
spine::SDLTextureLoader textureLoader(renderer);
|
||||||
spine::Atlas atlas("/Users/badlogic/workspaces/spine-runtimes/examples/spineboy/export/spineboy.atlas", &textureLoader);
|
spine::Atlas atlas("/Users/badlogic/workspaces/spine-runtimes/examples/spineboy/export/spineboy.atlas", &textureLoader);
|
||||||
spine::AtlasAttachmentLoader attachmentLoader(&atlas);
|
spine::AtlasAttachmentLoader attachmentLoader(&atlas);
|
||||||
spine::SkeletonJson json(&attachmentLoader);
|
spine::SkeletonJson json(&attachmentLoader);
|
||||||
spine::SkeletonData *skeletonData = json.readSkeletonDataFile("/Users/badlogic/workspaces/spine-runtimes/examples/spineboy/export/spineboy-pro.json");
|
json.setScale(0.5f);
|
||||||
spine::SkeletonDrawable drawable(skeletonData);
|
spine::SkeletonData *skeletonData = json.readSkeletonDataFile("/Users/badlogic/workspaces/spine-runtimes/examples/spineboy/export/spineboy-pro.json");
|
||||||
drawable.skeleton->setPosition(400, 500);
|
spine::SkeletonDrawable drawable(skeletonData);
|
||||||
drawable.update(0);
|
drawable.skeleton->setPosition(400, 500);
|
||||||
|
drawable.skeleton->setToSetupPose();
|
||||||
|
drawable.update(0);
|
||||||
|
drawable.animationState->setAnimation(0, "run", true);
|
||||||
|
|
||||||
// spine::SkeletonDrawable skeletonDrawable(nullptr, nullptr);
|
bool quit = false;
|
||||||
|
uint64_t lastFrameTime = SDL_GetPerformanceCounter();
|
||||||
|
while (!quit) {
|
||||||
|
SDL_Event event;
|
||||||
|
while (SDL_PollEvent(&event) != 0) {
|
||||||
|
if (event.type == SDL_QUIT) {
|
||||||
|
quit = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool quit = false;
|
SDL_SetRenderDrawColor(renderer, 94, 93, 96, 255);
|
||||||
while (!quit) {
|
SDL_RenderClear(renderer);
|
||||||
SDL_Event event;
|
|
||||||
while (SDL_PollEvent(&event) != 0) {
|
|
||||||
if (event.type == SDL_QUIT) {
|
|
||||||
quit = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
|
uint64_t now = SDL_GetPerformanceCounter();
|
||||||
SDL_RenderClear(renderer);
|
double deltaTime = (now - lastFrameTime) / (double) SDL_GetPerformanceFrequency();
|
||||||
drawable.draw(renderer);
|
lastFrameTime = now;
|
||||||
SDL_RenderPresent(renderer);
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_DestroyWindow(window);
|
drawable.update(deltaTime);
|
||||||
SDL_Quit();
|
drawable.draw(renderer);
|
||||||
return 0;
|
|
||||||
|
SDL_RenderPresent(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_DestroyWindow(window);
|
||||||
|
SDL_Quit();
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
@ -0,0 +1,223 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* 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-cpp.h"
|
||||||
|
#include <SDL.h>
|
||||||
|
|
||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
|
||||||
|
#include <stb_image.h>
|
||||||
|
|
||||||
|
using namespace spine;
|
||||||
|
|
||||||
|
SkeletonDrawable::SkeletonDrawable(SkeletonData *skeletonData, AnimationStateData *animationStateData) {
|
||||||
|
Bone::setYDown(true);
|
||||||
|
skeleton = new (__FILE__, __LINE__) Skeleton(skeletonData);
|
||||||
|
|
||||||
|
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() {
|
||||||
|
if (ownsAnimationStateData) delete animationState->getData();
|
||||||
|
delete animationState;
|
||||||
|
delete skeleton;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SkeletonDrawable::update(float delta) {
|
||||||
|
animationState->update(delta);
|
||||||
|
animationState->apply(*skeleton);
|
||||||
|
skeleton->updateWorldTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SkeletonDrawable::draw(SDL_Renderer *renderer) {
|
||||||
|
SDL_Texture *texture;
|
||||||
|
SDL_Vertex sdlVertex;
|
||||||
|
for (unsigned i = 0; i < skeleton->getSlots().size(); ++i) {
|
||||||
|
Slot &slot = *skeleton->getDrawOrder()[i];
|
||||||
|
Attachment *attachment = slot.getAttachment();
|
||||||
|
if (!attachment) continue;
|
||||||
|
|
||||||
|
// Early out if the slot color is 0 or the bone is not active
|
||||||
|
if (slot.getColor().a == 0 || !slot.getBone().isActive()) {
|
||||||
|
clipper.clipEnd(slot);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector<float> *vertices = &worldVertices;
|
||||||
|
int verticesCount = 0;
|
||||||
|
Vector<float> *uvs = NULL;
|
||||||
|
Vector<unsigned short> *indices;
|
||||||
|
int indicesCount = 0;
|
||||||
|
Color *attachmentColor;
|
||||||
|
|
||||||
|
if (attachment->getRTTI().isExactly(RegionAttachment::rtti)) {
|
||||||
|
RegionAttachment *regionAttachment = (RegionAttachment *) attachment;
|
||||||
|
attachmentColor = ®ionAttachment->getColor();
|
||||||
|
|
||||||
|
// Early out if the slot color is 0
|
||||||
|
if (attachmentColor->a == 0) {
|
||||||
|
clipper.clipEnd(slot);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
worldVertices.setSize(8, 0);
|
||||||
|
regionAttachment->computeWorldVertices(slot, worldVertices, 0, 2);
|
||||||
|
verticesCount = 4;
|
||||||
|
uvs = ®ionAttachment->getUVs();
|
||||||
|
indices = &quadIndices;
|
||||||
|
indicesCount = 6;
|
||||||
|
texture = (SDL_Texture *) ((AtlasRegion *) regionAttachment->getRendererObject())->page->getRendererObject();
|
||||||
|
|
||||||
|
} else if (attachment->getRTTI().isExactly(MeshAttachment::rtti)) {
|
||||||
|
MeshAttachment *mesh = (MeshAttachment *) attachment;
|
||||||
|
attachmentColor = &mesh->getColor();
|
||||||
|
|
||||||
|
// Early out if the slot color is 0
|
||||||
|
if (attachmentColor->a == 0) {
|
||||||
|
clipper.clipEnd(slot);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
worldVertices.setSize(mesh->getWorldVerticesLength(), 0);
|
||||||
|
texture = (SDL_Texture *) ((AtlasRegion *) mesh->getRendererObject())->page->getRendererObject();
|
||||||
|
mesh->computeWorldVertices(slot, 0, mesh->getWorldVerticesLength(), worldVertices.buffer(), 0, 2);
|
||||||
|
verticesCount = mesh->getWorldVerticesLength() >> 1;
|
||||||
|
uvs = &mesh->getUVs();
|
||||||
|
indices = &mesh->getTriangles();
|
||||||
|
indicesCount = indices->size();
|
||||||
|
|
||||||
|
} else if (attachment->getRTTI().isExactly(ClippingAttachment::rtti)) {
|
||||||
|
ClippingAttachment *clip = (ClippingAttachment *) slot.getAttachment();
|
||||||
|
clipper.clipStart(slot, clip);
|
||||||
|
continue;
|
||||||
|
} else
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Uint8 r = static_cast<Uint8>(skeleton->getColor().r * slot.getColor().r * attachmentColor->r * 255);
|
||||||
|
Uint8 g = static_cast<Uint8>(skeleton->getColor().g * slot.getColor().g * attachmentColor->g * 255);
|
||||||
|
Uint8 b = static_cast<Uint8>(skeleton->getColor().b * slot.getColor().b * attachmentColor->b * 255);
|
||||||
|
Uint8 a = static_cast<Uint8>(skeleton->getColor().a * slot.getColor().a * attachmentColor->a * 255);
|
||||||
|
sdlVertex.color.r = r;
|
||||||
|
sdlVertex.color.g = g;
|
||||||
|
sdlVertex.color.b = b;
|
||||||
|
sdlVertex.color.a = a;
|
||||||
|
|
||||||
|
if (clipper.isClipping()) {
|
||||||
|
clipper.clipTriangles(worldVertices, *indices, *uvs, 2);
|
||||||
|
vertices = &clipper.getClippedVertices();
|
||||||
|
verticesCount = clipper.getClippedVertices().size() >> 1;
|
||||||
|
uvs = &clipper.getClippedUVs();
|
||||||
|
indices = &clipper.getClippedTriangles();
|
||||||
|
indicesCount = clipper.getClippedTriangles().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
sdlVertices.clear();
|
||||||
|
for (int ii = 0; ii < verticesCount << 1; ii += 2) {
|
||||||
|
sdlVertex.position.x = (*vertices)[ii];
|
||||||
|
sdlVertex.position.y = (*vertices)[ii + 1];
|
||||||
|
sdlVertex.tex_coord.x = (*uvs)[ii];
|
||||||
|
sdlVertex.tex_coord.y = (*uvs)[ii + 1];
|
||||||
|
sdlVertices.add(sdlVertex);
|
||||||
|
}
|
||||||
|
sdlIndices.clear();
|
||||||
|
for (int ii = 0; ii < (int) indices->size(); ii++)
|
||||||
|
sdlIndices.add((*indices)[ii]);
|
||||||
|
|
||||||
|
switch (slot.getData().getBlendMode()) {
|
||||||
|
case BlendMode_Normal:
|
||||||
|
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
|
||||||
|
break;
|
||||||
|
case BlendMode_Multiply:
|
||||||
|
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_MOD);
|
||||||
|
break;
|
||||||
|
case BlendMode_Additive:
|
||||||
|
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_ADD);
|
||||||
|
break;
|
||||||
|
case BlendMode_Screen:
|
||||||
|
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_RenderGeometry(renderer, texture, sdlVertices.buffer(), sdlVertices.size(), sdlIndices.buffer(),
|
||||||
|
indicesCount);
|
||||||
|
clipper.clipEnd(slot);
|
||||||
|
}
|
||||||
|
clipper.clipEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Texture *loadTexture(SDL_Renderer *renderer, const String &path) {
|
||||||
|
int width, height, components;
|
||||||
|
stbi_uc *imageData = stbi_load(path.buffer(), &width, &height, &components, 4);
|
||||||
|
if (!imageData) return nullptr;
|
||||||
|
SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STATIC, width,
|
||||||
|
height);
|
||||||
|
if (!texture) {
|
||||||
|
stbi_image_free(imageData);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (SDL_UpdateTexture(texture, nullptr, imageData, width * 4)) {
|
||||||
|
stbi_image_free(imageData);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
stbi_image_free(imageData);
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDLTextureLoader::load(AtlasPage &page, const String &path) {
|
||||||
|
SDL_Texture *texture = loadTexture(renderer, path);
|
||||||
|
if (!texture) return;
|
||||||
|
page.setRendererObject(texture);
|
||||||
|
SDL_QueryTexture(texture, nullptr, nullptr, &page.width, &page.height);
|
||||||
|
switch (page.magFilter) {
|
||||||
|
case TextureFilter_Nearest:
|
||||||
|
SDL_SetTextureScaleMode(texture, SDL_ScaleModeNearest);
|
||||||
|
break;
|
||||||
|
case TextureFilter_Linear:
|
||||||
|
SDL_SetTextureScaleMode(texture, SDL_ScaleModeLinear);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
SDL_SetTextureScaleMode(texture, SDL_ScaleModeBest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDLTextureLoader::unload(void *texture) {
|
||||||
|
SDL_DestroyTexture((SDL_Texture *) texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
SpineExtension *spine::getDefaultExtension() {
|
||||||
|
return new DefaultSpineExtension();
|
||||||
|
}
|
||||||
@ -0,0 +1,74 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* 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>
|
||||||
|
|
||||||
|
struct SDL_Renderer;
|
||||||
|
struct SDL_Vertex;
|
||||||
|
|
||||||
|
namespace spine {
|
||||||
|
class SkeletonDrawable {
|
||||||
|
public:
|
||||||
|
SkeletonDrawable(SkeletonData *skeletonData, AnimationStateData *animationStateData = nullptr);
|
||||||
|
|
||||||
|
~SkeletonDrawable();
|
||||||
|
|
||||||
|
void update(float delta);
|
||||||
|
|
||||||
|
void draw(SDL_Renderer *renderer);
|
||||||
|
|
||||||
|
Skeleton *skeleton;
|
||||||
|
AnimationState *animationState;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool ownsAnimationStateData;
|
||||||
|
SkeletonClipping clipper;
|
||||||
|
Vector<float> worldVertices;
|
||||||
|
Vector<unsigned short> quadIndices;
|
||||||
|
Vector<SDL_Vertex> sdlVertices;
|
||||||
|
Vector<int> sdlIndices;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SDLTextureLoader : public spine::TextureLoader {
|
||||||
|
SDL_Renderer *renderer;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SDLTextureLoader(SDL_Renderer *renderer) : renderer(renderer) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void load(AtlasPage &page, const String &path);
|
||||||
|
|
||||||
|
void unload(void *texture);
|
||||||
|
};
|
||||||
|
}// namespace spine
|
||||||
|
|
||||||
|
#endif
|
||||||
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user