mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-03-26 22:49:01 +08:00
Formatting
This commit is contained in:
parent
e9aab1c94e
commit
bf0a33876a
@ -21,12 +21,20 @@ 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-glfw/src/**/*.cpp',
|
||||||
'spine-sdl/**/*.cpp',
|
'spine-glfw/src/**/*.h',
|
||||||
'spine-sdl/**/*.h',
|
'spine-glfw/example/**/*.cpp',
|
||||||
'spine-sfml/**/*.c',
|
'spine-glfw/example/**/*.h',
|
||||||
'spine-sfml/**/*.cpp',
|
'spine-sdl/src/**/*.c',
|
||||||
'spine-sfml/**/*.h',
|
'spine-sdl/src/**/*.cpp',
|
||||||
|
'spine-sdl/src/**/*.h',
|
||||||
|
'spine-sdl/example/**/*.c',
|
||||||
|
'spine-sdl/example/**/*.cpp',
|
||||||
|
'spine-sdl/example/**/*.h',
|
||||||
|
'spine-sfml/c/src/**/*.c',
|
||||||
|
'spine-sfml/c/src/**/*.h',
|
||||||
|
'spine-sfml/cpp/src/**/*.cpp',
|
||||||
|
'spine-sfml/cpp/src/**/*.h',
|
||||||
'spine-ue/**/*.cpp',
|
'spine-ue/**/*.cpp',
|
||||||
'spine-ue/**/*.h',
|
'spine-ue/**/*.h',
|
||||||
'spine-godot/spine_godot/*.cpp',
|
'spine-godot/spine_godot/*.cpp',
|
||||||
|
|||||||
@ -81,7 +81,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void compress() {
|
void compress() {
|
||||||
if (blocks.size() == 1) return;
|
if (blocks.size() == 1) return;
|
||||||
int totalSize = 0;
|
int totalSize = 0;
|
||||||
for (int i = 0, n = blocks.size(); i < n; i++) {
|
for (int i = 0, n = blocks.size(); i < n; i++) {
|
||||||
totalSize += blocks[i].size;
|
totalSize += blocks[i].size;
|
||||||
|
|||||||
@ -39,210 +39,210 @@
|
|||||||
|
|
||||||
using namespace spine;
|
using namespace spine;
|
||||||
|
|
||||||
SkeletonRenderer::SkeletonRenderer(): _allocator(4096), _worldVertices(), _quadIndices(), _clipping(), _renderCommands() {
|
SkeletonRenderer::SkeletonRenderer() : _allocator(4096), _worldVertices(), _quadIndices(), _clipping(), _renderCommands() {
|
||||||
_quadIndices.add(0);
|
_quadIndices.add(0);
|
||||||
_quadIndices.add(1);
|
_quadIndices.add(1);
|
||||||
_quadIndices.add(2);
|
_quadIndices.add(2);
|
||||||
_quadIndices.add(2);
|
_quadIndices.add(2);
|
||||||
_quadIndices.add(3);
|
_quadIndices.add(3);
|
||||||
_quadIndices.add(0);
|
_quadIndices.add(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
SkeletonRenderer::~SkeletonRenderer() {
|
SkeletonRenderer::~SkeletonRenderer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
static RenderCommand *createRenderCommand(BlockAllocator &allocator, int numVertices, int32_t numIndices, BlendMode blendMode, void *texture) {
|
static RenderCommand *createRenderCommand(BlockAllocator &allocator, int numVertices, int32_t numIndices, BlendMode blendMode, void *texture) {
|
||||||
RenderCommand *cmd = allocator.allocate<RenderCommand>(1);
|
RenderCommand *cmd = allocator.allocate<RenderCommand>(1);
|
||||||
cmd->positions = allocator.allocate<float>(numVertices << 1);
|
cmd->positions = allocator.allocate<float>(numVertices << 1);
|
||||||
cmd->uvs = allocator.allocate<float>(numVertices << 1);
|
cmd->uvs = allocator.allocate<float>(numVertices << 1);
|
||||||
cmd->colors = allocator.allocate<uint32_t>(numVertices);
|
cmd->colors = allocator.allocate<uint32_t>(numVertices);
|
||||||
cmd->darkColors = allocator.allocate<uint32_t>(numVertices);
|
cmd->darkColors = allocator.allocate<uint32_t>(numVertices);
|
||||||
cmd->numVertices = numVertices;
|
cmd->numVertices = numVertices;
|
||||||
cmd->indices = allocator.allocate<uint16_t>(numIndices);
|
cmd->indices = allocator.allocate<uint16_t>(numIndices);
|
||||||
cmd->numIndices = numIndices;
|
cmd->numIndices = numIndices;
|
||||||
cmd->blendMode = blendMode;
|
cmd->blendMode = blendMode;
|
||||||
cmd->texture = texture;
|
cmd->texture = texture;
|
||||||
cmd->next = nullptr;
|
cmd->next = nullptr;
|
||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
static RenderCommand *batchSubCommands(BlockAllocator &allocator, Vector<RenderCommand *> &commands, int first, int last, int numVertices, int numIndices) {
|
static RenderCommand *batchSubCommands(BlockAllocator &allocator, Vector<RenderCommand *> &commands, int first, int last, int numVertices, int numIndices) {
|
||||||
RenderCommand *batched = createRenderCommand(allocator, numVertices, numIndices, commands[first]->blendMode, commands[first]->texture);
|
RenderCommand *batched = createRenderCommand(allocator, numVertices, numIndices, commands[first]->blendMode, commands[first]->texture);
|
||||||
float *positions = batched->positions;
|
float *positions = batched->positions;
|
||||||
float *uvs = batched->uvs;
|
float *uvs = batched->uvs;
|
||||||
uint32_t *colors = batched->colors;
|
uint32_t *colors = batched->colors;
|
||||||
uint32_t *darkColors = batched->darkColors;
|
uint32_t *darkColors = batched->darkColors;
|
||||||
uint16_t *indices = batched->indices;
|
uint16_t *indices = batched->indices;
|
||||||
int indicesOffset = 0;
|
int indicesOffset = 0;
|
||||||
for (int i = first; i <= last; i++) {
|
for (int i = first; i <= last; i++) {
|
||||||
RenderCommand *cmd = commands[i];
|
RenderCommand *cmd = commands[i];
|
||||||
memcpy(positions, cmd->positions, sizeof(float) * 2 * cmd->numVertices);
|
memcpy(positions, cmd->positions, sizeof(float) * 2 * cmd->numVertices);
|
||||||
memcpy(uvs, cmd->uvs, sizeof(float) * 2 * cmd->numVertices);
|
memcpy(uvs, cmd->uvs, sizeof(float) * 2 * cmd->numVertices);
|
||||||
memcpy(colors, cmd->colors, sizeof(int32_t) * cmd->numVertices);
|
memcpy(colors, cmd->colors, sizeof(int32_t) * cmd->numVertices);
|
||||||
memcpy(darkColors, cmd->darkColors, sizeof(int32_t) * cmd->numVertices);
|
memcpy(darkColors, cmd->darkColors, sizeof(int32_t) * cmd->numVertices);
|
||||||
for (int ii = 0; ii < cmd->numIndices; ii++)
|
for (int ii = 0; ii < cmd->numIndices; ii++)
|
||||||
indices[ii] = cmd->indices[ii] + indicesOffset;
|
indices[ii] = cmd->indices[ii] + indicesOffset;
|
||||||
indicesOffset += cmd->numVertices;
|
indicesOffset += cmd->numVertices;
|
||||||
positions += 2 * cmd->numVertices;
|
positions += 2 * cmd->numVertices;
|
||||||
uvs += 2 * cmd->numVertices;
|
uvs += 2 * cmd->numVertices;
|
||||||
colors += cmd->numVertices;
|
colors += cmd->numVertices;
|
||||||
darkColors += cmd->numVertices;
|
darkColors += cmd->numVertices;
|
||||||
indices += cmd->numIndices;
|
indices += cmd->numIndices;
|
||||||
}
|
}
|
||||||
return batched;
|
return batched;
|
||||||
}
|
}
|
||||||
|
|
||||||
static RenderCommand *batchCommands(BlockAllocator &allocator, Vector<RenderCommand *> &commands) {
|
static RenderCommand *batchCommands(BlockAllocator &allocator, Vector<RenderCommand *> &commands) {
|
||||||
if (commands.size() == 0) return nullptr;
|
if (commands.size() == 0) return nullptr;
|
||||||
|
|
||||||
RenderCommand *root = nullptr;
|
RenderCommand *root = nullptr;
|
||||||
RenderCommand *last = nullptr;
|
RenderCommand *last = nullptr;
|
||||||
|
|
||||||
RenderCommand *first = commands[0];
|
RenderCommand *first = commands[0];
|
||||||
int startIndex = 0;
|
int startIndex = 0;
|
||||||
int i = 1;
|
int i = 1;
|
||||||
int numVertices = first->numVertices;
|
int numVertices = first->numVertices;
|
||||||
int numIndices = first->numIndices;
|
int numIndices = first->numIndices;
|
||||||
while (i <= (int) commands.size()) {
|
while (i <= (int) commands.size()) {
|
||||||
RenderCommand *cmd = i < (int) commands.size() ? commands[i] : nullptr;
|
RenderCommand *cmd = i < (int) commands.size() ? commands[i] : nullptr;
|
||||||
|
|
||||||
if (cmd && cmd->numVertices == 0 && cmd->numIndices == 0) {
|
if (cmd && cmd->numVertices == 0 && cmd->numIndices == 0) {
|
||||||
i++;
|
i++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmd != nullptr && cmd->texture == first->texture &&
|
if (cmd != nullptr && cmd->texture == first->texture &&
|
||||||
cmd->blendMode == first->blendMode &&
|
cmd->blendMode == first->blendMode &&
|
||||||
cmd->colors[0] == first->colors[0] &&
|
cmd->colors[0] == first->colors[0] &&
|
||||||
cmd->darkColors[0] == first->darkColors[0] &&
|
cmd->darkColors[0] == first->darkColors[0] &&
|
||||||
numIndices + cmd->numIndices < 0xffff) {
|
numIndices + cmd->numIndices < 0xffff) {
|
||||||
numVertices += cmd->numVertices;
|
numVertices += cmd->numVertices;
|
||||||
numIndices += cmd->numIndices;
|
numIndices += cmd->numIndices;
|
||||||
} else {
|
} else {
|
||||||
RenderCommand *batched = batchSubCommands(allocator, commands, startIndex, i - 1, numVertices, numIndices);
|
RenderCommand *batched = batchSubCommands(allocator, commands, startIndex, i - 1, numVertices, numIndices);
|
||||||
if (!last) {
|
if (!last) {
|
||||||
root = last = batched;
|
root = last = batched;
|
||||||
} else {
|
} else {
|
||||||
last->next = batched;
|
last->next = batched;
|
||||||
last = batched;
|
last = batched;
|
||||||
}
|
}
|
||||||
if (i == (int) commands.size()) break;
|
if (i == (int) commands.size()) break;
|
||||||
first = commands[i];
|
first = commands[i];
|
||||||
startIndex = i;
|
startIndex = i;
|
||||||
numVertices = first->numVertices;
|
numVertices = first->numVertices;
|
||||||
numIndices = first->numIndices;
|
numIndices = first->numIndices;
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
RenderCommand *SkeletonRenderer::render(Skeleton &skeleton) {
|
RenderCommand *SkeletonRenderer::render(Skeleton &skeleton) {
|
||||||
_allocator.compress();
|
_allocator.compress();
|
||||||
_renderCommands.clear();
|
_renderCommands.clear();
|
||||||
|
|
||||||
SkeletonClipping &clipper = _clipping;
|
SkeletonClipping &clipper = _clipping;
|
||||||
|
|
||||||
for (unsigned i = 0; i < skeleton.getSlots().size(); ++i) {
|
for (unsigned i = 0; i < skeleton.getSlots().size(); ++i) {
|
||||||
Slot &slot = *skeleton.getDrawOrder()[i];
|
Slot &slot = *skeleton.getDrawOrder()[i];
|
||||||
Attachment *attachment = slot.getAttachment();
|
Attachment *attachment = slot.getAttachment();
|
||||||
if (!attachment) {
|
if (!attachment) {
|
||||||
clipper.clipEnd(slot);
|
clipper.clipEnd(slot);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Early out if the slot color is 0 or the bone is not active
|
// Early out if the slot color is 0 or the bone is not active
|
||||||
if (slot.getColor().a == 0 || !slot.getBone().isActive()) {
|
if (slot.getColor().a == 0 || !slot.getBone().isActive()) {
|
||||||
clipper.clipEnd(slot);
|
clipper.clipEnd(slot);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector<float> *worldVertices = &_worldVertices;
|
Vector<float> *worldVertices = &_worldVertices;
|
||||||
Vector<unsigned short> *quadIndices = &_quadIndices;
|
Vector<unsigned short> *quadIndices = &_quadIndices;
|
||||||
Vector<float> *vertices = worldVertices;
|
Vector<float> *vertices = worldVertices;
|
||||||
int32_t verticesCount;
|
int32_t verticesCount;
|
||||||
Vector<float> *uvs;
|
Vector<float> *uvs;
|
||||||
Vector<unsigned short> *indices;
|
Vector<unsigned short> *indices;
|
||||||
int32_t indicesCount;
|
int32_t indicesCount;
|
||||||
Color *attachmentColor;
|
Color *attachmentColor;
|
||||||
void *texture;
|
void *texture;
|
||||||
|
|
||||||
if (attachment->getRTTI().isExactly(RegionAttachment::rtti)) {
|
if (attachment->getRTTI().isExactly(RegionAttachment::rtti)) {
|
||||||
RegionAttachment *regionAttachment = (RegionAttachment *) attachment;
|
RegionAttachment *regionAttachment = (RegionAttachment *) attachment;
|
||||||
attachmentColor = ®ionAttachment->getColor();
|
attachmentColor = ®ionAttachment->getColor();
|
||||||
|
|
||||||
// Early out if the slot color is 0
|
// Early out if the slot color is 0
|
||||||
if (attachmentColor->a == 0) {
|
if (attachmentColor->a == 0) {
|
||||||
clipper.clipEnd(slot);
|
clipper.clipEnd(slot);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
worldVertices->setSize(8, 0);
|
worldVertices->setSize(8, 0);
|
||||||
regionAttachment->computeWorldVertices(slot, *worldVertices, 0, 2);
|
regionAttachment->computeWorldVertices(slot, *worldVertices, 0, 2);
|
||||||
verticesCount = 4;
|
verticesCount = 4;
|
||||||
uvs = ®ionAttachment->getUVs();
|
uvs = ®ionAttachment->getUVs();
|
||||||
indices = quadIndices;
|
indices = quadIndices;
|
||||||
indicesCount = 6;
|
indicesCount = 6;
|
||||||
texture = regionAttachment->getRegion()->rendererObject;
|
texture = regionAttachment->getRegion()->rendererObject;
|
||||||
|
|
||||||
} else if (attachment->getRTTI().isExactly(MeshAttachment::rtti)) {
|
} else if (attachment->getRTTI().isExactly(MeshAttachment::rtti)) {
|
||||||
MeshAttachment *mesh = (MeshAttachment *) attachment;
|
MeshAttachment *mesh = (MeshAttachment *) attachment;
|
||||||
attachmentColor = &mesh->getColor();
|
attachmentColor = &mesh->getColor();
|
||||||
|
|
||||||
// Early out if the slot color is 0
|
// Early out if the slot color is 0
|
||||||
if (attachmentColor->a == 0) {
|
if (attachmentColor->a == 0) {
|
||||||
clipper.clipEnd(slot);
|
clipper.clipEnd(slot);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
worldVertices->setSize(mesh->getWorldVerticesLength(), 0);
|
worldVertices->setSize(mesh->getWorldVerticesLength(), 0);
|
||||||
mesh->computeWorldVertices(slot, 0, mesh->getWorldVerticesLength(), worldVertices->buffer(), 0, 2);
|
mesh->computeWorldVertices(slot, 0, mesh->getWorldVerticesLength(), worldVertices->buffer(), 0, 2);
|
||||||
verticesCount = (int32_t) (mesh->getWorldVerticesLength() >> 1);
|
verticesCount = (int32_t) (mesh->getWorldVerticesLength() >> 1);
|
||||||
uvs = &mesh->getUVs();
|
uvs = &mesh->getUVs();
|
||||||
indices = &mesh->getTriangles();
|
indices = &mesh->getTriangles();
|
||||||
indicesCount = (int32_t) indices->size();
|
indicesCount = (int32_t) indices->size();
|
||||||
texture = mesh->getRegion()->rendererObject;
|
texture = mesh->getRegion()->rendererObject;
|
||||||
|
|
||||||
} else if (attachment->getRTTI().isExactly(ClippingAttachment::rtti)) {
|
} else if (attachment->getRTTI().isExactly(ClippingAttachment::rtti)) {
|
||||||
ClippingAttachment *clip = (ClippingAttachment *) slot.getAttachment();
|
ClippingAttachment *clip = (ClippingAttachment *) slot.getAttachment();
|
||||||
clipper.clipStart(slot, clip);
|
clipper.clipStart(slot, clip);
|
||||||
continue;
|
continue;
|
||||||
} else
|
} else
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
uint8_t r = static_cast<uint8_t>(skeleton.getColor().r * slot.getColor().r * attachmentColor->r * 255);
|
uint8_t r = static_cast<uint8_t>(skeleton.getColor().r * slot.getColor().r * attachmentColor->r * 255);
|
||||||
uint8_t g = static_cast<uint8_t>(skeleton.getColor().g * slot.getColor().g * attachmentColor->g * 255);
|
uint8_t g = static_cast<uint8_t>(skeleton.getColor().g * slot.getColor().g * attachmentColor->g * 255);
|
||||||
uint8_t b = static_cast<uint8_t>(skeleton.getColor().b * slot.getColor().b * attachmentColor->b * 255);
|
uint8_t b = static_cast<uint8_t>(skeleton.getColor().b * slot.getColor().b * attachmentColor->b * 255);
|
||||||
uint8_t a = static_cast<uint8_t>(skeleton.getColor().a * slot.getColor().a * attachmentColor->a * 255);
|
uint8_t a = static_cast<uint8_t>(skeleton.getColor().a * slot.getColor().a * attachmentColor->a * 255);
|
||||||
uint32_t color = (a << 24) | (r << 16) | (g << 8) | b;
|
uint32_t color = (a << 24) | (r << 16) | (g << 8) | b;
|
||||||
uint32_t darkColor = 0xff000000;
|
uint32_t darkColor = 0xff000000;
|
||||||
if (slot.hasDarkColor()) {
|
if (slot.hasDarkColor()) {
|
||||||
Color &slotDarkColor = slot.getDarkColor();
|
Color &slotDarkColor = slot.getDarkColor();
|
||||||
darkColor = 0xff000000 | (static_cast<uint8_t>(slotDarkColor.r * 255) << 16) | (static_cast<uint8_t>(slotDarkColor.g * 255) << 8) | static_cast<uint8_t>(slotDarkColor.b * 255);
|
darkColor = 0xff000000 | (static_cast<uint8_t>(slotDarkColor.r * 255) << 16) | (static_cast<uint8_t>(slotDarkColor.g * 255) << 8) | static_cast<uint8_t>(slotDarkColor.b * 255);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clipper.isClipping()) {
|
if (clipper.isClipping()) {
|
||||||
clipper.clipTriangles(*worldVertices, *indices, *uvs, 2);
|
clipper.clipTriangles(*worldVertices, *indices, *uvs, 2);
|
||||||
vertices = &clipper.getClippedVertices();
|
vertices = &clipper.getClippedVertices();
|
||||||
verticesCount = (int32_t) (clipper.getClippedVertices().size() >> 1);
|
verticesCount = (int32_t) (clipper.getClippedVertices().size() >> 1);
|
||||||
uvs = &clipper.getClippedUVs();
|
uvs = &clipper.getClippedUVs();
|
||||||
indices = &clipper.getClippedTriangles();
|
indices = &clipper.getClippedTriangles();
|
||||||
indicesCount = (int32_t) (clipper.getClippedTriangles().size());
|
indicesCount = (int32_t) (clipper.getClippedTriangles().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderCommand *cmd = createRenderCommand(_allocator, verticesCount, indicesCount, slot.getData().getBlendMode(), texture);
|
RenderCommand *cmd = createRenderCommand(_allocator, verticesCount, indicesCount, slot.getData().getBlendMode(), texture);
|
||||||
_renderCommands.add(cmd);
|
_renderCommands.add(cmd);
|
||||||
memcpy(cmd->positions, vertices->buffer(), (verticesCount << 1) * sizeof(float));
|
memcpy(cmd->positions, vertices->buffer(), (verticesCount << 1) * sizeof(float));
|
||||||
memcpy(cmd->uvs, uvs->buffer(), (verticesCount << 1) * sizeof(float));
|
memcpy(cmd->uvs, uvs->buffer(), (verticesCount << 1) * sizeof(float));
|
||||||
for (int ii = 0; ii < verticesCount; ii++) {
|
for (int ii = 0; ii < verticesCount; ii++) {
|
||||||
cmd->colors[ii] = color;
|
cmd->colors[ii] = color;
|
||||||
cmd->darkColors[ii] = darkColor;
|
cmd->darkColors[ii] = darkColor;
|
||||||
}
|
}
|
||||||
memcpy(cmd->indices, indices->buffer(), indices->size() * sizeof(uint16_t));
|
memcpy(cmd->indices, indices->buffer(), indices->size() * sizeof(uint16_t));
|
||||||
clipper.clipEnd(slot);
|
clipper.clipEnd(slot);
|
||||||
}
|
}
|
||||||
clipper.clipEnd();
|
clipper.clipEnd();
|
||||||
|
|
||||||
return batchCommands(_allocator, _renderCommands);
|
return batchCommands(_allocator, _renderCommands);
|
||||||
}
|
}
|
||||||
@ -9,92 +9,92 @@ using namespace spine;
|
|||||||
|
|
||||||
int width = 800, height = 600;
|
int width = 800, height = 600;
|
||||||
|
|
||||||
GLFWwindow* init_glfw() {
|
GLFWwindow *init_glfw() {
|
||||||
if (!glfwInit()) {
|
if (!glfwInit()) {
|
||||||
std::cerr << "Failed to initialize GLFW" << std::endl;
|
std::cerr << "Failed to initialize GLFW" << std::endl;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
||||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||||
GLFWwindow* window = glfwCreateWindow(width, height, "spine-glfw", NULL, NULL);
|
GLFWwindow *window = glfwCreateWindow(width, height, "spine-glfw", NULL, NULL);
|
||||||
if (!window) {
|
if (!window) {
|
||||||
std::cerr << "Failed to create GLFW window" << std::endl;
|
std::cerr << "Failed to create GLFW window" << std::endl;
|
||||||
glfwTerminate();
|
glfwTerminate();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
glfwMakeContextCurrent(window);
|
glfwMakeContextCurrent(window);
|
||||||
glbinding::initialize(glfwGetProcAddress);
|
glbinding::initialize(glfwGetProcAddress);
|
||||||
return window;
|
return window;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
// Initialize GLFW and glbinding
|
// Initialize GLFW and glbinding
|
||||||
GLFWwindow *window = init_glfw();
|
GLFWwindow *window = init_glfw();
|
||||||
if (!window) return -1;
|
if (!window) return -1;
|
||||||
|
|
||||||
// We use a y-down coordinate system, see renderer_set_viewport_size()
|
// We use a y-down coordinate system, see renderer_set_viewport_size()
|
||||||
Bone::setYDown(true);
|
Bone::setYDown(true);
|
||||||
|
|
||||||
// Load the atlas and the skeleton data
|
// Load the atlas and the skeleton data
|
||||||
GlTextureLoader textureLoader;
|
GlTextureLoader textureLoader;
|
||||||
Atlas *atlas = new Atlas("data/spineboy-pma.atlas", &textureLoader);
|
Atlas *atlas = new Atlas("data/spineboy-pma.atlas", &textureLoader);
|
||||||
SkeletonJson json(atlas);
|
SkeletonJson json(atlas);
|
||||||
SkeletonData *skeletonData = json.readSkeletonDataFile("data/spineboy-pro.json");
|
SkeletonData *skeletonData = json.readSkeletonDataFile("data/spineboy-pro.json");
|
||||||
|
|
||||||
// Create a skeleton from the data, set the skeleton's position to the bottom center of
|
// Create a skeleton from the data, set the skeleton's position to the bottom center of
|
||||||
// the screen and scale it to make it smaller.
|
// the screen and scale it to make it smaller.
|
||||||
Skeleton skeleton(skeletonData);
|
Skeleton skeleton(skeletonData);
|
||||||
skeleton.setPosition(width / 2, height - 100);
|
skeleton.setPosition(width / 2, height - 100);
|
||||||
skeleton.setScaleX(0.3);
|
skeleton.setScaleX(0.3);
|
||||||
skeleton.setScaleY(0.3);
|
skeleton.setScaleY(0.3);
|
||||||
|
|
||||||
// Create an AnimationState to drive animations on the skeleton. Set the "portal" animation
|
// Create an AnimationState to drive animations on the skeleton. Set the "portal" animation
|
||||||
// on track with index 0.
|
// on track with index 0.
|
||||||
AnimationStateData animationStateData(skeletonData);
|
AnimationStateData animationStateData(skeletonData);
|
||||||
AnimationState animationState(&animationStateData);
|
AnimationState animationState(&animationStateData);
|
||||||
animationState.setAnimation(0, "portal", true);
|
animationState.setAnimation(0, "portal", true);
|
||||||
|
|
||||||
// Create the renderer and set the viewport size to match the window size. This sets up a
|
// Create the renderer and set the viewport size to match the window size. This sets up a
|
||||||
// pixel perfect orthogonal projection for 2D rendering.
|
// pixel perfect orthogonal projection for 2D rendering.
|
||||||
renderer_t *renderer = renderer_create();
|
renderer_t *renderer = renderer_create();
|
||||||
renderer_set_viewport_size(renderer, width, height);
|
renderer_set_viewport_size(renderer, width, height);
|
||||||
|
|
||||||
// Rendering loop
|
// Rendering loop
|
||||||
double lastTime = glfwGetTime();
|
double lastTime = glfwGetTime();
|
||||||
while (!glfwWindowShouldClose(window)) {
|
while (!glfwWindowShouldClose(window)) {
|
||||||
// Calculate the delta time in seconds
|
// Calculate the delta time in seconds
|
||||||
double currTime = glfwGetTime();
|
double currTime = glfwGetTime();
|
||||||
float delta = currTime - lastTime;
|
float delta = currTime - lastTime;
|
||||||
lastTime = currTime;
|
lastTime = currTime;
|
||||||
|
|
||||||
// Update and apply the animation state to the skeleton
|
// Update and apply the animation state to the skeleton
|
||||||
animationState.update(delta);
|
animationState.update(delta);
|
||||||
animationState.apply(skeleton);
|
animationState.apply(skeleton);
|
||||||
|
|
||||||
// Update the skeleton time (used for physics)
|
// Update the skeleton time (used for physics)
|
||||||
skeleton.update(delta);
|
skeleton.update(delta);
|
||||||
|
|
||||||
// Calculate the new pose
|
// Calculate the new pose
|
||||||
skeleton.updateWorldTransform(spine::Physics_Update);
|
skeleton.updateWorldTransform(spine::Physics_Update);
|
||||||
|
|
||||||
// Clear the screen
|
// Clear the screen
|
||||||
gl::glClear(gl::GL_COLOR_BUFFER_BIT);
|
gl::glClear(gl::GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
// Render the skeleton in its current pose
|
// Render the skeleton in its current pose
|
||||||
renderer_draw(renderer, &skeleton, true);
|
renderer_draw(renderer, &skeleton, true);
|
||||||
|
|
||||||
// Present the rendering results and poll for events
|
// Present the rendering results and poll for events
|
||||||
glfwSwapBuffers(window);
|
glfwSwapBuffers(window);
|
||||||
glfwPollEvents();
|
glfwPollEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dispose everything
|
// Dispose everything
|
||||||
renderer_dispose(renderer);
|
renderer_dispose(renderer);
|
||||||
delete skeletonData;
|
delete skeletonData;
|
||||||
delete atlas;
|
delete atlas;
|
||||||
|
|
||||||
// Kill the window and GLFW
|
// Kill the window and GLFW
|
||||||
glfwTerminate();
|
glfwTerminate();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,231 +9,230 @@ using namespace spine;
|
|||||||
|
|
||||||
/// Set the default extension used for memory allocations and file I/O
|
/// Set the default extension used for memory allocations and file I/O
|
||||||
SpineExtension *spine::getDefaultExtension() {
|
SpineExtension *spine::getDefaultExtension() {
|
||||||
return new spine::DefaultSpineExtension();
|
return new spine::DefaultSpineExtension();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A blend mode, see https://en.esotericsoftware.com/spine-slots#Blending
|
/// A blend mode, see https://en.esotericsoftware.com/spine-slots#Blending
|
||||||
/// Encodes the OpenGL source and destination blend function for both premultiplied and
|
/// Encodes the OpenGL source and destination blend function for both premultiplied and
|
||||||
/// non-premultiplied alpha blending.
|
/// non-premultiplied alpha blending.
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned int source_color;
|
unsigned int source_color;
|
||||||
unsigned int source_color_pma;
|
unsigned int source_color_pma;
|
||||||
unsigned int dest_color;
|
unsigned int dest_color;
|
||||||
unsigned int source_alpha;
|
unsigned int source_alpha;
|
||||||
} blend_mode_t;
|
} blend_mode_t;
|
||||||
|
|
||||||
/// The 4 supported blend modes SPINE_BLEND_MODE_NORMAL, SPINE_BLEND_MODE_ADDITIVE, SPINE_BLEND_MODE_MULTIPLY,
|
/// The 4 supported blend modes SPINE_BLEND_MODE_NORMAL, SPINE_BLEND_MODE_ADDITIVE, SPINE_BLEND_MODE_MULTIPLY,
|
||||||
/// and SPINE_BLEND_MODE_SCREEN, expressed as OpenGL blend functions.
|
/// and SPINE_BLEND_MODE_SCREEN, expressed as OpenGL blend functions.
|
||||||
blend_mode_t blend_modes[] = {
|
blend_mode_t blend_modes[] = {
|
||||||
{(unsigned int)GL_SRC_ALPHA, (unsigned int)GL_ONE, (unsigned int)GL_ONE_MINUS_SRC_ALPHA, (unsigned int)GL_ONE},
|
{(unsigned int) GL_SRC_ALPHA, (unsigned int) GL_ONE, (unsigned int) GL_ONE_MINUS_SRC_ALPHA, (unsigned int) GL_ONE},
|
||||||
{(unsigned int)GL_SRC_ALPHA, (unsigned int)GL_ONE, (unsigned int)GL_ONE, (unsigned int)GL_ONE},
|
{(unsigned int) GL_SRC_ALPHA, (unsigned int) GL_ONE, (unsigned int) GL_ONE, (unsigned int) GL_ONE},
|
||||||
{(unsigned int)GL_DST_COLOR, (unsigned int)GL_DST_COLOR, (unsigned int)GL_ONE_MINUS_SRC_ALPHA, (unsigned int)GL_ONE_MINUS_SRC_ALPHA},
|
{(unsigned int) GL_DST_COLOR, (unsigned int) GL_DST_COLOR, (unsigned int) GL_ONE_MINUS_SRC_ALPHA, (unsigned int) GL_ONE_MINUS_SRC_ALPHA},
|
||||||
{(unsigned int)GL_ONE, (unsigned int)GL_ONE, (unsigned int)GL_ONE_MINUS_SRC_COLOR, (unsigned int)GL_ONE_MINUS_SRC_COLOR}
|
{(unsigned int) GL_ONE, (unsigned int) GL_ONE, (unsigned int) GL_ONE_MINUS_SRC_COLOR, (unsigned int) GL_ONE_MINUS_SRC_COLOR}};
|
||||||
};
|
|
||||||
|
|
||||||
mesh_t *mesh_create() {
|
mesh_t *mesh_create() {
|
||||||
GLuint vao, vbo, ibo;
|
GLuint vao, vbo, ibo;
|
||||||
glGenVertexArrays(1, &vao);
|
glGenVertexArrays(1, &vao);
|
||||||
glGenBuffers(1, &vbo);
|
glGenBuffers(1, &vbo);
|
||||||
glGenBuffers(1, &ibo);
|
glGenBuffers(1, &ibo);
|
||||||
|
|
||||||
glBindVertexArray(vao);
|
glBindVertexArray(vao);
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
|
||||||
|
|
||||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (void*)offsetof(vertex_t, x));
|
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (void *) offsetof(vertex_t, x));
|
||||||
glEnableVertexAttribArray(0);
|
glEnableVertexAttribArray(0);
|
||||||
|
|
||||||
glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(vertex_t), (void*)offsetof(vertex_t, color));
|
glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(vertex_t), (void *) offsetof(vertex_t, color));
|
||||||
glEnableVertexAttribArray(1);
|
glEnableVertexAttribArray(1);
|
||||||
|
|
||||||
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (void*)offsetof(vertex_t, u));
|
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (void *) offsetof(vertex_t, u));
|
||||||
glEnableVertexAttribArray(2);
|
glEnableVertexAttribArray(2);
|
||||||
|
|
||||||
glVertexAttribPointer(3, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(vertex_t), (void*)offsetof(vertex_t, darkColor));
|
glVertexAttribPointer(3, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(vertex_t), (void *) offsetof(vertex_t, darkColor));
|
||||||
glEnableVertexAttribArray(3);
|
glEnableVertexAttribArray(3);
|
||||||
|
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
|
|
||||||
auto *mesh = (mesh_t*)malloc(sizeof(mesh_t));
|
auto *mesh = (mesh_t *) malloc(sizeof(mesh_t));
|
||||||
mesh->vao = vao;
|
mesh->vao = vao;
|
||||||
mesh->vbo = vbo;
|
mesh->vbo = vbo;
|
||||||
mesh->num_vertices = 0;
|
mesh->num_vertices = 0;
|
||||||
mesh->ibo = ibo;
|
mesh->ibo = ibo;
|
||||||
mesh->num_indices = 0;
|
mesh->num_indices = 0;
|
||||||
return mesh;
|
return mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mesh_update(mesh_t *mesh, vertex_t *vertices, int num_vertices, uint16_t *indices, int num_indices) {
|
void mesh_update(mesh_t *mesh, vertex_t *vertices, int num_vertices, uint16_t *indices, int num_indices) {
|
||||||
glBindVertexArray(mesh->vao);
|
glBindVertexArray(mesh->vao);
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, mesh->vbo);
|
glBindBuffer(GL_ARRAY_BUFFER, mesh->vbo);
|
||||||
glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)(num_vertices * sizeof(vertex_t)), vertices, GL_STATIC_DRAW);
|
glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr) (num_vertices * sizeof(vertex_t)), vertices, GL_STATIC_DRAW);
|
||||||
mesh->num_vertices = num_vertices;
|
mesh->num_vertices = num_vertices;
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->ibo);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->ibo);
|
||||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)(num_indices * sizeof(uint16_t)), indices, GL_STATIC_DRAW);
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr) (num_indices * sizeof(uint16_t)), indices, GL_STATIC_DRAW);
|
||||||
mesh->num_indices = num_indices;
|
mesh->num_indices = num_indices;
|
||||||
|
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mesh_draw(mesh_t *mesh) {
|
void mesh_draw(mesh_t *mesh) {
|
||||||
glBindVertexArray(mesh->vao);
|
glBindVertexArray(mesh->vao);
|
||||||
glDrawElements(GL_TRIANGLES, mesh->num_indices, GL_UNSIGNED_SHORT, nullptr);
|
glDrawElements(GL_TRIANGLES, mesh->num_indices, GL_UNSIGNED_SHORT, nullptr);
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mesh_dispose(mesh_t *mesh) {
|
void mesh_dispose(mesh_t *mesh) {
|
||||||
glDeleteBuffers(1, &mesh->vbo);
|
glDeleteBuffers(1, &mesh->vbo);
|
||||||
glDeleteBuffers(1, &mesh->ibo);
|
glDeleteBuffers(1, &mesh->ibo);
|
||||||
glDeleteVertexArrays(1, &mesh->vao);
|
glDeleteVertexArrays(1, &mesh->vao);
|
||||||
free(mesh);
|
free(mesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
GLuint compile_shader(const char* source, GLenum type) {
|
GLuint compile_shader(const char *source, GLenum type) {
|
||||||
GLuint shader = glCreateShader(type);
|
GLuint shader = glCreateShader(type);
|
||||||
glShaderSource(shader, 1, &source, nullptr);
|
glShaderSource(shader, 1, &source, nullptr);
|
||||||
glCompileShader(shader);
|
glCompileShader(shader);
|
||||||
|
|
||||||
GLint success;
|
GLint success;
|
||||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
char infoLog[512];
|
char infoLog[512];
|
||||||
glGetShaderInfoLog(shader, 512, nullptr, infoLog);
|
glGetShaderInfoLog(shader, 512, nullptr, infoLog);
|
||||||
printf("Error, shader compilation failed:\n%s\n", infoLog);
|
printf("Error, shader compilation failed:\n%s\n", infoLog);
|
||||||
glDeleteShader(shader);
|
glDeleteShader(shader);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return shader;
|
return shader;
|
||||||
}
|
}
|
||||||
|
|
||||||
shader_t shader_create(const char* vertex_shader, const char* fragment_shader) {
|
shader_t shader_create(const char *vertex_shader, const char *fragment_shader) {
|
||||||
shader_t program;
|
shader_t program;
|
||||||
|
|
||||||
GLuint vertex_shader_id = compile_shader(vertex_shader, GL_VERTEX_SHADER);
|
GLuint vertex_shader_id = compile_shader(vertex_shader, GL_VERTEX_SHADER);
|
||||||
GLuint fragment_shader_id = compile_shader(fragment_shader, GL_FRAGMENT_SHADER);
|
GLuint fragment_shader_id = compile_shader(fragment_shader, GL_FRAGMENT_SHADER);
|
||||||
if (!vertex_shader_id || !fragment_shader_id) {
|
if (!vertex_shader_id || !fragment_shader_id) {
|
||||||
glDeleteShader(vertex_shader_id);
|
glDeleteShader(vertex_shader_id);
|
||||||
glDeleteShader(fragment_shader_id);
|
glDeleteShader(fragment_shader_id);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
program = glCreateProgram();
|
program = glCreateProgram();
|
||||||
glAttachShader(program, vertex_shader_id);
|
glAttachShader(program, vertex_shader_id);
|
||||||
glAttachShader(program, fragment_shader_id);
|
glAttachShader(program, fragment_shader_id);
|
||||||
glLinkProgram(program);
|
glLinkProgram(program);
|
||||||
|
|
||||||
GLint success;
|
GLint success;
|
||||||
glGetProgramiv(program, GL_LINK_STATUS, &success);
|
glGetProgramiv(program, GL_LINK_STATUS, &success);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
char infoLog[512];
|
char infoLog[512];
|
||||||
glGetProgramInfoLog(program, 512, nullptr, infoLog);
|
glGetProgramInfoLog(program, 512, nullptr, infoLog);
|
||||||
printf("Error, shader linking failed:\n%s\n", infoLog);
|
printf("Error, shader linking failed:\n%s\n", infoLog);
|
||||||
glDeleteProgram(program);
|
glDeleteProgram(program);
|
||||||
program = 0;
|
program = 0;
|
||||||
}
|
}
|
||||||
glDeleteShader(vertex_shader_id);
|
glDeleteShader(vertex_shader_id);
|
||||||
glDeleteShader(fragment_shader_id);
|
glDeleteShader(fragment_shader_id);
|
||||||
return program;
|
return program;
|
||||||
}
|
}
|
||||||
|
|
||||||
void shader_set_matrix4(shader_t shader, const char* name, const float *matrix) {
|
void shader_set_matrix4(shader_t shader, const char *name, const float *matrix) {
|
||||||
shader_use(shader);
|
shader_use(shader);
|
||||||
GLint location = glGetUniformLocation(shader, name);
|
GLint location = glGetUniformLocation(shader, name);
|
||||||
glUniformMatrix4fv(location, 1, GL_FALSE, matrix);
|
glUniformMatrix4fv(location, 1, GL_FALSE, matrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
void shader_set_float(shader_t shader, const char* name, float value) {
|
void shader_set_float(shader_t shader, const char *name, float value) {
|
||||||
shader_use(shader);
|
shader_use(shader);
|
||||||
GLint location = glGetUniformLocation(shader, name);
|
GLint location = glGetUniformLocation(shader, name);
|
||||||
glUniform1f(location, value);
|
glUniform1f(location, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void shader_set_int(shader_t shader, const char* name, int value) {
|
void shader_set_int(shader_t shader, const char *name, int value) {
|
||||||
shader_use(shader);
|
shader_use(shader);
|
||||||
GLint location = glGetUniformLocation(shader, name);
|
GLint location = glGetUniformLocation(shader, name);
|
||||||
glUniform1i(location, value);
|
glUniform1i(location, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void shader_use(shader_t program) {
|
void shader_use(shader_t program) {
|
||||||
glUseProgram(program);
|
glUseProgram(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
void shader_dispose(shader_t program) {
|
void shader_dispose(shader_t program) {
|
||||||
glDeleteProgram(program);
|
glDeleteProgram(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
texture_t texture_load(const char *file_path) {
|
texture_t texture_load(const char *file_path) {
|
||||||
int width, height, nrChannels;
|
int width, height, nrChannels;
|
||||||
unsigned char *data = stbi_load(file_path, &width, &height, &nrChannels, 0);
|
unsigned char *data = stbi_load(file_path, &width, &height, &nrChannels, 0);
|
||||||
if (!data) {
|
if (!data) {
|
||||||
printf("Failed to load texture\n");
|
printf("Failed to load texture\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLenum format = GL_RGBA;
|
GLenum format = GL_RGBA;
|
||||||
if (nrChannels == 1)
|
if (nrChannels == 1)
|
||||||
format = GL_RED;
|
format = GL_RED;
|
||||||
else if (nrChannels == 3)
|
else if (nrChannels == 3)
|
||||||
format = GL_RGB;
|
format = GL_RGB;
|
||||||
else if (nrChannels == 4)
|
else if (nrChannels == 4)
|
||||||
format = GL_RGBA;
|
format = GL_RGBA;
|
||||||
|
|
||||||
texture_t texture;
|
texture_t texture;
|
||||||
glGenTextures(1, &texture);
|
glGenTextures(1, &texture);
|
||||||
glBindTexture(GL_TEXTURE_2D, texture);
|
glBindTexture(GL_TEXTURE_2D, texture);
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
|
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
|
||||||
glGenerateMipmap(GL_TEXTURE_2D);
|
glGenerateMipmap(GL_TEXTURE_2D);
|
||||||
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
|
||||||
stbi_image_free(data);
|
stbi_image_free(data);
|
||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
void texture_use(texture_t texture) {
|
void texture_use(texture_t texture) {
|
||||||
glActiveTexture(GL_TEXTURE0); // Set active texture unit to 0
|
glActiveTexture(GL_TEXTURE0);// Set active texture unit to 0
|
||||||
glBindTexture(GL_TEXTURE_2D, texture);
|
glBindTexture(GL_TEXTURE_2D, texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
void texture_dispose(texture_t texture) {
|
void texture_dispose(texture_t texture) {
|
||||||
glDeleteTextures(1, &texture);
|
glDeleteTextures(1, &texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
void matrix_ortho_projection(float *matrix, float width, float height) {
|
void matrix_ortho_projection(float *matrix, float width, float height) {
|
||||||
memset(matrix, 0, 16 * sizeof(float));
|
memset(matrix, 0, 16 * sizeof(float));
|
||||||
|
|
||||||
float left = 0.0f;
|
float left = 0.0f;
|
||||||
float right = width;
|
float right = width;
|
||||||
float bottom = height;
|
float bottom = height;
|
||||||
float top = 0.0f;
|
float top = 0.0f;
|
||||||
float near = -1.0f;
|
float near = -1.0f;
|
||||||
float far = 1.0f;
|
float far = 1.0f;
|
||||||
|
|
||||||
matrix[0] = 2.0f / (right - left);
|
matrix[0] = 2.0f / (right - left);
|
||||||
matrix[5] = 2.0f / (top - bottom);
|
matrix[5] = 2.0f / (top - bottom);
|
||||||
matrix[10] = -2.0f / (far - near);
|
matrix[10] = -2.0f / (far - near);
|
||||||
matrix[12] = -(right + left) / (right - left);
|
matrix[12] = -(right + left) / (right - left);
|
||||||
matrix[13] = -(top + bottom) / (top - bottom);
|
matrix[13] = -(top + bottom) / (top - bottom);
|
||||||
matrix[14] = -(far + near) / (far - near);
|
matrix[14] = -(far + near) / (far - near);
|
||||||
matrix[15] = 1.0f;
|
matrix[15] = 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlTextureLoader::load(spine::AtlasPage &page, const spine::String &path) {
|
void GlTextureLoader::load(spine::AtlasPage &page, const spine::String &path) {
|
||||||
page.texture = (void *)(uintptr_t)texture_load(path.buffer());
|
page.texture = (void *) (uintptr_t) texture_load(path.buffer());
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlTextureLoader::unload(void *texture) {
|
void GlTextureLoader::unload(void *texture) {
|
||||||
texture_dispose((texture_t)(uintptr_t)texture);
|
texture_dispose((texture_t) (uintptr_t) texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderer_t *renderer_create() {
|
renderer_t *renderer_create() {
|
||||||
shader_t shader = shader_create(R"(
|
shader_t shader = shader_create(R"(
|
||||||
#version 330 core
|
#version 330 core
|
||||||
layout (location = 0) in vec2 aPos;
|
layout (location = 0) in vec2 aPos;
|
||||||
layout (location = 1) in vec4 aLightColor;
|
layout (location = 1) in vec4 aLightColor;
|
||||||
@ -252,7 +251,8 @@ renderer_t *renderer_create() {
|
|||||||
texCoord = aTexCoord;
|
texCoord = aTexCoord;
|
||||||
gl_Position = uMatrix * vec4(aPos, 0.0, 1.0);
|
gl_Position = uMatrix * vec4(aPos, 0.0, 1.0);
|
||||||
}
|
}
|
||||||
)", R"(
|
)",
|
||||||
|
R"(
|
||||||
#version 330 core
|
#version 330 core
|
||||||
in vec4 lightColor;
|
in vec4 lightColor;
|
||||||
in vec4 darkColor;
|
in vec4 darkColor;
|
||||||
@ -267,71 +267,71 @@ renderer_t *renderer_create() {
|
|||||||
fragColor.rgb = ((texColor.a - 1.0) * darkColor.a + 1.0 - texColor.rgb) * darkColor.rgb + texColor.rgb * lightColor.rgb;
|
fragColor.rgb = ((texColor.a - 1.0) * darkColor.a + 1.0 - texColor.rgb) * darkColor.rgb + texColor.rgb * lightColor.rgb;
|
||||||
}
|
}
|
||||||
)");
|
)");
|
||||||
if (!shader) return nullptr;
|
if (!shader) return nullptr;
|
||||||
mesh_t *mesh = mesh_create();
|
mesh_t *mesh = mesh_create();
|
||||||
auto *renderer = (renderer_t*)malloc(sizeof(renderer_t));
|
auto *renderer = (renderer_t *) malloc(sizeof(renderer_t));
|
||||||
renderer->shader = shader;
|
renderer->shader = shader;
|
||||||
renderer->mesh = mesh;
|
renderer->mesh = mesh;
|
||||||
renderer->vertex_buffer_size = 0;
|
renderer->vertex_buffer_size = 0;
|
||||||
renderer->vertex_buffer = nullptr;
|
renderer->vertex_buffer = nullptr;
|
||||||
renderer->renderer = new SkeletonRenderer();
|
renderer->renderer = new SkeletonRenderer();
|
||||||
return renderer;
|
return renderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderer_set_viewport_size(renderer_t *renderer, int width, int height) {
|
void renderer_set_viewport_size(renderer_t *renderer, int width, int height) {
|
||||||
float matrix[16];
|
float matrix[16];
|
||||||
matrix_ortho_projection(matrix, (float)width, (float)height);
|
matrix_ortho_projection(matrix, (float) width, (float) height);
|
||||||
shader_use(renderer->shader);
|
shader_use(renderer->shader);
|
||||||
shader_set_matrix4(renderer->shader, "uMatrix", matrix);
|
shader_set_matrix4(renderer->shader, "uMatrix", matrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderer_draw(renderer_t *renderer, Skeleton *skeleton, bool premultipliedAlpha) {
|
void renderer_draw(renderer_t *renderer, Skeleton *skeleton, bool premultipliedAlpha) {
|
||||||
shader_use(renderer->shader);
|
shader_use(renderer->shader);
|
||||||
shader_set_int(renderer->shader, "uTexture", 0);
|
shader_set_int(renderer->shader, "uTexture", 0);
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
|
|
||||||
RenderCommand *command = renderer->renderer->render(*skeleton);
|
RenderCommand *command = renderer->renderer->render(*skeleton);
|
||||||
while (command) {
|
while (command) {
|
||||||
int num_command_vertices = command->numVertices;
|
int num_command_vertices = command->numVertices;
|
||||||
if (renderer->vertex_buffer_size < num_command_vertices) {
|
if (renderer->vertex_buffer_size < num_command_vertices) {
|
||||||
renderer->vertex_buffer_size = num_command_vertices;
|
renderer->vertex_buffer_size = num_command_vertices;
|
||||||
free(renderer->vertex_buffer);
|
free(renderer->vertex_buffer);
|
||||||
renderer->vertex_buffer = (vertex_t *)malloc(sizeof(vertex_t) * renderer->vertex_buffer_size);
|
renderer->vertex_buffer = (vertex_t *) malloc(sizeof(vertex_t) * renderer->vertex_buffer_size);
|
||||||
}
|
}
|
||||||
float *positions = command->positions;
|
float *positions = command->positions;
|
||||||
float *uvs = command->uvs;
|
float *uvs = command->uvs;
|
||||||
int32_t *colors = command->colors;
|
int32_t *colors = command->colors;
|
||||||
int32_t *darkColors = command->darkColors;
|
int32_t *darkColors = command->darkColors;
|
||||||
for (int i = 0, j = 0; i < num_command_vertices; i++, j += 2) {
|
for (int i = 0, j = 0; i < num_command_vertices; i++, j += 2) {
|
||||||
vertex_t *vertex = &renderer->vertex_buffer[i];
|
vertex_t *vertex = &renderer->vertex_buffer[i];
|
||||||
vertex->x = positions[j];
|
vertex->x = positions[j];
|
||||||
vertex->y = positions[j + 1];
|
vertex->y = positions[j + 1];
|
||||||
vertex->u = uvs[j];
|
vertex->u = uvs[j];
|
||||||
vertex->v = uvs[j+1];
|
vertex->v = uvs[j + 1];
|
||||||
uint32_t color = colors[i];
|
uint32_t color = colors[i];
|
||||||
vertex->color = (color & 0xFF00FF00) | ((color & 0x00FF0000) >> 16) | ((color & 0x000000FF) << 16);
|
vertex->color = (color & 0xFF00FF00) | ((color & 0x00FF0000) >> 16) | ((color & 0x000000FF) << 16);
|
||||||
uint32_t darkColor = darkColors[i];
|
uint32_t darkColor = darkColors[i];
|
||||||
vertex->darkColor = (darkColor & 0xFF00FF00) | ((darkColor & 0x00FF0000) >> 16) | ((darkColor & 0x000000FF) << 16);
|
vertex->darkColor = (darkColor & 0xFF00FF00) | ((darkColor & 0x00FF0000) >> 16) | ((darkColor & 0x000000FF) << 16);
|
||||||
}
|
}
|
||||||
int num_command_indices = command->numIndices;
|
int num_command_indices = command->numIndices;
|
||||||
uint16_t *indices = command->indices;
|
uint16_t *indices = command->indices;
|
||||||
mesh_update(renderer->mesh, renderer->vertex_buffer, num_command_vertices, indices, num_command_indices);
|
mesh_update(renderer->mesh, renderer->vertex_buffer, num_command_vertices, indices, num_command_indices);
|
||||||
|
|
||||||
blend_mode_t blend_mode = blend_modes[command->blendMode];
|
blend_mode_t blend_mode = blend_modes[command->blendMode];
|
||||||
glBlendFuncSeparate(premultipliedAlpha ? (GLenum)blend_mode.source_color_pma : (GLenum)blend_mode.source_color, (GLenum)blend_mode.dest_color, (GLenum)blend_mode.source_alpha, (GLenum)blend_mode.dest_color);
|
glBlendFuncSeparate(premultipliedAlpha ? (GLenum) blend_mode.source_color_pma : (GLenum) blend_mode.source_color, (GLenum) blend_mode.dest_color, (GLenum) blend_mode.source_alpha, (GLenum) blend_mode.dest_color);
|
||||||
|
|
||||||
auto texture = (texture_t)(uintptr_t)command->texture;
|
auto texture = (texture_t) (uintptr_t) command->texture;
|
||||||
texture_use(texture);
|
texture_use(texture);
|
||||||
|
|
||||||
mesh_draw(renderer->mesh);
|
mesh_draw(renderer->mesh);
|
||||||
command = command->next;
|
command = command->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderer_dispose(renderer_t *renderer) {
|
void renderer_dispose(renderer_t *renderer) {
|
||||||
shader_dispose(renderer->shader);
|
shader_dispose(renderer->shader);
|
||||||
mesh_dispose(renderer->mesh);
|
mesh_dispose(renderer->mesh);
|
||||||
free(renderer->vertex_buffer);
|
free(renderer->vertex_buffer);
|
||||||
delete renderer->renderer;
|
delete renderer->renderer;
|
||||||
free(renderer);
|
free(renderer);
|
||||||
}
|
}
|
||||||
@ -5,20 +5,20 @@
|
|||||||
|
|
||||||
/// A vertex of a mesh generated from a Spine skeleton
|
/// A vertex of a mesh generated from a Spine skeleton
|
||||||
struct vertex_t {
|
struct vertex_t {
|
||||||
float x, y;
|
float x, y;
|
||||||
uint32_t color;
|
uint32_t color;
|
||||||
float u, v;
|
float u, v;
|
||||||
uint32_t darkColor;
|
uint32_t darkColor;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A GPU-side mesh using OpenGL vertex arrays, vertex buffer, and
|
/// A GPU-side mesh using OpenGL vertex arrays, vertex buffer, and
|
||||||
/// indices buffer.
|
/// indices buffer.
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned int vao;
|
unsigned int vao;
|
||||||
unsigned int vbo;
|
unsigned int vbo;
|
||||||
int num_vertices;
|
int num_vertices;
|
||||||
unsigned int ibo;
|
unsigned int ibo;
|
||||||
int num_indices;
|
int num_indices;
|
||||||
} mesh_t;
|
} mesh_t;
|
||||||
|
|
||||||
mesh_t *mesh_create();
|
mesh_t *mesh_create();
|
||||||
@ -33,13 +33,13 @@ typedef unsigned int shader_t;
|
|||||||
shader_t shader_create(const char *vertex_shader, const char *fragment_shader);
|
shader_t shader_create(const char *vertex_shader, const char *fragment_shader);
|
||||||
|
|
||||||
/// Sets a uniform matrix by name
|
/// Sets a uniform matrix by name
|
||||||
void shader_set_matrix4(shader_t program, const char* name, const float *matrix);
|
void shader_set_matrix4(shader_t program, const char *name, const float *matrix);
|
||||||
|
|
||||||
/// Sets a uniform float by name
|
/// Sets a uniform float by name
|
||||||
void shader_set_float(shader_t program, const char* name, float value);
|
void shader_set_float(shader_t program, const char *name, float value);
|
||||||
|
|
||||||
/// Sets a uniform int by name
|
/// Sets a uniform int by name
|
||||||
void shader_set_int(shader_t program, const char* name, int value);
|
void shader_set_int(shader_t program, const char *name, int value);
|
||||||
|
|
||||||
/// Binds the shader
|
/// Binds the shader
|
||||||
void shader_use(shader_t shader);
|
void shader_use(shader_t shader);
|
||||||
@ -60,20 +60,20 @@ void texture_use(texture_t texture);
|
|||||||
void texture_dispose(texture_t texture);
|
void texture_dispose(texture_t texture);
|
||||||
|
|
||||||
/// A TextureLoader implementation for OpenGL. Use this with spine::Atlas.
|
/// A TextureLoader implementation for OpenGL. Use this with spine::Atlas.
|
||||||
class GlTextureLoader: public spine::TextureLoader {
|
class GlTextureLoader : public spine::TextureLoader {
|
||||||
public:
|
public:
|
||||||
void load(spine::AtlasPage &page, const spine::String &path);
|
void load(spine::AtlasPage &page, const spine::String &path);
|
||||||
void unload(void *texture);
|
void unload(void *texture);
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Renderer capable of rendering a spine_skeleton_drawable, using a shader, a mesh, and a
|
/// Renderer capable of rendering a spine_skeleton_drawable, using a shader, a mesh, and a
|
||||||
/// temporary CPU-side vertex buffer used to update the GPU-side mesh
|
/// temporary CPU-side vertex buffer used to update the GPU-side mesh
|
||||||
typedef struct {
|
typedef struct {
|
||||||
shader_t shader;
|
shader_t shader;
|
||||||
mesh_t *mesh;
|
mesh_t *mesh;
|
||||||
int vertex_buffer_size;
|
int vertex_buffer_size;
|
||||||
vertex_t *vertex_buffer;
|
vertex_t *vertex_buffer;
|
||||||
spine::SkeletonRenderer *renderer;
|
spine::SkeletonRenderer *renderer;
|
||||||
} renderer_t;
|
} renderer_t;
|
||||||
|
|
||||||
/// Creates a new renderer
|
/// Creates a new renderer
|
||||||
|
|||||||
@ -35,68 +35,68 @@ spine::DebugExtension dbgExtension(spine::SpineExtension::getInstance());
|
|||||||
extern spine::SkeletonRenderer *skeletonRenderer;
|
extern spine::SkeletonRenderer *skeletonRenderer;
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
spine::SpineExtension::setInstance(&dbgExtension);
|
spine::SpineExtension::setInstance(&dbgExtension);
|
||||||
{
|
{
|
||||||
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,
|
SDL_Window *window = SDL_CreateWindow("Spine SDL", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 800, 600,
|
||||||
0);
|
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_PRESENTVSYNC);
|
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("data/spineboy-pma.atlas", &textureLoader);
|
spine::Atlas atlas("data/spineboy-pma.atlas", &textureLoader);
|
||||||
spine::AtlasAttachmentLoader attachmentLoader(&atlas);
|
spine::AtlasAttachmentLoader attachmentLoader(&atlas);
|
||||||
spine::SkeletonJson json(&attachmentLoader);
|
spine::SkeletonJson json(&attachmentLoader);
|
||||||
json.setScale(0.5f);
|
json.setScale(0.5f);
|
||||||
spine::SkeletonData *skeletonData = json.readSkeletonDataFile("data/spineboy-pro.json");
|
spine::SkeletonData *skeletonData = json.readSkeletonDataFile("data/spineboy-pro.json");
|
||||||
spine::SkeletonDrawable drawable(skeletonData);
|
spine::SkeletonDrawable drawable(skeletonData);
|
||||||
drawable.usePremultipliedAlpha = true;
|
drawable.usePremultipliedAlpha = true;
|
||||||
drawable.animationState->getData()->setDefaultMix(0.2f);
|
drawable.animationState->getData()->setDefaultMix(0.2f);
|
||||||
drawable.skeleton->setPosition(400, 500);
|
drawable.skeleton->setPosition(400, 500);
|
||||||
drawable.skeleton->setToSetupPose();
|
drawable.skeleton->setToSetupPose();
|
||||||
drawable.animationState->setAnimation(0, "portal", true);
|
drawable.animationState->setAnimation(0, "portal", true);
|
||||||
drawable.animationState->addAnimation(0, "run", true, 0);
|
drawable.animationState->addAnimation(0, "run", true, 0);
|
||||||
drawable.update(0, spine::Physics_Update);
|
drawable.update(0, spine::Physics_Update);
|
||||||
|
|
||||||
bool quit = false;
|
bool quit = false;
|
||||||
uint64_t lastFrameTime = SDL_GetPerformanceCounter();
|
uint64_t lastFrameTime = SDL_GetPerformanceCounter();
|
||||||
while (!quit) {
|
while (!quit) {
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
while (SDL_PollEvent(&event) != 0) {
|
while (SDL_PollEvent(&event) != 0) {
|
||||||
if (event.type == SDL_QUIT) {
|
if (event.type == SDL_QUIT) {
|
||||||
quit = true;
|
quit = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_SetRenderDrawColor(renderer, 94, 93, 96, 255);
|
SDL_SetRenderDrawColor(renderer, 94, 93, 96, 255);
|
||||||
SDL_RenderClear(renderer);
|
SDL_RenderClear(renderer);
|
||||||
|
|
||||||
uint64_t now = SDL_GetPerformanceCounter();
|
uint64_t now = SDL_GetPerformanceCounter();
|
||||||
double deltaTime = (now - lastFrameTime) / (double) SDL_GetPerformanceFrequency();
|
double deltaTime = (now - lastFrameTime) / (double) SDL_GetPerformanceFrequency();
|
||||||
lastFrameTime = now;
|
lastFrameTime = now;
|
||||||
|
|
||||||
drawable.update(deltaTime, spine::Physics_Update);
|
drawable.update(deltaTime, spine::Physics_Update);
|
||||||
drawable.draw(renderer);
|
drawable.draw(renderer);
|
||||||
|
|
||||||
SDL_RenderPresent(renderer);
|
SDL_RenderPresent(renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_DestroyWindow(window);
|
SDL_DestroyWindow(window);
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
delete skeletonData;
|
delete skeletonData;
|
||||||
}
|
}
|
||||||
delete skeletonRenderer;
|
delete skeletonRenderer;
|
||||||
dbgExtension.reportLeaks();
|
dbgExtension.reportLeaks();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -62,76 +62,76 @@ void SkeletonDrawable::update(float delta, Physics physics) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline void toSDLColor(uint32_t color, SDL_Color *sdlColor) {
|
inline void toSDLColor(uint32_t color, SDL_Color *sdlColor) {
|
||||||
sdlColor->a = (color >> 24) & 0xFF;
|
sdlColor->a = (color >> 24) & 0xFF;
|
||||||
sdlColor->r = (color >> 16) & 0xFF;
|
sdlColor->r = (color >> 16) & 0xFF;
|
||||||
sdlColor->g = (color >> 8) & 0xFF;
|
sdlColor->g = (color >> 8) & 0xFF;
|
||||||
sdlColor->b = color & 0xFF;
|
sdlColor->b = color & 0xFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkeletonDrawable::draw(SDL_Renderer *renderer) {
|
void SkeletonDrawable::draw(SDL_Renderer *renderer) {
|
||||||
if (!skeletonRenderer) skeletonRenderer = new (__FILE__, __LINE__) SkeletonRenderer();
|
if (!skeletonRenderer) skeletonRenderer = new (__FILE__, __LINE__) SkeletonRenderer();
|
||||||
RenderCommand *command = skeletonRenderer->render(*skeleton);
|
RenderCommand *command = skeletonRenderer->render(*skeleton);
|
||||||
while(command) {
|
while (command) {
|
||||||
float *positions = command->positions;
|
float *positions = command->positions;
|
||||||
float *uvs = command->uvs;
|
float *uvs = command->uvs;
|
||||||
uint32_t *colors = command->colors;
|
uint32_t *colors = command->colors;
|
||||||
sdlVertices.clear();
|
sdlVertices.clear();
|
||||||
for (int ii = 0; ii < command->numVertices << 1; ii += 2) {
|
for (int ii = 0; ii < command->numVertices << 1; ii += 2) {
|
||||||
SDL_Vertex sdlVertex;
|
SDL_Vertex sdlVertex;
|
||||||
sdlVertex.position.x = positions[ii];
|
sdlVertex.position.x = positions[ii];
|
||||||
sdlVertex.position.y = positions[ii + 1];
|
sdlVertex.position.y = positions[ii + 1];
|
||||||
sdlVertex.tex_coord.x = uvs[ii];
|
sdlVertex.tex_coord.x = uvs[ii];
|
||||||
sdlVertex.tex_coord.y = uvs[ii + 1];
|
sdlVertex.tex_coord.y = uvs[ii + 1];
|
||||||
toSDLColor(colors[ii >> 1], &sdlVertex.color);
|
toSDLColor(colors[ii >> 1], &sdlVertex.color);
|
||||||
sdlVertices.add(sdlVertex);
|
sdlVertices.add(sdlVertex);
|
||||||
}
|
}
|
||||||
sdlIndices.clear();
|
sdlIndices.clear();
|
||||||
uint16_t *indices = command->indices;
|
uint16_t *indices = command->indices;
|
||||||
for (int ii = 0; ii < command->numIndices; ii++)
|
for (int ii = 0; ii < command->numIndices; ii++)
|
||||||
sdlIndices.add(indices[ii]);
|
sdlIndices.add(indices[ii]);
|
||||||
|
|
||||||
BlendMode blendMode = command->blendMode;
|
BlendMode blendMode = command->blendMode;
|
||||||
SDL_Texture *texture = (SDL_Texture *)command->texture;
|
SDL_Texture *texture = (SDL_Texture *) command->texture;
|
||||||
if (!usePremultipliedAlpha) {
|
if (!usePremultipliedAlpha) {
|
||||||
switch (blendMode) {
|
switch (blendMode) {
|
||||||
case BlendMode_Normal:
|
case BlendMode_Normal:
|
||||||
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
|
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
|
||||||
break;
|
break;
|
||||||
case BlendMode_Multiply:
|
case BlendMode_Multiply:
|
||||||
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_MOD);
|
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_MOD);
|
||||||
break;
|
break;
|
||||||
case BlendMode_Additive:
|
case BlendMode_Additive:
|
||||||
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_ADD);
|
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_ADD);
|
||||||
break;
|
break;
|
||||||
case BlendMode_Screen:
|
case BlendMode_Screen:
|
||||||
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
|
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
SDL_BlendMode target;
|
SDL_BlendMode target;
|
||||||
switch (blendMode) {
|
switch (blendMode) {
|
||||||
case BlendMode_Normal:
|
case BlendMode_Normal:
|
||||||
target = SDL_ComposeCustomBlendMode(SDL_BLENDFACTOR_ONE, SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, SDL_BLENDOPERATION_ADD, SDL_BLENDFACTOR_ONE, SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, SDL_BLENDOPERATION_ADD);
|
target = SDL_ComposeCustomBlendMode(SDL_BLENDFACTOR_ONE, SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, SDL_BLENDOPERATION_ADD, SDL_BLENDFACTOR_ONE, SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, SDL_BLENDOPERATION_ADD);
|
||||||
SDL_SetTextureBlendMode(texture, target);
|
SDL_SetTextureBlendMode(texture, target);
|
||||||
break;
|
break;
|
||||||
case BlendMode_Multiply:
|
case BlendMode_Multiply:
|
||||||
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_MOD);
|
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_MOD);
|
||||||
break;
|
break;
|
||||||
case BlendMode_Additive:
|
case BlendMode_Additive:
|
||||||
target = SDL_ComposeCustomBlendMode(SDL_BLENDFACTOR_ONE, SDL_BLENDFACTOR_ONE, SDL_BLENDOPERATION_ADD, SDL_BLENDFACTOR_ONE, SDL_BLENDFACTOR_ONE, SDL_BLENDOPERATION_ADD);
|
target = SDL_ComposeCustomBlendMode(SDL_BLENDFACTOR_ONE, SDL_BLENDFACTOR_ONE, SDL_BLENDOPERATION_ADD, SDL_BLENDFACTOR_ONE, SDL_BLENDFACTOR_ONE, SDL_BLENDOPERATION_ADD);
|
||||||
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_ADD);
|
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_ADD);
|
||||||
break;
|
break;
|
||||||
case BlendMode_Screen:
|
case BlendMode_Screen:
|
||||||
target = SDL_ComposeCustomBlendMode(SDL_BLENDFACTOR_ONE, SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, SDL_BLENDOPERATION_ADD, SDL_BLENDFACTOR_ONE, SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, SDL_BLENDOPERATION_ADD);
|
target = SDL_ComposeCustomBlendMode(SDL_BLENDFACTOR_ONE, SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, SDL_BLENDOPERATION_ADD, SDL_BLENDFACTOR_ONE, SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, SDL_BLENDOPERATION_ADD);
|
||||||
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
|
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_RenderGeometry(renderer, texture, sdlVertices.buffer(), sdlVertices.size(), sdlIndices.buffer(),
|
SDL_RenderGeometry(renderer, texture, sdlVertices.buffer(), sdlVertices.size(), sdlIndices.buffer(),
|
||||||
command->numIndices);
|
command->numIndices);
|
||||||
command = command->next;
|
command = command->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_Texture *loadTexture(SDL_Renderer *renderer, const String &path) {
|
SDL_Texture *loadTexture(SDL_Renderer *renderer, const String &path) {
|
||||||
|
|||||||
@ -37,103 +37,102 @@ using namespace sf;
|
|||||||
using namespace spine;
|
using namespace spine;
|
||||||
|
|
||||||
sf::BlendMode blendModes[] = {
|
sf::BlendMode blendModes[] = {
|
||||||
sf::BlendMode(sf::BlendMode::SrcAlpha, sf::BlendMode::OneMinusSrcAlpha),
|
sf::BlendMode(sf::BlendMode::SrcAlpha, sf::BlendMode::OneMinusSrcAlpha),
|
||||||
sf::BlendMode(sf::BlendMode::SrcAlpha, sf::BlendMode::One),
|
sf::BlendMode(sf::BlendMode::SrcAlpha, sf::BlendMode::One),
|
||||||
sf::BlendMode(sf::BlendMode::DstColor, sf::BlendMode::OneMinusSrcAlpha),
|
sf::BlendMode(sf::BlendMode::DstColor, sf::BlendMode::OneMinusSrcAlpha),
|
||||||
sf::BlendMode(sf::BlendMode::One, sf::BlendMode::OneMinusSrcColor)
|
sf::BlendMode(sf::BlendMode::One, sf::BlendMode::OneMinusSrcColor)};
|
||||||
};
|
|
||||||
|
|
||||||
sf::BlendMode blendModesPma[] = {
|
sf::BlendMode blendModesPma[] = {
|
||||||
sf::BlendMode(sf::BlendMode::One, sf::BlendMode::OneMinusSrcAlpha),
|
sf::BlendMode(sf::BlendMode::One, sf::BlendMode::OneMinusSrcAlpha),
|
||||||
sf::BlendMode(sf::BlendMode::One, sf::BlendMode::One),
|
sf::BlendMode(sf::BlendMode::One, sf::BlendMode::One),
|
||||||
sf::BlendMode(sf::BlendMode::DstColor, sf::BlendMode::OneMinusSrcAlpha),
|
sf::BlendMode(sf::BlendMode::DstColor, sf::BlendMode::OneMinusSrcAlpha),
|
||||||
sf::BlendMode(sf::BlendMode::One, sf::BlendMode::OneMinusSrcColor),
|
sf::BlendMode(sf::BlendMode::One, sf::BlendMode::OneMinusSrcColor),
|
||||||
};
|
};
|
||||||
|
|
||||||
SkeletonRenderer *skeletonRenderer = nullptr;
|
SkeletonRenderer *skeletonRenderer = nullptr;
|
||||||
|
|
||||||
SkeletonDrawable::SkeletonDrawable(SkeletonData *skeletonData, AnimationStateData *stateData) : timeScale(1),
|
SkeletonDrawable::SkeletonDrawable(SkeletonData *skeletonData, AnimationStateData *stateData) : timeScale(1),
|
||||||
usePremultipliedAlpha(false),
|
usePremultipliedAlpha(false),
|
||||||
vertexArray(new VertexArray(Triangles, skeletonData->getBones().size() * 4)) {
|
vertexArray(new VertexArray(Triangles, skeletonData->getBones().size() * 4)) {
|
||||||
Bone::setYDown(true);
|
Bone::setYDown(true);
|
||||||
skeleton = new (__FILE__, __LINE__) Skeleton(skeletonData);
|
skeleton = new (__FILE__, __LINE__) Skeleton(skeletonData);
|
||||||
ownsAnimationStateData = stateData == 0;
|
ownsAnimationStateData = stateData == 0;
|
||||||
if (ownsAnimationStateData) stateData = new (__FILE__, __LINE__) AnimationStateData(skeletonData);
|
if (ownsAnimationStateData) stateData = new (__FILE__, __LINE__) AnimationStateData(skeletonData);
|
||||||
state = new (__FILE__, __LINE__) AnimationState(stateData);
|
state = new (__FILE__, __LINE__) AnimationState(stateData);
|
||||||
}
|
}
|
||||||
|
|
||||||
SkeletonDrawable::~SkeletonDrawable() {
|
SkeletonDrawable::~SkeletonDrawable() {
|
||||||
delete vertexArray;
|
delete vertexArray;
|
||||||
if (ownsAnimationStateData) delete state->getData();
|
if (ownsAnimationStateData) delete state->getData();
|
||||||
delete state;
|
delete state;
|
||||||
delete skeleton;
|
delete skeleton;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkeletonDrawable::update(float deltaTime, Physics physics) {
|
void SkeletonDrawable::update(float deltaTime, Physics physics) {
|
||||||
state->update(deltaTime * timeScale);
|
state->update(deltaTime * timeScale);
|
||||||
state->apply(*skeleton);
|
state->apply(*skeleton);
|
||||||
skeleton->update(deltaTime * timeScale);
|
skeleton->update(deltaTime * timeScale);
|
||||||
skeleton->updateWorldTransform(physics);
|
skeleton->updateWorldTransform(physics);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void toSFMLColor(uint32_t color, sf::Color *sfmlColor) {
|
inline void toSFMLColor(uint32_t color, sf::Color *sfmlColor) {
|
||||||
sfmlColor->a = (color >> 24) & 0xFF;
|
sfmlColor->a = (color >> 24) & 0xFF;
|
||||||
sfmlColor->r = (color >> 16) & 0xFF;
|
sfmlColor->r = (color >> 16) & 0xFF;
|
||||||
sfmlColor->g = (color >> 8) & 0xFF;
|
sfmlColor->g = (color >> 8) & 0xFF;
|
||||||
sfmlColor->b = color & 0xFF;
|
sfmlColor->b = color & 0xFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkeletonDrawable::draw(RenderTarget &target, RenderStates states) const {
|
void SkeletonDrawable::draw(RenderTarget &target, RenderStates states) const {
|
||||||
states.texture = NULL;
|
states.texture = NULL;
|
||||||
vertexArray->clear();
|
vertexArray->clear();
|
||||||
|
|
||||||
if (!skeletonRenderer) skeletonRenderer = new (__FILE__, __LINE__) SkeletonRenderer();
|
if (!skeletonRenderer) skeletonRenderer = new (__FILE__, __LINE__) SkeletonRenderer();
|
||||||
RenderCommand *command = skeletonRenderer->render(*skeleton);
|
RenderCommand *command = skeletonRenderer->render(*skeleton);
|
||||||
while (command) {
|
while (command) {
|
||||||
Vertex vertex;
|
Vertex vertex;
|
||||||
float *positions = command->positions;
|
float *positions = command->positions;
|
||||||
float *uvs = command->uvs;
|
float *uvs = command->uvs;
|
||||||
uint32_t *colors = command->colors;
|
uint32_t *colors = command->colors;
|
||||||
uint16_t *indices = command->indices;
|
uint16_t *indices = command->indices;
|
||||||
Texture *texture = (Texture *)command->texture;
|
Texture *texture = (Texture *) command->texture;
|
||||||
Vector2u size = texture->getSize();
|
Vector2u size = texture->getSize();
|
||||||
for (int i = 0, n = command->numIndices; i < n; ++i) {
|
for (int i = 0, n = command->numIndices; i < n; ++i) {
|
||||||
int ii = indices[i];
|
int ii = indices[i];
|
||||||
int index = ii << 1;
|
int index = ii << 1;
|
||||||
vertex.position.x = positions[index];
|
vertex.position.x = positions[index];
|
||||||
vertex.position.y = positions[index + 1];
|
vertex.position.y = positions[index + 1];
|
||||||
vertex.texCoords.x = uvs[index] * size.x;
|
vertex.texCoords.x = uvs[index] * size.x;
|
||||||
vertex.texCoords.y = uvs[index + 1] * size.y;
|
vertex.texCoords.y = uvs[index + 1] * size.y;
|
||||||
toSFMLColor(colors[ii], &vertex.color);
|
toSFMLColor(colors[ii], &vertex.color);
|
||||||
vertexArray->append(vertex);
|
vertexArray->append(vertex);
|
||||||
}
|
}
|
||||||
BlendMode blendMode = command->blendMode;
|
BlendMode blendMode = command->blendMode;
|
||||||
states.blendMode = usePremultipliedAlpha ? blendModesPma[blendMode] : blendModes[blendMode];
|
states.blendMode = usePremultipliedAlpha ? blendModesPma[blendMode] : blendModes[blendMode];
|
||||||
states.texture = texture;
|
states.texture = texture;
|
||||||
target.draw(*vertexArray, states);
|
target.draw(*vertexArray, states);
|
||||||
vertexArray->clear();
|
vertexArray->clear();
|
||||||
|
|
||||||
command = command->next;
|
command = command->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SFMLTextureLoader::load(AtlasPage &page, const String &path) {
|
void SFMLTextureLoader::load(AtlasPage &page, const String &path) {
|
||||||
Texture *texture = new Texture();
|
Texture *texture = new Texture();
|
||||||
if (!texture->loadFromFile(path.buffer())) return;
|
if (!texture->loadFromFile(path.buffer())) return;
|
||||||
|
|
||||||
if (page.magFilter == TextureFilter_Linear) texture->setSmooth(true);
|
if (page.magFilter == TextureFilter_Linear) texture->setSmooth(true);
|
||||||
if (page.uWrap == TextureWrap_Repeat && page.vWrap == TextureWrap_Repeat) texture->setRepeated(true);
|
if (page.uWrap == TextureWrap_Repeat && page.vWrap == TextureWrap_Repeat) texture->setRepeated(true);
|
||||||
|
|
||||||
page.texture = texture;
|
page.texture = texture;
|
||||||
Vector2u size = texture->getSize();
|
Vector2u size = texture->getSize();
|
||||||
page.width = size.x;
|
page.width = size.x;
|
||||||
page.height = size.y;
|
page.height = size.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SFMLTextureLoader::unload(void *texture) {
|
void SFMLTextureLoader::unload(void *texture) {
|
||||||
delete (Texture *) texture;
|
delete (Texture *) texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
SpineExtension *spine::getDefaultExtension() {
|
SpineExtension *spine::getDefaultExtension() {
|
||||||
return new DefaultSpineExtension();
|
return new DefaultSpineExtension();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -62,7 +62,7 @@ namespace spine {
|
|||||||
private:
|
private:
|
||||||
bool ownsAnimationStateData;
|
bool ownsAnimationStateData;
|
||||||
mutable bool usePremultipliedAlpha;
|
mutable bool usePremultipliedAlpha;
|
||||||
sf::VertexArray *vertexArray;
|
sf::VertexArray *vertexArray;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SFMLTextureLoader : public TextureLoader {
|
class SFMLTextureLoader : public TextureLoader {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user