mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-14 02:58:44 +08:00
[glfw] Add spine-cpp-lite example.
This commit is contained in:
parent
8d12efd9ef
commit
5e80111b87
@ -206,6 +206,44 @@ spine_atlas spine_atlas_load(const utf8 *atlasData) {
|
||||
return (spine_atlas) result;
|
||||
}
|
||||
|
||||
class CallbackTextureLoad : public TextureLoader {
|
||||
spine_texture_loader_load_func loadCb;
|
||||
spine_texture_loader_unload_func unloadCb;
|
||||
|
||||
public:
|
||||
CallbackTextureLoad(): loadCb(nullptr), unloadCb(nullptr) {}
|
||||
|
||||
void setCallbacks(spine_texture_loader_load_func load, spine_texture_loader_unload_func unload) {
|
||||
loadCb = load;
|
||||
unloadCb = unload;
|
||||
}
|
||||
|
||||
void load(AtlasPage &page, const String &path) {
|
||||
page.texture = this->loadCb(path.buffer());
|
||||
}
|
||||
|
||||
void unload(void *texture) {
|
||||
this->unloadCb(texture);
|
||||
}
|
||||
};
|
||||
|
||||
CallbackTextureLoad callbackLoader;
|
||||
|
||||
spine_atlas spine_atlas_load_callback(const utf8 *atlasData, const utf8 *atlasDir, spine_texture_loader_load_func load, spine_texture_loader_unload_func unload) {
|
||||
if (!atlasData) return nullptr;
|
||||
int32_t length = (int32_t) strlen(atlasData);
|
||||
callbackLoader.setCallbacks(load, unload);
|
||||
auto atlas = new (__FILE__, __LINE__) Atlas(atlasData, length, (const char *)atlasDir, &callbackLoader, true);
|
||||
_spine_atlas *result = SpineExtension::calloc<_spine_atlas>(1, __FILE__, __LINE__);
|
||||
result->atlas = atlas;
|
||||
result->numImagePaths = (int32_t) atlas->getPages().size();
|
||||
result->imagePaths = SpineExtension::calloc<utf8 *>(result->numImagePaths, __FILE__, __LINE__);
|
||||
for (int i = 0; i < result->numImagePaths; i++) {
|
||||
result->imagePaths[i] = (utf8 *) strdup(atlas->getPages()[i]->texturePath.buffer());
|
||||
}
|
||||
return (spine_atlas) result;
|
||||
}
|
||||
|
||||
int32_t spine_atlas_get_num_image_paths(spine_atlas atlas) {
|
||||
if (!atlas) return 0;
|
||||
return ((_spine_atlas *) atlas)->numImagePaths;
|
||||
|
||||
@ -189,6 +189,10 @@ typedef enum spine_physics {
|
||||
|
||||
typedef int32_t spine_bool;
|
||||
|
||||
typedef void* (*spine_texture_loader_load_func)(const char *path);
|
||||
|
||||
typedef void (*spine_texture_loader_unload_func)(void *texture);
|
||||
|
||||
// @start: function_declarations
|
||||
|
||||
SPINE_CPP_LITE_EXPORT int32_t spine_major_version();
|
||||
@ -210,6 +214,8 @@ SPINE_CPP_LITE_EXPORT float spine_vector_get_x(spine_vector vector);
|
||||
SPINE_CPP_LITE_EXPORT float spine_vector_get_y(spine_vector vector);
|
||||
|
||||
SPINE_CPP_LITE_EXPORT spine_atlas spine_atlas_load(const utf8 *atlasData);
|
||||
// @ignore
|
||||
SPINE_CPP_LITE_EXPORT spine_atlas spine_atlas_load_callback(const utf8 *atlasData, const utf8 *atlasDir, spine_texture_loader_load_func load, spine_texture_loader_unload_func unload);
|
||||
SPINE_CPP_LITE_EXPORT int32_t spine_atlas_get_num_image_paths(spine_atlas atlas);
|
||||
SPINE_CPP_LITE_EXPORT utf8 *spine_atlas_get_image_path(spine_atlas atlas, int32_t index);
|
||||
SPINE_CPP_LITE_EXPORT spine_bool spine_atlas_is_pma(spine_atlas atlas);
|
||||
|
||||
@ -43,7 +43,7 @@ add_subdirectory(${CMAKE_SOURCE_DIR}/../spine-cpp ${CMAKE_BINARY_DIR}/spine-cpp-
|
||||
# spine-glfw library
|
||||
add_library(spine-glfw STATIC src/spine-glfw.cpp src/spine-glfw.h src/stb_image.h)
|
||||
target_link_libraries(spine-glfw PRIVATE glbinding::glbinding)
|
||||
target_link_libraries(spine-glfw LINK_PUBLIC spine-cpp)
|
||||
target_link_libraries(spine-glfw LINK_PUBLIC spine-cpp-lite)
|
||||
|
||||
# Example
|
||||
add_executable(spine-glfw-example example/main.cpp)
|
||||
@ -53,6 +53,15 @@ target_link_libraries(spine-glfw-example LINK_PUBLIC spine-glfw)
|
||||
target_link_libraries(spine-glfw-example PRIVATE glbinding::glbinding)
|
||||
set_property(TARGET spine-glfw-example PROPERTY VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/spine-glfw")
|
||||
|
||||
# spine-cpp-lite Example
|
||||
add_executable(spine-glfw-example-cpp-lite example/main-cpp-lite.cpp)
|
||||
target_link_libraries(spine-glfw-example-cpp-lite PRIVATE glfw)
|
||||
target_link_libraries(spine-glfw-example-cpp-lite PRIVATE OpenGL::GL)
|
||||
target_link_libraries(spine-glfw-example-cpp-lite LINK_PUBLIC spine-glfw)
|
||||
target_link_libraries(spine-glfw-example-cpp-lite PRIVATE glbinding::glbinding)
|
||||
set_property(TARGET spine-glfw-example-cpp-lite PROPERTY VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/spine-glfw")
|
||||
|
||||
|
||||
# copy data to build directory
|
||||
add_custom_command(TARGET spine-glfw-example PRE_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||
|
||||
125
spine-glfw/example/main-cpp-lite.cpp
Normal file
125
spine-glfw/example/main-cpp-lite.cpp
Normal file
@ -0,0 +1,125 @@
|
||||
#include <glbinding/glbinding.h>
|
||||
#include <glbinding/gl/gl.h>
|
||||
#define GLFW_INCLUDE_NONE
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <iostream>
|
||||
#include <spine-glfw.h>
|
||||
|
||||
using namespace spine;
|
||||
|
||||
int width = 800, height = 600;
|
||||
|
||||
GLFWwindow *init_glfw() {
|
||||
if (!glfwInit()) {
|
||||
std::cerr << "Failed to initialize GLFW" << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
GLFWwindow *window = glfwCreateWindow(width, height, "spine-glfw", NULL, NULL);
|
||||
if (!window) {
|
||||
std::cerr << "Failed to create GLFW window" << std::endl;
|
||||
glfwTerminate();
|
||||
return nullptr;
|
||||
}
|
||||
glfwMakeContextCurrent(window);
|
||||
glbinding::initialize(glfwGetProcAddress);
|
||||
return window;
|
||||
}
|
||||
|
||||
uint8_t *read_file(const char *path, int *length) {
|
||||
FILE *file = fopen(path, "rb");
|
||||
if (!file) return 0;
|
||||
|
||||
fseek(file, 0, SEEK_END);
|
||||
*length = (int) ftell(file);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
|
||||
uint8_t *data = (uint8_t*)malloc(*length);
|
||||
fread(data, 1, *length, file);
|
||||
fclose(file);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void *load_texture(const char *path) {
|
||||
return (void *) (uintptr_t)texture_load(path);
|
||||
}
|
||||
|
||||
void unload_texture(void *texture) {
|
||||
texture_dispose((texture_t)(uintptr_t)texture);
|
||||
}
|
||||
|
||||
int main() {
|
||||
// Initialize GLFW and glbinding
|
||||
GLFWwindow *window = init_glfw();
|
||||
if (!window) return -1;
|
||||
|
||||
// We use a y-down coordinate system, see renderer_set_viewport_size()
|
||||
Bone::setYDown(true);
|
||||
|
||||
// Load the atlas and the skeleton data
|
||||
int atlas_length = 0;
|
||||
uint8_t *atlas_bytes = read_file("data/spineboy-pma.atlas", &atlas_length);
|
||||
spine_atlas atlas = spine_atlas_load_callback((utf8 *)atlas_bytes, "data/", load_texture, unload_texture);
|
||||
int skeleton_length = 0;
|
||||
uint8_t *skeleton_bytes = read_file("data/spineboy-pro.skel", &skeleton_length);
|
||||
spine_skeleton_data_result result = spine_skeleton_data_load_binary(atlas, skeleton_bytes, skeleton_length);
|
||||
spine_skeleton_data skeleton_data = spine_skeleton_data_result_get_data(result);
|
||||
|
||||
// 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.
|
||||
spine_skeleton_drawable drawable = spine_skeleton_drawable_create(skeleton_data);
|
||||
spine_skeleton skeleton = spine_skeleton_drawable_get_skeleton(drawable);
|
||||
spine_skeleton_set_position(skeleton, width / 2, height - 100);
|
||||
spine_skeleton_set_scale(skeleton, 0.3f, 0.3f);
|
||||
|
||||
// Create an AnimationState to drive animations on the skeleton. Set the "portal" animation
|
||||
// on track with index 0.
|
||||
spine_animation_state animation_state = spine_skeleton_drawable_get_animation_state(drawable);
|
||||
spine_animation_state_set_animation_by_name(animation_state, 0, "portal", true);
|
||||
|
||||
// Create the renderer and set the viewport size to match the window size. This sets up a
|
||||
// pixel perfect orthogonal projection for 2D rendering.
|
||||
renderer_t *renderer = renderer_create();
|
||||
renderer_set_viewport_size(renderer, width, height);
|
||||
|
||||
// Rendering loop
|
||||
double lastTime = glfwGetTime();
|
||||
while (!glfwWindowShouldClose(window)) {
|
||||
// Calculate the delta time in seconds
|
||||
double currTime = glfwGetTime();
|
||||
float delta = currTime - lastTime;
|
||||
lastTime = currTime;
|
||||
|
||||
// Update and apply the animation state to the skeleton
|
||||
spine_animation_state_update(animation_state, delta);
|
||||
spine_animation_state_apply(animation_state, skeleton);
|
||||
|
||||
// Update the skeleton time (used for physics)
|
||||
spine_skeleton_update(skeleton, delta);
|
||||
|
||||
// Calculate the new pose
|
||||
spine_skeleton_update_world_transform(skeleton, SPINE_PHYSICS_UPDATE);
|
||||
|
||||
// Clear the screen
|
||||
gl::glClear(gl::GL_COLOR_BUFFER_BIT);
|
||||
|
||||
// Render the skeleton in its current pose
|
||||
renderer_draw_lite(renderer, skeleton, true);
|
||||
|
||||
// Present the rendering results and poll for events
|
||||
glfwSwapBuffers(window);
|
||||
glfwPollEvents();
|
||||
}
|
||||
|
||||
// Dispose everything
|
||||
renderer_dispose(renderer);
|
||||
// delete skeletonData;
|
||||
delete atlas;
|
||||
|
||||
// Kill the window and GLFW
|
||||
glfwTerminate();
|
||||
return 0;
|
||||
}
|
||||
@ -8,9 +8,9 @@ using namespace gl;
|
||||
using namespace spine;
|
||||
|
||||
/// Set the default extension used for memory allocations and file I/O
|
||||
SpineExtension *spine::getDefaultExtension() {
|
||||
return new spine::DefaultSpineExtension();
|
||||
}
|
||||
// SpineExtension *spine::getDefaultExtension() {
|
||||
// return new spine::DefaultSpineExtension();
|
||||
// }
|
||||
|
||||
/// A blend mode, see https://en.esotericsoftware.com/spine-slots#Blending
|
||||
/// Encodes the OpenGL source and destination blend function for both premultiplied and
|
||||
@ -285,6 +285,10 @@ void renderer_set_viewport_size(renderer_t *renderer, int width, int height) {
|
||||
shader_set_matrix4(renderer->shader, "uMatrix", matrix);
|
||||
}
|
||||
|
||||
void renderer_draw_lite(renderer_t *renderer, spine_skeleton skeleton, bool premultipliedAlpha) {
|
||||
renderer_draw(renderer, (Skeleton*)skeleton, premultipliedAlpha);
|
||||
}
|
||||
|
||||
void renderer_draw(renderer_t *renderer, Skeleton *skeleton, bool premultipliedAlpha) {
|
||||
shader_use(renderer->shader);
|
||||
shader_set_int(renderer->shader, "uTexture", 0);
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <spine/spine.h>
|
||||
#include <spine-cpp-lite.h>
|
||||
|
||||
/// A vertex of a mesh generated from a Spine skeleton
|
||||
struct vertex_t {
|
||||
@ -86,5 +87,9 @@ void renderer_set_viewport_size(renderer_t *renderer, int width, int height);
|
||||
/// was constructed.
|
||||
void renderer_draw(renderer_t *renderer, spine::Skeleton *skeleton, bool premultipliedAlpha);
|
||||
|
||||
/// Draws the given skeleton. The atlas must be the atlas from which the drawable
|
||||
/// was constructed.
|
||||
void renderer_draw_lite(renderer_t *renderer, spine_skeleton skeleton, bool premultipliedAlpha);
|
||||
|
||||
/// Disposes the renderer
|
||||
void renderer_dispose(renderer_t *renderer);
|
||||
Loading…
x
Reference in New Issue
Block a user