Explorar el Código

Bezier curve based animation now properly samples curves based on x (not t) except for quaternion curve animations, entity mouse events now contain ray depth information, entity editor will now select closest entity at first click, added visibility layers to SceneEntityInstance and visibility layer sheets to the entity editor

Ivan Safrin hace 11 años
padre
commit
7834ea4719
Se han modificado 27 ficheros con 789 adiciones y 351 borrados
  1. 1 0
      Bindings/Scripts/create_lua_library/create_lua_library.py
  2. 13 20
      Core/Contents/Include/PolyBezierCurve.h
  3. 6 1
      Core/Contents/Include/PolyEntity.h
  4. 2 0
      Core/Contents/Include/PolyInputEvent.h
  5. 2 4
      Core/Contents/Include/PolyQuaternionCurve.h
  6. 1 1
      Core/Contents/Include/PolyRay.h
  7. 24 1
      Core/Contents/Include/PolySceneEntityInstance.h
  8. 10 20
      Core/Contents/Include/PolySkeleton.h
  9. 46 29
      Core/Contents/Source/PolyBezierCurve.cpp
  10. 50 14
      Core/Contents/Source/PolyEntity.cpp
  11. 5 5
      Core/Contents/Source/PolyParticleEmitter.cpp
  12. 25 122
      Core/Contents/Source/PolyQuaternionCurve.cpp
  13. 9 5
      Core/Contents/Source/PolyRay.cpp
  14. 100 1
      Core/Contents/Source/PolySceneEntityInstance.cpp
  15. 59 65
      Core/Contents/Source/PolySkeleton.cpp
  16. 3 3
      IDE/Assets/ide_icons.ai
  17. 23 9
      IDE/Contents/Include/EntityEditorTreeView.h
  18. 16 1
      IDE/Contents/Include/PolycodeEntityEditor.h
  19. 51 0
      IDE/Contents/Include/PolycodeProps.h
  20. BIN
      IDE/Contents/Resources/ImagesRetina/entityEditor/button_more.png
  21. BIN
      IDE/Contents/Resources/ImagesRetina/entityEditor/invisible_button.png
  22. BIN
      IDE/Contents/Resources/ImagesRetina/entityEditor/visible_button.png
  23. 1 0
      IDE/Contents/Source/EntityEditorPropertyView.cpp
  24. 42 24
      IDE/Contents/Source/EntityEditorTreeView.cpp
  25. 70 21
      IDE/Contents/Source/PolycodeEntityEditor.cpp
  26. 1 2
      IDE/Contents/Source/PolycodeFrame.cpp
  27. 229 3
      IDE/Contents/Source/PolycodeProps.cpp

+ 1 - 0
Bindings/Scripts/create_lua_library/create_lua_library.py

@@ -52,6 +52,7 @@ def typeFilter(ty):
 	ty = ty.replace("virtual", "")
 	ty = ty.replace("&", "")
 	ty = re.sub(r'^.*\sint\s*$', 'int', ty) # eg "unsigned int"
+	ty = re.sub(r'^.*\schar\s*$', 'char', ty) # eg "unsigned int"
 	ty = re.sub(r'^.*\slong\s*$', 'int', ty)
 	ty = re.sub(r'^.*\sshort\s*$', 'int', ty)
 	ty = re.sub(r'^.*\sfloat\s*$', 'Number', ty)

+ 13 - 20
Core/Contents/Include/PolyBezierCurve.h

@@ -26,11 +26,10 @@
 
 #include "PolyGlobals.h"
 #include "PolyVector3.h"
+#include "PolyVector2.h"
 #include <vector>
 
 
-#define BUFFER_CACHE_PRECISION 100
-
 namespace Polycode {
 
 	/** 
@@ -143,12 +142,6 @@ namespace Polycode {
 		*/										
 		void addControlPoint2d(Number x, Number y);
 		
-		/**
-		* Returns the height of the curve at a specified point on the curve. Heights are cached into a buffer with a finite cache precision to speed up the curve usage in animation. If you need to quickly get 2D height out of a curve and you don't care about total precision, use this method.
-		* @param a Normalized (0-1) position along the curve.
-		* @return Height value at specified position.
-		*/												
-		Number getHeightAt(Number a);
 
 		/**
 		* Returns the 3d point of the curve at a specified point on the curve.
@@ -163,33 +156,33 @@ namespace Polycode {
 		* @return 3d point at specified position.
 		*/																				
 		Vector3 getPointBetween(Number a, BezierPoint *bp1, BezierPoint *bp2);
-		
+
 		void clearControlPoints();
-		
-		/** 
-		* Rebuilds the height cache buffers for 2d height curves.
-		*/	
-		void rebuildBuffers();
+        
+        Number getYValueAtX(Number x);
+		Number getTValueAtX(Number x);
 		
 		/**
 		* Removes (and deletes!) a given point by pointer
 		*/
 		void removePoint(BezierPoint *point);
-
-		Number heightBuffer[BUFFER_CACHE_PRECISION];
-
+        
 		BezierPoint *insertPoint;
 
 		std::vector<BezierPoint*> controlPoints;
 		std::vector<Number> distances;
 		
-		void recalculateDistances();		
+		void recalculateDistances();
+		
+        Number evaluationAccuracy;
 		
 		protected:
 		
+            Number minX;
+            Number maxX;
+            Number midX;
+        
             bool distancesDirty;
-
-	
 			
 	};
 

+ 6 - 1
Core/Contents/Include/PolyEntity.h

@@ -641,7 +641,10 @@ namespace Polycode {
 			
 			Entity *getEntityById(String id, bool recursive) const;
 			std::vector<Entity*> getEntitiesByTag(String tag, bool recursive) const;
-			
+
+            std::vector<Entity*> getEntitiesByLayerID(unsigned char layerID, bool recursive) const;
+        
+        
 			std::vector <EntityProp> entityProps;
 			String getEntityProp(const String& propName);
 			void setEntityProp(const String& propName, const String& propValue);
@@ -716,6 +719,8 @@ namespace Polycode {
             void setLocalBoundingBoxZ(Number z);
         
             bool rendererVis;
+        
+            unsigned char layerID;
 
 		protected:
 		

+ 2 - 0
Core/Contents/Include/PolyInputEvent.h

@@ -115,6 +115,8 @@ namespace Polycode {
 		unsigned int joystickButton;
 		unsigned int joystickAxis;
 		unsigned int joystickIndex;
+        
+        Number hitDistance;
 		
 		protected:
 		

+ 2 - 4
Core/Contents/Include/PolyQuaternionCurve.h

@@ -33,7 +33,8 @@ namespace Polycode {
 		public:
 		Quaternion q1;
 		Quaternion q2;
-		Quaternion q3;		
+		Quaternion q3;
+        Number time;
 	};	
 
 	class _PolyExport QuaternionCurve : public PolyBase {
@@ -45,12 +46,9 @@ namespace Polycode {
 			Quaternion interpolate(unsigned int fromIndex, Number t, bool useShortestPath);
 						
 			void generatePointsFromCurves(BezierCurve *wCurve, BezierCurve *xCurve, BezierCurve *yCurve, BezierCurve *zCurve);
-			void recalcTangents();
 		
 		protected:
 		
 			std::vector<QuatTriple> tPoints;
-			std::vector<Quaternion> points;
-			std::vector<Quaternion> tangents;
 	};
 }

+ 1 - 1
Core/Contents/Include/PolyRay.h

@@ -36,7 +36,7 @@ namespace Polycode {
 			Ray();
 			Ray(const Vector3 &origin, const Vector3 &direction);
 	
-			bool boxIntersect(const Vector3 &box, const Matrix4 &transformMatrix, float near = 0.0, float far = 9999.0) const;
+			Number boxIntersect(const Vector3 &box, const Matrix4 &transformMatrix, float near = 0.0, float far = 9999.0) const;
 			
 			Vector3 planeIntersectPoint(const Vector3 &planeNormal, Number planeDistance) const;
 			Ray tranformByMatrix(const Matrix4& matrix) const;

+ 24 - 1
Core/Contents/Include/PolySceneEntityInstance.h

@@ -36,7 +36,8 @@ THE SOFTWARE.
 namespace Polycode {
 
 class SceneEntityInstanceResourceEntry;
-
+    class SceneEntityInstanceLayer;
+    
 class SceneEntityInstance : public Entity {
 	public:
     
@@ -69,6 +70,13 @@ class SceneEntityInstance : public Entity {
     
         ResourcePool *getTopLevelResourcePool();
 
+        bool hasLayerID(unsigned char layerID) const;
+        unsigned int getNumLayers() const;
+        SceneEntityInstanceLayer *getLayerAtIndex(unsigned int index) const;
+        void removeLayer(SceneEntityInstanceLayer *layer);
+    
+    
+        SceneEntityInstanceLayer *createNewLayer(String name);
 		
 		String getFileName() const;
 		bool cloneUsingReload;
@@ -77,6 +85,8 @@ class SceneEntityInstance : public Entity {
 		
 	protected:
 		
+        std::vector<SceneEntityInstanceLayer*> layers;
+    
         void rebuildResourceLinks();
     
         ResourcePool *topLevelResourcePool;
@@ -85,6 +95,19 @@ class SceneEntityInstance : public Entity {
 		SceneEntityInstanceResourceEntry *resourceEntry;
 		
 };
+    
+class SceneEntityInstanceLayer {
+    public:
+        SceneEntityInstanceLayer(SceneEntityInstance *instance,String name);
+    
+        void setLayerVisibility(bool val);
+    
+        String name;
+        unsigned char layerID;
+        bool visible;
+        SceneEntityInstance *instance;
+};
+
 
 class SceneEntityInstanceResourceEntry : public Resource {
 	public:

+ 10 - 20
Core/Contents/Include/PolySkeleton.h

@@ -27,6 +27,7 @@ THE SOFTWARE.
 #include "PolyColor.h"
 #include "PolyVector3.h"
 #include "PolyQuaternion.h"
+#include "PolyQuaternionCurve.h"
 #include "PolyEntity.h"
 #include <vector>
 
@@ -40,13 +41,11 @@ namespace Polycode {
 	class _PolyExport BoneTrack : public PolyBase {
 		public:
 			BoneTrack(Bone *bone, Number length);
-        
-            void initTweens();
 			~BoneTrack();
         
 			void Play(bool once=false);
 			void Stop();
-			void Update();
+			void Update(Number elapsed);
             void Reset();
 		
 			void setSpeed(Number speed);
@@ -62,30 +61,21 @@ namespace Polycode {
 			BezierCurve *LocY;
 			BezierCurve *LocZ;
 			
-			Vector3 LocXVec;
-			Vector3 LocYVec;
-			Vector3 LocZVec;						
-
-			Vector3 ScaleXVec;
-			Vector3 ScaleYVec;
-			Vector3 ScaleZVec;						
-		
-		
+			Vector3 position;
+            Vector3 scale;
 			Quaternion boneQuat;
-			QuaternionTween *quatTween;
-			
-			Vector3 QuatWVec;
-			Vector3 QuatXVec;
-			Vector3 QuatYVec;			
-			Vector3 QuatZVec;		
-		
+            QuaternionCurve *quatCurve;
+        
             Number weight;
 			
 		protected:
 		
 			Number length;
+            Number speed;
+            bool paused;
+            Number time;
 			Bone *targetBone;
-			std::vector <BezierPathTween*> pathTweens;
+            bool playOnce;
 		
 	};
 

+ 46 - 29
Core/Contents/Source/PolyBezierCurve.cpp

@@ -39,19 +39,12 @@ BezierPoint::BezierPoint(Number p1x, Number p1y, Number p1z, Number p2x, Number
 
 BezierCurve::BezierCurve(){
 	insertPoint = NULL;
-	for(int i=0; i < BUFFER_CACHE_PRECISION; i++) {
-		heightBuffer[i] = 0;
-	}
-	
+	evaluationAccuracy = 0.01;
     distancesDirty =  false;
 }
 
 void BezierCurve::clearControlPoints() {
 	insertPoint = NULL;
-	for(int i=0; i < BUFFER_CACHE_PRECISION; i++) {
-		heightBuffer[i] = 0;
-	}
-	
     distancesDirty =  true;
 	for(int i=0; i < controlPoints.size(); i++) {
 		delete controlPoints[i];
@@ -103,6 +96,7 @@ void BezierCurve::addControlPoint2d(Number x, Number y) {
 void BezierCurve::recalculateDistances() {
 	if(controlPoints.size() < 2)
 		return;
+    
     distancesDirty = false;
 		
 	Number dist, lastDist = 0;
@@ -128,7 +122,10 @@ void BezierCurve::recalculateDistances() {
 		distances[i] = distances[i]/totalDistance;
 	}
     
-    rebuildBuffers();
+    minX = getPointAt(0.0).x;
+    maxX = getPointAt(1.0).x;
+    midX = getPointAt(0.5).x;
+    
 }
 
 Vector3 BezierCurve::getPointBetween(Number a, BezierPoint *bp1, BezierPoint *bp2) {
@@ -142,6 +139,46 @@ Vector3 BezierCurve::getPointBetween(Number a, BezierPoint *bp1, BezierPoint *bp
 	return retVector;
 }
 
+Number BezierCurve::getYValueAtX(Number x) {
+    return getPointAt(getTValueAtX(x)).y;
+}
+
+Number BezierCurve::getTValueAtX(Number x) {
+    if(controlPoints.size() < 2) {
+		return 0;
+    }
+    
+	if (distancesDirty)  {
+        recalculateDistances();
+    }    
+    
+    if(x <= minX) {
+        return 0.0;
+    }
+    if(x >= maxX) {
+        return 1.0;
+    }
+    
+    Number _x = midX;
+    
+    Number lower = 0.0;
+    Number upper = 1.0;
+    Number percent = (upper + lower) / 2.0;
+    
+    while(fabs(x - _x) > evaluationAccuracy) {
+        if(x  > _x) {
+            lower = percent;
+        } else {
+            upper = percent;
+        }
+        
+        percent = (upper + lower) / 2.0;
+        _x = getPointAt(percent).x;
+    }
+    
+    return percent;
+}
+
 BezierPoint *BezierCurve::getControlPoint(unsigned int index) {
 	return controlPoints[index];
 } 
@@ -161,26 +198,6 @@ void BezierCurve::removePoint(BezierPoint *point) {
     distancesDirty =  true;
 }
 
-Number BezierCurve::getHeightAt(Number a) {
-	if (distancesDirty)  {
-        recalculateDistances();
-    }
-	
-	int unsigned index = ((Number)(BUFFER_CACHE_PRECISION)) * a;
-	
-	if(index > BUFFER_CACHE_PRECISION-1)
-		index = BUFFER_CACHE_PRECISION-1;
-	return heightBuffer[index];
-	
-//	return getPointAt(a).y;
-}
-
-void BezierCurve::rebuildBuffers() {
-	for(int i=0; i < BUFFER_CACHE_PRECISION; i++) {
-		heightBuffer[i]	= getPointAt(((Number)i)/((Number)BUFFER_CACHE_PRECISION)).y;
-	}
-}
-
 Vector3 BezierCurve::getPointAt(Number a) {
     
 	if (distancesDirty)  {

+ 50 - 14
Core/Contents/Source/PolyEntity.cpp

@@ -78,6 +78,7 @@ void Entity::initEntity() {
 	yAdjust = 1.0;
 	lastClickTicks = 0.0;
     rendererVis = true;
+    layerID = 0;
 }
 
 Entity *Entity::getEntityById(String id, bool recursive) const {
@@ -126,6 +127,7 @@ void Entity::applyClone(Entity *clone, bool deepClone, bool ignoreEditorOnly) co
 	clone->editorOnly = editorOnly;
 	clone->snapToPixels = snapToPixels;
     clone->setAnchorPoint(anchorPoint);
+    clone->layerID = layerID;
     
 	clone->id = id;
 	if(tags == NULL) {
@@ -156,6 +158,23 @@ void Entity::setOwnsChildrenRecursive(bool val) {
 	}
 }
 
+std::vector<Entity*> Entity::getEntitiesByLayerID(unsigned char layerID, bool recursive) const {
+	std::vector<Entity*> retVector;
+    
+	for(int i=0;i<children.size();i++) {
+		if(children[i]->layerID == layerID) {
+			retVector.push_back(children[i]);
+		}
+		
+		if(recursive) {
+			std::vector<Entity*> childVector = children[i]->getEntitiesByLayerID(layerID, recursive);
+			retVector.insert(retVector.end(), childVector.begin(), childVector.end());
+		}
+	}
+	
+	return retVector;
+}
+
 std::vector<Entity*> Entity::getEntitiesByTag(String tag, bool recursive) const {
 
 	std::vector<Entity*> retVector;
@@ -999,9 +1018,11 @@ MouseEventResult Entity::onMouseDown(const Ray &ray, int mouseButton, int timest
 	MouseEventResult ret;
 	ret.hit = false;
 	ret.blocked = false;
+    Number hitDistance;
 	
 	if(processInputEvents && enabled) {
-		if(ray.boxIntersect(bBox, getAnchorAdjustedMatrix())) {
+        hitDistance = ray.boxIntersect(bBox, getAnchorAdjustedMatrix());
+		if(hitDistance >= 0.0) {
 			if(customHitDetection(ray)) {
 				ret.hit = true;	
 				
@@ -1010,6 +1031,7 @@ MouseEventResult Entity::onMouseDown(const Ray &ray, int mouseButton, int timest
 				localCoordinate = inverse * localCoordinate;			
 				
 				InputEvent *inputEvent = new InputEvent(Vector2(localCoordinate.x, localCoordinate.y*yAdjust), timestamp);
+                inputEvent->hitDistance = hitDistance;
 				inputEvent->mouseButton = mouseButton;
 				dispatchEvent(inputEvent, InputEvent::EVENT_MOUSEDOWN);
 				
@@ -1044,7 +1066,8 @@ MouseEventResult Entity::onMouseUp(const Ray &ray, int mouseButton, int timestam
 	MouseEventResult ret;
 	ret.hit = false;
 	ret.blocked = false;
-	
+	Number hitDistance;
+    
 	if(processInputEvents && enabled) {
 	
 		Vector3 localCoordinate = Vector3(ray.origin.x,ray.origin.y,0);
@@ -1053,10 +1076,11 @@ MouseEventResult Entity::onMouseUp(const Ray &ray, int mouseButton, int timestam
 	
 		InputEvent *inputEvent = new InputEvent(Vector2(localCoordinate.x, localCoordinate.y*yAdjust), timestamp);
 		inputEvent->mouseButton = mouseButton;			
-	
-		if(ray.boxIntersect(bBox, getAnchorAdjustedMatrix())) {
+
+        hitDistance = ray.boxIntersect(bBox, getAnchorAdjustedMatrix());
+		if(hitDistance >= 0.0) {
 			ret.hit = true;
-			
+			inputEvent->hitDistance = hitDistance;
 			dispatchEvent(inputEvent, InputEvent::EVENT_MOUSEUP);
 			if(blockMouseInput) {
 				ret.blocked = true;
@@ -1082,20 +1106,26 @@ MouseEventResult Entity::onMouseMove(const Ray &ray, int timestamp) {
 	MouseEventResult ret;
 	ret.hit = false;
 	ret.blocked = false;
-	
+    Number hitDistance;
+    
 	if(processInputEvents && enabled) {
 	
 		Vector3 localCoordinate = Vector3(ray.origin.x,ray.origin.y,0);
 		Matrix4 inverse = getConcatenatedMatrix().Inverse();
 		localCoordinate = inverse * localCoordinate;	
-	
-		if(ray.boxIntersect(bBox, getAnchorAdjustedMatrix())) {	
+        
+        hitDistance = ray.boxIntersect(bBox, getAnchorAdjustedMatrix());
+		if(hitDistance >= 0.0) {
 			//setColor(1.0, 0.0, 0.0, 1.0);
-			ret.hit = true;			
-			dispatchEvent(new InputEvent(Vector2(localCoordinate.x, localCoordinate.y*yAdjust), timestamp), InputEvent::EVENT_MOUSEMOVE);
+			ret.hit = true;
+            InputEvent *inputEvent = new InputEvent(Vector2(localCoordinate.x, localCoordinate.y*yAdjust), timestamp);
+            inputEvent->hitDistance = hitDistance;
+			dispatchEvent(inputEvent, InputEvent::EVENT_MOUSEMOVE);
 			
 			if(!mouseOver) {
-				dispatchEvent(new InputEvent(Vector2(localCoordinate.x, localCoordinate.y*yAdjust), timestamp), InputEvent::EVENT_MOUSEOVER);
+                InputEvent *inputEvent = new InputEvent(Vector2(localCoordinate.x, localCoordinate.y*yAdjust), timestamp);
+                inputEvent->hitDistance = hitDistance;
+				dispatchEvent(inputEvent, InputEvent::EVENT_MOUSEOVER);
 				mouseOver = true;
 			}			
 			
@@ -1127,9 +1157,11 @@ MouseEventResult Entity::onMouseWheelUp(const Ray &ray, int timestamp) {
 	MouseEventResult ret;
 	ret.hit = false;
 	ret.blocked = false;
+    Number hitDistance;
 	
 	if(processInputEvents && enabled) {
-		if(ray.boxIntersect(bBox, getAnchorAdjustedMatrix())) {
+        hitDistance = ray.boxIntersect(bBox, getAnchorAdjustedMatrix());
+		if(hitDistance >= 0.0) {
 			ret.hit = true;	
 			
 			Vector3 localCoordinate = Vector3(ray.origin.x,ray.origin.y,0);
@@ -1137,6 +1169,7 @@ MouseEventResult Entity::onMouseWheelUp(const Ray &ray, int timestamp) {
 			localCoordinate = inverse * localCoordinate;			
 			
 			InputEvent *inputEvent = new InputEvent(Vector2(localCoordinate.x, localCoordinate.y*yAdjust), timestamp);
+            inputEvent->hitDistance = hitDistance;
 			dispatchEvent(inputEvent, InputEvent::EVENT_MOUSEWHEEL_UP);
 												
 			if(blockMouseInput) {
@@ -1162,9 +1195,11 @@ MouseEventResult Entity::onMouseWheelDown(const Ray &ray, int timestamp) {
 	MouseEventResult ret;
 	ret.hit = false;
 	ret.blocked = false;
-	
+	Number hitDistance;
+    
 	if(processInputEvents && enabled) {
-		if(ray.boxIntersect(bBox, getAnchorAdjustedMatrix())) {
+        hitDistance = ray.boxIntersect(bBox, getAnchorAdjustedMatrix());
+		if(hitDistance >= 0.0) {
 			ret.hit = true;	
 			
 			Vector3 localCoordinate = Vector3(ray.origin.x,ray.origin.y,0);
@@ -1172,6 +1207,7 @@ MouseEventResult Entity::onMouseWheelDown(const Ray &ray, int timestamp) {
 			localCoordinate = inverse * localCoordinate;			
 			
 			InputEvent *inputEvent = new InputEvent(Vector2(localCoordinate.x, localCoordinate.y*yAdjust), timestamp);
+            inputEvent->hitDistance = hitDistance;
 			dispatchEvent(inputEvent, InputEvent::EVENT_MOUSEWHEEL_DOWN);
 												
 			if(blockMouseInput) {

+ 5 - 5
Core/Contents/Source/PolyParticleEmitter.cpp

@@ -422,14 +422,14 @@ void SceneParticleEmitter::updateParticles() {
         
         normLife = particles[i].lifetime / lifetime;
         if(useColorCurves) {
-            particles[i].color.setColor(colorCurveR.getHeightAt(normLife)*particles[i].brightnessDeviation,
-                                        colorCurveG.getHeightAt(normLife)*particles[i].brightnessDeviation,
-                                        colorCurveB.getHeightAt(normLife)*particles[i].brightnessDeviation,
-                                        colorCurveA.getHeightAt(normLife)*particles[i].brightnessDeviation);
+            particles[i].color.setColor(colorCurveR.getYValueAtX(normLife)*particles[i].brightnessDeviation,
+                                        colorCurveG.getYValueAtX(normLife)*particles[i].brightnessDeviation,
+                                        colorCurveB.getYValueAtX(normLife)*particles[i].brightnessDeviation,
+                                        colorCurveA.getYValueAtX(normLife)*particles[i].brightnessDeviation);
         }
         
         if(useScaleCurve) {
-            particles[i].scale = scaleCurve.getHeightAt(normLife);
+            particles[i].scale = scaleCurve.getYValueAtX(normLife);
         } else {
             particles[i].scale = 1.0;
         }

+ 25 - 122
Core/Contents/Source/PolyQuaternionCurve.cpp

@@ -36,15 +36,6 @@ QuaternionCurve::~QuaternionCurve() {
 
 void QuaternionCurve::generatePointsFromCurves(BezierCurve *wCurve, BezierCurve *xCurve, BezierCurve *yCurve, BezierCurve *zCurve) {
 	for(int i=0; i < wCurve->getNumControlPoints(); i++) {
-		/*
-		Quaternion newQuat(wCurve->getControlPoint(i)->p2.y,
-							xCurve->getControlPoint(i)->p2.y,
-							yCurve->getControlPoint(i)->p2.y,
-							zCurve->getControlPoint(i)->p2.y);
-
-		points.push_back(newQuat);
-		recalcTangents();
-		*/
 		Quaternion quat1(wCurve->getControlPoint(i)->p1.y,
 							xCurve->getControlPoint(i)->p1.y,
 							yCurve->getControlPoint(i)->p1.y,
@@ -64,130 +55,42 @@ void QuaternionCurve::generatePointsFromCurves(BezierCurve *wCurve, BezierCurve
 		QuatTriple newTriple;
 		newTriple.q1 = quat1;
 		newTriple.q2 = quat2;
-		newTriple.q3 = quat3;		
+		newTriple.q3 = quat3;
 		tPoints.push_back(newTriple);
 	}
 }
 
-    Quaternion QuaternionCurve::interpolate(Number t, bool useShortestPath)
-    {
-        // Work out which segment this is in
+Quaternion QuaternionCurve::interpolate(Number t, bool useShortestPath)
+{
         Number fSeg = t * (tPoints.size() - 1);
         unsigned int segIdx = (unsigned int)fSeg;
-        // Apportion t 
         t = fSeg - segIdx;
 
         return interpolate(segIdx, t, useShortestPath);
 
-    }
-    //---------------------------------------------------------------------
-    Quaternion QuaternionCurve::interpolate(unsigned int fromIndex, Number t,
-		bool useShortestPath)
-    {
-        // Bounds check
-        assert (fromIndex >= 0 && fromIndex < tPoints.size() &&
-            "fromIndex out of bounds");
-
-        if ((fromIndex + 1) == tPoints.size() && tPoints[fromIndex].q2 != tPoints[0].q2)
-        {
-			Logger::log("size\n");
-            // Duff request, cannot blend to nothing
-            // Just return source
-            return points[fromIndex];
-
-        }
-        // Fast special cases
-        if (t == 0.0f)
-        {
-            return tPoints[fromIndex].q2;
-        }
-        else if(t == 1.0f)
-        {
-            return tPoints[fromIndex + 1].q2;
-        }
-		
-        Quaternion &p = tPoints[fromIndex].q2;
-        Quaternion &q = tPoints[fromIndex+1].q2;
-        Quaternion &a = tPoints[fromIndex].q3;
-        Quaternion &b = tPoints[fromIndex+1].q1;		
-		
-		if ((fromIndex + 1) == tPoints.size() && tPoints[fromIndex].q2 == tPoints[0].q2) {
-			q = tPoints[1].q2;
-			b = tPoints[1].q1;					
-		} 
+}
 
-        // NB interpolate to nearest rotation
-        return Quaternion::Squad(t, p, a, b, q, useShortestPath);
+Quaternion QuaternionCurve::interpolate(unsigned int fromIndex, Number t, bool useShortestPath) {
+    if ((fromIndex + 1) == tPoints.size() && tPoints[fromIndex].q2 != tPoints[0].q2) {
+        return  tPoints[fromIndex].q2;
 
     }
-
-void QuaternionCurve::recalcTangents()
-{
-        unsigned int i, numPoints;
-        bool isClosed;
-
-        numPoints = (unsigned int)points.size();
-
-        if (numPoints < 2) {
-            return;
-        }
-
-        tangents.resize(numPoints);
-
-        if (points[0] == points[numPoints-1])
-        {
-            isClosed = true;
-        }
-        else
-        {
-            isClosed = false;
-        }
-
-        Quaternion invp, part1, part2, preExp;
-        for(i = 0; i < numPoints; ++i)
-        {
-            Quaternion &p = points[i];
-            invp = p.Inverse();
-
-            if (i ==0)
-            {
-                // special case start
-                part1 = (invp * points[i+1]).Log();
-                if (isClosed)
-                {
-                    // Use numPoints-2 since numPoints-1 == end == start == this one
-                    part2 = (invp * points[numPoints-2]).Log();
-                }
-                else
-                {
-                    part2 = (invp * p).Log();
-                }
-            }
-            else if (i == numPoints-1)
-            {
-                // special case end
-                if (isClosed)
-                {
-                    // Wrap to [1] (not [0], this is the same as end == this one)
-                    part1 = (invp * points[1]).Log();
-                }
-                else
-                {
-                    part1 = (invp * p).Log();
-                }
-                part2 = (invp * points[i-1]).Log();
-            }
-            else
-            {
-                part1 = (invp * points[i+1]).Log();
-                part2 = (invp * points[i-1]).Log();
-            }
-
-            preExp =(part1 + part2)  * -0.25 ;
-            tangents[i] = p * preExp.Exp();
-            
-        }
-
-
-
+    if (t == 0.0f) {
+        return tPoints[fromIndex].q2;
+    }
+    else if(t == 1.0f) {
+        return tPoints[fromIndex + 1].q2;
     }
+    
+    Quaternion &p = tPoints[fromIndex].q2;
+    Quaternion &q = tPoints[fromIndex+1].q2;
+    Quaternion &a = tPoints[fromIndex].q3;
+    Quaternion &b = tPoints[fromIndex+1].q1;		
+    
+    if ((fromIndex + 1) == tPoints.size() && tPoints[fromIndex].q2 == tPoints[0].q2) {
+        q = tPoints[1].q2;
+        b = tPoints[1].q1;					
+    } 
+
+    return Quaternion::Squad(t, p, a, b, q, useShortestPath);
+}

+ 9 - 5
Core/Contents/Source/PolyRay.cpp

@@ -94,10 +94,10 @@ bool Ray::polygonIntersect(Vertex *v1, Vertex *v2, Vertex *v3) const {
 	return true;
 }
 
-bool Ray::boxIntersect(const Vector3 &box, const Matrix4 &transformMatrix, float near, float far) const {	
+Number Ray::boxIntersect(const Vector3 &box, const Matrix4 &transformMatrix, float near, float far) const {
 
 	if(box.x == 0 || box.y == 0 || box.z == 0)
-		return false;
+		return -1.0;
 
 	Ray r  = tranformByMatrix(transformMatrix.Inverse());
 
@@ -112,7 +112,7 @@ bool Ray::boxIntersect(const Vector3 &box, const Matrix4 &transformMatrix, float
 	tymax = (bounds[1-r.sign[1]].y - r.origin.y) * r.inv_direction.y;
 
 	if ( (tmin > tymax) || (tymin > tmax) )
-		return false;
+		return -1.0;
 
 	if (tymin > tmin)
 		tmin = tymin;
@@ -124,7 +124,7 @@ bool Ray::boxIntersect(const Vector3 &box, const Matrix4 &transformMatrix, float
 	tzmax = (bounds[1-r.sign[2]].z - r.origin.z) * r.inv_direction.z;
 	
 	if ( (tmin > tzmax) || (tzmin > tmax) )
-		return false;
+		return -1.0;
 
 	if (tzmin > tmin)
 		tmin = tzmin;
@@ -132,5 +132,9 @@ bool Ray::boxIntersect(const Vector3 &box, const Matrix4 &transformMatrix, float
 	if (tzmax < tmax)
 		tmax = tzmax;
 		
-	return ( (tmin < far) && (tmax > near) );
+	if( (tmin < far) && (tmax > near) ) {
+        return fabs(tmin);
+    } else {
+        return -1.0;
+    }
 }

+ 100 - 1
Core/Contents/Source/PolySceneEntityInstance.cpp

@@ -55,6 +55,7 @@ SceneEntityInstance *SceneEntityInstance::BlankSceneEntityInstance(Scene *parent
 }
 
 SceneEntityInstance::SceneEntityInstance(Scene *parentScene, const String& fileName) : Entity() {
+    createNewLayer("default");
     this->parentScene = parentScene;
 	resourceEntry = new SceneEntityInstanceResourceEntry(this);
     topLevelResourcePool = CoreServices::getInstance()->getResourceManager()->getGlobalPool();
@@ -66,6 +67,7 @@ SceneEntityInstance::SceneEntityInstance(Scene *parentScene, const String& fileN
 }
 
 SceneEntityInstance::SceneEntityInstance(Scene *parentScene) : Entity() {
+    createNewLayer("default");
     this->parentScene = parentScene;
 	cloneUsingReload = true;
 	ownsChildren = true;
@@ -73,7 +75,11 @@ SceneEntityInstance::SceneEntityInstance(Scene *parentScene) : Entity() {
 	resourceEntry = new SceneEntityInstanceResourceEntry(this);
 }
 
-SceneEntityInstance::~SceneEntityInstance() {	
+SceneEntityInstance::~SceneEntityInstance() {
+    for(int i=0; i < layers.size(); i++) {
+            delete layers[i];
+    }
+    
 	CoreServices::getInstance()->getResourceManager()->removeResource(resourceEntry);
 	delete resourceEntry;
     for(int i=0; i < resourcePools.size(); i++) {
@@ -472,6 +478,10 @@ Entity *SceneEntityInstance::loadObjectEntryIntoEntity(ObjectEntry *entry, Entit
 	if((*entry)["id"]->stringVal != "") {
 		entity->id = (*entry)["id"]->stringVal;
 	}
+    
+    if((*entry)["layerID"]) {
+        entity->layerID = (unsigned int)((*entry)["layerID"]->intVal);
+    }
 	
 	String tagString = (*entry)["tags"]->stringVal; 
 	
@@ -524,6 +534,65 @@ void SceneEntityInstance::clearInstance() {
     children.clear();
 }
 
+bool SceneEntityInstance::hasLayerID(unsigned char layerID) const {
+    for(int i=0; i < layers.size(); i++) {
+        if(layers[i]->layerID == layerID) {
+            return true;
+        }
+    }
+    return false;
+}
+
+SceneEntityInstanceLayer::SceneEntityInstanceLayer(SceneEntityInstance *instance, String name) {
+    this->instance = instance;
+    this->name = name;
+    visible = true;
+}
+
+void SceneEntityInstanceLayer::setLayerVisibility(bool val) {
+    visible = val;
+    
+    std::vector<Entity*> entities = instance->getEntitiesByLayerID(layerID, true);
+    for(int i=0; i < entities.size(); i++) {
+        entities[i]->visible = val;
+    }
+}
+
+SceneEntityInstanceLayer *SceneEntityInstance::createNewLayer(String name) {
+    SceneEntityInstanceLayer *newLayer = new SceneEntityInstanceLayer(this, name);
+    
+    unsigned char layerID;
+    for(layerID=0; layerID <= 255; layerID++) {
+        if(!hasLayerID(layerID)) {
+            break;
+        }
+    }
+    newLayer->layerID = layerID;
+    layers.push_back(newLayer);
+    return newLayer;
+}
+
+unsigned int SceneEntityInstance::getNumLayers() const {
+    return layers.size();
+}
+
+void SceneEntityInstance::removeLayer(SceneEntityInstanceLayer *layer) {
+    for(int i=0; i < layers.size(); i++) {
+        if(layers[i] == layer) {
+            delete layers[i];
+            layers.erase(layers.begin()+i);
+        }
+    }
+}
+
+SceneEntityInstanceLayer *SceneEntityInstance::getLayerAtIndex(unsigned int index) const {
+    if(index < layers.size()) {
+        return layers[index];
+    } else {
+        return NULL;
+    }
+}
+
 bool SceneEntityInstance::loadFromFile(const String& fileName) {
 
 	clearInstance();
@@ -548,6 +617,24 @@ bool SceneEntityInstance::loadFromFile(const String& fileName) {
     
 	ObjectEntry *settings = loadObject.root["settings"];
     if(settings) {
+        
+        ObjectEntry *layersEntry = (*settings)["layers"];
+        if(layersEntry) {
+            for(int i=0; i < layersEntry->length; i++) {
+                ObjectEntry *layer = (*layersEntry)[i];
+                if(layer) {
+                    ObjectEntry *name = (*layer)["name"];
+                    ObjectEntry *layerID = (*layer)["id"];
+                    ObjectEntry *visible = (*layer)["visible"];
+                    if(name && layerID && visible) {
+                        SceneEntityInstanceLayer *newLayer = new SceneEntityInstanceLayer(this, name->stringVal);
+                        newLayer->visible = visible->boolVal;
+                        newLayer->layerID = (unsigned char) layerID->intVal;
+                        layers.push_back(newLayer);
+                    }
+                }
+            }
+        }
         ObjectEntry *matFiles = (*settings)["matFiles"];
         for(int i=0; i < matFiles->length; i++) {
             ObjectEntry *matFile = (*matFiles)[i];
@@ -572,6 +659,18 @@ bool SceneEntityInstance::loadFromFile(const String& fileName) {
 	if(root) {
 		loadObjectEntryIntoEntity(root, this, entityFileVersion);
 	}
+    
+    for(int i=0; i < layers.size(); i++ ) {
+        SceneEntityInstanceLayer *layer = layers[i];
+        if(layer->layerID != 0) {
+            if(layer->visible == false) {
+                std::vector<Entity*> layerEntities = getEntitiesByLayerID(layer->layerID, true);
+                for(int j=0; j < layerEntities.size(); j++) {
+                    layerEntities[j]->visible = false;
+                }
+            }
+        }
+    }
 	
 	return true;
 }

+ 59 - 65
Core/Contents/Source/PolySkeleton.cpp

@@ -327,7 +327,6 @@ void Skeleton::addAnimation(const String& name, const String& fileName) {
                     break;
             }
         }
-        newTrack->initTweens();
         newAnimation->addBoneTrack(newTrack);
     }
     
@@ -343,6 +342,11 @@ BoneTrack::BoneTrack(Bone *bone, Number length) {
     weight = 0.0;
 	this->length = length;
 	targetBone = bone;
+    paused = false;
+    time = 0.0;
+    speed = 1.0;
+    playOnce = false;
+    
 	scaleX = NULL;
 	scaleY = NULL;
 	scaleZ = NULL;
@@ -353,6 +357,8 @@ BoneTrack::BoneTrack(Bone *bone, Number length) {
 	LocX = NULL;			
 	LocY = NULL;
 	LocZ = NULL;
+    
+    quatCurve = NULL;
 }
 
 BoneTrack::~BoneTrack() {
@@ -369,91 +375,78 @@ BoneTrack::~BoneTrack() {
 }
 
 void BoneTrack::Reset() {
-    for(int i=0; i < pathTweens.size(); i++) {
-        if(pathTweens[i]->isComplete()) {
-            CoreServices::getInstance()->getTweenManager()->addTween(pathTweens[i]);
-        }
-        pathTweens[i]->Reset();
-    }
-    if(quatTween->isComplete()) {
-        CoreServices::getInstance()->getTweenManager()->addTween(quatTween);
-    }
-    quatTween->Reset();
+    time = 0.0;
 }
 
 void BoneTrack::Stop() {
-    for(int i=0; i < pathTweens.size(); i++) {
-        pathTweens[i]->Pause(true);
-    }
-    quatTween->Pause(true);
+    paused = true;
 }
 
-void BoneTrack::initTweens() {
-    
-    BezierPathTween *tween;
-	if(LocX) {
-		tween = new BezierPathTween(&LocXVec, LocX, Tween::EASE_NONE, length, true);
-		pathTweens.push_back(tween);
-	}
-	if(LocY) {
-		tween = new BezierPathTween(&LocYVec, LocY, Tween::EASE_NONE, length, true);
-		pathTweens.push_back(tween);
-	}
-    
-	if(LocZ) {
-		tween = new BezierPathTween(&LocZVec, LocZ, Tween::EASE_NONE, length, true);
-		pathTweens.push_back(tween);
-	}
-	tween = new BezierPathTween(&ScaleXVec, scaleX, Tween::EASE_NONE, length, true);
-	pathTweens.push_back(tween);
-	tween = new BezierPathTween(&ScaleYVec, scaleY, Tween::EASE_NONE, length, true);
-	pathTweens.push_back(tween);
-	tween = new BezierPathTween(&ScaleZVec, scaleZ, Tween::EASE_NONE, length, true);
-	pathTweens.push_back(tween);
-    
-	if(QuatW) {
-        quatTween = new QuaternionTween(&boneQuat, QuatW, QuatX, QuatY, QuatZ, Tween::EASE_NONE, length, true);
-    }
-}
 
 void BoneTrack::Play(bool once) {
-    for(int i=0; i < pathTweens.size(); i++) {
-            pathTweens[i]->Reset();
-			pathTweens[i]->Pause(false);
-            pathTweens[i]->repeat = !once;
-    }
-    if(quatTween) {
-        quatTween->Reset();
-        quatTween->Pause(false);
-        quatTween->repeat = !once;
-    }
+    paused = true;
+    playOnce = once;
 }
 
 
-void BoneTrack::Update() {
+void BoneTrack::Update(Number elapsed) {
 	if(!targetBone)
 		return;
     
-    if(quatTween->isComplete()) {
-        return;
+//    if(!paused) {
+        time += elapsed * speed;
+//    }
+    
+    if(time > length) {
+        if(playOnce) {
+            time = length;
+            return;
+        } else {
+            time = time - length;
+        }
+    }
+    
+    if(LocX) {
+        position.x = LocX->getYValueAtX(time);
+    }
+    if(LocY) {
+        position.y = LocY->getYValueAtX(time);
+    }
+    if(LocZ) {
+        position.z = LocZ->getYValueAtX(time);
+    }
+    
+    if(scaleX) {
+        scale.x = scaleX->getYValueAtX(time);
+    }
+    if(scaleY) {
+        scale.y = scaleY->getYValueAtX(time);
+    }
+    if(scaleZ) {
+        scale.z = scaleZ->getYValueAtX(time);
     }
     
+    if(!quatCurve) {
+        if(QuatW) {
+            quatCurve = new QuaternionCurve(QuatW, QuatX, QuatY, QuatZ);
+        }
+    }
+    
+    if(quatCurve) {
+        boneQuat = quatCurve->interpolate(time/length, true);
+    }
+
+    
     Quaternion rotationQuat = targetBone->getRotationQuat();
     rotationQuat = Quaternion::Slerp(weight, rotationQuat, boneQuat, true);
     targetBone->setRotationByQuaternion(rotationQuat);
 
-    Vector3 trackPosition = Vector3(LocXVec.y, LocYVec.y, LocZVec.y);
-    targetBone->setPosition((trackPosition * weight) + (targetBone->getPosition() * (1.0 - weight)));
-
-    Vector3 trackScale = Vector3(ScaleXVec.y, ScaleYVec.y, ScaleZVec.y);
-    Vector3 newScale = ((trackScale - Vector3(1.0, 1.0, 1.0)) * weight) + Vector3(1.0, 1.0, 1.0);
+    targetBone->setPosition((position * weight) + (targetBone->getPosition() * (1.0 - weight)));
+    Vector3 newScale = ((scale - Vector3(1.0, 1.0, 1.0)) * weight) + Vector3(1.0, 1.0, 1.0);
 }
 
 void BoneTrack::setSpeed(Number speed) {
-	for(int i=0; i < pathTweens.size(); i++) {
-		pathTweens[i]->setSpeed(speed);
-	}	
-	quatTween->setSpeed(speed);
+    this->speed = speed;
 }
 
 
@@ -484,9 +477,10 @@ void SkeletonAnimation::setSpeed(Number speed) {
 }
 
 void SkeletonAnimation::Update() {
+    Number elapsed = CoreServices::getInstance()->getCore()->getElapsed();
 	for(int i=0; i < boneTracks.size(); i++) {
         boneTracks[i]->weight = weight;
-		boneTracks[i]->Update();
+		boneTracks[i]->Update(elapsed);
 	}
 }
 

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 3 - 3
IDE/Assets/ide_icons.ai


+ 23 - 9
IDE/Contents/Include/EntityEditorTreeView.h

@@ -29,28 +29,42 @@
 
 using namespace Polycode;
 
-
-class EntityEditorTreeView : public UIElement {
+class EntityEditorTreeSheet : public PropSheet {
     public:
-        EntityEditorTreeView();
-        ~EntityEditorTreeView();
+        EntityEditorTreeSheet();
+        ~EntityEditorTreeSheet();
     
         void refreshTree();
         void syncNodeToEntity(UITree *node, Entity *entity);
-    
         void handleEvent(Event *event);
         void setSelectedEntity(Entity *entity);
         Entity *getSelectedEntity();
-    
         void Resize(Number width, Number height);
         void setRootEntity(Entity *entity);
     
     private:
-    
+
         Entity *selectedEntity;
         bool dontSendSelectionEvent;
-    
         UITreeContainer *treeContainer;
-        UIRect *headerBg;
         Entity *rootEntity;
+    
+};
+
+class EntityEditorTreeView : public UIElement {
+    public:
+        EntityEditorTreeView();
+
+        void setEntityInstance(SceneEntityInstance *instance);
+        EntityEditorTreeSheet *getTreeSheet();
+        void Resize(Number width, Number height);
+    
+    private:
+    
+    
+        PropList *entityProps;
+        EntityEditorTreeSheet *treeSheet;
+        LayerSheet *layerSheet;
+    
+
 };

+ 16 - 1
IDE/Contents/Include/PolycodeEntityEditor.h

@@ -148,6 +148,16 @@ class SceneMeshSettings {
         ShaderBinding *shaderBinding;
 };
 
+class MultiselectorEntry {
+    public:
+        Entity *entity;
+        Number distance;
+};
+
+class EntityDistanceSorter : public PolyBase {
+    public:
+    bool operator() (MultiselectorEntry i,MultiselectorEntry j);
+};
 
 class EntityEditorMainView : public UIElement {
 		public:
@@ -206,6 +216,8 @@ class EntityEditorMainView : public UIElement {
     
 		protected:
     
+            bool selectingNewEntities();
+    
             CoreInput *input;
             PolycodeSceneEditorActionData *beforeData;
 			
@@ -220,7 +232,10 @@ class EntityEditorMainView : public UIElement {
 				
             unsigned int multiselectIndex;
 			std::vector<Entity*> selectedEntities;
-            std::vector<Entity*> entitiesToSelect;
+            std::vector<MultiselectorEntry> entitiesToSelect;
+            std::vector<MultiselectorEntry> lastEntitiesToSelect;
+    
+            EntityDistanceSorter distanceSorter;
     
 			Scene *mainScene;
             Entity *sceneObjectRoot;

+ 51 - 0
IDE/Contents/Include/PolycodeProps.h

@@ -221,6 +221,33 @@ public:
 };
 
 
+class LayerProp : public PropProp {
+    public:
+        LayerProp(SceneEntityInstance *instance, SceneEntityInstanceLayer *layer);
+        ~LayerProp();
+        void handleEvent(Event *event);
+        void setPropWidth(Number width);
+    
+        void setInstance(SceneEntityInstance *instance);
+    
+    private:
+    
+        SceneEntityInstance *instance;
+        SceneEntityInstanceLayer *layer;
+        UILabel *layerName;
+        UIImageButton *hideLayerButton;
+        UIImageButton *showLayerButton;
+        UIImageButton *moreButton;
+    
+        UIMenu *menu;
+    
+        UIImageButton *removeLayerButton;
+    
+        unsigned char layerID = 0;
+    
+        UIRect *bgRect;
+};
+
 class CustomProp : public PropProp {
 	public:
 		CustomProp(String key, String value);
@@ -513,10 +540,16 @@ class EntitySheet : public PropSheet {
 	
 		void handleEvent(Event *event);
         void setEntity(Entity *entity);
+    
+        void refreshLayers();
+    
+        void setEntityInstance(SceneEntityInstance *instance);
 
     protected:
 		Entity *entity;
 		
+        SceneEntityInstance *instance;
+        ComboProp *layersProp;
 		StringProp *idProp;
 		StringProp *tagProp;
 		ColorProp *colorProp;
@@ -836,6 +869,24 @@ class SoundSheet : public PropSheet {
 		SliderProp *pitch;
 };
 
+class LayerSheet : public PropSheet {
+    public:
+        LayerSheet();
+        ~LayerSheet();
+        
+        void handleEvent(Event *event);
+        void setEntityInstance(SceneEntityInstance *instance);
+    
+        void setFromEntity();
+    
+        void Update();
+
+    private:
+        ButtonProp *addLayerProp;
+        SceneEntityInstance *instance;
+        int layerRemoveIndex;
+};
+
 class LinkedMaterialsSheet : public PropSheet {
     public:
         LinkedMaterialsSheet();

BIN
IDE/Contents/Resources/ImagesRetina/entityEditor/button_more.png


BIN
IDE/Contents/Resources/ImagesRetina/entityEditor/invisible_button.png


BIN
IDE/Contents/Resources/ImagesRetina/entityEditor/visible_button.png


+ 1 - 0
IDE/Contents/Source/EntityEditorPropertyView.cpp

@@ -88,6 +88,7 @@ EntityEditorPropertyView::EntityEditorPropertyView() : UIElement() {
 
 void EntityEditorPropertyView::setEntityInstance(SceneEntityInstance *instance) {
     materialSheet->setEntityInstance(instance);
+    entitySheet->setEntityInstance(instance);
 }
 
 void EntityEditorPropertyView::Resize(Number width, Number height) {

+ 42 - 24
IDE/Contents/Source/EntityEditorTreeView.cpp

@@ -22,36 +22,42 @@
 
 #include "EntityEditorTreeView.h"
 
-EntityEditorTreeView::EntityEditorTreeView() : UIElement() {
-
+EntityEditorTreeSheet::EntityEditorTreeSheet() : PropSheet("LIST VIEW", "list_view"){
     treeContainer = new UITreeContainer("folder.png", "Root", 10, 10);
-    addChild(treeContainer);
+    contents->addChild(treeContainer);
     treeContainer->getRootNode()->addEventListener(this, UITreeEvent::SELECTED_EVENT);
-    treeContainer->setPosition(0, 30);
+    treeContainer->setPosition(-20, -5);
     treeContainer->getRootNode()->toggleCollapsed();
     
-	headerBg = new UIRect(10,10);
-	addChild(headerBg);
-	headerBg->setAnchorPoint(-1.0, -1.0, 0.0);
-	headerBg->color.setColorHexFromString(CoreServices::getInstance()->getConfig()->getStringValue("Polycode", "uiHeaderBgColor"));
-	
-	UILabel *label = new UILabel("TREE VIEW", 18, "section", Label::ANTIALIAS_FULL);
-	label->color.setColorHexFromString(CoreServices::getInstance()->getConfig()->getStringValue("Polycode", "uiHeaderFontColor"));
 	
-	addChild(label);
-	label->setPosition(10, 3);
-    
     selectedEntity = NULL;
     dontSendSelectionEvent = false;
 }
 
-void EntityEditorTreeView::setRootEntity(Entity *entity) {
+EntityEditorTreeView::EntityEditorTreeView() : UIElement() {
+
+    entityProps = new PropList("HIERARCHY");
+    addChild(entityProps);
+    
+    layerSheet = new LayerSheet();
+    entityProps->addPropSheet(layerSheet);
+    layerSheet->addEventListener(this, PropEvent::EVENT_PROP_CHANGE);
+    
+    
+    treeSheet = new EntityEditorTreeSheet();
+    entityProps->addPropSheet(treeSheet);
+    
+
+}
+
+
+void EntityEditorTreeSheet::setRootEntity(Entity *entity) {
     rootEntity = entity;
     treeContainer->getRootNode()->setUserData((void*) entity);
     refreshTree();
 }
 
-void EntityEditorTreeView::syncNodeToEntity(UITree *node, Entity *entity) {
+void EntityEditorTreeSheet::syncNodeToEntity(UITree *node, Entity *entity) {
     // remove non existing and set proper ids,
 	
 	std::vector<UITree*> nodesToRemove;
@@ -132,16 +138,16 @@ void EntityEditorTreeView::syncNodeToEntity(UITree *node, Entity *entity) {
 	}
 }
 
-Entity *EntityEditorTreeView::getSelectedEntity() {
+Entity *EntityEditorTreeSheet::getSelectedEntity() {
     return selectedEntity;
 }
 
-void EntityEditorTreeView::setSelectedEntity(Entity *entity) {
+void EntityEditorTreeSheet::setSelectedEntity(Entity *entity) {
     selectedEntity = entity;
     refreshTree();
 }
 
-void EntityEditorTreeView::handleEvent(Event *event) {
+void EntityEditorTreeSheet::handleEvent(Event *event) {
 	
 	if(event->getDispatcher() == treeContainer->getRootNode()) {
 		if(event->getEventCode() == UITreeEvent::SELECTED_EVENT){
@@ -154,19 +160,31 @@ void EntityEditorTreeView::handleEvent(Event *event) {
 			dontSendSelectionEvent = false;
 		}
 	}
-	ScreenEntity::handleEvent(event);
+	PropSheet::handleEvent(event);
 }
 
+void EntityEditorTreeView::setEntityInstance(SceneEntityInstance *instance) {
+    treeSheet->setRootEntity(instance);
+    layerSheet->setEntityInstance(instance);
+}
 
-void EntityEditorTreeView::refreshTree() {
+void EntityEditorTreeSheet::refreshTree() {
     syncNodeToEntity(treeContainer->getRootNode(), rootEntity);
 }
 
-EntityEditorTreeView::~EntityEditorTreeView() {
+EntityEditorTreeSheet::~EntityEditorTreeSheet() {
     
 }
 
+EntityEditorTreeSheet *EntityEditorTreeView::getTreeSheet() {
+    return treeSheet;
+}
+
+void EntityEditorTreeSheet::Resize(Number width, Number height) {
+    treeContainer->Resize(width, height-60);
+    PropSheet::Resize(width, height);
+}
+
 void EntityEditorTreeView::Resize(Number width, Number height) {
-    treeContainer->Resize(width, height-30);
-    headerBg->Resize(width, 30);
+    entityProps->Resize(width, height);
 }

+ 70 - 21
IDE/Contents/Source/PolycodeEntityEditor.cpp

@@ -624,14 +624,40 @@ void EntityEditorMainView::Paste(EntityEditorClipboardData *data) {
     }
 }
 
+bool EntityEditorMainView::selectingNewEntities(){
+    
+    if(entitiesToSelect.size() != lastEntitiesToSelect.size()) {
+        return true;
+    }
+    
+    for(int i=0; i < entitiesToSelect.size(); i++) {
+        if(lastEntitiesToSelect[i].entity != entitiesToSelect[i].entity) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool EntityDistanceSorter::operator() (MultiselectorEntry i,MultiselectorEntry j) {
+	if(i.distance < j.distance) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
 void EntityEditorMainView::Update() {
     
     if(entitiesToSelect.size() != 0) {
-        if(multiselectIndex > entitiesToSelect.size()-1) {
+        
+        sort (entitiesToSelect.begin(), entitiesToSelect.end(), distanceSorter);
+        
+        if(multiselectIndex > entitiesToSelect.size()-1 || selectingNewEntities()) {
             multiselectIndex = 0;
         }
-        selectEntity(entitiesToSelect[multiselectIndex], input->getKeyState(KEY_LSHIFT) || input->getKeyState(KEY_RSHIFT));
+        selectEntity(entitiesToSelect[multiselectIndex].entity, input->getKeyState(KEY_LSHIFT) || input->getKeyState(KEY_RSHIFT));
         multiselectIndex++;
+        lastEntitiesToSelect = entitiesToSelect;
         entitiesToSelect.clear();
     }
     
@@ -643,19 +669,25 @@ void EntityEditorMainView::Update() {
     for(int i=0; i < icons.size(); i++) {
         Number scale;
         
-        Entity *parentEntity = (Entity*) icons[i]->getUserData();
         
-        Vector3 parentPosition = parentEntity->getConcatenatedMatrix().getPosition();
-        icons[i]->setPosition(parentPosition);
+        Entity *parentEntity = (Entity*) icons[i]->getUserData();
         
-        if(editorMode == EDITOR_MODE_2D) {
-            scale = trackballCamera->getCameraDistance() * 0.1;
+        if(!parentEntity->visible) {
+            icons[i]->visible = false;
         } else {
-            scale = mainScene->getDefaultCamera()->getPosition().distance(icons[i]->getConcatenatedMatrix().getPosition()) * 0.1;
+            icons[i]->visible = true;
+            Vector3 parentPosition = parentEntity->getConcatenatedMatrix().getPosition();
+            icons[i]->setPosition(parentPosition);
+            
+            if(editorMode == EDITOR_MODE_2D) {
+                scale = trackballCamera->getCameraDistance() * 0.1;
+            } else {
+                scale = mainScene->getDefaultCamera()->getPosition().distance(icons[i]->getConcatenatedMatrix().getPosition()) * 0.1;
+            }
+            icons[i]->setScale(scale, scale, scale);
+            icons[i]->rebuildTransformMatrix();
+            icons[i]->recalculateAABBAllChildren();
         }
-        icons[i]->setScale(scale, scale, scale);
-        icons[i]->rebuildTransformMatrix();
-        icons[i]->recalculateAABBAllChildren();
     }
     
     setBBox();
@@ -1212,8 +1244,9 @@ void EntityEditorMainView::handleEvent(Event *event) {
         if(event->getEventCode() == InputEvent::EVENT_MOUSEDOWN && hasFocus && event->getDispatcher() != renderTextureShape) {
             InputEvent *inputEvent = (InputEvent*) event;
 
-            if(inputEvent->mouseButton == CoreInput::MOUSE_BUTTON2) {
-                Entity* targetEntity = (Entity*) event->getDispatcher();
+            Entity* targetEntity = (Entity*) event->getDispatcher();
+            if(inputEvent->mouseButton == CoreInput::MOUSE_BUTTON2 && targetEntity->visible) {
+
                 
                 // if it's an icon, select the entity linked to the icon
                 for(int i=0; i < icons.size(); i++) {
@@ -1222,7 +1255,11 @@ void EntityEditorMainView::handleEvent(Event *event) {
                     }
                 }
                 
-                entitiesToSelect.push_back(targetEntity);
+                MultiselectorEntry entry;
+                entry.entity = targetEntity;
+                entry.distance = inputEvent->hitDistance;
+
+                entitiesToSelect.push_back(entry);
             }
         }
     }
@@ -1535,7 +1572,7 @@ void EntityEditorPropertyContainer::handleEvent(Event *event) {
             break;
             case 1:
                 currentView = treeView;
-                treeView->refreshTree();
+                treeView->getTreeSheet()->refreshTree();
             break;
             case 2:
                 currentView = settingsView;
@@ -1577,22 +1614,22 @@ PolycodeEntityEditor::PolycodeEntityEditor() : PolycodeEditor(true){
     treeView = propertyContainer->treeView;
     settingsView = propertyContainer->settingsView;
     
-    treeView->addEventListener(this, Event::CHANGE_EVENT);
+    treeView->getTreeSheet()->addEventListener(this, Event::CHANGE_EVENT);
     
     mainSizer->addRightChild(propertyContainer);
 }
 
 void PolycodeEntityEditor::handleEvent(Event *event) {
     
-    if(event->getDispatcher() == treeView) {
-        mainView->selectEntity(treeView->getSelectedEntity());
+    if(event->getDispatcher() == treeView->getTreeSheet()) {
+        mainView->selectEntity(treeView->getTreeSheet()->getSelectedEntity());
     }
     
     if(event->getDispatcher() == mainView) {
         switch(event->getEventCode()) {
             case Event::CHANGE_EVENT:
                 propertyView->setEntity(mainView->getSelectedEntity());
-                treeView->setSelectedEntity(mainView->getSelectedEntity());
+                treeView->getTreeSheet()->setSelectedEntity(mainView->getSelectedEntity());
             break;
         }
     }
@@ -1630,7 +1667,7 @@ bool PolycodeEntityEditor::openFile(OSFileEntry filePath) {
     mainView->setObjectRoot(loadedInstance);
     mainView->setEditorPropsRecursive(loadedInstance);
     
-    treeView->setRootEntity(loadedInstance);
+    treeView->setEntityInstance(loadedInstance);
     propertyView->setEntityInstance(loadedInstance);
     settingsView->setEntityInstance(loadedInstance);
     
@@ -1668,6 +1705,7 @@ void PolycodeEntityEditor::saveEntityToObjectEntry(Entity *entity, ObjectEntry *
         return;
     
     entry->addChild("id", entity->id);
+    entry->addChild("layerID", (int)entity->layerID);
     
     String tagString = "";
     for(int i=0; i < entity->getNumTags(); i++) {
@@ -2009,7 +2047,18 @@ void PolycodeEntityEditor::saveFile() {
     for(int i=0; i < loadedInstance->getNumLinkedResourePools(); i++) {
         ResourcePool *pool = loadedInstance->getLinkedResourcePoolAtIndex(i);
         linkedMaterialFiles->addChild("matFile")->addChild("path", pool->getName());
-    }    
+    }
+    
+    ObjectEntry *layersEntry = settings->addChild("layers");
+    for(int i=0; i < loadedInstance->getNumLayers(); i++) {
+        SceneEntityInstanceLayer *layer = loadedInstance->getLayerAtIndex(i);
+        if(layer->layerID != 0) {
+            ObjectEntry *layerEntry = layersEntry->addChild("layer");
+            layerEntry->addChild("name", layer->name);
+            layerEntry->addChild("id", layer->layerID);
+            layerEntry->addChild("visible", layer->visible);
+        }
+    }
     
     saveObject.root.name = "entity";
     saveObject.root.addChild("version", 2);

+ 1 - 2
IDE/Contents/Source/PolycodeFrame.cpp

@@ -313,7 +313,6 @@ void EditCurve::handleEvent(Event *event) {
 
 void EditCurve::updateCurve() {
 	targetCurve->recalculateDistances();
-	targetCurve->rebuildBuffers();
 	
 	Number interval = 300.0/CURVE_SIZE;
 	Number normInterval = 1.0/CURVE_SIZE;
@@ -1513,7 +1512,7 @@ void PolycodeFrame::showModal(UIWindow *modalChild) {
 void PolycodeFrame::hideModal() {
 	if(modalChild) {
 		modalRoot->removeChild(modalChild);
-		modalChild->removeAllHandlers();
+		assetBrowser->removeAllHandlers();
 		modalChild->hideWindow(); 
 		modalChild = NULL;
 	}

+ 229 - 3
IDE/Contents/Source/PolycodeProps.cpp

@@ -173,6 +173,7 @@ void PropList::Resize(Number width, Number height) {
 	bg2->Resize(width, 30);	
 	
 	Number offsetY = 0;
+    Number resizeHeight = height;
 	for(int i=0; i < props.size(); i++) {
 		props[i]->setPosition(0, offsetY);
 		if(props[i]->enabled) {
@@ -182,7 +183,8 @@ void PropList::Resize(Number width, Number height) {
                 offsetY += props[i]->propHeight;
             }
 		}
-		props[i]->Resize(getWidth(), getHeight());
+		props[i]->Resize(getWidth(), resizeHeight);
+        resizeHeight -= offsetY;        
 	}
 	
 	rebuildTransformMatrix();
@@ -571,6 +573,128 @@ void RemovableStringProp::handleEvent(Event *event) {
     }
 }
 
+LayerProp::LayerProp(SceneEntityInstance *instance, SceneEntityInstanceLayer *layer) : PropProp("", "Layer") {
+    
+    bgRect = new UIRect(1.0, 1.0);
+    bgRect->color.setColorHexFromString(CoreServices::getInstance()->getConfig()->getStringValue("Polycode", "uiHeaderBgColor"));
+
+    propContents->addChild(bgRect);
+    
+    this->layer = layer;
+    this->instance = instance;
+    
+    layerID = layer->layerID;
+    
+    removeLayerButton = new UIImageButton("main/remove_icon.png", 1.0, 12, 12);
+    propContents->addChild(removeLayerButton);
+    removeLayerButton->setPosition(-95, 5.0);
+    removeLayerButton->addEventListener(this, UIEvent::CLICK_EVENT);
+    
+    hideLayerButton = new UIImageButton("entityEditor/visible_button.png", 1.0, 24, 24);
+    propContents->addChild(hideLayerButton);
+    hideLayerButton->setPosition(-95, 0.0);
+    hideLayerButton->addEventListener(this, UIEvent::CLICK_EVENT);
+
+    
+    showLayerButton = new UIImageButton("entityEditor/invisible_button.png", 1.0, 24, 24);
+    propContents->addChild(showLayerButton);
+    showLayerButton->setPosition(-95, 0.0);
+    showLayerButton->addEventListener(this, UIEvent::CLICK_EVENT);
+    showLayerButton->visible = false;
+    showLayerButton->enabled = false;
+    
+    moreButton = new UIImageButton("entityEditor/button_more.png", 1.0, 24, 24);
+    propContents->addChild(moreButton);
+    moreButton->setPosition(-70, 0.0);
+    moreButton->addEventListener(this, UIEvent::CLICK_EVENT);
+    
+    
+    layerName = new UILabel(layer->name, 12);
+    layerName->setColor(1.0, 1.0, 1.0, 1.0);
+    propContents->addChild(layerName);
+    layerName->setPosition(-40, 5.0);
+    
+    if(layerID == 0) {
+        moreButton->visible = false;
+        moreButton->enabled = false;
+        removeLayerButton->visible = false;
+        removeLayerButton->enabled = false;
+    }
+    
+    if(layer->visible) {
+        hideLayerButton->visible = true;
+        hideLayerButton->enabled = true;
+        showLayerButton->visible = false;
+        showLayerButton->enabled = false;
+    } else {
+        hideLayerButton->visible = false;
+        hideLayerButton->enabled = false;
+        showLayerButton->visible = true;
+        showLayerButton->enabled = true;
+    }
+    
+    menu = NULL;
+    
+	setHeight(25);
+}
+
+void LayerProp::setInstance(SceneEntityInstance *instance) {
+    this->instance = instance;
+}
+
+LayerProp::~LayerProp() {
+    
+}
+
+void LayerProp::handleEvent(Event *event) {
+    if(!instance) {
+        return;
+    }
+    
+    if(event->getDispatcher() == hideLayerButton) {
+        hideLayerButton->visible = false;
+        hideLayerButton->enabled = false;
+        showLayerButton->visible = true;
+        showLayerButton->enabled = true;
+        layer->setLayerVisibility(false);
+    } else if(event->getDispatcher() == showLayerButton) {
+        hideLayerButton->visible = true;
+        hideLayerButton->enabled = true;
+        showLayerButton->visible = false;
+        showLayerButton->enabled = false;
+        layer->setLayerVisibility(true);
+    } else if(event->getDispatcher() == removeLayerButton) {
+        dispatchEvent(new Event(), Event::REMOVE_EVENT);
+    } else if(event->getDispatcher() == moreButton) {
+        menu = globalMenu->showMenuAtMouse(150);
+        menu->addOption("Rename", "rename");
+        menu->addEventListener(this, UIEvent::OK_EVENT);
+    } else if(event->getDispatcher() == menu) {
+        menu->removeAllHandlersForListener(this);
+        String command = menu->getSelectedItem()->getMenuItemID();
+        if(command == "rename") {
+            globalFrame->textInputPopup->action = "renameLayer";
+            globalFrame->textInputPopup->setCaption("Rename layer");
+            globalFrame->textInputPopup->setValue(layer->name);
+            globalFrame->textInputPopup->addEventListener(this, UIEvent::OK_EVENT);
+            globalFrame->showModal(globalFrame->textInputPopup);
+            
+        }
+    } else if(event->getDispatcher() == globalFrame->textInputPopup) {
+        globalFrame->textInputPopup->removeAllHandlersForListener(this);
+        if(globalFrame->textInputPopup->action == "renameLayer") {
+            layer->name = globalFrame->textInputPopup->getValue();
+            layerName->setText(layer->name);
+        }
+    }
+}
+
+void LayerProp::setPropWidth(Number width) {
+    bgRect->Resize(width-PROP_PADDING, 24.0);
+    bgRect->setPosition(-propContents->getPosition().x, 0.0);
+    
+    removeLayerButton->setPosition(width-PROP_PADDING-propContents->getPosition().x-20, 5.0);
+}
 
 CustomProp::CustomProp(String key, String value) : PropProp("", "Custom") {
 	keyEntry = new UITextInput(false, 120, 12);
@@ -2911,7 +3035,15 @@ void MaterialPropSheet::handleEvent(Event *event) {
     PropSheet::handleEvent(event);
 }
 
+void EntitySheet::setEntityInstance(SceneEntityInstance *instance) {
+    this->instance = instance;
+}
+
 EntitySheet::EntitySheet() : PropSheet("ENTITY", "entity"){
+    
+    layersProp = new ComboProp("Layer");
+    addProp(layersProp);
+    
 	idProp = new StringProp("ID");
 	addProp(idProp);
 
@@ -2973,11 +3105,24 @@ void EntitySheet::handleEvent(Event *event) {
 		for(int i=0; i < tags.size(); i++) {
 			entity->addTag(tags[i]);
 		}		
+	} else if(event->getDispatcher() == layersProp  && event->getEventCode() == Event::CHANGE_EVENT) {
+        SceneEntityInstanceLayer *layer = (SceneEntityInstanceLayer*)layersProp->comboEntry->getSelectedItem()->data;
+        entity->layerID = layer->layerID;
 	}
-	
 	PropSheet::handleEvent(event);	
 }
 
+void EntitySheet::refreshLayers() {
+    layersProp->comboEntry->clearItems();
+    
+    for(int i=0; i < instance->getNumLayers(); i++) {
+        SceneEntityInstanceLayer *layer = instance->getLayerAtIndex(i);
+        layersProp->comboEntry->addComboItem(layer->name, (void*)layer);
+        if(layer->layerID == entity->layerID) {
+            layersProp->comboEntry->setSelectedIndex(i);
+        }
+    }
+}
 
 void EntitySheet::setEntity(Entity *entity) {
     this->entity = entity;
@@ -2997,7 +3142,7 @@ void EntitySheet::setEntity(Entity *entity) {
         blendingProp->set(entity->blendingMode);
         
         bBoxProp->set(entity->getLocalBoundingBox());
-        
+        refreshLayers();
         enabled = true;
     } else {
         enabled = false;
@@ -3389,6 +3534,87 @@ void SceneLabelSheet::handleEvent(Event *event) {
 	PropSheet::handleEvent(event);
 }
 
+LayerSheet::LayerSheet() : PropSheet("VISIBILITY LAYERS", "layers") {
+    
+    
+    addLayerProp = new ButtonProp("Add new layer");
+    addProp(addLayerProp);
+    addLayerProp->getButton()->addEventListener(this, UIEvent::CLICK_EVENT);
+    
+    instance = NULL;
+    layerRemoveIndex = -1;
+}
+
+void LayerSheet::setFromEntity() {
+    if(!instance) {
+        return;
+    }
+    
+	for(int i=0; i < props.size(); i++) {
+		contents->removeChild(props[i]);
+		props[i]->removeAllHandlersForListener(this);
+        if(props[i] != addLayerProp) {
+            delete props[i];
+        }
+	}
+	props.clear();
+    
+    for(int i=0; i < instance->getNumLayers(); i++) {
+        SceneEntityInstanceLayer *layer = instance->getLayerAtIndex(i);
+        LayerProp *newProp = new LayerProp(this->instance, layer);
+        newProp->addEventListener(this, Event::REMOVE_EVENT);
+        addProp(newProp);
+    }
+    
+    addProp(addLayerProp);
+}
+
+LayerSheet::~LayerSheet() {
+    
+}
+
+void LayerSheet::Update() {
+    if(layerRemoveIndex != -1) {
+        
+        SceneEntityInstanceLayer *layer = instance->getLayerAtIndex(layerRemoveIndex);
+        if(layer) {
+            std::vector<Entity*> entities = instance->getEntitiesByLayerID(layer->layerID, true);
+            for(int i=0; i < entities.size(); i++) {
+                entities[i]->layerID = 0;
+                entities[i]->visible = true;
+            }
+            instance->removeLayer(layer);
+        }
+        setFromEntity();
+        layerRemoveIndex = -1;
+    }
+}
+
+void LayerSheet::setEntityInstance(SceneEntityInstance *instance) {
+    this->instance = instance;
+    setFromEntity();
+}
+
+void LayerSheet::handleEvent(Event *event) {
+    
+    if(!instance) {
+        return;
+    }
+    
+    for(int i=0; i < props.size(); i++) {
+        if(props[i] == event->getDispatcher()) {
+            layerRemoveIndex = i;
+        }
+    }
+    
+    if(event->getDispatcher() == addLayerProp->getButton()) {
+        instance->createNewLayer("newLayer");
+        setFromEntity();
+    }
+    
+    PropSheet::handleEvent(event);
+}
+
 LinkedMaterialsSheet::LinkedMaterialsSheet() : PropSheet("LINKED MATERIALS", "linked_materials") {
     
     addMaterialProp = new ButtonProp("Link materials file");

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio