Эх сурвалжийг харах

Merge remote-tracking branch 'upstream/master'

Conflicts:
	spine-libgdx/.classpath
	spine-libgdx/test/com/esotericsoftware/spine/MixTest.java
	spine-libgdx/test/com/esotericsoftware/spine/SkeletonTest.java

*First Merge attempt.. may Gawd help us all.  -Disk1of5.
Disk1of5 12 жил өмнө
parent
commit
3da5dcef69
39 өөрчлөгдсөн 215 нэмэгдсэн , 220 устгасан
  1. 4 0
      spine-corona/spine/Animation.lua
  2. 1 1
      spine-corona/spine/Skeleton.lua
  3. 1 1
      spine-corona/spine/Slot.lua
  4. 1 1
      spine-cpp/.cproject
  5. 0 22
      spine-cpp/data/spineboy-walk.json
  6. 2 4
      spine-cpp/includes/spine-sfml/Atlas.h
  7. 1 1
      spine-cpp/includes/spine-sfml/Skeleton.h
  8. 1 0
      spine-cpp/includes/spine-sfml/SkeletonJson.h
  9. 23 22
      spine-cpp/includes/spine/Animation.h
  10. 2 3
      spine-cpp/includes/spine/BaseAtlas.h
  11. 2 2
      spine-cpp/includes/spine/BaseAttachmentLoader.h
  12. 5 3
      spine-cpp/includes/spine/BaseSkeleton.h
  13. 2 1
      spine-cpp/includes/spine/BaseSkeletonJson.h
  14. 1 0
      spine-cpp/includes/spine/Bone.h
  15. 2 2
      spine-cpp/includes/spine/BoneData.h
  16. 5 1
      spine-cpp/includes/spine/SkeletonData.h
  17. 3 2
      spine-cpp/includes/spine/Skin.h
  18. 1 0
      spine-cpp/includes/spine/Slot.h
  19. 2 18
      spine-cpp/includes/spine/SlotData.h
  20. 7 1
      spine-cpp/src/spine-sfml/Atlas.cpp
  21. 2 2
      spine-cpp/src/spine-sfml/RegionAttachment.cpp
  22. 2 2
      spine-cpp/src/spine-sfml/SkeletonJson.cpp
  23. 21 28
      spine-cpp/src/spine/Animation.cpp
  24. 6 1
      spine-cpp/src/spine/BaseAtlas.cpp
  25. 2 2
      spine-cpp/src/spine/BaseRegionAttachment.cpp
  26. 8 7
      spine-cpp/src/spine/BaseSkeleton.cpp
  27. 23 21
      spine-cpp/src/spine/BaseSkeletonJson.cpp
  28. 1 1
      spine-cpp/src/spine/Bone.cpp
  29. 6 6
      spine-cpp/src/spine/SkeletonData.cpp
  30. 6 6
      spine-cpp/src/spine/Skin.cpp
  31. 3 2
      spine-cpp/src/spine/Slot.cpp
  32. 25 0
      spine-cpp/src/spine/SlotData.cpp
  33. 6 7
      spine-libgdx/.classpath
  34. 33 38
      spine-libgdx/spine-libgdx.iws
  35. 1 0
      spine-libgdx/src/com/esotericsoftware/spine/AttachmentLoader.java
  36. 1 1
      spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java
  37. 1 1
      spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java
  38. 1 5
      spine-libgdx/test/com/esotericsoftware/spine/MixTest.java
  39. 1 5
      spine-libgdx/test/com/esotericsoftware/spine/SkeletonTest.java

+ 4 - 0
spine-corona/spine/Animation.lua

@@ -138,6 +138,7 @@ function Animation.RotateTimeline.new ()
 
 	local self = Animation.CurveTimeline.new()
 	self.frames = {}
+	self.boneIndex = -1
 
 	function self:getDuration ()
 		return self.frames[#self.frames - 1]
@@ -207,6 +208,7 @@ function Animation.TranslateTimeline.new ()
 
 	local self = Animation.CurveTimeline.new()
 	self.frames = {}
+	self.boneIndex = -1
 
 	function self:getDuration ()
 		return self.frames[#self.frames - 2]
@@ -297,6 +299,7 @@ function Animation.ColorTimeline.new ()
 
 	local self = Animation.CurveTimeline.new()
 	self.frames = {}
+	self.slotIndex = -1
 
 	function self:getDuration ()
 		return self.frames[#self.frames - 4]
@@ -360,6 +363,7 @@ function Animation.AttachmentTimeline.new ()
 	local self = Animation.CurveTimeline.new()
 	self.frames = {}
 	self.attachmentNames = {}
+	self.slotName = nil
 
 	function self:getDuration ()
 		return self.frames[#self.frames]

+ 1 - 1
spine-corona/spine/Skeleton.lua

@@ -143,11 +143,11 @@ function Skeleton.new (skeletonData, group)
 		if not attachmentName then error("attachmentName cannot be nil.", 2) end
 		local slotIndex = self.data:findSlotIndex(slotName)
 		if slotIndex == -1 then error("Slot not found: " .. slotName, 2) end
+		if self.skin then return self.skin:getAttachment(slotIndex, attachmentName) end
 		if self.data.defaultSkin then
 			local attachment = self.data.defaultSkin:getAttachment(slotIndex, attachmentName)
 			if attachment then return attachment end
 		end
-		if self.skin then return self.skin:getAttachment(slotIndex, attachmentName) end
 		return nil
 	end
 

+ 1 - 1
spine-corona/spine/Slot.lua

@@ -47,7 +47,7 @@ function Slot.new (slotData, skeleton, bone)
 		self:setAttachment(attachment)
 	end
 
-	self:setColor(255, 255, 255, 255)
+	self:setToBindPose()
 
 	return self
 end

+ 1 - 1
spine-cpp/.cproject

@@ -31,7 +31,7 @@
 									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/includes}&quot;"/>
 									<listOptionValue builtIn="false" value="&quot;C:\Users\Nate\Desktop\SFML-2.0-rc\include&quot;"/>
 								</option>
-								<option id="gnu.cpp.compiler.option.warnings.allwarn.2053349441" name="All warnings (-Wall)" superClass="gnu.cpp.compiler.option.warnings.allwarn" value="false" valueType="boolean"/>
+								<option id="gnu.cpp.compiler.option.warnings.allwarn.2053349441" name="All warnings (-Wall)" superClass="gnu.cpp.compiler.option.warnings.allwarn" value="true" valueType="boolean"/>
 								<option id="gnu.cpp.compiler.option.preprocessor.def.1463772359" name="Defined symbols (-D)" superClass="gnu.cpp.compiler.option.preprocessor.def"/>
 								<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.1445618618" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
 							</tool>

+ 0 - 22
spine-cpp/data/spineboy-walk.json

@@ -274,27 +274,5 @@
 			{ "time": 1.0666, "angle": 3.6 }
 		]
 	}
-},
-"slots": {
-	"torso": {
-		"attachment": [
-			{ "time": 0.4333, "name": null },
-			{ "time": 0.8, "name": "torso" }
-		]
-	},
-	"head": {
-		"color": [
-			{ "time": 0.1666, "color": "ffffffff" },
-			{ "time": 0.9333, "color": "ff0f00c1" }
-		]
-	},
-	"eyes": {
-		"attachment": [
-			{ "time": 0.2, "name": "eyes-closed" },
-			{ "time": 0.3, "name": "eyes" },
-			{ "time": 0.7, "name": "eyes-closed" },
-			{ "time": 0.8333, "name": "eyes" }
-		]
-	}
 }
 }

+ 2 - 4
spine-cpp/includes/spine-sfml/Atlas.h

@@ -8,9 +8,7 @@ namespace spine {
 
 class AtlasPage: public BaseAtlasPage {
 public:
-	~AtlasPage(){
-		delete texture;
-	}
+	~AtlasPage ();
 
 	sf::Texture *texture;
 };
@@ -34,7 +32,7 @@ public:
 	AtlasRegion* findRegion (const std::string &name);
 
 private:
-	virtual BaseAtlasPage* newAtlasPage (std::string name);
+	virtual BaseAtlasPage* newAtlasPage (const std::string &name);
 	virtual BaseAtlasRegion* newAtlasRegion (BaseAtlasPage* page);
 };
 

+ 1 - 1
spine-cpp/includes/spine-sfml/Skeleton.h

@@ -9,7 +9,7 @@ namespace spine {
 class Skeleton: public BaseSkeleton, public sf::Drawable {
 public:
 	sf::VertexArray vertexArray;
-	sf::Texture *texture; // BOZO - This is ugly. Support multiple textures?
+	sf::Texture *texture; // This is a bit ugly and means all region attachments must use the same textures.
 
 	Skeleton (SkeletonData *skeletonData);
 

+ 1 - 0
spine-cpp/includes/spine-sfml/SkeletonJson.h

@@ -10,6 +10,7 @@ class Atlas;
 class SkeletonJson: public BaseSkeletonJson {
 public:
 	SkeletonJson (Atlas *atlas);
+	/** The SkeletonJson owns the attachmentLoader */
 	SkeletonJson (BaseAttachmentLoader *attachmentLoader);
 };
 

+ 23 - 22
spine-cpp/includes/spine/Animation.h

@@ -15,10 +15,10 @@ public:
 	float duration;
 
 	Animation (const std::vector<Timeline*> &timelines, float duration);
-  ~Animation();
+	~Animation ();
 
-	void apply (BaseSkeleton *skeleton, float time, bool loop);
-	void mix (BaseSkeleton *skeleton, float time, bool loop, float alpha);
+	void apply (BaseSkeleton *skeleton, float time, bool loop) const;
+	void mix (BaseSkeleton *skeleton, float time, bool loop, float alpha) const;
 };
 
 //
@@ -28,11 +28,11 @@ public:
 	virtual ~Timeline () {
 	}
 
-	virtual float getDuration () = 0;
+	virtual float getDuration () const = 0;
 
-	virtual int getKeyframeCount () = 0;
+	virtual int getKeyframeCount () const = 0;
 
-	virtual void apply (BaseSkeleton *skeleton, float time, float alpha) = 0;
+	virtual void apply (BaseSkeleton *skeleton, float time, float alpha) const = 0;
 };
 
 //
@@ -53,7 +53,7 @@ public:
 	 * the difference between the keyframe's values. */
 	void setCurve (int keyframeIndex, float cx1, float cy1, float cx2, float cy2);
 
-	float getCurvePercent (int keyframeIndex, float percent);
+	float getCurvePercent (int keyframeIndex, float percent) const;
 };
 
 //
@@ -67,9 +67,9 @@ public:
 	RotateTimeline (int keyframeCount);
 	virtual ~RotateTimeline ();
 
-	virtual float getDuration ();
-	virtual int getKeyframeCount ();
-	virtual void apply (BaseSkeleton *skeleton, float time, float alpha);
+	virtual float getDuration () const;
+	virtual int getKeyframeCount () const;
+	virtual void apply (BaseSkeleton *skeleton, float time, float alpha) const;
 
 	void setKeyframe (int keyframeIndex, float time, float value);
 };
@@ -85,9 +85,9 @@ public:
 	TranslateTimeline (int keyframeCount);
 	virtual ~TranslateTimeline ();
 
-	virtual float getDuration ();
-	virtual int getKeyframeCount ();
-	virtual void apply (BaseSkeleton *skeleton, float time, float alpha);
+	virtual float getDuration () const;
+	virtual int getKeyframeCount () const;
+	virtual void apply (BaseSkeleton *skeleton, float time, float alpha) const;
 
 	void setKeyframe (int keyframeIndex, float time, float x, float y);
 };
@@ -98,7 +98,7 @@ class ScaleTimeline: public TranslateTimeline {
 public:
 	ScaleTimeline (int keyframeCount);
 
-	virtual void apply (BaseSkeleton *skeleton, float time, float alpha);
+	virtual void apply (BaseSkeleton *skeleton, float time, float alpha) const;
 };
 
 //
@@ -112,9 +112,9 @@ public:
 	ColorTimeline (int keyframeCount);
 	virtual ~ColorTimeline ();
 
-	virtual float getDuration ();
-	virtual int getKeyframeCount ();
-	virtual void apply (BaseSkeleton *skeleton, float time, float alpha);
+	virtual float getDuration () const;
+	virtual int getKeyframeCount () const;
+	virtual void apply (BaseSkeleton *skeleton, float time, float alpha) const;
 
 	void setKeyframe (int keyframeIndex, float time, float r, float g, float b, float a);
 };
@@ -131,12 +131,13 @@ public:
 	AttachmentTimeline (int keyframeCount);
 	virtual ~AttachmentTimeline ();
 
-	virtual float getDuration ();
-	virtual int getKeyframeCount ();
-	virtual void apply (BaseSkeleton *skeleton, float time, float alpha);
+	virtual float getDuration () const;
+	virtual int getKeyframeCount () const;
+	virtual void apply (BaseSkeleton *skeleton, float time, float alpha) const;
 
-	/** @param attachmentName Pass an empty string to clear the image for a slot. */
-	void setKeyframe (int keyframeIndex, float time, const std::string &attachmentName);
+	/** The AttachmentTimeline owns the attachmentName.
+	 * @param attachmentName May be null to clear the image for a slot. */
+	void setKeyframe (int keyframeIndex, float time, std::string *attachmentName);
 };
 
 } /* namespace spine */

+ 2 - 3
spine-cpp/includes/spine/BaseAtlas.h

@@ -4,7 +4,6 @@
 #include <istream>
 #include <string>
 #include <vector>
-#include <map>
 
 namespace spine {
 
@@ -26,7 +25,7 @@ public:
 	virtual BaseAtlasRegion* findRegion (const std::string &name);
 
 private:
-	virtual BaseAtlasPage* newAtlasPage (std::string name) = 0;
+	virtual BaseAtlasPage* newAtlasPage (const std::string &name) = 0;
 	virtual BaseAtlasRegion* newAtlasRegion (BaseAtlasPage *page) = 0;
 };
 
@@ -71,7 +70,7 @@ public:
 	int *splits;
 	int *pads;
 
-  BaseAtlasRegion() : splits(0), pads(0) {}
+	BaseAtlasRegion ();
 	virtual ~BaseAtlasRegion ();
 };
 

+ 2 - 2
spine-cpp/includes/spine/BaseAttachmentLoader.h

@@ -1,10 +1,10 @@
 #ifndef SPINE_BASEATTACHMENTLOADER_H_
 #define SPINE_BASEATTACHMENTLOADER_H_
 
-#include <spine/Attachment.h>
-
 namespace spine {
 
+class Attachment;
+
 enum AttachmentType {
 	region, regionSequence
 };

+ 5 - 3
spine-cpp/includes/spine/BaseSkeleton.h

@@ -23,6 +23,7 @@ public:
 	float time;
 	bool flipX, flipY;
 
+	/** The BaseSkeleton owns the SkeletonData. */
 	BaseSkeleton (SkeletonData *data);
 	virtual ~BaseSkeleton ();
 
@@ -40,10 +41,11 @@ public:
 	int findSlotIndex (const std::string &slotName) const;
 
 	void setSkin (const std::string &skinName);
-	void setSkin (Skin *newSkin);
+	/** @param skin May be null. */
+	void setSkin (Skin *skin);
 
-	Attachment* getAttachment (const std::string &slotName, const std::string &attachmentName);
-	Attachment* getAttachment (int slotIndex, const std::string &attachmentName);
+	Attachment* getAttachment (const std::string &slotName, const std::string &attachmentName) const;
+	Attachment* getAttachment (int slotIndex, const std::string &attachmentName) const;
 	void setAttachment (const std::string &slotName, const std::string &attachmentName);
 };
 

+ 2 - 1
spine-cpp/includes/spine/BaseSkeletonJson.h

@@ -13,8 +13,9 @@ class BaseSkeletonJson {
 public:
 	BaseAttachmentLoader *attachmentLoader;
 	float scale;
-	bool flipY;
+	bool yDown;
 
+	/** The BaseSkeletonJson owns the attachmentLoader. */
 	BaseSkeletonJson (BaseAttachmentLoader *attachmentLoader);
 	virtual ~BaseSkeletonJson ();
 

+ 1 - 0
spine-cpp/includes/spine/Bone.h

@@ -8,6 +8,7 @@ class BoneData;
 class Bone {
 public:
 	BoneData *data;
+	/** May be null. */
 	Bone *parent;
 	float x, y;
 	float rotation;

+ 2 - 2
spine-cpp/includes/spine/BoneData.h

@@ -13,7 +13,7 @@ public:
 	float x, y;
 	float rotation;
 	float scaleX, scaleY;
-	float flipY;
+	float yDown;
 
 	BoneData (const std::string &name) :
 					name(name),
@@ -24,7 +24,7 @@ public:
 					rotation(0),
 					scaleX(1),
 					scaleY(1),
-					flipY(false) {
+					yDown(false) {
 	}
 };
 

+ 5 - 1
spine-cpp/includes/spine/SkeletonData.h

@@ -12,9 +12,13 @@ class Skin;
 
 class SkeletonData {
 public:
+	/** The SkeletonData owns the bones. */
 	std::vector<BoneData*> bones;
+	/** The SkeletonData owns the slots. */
 	std::vector<SlotData*> slots;
+	/** The SkeletonData owns the skins. */
 	std::vector<Skin*> skins;
+	/** May be null. */
 	Skin *defaultSkin;
 
 	SkeletonData ();
@@ -26,7 +30,7 @@ public:
 	SlotData* findSlot (const std::string &slotName) const;
 	int findSlotIndex (const std::string &slotName) const;
 
-	Skin* findSkin (const std::string &skinName);
+	Skin* findSkin (const std::string &skinName) const;
 };
 
 } /* namespace spine */

+ 3 - 2
spine-cpp/includes/spine/Skin.h

@@ -3,11 +3,11 @@
 
 #include <string>
 #include <map>
-#include <spine/Attachment.h>
 
 namespace spine {
 
 class BaseSkeleton;
+class Attachment;
 
 class Skin {
 	friend class BaseSkeleton;
@@ -31,8 +31,9 @@ public:
 	std::string name;
 
 	Skin (const std::string &name);
-  ~Skin();
+	~Skin ();
 
+	/** The Skin owns the attachment. */
 	void addAttachment (int slotIndex, const std::string &name, Attachment *attachment);
 
 	Attachment* getAttachment (int slotIndex, const std::string &name);

+ 1 - 0
spine-cpp/includes/spine/Slot.h

@@ -25,6 +25,7 @@ public:
 
 	Slot (SlotData *data, BaseSkeleton *skeleton, Bone *bone);
 
+	/** @param attachment May be null. */
 	void setAttachment (Attachment *attachment);
 
 	void setAttachmentTime (float time);

+ 2 - 18
spine-cpp/includes/spine/SlotData.h

@@ -2,7 +2,6 @@
 #define SPINE_SLOTDATA_H_
 
 #include <string>
-#include <stdexcept>
 
 namespace spine {
 
@@ -15,23 +14,8 @@ public:
 	float r, g, b, a;
 	std::string *attachmentName;
 
-	SlotData (const std::string &name, BoneData *boneData) :
-					name(name),
-					boneData(boneData),
-					r(1),
-					g(1),
-					b(1),
-					a(1),
-					attachmentName(0) {
-		if (!boneData) throw std::invalid_argument("boneData cannot be null.");
-	}
-
-	~SlotData () {
-		if (attachmentName) {
-			delete attachmentName;
-			attachmentName = 0;
-		}
-	}
+	SlotData (const std::string &name, BoneData *boneData);
+	~SlotData ();
 };
 
 } /* namespace spine */

+ 7 - 1
spine-cpp/src/spine-sfml/Atlas.cpp

@@ -3,6 +3,12 @@
 
 namespace spine {
 
+AtlasPage::~AtlasPage () {
+	delete texture;
+}
+
+//
+
 Atlas::Atlas (std::ifstream &file) {
 	load(file);
 }
@@ -19,7 +25,7 @@ Atlas::Atlas (const char *begin, const char *end) {
 	load(begin, end);
 }
 
-BaseAtlasPage* Atlas::newAtlasPage (std::string name) {
+BaseAtlasPage* Atlas::newAtlasPage (const std::string &name) {
 	AtlasPage *page = new AtlasPage();
 	page->texture = new sf::Texture();
 	page->texture->loadFromFile(name);

+ 2 - 2
spine-cpp/src/spine-sfml/RegionAttachment.cpp

@@ -9,7 +9,7 @@
 namespace spine {
 
 RegionAttachment::RegionAttachment (AtlasRegion *region) {
-	texture = region->page->texture; // BOZO - Resolve attachment as late as possible?
+	texture = region->page->texture;
 	int u = region->x;
 	int u2 = u + region->width;
 	int v = region->y;
@@ -59,9 +59,9 @@ void RegionAttachment::draw (Slot *slot) {
 	vertices[3].color.b = b;
 	vertices[3].color.a = a;
 
-	updateOffset(); // BOZO - Move to resolve()?
 	updateWorldVertices(slot->bone);
 
+	// SMFL doesn't handle batching for us, so we'll just force a single texture per skeleton.
 	skeleton->texture = texture;
 	skeleton->vertexArray.append(vertices[0]);
 	skeleton->vertexArray.append(vertices[1]);

+ 2 - 2
spine-cpp/src/spine-sfml/SkeletonJson.cpp

@@ -5,12 +5,12 @@ namespace spine {
 
 SkeletonJson::SkeletonJson (BaseAttachmentLoader *attachmentLoader) :
 				BaseSkeletonJson(attachmentLoader) {
-	flipY = true;
+	yDown = true;
 }
 
 SkeletonJson::SkeletonJson (Atlas *atlas) :
 				BaseSkeletonJson(new AtlasAttachmentLoader(atlas)) {
-	flipY = true;
+	yDown = true;
 }
 
 } /* namespace spine */

+ 21 - 28
spine-cpp/src/spine/Animation.cpp

@@ -18,26 +18,19 @@ Animation::Animation (const vector<Timeline*> &timelines, float duration) :
 				duration(duration) {
 }
 
-Animation::~Animation()
-{
-  for (std::vector<Timeline*>::iterator iter = timelines.begin(); iter != timelines.end(); ++iter)
-  {
-    delete *iter;
-  }
+Animation::~Animation () {
+	for (int i = 0, n = timelines.size(); i < n; i++)
+		delete timelines[i];
 }
 
-void Animation::apply (BaseSkeleton *skeleton, float time, bool loop) {
-	if (!skeleton) throw std::invalid_argument("skeleton cannot be null.");
-
+void Animation::apply (BaseSkeleton *skeleton, float time, bool loop) const {
 	if (loop && duration) time = fmodf(time, duration);
 
 	for (int i = 0, n = timelines.size(); i < n; i++)
 		timelines[i]->apply(skeleton, time, 1);
 }
 
-void Animation::mix (BaseSkeleton *skeleton, float time, bool loop, float alpha) {
-	if (!skeleton) throw std::invalid_argument("skeleton cannot be null.");
-
+void Animation::mix (BaseSkeleton *skeleton, float time, bool loop, float alpha) const {
 	if (loop && duration) time = fmodf(time, duration);
 
 	for (int i = 0, n = timelines.size(); i < n; i++)
@@ -88,7 +81,7 @@ void CurveTimeline::setCurve (int keyframeIndex, float cx1, float cy1, float cx2
 	curves[i + 5] = tmp2y * pre5;
 }
 
-float CurveTimeline::getCurvePercent (int keyframeIndex, float percent) {
+float CurveTimeline::getCurvePercent (int keyframeIndex, float percent) const {
 	int curveIndex = keyframeIndex * 6;
 	float dfx = curves[curveIndex];
 	if (dfx == LINEAR) return percent;
@@ -162,11 +155,11 @@ RotateTimeline::~RotateTimeline () {
 	delete[] frames;
 }
 
-float RotateTimeline::getDuration () {
+float RotateTimeline::getDuration () const {
 	return frames[framesLength - 2];
 }
 
-int RotateTimeline::getKeyframeCount () {
+int RotateTimeline::getKeyframeCount () const {
 	return framesLength / 2;
 }
 
@@ -176,7 +169,7 @@ void RotateTimeline::setKeyframe (int keyframeIndex, float time, float value) {
 	frames[keyframeIndex + 1] = value;
 }
 
-void RotateTimeline::apply (BaseSkeleton *skeleton, float time, float alpha) {
+void RotateTimeline::apply (BaseSkeleton *skeleton, float time, float alpha) const {
 	if (time < frames[0]) return; // Time is before first frame.
 
 	Bone *bone = skeleton->bones[boneIndex];
@@ -233,11 +226,11 @@ TranslateTimeline::~TranslateTimeline () {
 	delete[] frames;
 }
 
-float TranslateTimeline::getDuration () {
+float TranslateTimeline::getDuration () const {
 	return frames[framesLength - 3];
 }
 
-int TranslateTimeline::getKeyframeCount () {
+int TranslateTimeline::getKeyframeCount () const {
 	return framesLength / 3;
 }
 
@@ -248,7 +241,7 @@ void TranslateTimeline::setKeyframe (int keyframeIndex, float time, float x, flo
 	frames[keyframeIndex + 2] = y;
 }
 
-void TranslateTimeline::apply (BaseSkeleton *skeleton, float time, float alpha) {
+void TranslateTimeline::apply (BaseSkeleton *skeleton, float time, float alpha) const {
 	if (time < frames[0]) return; // Time is before first frame.
 
 	Bone *bone = skeleton->bones[boneIndex];
@@ -281,7 +274,7 @@ ScaleTimeline::ScaleTimeline (int keyframeCount) :
 				TranslateTimeline(keyframeCount) {
 }
 
-void ScaleTimeline::apply (BaseSkeleton *skeleton, float time, float alpha) {
+void ScaleTimeline::apply (BaseSkeleton *skeleton, float time, float alpha) const {
 	if (time < frames[0]) return; // Time is before first frame.
 
 	Bone *bone = skeleton->bones[boneIndex];
@@ -329,11 +322,11 @@ ColorTimeline::~ColorTimeline () {
 	delete[] frames;
 }
 
-float ColorTimeline::getDuration () {
+float ColorTimeline::getDuration () const {
 	return frames[framesLength - 5];
 }
 
-int ColorTimeline::getKeyframeCount () {
+int ColorTimeline::getKeyframeCount () const {
 	return framesLength / 5;
 }
 
@@ -346,7 +339,7 @@ void ColorTimeline::setKeyframe (int keyframeIndex, float time, float r, float g
 	frames[keyframeIndex + 4] = a;
 }
 
-void ColorTimeline::apply (BaseSkeleton *skeleton, float time, float alpha) {
+void ColorTimeline::apply (BaseSkeleton *skeleton, float time, float alpha) const {
 	if (time < frames[0]) return; // Time is before first frame.
 
 	Slot *slot = skeleton->slots[slotIndex];
@@ -410,21 +403,21 @@ AttachmentTimeline::~AttachmentTimeline () {
 	delete[] attachmentNames;
 }
 
-float AttachmentTimeline::getDuration () {
+float AttachmentTimeline::getDuration () const {
 	return frames[framesLength - 1];
 }
 
-int AttachmentTimeline::getKeyframeCount () {
+int AttachmentTimeline::getKeyframeCount () const {
 	return framesLength;
 }
 
-void AttachmentTimeline::setKeyframe (int keyframeIndex, float time, const string &attachmentName) {
+void AttachmentTimeline::setKeyframe (int keyframeIndex, float time, string *attachmentName) {
 	frames[keyframeIndex] = time;
 	if (attachmentNames[keyframeIndex]) delete attachmentNames[keyframeIndex];
-	attachmentNames[keyframeIndex] = attachmentName.length() == 0 ? 0 : new string(attachmentName);
+	attachmentNames[keyframeIndex] = attachmentName;
 }
 
-void AttachmentTimeline::apply (BaseSkeleton *skeleton, float time, float alpha) {
+void AttachmentTimeline::apply (BaseSkeleton *skeleton, float time, float alpha) const {
 	if (time < frames[0]) return; // Time is before first frame.
 
 	int frameIndex;

+ 6 - 1
spine-cpp/src/spine/BaseAtlas.cpp

@@ -105,7 +105,7 @@ void BaseAtlas::load (const char *current, const char *end) {
 
 	string value;
 	string tuple[4];
-	BaseAtlasPage *page = NULL;
+	BaseAtlasPage *page = 0;
 	while (current != end) {
 		readLine(current, end, value);
 		trim(value);
@@ -185,6 +185,11 @@ BaseAtlasRegion* BaseAtlas::findRegion (const std::string &name) {
 
 //
 
+BaseAtlasRegion::BaseAtlasRegion () :
+				splits(0),
+				pads(0) {
+}
+
 BaseAtlasRegion::~BaseAtlasRegion () {
 	if (splits) delete splits;
 	if (pads) delete pads;

+ 2 - 2
spine-cpp/src/spine/BaseRegionAttachment.cpp

@@ -1,8 +1,8 @@
 #include <math.h>
 #include <spine/BaseRegionAttachment.h>
 
-#ifndef M_PI // fix for windows removing precious information
-#define M_PI 3.14159265358979323846
+#ifndef M_PI
+#define M_PI 3.1415926535897932385
 #endif
 
 namespace spine {

+ 8 - 7
spine-cpp/src/spine/BaseSkeleton.cpp

@@ -1,3 +1,4 @@
+#include <stdexcept>
 #include <iostream>
 #include <spine/BaseSkeleton.h>
 #include <spine/SkeletonData.h>
@@ -92,25 +93,25 @@ Bone* BaseSkeleton::getRootBone () const {
 }
 
 Bone* BaseSkeleton::findBone (const string &boneName) const {
-	for (unsigned int i = 0; i < bones.size(); i++)
+	for (int i = 0, n = bones.size(); i < n; i++)
 		if (data->bones[i]->name == boneName) return bones[i];
 	return 0;
 }
 
 int BaseSkeleton::findBoneIndex (const string &boneName) const {
-	for (unsigned int i = 0; i < bones.size(); i++)
+	for (int i = 0, n = bones.size(); i < n; i++)
 		if (data->bones[i]->name == boneName) return i;
 	return -1;
 }
 
 Slot* BaseSkeleton::findSlot (const string &slotName) const {
-	for (unsigned int i = 0; i < slots.size(); i++)
+	for (int i = 0, n = slots.size(); i < n; i++)
 		if (data->slots[i]->name == slotName) return slots[i];
 	return 0;
 }
 
 int BaseSkeleton::findSlotIndex (const string &slotName) const {
-	for (unsigned int i = 0; i < slots.size(); i++)
+	for (int i = 0, n = slots.size(); i < n; i++)
 		if (data->slots[i]->name == slotName) return i;
 	return -1;
 }
@@ -126,16 +127,16 @@ void BaseSkeleton::setSkin (Skin *newSkin) {
 	skin = newSkin;
 }
 
-Attachment* BaseSkeleton::getAttachment (const string &slotName, const string &attachmentName) {
+Attachment* BaseSkeleton::getAttachment (const string &slotName, const string &attachmentName) const {
 	return getAttachment(data->findSlotIndex(slotName), attachmentName);
 }
 
-Attachment* BaseSkeleton::getAttachment (int slotIndex, const string &attachmentName) {
+Attachment* BaseSkeleton::getAttachment (int slotIndex, const string &attachmentName) const {
+	if (skin) return skin->getAttachment(slotIndex, attachmentName);
 	if (data->defaultSkin) {
 		Attachment *attachment = data->defaultSkin->getAttachment(slotIndex, attachmentName);
 		if (attachment) return attachment;
 	}
-	if (skin) return skin->getAttachment(slotIndex, attachmentName);
 	return 0;
 }
 

+ 23 - 21
spine-cpp/src/spine/BaseSkeletonJson.cpp

@@ -32,12 +32,12 @@ static float toColor (const string &value, int index) {
 BaseSkeletonJson::BaseSkeletonJson (BaseAttachmentLoader *attachmentLoader) :
 				attachmentLoader(attachmentLoader),
 				scale(1),
-				flipY(false) {
+				yDown(false) {
+	if (!attachmentLoader) throw invalid_argument("attachmentLoader cannot be null.");
 }
 
 BaseSkeletonJson::~BaseSkeletonJson () {
-  if (attachmentLoader)
-    delete attachmentLoader;
+	delete attachmentLoader;
 }
 
 SkeletonData* BaseSkeletonJson::readSkeletonData (std::ifstream &file) const {
@@ -76,7 +76,7 @@ SkeletonData* BaseSkeletonJson::readSkeletonData (const char *begin, const char
 
 	Json::Value bones = root["bones"];
 	skeletonData->bones.reserve(bones.size());
-	for (unsigned int i = 0; i < bones.size(); ++i) {
+	for (int i = 0, n = bones.size(); i < n; ++i) {
 		Json::Value boneMap = bones[i];
 		string boneName = boneMap["name"].asString();
 
@@ -92,7 +92,7 @@ SkeletonData* BaseSkeletonJson::readSkeletonData (const char *begin, const char
 		boneData->rotation = (float)(boneMap.get("rotation", 0).asDouble());
 		boneData->scaleX = (float)(boneMap.get("scaleX", 1).asDouble());
 		boneData->scaleY = (float)(boneMap.get("scaleY", 1).asDouble());
-		boneData->flipY = flipY;
+		boneData->yDown = yDown;
 
 		skeletonData->bones.push_back(boneData);
 	}
@@ -100,7 +100,7 @@ SkeletonData* BaseSkeletonJson::readSkeletonData (const char *begin, const char
 	Json::Value slots = root["slots"];
 	if (!slots.isNull()) {
 		skeletonData->slots.reserve(slots.size());
-		for (unsigned int i = 0; i < slots.size(); ++i) {
+		for (int i = 0, n = slots.size(); i < n; ++i) {
 			Json::Value slotMap = slots[i];
 			string slotName = slotMap["name"].asString();
 
@@ -128,7 +128,7 @@ SkeletonData* BaseSkeletonJson::readSkeletonData (const char *begin, const char
 		Json::Value skinsMap = root["skins"];
 		vector<string> skinNames = skinsMap.getMemberNames();
 		skeletonData->skins.reserve(skinNames.size());
-		for (unsigned int i = 0; i < skinNames.size(); i++) {
+		for (int i = 0, n = skinNames.size(); i < n; i++) {
 			string skinName = skinNames[i];
 			Skin *skin = new Skin(skinName);
 			skeletonData->skins.push_back(skin);
@@ -136,13 +136,13 @@ SkeletonData* BaseSkeletonJson::readSkeletonData (const char *begin, const char
 
 			Json::Value slotMap = skinsMap[skinName];
 			vector<string> slotNames = slotMap.getMemberNames();
-			for (unsigned int i = 0; i < slotNames.size(); i++) {
+			for (int i = 0, n = slotNames.size(); i < n; i++) {
 				string slotName = slotNames[i];
 				int slotIndex = skeletonData->findSlotIndex(slotName);
 
 				Json::Value attachmentsMap = slotMap[slotName];
 				vector<string> attachmentNames = attachmentsMap.getMemberNames();
-				for (unsigned int i = 0; i < attachmentNames.size(); i++) {
+				for (int i = 0, n = attachmentNames.size(); i < n; i++) {
 					string attachmentName = attachmentNames[i];
 					Json::Value attachmentMap = attachmentsMap[attachmentName];
 
@@ -167,6 +167,7 @@ SkeletonData* BaseSkeletonJson::readSkeletonData (const char *begin, const char
 						regionAttachment->rotation = (float)(attachmentMap.get("rotation", 0).asDouble());
 						regionAttachment->width = (float)(attachmentMap.get("width", 32).asDouble() * scale);
 						regionAttachment->height = (float)(attachmentMap.get("height", 32).asDouble() * scale);
+						regionAttachment->updateOffset();
 					}
 
 					skin->addAttachment(slotIndex, attachmentName, attachment);
@@ -205,7 +206,8 @@ static void readCurve (CurveTimeline *timeline, int keyframeIndex, const Json::V
 	if (curve.isString() && curve.asString() == "stepped")
 		timeline->setStepped(keyframeIndex);
 	else if (curve.isArray())
-		timeline->setCurve(keyframeIndex, (float)curve[0u].asDouble(), (float)curve[1u].asDouble(), (float)curve[2u].asDouble(), (float)curve[3u].asDouble());
+		timeline->setCurve(keyframeIndex, (float)curve[0u].asDouble(), (float)curve[1u].asDouble(), (float)curve[2u].asDouble(),
+				(float)curve[3u].asDouble());
 }
 
 Animation* BaseSkeletonJson::readAnimation (const char *begin, const char *end, const SkeletonData *skeletonData) const {
@@ -229,14 +231,14 @@ Animation* BaseSkeletonJson::readAnimation (const char *begin, const char *end,
 
 	Json::Value bones = root["bones"];
 	vector<string> boneNames = bones.getMemberNames();
-	for (unsigned int i = 0; i < boneNames.size(); i++) {
+	for (int i = 0, n = boneNames.size(); i < n; i++) {
 		string boneName = boneNames[i];
 		int boneIndex = skeletonData->findBoneIndex(boneName);
 		if (boneIndex == -1) throw runtime_error("Bone not found: " + boneName);
 
 		Json::Value timelineMap = bones[boneName];
 		vector<string> timelineNames = timelineMap.getMemberNames();
-		for (unsigned int i = 0; i < timelineNames.size(); i++) {
+		for (int i = 0, n = timelineNames.size(); i < n; i++) {
 			string timelineName = timelineNames[i];
 			Json::Value values = timelineMap[timelineName];
 
@@ -245,7 +247,7 @@ Animation* BaseSkeletonJson::readAnimation (const char *begin, const char *end,
 				timeline->boneIndex = boneIndex;
 
 				int keyframeIndex = 0;
-				for (unsigned int i = 0; i < values.size(); i++) {
+				for (int i = 0, n = values.size(); i < n; i++) {
 					Json::Value valueMap = values[i];
 
 					float time = (float)valueMap["time"].asDouble();
@@ -268,10 +270,9 @@ Animation* BaseSkeletonJson::readAnimation (const char *begin, const char *end,
 				timeline->boneIndex = boneIndex;
 
 				int keyframeIndex = 0;
-				for (unsigned int i = 0; i < values.size(); i++) {
+				for (int i = 0, n = values.size(); i < n; i++) {
 					Json::Value valueMap = values[i];
 
-					float time = (float)valueMap["time"].asDouble();
 					timeline->setKeyframe(keyframeIndex, //
 							(float)valueMap["time"].asDouble(), //
 							(float)valueMap.get("x", 0).asDouble() * timelineScale, //
@@ -291,14 +292,14 @@ Animation* BaseSkeletonJson::readAnimation (const char *begin, const char *end,
 	Json::Value slots = root["slots"];
 	if (!slots.isNull()) {
 		vector<string> slotNames = slots.getMemberNames();
-		for (unsigned int i = 0; i < slotNames.size(); i++) {
+		for (int i = 0, n = slotNames.size(); i < n; i++) {
 			string slotName = slotNames[i];
 			int slotIndex = skeletonData->findSlotIndex(slotName);
 			if (slotIndex == -1) throw runtime_error("Slot not found: " + slotName);
 
 			Json::Value timelineMap = slots[slotName];
 			vector<string> timelineNames = timelineMap.getMemberNames();
-			for (unsigned int i = 0; i < timelineNames.size(); i++) {
+			for (int i = 0, n = timelineNames.size(); i < n; i++) {
 				string timelineName = timelineNames[i];
 				Json::Value values = timelineMap[timelineName];
 
@@ -307,7 +308,7 @@ Animation* BaseSkeletonJson::readAnimation (const char *begin, const char *end,
 					timeline->slotIndex = slotIndex;
 
 					int keyframeIndex = 0;
-					for (unsigned int i = 0; i < values.size(); i++) {
+					for (int i = 0, n = values.size(); i < n; i++) {
 						Json::Value valueMap = values[i];
 
 						string s = valueMap["color"].asString();
@@ -324,11 +325,12 @@ Animation* BaseSkeletonJson::readAnimation (const char *begin, const char *end,
 					timeline->slotIndex = slotIndex;
 
 					int keyframeIndex = 0;
-					for (unsigned int i = 0; i < values.size(); i++) {
+					for (int i = 0, n = values.size(); i < n; i++) {
 						Json::Value valueMap = values[i];
 
-						Json::Value name = valueMap["name"];
-						timeline->setKeyframe(keyframeIndex++, (float)valueMap["time"].asDouble(), name.isNull() ? "" : name.asString());
+						Json::Value nameValue = valueMap["name"];
+						timeline->setKeyframe(keyframeIndex++, (float)valueMap["time"].asDouble(),
+								nameValue.isNull() ? 0 : new string(nameValue.asString()));
 					}
 					timelines.push_back(timeline);
 					if (timeline->getDuration() > duration) duration = timeline->getDuration();

+ 1 - 1
spine-cpp/src/spine/Bone.cpp

@@ -58,7 +58,7 @@ void Bone::updateWorldTransform (bool flipX, bool flipY) {
 		m10 = -m10;
 		m11 = -m11;
 	}
-	if (data->flipY) {
+	if (data->yDown) {
 		m10 = -m10;
 		m11 = -m11;
 	}

+ 6 - 6
spine-cpp/src/spine/SkeletonData.cpp

@@ -21,31 +21,31 @@ SkeletonData::~SkeletonData () {
 }
 
 BoneData* SkeletonData::findBone (const string &boneName) const {
-	for (unsigned int i = 0; i < bones.size(); i++)
+	for (int i = 0, n = bones.size(); i < n; i++)
 		if (bones[i]->name == boneName) return bones[i];
 	return 0;
 }
 
 int SkeletonData::findBoneIndex (const string &boneName) const {
-	for (unsigned int i = 0; i < bones.size(); i++)
+	for (int i = 0, n = bones.size(); i < n; i++)
 		if (bones[i]->name == boneName) return i;
 	return -1;
 }
 
 SlotData* SkeletonData::findSlot (const string &slotName) const {
-	for (unsigned int i = 0; i < slots.size(); i++)
+	for (int i = 0, n = slots.size(); i < n; i++)
 		if (slots[i]->name == slotName) return slots[i];
 	return 0;
 }
 
 int SkeletonData::findSlotIndex (const string &slotName) const {
-	for (unsigned int i = 0; i < slots.size(); i++)
+	for (int i = 0, n = slots.size(); i < n; i++)
 		if (slots[i]->name == slotName) return i;
 	return -1;
 }
 
-Skin* SkeletonData::findSkin (const string &skinName) {
-	for (unsigned int i = 0; i < skins.size(); i++)
+Skin* SkeletonData::findSkin (const string &skinName) const {
+	for (int i = 0, n = skins.size(); i < n; i++)
 		if (skins[i]->name == skinName) return skins[i];
 	return 0;
 }

+ 6 - 6
spine-cpp/src/spine/Skin.cpp

@@ -1,3 +1,5 @@
+#include <stdexcept>
+#include <spine/Attachment.h>
 #include <spine/Skin.h>
 #include <spine/BaseSkeleton.h>
 #include <spine/Slot.h>
@@ -8,14 +10,13 @@ Skin::Skin (const std::string &name) :
 				name(name) {
 }
 
-Skin::~Skin()
-{
-	for (std::map<Key, Attachment*>::iterator iter = attachments.begin(); iter != attachments.end(); ++iter) {
-    delete iter->second;
-  }
+Skin::~Skin () {
+	for (std::map<Key, Attachment*>::iterator iter = attachments.begin(); iter != attachments.end(); iter++)
+		delete iter->second;
 }
 
 void Skin::addAttachment (int slotIndex, const std::string &name, Attachment *attachment) {
+	if (!attachment) throw std::invalid_argument("attachment cannot be null.");
 	Key key = {slotIndex, name};
 	attachments[key] = attachment;
 }
@@ -26,7 +27,6 @@ Attachment* Skin::getAttachment (int slotIndex, const std::string &name) {
 	return 0;
 }
 
-/** Attach all attachments from this skin if the corresponding attachment from the old skin is currently attached. */
 void Skin::attachAll (BaseSkeleton *skeleton, Skin *oldSkin) {
 	for (std::map<Key, Attachment*>::iterator iter = attachments.begin(); iter != attachments.end(); iter++) {
 		const Key key = iter->first;

+ 3 - 2
spine-cpp/src/spine/Slot.cpp

@@ -1,3 +1,4 @@
+#include <stdexcept>
 #include <spine/Slot.h>
 #include <spine/SlotData.h>
 #include <spine/BaseSkeleton.h>
@@ -6,6 +7,7 @@
 namespace spine {
 
 Slot::Slot (SlotData *data, BaseSkeleton *skeleton, Bone *bone) :
+				attachmentTime(0),
 				data(data),
 				skeleton(skeleton),
 				bone(bone),
@@ -13,8 +15,7 @@ Slot::Slot (SlotData *data, BaseSkeleton *skeleton, Bone *bone) :
 				g(1),
 				b(1),
 				a(1),
-				attachment(0),
-				attachmentTime(0) {
+				attachment(0) {
 	if (!data) throw std::invalid_argument("data cannot be null.");
 	if (!skeleton) throw std::invalid_argument("skeleton cannot be null.");
 	if (!bone) throw std::invalid_argument("bone cannot be null.");

+ 25 - 0
spine-cpp/src/spine/SlotData.cpp

@@ -0,0 +1,25 @@
+#include <stdexcept>
+#include <spine/SlotData.h>
+
+namespace spine {
+
+SlotData::SlotData (const std::string &name, BoneData *boneData) :
+				name(name),
+				boneData(boneData),
+				r(1),
+				g(1),
+				b(1),
+				a(1),
+				attachmentName(0) {
+	if (!boneData) throw std::invalid_argument("boneData cannot be null.");
+}
+
+SlotData::~SlotData () {
+	if (attachmentName) {
+		delete attachmentName;
+		attachmentName = 0;
+	}
+}
+
+}
+/* namespace spine */

+ 6 - 7
spine-libgdx/.classpath

@@ -1,9 +1,8 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?xml version="1.0" encoding="UTF-8"?>
 <classpath>
-    <classpathentry kind="src" path="src"/>
-    <classpathentry kind="src" path="test"/>
-    <classpathentry combineaccessrules="false" exported="true" kind="src" path="/gdx-backend-jglfw"/>
-    <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
-    <classpathentry kind="output" path="bin"/>
-    <classpathentry exported="true" kind="lib" path="libs/gdx.jar" sourcepath="libs/gdx-sources.jar"/>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="src" path="test"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+	<classpathentry combineaccessrules="false" exported="true" kind="src" path="/gdx-backend-lwjgl"/>
+	<classpathentry kind="output" path="bin"/>
 </classpath>

+ 33 - 38
spine-libgdx/spine-libgdx.iws

@@ -22,7 +22,6 @@
     <disable_hints />
   </component>
   <component name="DebuggerManager">
-    <ui_properties default_suspend_policy="SuspendAll" default_condition_enabled="true" />
     <breakpoint_any default_suspend_policy="SuspendAll" default_condition_enabled="true">
       <breakpoint>
         <option name="NOTIFY_CAUGHT" value="true" />
@@ -57,6 +56,7 @@
         <option name="LOG_MESSAGE" value="" />
       </breakpoint>
     </breakpoint_any>
+    <ui_properties default_suspend_policy="SuspendAll" default_condition_enabled="true" />
     <breakpoint_rules />
     <ui_properties />
   </component>
@@ -78,7 +78,7 @@
       <file leaf-file-name="SkeletonTest.java" pinned="false" current="true" current-in-tab="true">
         <entry file="file://$PROJECT_DIR$/test/com/esotericsoftware/spine/SkeletonTest.java">
           <provider selected="true" editor-type-id="text-editor">
-            <state line="23" column="116" selection-start="940" selection-end="940" vertical-scroll-proportion="0.59380376">
+            <state line="23" column="116" selection-start="940" selection-end="940" vertical-scroll-proportion="0.017441861">
               <folding>
                 <element signature="imports" expanded="true" />
               </folding>
@@ -99,9 +99,7 @@
         <entry file="file://$PROJECT_DIR$/test/com/esotericsoftware/spine/MixTest.java">
           <provider selected="true" editor-type-id="text-editor">
             <state line="115" column="8" selection-start="3622" selection-end="3697" vertical-scroll-proportion="0.0">
-              <folding>
-                <element signature="imports" expanded="true" />
-              </folding>
+              <folding />
             </state>
           </provider>
         </entry>
@@ -154,7 +152,7 @@
       <file leaf-file-name="spine-libgdx.iws" pinned="false" current="false" current-in-tab="false">
         <entry file="file://$PROJECT_DIR$/spine-libgdx.iws">
           <provider selected="true" editor-type-id="text-editor">
-            <state line="10" column="0" selection-start="781" selection-end="781" vertical-scroll-proportion="0.0">
+            <state line="9" column="0" selection-start="648" selection-end="648" vertical-scroll-proportion="0.0">
               <folding />
             </state>
           </provider>
@@ -178,9 +176,10 @@
     </option>
   </component>
   <component name="ProjectFrameBounds">
-    <option name="y" value="24" />
-    <option name="width" value="1920" />
-    <option name="height" value="1056" />
+    <option name="x" value="1919" />
+    <option name="y" value="-4" />
+    <option name="width" value="1682" />
+    <option name="height" value="1055" />
   </component>
   <component name="ProjectInspectionProfilesVisibleTreeState">
     <entry key="Project Default">
@@ -254,6 +253,7 @@
     </navigator>
     <panes>
       <pane id="Scope" />
+      <pane id="PackagesPane" />
       <pane id="ProjectPane">
         <subPane>
           <PATH>
@@ -320,7 +320,6 @@
           </PATH>
         </subPane>
       </pane>
-      <pane id="PackagesPane" />
     </panes>
   </component>
   <component name="PropertiesComponent">
@@ -339,9 +338,9 @@
     <property name="restartRequiresConfirmation" value="true" />
     <property name="MemberChooser.showClasses" value="true" />
     <property name="GoToClass.includeLibraries" value="false" />
-    <property name="options.splitter.details.proportions" value="0.2" />
-    <property name="options.searchVisible" value="true" />
     <property name="dynamic.classpath" value="false" />
+    <property name="options.searchVisible" value="true" />
+    <property name="options.splitter.details.proportions" value="0.2" />
   </component>
   <component name="RecentsManager">
     <key name="CopyFile.RECENT_KEYS">
@@ -364,6 +363,19 @@
       <option name="PORT" value="5005" />
       <method />
     </configuration>
+    <configuration default="true" type="Applet" factoryName="Applet">
+      <module name="" />
+      <option name="MAIN_CLASS_NAME" />
+      <option name="HTML_FILE_NAME" />
+      <option name="HTML_USED" value="false" />
+      <option name="WIDTH" value="400" />
+      <option name="HEIGHT" value="300" />
+      <option name="POLICY_FILE" value="$APPLICATION_HOME_DIR$/bin/appletviewer.policy" />
+      <option name="VM_PARAMETERS" />
+      <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
+      <option name="ALTERNATIVE_JRE_PATH" />
+      <method />
+    </configuration>
     <configuration default="true" type="TestNG" factoryName="TestNG">
       <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
       <module name="" />
@@ -392,19 +404,6 @@
       <listeners />
       <method />
     </configuration>
-    <configuration default="true" type="Applet" factoryName="Applet">
-      <module name="" />
-      <option name="MAIN_CLASS_NAME" />
-      <option name="HTML_FILE_NAME" />
-      <option name="HTML_USED" value="false" />
-      <option name="WIDTH" value="400" />
-      <option name="HEIGHT" value="300" />
-      <option name="POLICY_FILE" value="$APPLICATION_HOME_DIR$/bin/appletviewer.policy" />
-      <option name="VM_PARAMETERS" />
-      <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
-      <option name="ALTERNATIVE_JRE_PATH" />
-      <method />
-    </configuration>
     <configuration default="true" type="Application" factoryName="Application">
       <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
       <option name="MAIN_CLASS_NAME" value="com.esotericsoftware.spine.MixTest" />
@@ -530,8 +529,8 @@
     <servers />
   </component>
   <component name="ToolWindowManager">
-    <frame x="0" y="24" width="1920" height="1056" extended-state="6" />
-    <editor active="true" />
+    <frame x="1919" y="-4" width="1682" height="1055" extended-state="6" />
+    <editor active="false" />
     <layout>
       <window_info id="Changes" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
       <window_info id="JetGradle" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
@@ -544,19 +543,19 @@
       <window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="2" side_tool="true" content_ui="tabs" />
       <window_info id="IDEtalk" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.32977587" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
       <window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
-      <window_info id="Messages" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.32977587" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
       <window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" />
       <window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="1" side_tool="true" content_ui="tabs" />
       <window_info id="Maven Projects" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
       <window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="SLIDING" type="SLIDING" visible="false" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
       <window_info id="Application Servers" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
       <window_info id="JSON Formatter" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
-      <window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" weight="0.2497332" sideWeight="0.67022413" order="0" side_tool="false" content_ui="combo" />
-      <window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" weight="0.32977587" sideWeight="0.9989328" order="2" side_tool="false" content_ui="tabs" />
+      <window_info id="Project" active="true" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" weight="0.249694" sideWeight="0.67022413" order="0" side_tool="false" content_ui="combo" />
+      <window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.32977587" sideWeight="0.9989328" order="2" side_tool="false" content_ui="tabs" />
       <window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="2" side_tool="false" content_ui="combo" />
       <window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" />
       <window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
       <window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
+      <window_info id="Messages" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.32977587" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
       <window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.4" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" />
     </layout>
   </component>
@@ -671,7 +670,7 @@
     </entry>
     <entry file="file://$PROJECT_DIR$/spine-libgdx.iws">
       <provider selected="true" editor-type-id="text-editor">
-        <state line="10" column="0" selection-start="781" selection-end="781" vertical-scroll-proportion="0.0">
+        <state line="9" column="0" selection-start="648" selection-end="648" vertical-scroll-proportion="0.0">
           <folding />
         </state>
       </provider>
@@ -685,9 +684,7 @@
     </entry>
     <entry file="file://$PROJECT_DIR$/src/com/esotericsoftware/spine/AttachmentType.java">
       <provider selected="true" editor-type-id="text-editor">
-        <state line="3" column="12" selection-start="50" selection-end="50" vertical-scroll-proportion="0.0">
-          <folding />
-        </state>
+        <state line="3" column="12" selection-start="50" selection-end="50" vertical-scroll-proportion="0.0" />
       </provider>
     </entry>
     <entry file="file://$PROJECT_DIR$/src/com/esotericsoftware/spine/BoneData.java">
@@ -721,15 +718,13 @@
     <entry file="file://$PROJECT_DIR$/test/com/esotericsoftware/spine/MixTest.java">
       <provider selected="true" editor-type-id="text-editor">
         <state line="115" column="8" selection-start="3622" selection-end="3697" vertical-scroll-proportion="0.0">
-          <folding>
-            <element signature="imports" expanded="true" />
-          </folding>
+          <folding />
         </state>
       </provider>
     </entry>
     <entry file="file://$PROJECT_DIR$/test/com/esotericsoftware/spine/SkeletonTest.java">
       <provider selected="true" editor-type-id="text-editor">
-        <state line="23" column="116" selection-start="940" selection-end="940" vertical-scroll-proportion="0.59380376">
+        <state line="23" column="116" selection-start="940" selection-end="940" vertical-scroll-proportion="0.017441861">
           <folding>
             <element signature="imports" expanded="true" />
           </folding>

+ 1 - 0
spine-libgdx/src/com/esotericsoftware/spine/AttachmentLoader.java

@@ -2,5 +2,6 @@
 package com.esotericsoftware.spine;
 
 public interface AttachmentLoader {
+	/** @return May be null to not load any attachment. */
 	public Attachment newAttachment (AttachmentType type, String name);
 }

+ 1 - 1
spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java

@@ -216,11 +216,11 @@ public class Skeleton {
 	/** @return May be null. */
 	public Attachment getAttachment (int slotIndex, String attachmentName) {
 		if (attachmentName == null) throw new IllegalArgumentException("attachmentName cannot be null.");
+		if (skin != null) return skin.getAttachment(slotIndex, attachmentName);
 		if (data.defaultSkin != null) {
 			Attachment attachment = data.defaultSkin.getAttachment(slotIndex, attachmentName);
 			if (attachment != null) return attachment;
 		}
-		if (skin != null) return skin.getAttachment(slotIndex, attachmentName);
 		return null;
 	}
 

+ 1 - 1
spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java

@@ -103,7 +103,7 @@ public class SkeletonJson {
 					int slotIndex = skeletonData.findSlotIndex(slotEntry.key);
 					for (Entry<String, OrderedMap> attachmentEntry : ((OrderedMap<String, OrderedMap>)slotEntry.value).entries()) {
 						Attachment attachment = readAttachment(attachmentEntry.key, attachmentEntry.value);
-						skin.addAttachment(slotIndex, attachmentEntry.key, attachment);
+						if (attachment != null) skin.addAttachment(slotIndex, attachmentEntry.key, attachment);
 					}
 				}
 				skeletonData.addSkin(skin);

+ 1 - 5
spine-libgdx/test/com/esotericsoftware/spine/MixTest.java

@@ -113,10 +113,6 @@ public class MixTest extends ApplicationAdapter {
 	}
 
 	public static void main (String[] args) throws Exception {
-		LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
-		config.title = "Mix Test";
-		config.width = 640;
-		config.height = 480;
-		new LwjglApplication(new MixTest(), config);
+		new LwjglApplication(new MixTest());
 	}
 }

+ 1 - 5
spine-libgdx/test/com/esotericsoftware/spine/SkeletonTest.java

@@ -114,10 +114,6 @@ public class SkeletonTest extends ApplicationAdapter {
 	}
 
 	public static void main (String[] args) throws Exception {
-        LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
-		config.title = "Skeleton Test";
-		config.width = 640;
-		config.height = 480;
-		new LwjglApplication(new SkeletonTest(), config);
+		new LwjglApplication(new SkeletonTest());
 	}
 }