Javadocs, argument checks, minor clean up.

This commit is contained in:
NathanSweet 2019-06-09 16:14:36 +02:00
parent b473b8afb4
commit 28862c94bc
22 changed files with 167 additions and 115 deletions

View File

@ -70,7 +70,8 @@ public class Animation {
/** Applies all the animation's timelines to the specified skeleton. /** Applies all the animation's timelines to the specified skeleton.
* <p> * <p>
* See Timeline {@link Timeline#apply(Skeleton, float, float, Array, float, MixBlend, MixDirection)}. * See Timeline {@link Timeline#apply(Skeleton, float, float, Array, float, MixBlend, MixDirection)}.
* @param loop If true, the animation repeats after {@link #getDuration()}. */ * @param loop If true, the animation repeats after {@link #getDuration()}.
* @param events May be null to ignore fired events. */
public void apply (Skeleton skeleton, float lastTime, float time, boolean loop, Array<Event> events, float alpha, public void apply (Skeleton skeleton, float lastTime, float time, boolean loop, Array<Event> events, float alpha,
MixBlend blend, MixDirection direction) { MixBlend blend, MixDirection direction) {
if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null."); if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null.");
@ -144,12 +145,12 @@ public class Animation {
* (exclusive) and <code>time</code> (inclusive). * (exclusive) and <code>time</code> (inclusive).
* @param time The time within the animation. Most timelines find the key before and the key after this time so they can * @param time The time within the animation. Most timelines find the key before and the key after this time so they can
* interpolate between the keys. * interpolate between the keys.
* @param events If any events are fired, they are added to this list. Can be null to ignore firing events or if the * @param events If any events are fired, they are added to this list. Can be null to ignore fired events or if the timeline
* timeline does not fire events. * does not fire events.
* @param alpha 0 applies the current or setup value (depending on <code>blend</code>). 1 applies the timeline value. * @param alpha 0 applies the current or setup value (depending on <code>blend</code>). 1 applies the timeline value.
* Between 0 and 1 applies a value between the current or setup value and the timeline value. By adjusting * Between 0 and 1 applies a value between the current or setup value and the timeline value. By adjusting
* <code>alpha</code> over time, an animation can be mixed in or out. <code>alpha</code> can also be useful to * <code>alpha</code> over time, an animation can be mixed in or out. <code>alpha</code> can also be useful to
* apply animations on top of each other (layered). * apply animations on top of each other (layering).
* @param blend Controls how mixing is applied when <code>alpha</code> < 1. * @param blend Controls how mixing is applied when <code>alpha</code> < 1.
* @param direction Indicates whether the timeline is mixing in or out. Used by timelines which perform instant transitions, * @param direction Indicates whether the timeline is mixing in or out. Used by timelines which perform instant transitions,
* such as {@link DrawOrderTimeline} or {@link AttachmentTimeline}. */ * such as {@link DrawOrderTimeline} or {@link AttachmentTimeline}. */
@ -160,7 +161,8 @@ public class Animation {
public int getPropertyId (); public int getPropertyId ();
} }
/** Controls how a timeline value is mixed with the setup pose value or current pose value. /** Controls how a timeline value is mixed with the setup pose value or current pose value when a timeline's <code>alpha</code>
* < 1.
* <p> * <p>
* See Timeline {@link Timeline#apply(Skeleton, float, float, Array, float, MixBlend, MixDirection)}. */ * See Timeline {@link Timeline#apply(Skeleton, float, float, Array, float, MixBlend, MixDirection)}. */
static public enum MixBlend { static public enum MixBlend {
@ -181,7 +183,9 @@ public class Animation {
/** Transitions from the current value to the current value plus the timeline value. No change is made before the first key /** Transitions from the current value to the current value plus the timeline value. No change is made before the first key
* (the current value is kept until the first key). * (the current value is kept until the first key).
* <p> * <p>
* <code>add</code> is intended for animations layered on top of others, not for the first animations applied. */ * <code>add</code> is intended for animations layered on top of others, not for the first animations applied. Properties
* keyed by additive animations must be set manually or by another animation before applying the additive animations, else
* the property values will increase continually. */
add add
} }
@ -779,7 +783,8 @@ public class Animation {
this.slotIndex = index; this.slotIndex = index;
} }
/** The index of the slot in {@link Skeleton#getSlots()} that will be changed. */ /** The index of the slot in {@link Skeleton#getSlots()} that will be changed. The {@link Slot#getDarkColor()} must not be
* null. */
public int getSlotIndex () { public int getSlotIndex () {
return slotIndex; return slotIndex;
} }

View File

@ -462,6 +462,7 @@ public class AnimationState {
* It may be desired to use {@link AnimationState#setEmptyAnimation(int, float)} to mix the skeletons back to the setup pose, * It may be desired to use {@link AnimationState#setEmptyAnimation(int, float)} to mix the skeletons back to the setup pose,
* rather than leaving them in their current pose. */ * rather than leaving them in their current pose. */
public void clearTrack (int trackIndex) { public void clearTrack (int trackIndex) {
if (trackIndex < 0) throw new IllegalArgumentException("trackIndex must be >= 0.");
if (trackIndex >= tracks.size) return; if (trackIndex >= tracks.size) return;
TrackEntry current = tracks.get(trackIndex); TrackEntry current = tracks.get(trackIndex);
if (current == null) return; if (current == null) return;
@ -521,6 +522,7 @@ public class AnimationState {
* @return A track entry to allow further customization of animation playback. References to the track entry must not be kept * @return A track entry to allow further customization of animation playback. References to the track entry must not be kept
* after the {@link AnimationStateListener#dispose(TrackEntry)} event occurs. */ * after the {@link AnimationStateListener#dispose(TrackEntry)} event occurs. */
public TrackEntry setAnimation (int trackIndex, Animation animation, boolean loop) { public TrackEntry setAnimation (int trackIndex, Animation animation, boolean loop) {
if (trackIndex < 0) throw new IllegalArgumentException("trackIndex must be >= 0.");
if (animation == null) throw new IllegalArgumentException("animation cannot be null."); if (animation == null) throw new IllegalArgumentException("animation cannot be null.");
boolean interrupt = true; boolean interrupt = true;
TrackEntry current = expandToIndex(trackIndex); TrackEntry current = expandToIndex(trackIndex);
@ -560,6 +562,7 @@ public class AnimationState {
* @return A track entry to allow further customization of animation playback. References to the track entry must not be kept * @return A track entry to allow further customization of animation playback. References to the track entry must not be kept
* after the {@link AnimationStateListener#dispose(TrackEntry)} event occurs. */ * after the {@link AnimationStateListener#dispose(TrackEntry)} event occurs. */
public TrackEntry addAnimation (int trackIndex, Animation animation, boolean loop, float delay) { public TrackEntry addAnimation (int trackIndex, Animation animation, boolean loop, float delay) {
if (trackIndex < 0) throw new IllegalArgumentException("trackIndex must be >= 0.");
if (animation == null) throw new IllegalArgumentException("animation cannot be null."); if (animation == null) throw new IllegalArgumentException("animation cannot be null.");
TrackEntry last = expandToIndex(trackIndex); TrackEntry last = expandToIndex(trackIndex);
@ -783,6 +786,7 @@ public class AnimationState {
/** Returns the track entry for the animation currently playing on the track, or null if no animation is currently playing. */ /** Returns the track entry for the animation currently playing on the track, or null if no animation is currently playing. */
public TrackEntry getCurrent (int trackIndex) { public TrackEntry getCurrent (int trackIndex) {
if (trackIndex < 0) throw new IllegalArgumentException("trackIndex must be >= 0.");
if (trackIndex >= tracks.size) return null; if (trackIndex >= tracks.size) return null;
return tracks.get(trackIndex); return tracks.get(trackIndex);
} }
@ -892,6 +896,7 @@ public class AnimationState {
} }
public void setAnimation (Animation animation) { public void setAnimation (Animation animation) {
if (animation == null) throw new IllegalArgumentException("animation cannot be null.");
this.animation = animation; this.animation = animation;
} }
@ -1124,6 +1129,7 @@ public class AnimationState {
} }
public void setMixBlend (MixBlend mixBlend) { public void setMixBlend (MixBlend mixBlend) {
if (mixBlend == null) throw new IllegalArgumentException("mixBlend cannot be null.");
this.mixBlend = mixBlend; this.mixBlend = mixBlend;
} }
@ -1178,40 +1184,40 @@ public class AnimationState {
private final Array objects = new Array(); private final Array objects = new Array();
boolean drainDisabled; boolean drainDisabled;
public void start (TrackEntry entry) { void start (TrackEntry entry) {
objects.add(EventType.start); objects.add(EventType.start);
objects.add(entry); objects.add(entry);
animationsChanged = true; animationsChanged = true;
} }
public void interrupt (TrackEntry entry) { void interrupt (TrackEntry entry) {
objects.add(EventType.interrupt); objects.add(EventType.interrupt);
objects.add(entry); objects.add(entry);
} }
public void end (TrackEntry entry) { void end (TrackEntry entry) {
objects.add(EventType.end); objects.add(EventType.end);
objects.add(entry); objects.add(entry);
animationsChanged = true; animationsChanged = true;
} }
public void dispose (TrackEntry entry) { void dispose (TrackEntry entry) {
objects.add(EventType.dispose); objects.add(EventType.dispose);
objects.add(entry); objects.add(entry);
} }
public void complete (TrackEntry entry) { void complete (TrackEntry entry) {
objects.add(EventType.complete); objects.add(EventType.complete);
objects.add(entry); objects.add(entry);
} }
public void event (TrackEntry entry, Event event) { void event (TrackEntry entry, Event event) {
objects.add(EventType.event); objects.add(EventType.event);
objects.add(entry); objects.add(entry);
objects.add(event); objects.add(event);
} }
public void drain () { void drain () {
if (drainDisabled) return; // Not reentrant. if (drainDisabled) return; // Not reentrant.
drainDisabled = true; drainDisabled = true;
@ -1260,7 +1266,7 @@ public class AnimationState {
drainDisabled = false; drainDisabled = false;
} }
public void clear () { void clear () {
objects.clear(); objects.clear();
} }
} }

View File

@ -55,5 +55,5 @@ public enum BlendMode {
return dest; return dest;
} }
static public BlendMode[] values = values(); static public final BlendMode[] values = values();
} }

View File

@ -538,6 +538,7 @@ public class Bone implements Updatable {
/** Transforms a point from world coordinates to the bone's local coordinates. */ /** Transforms a point from world coordinates to the bone's local coordinates. */
public Vector2 worldToLocal (Vector2 world) { public Vector2 worldToLocal (Vector2 world) {
if (world == null) throw new IllegalArgumentException("world cannot be null.");
float invDet = 1 / (a * d - b * c); float invDet = 1 / (a * d - b * c);
float x = world.x - worldX, y = world.y - worldY; float x = world.x - worldX, y = world.y - worldY;
world.x = x * d * invDet - y * b * invDet; world.x = x * d * invDet - y * b * invDet;
@ -547,6 +548,7 @@ public class Bone implements Updatable {
/** Transforms a point from the bone's local coordinates to world coordinates. */ /** Transforms a point from the bone's local coordinates to world coordinates. */
public Vector2 localToWorld (Vector2 local) { public Vector2 localToWorld (Vector2 local) {
if (local == null) throw new IllegalArgumentException("local cannot be null.");
float x = local.x, y = local.y; float x = local.x, y = local.y;
local.x = x * a + y * b + worldX; local.x = x * a + y * b + worldX;
local.y = x * c + y * d + worldY; local.y = x * c + y * d + worldY;

View File

@ -173,6 +173,7 @@ public class BoneData {
} }
public void setTransformMode (TransformMode transformMode) { public void setTransformMode (TransformMode transformMode) {
if (transformMode == null) throw new IllegalArgumentException("transformMode cannot be null.");
this.transformMode = transformMode; this.transformMode = transformMode;
} }

View File

@ -73,6 +73,7 @@ public class Event {
} }
public void setString (String stringValue) { public void setString (String stringValue) {
if (stringValue == null) throw new IllegalArgumentException("stringValue cannot be null.");
this.stringValue = stringValue; this.stringValue = stringValue;
} }

View File

@ -65,6 +65,7 @@ public class EventData {
} }
public void setString (String stringValue) { public void setString (String stringValue) {
if (stringValue == null) throw new IllegalArgumentException("stringValue cannot be null.");
this.stringValue = stringValue; this.stringValue = stringValue;
} }
@ -73,6 +74,7 @@ public class EventData {
} }
public void setAudioPath (String audioPath) { public void setAudioPath (String audioPath) {
if (audioPath == null) throw new IllegalArgumentException("audioPath cannot be null.");
this.audioPath = audioPath; this.audioPath = audioPath;
} }

View File

@ -106,6 +106,7 @@ public class IkConstraint implements Updatable {
} }
public void setTarget (Bone target) { public void setTarget (Bone target) {
if (target == null) throw new IllegalArgumentException("target cannot be null.");
this.target = target; this.target = target;
} }
@ -162,6 +163,7 @@ public class IkConstraint implements Updatable {
/** Applies 1 bone IK. The target is specified in the world coordinate system. */ /** Applies 1 bone IK. The target is specified in the world coordinate system. */
static public void apply (Bone bone, float targetX, float targetY, boolean compress, boolean stretch, boolean uniform, static public void apply (Bone bone, float targetX, float targetY, boolean compress, boolean stretch, boolean uniform,
float alpha) { float alpha) {
if (bone == null) throw new IllegalArgumentException("bone cannot be null.");
if (!bone.appliedValid) bone.updateAppliedTransform(); if (!bone.appliedValid) bone.updateAppliedTransform();
Bone p = bone.parent; Bone p = bone.parent;
float id = 1 / (p.a * p.d - p.b * p.c); float id = 1 / (p.a * p.d - p.b * p.c);
@ -188,6 +190,8 @@ public class IkConstraint implements Updatable {
/** Applies 2 bone IK. The target is specified in the world coordinate system. /** Applies 2 bone IK. The target is specified in the world coordinate system.
* @param child A direct descendant of the parent bone. */ * @param child A direct descendant of the parent bone. */
static public void apply (Bone parent, Bone child, float targetX, float targetY, int bendDir, boolean stretch, float alpha) { static public void apply (Bone parent, Bone child, float targetX, float targetY, int bendDir, boolean stretch, float alpha) {
if (parent == null) throw new IllegalArgumentException("parent cannot be null.");
if (child == null) throw new IllegalArgumentException("child cannot be null.");
if (alpha == 0) { if (alpha == 0) {
child.updateWorldTransform(); child.updateWorldTransform();
return; return;

View File

@ -497,6 +497,7 @@ public class PathConstraint implements Updatable {
} }
public void setTarget (Slot target) { public void setTarget (Slot target) {
if (target == null) throw new IllegalArgumentException("target cannot be null.");
this.target = target; this.target = target;
} }

View File

@ -58,6 +58,7 @@ public class PathConstraintData extends ConstraintData {
} }
public void setTarget (SlotData target) { public void setTarget (SlotData target) {
if (target == null) throw new IllegalArgumentException("target cannot be null.");
this.target = target; this.target = target;
} }
@ -67,6 +68,7 @@ public class PathConstraintData extends ConstraintData {
} }
public void setPositionMode (PositionMode positionMode) { public void setPositionMode (PositionMode positionMode) {
if (positionMode == null) throw new IllegalArgumentException("positionMode cannot be null.");
this.positionMode = positionMode; this.positionMode = positionMode;
} }
@ -76,6 +78,7 @@ public class PathConstraintData extends ConstraintData {
} }
public void setSpacingMode (SpacingMode spacingMode) { public void setSpacingMode (SpacingMode spacingMode) {
if (spacingMode == null) throw new IllegalArgumentException("spacingMode cannot be null.");
this.spacingMode = spacingMode; this.spacingMode = spacingMode;
} }
@ -85,6 +88,7 @@ public class PathConstraintData extends ConstraintData {
} }
public void setRotateMode (RotateMode rotateMode) { public void setRotateMode (RotateMode rotateMode) {
if (rotateMode == null) throw new IllegalArgumentException("rotateMode cannot be null.");
this.rotateMode = rotateMode; this.rotateMode = rotateMode;
} }

View File

@ -362,6 +362,7 @@ public class Skeleton {
* See <a href="http://esotericsoftware.com/spine-runtime-skeletons#World-transforms">World transforms</a> in the Spine * See <a href="http://esotericsoftware.com/spine-runtime-skeletons#World-transforms">World transforms</a> in the Spine
* Runtimes Guide. */ * Runtimes Guide. */
public void updateWorldTransform (Bone parent) { public void updateWorldTransform (Bone parent) {
if (parent == null) throw new IllegalArgumentException("parent cannot be null.");
// This partial update avoids computing the world transform for constrained bones when 1) the bone is not updated // This partial update avoids computing the world transform for constrained bones when 1) the bone is not updated
// before the constraint, 2) the constraint only needs to access the applied local transform, and 3) the constraint calls // before the constraint, 2) the constraint only needs to access the applied local transform, and 3) the constraint calls
// updateWorldTransform. // updateWorldTransform.
@ -462,6 +463,7 @@ public class Skeleton {
return bones; return bones;
} }
/** The list of bones and constraints, sorted in the order they should be updated, as computed by {@link #updateCache()}. */
public Array<Updatable> getUpdateCache () { public Array<Updatable> getUpdateCache () {
return updateCache; return updateCache;
} }
@ -473,7 +475,7 @@ public class Skeleton {
} }
/** Finds a bone by comparing each bone's name. It is more efficient to cache the results of this method than to call it /** Finds a bone by comparing each bone's name. It is more efficient to cache the results of this method than to call it
* multiple times. * repeatedly.
* @return May be null. */ * @return May be null. */
public Bone findBone (String boneName) { public Bone findBone (String boneName) {
if (boneName == null) throw new IllegalArgumentException("boneName cannot be null."); if (boneName == null) throw new IllegalArgumentException("boneName cannot be null.");
@ -491,7 +493,7 @@ public class Skeleton {
} }
/** Finds a slot by comparing each slot's name. It is more efficient to cache the results of this method than to call it /** Finds a slot by comparing each slot's name. It is more efficient to cache the results of this method than to call it
* multiple times. * repeatedly.
* @return May be null. */ * @return May be null. */
public Slot findSlot (String slotName) { public Slot findSlot (String slotName) {
if (slotName == null) throw new IllegalArgumentException("slotName cannot be null."); if (slotName == null) throw new IllegalArgumentException("slotName cannot be null.");
@ -607,7 +609,7 @@ public class Skeleton {
} }
/** Finds an IK constraint by comparing each IK constraint's name. It is more efficient to cache the results of this method /** Finds an IK constraint by comparing each IK constraint's name. It is more efficient to cache the results of this method
* than to call it multiple times. * than to call it repeatedly.
* @return May be null. */ * @return May be null. */
public IkConstraint findIkConstraint (String constraintName) { public IkConstraint findIkConstraint (String constraintName) {
if (constraintName == null) throw new IllegalArgumentException("constraintName cannot be null."); if (constraintName == null) throw new IllegalArgumentException("constraintName cannot be null.");
@ -625,7 +627,7 @@ public class Skeleton {
} }
/** Finds a transform constraint by comparing each transform constraint's name. It is more efficient to cache the results of /** Finds a transform constraint by comparing each transform constraint's name. It is more efficient to cache the results of
* this method than to call it multiple times. * this method than to call it repeatedly.
* @return May be null. */ * @return May be null. */
public TransformConstraint findTransformConstraint (String constraintName) { public TransformConstraint findTransformConstraint (String constraintName) {
if (constraintName == null) throw new IllegalArgumentException("constraintName cannot be null."); if (constraintName == null) throw new IllegalArgumentException("constraintName cannot be null.");
@ -643,7 +645,7 @@ public class Skeleton {
} }
/** Finds a path constraint by comparing each path constraint's name. It is more efficient to cache the results of this method /** Finds a path constraint by comparing each path constraint's name. It is more efficient to cache the results of this method
* than to call it multiple times. * than to call it repeatedly.
* @return May be null. */ * @return May be null. */
public PathConstraint findPathConstraint (String constraintName) { public PathConstraint findPathConstraint (String constraintName) {
if (constraintName == null) throw new IllegalArgumentException("constraintName cannot be null."); if (constraintName == null) throw new IllegalArgumentException("constraintName cannot be null.");
@ -658,10 +660,11 @@ public class Skeleton {
/** Returns the axis aligned bounding box (AABB) of the region and mesh attachments for the current pose. /** Returns the axis aligned bounding box (AABB) of the region and mesh attachments for the current pose.
* @param offset An output value, the distance from the skeleton origin to the bottom left corner of the AABB. * @param offset An output value, the distance from the skeleton origin to the bottom left corner of the AABB.
* @param size An output value, the width and height of the AABB. * @param size An output value, the width and height of the AABB.
* @param temp Working memory. */ * @param temp Working memory to temporarily store attachments' computed world vertices. */
public void getBounds (Vector2 offset, Vector2 size, FloatArray temp) { public void getBounds (Vector2 offset, Vector2 size, FloatArray temp) {
if (offset == null) throw new IllegalArgumentException("offset cannot be null."); if (offset == null) throw new IllegalArgumentException("offset cannot be null.");
if (size == null) throw new IllegalArgumentException("size cannot be null."); if (size == null) throw new IllegalArgumentException("size cannot be null.");
if (temp == null) throw new IllegalArgumentException("temp cannot be null.");
Array<Slot> drawOrder = this.drawOrder; Array<Slot> drawOrder = this.drawOrder;
float minX = Integer.MAX_VALUE, minY = Integer.MAX_VALUE, maxX = Integer.MIN_VALUE, maxY = Integer.MIN_VALUE; float minX = Integer.MAX_VALUE, minY = Integer.MAX_VALUE, maxX = Integer.MIN_VALUE, maxY = Integer.MIN_VALUE;
for (int i = 0, n = drawOrder.size; i < n; i++) { for (int i = 0, n = drawOrder.size; i < n; i++) {
@ -748,6 +751,7 @@ public class Skeleton {
this.y = y; this.y = y;
} }
/** Sets the skeleton X and Y position, which is added to the root bone worldX and worldY position. */
public void setPosition (float x, float y) { public void setPosition (float x, float y) {
this.x = x; this.x = x;
this.y = y; this.y = y;

View File

@ -122,6 +122,7 @@ public class SkeletonBinary {
} }
public void setScale (float scale) { public void setScale (float scale) {
if (scale == 0) throw new IllegalArgumentException("scale cannot be 0.");
this.scale = scale; this.scale = scale;
} }

View File

@ -35,8 +35,8 @@ import com.badlogic.gdx.utils.Pool;
import com.esotericsoftware.spine.attachments.Attachment; import com.esotericsoftware.spine.attachments.Attachment;
import com.esotericsoftware.spine.attachments.BoundingBoxAttachment; import com.esotericsoftware.spine.attachments.BoundingBoxAttachment;
/** Collects each {@link BoundingBoxAttachment} that is visible and computes the world vertices for its polygon. The polygon /** Collects each visible {@link BoundingBoxAttachment} and computes the world vertices for its polygon. The polygon vertices are
* vertices are provided along with convenience methods for doing hit detection. */ * provided along with convenience methods for doing hit detection. */
public class SkeletonBounds { public class SkeletonBounds {
private float minX, minY, maxX, maxY; private float minX, minY, maxX, maxY;
private Array<BoundingBoxAttachment> boundingBoxes = new Array(); private Array<BoundingBoxAttachment> boundingBoxes = new Array();
@ -135,6 +135,7 @@ public class SkeletonBounds {
/** Returns true if the axis aligned bounding box intersects the axis aligned bounding box of the specified bounds. */ /** Returns true if the axis aligned bounding box intersects the axis aligned bounding box of the specified bounds. */
public boolean aabbIntersectsSkeleton (SkeletonBounds bounds) { public boolean aabbIntersectsSkeleton (SkeletonBounds bounds) {
if (bounds == null) throw new IllegalArgumentException("bounds cannot be null.");
return minX < bounds.maxX && maxX > bounds.minX && minY < bounds.maxY && maxY > bounds.minY; return minX < bounds.maxX && maxX > bounds.minX && minY < bounds.maxY && maxY > bounds.minY;
} }
@ -149,6 +150,7 @@ public class SkeletonBounds {
/** Returns true if the polygon contains the point. */ /** Returns true if the polygon contains the point. */
public boolean containsPoint (FloatArray polygon, float x, float y) { public boolean containsPoint (FloatArray polygon, float x, float y) {
if (polygon == null) throw new IllegalArgumentException("polygon cannot be null.");
float[] vertices = polygon.items; float[] vertices = polygon.items;
int nn = polygon.size; int nn = polygon.size;
@ -178,6 +180,7 @@ public class SkeletonBounds {
/** Returns true if the polygon contains any part of the line segment. */ /** Returns true if the polygon contains any part of the line segment. */
public boolean intersectsSegment (FloatArray polygon, float x1, float y1, float x2, float y2) { public boolean intersectsSegment (FloatArray polygon, float x1, float y1, float x2, float y2) {
if (polygon == null) throw new IllegalArgumentException("polygon cannot be null.");
float[] vertices = polygon.items; float[] vertices = polygon.items;
int nn = polygon.size; int nn = polygon.size;

View File

@ -99,10 +99,12 @@ public class SkeletonJson {
} }
public void setScale (float scale) { public void setScale (float scale) {
if (scale == 0) throw new IllegalArgumentException("scale cannot be 0.");
this.scale = scale; this.scale = scale;
} }
protected JsonValue parse (FileHandle file) { protected JsonValue parse (FileHandle file) {
if (file == null) throw new IllegalArgumentException("file cannot be null.");
return new JsonReader().parse(file); return new JsonReader().parse(file);
} }

View File

@ -29,14 +29,6 @@
package com.esotericsoftware.spine; package com.esotericsoftware.spine;
import com.esotericsoftware.spine.attachments.Attachment;
import com.esotericsoftware.spine.attachments.ClippingAttachment;
import com.esotericsoftware.spine.attachments.MeshAttachment;
import com.esotericsoftware.spine.attachments.RegionAttachment;
import com.esotericsoftware.spine.attachments.SkeletonAttachment;
import com.esotericsoftware.spine.utils.SkeletonClipping;
import com.esotericsoftware.spine.utils.TwoColorPolygonBatch;
import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Batch; import com.badlogic.gdx.graphics.g2d.Batch;
@ -47,6 +39,14 @@ import com.badlogic.gdx.utils.FloatArray;
import com.badlogic.gdx.utils.NumberUtils; import com.badlogic.gdx.utils.NumberUtils;
import com.badlogic.gdx.utils.ShortArray; import com.badlogic.gdx.utils.ShortArray;
import com.esotericsoftware.spine.attachments.Attachment;
import com.esotericsoftware.spine.attachments.ClippingAttachment;
import com.esotericsoftware.spine.attachments.MeshAttachment;
import com.esotericsoftware.spine.attachments.RegionAttachment;
import com.esotericsoftware.spine.attachments.SkeletonAttachment;
import com.esotericsoftware.spine.utils.SkeletonClipping;
import com.esotericsoftware.spine.utils.TwoColorPolygonBatch;
public class SkeletonRenderer { public class SkeletonRenderer {
static private final short[] quadTriangles = {0, 1, 2, 2, 3, 0}; static private final short[] quadTriangles = {0, 1, 2, 2, 3, 0};
@ -72,10 +72,13 @@ public class SkeletonRenderer {
if (batch instanceof TwoColorPolygonBatch) { if (batch instanceof TwoColorPolygonBatch) {
draw((TwoColorPolygonBatch)batch, skeleton); draw((TwoColorPolygonBatch)batch, skeleton);
return; return;
} else if (batch instanceof PolygonSpriteBatch) { }
if (batch instanceof PolygonSpriteBatch) {
draw((PolygonSpriteBatch)batch, skeleton); draw((PolygonSpriteBatch)batch, skeleton);
return; return;
} }
if (batch == null) throw new IllegalArgumentException("batch cannot be null.");
if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null.");
VertexEffect vertexEffect = this.vertexEffect; VertexEffect vertexEffect = this.vertexEffect;
if (vertexEffect != null) vertexEffect.begin(skeleton); if (vertexEffect != null) vertexEffect.begin(skeleton);
@ -148,12 +151,12 @@ public class SkeletonRenderer {
* next. */ * next. */
@SuppressWarnings("null") @SuppressWarnings("null")
public void draw (PolygonSpriteBatch batch, Skeleton skeleton) { public void draw (PolygonSpriteBatch batch, Skeleton skeleton) {
Vector2 tempPos = this.temp; if (batch == null) throw new IllegalArgumentException("batch cannot be null.");
Vector2 tempUv = this.temp2; if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null.");
Color tempLight = this.temp3;
Color tempDark = this.temp4; Vector2 tempPosition = this.temp, tempUV = this.temp2;
Color temp5 = this.temp5; Color tempLight1 = this.temp3, tempDark1 = this.temp4;
Color temp6 = this.temp6; Color tempLight2 = this.temp5, tempDark2 = this.temp6;
VertexEffect vertexEffect = this.vertexEffect; VertexEffect vertexEffect = this.vertexEffect;
if (vertexEffect != null) vertexEffect.begin(skeleton); if (vertexEffect != null) vertexEffect.begin(skeleton);
@ -231,21 +234,21 @@ public class SkeletonRenderer {
clippedTriangles.size); clippedTriangles.size);
} else { } else {
if (vertexEffect != null) { if (vertexEffect != null) {
temp5.set(NumberUtils.floatToIntColor(c)); tempLight1.set(NumberUtils.floatToIntColor(c));
temp6.set(0); tempDark1.set(0);
for (int v = 0, u = 0; v < verticesLength; v += 5, u += 2) { for (int v = 0, u = 0; v < verticesLength; v += 5, u += 2) {
tempPos.x = vertices[v]; tempPosition.x = vertices[v];
tempPos.y = vertices[v + 1]; tempPosition.y = vertices[v + 1];
tempLight.set(temp5); tempLight2.set(tempLight1);
tempDark.set(temp6); tempDark2.set(tempDark1);
tempUv.x = uvs[u]; tempUV.x = uvs[u];
tempUv.y = uvs[u + 1]; tempUV.y = uvs[u + 1];
vertexEffect.transform(tempPos, tempUv, tempLight, tempDark); vertexEffect.transform(tempPosition, tempUV, tempLight2, tempDark2);
vertices[v] = tempPos.x; vertices[v] = tempPosition.x;
vertices[v + 1] = tempPos.y; vertices[v + 1] = tempPosition.y;
vertices[v + 2] = tempLight.toFloatBits(); vertices[v + 2] = tempLight2.toFloatBits();
vertices[v + 3] = tempUv.x; vertices[v + 3] = tempUV.x;
vertices[v + 4] = tempUv.y; vertices[v + 4] = tempUV.y;
} }
} else { } else {
for (int v = 2, u = 0; v < verticesLength; v += 5, u += 2) { for (int v = 2, u = 0; v < verticesLength; v += 5, u += 2) {
@ -271,12 +274,12 @@ public class SkeletonRenderer {
* next. */ * next. */
@SuppressWarnings("null") @SuppressWarnings("null")
public void draw (TwoColorPolygonBatch batch, Skeleton skeleton) { public void draw (TwoColorPolygonBatch batch, Skeleton skeleton) {
Vector2 tempPos = this.temp; if (batch == null) throw new IllegalArgumentException("batch cannot be null.");
Vector2 tempUv = this.temp2; if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null.");
Color tempLight = this.temp3;
Color tempDark = this.temp4; Vector2 tempPosition = this.temp, tempUV = this.temp2;
Color temp5 = this.temp5; Color tempLight1 = this.temp3, tempDark1 = this.temp4;
Color temp6 = this.temp6; Color tempLight2 = this.temp5, tempDark2 = this.temp6;
VertexEffect vertexEffect = this.vertexEffect; VertexEffect vertexEffect = this.vertexEffect;
if (vertexEffect != null) vertexEffect.begin(skeleton); if (vertexEffect != null) vertexEffect.begin(skeleton);
@ -363,22 +366,22 @@ public class SkeletonRenderer {
clippedTriangles.size); clippedTriangles.size);
} else { } else {
if (vertexEffect != null) { if (vertexEffect != null) {
temp5.set(NumberUtils.floatToIntColor(light)); tempLight1.set(NumberUtils.floatToIntColor(light));
temp6.set(NumberUtils.floatToIntColor(dark)); tempDark1.set(NumberUtils.floatToIntColor(dark));
for (int v = 0, u = 0; v < verticesLength; v += 6, u += 2) { for (int v = 0, u = 0; v < verticesLength; v += 6, u += 2) {
tempPos.x = vertices[v]; tempPosition.x = vertices[v];
tempPos.y = vertices[v + 1]; tempPosition.y = vertices[v + 1];
tempLight.set(temp5); tempLight2.set(tempLight1);
tempDark.set(temp6); tempDark2.set(tempDark1);
tempUv.x = uvs[u]; tempUV.x = uvs[u];
tempUv.y = uvs[u + 1]; tempUV.y = uvs[u + 1];
vertexEffect.transform(tempPos, tempUv, tempLight, tempDark); vertexEffect.transform(tempPosition, tempUV, tempLight2, tempDark2);
vertices[v] = tempPos.x; vertices[v] = tempPosition.x;
vertices[v + 1] = tempPos.y; vertices[v + 1] = tempPosition.y;
vertices[v + 2] = tempLight.toFloatBits(); vertices[v + 2] = tempLight2.toFloatBits();
vertices[v + 3] = tempDark.toFloatBits(); vertices[v + 3] = tempDark2.toFloatBits();
vertices[v + 4] = tempUv.x; vertices[v + 4] = tempUV.x;
vertices[v + 5] = tempUv.y; vertices[v + 5] = tempUV.y;
} }
} else { } else {
for (int v = 2, u = 0; v < verticesLength; v += 6, u += 2) { for (int v = 2, u = 0; v < verticesLength; v += 6, u += 2) {
@ -399,45 +402,42 @@ public class SkeletonRenderer {
} }
private void applyVertexEffect (float[] vertices, int verticesLength, int stride, float light, float dark) { private void applyVertexEffect (float[] vertices, int verticesLength, int stride, float light, float dark) {
Vector2 tempPos = this.temp; Vector2 tempPosition = this.temp, tempUV = this.temp2;
Vector2 tempUv = this.temp2; Color tempLight1 = this.temp3, tempDark1 = this.temp4;
Color tempLight = this.temp3; Color tempLight2 = this.temp5, tempDark2 = this.temp6;
Color tempDark = this.temp4;
Color temp5 = this.temp5;
Color temp6 = this.temp6;
VertexEffect vertexEffect = this.vertexEffect; VertexEffect vertexEffect = this.vertexEffect;
temp5.set(NumberUtils.floatToIntColor(light)); tempLight1.set(NumberUtils.floatToIntColor(light));
temp6.set(NumberUtils.floatToIntColor(dark)); tempDark1.set(NumberUtils.floatToIntColor(dark));
if (stride == 5) { if (stride == 5) {
for (int v = 0; v < verticesLength; v += stride) { for (int v = 0; v < verticesLength; v += stride) {
tempPos.x = vertices[v]; tempPosition.x = vertices[v];
tempPos.y = vertices[v + 1]; tempPosition.y = vertices[v + 1];
tempUv.x = vertices[v + 3]; tempUV.x = vertices[v + 3];
tempUv.y = vertices[v + 4]; tempUV.y = vertices[v + 4];
tempLight.set(temp5); tempLight2.set(tempLight1);
tempDark.set(temp6); tempDark2.set(tempDark1);
vertexEffect.transform(tempPos, tempUv, tempLight, tempDark); vertexEffect.transform(tempPosition, tempUV, tempLight2, tempDark2);
vertices[v] = tempPos.x; vertices[v] = tempPosition.x;
vertices[v + 1] = tempPos.y; vertices[v + 1] = tempPosition.y;
vertices[v + 2] = tempLight.toFloatBits(); vertices[v + 2] = tempLight2.toFloatBits();
vertices[v + 3] = tempUv.x; vertices[v + 3] = tempUV.x;
vertices[v + 4] = tempUv.y; vertices[v + 4] = tempUV.y;
} }
} else { } else {
for (int v = 0; v < verticesLength; v += stride) { for (int v = 0; v < verticesLength; v += stride) {
tempPos.x = vertices[v]; tempPosition.x = vertices[v];
tempPos.y = vertices[v + 1]; tempPosition.y = vertices[v + 1];
tempUv.x = vertices[v + 4]; tempUV.x = vertices[v + 4];
tempUv.y = vertices[v + 5]; tempUV.y = vertices[v + 5];
tempLight.set(temp5); tempLight2.set(tempLight1);
tempDark.set(temp6); tempDark2.set(tempDark1);
vertexEffect.transform(tempPos, tempUv, tempLight, tempDark); vertexEffect.transform(tempPosition, tempUV, tempLight2, tempDark2);
vertices[v] = tempPos.x; vertices[v] = tempPosition.x;
vertices[v + 1] = tempPos.y; vertices[v + 1] = tempPosition.y;
vertices[v + 2] = tempLight.toFloatBits(); vertices[v + 2] = tempLight2.toFloatBits();
vertices[v + 3] = tempDark.toFloatBits(); vertices[v + 3] = tempDark2.toFloatBits();
vertices[v + 4] = tempUv.x; vertices[v + 4] = tempUV.x;
vertices[v + 5] = tempUv.y; vertices[v + 5] = tempUV.y;
} }
} }
} }
@ -450,14 +450,17 @@ public class SkeletonRenderer {
this.premultipliedAlpha = premultipliedAlpha; this.premultipliedAlpha = premultipliedAlpha;
} }
/** @return May be null. */
public VertexEffect getVertexEffect () { public VertexEffect getVertexEffect () {
return vertexEffect; return vertexEffect;
} }
/** @param vertexEffect May be null. */
public void setVertexEffect (VertexEffect vertexEffect) { public void setVertexEffect (VertexEffect vertexEffect) {
this.vertexEffect = vertexEffect; this.vertexEffect = vertexEffect;
} }
/** Modifies the skeleton or vertex positions, UVs, or colors during rendering. */
static public interface VertexEffect { static public interface VertexEffect {
public void begin (Skeleton skeleton); public void begin (Skeleton skeleton);

View File

@ -67,10 +67,13 @@ public class SkeletonRendererDebug {
} }
public SkeletonRendererDebug (ShapeRenderer shapes) { public SkeletonRendererDebug (ShapeRenderer shapes) {
if (shapes == null) throw new IllegalArgumentException("shapes cannot be null.");
this.shapes = shapes; this.shapes = shapes;
} }
public void draw (Skeleton skeleton) { public void draw (Skeleton skeleton) {
if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null.");
Gdx.gl.glEnable(GL20.GL_BLEND); Gdx.gl.glEnable(GL20.GL_BLEND);
int srcFunc = premultipliedAlpha ? GL20.GL_ONE : GL20.GL_SRC_ALPHA; int srcFunc = premultipliedAlpha ? GL20.GL_ONE : GL20.GL_SRC_ALPHA;
Gdx.gl.glBlendFunc(srcFunc, GL20.GL_ONE_MINUS_SRC_ALPHA); Gdx.gl.glBlendFunc(srcFunc, GL20.GL_ONE_MINUS_SRC_ALPHA);

View File

@ -31,6 +31,7 @@ package com.esotericsoftware.spine;
import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.OrderedMap; import com.badlogic.gdx.utils.OrderedMap;
import com.esotericsoftware.spine.attachments.Attachment; import com.esotericsoftware.spine.attachments.Attachment;
import com.esotericsoftware.spine.attachments.MeshAttachment; import com.esotericsoftware.spine.attachments.MeshAttachment;
@ -53,13 +54,15 @@ public class Skin {
/** Adds an attachment to the skin for the specified slot index and name. */ /** Adds an attachment to the skin for the specified slot index and name. */
public void setAttachment (int slotIndex, String name, Attachment attachment) { public void setAttachment (int slotIndex, String name, Attachment attachment) {
if (attachment == null) throw new IllegalArgumentException("attachment cannot be null.");
if (slotIndex < 0) throw new IllegalArgumentException("slotIndex must be >= 0."); if (slotIndex < 0) throw new IllegalArgumentException("slotIndex must be >= 0.");
if (attachment == null) throw new IllegalArgumentException("attachment cannot be null.");
attachments.put(new SkinEntry(slotIndex, name, attachment), attachment); attachments.put(new SkinEntry(slotIndex, name, attachment), attachment);
} }
/** Adds all attachments, bones, and constraints from the specified skin to this skin. */ /** Adds all attachments, bones, and constraints from the specified skin to this skin. */
public void addSkin (Skin skin) { public void addSkin (Skin skin) {
if (skin == null) throw new IllegalArgumentException("skin cannot be null.");
for (BoneData data : skin.bones) for (BoneData data : skin.bones)
if (!bones.contains(data, true)) bones.add(data); if (!bones.contains(data, true)) bones.add(data);
@ -70,8 +73,11 @@ public class Skin {
setAttachment(entry.slotIndex, entry.name, entry.attachment); setAttachment(entry.slotIndex, entry.name, entry.attachment);
} }
/** Adds all attachments, bones, and constraints from the specified skin to this skin. Attachments are deep copied. */ /** Adds all bones and constraints and copies of all attachments from the specified skin to this skin. Mesh attachments are not
* copied, instead a new linked mesh is created. The attachment copies can be modified without affecting the originals. */
public void copySkin (Skin skin) { public void copySkin (Skin skin) {
if (skin == null) throw new IllegalArgumentException("skin cannot be null.");
for (BoneData data : skin.bones) for (BoneData data : skin.bones)
if (!bones.contains(data, true)) bones.add(data); if (!bones.contains(data, true)) bones.add(data);
@ -80,8 +86,7 @@ public class Skin {
for (SkinEntry entry : skin.attachments.keys()) { for (SkinEntry entry : skin.attachments.keys()) {
if (entry.attachment instanceof MeshAttachment) if (entry.attachment instanceof MeshAttachment)
setAttachment(entry.slotIndex, entry.name, setAttachment(entry.slotIndex, entry.name, ((MeshAttachment)entry.attachment).newLinkedMesh());
entry.attachment != null ? ((MeshAttachment)entry.attachment).newLinkedMesh() : null);
else else
setAttachment(entry.slotIndex, entry.name, entry.attachment != null ? entry.attachment.copy() : null); setAttachment(entry.slotIndex, entry.name, entry.attachment != null ? entry.attachment.copy() : null);
} }
@ -108,6 +113,8 @@ public class Skin {
/** Returns all attachments in this skin for the specified slot index. */ /** Returns all attachments in this skin for the specified slot index. */
public void getAttachments (int slotIndex, Array<SkinEntry> attachments) { public void getAttachments (int slotIndex, Array<SkinEntry> attachments) {
if (slotIndex < 0) throw new IllegalArgumentException("slotIndex must be >= 0.");
if (attachments == null) throw new IllegalArgumentException("attachments cannot be null.");
for (SkinEntry entry : this.attachments.keys()) for (SkinEntry entry : this.attachments.keys())
if (entry.slotIndex == slotIndex) attachments.add(entry); if (entry.slotIndex == slotIndex) attachments.add(entry);
} }

View File

@ -77,6 +77,7 @@ public class SlotData {
return darkColor; return darkColor;
} }
/** @param darkColor May be null. */
public void setDarkColor (Color darkColor) { public void setDarkColor (Color darkColor) {
this.darkColor = darkColor; this.darkColor = darkColor;
} }
@ -97,6 +98,7 @@ public class SlotData {
} }
public void setBlendMode (BlendMode blendMode) { public void setBlendMode (BlendMode blendMode) {
if (blendMode == null) throw new IllegalArgumentException("blendMode cannot be null.");
this.blendMode = blendMode; this.blendMode = blendMode;
} }

View File

@ -301,6 +301,7 @@ public class TransformConstraint implements Updatable {
} }
public void setTarget (Bone target) { public void setTarget (Bone target) {
if (target == null) throw new IllegalArgumentException("target cannot be null.");
this.target = target; this.target = target;
} }

View File

@ -33,8 +33,8 @@ package com.esotericsoftware.spine;
public interface Updatable { public interface Updatable {
public void update (); public void update ();
/** Returns false when this item has not been updated because a skine is required and the {@link Skeleton#getSkin() active /** Returns false when this item has not been updated because a skin is required and the {@link Skeleton#getSkin() active skin}
* skin} does not contain this item. * does not contain this item.
* @see Skin#getBones() * @see Skin#getBones()
* @see Skin#getConstraints() */ * @see Skin#getConstraints() */
public boolean isActive (); public boolean isActive ();

View File

@ -32,5 +32,5 @@ package com.esotericsoftware.spine.attachments;
public enum AttachmentType { public enum AttachmentType {
region, boundingbox, mesh, linkedmesh, path, point, clipping; region, boundingbox, mesh, linkedmesh, path, point, clipping;
static public AttachmentType[] values = values(); static public final AttachmentType[] values = values();
} }

View File

@ -259,7 +259,7 @@ public class MeshAttachment extends VertexAttachment {
return copy; return copy;
} }
/** Returns a new mesh with this mesh set as the {@link #parentMesh}. **/ /** Returns a new mesh with the {@link #parentMesh} set to this mesh's parent mesh, if any, else to this mesh. **/
public MeshAttachment newLinkedMesh () { public MeshAttachment newLinkedMesh () {
MeshAttachment mesh = new MeshAttachment(name); MeshAttachment mesh = new MeshAttachment(name);
mesh.region = region; mesh.region = region;