From 32a9a098312bb5a8922e15286d7b5731dcdbf156 Mon Sep 17 00:00:00 2001 From: NathanSweet Date: Thu, 28 Mar 2013 04:22:19 +0100 Subject: [PATCH] WIP C runtime. --- spine-c/.cproject | 131 ++++++ spine-c/.project | 27 ++ .../org.eclipse.cdt.codan.core.prefs | 68 +++ .../org.eclipse.cdt.managedbuilder.core.prefs | 13 + spine-c/data/spineboy-skeleton.json | 98 +++++ spine-c/data/spineboy-walk.json | 278 +++++++++++++ spine-c/data/spineboy.atlas | 166 ++++++++ spine-c/data/spineboy.png | Bin 0 -> 66315 bytes spine-c/src/SfmlRegionAttachment.c | 14 + spine-c/src/SfmlRegionAttachment.h | 23 ++ spine-c/src/SfmlSkeleton.c | 16 + spine-c/src/SfmlSkeleton.h | 23 ++ spine-c/src/main.c | 27 ++ spine-c/src/spine/Attachment.c | 22 + spine-c/src/spine/Attachment.h | 32 ++ spine-c/src/spine/Bone.c | 65 +++ spine-c/src/spine/Bone.h | 40 ++ spine-c/src/spine/BoneData.c | 16 + spine-c/src/spine/BoneData.h | 27 ++ spine-c/src/spine/RegionAttachment.c | 43 ++ spine-c/src/spine/RegionAttachment.h | 28 ++ spine-c/src/spine/Skeleton.c | 176 ++++++++ spine-c/src/spine/Skeleton.h | 71 ++++ spine-c/src/spine/SkeletonData.c | 46 +++ spine-c/src/spine/SkeletonData.h | 40 ++ spine-c/src/spine/SkeletonJson.c | 175 ++++++++ spine-c/src/spine/SkeletonJson.h | 26 ++ spine-c/src/spine/Skin.c | 52 +++ spine-c/src/spine/Skin.h | 37 ++ spine-c/src/spine/Slot.c | 58 +++ spine-c/src/spine/Slot.h | 39 ++ spine-c/src/spine/SlotData.c | 27 ++ spine-c/src/spine/SlotData.h | 29 ++ spine-c/src/spine/cJSON.c | 391 ++++++++++++++++++ spine-c/src/spine/cJSON.h | 84 ++++ spine-c/src/spine/spine.h | 15 + spine-c/src/spine/util.c | 17 + spine-c/src/spine/util.h | 17 + 38 files changed, 2457 insertions(+) create mode 100644 spine-c/.cproject create mode 100644 spine-c/.project create mode 100644 spine-c/.settings/org.eclipse.cdt.codan.core.prefs create mode 100644 spine-c/.settings/org.eclipse.cdt.managedbuilder.core.prefs create mode 100644 spine-c/data/spineboy-skeleton.json create mode 100644 spine-c/data/spineboy-walk.json create mode 100644 spine-c/data/spineboy.atlas create mode 100644 spine-c/data/spineboy.png create mode 100644 spine-c/src/SfmlRegionAttachment.c create mode 100644 spine-c/src/SfmlRegionAttachment.h create mode 100644 spine-c/src/SfmlSkeleton.c create mode 100644 spine-c/src/SfmlSkeleton.h create mode 100644 spine-c/src/main.c create mode 100644 spine-c/src/spine/Attachment.c create mode 100644 spine-c/src/spine/Attachment.h create mode 100644 spine-c/src/spine/Bone.c create mode 100644 spine-c/src/spine/Bone.h create mode 100644 spine-c/src/spine/BoneData.c create mode 100644 spine-c/src/spine/BoneData.h create mode 100644 spine-c/src/spine/RegionAttachment.c create mode 100644 spine-c/src/spine/RegionAttachment.h create mode 100644 spine-c/src/spine/Skeleton.c create mode 100644 spine-c/src/spine/Skeleton.h create mode 100644 spine-c/src/spine/SkeletonData.c create mode 100644 spine-c/src/spine/SkeletonData.h create mode 100644 spine-c/src/spine/SkeletonJson.c create mode 100644 spine-c/src/spine/SkeletonJson.h create mode 100644 spine-c/src/spine/Skin.c create mode 100644 spine-c/src/spine/Skin.h create mode 100644 spine-c/src/spine/Slot.c create mode 100644 spine-c/src/spine/Slot.h create mode 100644 spine-c/src/spine/SlotData.c create mode 100644 spine-c/src/spine/SlotData.h create mode 100644 spine-c/src/spine/cJSON.c create mode 100644 spine-c/src/spine/cJSON.h create mode 100644 spine-c/src/spine/spine.h create mode 100644 spine-c/src/spine/util.c create mode 100644 spine-c/src/spine/util.h diff --git a/spine-c/.cproject b/spine-c/.cproject new file mode 100644 index 000000000..c6d57c96e --- /dev/null +++ b/spine-c/.cproject @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spine-c/.project b/spine-c/.project new file mode 100644 index 000000000..462051309 --- /dev/null +++ b/spine-c/.project @@ -0,0 +1,27 @@ + + + spine-c + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.core.ccnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + diff --git a/spine-c/.settings/org.eclipse.cdt.codan.core.prefs b/spine-c/.settings/org.eclipse.cdt.codan.core.prefs new file mode 100644 index 000000000..c7be96702 --- /dev/null +++ b/spine-c/.settings/org.eclipse.cdt.codan.core.prefs @@ -0,0 +1,68 @@ +eclipse.preferences.version=1 +org.eclipse.cdt.codan.checkers.errnoreturn=Warning +org.eclipse.cdt.codan.checkers.errnoreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} +org.eclipse.cdt.codan.checkers.errreturnvalue=Error +org.eclipse.cdt.codan.checkers.errreturnvalue.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.noreturn=Error +org.eclipse.cdt.codan.checkers.noreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} +org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=Error +org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem=Error +org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem=Warning +org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=Error +org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=-Warning +org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>true,empty_case_param\=>false} +org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning +org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},unknown\=>false,exceptions\=>()} +org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=Error +org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization=Warning +org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},skip\=>true} +org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem=Error +org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem=Error +org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.InvalidArguments=Error +org.eclipse.cdt.codan.internal.checkers.InvalidArguments.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem=Error +org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem=Error +org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem=Error +org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem=Error +org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker=-Info +org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},pattern\=>"^[a-z]",macro\=>true,exceptions\=>()} +org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem=Warning +org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.OverloadProblem=Error +org.eclipse.cdt.codan.internal.checkers.OverloadProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem=Error +org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem=Error +org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem=-Warning +org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem=-Warning +org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem=Warning +org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true,exceptions\=>()} +org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem=Warning +org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},paramNot\=>false} +org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem=Warning +org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},else\=>false,afterelse\=>false} +org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem=Error +org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem=Warning +org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true} +org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem=Warning +org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true} +org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem=Warning +org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true,exceptions\=>("@(\#)","$Id")} +org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem=Error +org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +useParentScope=false diff --git a/spine-c/.settings/org.eclipse.cdt.managedbuilder.core.prefs b/spine-c/.settings/org.eclipse.cdt.managedbuilder.core.prefs new file mode 100644 index 000000000..f647a60a9 --- /dev/null +++ b/spine-c/.settings/org.eclipse.cdt.managedbuilder.core.prefs @@ -0,0 +1,13 @@ +eclipse.preferences.version=1 +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.debug.784427509/CPATH/delimiter=; +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.debug.784427509/CPATH/operation=remove +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.debug.784427509/CPLUS_INCLUDE_PATH/delimiter=; +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.debug.784427509/CPLUS_INCLUDE_PATH/operation=remove +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.debug.784427509/C_INCLUDE_PATH/delimiter=; +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.debug.784427509/C_INCLUDE_PATH/operation=remove +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.debug.784427509/append=true +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.debug.784427509/appendContributed=true +environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.debug.784427509/LIBRARY_PATH/delimiter=; +environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.debug.784427509/LIBRARY_PATH/operation=remove +environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.debug.784427509/append=true +environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.debug.784427509/appendContributed=true diff --git a/spine-c/data/spineboy-skeleton.json b/spine-c/data/spineboy-skeleton.json new file mode 100644 index 000000000..e6df6f99a --- /dev/null +++ b/spine-c/data/spineboy-skeleton.json @@ -0,0 +1,98 @@ +{ +"bones": [ + { "name": "root", "length": 0 }, + { "name": "hip", "parent": "root", "length": 0, "x": 0.64, "y": 114.41 }, + { "name": "left upper leg", "parent": "hip", "length": 50.39, "x": 14.45, "y": 2.81, "rotation": -89.09 }, + { "name": "left lower leg", "parent": "left upper leg", "length": 56.45, "x": 51.78, "y": 3.46, "rotation": -16.65 }, + { "name": "left foot", "parent": "left lower leg", "length": 46.5, "x": 64.02, "y": -8.67, "rotation": 102.43 }, + { "name": "right upper leg", "parent": "hip", "length": 45.76, "x": -18.27, "rotation": -101.13 }, + { "name": "right lower leg", "parent": "right upper leg", "length": 58.52, "x": 50.21, "y": 0.6, "rotation": -10.7 }, + { "name": "right foot", "parent": "right lower leg", "length": 45.45, "x": 64.88, "y": 0.04, "rotation": 110.3 }, + { "name": "torso", "parent": "hip", "length": 85.82, "x": -6.42, "y": 1.97, "rotation": 94.95 }, + { "name": "neck", "parent": "torso", "length": 18.38, "x": 83.64, "y": -1.78, "rotation": 0.9 }, + { "name": "head", "parent": "neck", "length": 68.28, "x": 19.09, "y": 6.97, "rotation": -8.94 }, + { "name": "right shoulder", "parent": "torso", "length": 49.95, "x": 81.9, "y": 6.79, "rotation": 130.6 }, + { "name": "right arm", "parent": "right shoulder", "length": 36.74, "x": 49.95, "y": -0.12, "rotation": 40.12 }, + { "name": "right hand", "parent": "right arm", "length": 15.32, "x": 36.9, "y": 0.34, "rotation": 2.35 }, + { "name": "left shoulder", "parent": "torso", "length": 44.19, "x": 78.96, "y": -15.75, "rotation": -156.96 }, + { "name": "left arm", "parent": "left shoulder", "length": 35.62, "x": 44.19, "y": -0.01, "rotation": 28.16 }, + { "name": "left hand", "parent": "left arm", "length": 11.52, "x": 35.62, "y": 0.07, "rotation": 2.7 }, + { "name": "pelvis", "parent": "hip", "length": 0, "x": 1.41, "y": -6.57 } +], +"slots": [ + { "name": "template", "bone": "root", "color": "ff898c86" }, + { "name": "left shoulder", "bone": "left shoulder", "attachment": "left-shoulder" }, + { "name": "left arm", "bone": "left arm", "attachment": "left-arm" }, + { "name": "left hand", "bone": "left hand", "attachment": "left-hand" }, + { "name": "left foot", "bone": "left foot", "attachment": "left-foot" }, + { "name": "left lower leg", "bone": "left lower leg", "attachment": "left-lower-leg" }, + { "name": "left upper leg", "bone": "left upper leg", "attachment": "left-upper-leg" }, + { "name": "pelvis", "bone": "pelvis", "attachment": "pelvis" }, + { "name": "right foot", "bone": "right foot", "attachment": "right-foot" }, + { "name": "right lower leg", "bone": "right lower leg", "attachment": "right-lower-leg" }, + { "name": "right upper leg", "bone": "right upper leg", "attachment": "right-upper-leg" }, + { "name": "torso", "bone": "torso", "attachment": "torso" }, + { "name": "neck", "bone": "neck", "attachment": "neck" }, + { "name": "head", "bone": "head", "attachment": "head" }, + { "name": "eyes", "bone": "head", "attachment": "eyes" }, + { "name": "right shoulder", "bone": "right shoulder", "attachment": "right-shoulder" }, + { "name": "right arm", "bone": "right arm", "attachment": "right-arm" }, + { "name": "right hand", "bone": "right hand", "attachment": "right-hand" } +], +"skins": { + "default": { + "left shoulder": { + "left-shoulder": { "x": 23.74, "y": 0.11, "rotation": 62.01, "width": 34, "height": 53 } + }, + "left arm": { + "left-arm": { "x": 15.11, "y": -0.44, "rotation": 33.84, "width": 35, "height": 29 } + }, + "left hand": { + "left-hand": { "x": 0.75, "y": 1.86, "rotation": 31.14, "width": 35, "height": 38 } + }, + "left foot": { + "left-foot": { "x": 24.35, "y": 8.88, "rotation": 3.32, "width": 65, "height": 30 } + }, + "left lower leg": { + "left-lower-leg": { "x": 24.55, "y": -1.92, "rotation": 105.75, "width": 49, "height": 64 } + }, + "left upper leg": { + "left-upper-leg": { "x": 26.12, "y": -1.85, "rotation": 89.09, "width": 33, "height": 67 } + }, + "pelvis": { + "pelvis": { "x": -4.83, "y": 10.62, "width": 63, "height": 47 } + }, + "right foot": { + "right-foot": { "x": 19.02, "y": 8.47, "rotation": 1.52, "width": 67, "height": 30 } + }, + "right lower leg": { + "right-lower-leg": { "x": 23.28, "y": -2.59, "rotation": 111.83, "width": 51, "height": 64 } + }, + "right upper leg": { + "right-upper-leg": { "x": 23.03, "y": 0.25, "rotation": 101.13, "width": 44, "height": 70 } + }, + "torso": { + "torso": { "x": 44.57, "y": -7.08, "rotation": -94.95, "width": 68, "height": 92 } + }, + "neck": { + "neck": { "x": 9.42, "y": -3.66, "rotation": -100.15, "width": 34, "height": 28 } + }, + "head": { + "head": { "x": 53.94, "y": -5.75, "rotation": -86.9, "width": 121, "height": 132 } + }, + "eyes": { + "eyes": { "x": 28.94, "y": -32.92, "rotation": -86.9, "width": 34, "height": 27 }, + "eyes-closed": { "x": 28.77, "y": -32.86, "rotation": -86.9, "width": 34, "height": 27 } + }, + "right shoulder": { + "right-shoulder": { "x": 25.86, "y": 0.03, "rotation": 134.44, "width": 52, "height": 51 } + }, + "right arm": { + "right-arm": { "x": 18.34, "y": -2.64, "rotation": 94.32, "width": 21, "height": 45 } + }, + "right hand": { + "right-hand": { "x": 6.82, "y": 1.25, "rotation": 91.96, "width": 32, "height": 32 } + } + } +} +} \ No newline at end of file diff --git a/spine-c/data/spineboy-walk.json b/spine-c/data/spineboy-walk.json new file mode 100644 index 000000000..b40e53a95 --- /dev/null +++ b/spine-c/data/spineboy-walk.json @@ -0,0 +1,278 @@ +{ +"bones": { + "left upper leg": { + "rotate": [ + { "time": 0, "angle": -26.55 }, + { "time": 0.1333, "angle": -8.78 }, + { "time": 0.2666, "angle": 9.51 }, + { "time": 0.4, "angle": 30.74 }, + { "time": 0.5333, "angle": 25.33 }, + { "time": 0.6666, "angle": 26.11 }, + { "time": 0.8, "angle": -7.7 }, + { "time": 0.9333, "angle": -21.19 }, + { "time": 1.0666, "angle": -26.55 } + ], + "translate": [ + { "time": 0, "x": -3, "y": -2.25 }, + { "time": 0.4, "x": -2.18, "y": -2.25 }, + { "time": 1.0666, "x": -3, "y": -2.25 } + ] + }, + "right upper leg": { + "rotate": [ + { "time": 0, "angle": 42.45 }, + { "time": 0.1333, "angle": 52.1 }, + { "time": 0.2666, "angle": 5.96 }, + { "time": 0.5333, "angle": -16.93 }, + { "time": 0.6666, "angle": 1.89 }, + { + "time": 0.8, + "angle": 28.06, + "curve": [ 0.462, 0.11, 1, 1 ] + }, + { + "time": 0.9333, + "angle": 58.68, + "curve": [ 0.5, 0.02, 1, 1 ] + }, + { "time": 1.0666, "angle": 42.45 } + ], + "translate": [ + { "time": 0, "x": 8.11, "y": -2.36 }, + { "time": 0.1333, "x": 10.03, "y": -2.56 }, + { "time": 0.4, "x": 2.76, "y": -2.97 }, + { "time": 0.5333, "x": 2.76, "y": -2.81 }, + { "time": 0.9333, "x": 8.67, "y": -2.54 }, + { "time": 1.0666, "x": 8.11, "y": -2.36 } + ] + }, + "left lower leg": { + "rotate": [ + { "time": 0, "angle": -10.21 }, + { "time": 0.1333, "angle": -55.64 }, + { "time": 0.2666, "angle": -68.12 }, + { "time": 0.5333, "angle": 5.11 }, + { "time": 0.6666, "angle": -28.29 }, + { "time": 0.8, "angle": 4.08 }, + { "time": 0.9333, "angle": 3.53 }, + { "time": 1.0666, "angle": -10.21 } + ] + }, + "left foot": { + "rotate": [ + { "time": 0, "angle": -3.69 }, + { "time": 0.1333, "angle": -10.42 }, + { "time": 0.2666, "angle": -17.14 }, + { "time": 0.4, "angle": -2.83 }, + { "time": 0.5333, "angle": -3.87 }, + { "time": 0.6666, "angle": 2.78 }, + { "time": 0.8, "angle": 1.68 }, + { "time": 0.9333, "angle": -8.54 }, + { "time": 1.0666, "angle": -3.69 } + ] + }, + "right shoulder": { + "rotate": [ + { + "time": 0, + "angle": 20.89, + "curve": [ 0.264, 0, 0.75, 1 ] + }, + { + "time": 0.1333, + "angle": 3.72, + "curve": [ 0.272, 0, 0.841, 1 ] + }, + { "time": 0.6666, "angle": -278.28 }, + { "time": 1.0666, "angle": 20.89 } + ], + "translate": [ + { "time": 0, "x": -7.84, "y": 7.19 }, + { "time": 0.1333, "x": -6.36, "y": 6.42 }, + { "time": 0.6666, "x": -11.07, "y": 5.25 }, + { "time": 1.0666, "x": -7.84, "y": 7.19 } + ] + }, + "right arm": { + "rotate": [ + { + "time": 0, + "angle": -4.02, + "curve": [ 0.267, 0, 0.804, 0.99 ] + }, + { + "time": 0.1333, + "angle": -13.99, + "curve": [ 0.341, 0, 1, 1 ] + }, + { + "time": 0.6666, + "angle": 36.54, + "curve": [ 0.307, 0, 0.787, 0.99 ] + }, + { "time": 1.0666, "angle": -4.02 } + ] + }, + "right hand": { + "rotate": [ + { "time": 0, "angle": 22.92 }, + { "time": 0.4, "angle": -8.97 }, + { "time": 0.6666, "angle": 0.51 }, + { "time": 1.0666, "angle": 22.92 } + ] + }, + "left shoulder": { + "rotate": [ + { "time": 0, "angle": -1.47 }, + { "time": 0.1333, "angle": 13.6 }, + { "time": 0.6666, "angle": 280.74 }, + { "time": 1.0666, "angle": -1.47 } + ], + "translate": [ + { "time": 0, "x": -1.76, "y": 0.56 }, + { "time": 0.6666, "x": -2.47, "y": 8.14 }, + { "time": 1.0666, "x": -1.76, "y": 0.56 } + ] + }, + "left hand": { + "rotate": [ + { + "time": 0, + "angle": 11.58, + "curve": [ 0.169, 0.37, 0.632, 1.55 ] + }, + { + "time": 0.1333, + "angle": 28.13, + "curve": [ 0.692, 0, 0.692, 0.99 ] + }, + { + "time": 0.6666, + "angle": -27.42, + "curve": [ 0.117, 0.41, 0.738, 1.76 ] + }, + { "time": 0.8, "angle": -36.32 }, + { "time": 1.0666, "angle": 11.58 } + ] + }, + "left arm": { + "rotate": [ + { "time": 0, "angle": -8.27 }, + { "time": 0.1333, "angle": 18.43 }, + { "time": 0.6666, "angle": 0.88 }, + { "time": 1.0666, "angle": -8.27 } + ] + }, + "torso": { + "rotate": [ + { "time": 0, "angle": -10.28 }, + { + "time": 0.1333, + "angle": -15.38, + "curve": [ 0.545, 0, 1, 1 ] + }, + { + "time": 0.4, + "angle": -9.78, + "curve": [ 0.58, 0.17, 1, 1 ] + }, + { "time": 0.6666, "angle": -15.75 }, + { "time": 0.9333, "angle": -7.06 }, + { "time": 1.0666, "angle": -10.28 } + ], + "translate": [ + { "time": 0, "x": -3.67, "y": 1.68 }, + { "time": 0.1333, "x": -3.67, "y": 0.68 }, + { "time": 0.4, "x": -3.67, "y": 1.97 }, + { "time": 0.6666, "x": -3.67, "y": -0.14 }, + { "time": 1.0666, "x": -3.67, "y": 1.68 } + ] + }, + "right foot": { + "rotate": [ + { "time": 0, "angle": -5.25 }, + { "time": 0.2666, "angle": -4.08 }, + { "time": 0.4, "angle": -6.45 }, + { "time": 0.5333, "angle": -5.39 }, + { "time": 0.8, "angle": -11.68 }, + { "time": 0.9333, "angle": 0.46 }, + { "time": 1.0666, "angle": -5.25 } + ] + }, + "right lower leg": { + "rotate": [ + { "time": 0, "angle": -3.39 }, + { "time": 0.1333, "angle": -45.53 }, + { "time": 0.2666, "angle": -2.59 }, + { "time": 0.5333, "angle": -19.53 }, + { "time": 0.6666, "angle": -64.8 }, + { + "time": 0.8, + "angle": -82.56, + "curve": [ 0.557, 0.18, 1, 1 ] + }, + { "time": 1.0666, "angle": -3.39 } + ] + }, + "hip": { + "rotate": [ + { "time": 0, "angle": 0, "curve": "stepped" }, + { "time": 1.0666, "angle": 0 } + ], + "translate": [ + { "time": 0, "x": 0, "y": 0 }, + { + "time": 0.1333, + "x": 0, + "y": -7.61, + "curve": [ 0.272, 0.86, 1, 1 ] + }, + { "time": 0.4, "x": 0, "y": 8.7 }, + { "time": 0.5333, "x": 0, "y": -0.41 }, + { + "time": 0.6666, + "x": 0, + "y": -7.05, + "curve": [ 0.235, 0.89, 1, 1 ] + }, + { "time": 0.8, "x": 0, "y": 2.92 }, + { "time": 0.9333, "x": 0, "y": 6.78 }, + { "time": 1.0666, "x": 0, "y": 0 } + ] + }, + "neck": { + "rotate": [ + { "time": 0, "angle": 3.6 }, + { "time": 0.1333, "angle": 17.49 }, + { "time": 0.2666, "angle": 6.1 }, + { "time": 0.4, "angle": 3.45 }, + { "time": 0.5333, "angle": 5.17 }, + { "time": 0.6666, "angle": 18.36 }, + { "time": 0.8, "angle": 6.09 }, + { "time": 0.9333, "angle": 2.28 }, + { "time": 1.0666, "angle": 3.6 } + ] + }, + "head": { + "rotate": [ + { + "time": 0, + "angle": 3.6, + "curve": [ 0, 0, 0.704, 1.61 ] + }, + { "time": 0.1666, "angle": -0.2 }, + { "time": 0.2666, "angle": 6.1 }, + { "time": 0.4, "angle": 3.45 }, + { + "time": 0.5333, + "angle": 5.17, + "curve": [ 0, 0, 0.704, 1.61 ] + }, + { "time": 0.7, "angle": 1.1 }, + { "time": 0.8, "angle": 6.09 }, + { "time": 0.9333, "angle": 2.28 }, + { "time": 1.0666, "angle": 3.6 } + ] + } +} +} \ No newline at end of file diff --git a/spine-c/data/spineboy.atlas b/spine-c/data/spineboy.atlas new file mode 100644 index 000000000..ac19de904 --- /dev/null +++ b/spine-c/data/spineboy.atlas @@ -0,0 +1,166 @@ + +../data/spineboy.png +format: RGBA8888 +filter: Nearest,Nearest +repeat: none +head + rotate: false + xy: 1, 122 + size: 121, 132 + orig: 121, 132 + offset: 0, 0 + index: -1 +torso + rotate: false + xy: 1, 28 + size: 68, 92 + orig: 68, 92 + offset: 0, 0 + index: -1 +left-pant-bottom + rotate: false + xy: 1, 4 + size: 44, 22 + orig: 44, 22 + offset: 0, 0 + index: -1 +right-pant-bottom + rotate: false + xy: 47, 8 + size: 46, 18 + orig: 46, 18 + offset: 0, 0 + index: -1 +right-upper-leg + rotate: false + xy: 71, 50 + size: 44, 70 + orig: 44, 70 + offset: 0, 0 + index: -1 +pelvis + rotate: false + xy: 95, 1 + size: 63, 47 + orig: 63, 47 + offset: 0, 0 + index: -1 +left-upper-leg + rotate: false + xy: 117, 53 + size: 33, 67 + orig: 33, 67 + offset: 0, 0 + index: -1 +right-foot + rotate: false + xy: 160, 224 + size: 67, 30 + orig: 67, 30 + offset: 0, 0 + index: -1 +left-shoulder + rotate: false + xy: 124, 201 + size: 34, 53 + orig: 34, 53 + offset: 0, 0 + index: -1 +left-ankle + rotate: false + xy: 229, 222 + size: 25, 32 + orig: 25, 32 + offset: 0, 0 + index: -1 +left-foot + rotate: false + xy: 160, 192 + size: 65, 30 + orig: 65, 30 + offset: 0, 0 + index: -1 +neck + rotate: false + xy: 124, 171 + size: 34, 28 + orig: 34, 28 + offset: 0, 0 + index: -1 +right-arm + rotate: false + xy: 124, 124 + size: 21, 45 + orig: 21, 45 + offset: 0, 0 + index: -1 +right-ankle + rotate: false + xy: 227, 190 + size: 25, 30 + orig: 25, 30 + offset: 0, 0 + index: -1 +left-hand + rotate: false + xy: 147, 131 + size: 35, 38 + orig: 35, 38 + offset: 0, 0 + index: -1 +left-arm + rotate: false + xy: 184, 161 + size: 35, 29 + orig: 35, 29 + offset: 0, 0 + index: -1 +eyes-closed + rotate: false + xy: 221, 161 + size: 34, 27 + orig: 34, 27 + offset: 0, 0 + index: -1 +right-lower-leg + rotate: false + xy: 152, 65 + size: 51, 64 + orig: 51, 64 + offset: 0, 0 + index: -1 +right-foot-idle + rotate: false + xy: 184, 131 + size: 53, 28 + orig: 53, 28 + offset: 0, 0 + index: -1 +left-lower-leg + rotate: false + xy: 205, 65 + size: 49, 64 + orig: 49, 64 + offset: 0, 0 + index: -1 +right-shoulder + rotate: false + xy: 160, 12 + size: 52, 51 + orig: 52, 51 + offset: 0, 0 + index: -1 +eyes + rotate: false + xy: 214, 36 + size: 34, 27 + orig: 34, 27 + offset: 0, 0 + index: -1 +right-hand + rotate: false + xy: 214, 2 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 diff --git a/spine-c/data/spineboy.png b/spine-c/data/spineboy.png new file mode 100644 index 0000000000000000000000000000000000000000..b8b493dfd171fea37d29596ef6a67725d8a2f36f GIT binary patch literal 66315 zcmV)#K##wPP)nw>WaP5YXSsFZ<9<hd-bjOl0O`Fa5PA(oYG@*ey{?K178C+l zuwz{zdH-|1%wPx!q=O6dJmXQ3&Uf8)*B<|~kHeeuZ#~vrH2Tx6 zrDjK)OQlD*7i*3;mzZK-*53g9<SbnyxUv0m5)8TqgZydxg_%F z_L7Wa+e-?_mXRGGJKVCpwv zWpn;8CW>ok_!SI=X)TGq7XrJWh@L4lsB4($?M^>c9MJ`E8jLlAoi?*E^7cnL) zIqHF^sHneRyG^dU?&DpB_Z;0;>cBug)?D%;0rx9141)bmc9d*y%l6_bA_||AyNVyY zb_E6y^i3r<(zTRp$@f+5wLEjdwP-FqdHT7Unb!#5Dt!>xjmb;T)q3>b1_|&zGCGcz z=w^*RzO&??*C5=t$FXg>cOKndT1=$+V^7cf>E~;)y(GCjTqgVXpZ)}7B*t2##zqw< zM1*`C6B2-^Kwm@!`5`*kAJMdpq`zb6IgtX=5@IkrIsVMd=q>9Qv)eldNi!vqK zLms~!_zZe2z%OPY-tO)D(UyP@FMHKew!t_?52^GvjZ9|Xppdz16w*k0r99DIDT~u6 zWJwNk=`4*>mO}4k*vqB!92D|w+Rm|8$Z|DuSqbe^&d==?Qf~*jT<&0Fb6>x1l;+}~ zZf*n}2rs81xcK*PD|z~}t@SrugL|iVzq!P;Ki7cNAcX;Sczx+?c$!-vTBAw7@;!cH z%=onUn7Z?TPu~4f!0&9~eqQi#vV*JAwvg?AnE;OOC>wu~8=-XwynkN_qV>G+U|UJR zHQ4|0_;!EwoBhteG?(JX=WDRFC>GAfmYD1Bo_VDv_9mpo#cX5g9vR?sPS*Dp_#Fwr z+ffY{g^eFue~wM1Qr%0yUQQscaZt*93Dh|b3h8Fr9whsP3KoDdqn|1B_^_# zJw7M)&c*U1;rj~yFkeq$o^}d2NhKC+eK|IbTyEtcmn|gFe?LGV@2MShwo^LyhV! z?Xm$q$4AM&c)A*2>?%e{s1w3es^^9d`0>#*Nanw%i|+@@+jo}!5&qt-{;rO2kx5!O zN!OEOv$M0igMh#FN&x;j0Vq%0D`V)%Sy7d0!C7Id(mk5B9R)PR_ltup;fj?u$ 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 literal 0 HcmV?d00001 diff --git a/spine-c/src/SfmlRegionAttachment.c b/spine-c/src/SfmlRegionAttachment.c new file mode 100644 index 000000000..82ca6f5ea --- /dev/null +++ b/spine-c/src/SfmlRegionAttachment.c @@ -0,0 +1,14 @@ +#include "SfmlRegionAttachment.h" +#include + +void SfmlRegionAttachment_dispose (Attachment* attachment) { + SfmlRegionAttachment* this = (SfmlRegionAttachment*)attachment; + RegionAttachment_dispose(&this->super); +} + +SfmlRegionAttachment* SfmlRegionAttachment_create (const char* name) { + SfmlRegionAttachment* this = calloc(1, sizeof(SfmlRegionAttachment)); + RegionAttachment_init(&this->super, name); + ((Attachment*)this)->_dispose = SfmlRegionAttachment_dispose; + return this; +} diff --git a/spine-c/src/SfmlRegionAttachment.h b/spine-c/src/SfmlRegionAttachment.h new file mode 100644 index 000000000..6e77e1161 --- /dev/null +++ b/spine-c/src/SfmlRegionAttachment.h @@ -0,0 +1,23 @@ +#ifndef SPINE_SFMLREGIONATTACHMENT_H_ +#define SPINE_SFMLREGIONATTACHMENT_H_ + +#include + +#ifdef __cplusplus +namespace spine { +extern "C" { +#endif + +typedef struct { + RegionAttachment super; + int meow; +} SfmlRegionAttachment; + +SfmlRegionAttachment* SfmlRegionAttachment_create (const char* name); + +#ifdef __cplusplus +} +} +#endif + +#endif /* SPINE_SFMLREGIONATTACHMENT_H_ */ diff --git a/spine-c/src/SfmlSkeleton.c b/spine-c/src/SfmlSkeleton.c new file mode 100644 index 000000000..6663c5934 --- /dev/null +++ b/spine-c/src/SfmlSkeleton.c @@ -0,0 +1,16 @@ +#include "SfmlSkeleton.h" +#include + +void SfmlSkeleton_dispose (Skeleton* skeleton) { + // SfmlSkeleton* this = (SfmlSkeleton*)skeleton; +} + +Skeleton* Skeleton_create (SkeletonData* data) { + SfmlSkeleton* this = calloc(1, sizeof(SfmlSkeleton)); + Skeleton_init(&this->super, data); + this->super._dispose = SfmlSkeleton_dispose; + return &this->super; +} + +void Skeleton_draw (Skeleton* skeleton) { +} diff --git a/spine-c/src/SfmlSkeleton.h b/spine-c/src/SfmlSkeleton.h new file mode 100644 index 000000000..a4ee5a5b0 --- /dev/null +++ b/spine-c/src/SfmlSkeleton.h @@ -0,0 +1,23 @@ +#ifndef SPINE_SFMLSKELETON_H_ +#define SPINE_SFMLSKELETON_H_ + +#include + +#ifdef __cplusplus +namespace spine {extern "C" { +#endif + +typedef struct { + Skeleton super; + int meow; +} SfmlSkeleton; + +Skeleton* Skeleton_create (SkeletonData* data); + +void Skeleton_draw (); + +#ifdef __cplusplus +}} +#endif + +#endif /* SPINE_SFMLSKELETON_H_ */ diff --git a/spine-c/src/main.c b/spine-c/src/main.c new file mode 100644 index 000000000..c3efaa9f5 --- /dev/null +++ b/spine-c/src/main.c @@ -0,0 +1,27 @@ +#include +#include +#include + +#include +#include "SfmlSkeleton.h" +#include "spine/cJSON.h" + +int main (void) { + //BoneData *boneData = BoneData_create("meow"); + + //printf("name: %s\n", boneData->name); + //printf("length struct: %f\n", boneData->length); + + //SkeletonData* data = + SkeletonJson_readSkeletonDataFile("data/spineboy-skeleton.json"); + printf("error: %s\n", SkeletonJson_getError()); + + SkeletonData *skeletonData = SkeletonData_create(); + Skeleton* skeleton = Skeleton_create(skeletonData); + //Skeleton_something(skeleton); + printf("meow? %d\n", ((SfmlSkeleton*)skeleton)->meow); + Skeleton_dispose(skeleton); + printf("meow? %d\n", ((SfmlSkeleton*)skeleton)->meow); + + return 0; +} diff --git a/spine-c/src/spine/Attachment.c b/spine-c/src/spine/Attachment.c new file mode 100644 index 000000000..03755e8ee --- /dev/null +++ b/spine-c/src/spine/Attachment.c @@ -0,0 +1,22 @@ +#include +#include + +static AttachmentLoader loader; + +void Attachment_setAttachmentLoader (AttachmentLoader value) { + loader = value; +} + +AttachmentLoader Attachment_getAttachmentLoader () { + return loader; +} + +void Attachment_init (Attachment* this, const char* name) { + MALLOC_STR(this->name, name); +} + +void Attachment_dispose (Attachment* this) { + this->_dispose(this); + FREE(this->name) + FREE(this) +} diff --git a/spine-c/src/spine/Attachment.h b/spine-c/src/spine/Attachment.h new file mode 100644 index 000000000..9b7957689 --- /dev/null +++ b/spine-c/src/spine/Attachment.h @@ -0,0 +1,32 @@ +#ifndef SPINE_ATTACHMENT_H_ +#define SPINE_ATTACHMENT_H_ + +#ifdef __cplusplus +namespace spine { +extern "C" { +#endif + +typedef enum { + ATTACHMENT_REGION, ATTACHMENT_REGION_SEQUENCE +} AttachmentType; + +typedef struct Attachment Attachment; +struct Attachment { + const char* const name; + void (*_dispose) (Attachment* attachment); +}; + +typedef Attachment* (*AttachmentLoader) (AttachmentType type, const char* name); + +void Attachment_setAttachmentLoader (AttachmentLoader loader); +AttachmentLoader Attachment_getAttachmentLoader (); + +void Attachment_init (Attachment* attachment, const char* name); +void Attachment_dispose (Attachment* attachment); + +#ifdef __cplusplus +} +} +#endif + +#endif /* SPINE_ATTACHMENT_H_ */ diff --git a/spine-c/src/spine/Bone.c b/spine-c/src/spine/Bone.c new file mode 100644 index 000000000..30fb73d3d --- /dev/null +++ b/spine-c/src/spine/Bone.c @@ -0,0 +1,65 @@ +#include +#include +#include + +static int yDown; + +void Bone_setYDown (int value) { + yDown = value; +} + +Bone* Bone_create (BoneData* data, Bone* parent) { + Bone* this = calloc(1, sizeof(Bone)); + CAST(BoneData*, this->data) = data; + CAST(Bone*, this->parent) = parent; + this->scaleX = 1; + this->scaleY = 1; + return this; +} + +void Bone_dispose (Bone* this) { + FREE(this) +} + +void Bone_setToBindPose (Bone* this) { + this->x = this->data->x; + this->y = this->data->y; + this->rotation = this->data->rotation; + this->scaleX = this->data->scaleX; + this->scaleY = this->data->scaleY; +} + +void Bone_updateWorldTransform (Bone* this, int flipX, int flipY) { + if (this->parent) { + CAST(float, this->worldX) = this->x * this->parent->m00 + this->y * this->parent->m01 + this->parent->worldX; + CAST(float, this->worldY) = this->x * this->parent->m10 + this->y * this->parent->m11 + this->parent->worldY; + CAST(float, this->worldScaleX) = this->parent->worldScaleX * this->scaleX; + CAST(float, this->worldScaleY) = this->parent->worldScaleY * this->scaleY; + CAST(float, this->worldRotation) = this->parent->worldRotation + this->rotation; + } else { + CAST(float, this->worldX) = this->x; + CAST(float, this->worldY) = this->y; + CAST(float, this->worldScaleX) = this->scaleX; + CAST(float, this->worldScaleY) = this->scaleY; + CAST(float, this->worldRotation) = this->rotation; + } + float radians = (float)(this->worldRotation * 3.1415926535897932385 / 180); + float cos = cosf(radians); + float sin = sinf(radians); + CAST(float, this->m00) = cos * this->worldScaleX; + CAST(float, this->m10) = sin * this->worldScaleX; + CAST(float, this->m01) = -sin * this->worldScaleY; + CAST(float, this->m11) = cos * this->worldScaleY; + if (flipX) { + CAST(float, this->m00) = -this->m00; + CAST(float, this->m01) = -this->m01; + } + if (flipY) { + CAST(float, this->m10) = -this->m10; + CAST(float, this->m11) = -this->m11; + } + if (yDown) { + CAST(float, this->m10) = -this->m10; + CAST(float, this->m11) = -this->m11; + } +} diff --git a/spine-c/src/spine/Bone.h b/spine-c/src/spine/Bone.h new file mode 100644 index 000000000..2cac45d29 --- /dev/null +++ b/spine-c/src/spine/Bone.h @@ -0,0 +1,40 @@ +#ifndef SPINE_BONE_H_ +#define SPINE_BONE_H_ + +#include + +#ifdef __cplusplus +namespace spine { +extern "C" { +#endif + +typedef struct Bone Bone; +struct Bone { + BoneData* const data; + Bone* const parent; + float x, y; + float rotation; + float scaleX, scaleY; + + float const m00, m01, worldX; // a b x + float const m10, m11, worldY; // c d y + float const worldRotation; + float const worldScaleX, worldScaleY; +}; + +void Bone_setYDown (int yDown); + +/** @param parent May be zero. */ +Bone* Bone_create (BoneData* data, Bone* parent); +void Bone_dispose (Bone* bone); + +void Bone_setToBindPose (Bone* bone); + +void Bone_updateWorldTransform (Bone* bone, int flipX, int flipY); + +#ifdef __cplusplus +} +} +#endif + +#endif /* SPINE_BONE_H_ */ diff --git a/spine-c/src/spine/BoneData.c b/spine-c/src/spine/BoneData.c new file mode 100644 index 000000000..ceb09c3d5 --- /dev/null +++ b/spine-c/src/spine/BoneData.c @@ -0,0 +1,16 @@ +#include +#include + +BoneData* BoneData_create (const char* name, BoneData* parent) { + BoneData* this = calloc(1, sizeof(BoneData)); + MALLOC_STR(this->name, name) + CAST(BoneData*, this->parent) = parent; + this->scaleX = 1; + this->scaleY = 1; + return this; +} + +void BoneData_dispose (BoneData* this) { + FREE(this->name) + FREE(this) +} diff --git a/spine-c/src/spine/BoneData.h b/spine-c/src/spine/BoneData.h new file mode 100644 index 000000000..3eb9a541c --- /dev/null +++ b/spine-c/src/spine/BoneData.h @@ -0,0 +1,27 @@ +#ifndef SPINE_BONEDATA_H_ +#define SPINE_BONEDATA_H_ + +#ifdef __cplusplus +namespace spine { +extern "C" { +#endif + +typedef struct BoneData BoneData; +struct BoneData { + const char* const name; + BoneData* const parent; + float length; + float x, y; + float rotation; + float scaleX, scaleY; +}; + +BoneData* BoneData_create (const char* name, BoneData* parent); +void BoneData_dispose (BoneData* boneData); + +#ifdef __cplusplus +} +} +#endif + +#endif /* SPINE_BONEDATA_H_ */ diff --git a/spine-c/src/spine/RegionAttachment.c b/spine-c/src/spine/RegionAttachment.c new file mode 100644 index 000000000..47b380cf2 --- /dev/null +++ b/spine-c/src/spine/RegionAttachment.c @@ -0,0 +1,43 @@ +#include +#include +#include + +void RegionAttachment_init (RegionAttachment* this, const char* name) { + Attachment_init(&this->super, name); + this->scaleX = 1; + this->scaleY = 1; +} + +void RegionAttachment_dispose (RegionAttachment* this) { + Attachment_dispose(&this->super); +} + +void RegionAttachment_updateOffset (RegionAttachment* this) { + float localX2 = this->width / 2; + float localY2 = this->height / 2; + float localX = -localX2; + float localY = -localY2; + localX *= this->scaleX; + localY *= this->scaleY; + localX2 *= this->scaleX; + localY2 *= this->scaleY; + float radians = (float)(this->rotation * 3.1415926535897932385 / 180); + float cos = cosf(radians); + float sin = sinf(radians); + float localXCos = localX * cos + this->x; + float localXSin = localX * sin; + float localYCos = localY * cos + this->y; + float localYSin = localY * sin; + float localX2Cos = localX2 * cos + this->x; + float localX2Sin = localX2 * sin; + float localY2Cos = localY2 * cos + this->y; + float localY2Sin = localY2 * sin; + this->offset[0] = localXCos - localYSin; + this->offset[1] = localYCos + localXSin; + this->offset[2] = localXCos - localY2Sin; + this->offset[3] = localY2Cos + localXSin; + this->offset[4] = localX2Cos - localY2Sin; + this->offset[5] = localY2Cos + localX2Sin; + this->offset[6] = localX2Cos - localYSin; + this->offset[7] = localYCos + localX2Sin; +} diff --git a/spine-c/src/spine/RegionAttachment.h b/spine-c/src/spine/RegionAttachment.h new file mode 100644 index 000000000..1d758b359 --- /dev/null +++ b/spine-c/src/spine/RegionAttachment.h @@ -0,0 +1,28 @@ +#ifndef SPINE_REGIONATTACHMENT_H_ +#define SPINE_REGIONATTACHMENT_H_ + +#include + +#ifdef __cplusplus +namespace spine { +extern "C" { +#endif + +typedef struct RegionAttachment RegionAttachment; +struct RegionAttachment { + Attachment super; + float x, y, scaleX, scaleY, rotation, width, height; + float offset[8]; +}; + +void RegionAttachment_init (RegionAttachment* this, const char* name); +void RegionAttachment_dispose (RegionAttachment* attachment); + +void RegionAttachment_updateOffset (RegionAttachment* attachment); + +#ifdef __cplusplus +} +} +#endif + +#endif /* SPINE_REGIONATTACHMENT_H_ */ diff --git a/spine-c/src/spine/Skeleton.c b/spine-c/src/spine/Skeleton.c new file mode 100644 index 000000000..6909deaba --- /dev/null +++ b/spine-c/src/spine/Skeleton.c @@ -0,0 +1,176 @@ +#include +#include + +void Skeleton_init (Skeleton* this, SkeletonData* data) { + CAST(SkeletonData*, this->data) = data; + + this->boneCount = this->data->boneCount; + this->bones = malloc(sizeof(Bone*) * this->boneCount); + int i, ii; + for (i = 0; i < this->boneCount; ++i) { + BoneData* boneData = this->data->bones[i]; + Bone* parent = 0; + if (boneData->parent) { + // Find parent bone. + for (ii = 0; ii < this->boneCount; ++ii) { + if (data->bones[ii] == boneData->parent) { + parent = this->bones[ii]; + break; + } + } + } + this->bones[i] = Bone_create(boneData, parent); + } + + this->slotCount = data->slotCount; + this->slots = malloc(sizeof(Slot*) * this->slotCount); + for (i = 0; i < this->slotCount; ++i) { + SlotData *slotData = data->slots[i]; + + // Find bone for the slotData's boneData. + Bone *bone; + for (ii = 0; ii < this->boneCount; ++ii) { + if (data->bones[ii] == slotData->boneData) { + bone = this->bones[ii]; + break; + } + } + + this->slots[i] = Slot_create(slotData, this, bone); + } + + this->drawOrder = malloc(sizeof(Slot*) * this->slotCount); + memcpy(this->drawOrder, this->slots, sizeof(Slot*) * this->slotCount); +} + +void Skeleton_dispose (Skeleton* this) { + if (this->_dispose) this->_dispose(this); + + int i; + for (i = 0; i < this->boneCount; ++i) + Bone_dispose(this->bones[i]); + FREE(this->bones) + + FREE(this->slots) + for (i = 0; i < this->slotCount; ++i) + Slot_dispose(this->slots[i]); + + FREE(this->drawOrder) + + FREE(this) +} + +void Skeleton_updateWorldTransform (const Skeleton* this) { + int i; + for (i = 0; i < this->boneCount; ++i) + Bone_updateWorldTransform(this->bones[i], this->flipX, this->flipY); +} + +void Skeleton_setToBindPose (const Skeleton* this) { + Skeleton_setBonesToBindPose(this); + Skeleton_setSlotsToBindPose(this); +} + +void Skeleton_setBonesToBindPose (const Skeleton* this) { + int i; + for (i = 0; i < this->boneCount; ++i) + Bone_setToBindPose(this->bones[i]); +} + +void Skeleton_setSlotsToBindPose (const Skeleton* this) { + int i; + for (i = 0; i < this->slotCount; ++i) + Slot_setToBindPose(this->slots[i]); +} + +Bone* Skeleton_getRootBone (const Skeleton* this) { + if (this->boneCount == 0) return 0; + return this->bones[0]; +} + +Bone* Skeleton_findBone (const Skeleton* this, const char* boneName) { + int i; + for (i = 0; i < this->boneCount; ++i) + if (this->data->bones[i]->name == boneName) return this->bones[i]; + return 0; +} + +int Skeleton_findBoneIndex (const Skeleton* this, const char* boneName) { + int i; + for (i = 0; i < this->boneCount; ++i) + if (this->data->bones[i]->name == boneName) return i; + return -1; +} + +Slot* Skeleton_findSlot (const Skeleton* this, const char* slotName) { + int i; + for (i = 0; i < this->slotCount; ++i) + if (this->data->slots[i]->name == slotName) return this->slots[i]; + return 0; +} + +int Skeleton_findSlotIndex (const Skeleton* this, const char* slotName) { + int i; + for (i = 0; i < this->slotCount; ++i) + if (this->data->slots[i]->name == slotName) return i; + return -1; +} + +int Skeleton_setSkinByName (Skeleton* this, const char* skinName) { + Skin *skin = SkeletonData_findSkin(this->data, skinName); + if (!skin) return 0; + Skeleton_setSkin(this, skin); + return 1; +} + +void Skeleton_setSkin (Skeleton* this, Skin* newSkin) { + if (this->skin && newSkin) { + // Attach each attachment in the new skin if the corresponding attachment in the old skin is currently attached. + const SkinEntry *entry = this->skin->entryList; + while (entry) { + Slot *slot = this->slots[entry->slotIndex]; + if (slot->attachment == entry->attachment) { + Attachment *attachment = Skin_getAttachment(newSkin, entry->slotIndex, entry->name); + if (attachment) Slot_setAttachment(slot, attachment); + } + entry = entry->next; + } + } + CAST(Skin*, this->skin) = newSkin; +} + +Attachment* Skeleton_getAttachmentForSlotName (const Skeleton* this, const char* slotName, const char* attachmentName) { + int slotIndex = SkeletonData_findSlotIndex(this->data, slotName); + return Skeleton_getAttachmentForSlotIndex(this, slotIndex, attachmentName); +} + +Attachment* Skeleton_getAttachmentForSlotIndex (const Skeleton* this, int slotIndex, const char* attachmentName) { + if (slotIndex == -1) return 0; + if (this->skin) { + Attachment *attachment = Skin_getAttachment(this->skin, slotIndex, attachmentName); + if (attachment) return attachment; + } + if (this->data->defaultSkin) { + Attachment *attachment = Skin_getAttachment(this->data->defaultSkin, slotIndex, attachmentName); + if (attachment) return attachment; + } + return 0; +} + +int Skeleton_setAttachment (Skeleton* this, const char* slotName, const char* attachmentName) { + int i; + for (i = 0; i < this->slotCount; ++i) { + Slot *slot = this->slots[i]; + if (slot->data->name == slotName) { + Attachment* attachment = Skeleton_getAttachmentForSlotIndex(this, i, attachmentName); + if (!attachment) return 0; + Slot_setAttachment(slot, attachment); + return 1; + } + } + return 0; +} + +void Skeleton_update (Skeleton* this, float deltaTime) { + this->time += deltaTime; +} diff --git a/spine-c/src/spine/Skeleton.h b/spine-c/src/spine/Skeleton.h new file mode 100644 index 000000000..d817ccd4e --- /dev/null +++ b/spine-c/src/spine/Skeleton.h @@ -0,0 +1,71 @@ +#ifndef SPINE_SKELETON_H_ +#define SPINE_SKELETON_H_ + +#include +#include +#include + +#ifdef __cplusplus +namespace spine { +extern "C" { +#endif + +typedef struct Skeleton Skeleton; +struct Skeleton { + SkeletonData* const data; + + int boneCount; + Bone** bones; + + int slotCount; + Slot** slots; + Slot** drawOrder; + + Skin* const skin; + float r, g, b, a; + float time; + int flipX, flipY; + + void (*_dispose) (Skeleton* skeleton); +}; + +void Skeleton_init (Skeleton* skeleton, SkeletonData* data); +void Skeleton_dispose (Skeleton* skeleton); + +void Skeleton_updateWorldTransform (const Skeleton* skeleton); + +void Skeleton_setToBindPose (const Skeleton* skeleton); +void Skeleton_setBonesToBindPose (const Skeleton* skeleton); +void Skeleton_setSlotsToBindPose (const Skeleton* skeleton); + +Bone* Skeleton_getRootBone (const Skeleton* skeleton); +/** Returns 0 if the bone could not be found. */ +Bone* Skeleton_findBone (const Skeleton* skeleton, const char* boneName); +/** Returns -1 if the bone could not be found. */ +int Skeleton_findBoneIndex (const Skeleton* skeleton, const char* boneName); + +/** Returns 0 if the slot could not be found. */ +Slot* Skeleton_findSlot (const Skeleton* skeleton, const char* slotName); +/** Returns -1 if the slot could not be found. */ +int Skeleton_findSlotIndex (const Skeleton* skeleton, const char* slotName); + +/** Returns 0 if the skin could not be found. */ +int Skeleton_setSkinByName (Skeleton* skeleton, const char* skinName); +/** @param skin May be 0.*/ +void Skeleton_setSkin (Skeleton* skeleton, Skin* skin); + +/** Returns 0 if the slot or attachment could not be found. */ +Attachment* Skeleton_getAttachmentForSlotName (const Skeleton* skeleton, const char* slotName, const char* attachmentName); +/** Returns 0 if the slot or attachment could not be found. */ +Attachment* Skeleton_getAttachmentForSlotIndex (const Skeleton* this, int slotIndex, const char* attachmentName); +/** Returns 0 if the slot or attachment could not be found. */ +int Skeleton_setAttachment (Skeleton* skeleton, const char* slotName, const char* attachmentName); + +void Skeleton_update (Skeleton* this, float deltaTime); + +#ifdef __cplusplus +} +} +#endif + +#endif /* SPINE_SKELETON_H_*/ diff --git a/spine-c/src/spine/SkeletonData.c b/spine-c/src/spine/SkeletonData.c new file mode 100644 index 000000000..f49a2f685 --- /dev/null +++ b/spine-c/src/spine/SkeletonData.c @@ -0,0 +1,46 @@ +#include +#include + +SkeletonData* SkeletonData_create () { + SkeletonData* this = calloc(1, sizeof(SkeletonData)); + return this; +} + +void SkeletonData_dispose (SkeletonData* this) { + FREE(this) +} + +BoneData* SkeletonData_findBone (const SkeletonData* this, const char* boneName) { + int i; + for (i = 0; i < this->boneCount; ++i) + if (strcmp(this->bones[i]->name, boneName) == 0) return this->bones[i]; + return 0; +} + +int SkeletonData_findBoneIndex (const SkeletonData* this, const char* boneName) { + int i; + for (i = 0; i < this->boneCount; ++i) + if (strcmp(this->bones[i]->name, boneName) == 0) return i; + return 0; +} + +SlotData* SkeletonData_findSlot (const SkeletonData* this, const char* slotName) { + int i; + for (i = 0; i < this->slotCount; ++i) + if (strcmp(this->slots[i]->name, slotName) == 0) return this->slots[i]; + return 0; +} + +int SkeletonData_findSlotIndex (const SkeletonData* this, const char* slotName) { + int i; + for (i = 0; i < this->slotCount; ++i) + if (strcmp(this->slots[i]->name, slotName) == 0) return i; + return 0; +} + +Skin* SkeletonData_findSkin (const SkeletonData* this, const char* skinName) { + int i; + for (i = 0; i < this->skinCount; ++i) + if (strcmp(this->skins[i]->name, skinName) == 0) return this->skins[i]; + return 0; +} diff --git a/spine-c/src/spine/SkeletonData.h b/spine-c/src/spine/SkeletonData.h new file mode 100644 index 000000000..f9a60bfac --- /dev/null +++ b/spine-c/src/spine/SkeletonData.h @@ -0,0 +1,40 @@ +#ifndef SPINE_SKELETONDATA_H_ +#define SPINE_SKELETONDATA_H_ + +#include +#include +#include + +#ifdef __cplusplus +namespace spine {extern "C" { +#endif + +typedef struct { + int boneCount; + BoneData** bones; + + int slotCount; + SlotData** slots; + + int skinCount; + Skin** skins; + + Skin* defaultSkin; +} SkeletonData; + +SkeletonData* SkeletonData_create (); +void SkeletonData_dispose (SkeletonData* skeletonData); + +BoneData* SkeletonData_findBone (const SkeletonData* skeletonData, const char* boneName); +int SkeletonData_findBoneIndex (const SkeletonData* skeletonData, const char* boneName); + +SlotData* SkeletonData_findSlot (const SkeletonData* skeletonData, const char* slotName); +int SkeletonData_findSlotIndex (const SkeletonData* skeletonData, const char* slotName); + +Skin* SkeletonData_findSkin (const SkeletonData* skeletonData, const char* skinName); + +#ifdef __cplusplus +}} +#endif + +#endif /* SPINE_SKELETONDATA_H_ */ diff --git a/spine-c/src/spine/SkeletonJson.c b/spine-c/src/spine/SkeletonJson.c new file mode 100644 index 000000000..9f5a5f8a0 --- /dev/null +++ b/spine-c/src/spine/SkeletonJson.c @@ -0,0 +1,175 @@ +#include +#include +#include +#include +#include + +#include + +static float scale; +static const char* error; + +void SkeletonJson_setScale (float value) { + scale = value; +} + +void* SkeletonJson_setError (cJSON* root, const char* value1, const char* value2) { + FREE(error) + char message[256]; + strcpy(message, value1); + int length = strlen(value1); + if (value2) strncat(message + length, value2, 256 - length); + MALLOC_STR(error, message) + if (root) cJSON_dispose(root); + return 0; +} + +const char* SkeletonJson_getError () { + return error; +} + +static float toColor (const char* value, int index) { + if (strlen(value) != 8) return -1; + value += index * 2; + char digits[3]; + digits[0] = *value; + digits[1] = *(value + 1); + digits[2] = '\0'; + char* error; + int color = strtoul(digits, &error, 16); + if (*error != 0) return -1; + return color / (float)255; +} + +SkeletonData* SkeletonJson_readSkeletonDataFile (const char* path) { + char* data = readFile(path); + if (!data) return SkeletonJson_setError(0, "Unable to read file: ", path); + SkeletonData* skeletonData = SkeletonJson_readSkeletonData(data); + free(data); + return skeletonData; +} + +SkeletonData* SkeletonJson_readSkeletonData (const char* json) { + FREE(error) + error = 0; + + cJSON* root = cJSON_Parse(json); + if (!root) return SkeletonJson_setError(0, "Invalid JSON: ", cJSON_GetErrorPtr()); + + SkeletonData* skeletonData = SkeletonData_create(); + int i, ii, iii; + + cJSON* bones = cJSON_GetObjectItem(root, "bones"); + int boneCount = cJSON_GetArraySize(bones); + skeletonData->bones = malloc(sizeof(BoneData*) * boneCount); + for (i = 0; i < boneCount; ++i) { + cJSON* boneMap = cJSON_GetArrayItem(bones, i); + + const char* boneName = cJSON_GetObjectString(boneMap, "name", 0); + + BoneData* parent = 0; + const char* parentName = cJSON_GetObjectString(boneMap, "parent", 0); + if (parentName) { + parent = SkeletonData_findBone(skeletonData, parentName); + if (!parent) return SkeletonJson_setError(root, "Parent bone not found: ", parentName); + } + + BoneData* boneData = BoneData_create(boneName, parent); + boneData->length = cJSON_GetObjectFloat(boneMap, "parent", 0) * scale; + boneData->x = cJSON_GetObjectFloat(boneMap, "x", 0) * scale; + boneData->y = cJSON_GetObjectFloat(boneMap, "y", 0) * scale; + boneData->rotation = cJSON_GetObjectFloat(boneMap, "rotation", 0); + boneData->scaleX = cJSON_GetObjectFloat(boneMap, "scaleX", 1); + boneData->scaleY = cJSON_GetObjectFloat(boneMap, "scaleY", 1); + + skeletonData->bones[i] = boneData; + skeletonData->boneCount++; + } + + cJSON* slots = cJSON_GetObjectItem(root, "slots"); + if (slots) { + int slotCount = cJSON_GetArraySize(slots); + skeletonData->slots = malloc(sizeof(SlotData*) * slotCount); + for (i = 0; i < slotCount; ++i) { + cJSON* slotMap = cJSON_GetArrayItem(slots, i); + + const char* slotName = cJSON_GetObjectString(slotMap, "name", 0); + + const char* boneName = cJSON_GetObjectString(slotMap, "bone", 0); + BoneData* boneData = SkeletonData_findBone(skeletonData, boneName); + if (!boneData) return SkeletonJson_setError(root, "Slot bone not found: ", boneName); + + SlotData* slotData = SlotData_create(slotName, boneData); + + const char* color = cJSON_GetObjectString(slotMap, "color", 0); + if (color) { + slotData->r = toColor(color, 0); + slotData->g = toColor(color, 1); + slotData->b = toColor(color, 2); + slotData->a = toColor(color, 3); + } + + cJSON *attachmentItem = cJSON_GetObjectItem(slotMap, "attachment"); + if (attachmentItem) SlotData_setAttachmentName(slotData, attachmentItem->valuestring); + + skeletonData->slots[i] = slotData; + skeletonData->slotCount++; + } + } + + cJSON* skinsMap = cJSON_GetObjectItem(root, "skins"); + if (skinsMap) { + int skinCount = cJSON_GetArraySize(skinsMap); + skeletonData->skins = malloc(sizeof(Skin*) * skinCount); + for (i = 0; i < skinCount; ++i) { + cJSON* slotMap = cJSON_GetArrayItem(skinsMap, i); + const char* skinName = slotMap->name; + Skin *skin = Skin_create(skinName); + skeletonData->skins[i] = skin; + skeletonData->skinCount++; + if (strcmp(skinName, "default") == 0) skeletonData->defaultSkin = skin; + + int slotNameCount = cJSON_GetArraySize(slotMap); + for (ii = 0; ii < slotNameCount; ++ii) { + cJSON* attachmentsMap = cJSON_GetArrayItem(slotMap, ii); + const char* slotName = attachmentsMap->name; + int slotIndex = SkeletonData_findSlotIndex(skeletonData, slotName); + + int attachmentCount = cJSON_GetArraySize(attachmentsMap); + for (iii = 0; iii < attachmentCount; ++iii) { + cJSON* attachmentMap = cJSON_GetArrayItem(attachmentsMap, iii); + const char* attachmentName = attachmentMap->name; + + const char* typeString = cJSON_GetObjectString(attachmentMap, "type", "region"); + AttachmentType type; + if (strcmp(typeString, "region") == 0) + type = ATTACHMENT_REGION; + else if (strcmp(typeString, "regionSequence") == 0) + type = ATTACHMENT_REGION_SEQUENCE; + else + return SkeletonJson_setError(root, "Unknown attachment type: ", typeString); + + Attachment* attachment = Attachment_getAttachmentLoader()(type, + cJSON_GetObjectString(attachmentMap, "name", attachmentName)); + + if (type == ATTACHMENT_REGION || type == ATTACHMENT_REGION_SEQUENCE) { + RegionAttachment* regionAttachment = (RegionAttachment*)attachment; + regionAttachment->x = cJSON_GetObjectFloat(attachmentMap, "x", 0) * scale; + regionAttachment->y = cJSON_GetObjectFloat(attachmentMap, "y", 0) * scale; + regionAttachment->scaleX = cJSON_GetObjectFloat(attachmentMap, "scaleX", 1); + regionAttachment->scaleY = cJSON_GetObjectFloat(attachmentMap, "scaleY", 1); + regionAttachment->rotation = cJSON_GetObjectFloat(attachmentMap, "rotation", 0); + regionAttachment->width = cJSON_GetObjectFloat(attachmentMap, "width", 32) * scale; + regionAttachment->height = cJSON_GetObjectFloat(attachmentMap, "height", 32) * scale; + RegionAttachment_updateOffset(regionAttachment); + } + + Skin_addAttachment(skin, slotIndex, attachmentName, attachment); + } + } + } + } + + cJSON_dispose(root); + return skeletonData; +} diff --git a/spine-c/src/spine/SkeletonJson.h b/spine-c/src/spine/SkeletonJson.h new file mode 100644 index 000000000..b71ac6f5f --- /dev/null +++ b/spine-c/src/spine/SkeletonJson.h @@ -0,0 +1,26 @@ +#ifndef SPINE_SKELETONJSON_H_ +#define SPINE_SKELETONJSON_H_ + +#include +#include + +#ifdef __cplusplus +namespace spine { +extern "C" { +#endif + +void SkeletonJson_setScale (float scale); + +SkeletonData* SkeletonJson_readSkeletonData (const char* json); +SkeletonData* SkeletonJson_readSkeletonDataFile (const char* path); + +// Animation* readAnimation (char* json, const SkeletonData *skeletonData) const; + +const char* SkeletonJson_getError (); + +#ifdef __cplusplus +} +} +#endif + +#endif /* SPINE_SKELETONJSON_H_ */ diff --git a/spine-c/src/spine/Skin.c b/spine-c/src/spine/Skin.c new file mode 100644 index 000000000..250fbcd4e --- /dev/null +++ b/spine-c/src/spine/Skin.c @@ -0,0 +1,52 @@ +#include +#include + +SkinEntry* SkinEntry_create (int slotIndex, const char* name, Attachment* attachment) { + SkinEntry* entry = calloc(1, sizeof(SkinEntry)); + entry->slotIndex = slotIndex; + MALLOC_STR(entry->name, name) + entry->attachment = attachment; + return entry; +} + +void SkinEntry_dispose (SkinEntry* entry) { + if (entry->next) SkinEntry_dispose((SkinEntry*)entry->next); + Attachment_dispose(entry->attachment); + FREE(entry->name) + FREE(entry) +} + +// + +Skin* Skin_create (const char* name) { + Skin* this = calloc(1, sizeof(Skin)); + MALLOC_STR(this->name, name) + return this; +} + +void Skin_dispose (Skin* this) { + SkinEntry_dispose((SkinEntry*)this->entryList); + FREE(this->name) + FREE(this) +} + +void Skin_addAttachment (Skin* this, int slotIndex, const char* name, Attachment* attachment) { + SkinEntry* newEntry = SkinEntry_create(slotIndex, name, attachment); + SkinEntry* entry = (SkinEntry*)this->entryList; + if (!entry) + entry = newEntry; + else { + while (entry->next) + entry = (SkinEntry*)entry->next; + entry->next = newEntry; + } +} + +Attachment* Skin_getAttachment (const Skin* this, int slotIndex, const char* name) { + const SkinEntry* entry = this->entryList; + while (entry) { + if (entry->slotIndex == slotIndex && strcmp(entry->name, name) == 0) return entry->attachment; + entry = entry->next; + } + return 0; +} diff --git a/spine-c/src/spine/Skin.h b/spine-c/src/spine/Skin.h new file mode 100644 index 000000000..c1890bdb4 --- /dev/null +++ b/spine-c/src/spine/Skin.h @@ -0,0 +1,37 @@ +#ifndef SPINE_SKIN_H_ +#define SPINE_SKIN_H_ + +#include + +#ifdef __cplusplus +namespace spine { +extern "C" { +#endif + +typedef struct SkinEntry SkinEntry; +struct SkinEntry { + int slotIndex; + const char* name; + Attachment* attachment; + const SkinEntry* next; +}; + +typedef struct { + const char* const name; + const SkinEntry* const entryList; +} Skin; + +Skin* Skin_create (const char* name); +void Skin_dispose (Skin* skin); + +/** The Skin owns the attachment. */ +void Skin_addAttachment (Skin* skin, int slotIndex, const char* name, Attachment* attachment); +/** May return null. */ +Attachment* Skin_getAttachment (const Skin* skin, int slotIndex, const char* name); + +#ifdef __cplusplus +} +} +#endif + +#endif /* SPINE_SKIN_H_ */ diff --git a/spine-c/src/spine/Slot.c b/spine-c/src/spine/Slot.c new file mode 100644 index 000000000..692c78f75 --- /dev/null +++ b/spine-c/src/spine/Slot.c @@ -0,0 +1,58 @@ +#include +#include +#include + +typedef struct { + Slot slot; + float attachmentTime; +} Private; + +Slot* Slot_create (SlotData* data, Skeleton* skeleton, Bone* bone) { + Private* private = calloc(1, sizeof(Private)); + Slot* this = &private->slot; + CAST(SlotData*, this->data) = data; + CAST(Skeleton*, this->skeleton) = skeleton; + CAST(Bone*, this->bone) = bone; + this->r = 1; + this->g = 1; + this->b = 1; + this->a = 1; + return this; +} + +void Slot_dispose (Slot* this) { + FREE(this); +} + +/** @param attachment May be null. */ +void Slot_setAttachment (Slot* this, Attachment* attachment) { + CAST(Attachment*, this->attachment) = attachment; + ((Private*)this)->attachmentTime = this->skeleton->time; +} + +void Slot_setAttachmentTime (Slot* this, float time) { + ((Private*)this)->attachmentTime = this->skeleton->time - time; +} + +float Slot_getAttachmentTime (const Slot* this) { + return this->skeleton->time - ((Private*)this)->attachmentTime; +} + +void Slot_setToBindPose (Slot* this) { + this->r = this->data->r; + this->g = this->data->g; + this->b = this->data->b; + this->a = this->data->a; + + Attachment* attachment = 0; + if (this->data->attachmentName) { + int i; + for (i = 0; i < this->skeleton->data->slotCount; ++i) { + if (this->data == this->skeleton->data->slots[i]) { + attachment = Skeleton_getAttachmentForSlotIndex(this->skeleton, i, this->data->attachmentName); + break; + } + } + } + Slot_setAttachment(this, attachment); +} diff --git a/spine-c/src/spine/Slot.h b/spine-c/src/spine/Slot.h new file mode 100644 index 000000000..d6c50502f --- /dev/null +++ b/spine-c/src/spine/Slot.h @@ -0,0 +1,39 @@ +#ifndef SPINE_SLOT_H_ +#define SPINE_SLOT_H_ + +#include +#include +#include + +#ifdef __cplusplus +namespace spine { +extern "C" { +#endif + +struct Skeleton; + +typedef struct { + SlotData* const data; + struct Skeleton* const skeleton; + Bone* const bone; + float r, g, b, a; + Attachment* const attachment; +} Slot; + +Slot* Slot_create (SlotData* data, struct Skeleton* skeleton, Bone* bone); +void Slot_dispose (Slot* slot); + +/** @param attachment May be null. */ +void Slot_setAttachment (Slot* slot, Attachment* attachment); + +void Slot_setAttachmentTime (Slot* slot, float time); +float Slot_getAttachmentTime (const Slot* slot); + +void Slot_setToBindPose (Slot* slot); + +#ifdef __cplusplus +} +} +#endif + +#endif /* SPINE_SLOT_H_ */ diff --git a/spine-c/src/spine/SlotData.c b/spine-c/src/spine/SlotData.c new file mode 100644 index 000000000..cdc508986 --- /dev/null +++ b/spine-c/src/spine/SlotData.c @@ -0,0 +1,27 @@ +#include +#include + +SlotData* SlotData_create (const char* name, BoneData* boneData) { + SlotData* this = calloc(1, sizeof(SlotData)); + MALLOC_STR(this->name, name) + CAST(BoneData*, this->boneData) = boneData; + this->r = 1; + this->g = 1; + this->b = 1; + this->a = 1; + return this; +} + +void SlotData_dispose (SlotData* this) { + FREE(this->name); + FREE(this->attachmentName); + FREE(this); +} + +void SlotData_setAttachmentName (SlotData* this, const char* attachmentName) { + FREE(this->attachmentName); + if (attachmentName) + MALLOC_STR(this->attachmentName, attachmentName) + else + CAST(char*, this->attachmentName) = 0; +} diff --git a/spine-c/src/spine/SlotData.h b/spine-c/src/spine/SlotData.h new file mode 100644 index 000000000..34543efca --- /dev/null +++ b/spine-c/src/spine/SlotData.h @@ -0,0 +1,29 @@ +#ifndef SPINE_SLOTDATA_H_ +#define SPINE_SLOTDATA_H_ + +#include + +#ifdef __cplusplus +namespace spine { +extern "C" { +#endif + +typedef struct { + const char* const name; + const BoneData* const boneData; + const char* const attachmentName; + float r, g, b, a; +} SlotData; + +SlotData* SlotData_create (const char* name, BoneData* boneData); +void SlotData_dispose (SlotData* slotData); + +/** @param attachmentName May be zero. */ +void SlotData_setAttachmentName (SlotData* this, const char* attachmentName); + +#ifdef __cplusplus +} +} +#endif + +#endif /* SPINE_SLOTDATA_H_ */ diff --git a/spine-c/src/spine/cJSON.c b/spine-c/src/spine/cJSON.c new file mode 100644 index 000000000..7e42c047c --- /dev/null +++ b/spine-c/src/spine/cJSON.c @@ -0,0 +1,391 @@ +/* + Copyright (c) 2009 Dave Gamble + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + */ + +/* cJSON */ +/* JSON parser in C. */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static const char* ep; + +const char* cJSON_GetErrorPtr (void) { + return ep; +} + +static int cJSON_strcasecmp (const char* s1, const char* s2) { + if (!s1) return (s1 == s2) ? 0 : 1; + if (!s2) return 1; + for (; tolower(*s1) == tolower(*s2); ++s1, ++s2) + if (*s1 == 0) return 0; + return tolower(*(const unsigned char*)s1) - tolower(*(const unsigned char*)s2); +} + +/* Internal constructor. */ +static cJSON *cJSON_create_Item (void) { + cJSON* node = (cJSON*)malloc(sizeof(cJSON)); + if (node) memset(node, 0, sizeof(cJSON)); + return node; +} + +/* Delete a cJSON structure. */ +void cJSON_dispose (cJSON *c) { + cJSON *next; + while (c) { + next = c->next; + if (!(c->type & cJSON_IsReference) && c->child) cJSON_dispose(c->child); + if (!(c->type & cJSON_IsReference) && c->valuestring) free((char*)c->valuestring); + if (c->name) free((char*)c->name); + free(c); + c = next; + } +} + +/* Parse the input text to generate a number, and populate the result into item. */ +static const char* parse_number (cJSON *item, const char* num) { + float n = 0, sign = 1, scale = 0; + int subscale = 0, signsubscale = 1; + + /* Could use sscanf for this? */ + if (*num == '-') sign = -1, num++; /* Has sign? */ + if (*num == '0') num++; /* is zero */ + if (*num >= '1' && *num <= '9') do + n = (n * 10.0) + (*num++ - '0'); + while (*num >= '0' && *num <= '9'); /* Number? */ + if (*num == '.' && num[1] >= '0' && num[1] <= '9') { + num++; + do + n = (n * 10.0) + (*num++ - '0'), scale--; + while (*num >= '0' && *num <= '9'); + } /* Fractional part? */ + if (*num == 'e' || *num == 'E') /* Exponent? */ + { + num++; + if (*num == '+') + num++; + else if (*num == '-') signsubscale = -1, num++; /* With sign? */ + while (*num >= '0' && *num <= '9') + subscale = (subscale * 10) + (*num++ - '0'); /* Number? */ + } + + n = sign * n * pow(10.0, (scale + subscale * signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */ + + item->valuefloat = n; + item->valueint = (int)n; + item->type = cJSON_Number; + return num; +} + +/* Parse the input text into an unescaped cstring, and populate item. */ +static const unsigned char firstByteMark[7] = {0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC}; +static const char* parse_string (cJSON *item, const char* str) { + const char* ptr = str + 1; + char* ptr2; + char* out; + int len = 0; + unsigned uc, uc2; + if (*str != '\"') { + ep = str; + return 0; + } /* not a string! */ + + while (*ptr != '\"' && *ptr && ++len) + if (*ptr++ == '\\') ptr++; /* Skip escaped quotes. */ + + out = (char*)malloc(len + 1); /* This is how long we need for the string, roughly. */ + if (!out) return 0; + + ptr = str + 1; + ptr2 = out; + while (*ptr != '\"' && *ptr) { + if (*ptr != '\\') + *ptr2++ = *ptr++; + else { + ptr++; + switch (*ptr) { + case 'b': + *ptr2++ = '\b'; + break; + case 'f': + *ptr2++ = '\f'; + break; + case 'n': + *ptr2++ = '\n'; + break; + case 'r': + *ptr2++ = '\r'; + break; + case 't': + *ptr2++ = '\t'; + break; + case 'u': /* transcode utf16 to utf8. */ + sscanf(ptr + 1, "%4x", &uc); + ptr += 4; /* get the unicode char. */ + + if ((uc >= 0xDC00 && uc <= 0xDFFF) || uc == 0) break; /* check for invalid. */ + + if (uc >= 0xD800 && uc <= 0xDBFF) /* UTF16 surrogate pairs. */ + { + if (ptr[1] != '\\' || ptr[2] != 'u') break; /* missing second-half of surrogate. */ + sscanf(ptr + 3, "%4x", &uc2); + ptr += 6; + if (uc2 < 0xDC00 || uc2 > 0xDFFF) break; /* invalid second-half of surrogate. */ + uc = 0x10000 + (((uc & 0x3FF) << 10) | (uc2 & 0x3FF)); + } + + len = 4; + if (uc < 0x80) + len = 1; + else if (uc < 0x800) + len = 2; + else if (uc < 0x10000) len = 3; + ptr2 += len; + + switch (len) { + case 4: + *--ptr2 = ((uc | 0x80) & 0xBF); + uc >>= 6; + case 3: + *--ptr2 = ((uc | 0x80) & 0xBF); + uc >>= 6; + case 2: + *--ptr2 = ((uc | 0x80) & 0xBF); + uc >>= 6; + case 1: + *--ptr2 = (uc | firstByteMark[len]); + } + ptr2 += len; + break; + default: + *ptr2++ = *ptr; + break; + } + ptr++; + } + } + *ptr2 = 0; + if (*ptr == '\"') ptr++; + item->valuestring = out; + item->type = cJSON_String; + return ptr; +} + +/* Predeclare these prototypes. */ +static const char* parse_value (cJSON *item, const char* value); +static const char* parse_array (cJSON *item, const char* value); +static const char* parse_object (cJSON *item, const char* value); + +/* Utility to jump whitespace and cr/lf */ +static const char* skip (const char* in) { + while (in && *in && (unsigned char)*in <= 32) + in++; + return in; +} + +/* Parse an object - create a new root, and populate. */ +cJSON *cJSON_ParseWithOpts (const char* value, const char* *return_parse_end, int require_null_terminated) { + const char* end = 0; + cJSON *c = cJSON_create_Item(); + ep = 0; + if (!c) return 0; /* memory fail */ + + end = parse_value(c, skip(value)); + if (!end) { + cJSON_dispose(c); + return 0; + } /* parse failure. ep is set. */ + + /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ + if (require_null_terminated) { + end = skip(end); + if (*end) { + cJSON_dispose(c); + ep = end; + return 0; + } + } + if (return_parse_end) *return_parse_end = end; + return c; +} + +/* Default options for cJSON_Parse */ +cJSON *cJSON_Parse (const char* value) { + return cJSON_ParseWithOpts(value, 0, 0); +} + +/* Parser core - when encountering text, process appropriately. */ +static const char* parse_value (cJSON *item, const char* value) { + if (!value) return 0; /* Fail on null. */ + if (!strncmp(value, "null", 4)) { + item->type = cJSON_NULL; + return value + 4; + } + if (!strncmp(value, "false", 5)) { + item->type = cJSON_False; + return value + 5; + } + if (!strncmp(value, "true", 4)) { + item->type = cJSON_True; + item->valueint = 1; + return value + 4; + } + if (*value == '\"') { + return parse_string(item, value); + } + if (*value == '-' || (*value >= '0' && *value <= '9')) { + return parse_number(item, value); + } + if (*value == '[') { + return parse_array(item, value); + } + if (*value == '{') { + return parse_object(item, value); + } + + ep = value; + return 0; /* failure. */ +} + +/* Build an array from input text. */ +static const char* parse_array (cJSON *item, const char* value) { + cJSON *child; + if (*value != '[') { + ep = value; + return 0; + } /* not an array! */ + + item->type = cJSON_Array; + value = skip(value + 1); + if (*value == ']') return value + 1; /* empty array. */ + + item->child = child = cJSON_create_Item(); + if (!item->child) return 0; /* memory fail */ + value = skip(parse_value(child, skip(value))); /* skip any spacing, get the value. */ + if (!value) return 0; + + while (*value == ',') { + cJSON *new_item; + if (!(new_item = cJSON_create_Item())) return 0; /* memory fail */ + child->next = new_item; + new_item->prev = child; + child = new_item; + value = skip(parse_value(child, skip(value + 1))); + if (!value) return 0; /* memory fail */ + } + + if (*value == ']') return value + 1; /* end of array */ + ep = value; + return 0; /* malformed. */ +} + +/* Build an object from the text. */ +static const char* parse_object (cJSON *item, const char* value) { + cJSON *child; + if (*value != '{') { + ep = value; + return 0; + } /* not an object! */ + + item->type = cJSON_Object; + value = skip(value + 1); + if (*value == '}') return value + 1; /* empty array. */ + + item->child = child = cJSON_create_Item(); + if (!item->child) return 0; + value = skip(parse_string(child, skip(value))); + if (!value) return 0; + child->name = child->valuestring; + child->valuestring = 0; + if (*value != ':') { + ep = value; + return 0; + } /* fail! */ + value = skip(parse_value(child, skip(value + 1))); /* skip any spacing, get the value. */ + if (!value) return 0; + + while (*value == ',') { + cJSON *new_item; + if (!(new_item = cJSON_create_Item())) return 0; /* memory fail */ + child->next = new_item; + new_item->prev = child; + child = new_item; + value = skip(parse_string(child, skip(value + 1))); + if (!value) return 0; + child->name = child->valuestring; + child->valuestring = 0; + if (*value != ':') { + ep = value; + return 0; + } /* fail! */ + value = skip(parse_value(child, skip(value + 1))); /* skip any spacing, get the value. */ + if (!value) return 0; + } + + if (*value == '}') return value + 1; /* end of array */ + ep = value; + return 0; /* malformed. */ +} + +/* Get Array size/item / object item. */ +int cJSON_GetArraySize (cJSON *array) { + cJSON *c = array->child; + int i = 0; + while (c) + i++, c = c->next; + return i; +} + +cJSON *cJSON_GetArrayItem (cJSON *array, int item) { + cJSON *c = array->child; + while (c && item > 0) + item--, c = c->next; + return c; +} + +cJSON *cJSON_GetObjectItem (cJSON *object, const char* string) { + cJSON *c = object->child; + while (c && cJSON_strcasecmp(c->name, string)) + c = c->next; + return c; +} + +const char* cJSON_GetObjectString (cJSON* object, const char* name, const char* defaultValue) { + object = cJSON_GetObjectItem(object, name); + if (object) return object->valuestring; + return defaultValue; +} + +float cJSON_GetObjectFloat (cJSON* value, const char* name, float defaultValue) { + value = cJSON_GetObjectItem(value, name); + return value ? value->valuefloat : defaultValue; +} + +int cJSON_GetObjectInt (cJSON* value, const char* name, int defaultValue) { + value = cJSON_GetObjectItem(value, name); + return value ? value->valuefloat : defaultValue; +} diff --git a/spine-c/src/spine/cJSON.h b/spine-c/src/spine/cJSON.h new file mode 100644 index 000000000..a76e7e456 --- /dev/null +++ b/spine-c/src/spine/cJSON.h @@ -0,0 +1,84 @@ +/* + Copyright (c) 2009 Dave Gamble + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + */ + +/* Esoteric Software: Removed everything except parsing, added cJSON_GetObject*, formatted, double to float. */ + +#ifndef cJSON__h +#define cJSON__h + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* cJSON Types: */ +#define cJSON_False 0 +#define cJSON_True 1 +#define cJSON_NULL 2 +#define cJSON_Number 3 +#define cJSON_String 4 +#define cJSON_Array 5 +#define cJSON_Object 6 + +#define cJSON_IsReference 256 + +/* The cJSON structure: */ +typedef struct cJSON { + struct cJSON *next, *prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ + struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ + + int type; /* The type of the item, as above. */ + + const char* valuestring; /* The item's string, if type==cJSON_String */ + int valueint; /* The item's number, if type==cJSON_Number */ + float valuefloat; /* The item's number, if type==cJSON_Number */ + + const char* name; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ +} cJSON; + +/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_dispose when finished. */ +extern cJSON *cJSON_Parse (const char* value); + +/* Delete a cJSON entity and all subentities. */ +extern void cJSON_dispose (cJSON *c); + +/* Returns the number of items in an array (or object). */ +extern int cJSON_GetArraySize (cJSON *array); + +/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */ +extern cJSON *cJSON_GetArrayItem (cJSON *array, int item); + +/* Get item "string" from object. Case insensitive. */ +extern cJSON *cJSON_GetObjectItem (cJSON *object, const char* string); +extern const char* cJSON_GetObjectString (cJSON* object, const char* name, const char* defaultValue); +extern float cJSON_GetObjectFloat (cJSON* value, const char* name, float defaultValue); +extern int cJSON_GetObjectInt (cJSON* value, const char* name, int defaultValue); + +/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ +extern const char* cJSON_GetErrorPtr (void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/spine-c/src/spine/spine.h b/spine-c/src/spine/spine.h new file mode 100644 index 000000000..08cfa5661 --- /dev/null +++ b/spine-c/src/spine/spine.h @@ -0,0 +1,15 @@ +#ifndef SPINE_SPINE_H_ +#define SPINE_SPINE_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif /* SPINE_SPINE_H_ */ diff --git a/spine-c/src/spine/util.c b/spine-c/src/spine/util.c new file mode 100644 index 000000000..a58161c4d --- /dev/null +++ b/spine-c/src/spine/util.c @@ -0,0 +1,17 @@ +#include + +char* readFile (const char* path) { + FILE *file = fopen(path, "rb"); + if (!file) return 0; + + fseek(file, 0, SEEK_END); + long length = ftell(file); + fseek(file, 0, SEEK_SET); + + char* data = (char*)malloc(sizeof(char) * length + 1); + fread(data, sizeof(char), length, file); + fclose(file); + data[length] = '\0'; + + return data; +} diff --git a/spine-c/src/spine/util.h b/spine-c/src/spine/util.h new file mode 100644 index 000000000..1435d5170 --- /dev/null +++ b/spine-c/src/spine/util.h @@ -0,0 +1,17 @@ +#ifndef SPINE_UTIL_H_ +#define SPINE_UTIL_H_ + +#include +#include +#include + +/** Used to cast away const on an lvalue. */ +#define CAST(TYPE,VALUE) *(TYPE*)&VALUE + +#define MALLOC_STR(TO,FROM) strcpy(CAST(char*, TO) = malloc(strlen(FROM)), FROM); + +#define FREE(E) free((void*)E); + +char* readFile (const char* path); + +#endif /* SPINE_UTIL_H_ */