HeadlessTest.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. /******************************************************************************
  2. * Spine Runtimes License Agreement
  3. * Last updated April 5, 2025. Replaces all prior versions.
  4. *
  5. * Copyright (c) 2013-2025, Esoteric Software LLC
  6. *
  7. * Integration of the Spine Runtimes into software or otherwise creating
  8. * derivative works of the Spine Runtimes is permitted under the terms and
  9. * conditions of Section 2 of the Spine Editor License Agreement:
  10. * http://esotericsoftware.com/spine-editor-license
  11. *
  12. * Otherwise, it is permitted to integrate the Spine Runtimes into software
  13. * or otherwise create derivative works of the Spine Runtimes (collectively,
  14. * "Products"), provided that each user of the Products must obtain their own
  15. * Spine Editor license and redistribution of the Products in any form must
  16. * include this license and copyright notice.
  17. *
  18. * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
  19. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  20. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  21. * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
  22. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  23. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
  24. * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
  25. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  27. * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. *****************************************************************************/
  29. #include <spine/spine.h>
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <string.h>
  33. #include <stdarg.h>
  34. #include <locale.h>
  35. using namespace spine;
  36. // Provide the default extension implementation
  37. namespace spine {
  38. SpineExtension *getDefaultExtension() {
  39. return new DefaultSpineExtension();
  40. }
  41. }// namespace spine
  42. // Mock texture that doesn't require OpenGL
  43. class MockTexture {
  44. public:
  45. int width = 1024;
  46. int height = 1024;
  47. };
  48. // Custom texture loader that doesn't load actual textures
  49. class HeadlessTextureLoader : public TextureLoader {
  50. public:
  51. virtual void load(AtlasPage &page, const String &path) override {
  52. // Don't load actual texture, just set dimensions
  53. page.texture = new MockTexture();
  54. page.width = 1024;
  55. page.height = 1024;
  56. }
  57. virtual void unload(void *texture) override {
  58. delete static_cast<MockTexture *>(texture);
  59. }
  60. };
  61. class Printer {
  62. private:
  63. int indentLevel = 0;
  64. static constexpr const char *INDENT = " ";
  65. void print(const char *format, ...) {
  66. for (int i = 0; i < indentLevel; i++) {
  67. printf("%s", INDENT);
  68. }
  69. va_list args;
  70. va_start(args, format);
  71. vprintf(format, args);
  72. va_end(args);
  73. printf("\n");
  74. }
  75. void indent() {
  76. indentLevel++;
  77. }
  78. void unindent() {
  79. indentLevel--;
  80. }
  81. public:
  82. void printSkeletonData(SkeletonData *data) {
  83. print("SkeletonData {");
  84. indent();
  85. print("name: \"%s\"", data->getName().buffer());
  86. print("version: \"%s\"", data->getVersion().buffer());
  87. print("hash: \"%s\"", data->getHash().buffer());
  88. print("x: %.6f", data->getX());
  89. print("y: %.6f", data->getY());
  90. print("width: %.6f", data->getWidth());
  91. print("height: %.6f", data->getHeight());
  92. print("referenceScale: %.6f", data->getReferenceScale());
  93. print("fps: %.6f", data->getFps());
  94. print("imagesPath: \"%s\"", data->getImagesPath().buffer());
  95. print("audioPath: \"%s\"", data->getAudioPath().buffer());
  96. // TODO: Add bones, slots, skins, animations, etc. in future expansion
  97. unindent();
  98. print("}");
  99. }
  100. void printSkeleton(Skeleton *skeleton) {
  101. print("Skeleton {");
  102. indent();
  103. print("x: %.6f", skeleton->getX());
  104. print("y: %.6f", skeleton->getY());
  105. print("scaleX: %.6f", skeleton->getScaleX());
  106. print("scaleY: %.6f", skeleton->getScaleY());
  107. print("time: %.6f", skeleton->getTime());
  108. // TODO: Add runtime state (bones, slots, etc.) in future expansion
  109. unindent();
  110. print("}");
  111. }
  112. };
  113. int main(int argc, char *argv[]) {
  114. // Set locale to ensure consistent number formatting
  115. setlocale(LC_ALL, "C");
  116. if (argc < 3) {
  117. fprintf(stderr, "Usage: DebugPrinter <skeleton-path> <atlas-path> [animation-name]\n");
  118. return 1;
  119. }
  120. Bone::setYDown(false);
  121. const char *skeletonPath = argv[1];
  122. const char *atlasPath = argv[2];
  123. const char *animationName = argc >= 4 ? argv[3] : nullptr;
  124. // Load atlas with headless texture loader
  125. HeadlessTextureLoader textureLoader;
  126. Atlas *atlas = new Atlas(atlasPath, &textureLoader);
  127. // Load skeleton data
  128. SkeletonData *skeletonData = nullptr;
  129. if (strstr(skeletonPath, ".json") != nullptr) {
  130. SkeletonJson json(atlas);
  131. skeletonData = json.readSkeletonDataFile(skeletonPath);
  132. } else {
  133. SkeletonBinary binary(atlas);
  134. skeletonData = binary.readSkeletonDataFile(skeletonPath);
  135. }
  136. if (!skeletonData) {
  137. fprintf(stderr, "Failed to load skeleton data\n");
  138. delete atlas;
  139. return 1;
  140. }
  141. // Print skeleton data
  142. printf("=== SKELETON DATA ===\n");
  143. Printer printer;
  144. printer.printSkeletonData(skeletonData);
  145. // Create skeleton instance
  146. Skeleton skeleton(*skeletonData);
  147. // Create animation state
  148. AnimationStateData stateData(skeletonData);
  149. AnimationState state(&stateData);
  150. skeleton.setupPose();
  151. // Set animation or setup pose
  152. if (animationName != nullptr) {
  153. // Find and set animation
  154. Animation *animation = skeletonData->findAnimation(animationName);
  155. if (!animation) {
  156. fprintf(stderr, "Animation not found: %s\n", animationName);
  157. delete skeletonData;
  158. delete atlas;
  159. return 1;
  160. }
  161. state.setAnimation(0, animation, true);
  162. // Update and apply
  163. state.update(0.016f);
  164. state.apply(skeleton);
  165. }
  166. skeleton.updateWorldTransform(Physics_Update);
  167. // Print skeleton state
  168. printf("\n=== SKELETON STATE ===\n");
  169. printer.printSkeleton(&skeleton);
  170. // Cleanup
  171. delete skeletonData;
  172. delete atlas;
  173. return 0;
  174. }