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 000000000..b8b493dfd Binary files /dev/null and b/spine-c/data/spineboy.png differ 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_ */