Просмотр исходного кода

Added a a custom hit test callback to Entities and a geometry-based ray test to SceneMesh, added polygon intersection test to Ray, added a basic grid to the 3d editor, added a basic transform gizmo to the entity editor

Ivan Safrin 12 лет назад
Родитель
Сommit
80a1443ba0

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

@@ -669,8 +669,9 @@ namespace Polycode {
 			
 			void doUpdates();				
 			virtual Matrix4 buildPositionMatrix();
-			void setRenderer(Renderer *renderer);						
+			void setRenderer(Renderer *renderer);
 			
+			virtual bool customHitDetection(const Ray &ray) { return true; }			
 			
 			Vector3 bBox;			
 			bool ignoreParentMatrix;

+ 3 - 0
Core/Contents/Include/PolyRay.h

@@ -24,6 +24,7 @@
 #include "PolyGlobals.h"
 #include "PolyVector3.h"
 #include "PolyMatrix4.h"
+#include "PolyPolygon.h"
 
 namespace Polycode {
 
@@ -39,6 +40,8 @@ namespace Polycode {
 			
 			Vector3 planeIntersectPoint(const Vector3 &planeNormal, Number planeDistance) const;
 			Ray tranformByMatrix(const Matrix4& matrix) const;
+			
+			bool polygonIntersect(Polycode::Polygon *polygon) const;
 		
 			Vector3 origin;
 			Vector3 direction;

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

@@ -173,7 +173,12 @@ namespace Polycode {
 			bool ownsSkeleton;
 			
 			bool overlayWireframe;
-			Color wireFrameColor;			
+			Color wireFrameColor;	
+			
+			bool useGeometryHitDetection;
+			
+			bool customHitDetection(const Ray &ray);			
+
 			
 		protected:
 		

+ 19 - 17
Core/Contents/Source/PolyEntity.cpp

@@ -918,25 +918,27 @@ MouseEventResult Entity::onMouseDown(const Ray &ray, int mouseButton, int timest
 	
 	if(processInputEvents && enabled) {
 		if(ray.boxIntersect(bBox, getAnchorAdjustedMatrix())) {
-			ret.hit = true;	
-			
-			Vector3 localCoordinate = Vector3(ray.origin.x,ray.origin.y,0);
-			Matrix4 inverse = getConcatenatedMatrix().Inverse();
-			localCoordinate = inverse * localCoordinate;			
-			
-			InputEvent *inputEvent = new InputEvent(Vector2(localCoordinate.x, localCoordinate.y*yAdjust), timestamp);
-			inputEvent->mouseButton = mouseButton;
-			dispatchEvent(inputEvent, InputEvent::EVENT_MOUSEDOWN);
-			
-			if(timestamp - lastClickTicks < 400) {
+			if(customHitDetection(ray)) {
+				ret.hit = true;	
+				
+				Vector3 localCoordinate = Vector3(ray.origin.x,ray.origin.y,0);
+				Matrix4 inverse = getConcatenatedMatrix().Inverse();
+				localCoordinate = inverse * localCoordinate;			
+				
 				InputEvent *inputEvent = new InputEvent(Vector2(localCoordinate.x, localCoordinate.y*yAdjust), timestamp);
 				inputEvent->mouseButton = mouseButton;
-				dispatchEvent(inputEvent, InputEvent::EVENT_DOUBLECLICK);
-			}
-			lastClickTicks = timestamp;			
-						
-			if(blockMouseInput) {
-				ret.blocked = true;
+				dispatchEvent(inputEvent, InputEvent::EVENT_MOUSEDOWN);
+				
+				if(timestamp - lastClickTicks < 400) {
+					InputEvent *inputEvent = new InputEvent(Vector2(localCoordinate.x, localCoordinate.y*yAdjust), timestamp);
+					inputEvent->mouseButton = mouseButton;
+					dispatchEvent(inputEvent, InputEvent::EVENT_DOUBLECLICK);
+				}
+				lastClickTicks = timestamp;			
+							
+				if(blockMouseInput) {
+					ret.blocked = true;
+				}
 			}
 		}
 		

+ 43 - 0
Core/Contents/Source/PolyRay.cpp

@@ -55,6 +55,49 @@ Vector3 Ray::planeIntersectPoint(const Vector3 &planeNormal, Number planeDistanc
 	 return origin + direction * (-distanceToOrigin / direction.dot(planeNormal));
 }
 
+bool Ray::polygonIntersect(Polycode::Polygon *polygon) const {
+
+	if(polygon->getVertexCount() < 3) {
+		return false;
+	}
+	
+	Number t,u,v;
+	t = 0; u = 0; v = 0;
+
+	Vector3 edge1 = (*(Vector3*)polygon->getVertex(1)) - (*(Vector3*)polygon->getVertex(0));
+	Vector3 edge2 = (*(Vector3*)polygon->getVertex(2)) - (*(Vector3*)polygon->getVertex(0));
+
+	Vector3 tvec, pvec, qvec;
+	Number det, inv_det;
+
+	pvec = direction.crossProduct(edge2);
+	det = edge1.dot(pvec);
+
+	if (det > -0.00001f)
+			return false;
+
+	inv_det = 1.0f / det;
+
+	tvec = origin - (*(Vector3*)polygon->getVertex(0));
+
+	u = tvec.dot(pvec) * inv_det;
+	if (u < -0.001f || u > 1.001f)
+			return false;
+
+	qvec = tvec.crossProduct(edge1);
+
+	v = direction.dot(qvec) * inv_det;
+	if (v < -0.001f || u + v > 1.001f)
+			return false;
+
+	t = edge2.dot(qvec) * inv_det;
+
+	if (t <= 0)
+			return false;
+			
+	return true;
+}
+
 bool Ray::boxIntersect(const Vector3 &box, const Matrix4 &transformMatrix, float near, float far) const {	
 
 	if(box.x == 0 || box.y == 0 || box.z == 0)

+ 24 - 3
Core/Contents/Source/PolySceneMesh.cpp

@@ -58,6 +58,7 @@ SceneMesh::SceneMesh(const String& fileName) : Entity(), texture(NULL), material
 	pointSize = 1.0;
 	pointSmooth = false;
 	overlayWireframe = false;
+	useGeometryHitDetection = false;
 }
 
 SceneMesh::SceneMesh(Mesh *mesh) : Entity(), texture(NULL), material(NULL), skeleton(NULL), localShaderOptions(NULL) {
@@ -73,8 +74,8 @@ SceneMesh::SceneMesh(Mesh *mesh) : Entity(), texture(NULL), material(NULL), skel
 	lineWidth = 1.0;
 	pointSize = 1.0;
 	pointSmooth = false;
-	overlayWireframe = false;		
-		
+	overlayWireframe = false;	
+	useGeometryHitDetection = false;
 }
 
 SceneMesh::SceneMesh(int meshType) : texture(NULL), material(NULL), skeleton(NULL), localShaderOptions(NULL) {
@@ -88,7 +89,8 @@ SceneMesh::SceneMesh(int meshType) : texture(NULL), material(NULL), skeleton(NUL
 	ownsMesh = true;
 	ownsSkeleton = true;	
 	lineWidth = 1.0;
-	overlayWireframe = false;		
+	overlayWireframe = false;
+	useGeometryHitDetection = false;			
 }
 
 void SceneMesh::setMesh(Mesh *mesh) {
@@ -278,6 +280,25 @@ void SceneMesh::cacheToVertexBuffer(bool cache) {
 	useVertexBuffer = cache;
 }
 
+bool SceneMesh::customHitDetection(const Ray &ray) {
+	if(!useGeometryHitDetection)
+		return true;
+	
+	Ray transformedRay;
+	
+	Matrix4 adjustedMatrix = getAnchorAdjustedMatrix().Inverse();
+	transformedRay.origin = adjustedMatrix * ray.origin;
+	transformedRay.direction = adjustedMatrix.rotateVector(ray.direction);
+	
+	for(int i=0; i < mesh->getPolygonCount(); i++) {
+		if(transformedRay.polygonIntersect(mesh->getPolygon(i))) {
+			return true;
+		}
+	}
+	
+	return false;
+}
+
 void SceneMesh::Render() {
 	
 	Renderer *renderer = CoreServices::getInstance()->getRenderer();

+ 34 - 6
IDE/Build/Mac OS X/Polycode.xcodeproj/project.pbxproj

@@ -37,7 +37,9 @@
 		6DC825791648571E006AFC03 /* ExportProjectWindow.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6DC825781648571E006AFC03 /* ExportProjectWindow.cpp */; };
 		6DCAFD4314B519C900039F34 /* ExampleBrowserWindow.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6DCAFD4214B519C900039F34 /* ExampleBrowserWindow.cpp */; };
 		6DCB6026181F1F4B006701AF /* PolycodeEntityEditor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6DCB6025181F1F4B006701AF /* PolycodeEntityEditor.cpp */; };
-		6DCB602B18219FF1006701AF /* TrackballCamera.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6DCB602A18219FF1006701AF /* TrackballCamera.cpp */; };
+		6DCB602F1822EA84006701AF /* TrackballCamera.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6DCB602E1822EA84006701AF /* TrackballCamera.cpp */; };
+		6DCB60321822EADE006701AF /* TransformGizmo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6DCB60311822EADE006701AF /* TransformGizmo.cpp */; };
+		6DCB60351822EBDD006701AF /* EditorGrid.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6DCB60341822EBDD006701AF /* EditorGrid.cpp */; };
 		6DCE857A12AE018800566FAE /* PolycodeEditor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6DCE857812AE018800566FAE /* PolycodeEditor.cpp */; };
 		6DCE857B12AE018800566FAE /* PolycodeEditorManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6DCE857912AE018800566FAE /* PolycodeEditorManager.cpp */; };
 		6DCE85B712AE082B00566FAE /* PolycodeImageEditor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6DCE85B612AE082B00566FAE /* PolycodeImageEditor.cpp */; };
@@ -134,8 +136,12 @@
 		6DCAFD4614B51A2D00039F34 /* ExampleBrowserWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExampleBrowserWindow.h; sourceTree = "<group>"; };
 		6DCB6023181F1F44006701AF /* PolycodeEntityEditor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PolycodeEntityEditor.h; sourceTree = "<group>"; };
 		6DCB6025181F1F4B006701AF /* PolycodeEntityEditor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PolycodeEntityEditor.cpp; sourceTree = "<group>"; };
-		6DCB602818219FDF006701AF /* TrackballCamera.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TrackballCamera.h; path = utils/TrackballCamera.h; sourceTree = "<group>"; };
-		6DCB602A18219FF1006701AF /* TrackballCamera.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TrackballCamera.cpp; path = utils/TrackballCamera.cpp; sourceTree = "<group>"; };
+		6DCB602D1822EA7E006701AF /* TrackballCamera.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TrackballCamera.h; sourceTree = "<group>"; };
+		6DCB602E1822EA84006701AF /* TrackballCamera.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TrackballCamera.cpp; sourceTree = "<group>"; };
+		6DCB60311822EADE006701AF /* TransformGizmo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TransformGizmo.cpp; sourceTree = "<group>"; };
+		6DCB60331822EAE5006701AF /* TransformGizmo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TransformGizmo.h; sourceTree = "<group>"; };
+		6DCB60341822EBDD006701AF /* EditorGrid.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EditorGrid.cpp; sourceTree = "<group>"; };
+		6DCB60361822EDB1006701AF /* EditorGrid.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EditorGrid.h; sourceTree = "<group>"; };
 		6DCE857612AE018000566FAE /* PolycodeEditor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PolycodeEditor.h; sourceTree = "<group>"; };
 		6DCE857712AE018000566FAE /* PolycodeEditorManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PolycodeEditorManager.h; sourceTree = "<group>"; };
 		6DCE857812AE018800566FAE /* PolycodeEditor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PolycodeEditor.cpp; sourceTree = "<group>"; };
@@ -283,6 +289,7 @@
 		6D80E91212AB53FB0037A708 /* Include */ = {
 			isa = PBXGroup;
 			children = (
+				6DCB602C1822EA4A006701AF /* entity_editor */,
 				6DCB602718219FD5006701AF /* utils */,
 				6DCB6023181F1F44006701AF /* PolycodeEntityEditor.h */,
 				6D0F6B5F18170C0400C5327F /* PolycodeMeshEditor.h */,
@@ -320,6 +327,7 @@
 		6D80E91812AB53FB0037A708 /* Source */ = {
 			isa = PBXGroup;
 			children = (
+				6DCB60301822EAD5006701AF /* entity_editor */,
 				6DCB602918219FE7006701AF /* utils */,
 				6DCB6025181F1F4B006701AF /* PolycodeEntityEditor.cpp */,
 				6D0F6B6118170C1000C5327F /* PolycodeMeshEditor.cpp */,
@@ -356,7 +364,7 @@
 		6DCB602718219FD5006701AF /* utils */ = {
 			isa = PBXGroup;
 			children = (
-				6DCB602818219FDF006701AF /* TrackballCamera.h */,
+				6DCB602D1822EA7E006701AF /* TrackballCamera.h */,
 			);
 			name = utils;
 			sourceTree = "<group>";
@@ -364,11 +372,29 @@
 		6DCB602918219FE7006701AF /* utils */ = {
 			isa = PBXGroup;
 			children = (
-				6DCB602A18219FF1006701AF /* TrackballCamera.cpp */,
+				6DCB602E1822EA84006701AF /* TrackballCamera.cpp */,
 			);
 			name = utils;
 			sourceTree = "<group>";
 		};
+		6DCB602C1822EA4A006701AF /* entity_editor */ = {
+			isa = PBXGroup;
+			children = (
+				6DCB60361822EDB1006701AF /* EditorGrid.h */,
+				6DCB60331822EAE5006701AF /* TransformGizmo.h */,
+			);
+			name = entity_editor;
+			sourceTree = "<group>";
+		};
+		6DCB60301822EAD5006701AF /* entity_editor */ = {
+			isa = PBXGroup;
+			children = (
+				6DCB60341822EBDD006701AF /* EditorGrid.cpp */,
+				6DCB60311822EADE006701AF /* TransformGizmo.cpp */,
+			);
+			name = entity_editor;
+			sourceTree = "<group>";
+		};
 /* End PBXGroup section */
 
 /* Begin PBXNativeTarget section */
@@ -483,7 +509,9 @@
 				6D128ABD174A9940007B0375 /* SettingsWindow.cpp in Sources */,
 				6D0F6B6218170C1000C5327F /* PolycodeMeshEditor.cpp in Sources */,
 				6DCB6026181F1F4B006701AF /* PolycodeEntityEditor.cpp in Sources */,
-				6DCB602B18219FF1006701AF /* TrackballCamera.cpp in Sources */,
+				6DCB602F1822EA84006701AF /* TrackballCamera.cpp in Sources */,
+				6DCB60321822EADE006701AF /* TransformGizmo.cpp in Sources */,
+				6DCB60351822EBDD006701AF /* EditorGrid.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

+ 39 - 0
IDE/Contents/Include/EditorGrid.h

@@ -0,0 +1,39 @@
+/*
+ Copyright (C) 2013 by Ivan Safrin
+ 
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+ 
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+ 
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ */
+
+#pragma once
+
+#include "Polycode.h"
+#include "OSBasics.h"
+
+using namespace Polycode;
+
+class EditorGrid : public Entity {
+	public:
+		EditorGrid();
+		~EditorGrid();
+		
+		void setGrid(int gridSize);
+		
+	private:
+		SceneMesh *grid;
+};

+ 8 - 60
IDE/Contents/Include/PolycodeEntityEditor.h

@@ -26,66 +26,13 @@
 #include "PolyUIElement.h"
 #include <Polycode.h>
 #include "PolycodeUI.h"
-#include "utils/TrackballCamera.h"
 
-using namespace Polycode;
+#include "TrackballCamera.h"
 
-class TransformGizmo : public Entity {
-	public:
-		TransformGizmo(Scene *targetScene, Camera *targetCamera);
-		~TransformGizmo();
-		
-		void handleEvent(Event *event);		
-		
-		void setTransformMode(int newMode);
-		
-		void Update();
-		
-		void setTransformSelection(std::vector<Entity*> selectedEntities);
-		
-		void transfromSelectedEntities(const Vector3 &move, const Vector3 &scale);	
-		Vector3 getTransformPlanePosition();
-		
-		static const int TRANSFORM_MOVE = 0;		
-		static const int TRANSFORM_SCALE = 1;
-		static const int TRANSFORM_ROTATE = 2;
-								
-	private:
-	
-		std::vector<Entity*> selectedEntities;
-	
-		Scene *targetScene;
-		Camera *targetCamera;
-	
-		CoreInput *coreInput;
-		int mode;
-		bool transforming;
-		
-		Vector3 transformConstraint;
-		Vector3 transformPlane;
-				
-		Vector3 startingPoint;
-					
-		Entity *trasnformDecorators;
-		Entity *scaleDecorators;
-		Entity *transformAndScaleLines;			
-		Entity *rotateDectorators;	
-							
-		Entity *xTransformGrip;
-		Entity *yTransformGrip;
-		Entity *zTransformGrip;				
-};
+#include "TransformGizmo.h"
+#include "EditorGrid.h"
 
-class EditorGrid : public Entity {
-	public:
-		EditorGrid();
-		~EditorGrid();
-		
-		void setGrid(int gridSize);
-		
-	private:
-		SceneMesh *grid;
-};
+using namespace Polycode;
 
 class EntityEditorMainView : public UIElement {
 		public:
@@ -105,14 +52,15 @@ class EntityEditorMainView : public UIElement {
 			
 			Scene *mainScene;
 			SceneRenderTexture *renderTexture;
-			UIRect *renderTextureShape;			
+			UIRect *renderTextureShape;	
 
 			TransformGizmo *transformGizmo;
+			TransformGizmoMenu *transformGizmoMenu;
 			TrackballCamera *trackballCamera;
-			EditorGrid *grid;
-			
+			EditorGrid *grid;			
 };
 
+
 class PolycodeEntityEditor : public PolycodeEditor {
 	public:
 		PolycodeEntityEditor();

+ 69 - 0
IDE/Contents/Include/TrackballCamera.h

@@ -0,0 +1,69 @@
+/*
+ Copyright (C) 2013 by Ivan Safrin
+ 
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+ 
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+ 
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ */
+
+#pragma once
+
+#include "Polycode.h"
+#include "OSBasics.h"
+
+using namespace Polycode;
+
+class TrackballCamera : public EventHandler {
+	public:
+		TrackballCamera(Camera *targetCamera, Entity *trackballShape);
+		~TrackballCamera();
+		
+		void handleEvent(Event *event);		
+		void setOrbitingCenter(const Vector3 &newCenter);
+		void setCameraDistance(Number cameraDistance);
+		Camera *getTargetCamera();
+		
+		static const int MOUSE_MODE_IDLE = 0;
+		static const int MOUSE_MODE_ORBITING = 1;
+		static const int MOUSE_MODE_PANNING = 2;
+		static const int MOUSE_MODE_ZOOMING = 3;				
+		
+		Number trackballPanSpeed;
+		Number trackballZoomSpeed;	
+		Number trackballRotateSpeed;
+		
+	private:
+	
+		int mouseMode;
+	
+		Vector3 getMouseProjectionOnBall(const Vector2 &mousePosition);
+		void updateCamera();	
+		void processMouseMovement(const Vector2 &newPosition);
+		
+		Camera *targetCamera;
+		Entity *trackballShape;
+		
+		Vector2 trackBallMouseStart;
+		Vector2 trackBallMouseEnd;			
+		Vector3 orbitingCenter;
+		Vector3 trackballRotateStart;
+		Vector3 trackballRotateEnd;	
+		Vector3 trackballEye;		
+		Number cameraDistance;
+		CoreInput *coreInput;		
+		
+};

+ 101 - 0
IDE/Contents/Include/TransformGizmo.h

@@ -0,0 +1,101 @@
+/*
+ Copyright (C) 2013 by Ivan Safrin
+ 
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+ 
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+ 
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ */
+
+#pragma once
+
+#include "Polycode.h"
+#include "OSBasics.h"
+#include "PolycodeUI.h"
+
+using namespace Polycode;
+
+class TransformGizmo : public Entity {
+	public:
+		TransformGizmo(Scene *targetScene, Camera *targetCamera);
+		~TransformGizmo();
+		
+		void handleEvent(Event *event);		
+		
+		void setTransformMode(int newMode);
+		
+		void Update();
+		
+		void setTransformSelection(std::vector<Entity*> selectedEntities);
+		
+		void transfromSelectedEntities(const Vector3 &move, const Vector3 &scale, Number rotate);
+		Vector3 getTransformPlanePosition();
+		
+		Number getTransformPlaneAngle();
+		
+		static const int TRANSFORM_MOVE = 0;		
+		static const int TRANSFORM_SCALE = 1;
+		static const int TRANSFORM_ROTATE = 2;
+								
+	private:
+	
+		std::vector<Entity*> selectedEntities;
+	
+		Scene *targetScene;
+		Camera *targetCamera;
+	
+		CoreInput *coreInput;
+		int mode;
+		bool transforming;
+		
+		Vector3 transformConstraint;
+		Vector3 transformPlane;
+				
+		Vector3 startingPoint;
+		Number startingAngle;
+					
+		Entity *trasnformDecorators;
+		Entity *scaleDecorators;
+		Entity *transformAndScaleLines;			
+		Entity *rotateDectorators;	
+							
+		Entity *xTransformGrip;
+		Entity *yTransformGrip;
+		Entity *zTransformGrip;	
+		
+		ScenePrimitive *pitchGrip;
+		ScenePrimitive *rollGrip;
+		ScenePrimitive *yawGrip;				
+};
+
+class TransformGizmoMenu : public UIElement {
+	public:
+		TransformGizmoMenu(TransformGizmo *gizmo);
+		~TransformGizmoMenu();
+		
+		void handleEvent(Event *event);
+		
+	private:
+	
+		UIImageButton *moveModeButton;
+		UIImageButton *scaleModeButton;
+		UIImageButton *rotateModeButton;
+		
+		TransformGizmo *gizmo;
+		
+		UIRect *bg;
+};
+

+ 62 - 0
IDE/Contents/Source/EditorGrid.cpp

@@ -0,0 +1,62 @@
+/*
+ Copyright (C) 2013 by Ivan Safrin
+ 
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+ 
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+ 
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ */
+ 
+#include "EditorGrid.h"
+
+EditorGrid::EditorGrid() : Entity() {
+	grid = NULL;
+	setGrid(1.0);
+	setPitch(90);
+}
+
+void EditorGrid::setGrid(int gridSize) {
+	Polycode::Polygon *gridPoly = new Polycode::Polygon();
+	int gridLen = 16;
+	
+	for(int x=0; x < gridLen+1; x++) {
+			gridPoly->addVertex(x * gridSize,0, 0);
+			gridPoly->addVertex(x * gridSize,gridSize * gridLen, 0);
+	}
+
+	for(int y=0; y < gridLen+1; y++) {
+			gridPoly->addVertex(0, y * gridSize, 0);
+			gridPoly->addVertex(gridSize * gridLen, y * gridSize, 0);                
+	}        
+
+	if(grid) {
+			grid->getMesh()->clearMesh();
+			grid->getMesh()->addPolygon(gridPoly);
+	} else {
+			Mesh *gridMesh = new Mesh(Mesh::LINE_MESH);
+			gridMesh->addPolygon(gridPoly);
+				
+			grid = new SceneMesh(gridMesh);
+			grid->setColor(1.0, 1.0, 1.0, 0.1);
+			addChild(grid);                
+			grid->setPosition(-gridSize * gridLen * 0.5, -gridSize * gridLen * 0.5);
+	}
+}
+
+
+EditorGrid::~EditorGrid() {
+
+}

+ 5 - 358
IDE/Contents/Source/PolycodeEntityEditor.cpp

@@ -22,358 +22,6 @@
  
 #include "PolycodeEntityEditor.h"
 
-TransformGizmo::TransformGizmo(Scene *targetScene, Camera *targetCamera) : Entity() {
-	processInputEvents = true;
-	
-	this->targetScene = targetScene;
-	this->targetCamera = targetCamera;
-	
-	trasnformDecorators = new Entity();
-	addChild(trasnformDecorators);
-	
-	scaleDecorators = new Entity();
-	addChild(scaleDecorators);
-		
-	transformAndScaleLines = new Entity();
-	addChild(transformAndScaleLines);
-		
-	rotateDectorators = new Entity();
-	addChild(rotateDectorators);	
-	
-			
-	SceneMesh *yLine = new SceneMesh(Mesh::LINE_MESH);	
-	Polycode::Polygon *poly = new Polycode::Polygon();
-	poly->addVertex(0.0, 0.0, 0.0);
-	poly->addVertex(0.0, 1.0, 0.0);	
-	yLine->getMesh()->addPolygon(poly);
-	yLine->getMesh()->dirtyArrays();
-	yLine->depthTest = false;
-	yLine->setColor(0.0, 1.0, 0.0, 1.0);
-	transformAndScaleLines->addChild(yLine);
-
-	SceneMesh *xLine = new SceneMesh(Mesh::LINE_MESH);	
-	poly = new Polycode::Polygon();
-	poly->addVertex(0.0, 0.0, 0.0);
-	poly->addVertex(1.0, 0.0, 0.0);	
-	xLine->getMesh()->addPolygon(poly);
-	xLine->getMesh()->dirtyArrays();
-	xLine->depthTest = false;
-	xLine->setColor(1.0, 0.0, 0.0, 1.0);
-	transformAndScaleLines->addChild(xLine);
-
-	SceneMesh *zLine = new SceneMesh(Mesh::LINE_MESH);	
-	poly = new Polycode::Polygon();
-	poly->addVertex(0.0, 0.0, 0.0);
-	poly->addVertex(0.0, 0.0, 1.0);	
-	zLine->getMesh()->addPolygon(poly);
-	zLine->getMesh()->dirtyArrays();
-	zLine->depthTest = false;
-	zLine->setColor(0.0, 0.0, 1.0, 1.0);
-	transformAndScaleLines->addChild(zLine);
-	
-	// MOVE
-	
-	ScenePrimitive *yArrow = new ScenePrimitive(ScenePrimitive::TYPE_CONE, 0.2, 0.05, 12);
-	yArrow->setColor(0.0, 1.0, 0.0, 1.0);
-	yArrow->setPosition(0.0, 1.0, 0.0);
-	yArrow->depthTest = false;
-	trasnformDecorators->addChild(yArrow);
-	
-	ScenePrimitive *xArrow = new ScenePrimitive(ScenePrimitive::TYPE_CONE, 0.2, 0.05, 12);
-	xArrow->setColor(1.0, 0.0, 0.0, 1.0);
-	xArrow->setPosition(1.0, 0.0, 0.0);
-	xArrow->Roll(-90);
-	xArrow->depthTest = false;
-	trasnformDecorators->addChild(xArrow);
-
-	ScenePrimitive *zArrow = new ScenePrimitive(ScenePrimitive::TYPE_CONE, 0.2, 0.05, 12);
-	zArrow->setColor(0.0, 0.0, 1.0, 1.0);
-	zArrow->setPosition(0.0, 0.0, 1.0);
-	zArrow->Pitch(90);
-	zArrow->depthTest = false;	
-	trasnformDecorators->addChild(zArrow);
-
-	// SCALE
-
-	ScenePrimitive *yBox = new ScenePrimitive(ScenePrimitive::TYPE_BOX, 0.1, 0.1, 0.1);
-	yBox->setColor(0.0, 1.0, 0.0, 1.0);
-	yBox->setPosition(0.0, 1.0, 0.0);
-	yBox->depthTest = false;
-	scaleDecorators->addChild(yBox);
-	
-	ScenePrimitive *xBox = new ScenePrimitive(ScenePrimitive::TYPE_BOX, 0.1, 0.1, 0.1);
-	xBox->setColor(1.0, 0.0, 0.0, 1.0);
-	xBox->setPosition(1.0, 0.0, 0.0);
-	xBox->Roll(-90);
-	xBox->depthTest = false;
-	scaleDecorators->addChild(xBox);
-
-	ScenePrimitive *zBox = new ScenePrimitive(ScenePrimitive::TYPE_BOX, 0.1, 0.1, 0.1);
-	zBox->setColor(0.0, 0.0, 1.0, 1.0);
-	zBox->setPosition(0.0, 0.0, 1.0);
-	zBox->Pitch(90);
-	zBox->depthTest = false;	
-	scaleDecorators->addChild(zBox);
-
-	// ROTATE
-
-	ScenePrimitive *bgCircle = new ScenePrimitive(ScenePrimitive::TYPE_CIRCLE, 1.6, 1.6, 32);
-	bgCircle->getMesh()->setMeshType(Mesh::LINE_LOOP_MESH);
-	bgCircle->setColor(0.0, 0.0, 0.0, 1.0);
-	bgCircle->depthTest = false;
-	bgCircle->billboardMode = true;
-	rotateDectorators->addChild(bgCircle);
-
-	ScenePrimitive *outerCircle = new ScenePrimitive(ScenePrimitive::TYPE_CIRCLE, 2.0, 2.0, 32);
-	outerCircle->getMesh()->setMeshType(Mesh::LINE_LOOP_MESH);
-	outerCircle->setColor(1.0, 1.0, 1.0, 1.0);
-	outerCircle->depthTest = false;
-	outerCircle->billboardMode = true;
-	rotateDectorators->addChild(outerCircle);
-	
-	ScenePrimitive *pitchCircle = new ScenePrimitive(ScenePrimitive::TYPE_CIRCLE, 1.6, 1.6, 32);
-	pitchCircle->getMesh()->setMeshType(Mesh::LINE_LOOP_MESH);
-	pitchCircle->setColor(1.0, 0.0, 0.0, 1.0);
-	pitchCircle->depthTest = false;
-	pitchCircle->Yaw(90);	
-	rotateDectorators->addChild(pitchCircle);
-	pitchCircle->setMaterialByName("OneSidedLine");
-
-	ScenePrimitive *yawCircle = new ScenePrimitive(ScenePrimitive::TYPE_CIRCLE, 1.6, 1.6, 32);
-	yawCircle->getMesh()->setMeshType(Mesh::LINE_LOOP_MESH);
-	yawCircle->setColor(0.0, 1.0, 0.0, 1.0);
-	yawCircle->depthTest = false;
-	yawCircle->Pitch(90);
-	rotateDectorators->addChild(yawCircle);
-	yawCircle->setMaterialByName("OneSidedLine");
-	
-	ScenePrimitive *rollCircle = new ScenePrimitive(ScenePrimitive::TYPE_CIRCLE, 1.6, 1.6, 32);
-	rollCircle->getMesh()->setMeshType(Mesh::LINE_LOOP_MESH);
-	rollCircle->setColor(0.0, 0.0, 1.0, 1.0);
-	rollCircle->depthTest = false;
-	rotateDectorators->addChild(rollCircle);
-	rollCircle->setMaterialByName("OneSidedLine");
-		
-	pitchCircle->lineWidth = 2.0;	
-	yawCircle->lineWidth = 2.0;
-	rollCircle->lineWidth = 2.0;		
-	
-	xTransformGrip = new Entity();
-	xTransformGrip->bBox.set(1.3, 0.1, 0.1);
-	addChild(xTransformGrip);
-	xTransformGrip->setAnchorPoint(Vector3(-1.0, 0.0, 0.0));
-	xTransformGrip->processInputEvents = true;
-	xTransformGrip->addEventListener(this, InputEvent::EVENT_MOUSEDOWN);
-
-	yTransformGrip = new Entity();
-	yTransformGrip->bBox.set(0.1, 1.3, 0.1);
-	addChild(yTransformGrip);
-	yTransformGrip->setAnchorPoint(Vector3(0.0, -1.0, 0.0));
-	yTransformGrip->processInputEvents = true;
-	yTransformGrip->addEventListener(this, InputEvent::EVENT_MOUSEDOWN);
-
-	zTransformGrip = new Entity();
-	zTransformGrip->bBox.set(0.1, 0.1, 1.3);
-	addChild(zTransformGrip);
-	zTransformGrip->setAnchorPoint(Vector3(0.0, 0.0, -1.0));
-	zTransformGrip->processInputEvents = true;
-	zTransformGrip->addEventListener(this, InputEvent::EVENT_MOUSEDOWN);
-
-
-		
-	transforming = false;
-	mode = TRANSFORM_MOVE;
-	
-	visible = false;
-	enabled = false;
-	
-	coreInput = CoreServices::getInstance()->getCore()->getInput();
-	coreInput->addEventListener(this, InputEvent::EVENT_MOUSEMOVE);
-	coreInput->addEventListener(this, InputEvent::EVENT_MOUSEUP);	
-	
-	setTransformMode(TRANSFORM_MOVE);
-}
-
-Vector3 TransformGizmo::getTransformPlanePosition() {
-
-	Number planeDistance = 0;
-	if(transformPlane.x > 0) {
-		planeDistance = getPosition().x;
-	} else if(transformPlane.y > 0.0) {
-		planeDistance = getPosition().y;	
-	} else if(transformPlane.z > 0.0) {
-		planeDistance = getPosition().z;	
-	}
-	Ray ray = targetScene->projectRayFromCameraAndViewportCoordinate(targetCamera, coreInput->getMousePosition());	
-	
-	return ray.planeIntersectPoint(transformPlane, planeDistance);
-}
-
-void TransformGizmo::setTransformMode(int newMode) {
-
-	trasnformDecorators->visible = false;
-	scaleDecorators->visible = false;
-	transformAndScaleLines->visible = false;
-	rotateDectorators->visible = false;
-	xTransformGrip->enabled = false;
-	yTransformGrip->enabled = false;
-	zTransformGrip->enabled = false;
-			
-	mode = newMode;
-	switch (mode) {
-		case TRANSFORM_MOVE:
-			trasnformDecorators->visible = true;
-			transformAndScaleLines->visible = true;
-			xTransformGrip->enabled = true;
-			yTransformGrip->enabled = true;
-			zTransformGrip->enabled = true;						
-		break;
-		case TRANSFORM_SCALE:
-			scaleDecorators->visible = true;
-			transformAndScaleLines->visible = true;					
-			xTransformGrip->enabled = true;
-			yTransformGrip->enabled = true;
-			zTransformGrip->enabled = true;				
-		break;	
-		case TRANSFORM_ROTATE:
-			rotateDectorators->visible = true;
-		break;
-		default:
-			assert(false); // invalid mode
-		break;
-	}
-}
-
-void TransformGizmo::setTransformSelection(std::vector<Entity*> selectedEntities) {
-	this->selectedEntities = selectedEntities;
-	if(selectedEntities.size() > 0) {
-		visible = true;
-		enabled = true;
-		
-		Vector3 centerPoint;
-		for(int i=0; i < selectedEntities.size(); i++) {
-			centerPoint += selectedEntities[i]->getConcatenatedMatrix().getPosition();			
-		}
-		centerPoint = centerPoint / selectedEntities.size();
-		setPosition(centerPoint);
-	} else {
-		visible = false;
-		enabled = false;
-	}
-	
-}
-
-void TransformGizmo::transfromSelectedEntities(const Vector3 &move, const Vector3 &scale) {
-	for(int i=0; i < selectedEntities.size(); i++) {
-		selectedEntities[i]->Translate(move);
-		selectedEntities[i]->setScale(selectedEntities[i]->getScale() + scale);
-	}
-	Translate(move);
-}
-
-void TransformGizmo::handleEvent(Event *event) {
-	if(event->getDispatcher() == xTransformGrip) {
-		if(event->getEventCode() == InputEvent::EVENT_MOUSEDOWN) {
-			transforming = true;
-			transformConstraint = Vector3(1.0, 0.0, 0.0);
-			transformPlane = Vector3(0.0, 1.0, 0.0);
-			startingPoint = getTransformPlanePosition();
-		}
-	} else 	if(event->getDispatcher() == yTransformGrip) {
-		if(event->getEventCode() == InputEvent::EVENT_MOUSEDOWN) {
-			transforming = true;
-			transformConstraint = Vector3(0.0, 1.0, 0.0);
-			transformPlane = Vector3(0.0, 0.0, 1.0);			
-			startingPoint = getTransformPlanePosition();
-		}
-	} else 	if(event->getDispatcher() == zTransformGrip) {
-		if(event->getEventCode() == InputEvent::EVENT_MOUSEDOWN) {
-			transforming = true;
-			transformConstraint = Vector3(0.0, 0.0, 1.0);
-			transformPlane = Vector3(0.0, 1.0, 0.0);			
-			startingPoint = getTransformPlanePosition();
-		}		
-	} else if(event->getDispatcher() == coreInput && transforming) {
-		InputEvent *inputEvent = (InputEvent*) event;
-		switch(event->getEventCode()) {
-			case InputEvent::EVENT_MOUSEMOVE:
-			{
-				switch(mode) {
-					case TRANSFORM_MOVE:
-					{
-						Vector3 newPoint = getTransformPlanePosition();
-						transfromSelectedEntities((newPoint-startingPoint) * transformConstraint, Vector3(0.0, 0.0, 0.0));
-						startingPoint = newPoint;
-					}
-					break;
-					case TRANSFORM_SCALE:
-					{
-						Vector3 newPoint = getTransformPlanePosition();
-						transfromSelectedEntities(Vector3(0.0, 0.0, 0.0), ((newPoint-startingPoint) * transformConstraint));
-						startingPoint = newPoint;					
-					}
-					break;
-				}
-			}
-			break;
-			case InputEvent::EVENT_MOUSEUP:
-			{
-				transforming = false;
-			}
-			break;
-		}
-	}
-}
-
-TransformGizmo::~TransformGizmo() {
-
-}
-
-void TransformGizmo::Update() {
-	Number scale = getPosition().distance(targetCamera->getPosition()) * 0.1;
-	setScale(scale, scale, scale);
-}
-
-EditorGrid::EditorGrid() : Entity() {
-	grid = NULL;
-	setGrid(1.0);
-	setPitch(90);
-}
-
-void EditorGrid::setGrid(int gridSize) {
-	Polycode::Polygon *gridPoly = new Polycode::Polygon();
-	int gridLen = 16;
-	
-	for(int x=0; x < gridLen+1; x++) {
-			gridPoly->addVertex(x * gridSize,0, 0);
-			gridPoly->addVertex(x * gridSize,gridSize * gridLen, 0);
-	}
-
-	for(int y=0; y < gridLen+1; y++) {
-			gridPoly->addVertex(0, y * gridSize, 0);
-			gridPoly->addVertex(gridSize * gridLen, y * gridSize, 0);                
-	}        
-
-	if(grid) {
-			grid->getMesh()->clearMesh();
-			grid->getMesh()->addPolygon(gridPoly);
-	} else {
-			Mesh *gridMesh = new Mesh(Mesh::LINE_MESH);
-			gridMesh->addPolygon(gridPoly);
-				
-			grid = new SceneMesh(gridMesh);
-			grid->setColor(1.0, 1.0, 1.0, 0.1);
-			addChild(grid);                
-			grid->setPosition(-gridSize * gridLen * 0.5, -gridSize * gridLen * 0.5);
-	}
-}
-
-
-EditorGrid::~EditorGrid() {
-
-}
-
-
 EntityEditorMainView::EntityEditorMainView() {
 	processInputEvents = true;
 
@@ -392,10 +40,8 @@ EntityEditorMainView::EntityEditorMainView() {
 	sideBar = new Entity();
 	addChild(sideBar);
 	sideBar->setPosition(0, 30);
-	
-	UIImage *sidebarBg = new UIImage("Images/entity_editor/sidebar.png");
-	sideBar->addChild(sidebarBg);
-	
+	sideBar->processInputEvents = true;
+			
 	headerBg = new UIRect(10,10);
 	addChild(headerBg);
 	headerBg->setAnchorPoint(-1.0, -1.0, 0.0);
@@ -422,8 +68,9 @@ EntityEditorMainView::EntityEditorMainView() {
 	mainScene->addChild(transformGizmo);		
 	trackballCamera = new TrackballCamera(mainScene->getDefaultCamera(), renderTextureShape);
 	
-	
-//	transformGizmo->setTransformMode(TransformGizmo::TRANSFORM_ROTATE);
+	transformGizmoMenu = new TransformGizmoMenu(transformGizmo);
+	sideBar->addChild(transformGizmoMenu);
+
 }
 
 void EntityEditorMainView::Update() {

+ 213 - 0
IDE/Contents/Source/TrackballCamera.cpp

@@ -0,0 +1,213 @@
+/*
+ Copyright (C) 2013 by Ivan Safrin
+ 
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+ 
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+ 
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ */
+ 
+#include "TrackballCamera.h"
+
+
+TrackballCamera::TrackballCamera(Camera *targetCamera, Entity *trackballShape) : EventHandler() {
+	mouseMode = MOUSE_MODE_IDLE;
+	
+	this->targetCamera = targetCamera;
+	this->trackballShape = trackballShape;
+	
+	trackballShape->addEventListener(this, InputEvent::EVENT_MOUSEDOWN);
+	trackballShape->addEventListener(this, InputEvent::EVENT_MOUSEUP);
+	trackballShape->addEventListener(this, InputEvent::EVENT_MOUSEMOVE);	
+	trackballShape->addEventListener(this, InputEvent::EVENT_MOUSEUP_OUTSIDE);
+	trackballShape->processInputEvents = true;
+	
+	trackballRotateSpeed = 1.0;
+	trackballPanSpeed = 0.6;
+	trackballZoomSpeed = 1.0;
+	cameraDistance = 10.0;
+	
+	coreInput = CoreServices::getInstance()->getCore()->getInput();
+	
+	targetCamera->setPosition(cameraDistance, cameraDistance, cameraDistance);
+	trackballRotateEnd = getMouseProjectionOnBall(Vector2(trackballShape->getWidth()/2.0, trackballShape->getHeight()/2.0));
+	trackballRotateStart = trackballRotateEnd;
+	
+	updateCamera();	
+}
+
+TrackballCamera::~TrackballCamera() {
+	trackballShape->removeAllHandlersForListener(this);
+}
+
+void TrackballCamera::setCameraDistance(Number cameraDistance) {
+	this->cameraDistance = cameraDistance;
+	updateCamera();
+}
+
+Camera *TrackballCamera::getTargetCamera() {
+	return targetCamera;
+}
+
+void TrackballCamera::handleEvent(Event *event) {
+
+	if(event->getDispatcher() == trackballShape) {
+		InputEvent *inputEvent = (InputEvent*) event;
+		switch(event->getEventCode()) {
+			case InputEvent::EVENT_MOUSEDOWN:
+				if(coreInput->getKeyState(KEY_LALT) || coreInput->getKeyState(KEY_RALT)) {		
+					if(coreInput->getKeyState(KEY_LSHIFT) || coreInput->getKeyState(KEY_RSHIFT)) {
+						mouseMode = MOUSE_MODE_PANNING;
+						trackBallMouseStart = Vector2(
+							inputEvent->getMousePosition().x / trackballShape->getWidth(),
+							inputEvent->getMousePosition().y / trackballShape->getHeight()
+						);
+						trackBallMouseEnd = trackBallMouseStart;
+					} else if(coreInput->getKeyState(KEY_LCTRL) || coreInput->getKeyState(KEY_RCTRL)) {
+						mouseMode = MOUSE_MODE_ZOOMING;
+						trackBallMouseStart = Vector2(
+							inputEvent->getMousePosition().x / trackballShape->getWidth(),
+							inputEvent->getMousePosition().y / trackballShape->getHeight()
+						);
+						trackBallMouseEnd = trackBallMouseStart;												
+					} else {
+						mouseMode = MOUSE_MODE_ORBITING;
+						trackballRotateStart = trackballRotateEnd = getMouseProjectionOnBall(inputEvent->getMousePosition());
+					}
+				}
+			break;
+			case InputEvent::EVENT_MOUSEUP:
+			case InputEvent::EVENT_MOUSEUP_OUTSIDE:
+				mouseMode = MOUSE_MODE_IDLE;
+			break;
+			case InputEvent::EVENT_MOUSEMOVE:
+				processMouseMovement(inputEvent->getMousePosition());
+			break;						
+		}		
+		return;
+	}
+}
+
+void TrackballCamera::setOrbitingCenter(const Vector3 &newCenter) {
+	orbitingCenter = newCenter;
+	updateCamera();	
+}
+
+void TrackballCamera::processMouseMovement(const Vector2 &newPosition) {
+	switch(mouseMode) {
+		case MOUSE_MODE_ORBITING:
+		{
+			trackballRotateEnd = getMouseProjectionOnBall(newPosition);
+			updateCamera();
+		}	
+		break;
+		case MOUSE_MODE_PANNING:
+		{
+			trackBallMouseEnd  = Vector2(
+							newPosition.x / trackballShape->getWidth(),
+							newPosition.y / trackballShape->getHeight()
+						);
+
+			
+			Vector2 mouseChange = trackBallMouseEnd - trackBallMouseStart;
+			Number mouseChangeLength = mouseChange.length() * mouseChange.length();
+			if(mouseChangeLength) {
+				mouseChange = mouseChange * trackballEye.length() * trackballPanSpeed;
+								
+				Vector3 pan = trackballEye.crossProduct(Vector3(0.0, 1.0, 0.0)).setLength(mouseChange.x);
+				
+				pan = pan + (Vector3(0.0, 1.0, 0.0).setLength(mouseChange.y));
+				
+				targetCamera->Translate(pan);
+				orbitingCenter += pan;
+				trackBallMouseStart = trackBallMouseEnd;
+			}
+		}	
+		break;		
+		case MOUSE_MODE_ZOOMING:
+		{
+			trackBallMouseEnd  = Vector2(
+							newPosition.x / trackballShape->getWidth(),
+							newPosition.y / trackballShape->getHeight()
+						);
+								
+			Number factor = 1.0 + ( trackBallMouseEnd.y - trackBallMouseStart.y ) * trackballZoomSpeed;			
+			if(factor != 1.0 && factor > 0.0 ) {
+				cameraDistance *= factor;
+			}
+			trackBallMouseStart = trackBallMouseEnd;			
+			updateCamera();
+		}
+		break;
+		default:
+		break;
+	}
+}
+
+
+
+void TrackballCamera::updateCamera() {
+
+	trackballEye = targetCamera->getPosition() - orbitingCenter;
+	trackballEye.setLength(cameraDistance);
+	
+	
+	Number angle = acos(trackballRotateStart.dot(trackballRotateEnd) / trackballRotateStart.length() / trackballRotateEnd.length());
+	
+	if(angle == angle) {
+		Vector3 axis = trackballRotateStart.crossProduct(trackballRotateEnd);
+		axis.Normalize();
+		Quaternion q;
+		
+		angle *= trackballRotateSpeed;	
+		q.fromAngleAxis(angle, axis);
+		
+		trackballEye = q.applyTo(trackballEye);
+		trackballRotateEnd = q.applyTo(trackballRotateEnd);
+		
+		trackballRotateStart = trackballRotateEnd;
+	}
+		
+	targetCamera->setPosition(orbitingCenter + trackballEye);	
+	targetCamera->lookAt(orbitingCenter);
+	
+}
+
+Vector3 TrackballCamera::getMouseProjectionOnBall(const Vector2 &mousePosition) {
+
+	Vector3 mouseOnBall = Vector3((mousePosition.x - (trackballShape->getWidth() * 0.5)) / (trackballShape->getWidth() * 0.5),(mousePosition.y - (trackballShape->getHeight() * 0.5)) / (trackballShape->getHeight() * 0.5), 0.0);
+	mouseOnBall.x *= -1;	
+	
+	Number length = mouseOnBall.length();
+	
+
+	if (length < sqrt(0.5)) {
+		mouseOnBall.z = sqrt(1.0 - length*length);
+	} else {
+		mouseOnBall.z = 0.5 / length;
+	}
+
+	trackballEye = targetCamera->getPosition() - orbitingCenter;
+	
+	Vector3 projection = Vector3(0.0, 1.0, 0.0).setLength(mouseOnBall.y);		
+	
+	projection = projection + (Vector3(0.0, 1.0, 0.0).crossProduct(trackballEye).setLength(mouseOnBall.x));				
+	
+	trackballEye.setLength(mouseOnBall.z);
+	projection = projection + (trackballEye);
+	
+	return projection;	
+}

+ 507 - 0
IDE/Contents/Source/TransformGizmo.cpp

@@ -0,0 +1,507 @@
+/*
+ Copyright (C) 2013 by Ivan Safrin
+ 
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+ 
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+ 
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ */
+ 
+#include "TransformGizmo.h"
+
+TransformGizmoMenu::TransformGizmoMenu(TransformGizmo *gizmo) : UIElement() {
+	processInputEvents = true;
+	
+	this->gizmo = gizmo;
+	
+	bg = new UIRect(100, 30);
+	bg->setColor(0.0, 0.0, 0.0, 0.75);
+	addChild(bg);
+	
+	moveModeButton = new UIImageButton("Images/entity_editor/move_gizmo.png");
+	addChild(moveModeButton);
+	moveModeButton->setPosition(4, 2);
+	moveModeButton->addEventListener(this, InputEvent::EVENT_MOUSEDOWN);
+	
+	scaleModeButton = new UIImageButton("Images/entity_editor/scale_gizmo.png");
+	addChild(scaleModeButton);
+	scaleModeButton->setPosition(30, 2);
+	scaleModeButton->addEventListener(this, InputEvent::EVENT_MOUSEDOWN);
+	
+	rotateModeButton = new UIImageButton("Images/entity_editor/rotate_gizmo.png");
+	addChild(rotateModeButton);
+	rotateModeButton->setPosition(60, 2);
+	rotateModeButton->addEventListener(this, InputEvent::EVENT_MOUSEDOWN);
+}
+
+void TransformGizmoMenu::handleEvent(Event *event) {
+	if(event->getDispatcher() == moveModeButton) {
+		gizmo->setTransformMode(TransformGizmo::TRANSFORM_MOVE);
+	} else if(event->getDispatcher() == scaleModeButton) {
+		gizmo->setTransformMode(TransformGizmo::TRANSFORM_SCALE);	
+	} else if(event->getDispatcher() == rotateModeButton) {
+		gizmo->setTransformMode(TransformGizmo::TRANSFORM_ROTATE);	
+	}
+}
+
+TransformGizmoMenu::~TransformGizmoMenu() {
+
+}
+
+
+TransformGizmo::TransformGizmo(Scene *targetScene, Camera *targetCamera) : Entity() {
+	processInputEvents = true;
+	
+	this->targetScene = targetScene;
+	this->targetCamera = targetCamera;
+	
+	ScenePrimitive *centerCircle = new ScenePrimitive(ScenePrimitive::TYPE_CIRCLE, 0.3, 0.3, 16);
+	centerCircle->getMesh()->setMeshType(Mesh::LINE_LOOP_MESH);
+	centerCircle->setColor(0.7, 0.7, 0.7, 1.0);
+	centerCircle->depthTest = false;
+	centerCircle->billboardMode = true;
+	addChild(centerCircle);
+		
+	trasnformDecorators = new Entity();
+	addChild(trasnformDecorators);
+	
+	scaleDecorators = new Entity();
+	addChild(scaleDecorators);
+		
+	transformAndScaleLines = new Entity();
+	addChild(transformAndScaleLines);
+		
+	rotateDectorators = new Entity();
+	addChild(rotateDectorators);	
+		
+			
+	SceneMesh *yLine = new SceneMesh(Mesh::LINE_MESH);	
+	Polycode::Polygon *poly = new Polycode::Polygon();
+	poly->addVertex(0.0, 0.0, 0.0);
+	poly->addVertex(0.0, 1.0, 0.0);	
+	yLine->getMesh()->addPolygon(poly);
+	yLine->getMesh()->dirtyArrays();
+	yLine->depthTest = false;
+	yLine->setColor(0.0, 1.0, 0.0, 1.0);
+	transformAndScaleLines->addChild(yLine);
+
+	SceneMesh *xLine = new SceneMesh(Mesh::LINE_MESH);	
+	poly = new Polycode::Polygon();
+	poly->addVertex(0.0, 0.0, 0.0);
+	poly->addVertex(1.0, 0.0, 0.0);	
+	xLine->getMesh()->addPolygon(poly);
+	xLine->getMesh()->dirtyArrays();
+	xLine->depthTest = false;
+	xLine->setColor(1.0, 0.0, 0.0, 1.0);
+	transformAndScaleLines->addChild(xLine);
+
+	SceneMesh *zLine = new SceneMesh(Mesh::LINE_MESH);	
+	poly = new Polycode::Polygon();
+	poly->addVertex(0.0, 0.0, 0.0);
+	poly->addVertex(0.0, 0.0, 1.0);	
+	zLine->getMesh()->addPolygon(poly);
+	zLine->getMesh()->dirtyArrays();
+	zLine->depthTest = false;
+	zLine->setColor(0.0, 0.0, 1.0, 1.0);
+	transformAndScaleLines->addChild(zLine);
+	
+	// MOVE
+	
+	ScenePrimitive *yArrow = new ScenePrimitive(ScenePrimitive::TYPE_CONE, 0.2, 0.05, 12);
+	yArrow->setColor(0.0, 1.0, 0.0, 1.0);
+	yArrow->setPosition(0.0, 1.0, 0.0);
+	yArrow->depthTest = false;
+	trasnformDecorators->addChild(yArrow);
+	
+	ScenePrimitive *xArrow = new ScenePrimitive(ScenePrimitive::TYPE_CONE, 0.2, 0.05, 12);
+	xArrow->setColor(1.0, 0.0, 0.0, 1.0);
+	xArrow->setPosition(1.0, 0.0, 0.0);
+	xArrow->Roll(-90);
+	xArrow->depthTest = false;
+	trasnformDecorators->addChild(xArrow);
+
+	ScenePrimitive *zArrow = new ScenePrimitive(ScenePrimitive::TYPE_CONE, 0.2, 0.05, 12);
+	zArrow->setColor(0.0, 0.0, 1.0, 1.0);
+	zArrow->setPosition(0.0, 0.0, 1.0);
+	zArrow->Pitch(90);
+	zArrow->depthTest = false;	
+	trasnformDecorators->addChild(zArrow);
+
+	// SCALE
+
+	ScenePrimitive *yBox = new ScenePrimitive(ScenePrimitive::TYPE_BOX, 0.1, 0.1, 0.1);
+	yBox->setColor(0.0, 1.0, 0.0, 1.0);
+	yBox->setPosition(0.0, 1.0, 0.0);
+	yBox->depthTest = false;
+	scaleDecorators->addChild(yBox);
+	
+	ScenePrimitive *xBox = new ScenePrimitive(ScenePrimitive::TYPE_BOX, 0.1, 0.1, 0.1);
+	xBox->setColor(1.0, 0.0, 0.0, 1.0);
+	xBox->setPosition(1.0, 0.0, 0.0);
+	xBox->Roll(-90);
+	xBox->depthTest = false;
+	scaleDecorators->addChild(xBox);
+
+	ScenePrimitive *zBox = new ScenePrimitive(ScenePrimitive::TYPE_BOX, 0.1, 0.1, 0.1);
+	zBox->setColor(0.0, 0.0, 1.0, 1.0);
+	zBox->setPosition(0.0, 0.0, 1.0);
+	zBox->Pitch(90);
+	zBox->depthTest = false;	
+	scaleDecorators->addChild(zBox);
+
+	// ROTATE
+
+	ScenePrimitive *bgCircle = new ScenePrimitive(ScenePrimitive::TYPE_CIRCLE, 1.6, 1.6, 32);
+	bgCircle->getMesh()->setMeshType(Mesh::LINE_LOOP_MESH);
+	bgCircle->setColor(0.0, 0.0, 0.0, 1.0);
+	bgCircle->depthTest = false;
+	bgCircle->billboardMode = true;
+	rotateDectorators->addChild(bgCircle);
+
+	ScenePrimitive *outerCircle = new ScenePrimitive(ScenePrimitive::TYPE_CIRCLE, 2.0, 2.0, 32);
+	outerCircle->getMesh()->setMeshType(Mesh::LINE_LOOP_MESH);
+	outerCircle->setColor(1.0, 1.0, 1.0, 1.0);
+	outerCircle->depthTest = false;
+	outerCircle->billboardMode = true;
+	rotateDectorators->addChild(outerCircle);
+	
+	ScenePrimitive *pitchCircle = new ScenePrimitive(ScenePrimitive::TYPE_CIRCLE, 1.55, 1.55, 32);
+	pitchCircle->getMesh()->setMeshType(Mesh::LINE_LOOP_MESH);
+	pitchCircle->setColor(1.0, 0.0, 0.0, 1.0);
+	pitchCircle->depthTest = false;
+	pitchCircle->Yaw(90);	
+	rotateDectorators->addChild(pitchCircle);
+	pitchCircle->setMaterialByName("OneSidedLine");
+
+	ScenePrimitive *yawCircle = new ScenePrimitive(ScenePrimitive::TYPE_CIRCLE, 1.65, 1.65, 32);
+	yawCircle->getMesh()->setMeshType(Mesh::LINE_LOOP_MESH);
+	yawCircle->setColor(0.0, 1.0, 0.0, 1.0);
+	yawCircle->depthTest = false;
+	yawCircle->Pitch(90);
+	rotateDectorators->addChild(yawCircle);
+	yawCircle->setMaterialByName("OneSidedLine");
+	
+	ScenePrimitive *rollCircle = new ScenePrimitive(ScenePrimitive::TYPE_CIRCLE, 1.6, 1.6, 32);
+	rollCircle->getMesh()->setMeshType(Mesh::LINE_LOOP_MESH);
+	rollCircle->setColor(0.0, 0.0, 1.0, 1.0);
+	rollCircle->depthTest = false;
+	rotateDectorators->addChild(rollCircle);
+	rollCircle->setMaterialByName("OneSidedLine");
+		
+	pitchCircle->lineWidth = 2.0;	
+	yawCircle->lineWidth = 2.0;
+	rollCircle->lineWidth = 2.0;		
+	
+	rotateDectorators->processInputEvents = true;
+	
+	pitchGrip = new ScenePrimitive(ScenePrimitive::TYPE_TORUS, 1.55 * 0.5, 0.1, 10, 3);
+	pitchGrip->setColor(1.0, 0.0, 0.0, 0.2);
+	pitchGrip->depthTest = false;
+	pitchGrip->Pitch(90);	
+	pitchGrip->Yaw(90);		
+	rotateDectorators->addChild(pitchGrip);
+	pitchGrip->processInputEvents = true;
+	pitchGrip->addEventListener(this, InputEvent::EVENT_MOUSEDOWN);
+	pitchGrip->useGeometryHitDetection = true;
+	pitchGrip->blockMouseInput = true;
+
+	rollGrip = new ScenePrimitive(ScenePrimitive::TYPE_TORUS, 1.6 * 0.5, 0.1, 10, 3);
+	rollGrip->setColor(0.0, 0.0, 1.0, 0.2);
+	rollGrip->depthTest = false;
+	rollGrip->Pitch(90);		
+	rotateDectorators->addChild(rollGrip);
+	rollGrip->processInputEvents = true;
+	rollGrip->addEventListener(this, InputEvent::EVENT_MOUSEDOWN);
+	rollGrip->useGeometryHitDetection = true;
+	rollGrip->blockMouseInput = true;
+	
+	yawGrip = new ScenePrimitive(ScenePrimitive::TYPE_TORUS, 1.65 * 0.5, 0.1, 10, 3);
+	yawGrip->setColor(0.0, 1.0, 0.0, 0.2);
+	yawGrip->depthTest = false;
+	yawGrip->Yaw(90);		
+	rotateDectorators->addChild(yawGrip);
+	yawGrip->processInputEvents = true;
+	yawGrip->addEventListener(this, InputEvent::EVENT_MOUSEDOWN);
+	yawGrip->useGeometryHitDetection = true;
+	yawGrip->blockMouseInput = true;
+	
+	pitchGrip->visible = false;		
+	yawGrip->visible = false;
+	rollGrip->visible = false;
+
+	xTransformGrip = new Entity();
+	xTransformGrip->bBox.set(1.3, 0.1, 0.1);
+	addChild(xTransformGrip);
+	xTransformGrip->setAnchorPoint(Vector3(-1.0, 0.0, 0.0));
+	xTransformGrip->processInputEvents = true;
+	xTransformGrip->addEventListener(this, InputEvent::EVENT_MOUSEDOWN);
+
+	yTransformGrip = new Entity();
+	yTransformGrip->bBox.set(0.1, 1.3, 0.1);
+	addChild(yTransformGrip);
+	yTransformGrip->setAnchorPoint(Vector3(0.0, -1.0, 0.0));
+	yTransformGrip->processInputEvents = true;
+	yTransformGrip->addEventListener(this, InputEvent::EVENT_MOUSEDOWN);
+
+	zTransformGrip = new Entity();
+	zTransformGrip->bBox.set(0.1, 0.1, 1.3);
+	addChild(zTransformGrip);
+	zTransformGrip->setAnchorPoint(Vector3(0.0, 0.0, -1.0));
+	zTransformGrip->processInputEvents = true;
+	zTransformGrip->addEventListener(this, InputEvent::EVENT_MOUSEDOWN);
+		
+	transforming = false;
+	mode = TRANSFORM_MOVE;
+	
+	visible = false;
+	enabled = false;
+	
+	coreInput = CoreServices::getInstance()->getCore()->getInput();
+	coreInput->addEventListener(this, InputEvent::EVENT_MOUSEMOVE);
+	coreInput->addEventListener(this, InputEvent::EVENT_MOUSEUP);	
+	
+	setTransformMode(TRANSFORM_MOVE);
+}
+
+Vector3 TransformGizmo::getTransformPlanePosition() {
+
+	Number planeDistance = 0;
+	if(transformPlane.x > 0) {
+		planeDistance = getPosition().x;
+	} else if(transformPlane.y > 0.0) {
+		planeDistance = getPosition().y;	
+	} else if(transformPlane.z > 0.0) {
+		planeDistance = getPosition().z;	
+	}
+	Ray ray = targetScene->projectRayFromCameraAndViewportCoordinate(targetCamera, coreInput->getMousePosition());		
+	return ray.planeIntersectPoint(transformPlane, planeDistance);
+}
+
+void TransformGizmo::setTransformMode(int newMode) {
+	trasnformDecorators->visible = false;
+	scaleDecorators->visible = false;
+	transformAndScaleLines->visible = false;
+	rotateDectorators->visible = false;
+	xTransformGrip->enabled = false;
+	yTransformGrip->enabled = false;
+	zTransformGrip->enabled = false;
+	
+	pitchGrip->enabled = false;
+	rollGrip->enabled = false;
+	yawGrip->enabled = false;
+	
+			
+	mode = newMode;
+	switch (mode) {
+		case TRANSFORM_MOVE:
+			trasnformDecorators->visible = true;
+			transformAndScaleLines->visible = true;
+			xTransformGrip->enabled = true;
+			yTransformGrip->enabled = true;
+			zTransformGrip->enabled = true;						
+		break;
+		case TRANSFORM_SCALE:
+			scaleDecorators->visible = true;
+			transformAndScaleLines->visible = true;					
+			xTransformGrip->enabled = true;
+			yTransformGrip->enabled = true;
+			zTransformGrip->enabled = true;				
+		break;	
+		case TRANSFORM_ROTATE:
+			rotateDectorators->visible = true;
+			pitchGrip->enabled = true;
+			rollGrip->enabled = true;
+			yawGrip->enabled = true;			
+		break;
+		default:
+			assert(false); // invalid mode
+		break;
+	}
+}
+
+void TransformGizmo::setTransformSelection(std::vector<Entity*> selectedEntities) {
+	this->selectedEntities = selectedEntities;
+	if(selectedEntities.size() > 0) {
+		visible = true;
+		enabled = true;
+		
+		Vector3 centerPoint;
+		for(int i=0; i < selectedEntities.size(); i++) {
+			centerPoint += selectedEntities[i]->getConcatenatedMatrix().getPosition();			
+		}
+		centerPoint = centerPoint / selectedEntities.size();
+		setPosition(centerPoint);
+	} else {
+		visible = false;
+		enabled = false;
+	}
+	
+}
+
+void TransformGizmo::transfromSelectedEntities(const Vector3 &move, const Vector3 &scale, Number rotate) {
+	for(int i=0; i < selectedEntities.size(); i++) {
+		selectedEntities[i]->Translate(move);
+		selectedEntities[i]->setScale(selectedEntities[i]->getScale() + scale);
+		
+		Quaternion q;
+		Quaternion currentRotation = selectedEntities[i]->getRotationQuat();
+					
+		Vector3 axisVector = transformConstraint;
+		axisVector = currentRotation.Inverse().applyTo(axisVector);
+		
+		q.fromAngleAxis(rotate, axisVector);
+		selectedEntities[i]->setRotationByQuaternion(currentRotation * q);
+	}
+	Translate(move);
+}
+
+Number TransformGizmo::getTransformPlaneAngle() {
+
+	Number planeDistance = 0;
+	
+	Ray gizmoRay;
+	gizmoRay.origin = getConcatenatedMatrix().getPosition();
+	gizmoRay.direction = transformPlane * -1;
+					
+	if(transformPlane.x > 0) {
+		planeDistance = getPosition().x;
+	} else if(transformPlane.y > 0.0) {
+		planeDistance = getPosition().y;	
+	} else if(transformPlane.z > 0.0) {
+		planeDistance = getPosition().z;	
+	}
+						
+	Vector3 gizmoIntersect = gizmoRay.planeIntersectPoint(transformPlane, planeDistance);
+	
+	Ray ray = targetScene->projectRayFromCameraAndViewportCoordinate(targetCamera, coreInput->getMousePosition());	
+	Vector3 mouseIntersect = ray.planeIntersectPoint(transformPlane, planeDistance);
+
+	Vector2 planePosition;
+	
+	if(transformPlane.x > 0) {
+		planePosition.x = mouseIntersect.z - gizmoIntersect.z;
+		planePosition.y = mouseIntersect.y - gizmoIntersect.y;
+	} else if(transformPlane.y > 0.0) {
+		planePosition.x = mouseIntersect.x - gizmoIntersect.x;
+		planePosition.y = mouseIntersect.z - gizmoIntersect.z;
+	} else if(transformPlane.z > 0.0) {
+		planePosition.x = mouseIntersect.x - gizmoIntersect.x;
+		planePosition.y = mouseIntersect.y - gizmoIntersect.y;
+	}
+	
+	planePosition.Normalize();
+	
+	return atan2(planePosition.x, planePosition.y);
+}
+
+void TransformGizmo::handleEvent(Event *event) {
+
+	if(!coreInput->getKeyState(KEY_LALT) && !coreInput->getKeyState(KEY_RALT)) {
+		if(event->getDispatcher() == pitchGrip) {
+			if(event->getEventCode() == InputEvent::EVENT_MOUSEDOWN) {
+				transforming = true;
+				transformConstraint = Vector3(1.0, 0.0, 0.0);
+				transformPlane = Vector3(1.0, 0.0, 0.0);
+				startingAngle = getTransformPlaneAngle();
+			}
+		} else 	if(event->getDispatcher() == yawGrip) {
+			if(event->getEventCode() == InputEvent::EVENT_MOUSEDOWN) {
+				transforming = true;
+				transformConstraint = Vector3(0.0, 1.0, 0.0);
+				transformPlane = Vector3(0.0, 1.0, 0.0);
+				startingAngle = getTransformPlaneAngle();
+			}
+		} else 	if(event->getDispatcher() == rollGrip) {
+			if(event->getEventCode() == InputEvent::EVENT_MOUSEDOWN) {
+				transforming = true;
+				transformConstraint = Vector3(0.0, 0.0, -1.0);
+				transformPlane = Vector3(0.0, 0.0, 1.0);
+				startingAngle = getTransformPlaneAngle();
+			}
+		}
+
+		if(event->getDispatcher() == xTransformGrip) {
+			if(event->getEventCode() == InputEvent::EVENT_MOUSEDOWN) {
+				transforming = true;
+				transformConstraint = Vector3(1.0, 0.0, 0.0);
+				transformPlane = Vector3(0.0, 1.0, 0.0);
+				startingPoint = getTransformPlanePosition();
+			}
+		} else 	if(event->getDispatcher() == yTransformGrip) {
+			if(event->getEventCode() == InputEvent::EVENT_MOUSEDOWN) {
+				transforming = true;
+				transformConstraint = Vector3(0.0, 1.0, 0.0);
+				transformPlane = Vector3(0.0, 0.0, 1.0);			
+				startingPoint = getTransformPlanePosition();
+			}
+		} else 	if(event->getDispatcher() == zTransformGrip) {
+			if(event->getEventCode() == InputEvent::EVENT_MOUSEDOWN) {
+				transforming = true;
+				transformConstraint = Vector3(0.0, 0.0, 1.0);
+				transformPlane = Vector3(0.0, 1.0, 0.0);			
+				startingPoint = getTransformPlanePosition();
+			}		
+		}
+	}
+	
+	if(event->getDispatcher() == coreInput && transforming) {
+		InputEvent *inputEvent = (InputEvent*) event;
+		switch(event->getEventCode()) {
+			case InputEvent::EVENT_MOUSEMOVE:
+			{
+				switch(mode) {
+					case TRANSFORM_MOVE:
+					{
+						Vector3 newPoint = getTransformPlanePosition();
+						transfromSelectedEntities((newPoint-startingPoint) * transformConstraint, Vector3(0.0, 0.0, 0.0), 0.0);
+						startingPoint = newPoint;
+					}
+					break;
+					case TRANSFORM_SCALE:
+					{
+						Vector3 newPoint = getTransformPlanePosition();
+						transfromSelectedEntities(Vector3(0.0, 0.0, 0.0), ((newPoint-startingPoint) * transformConstraint), 0.0);
+						startingPoint = newPoint;					
+					}
+					break;
+					case TRANSFORM_ROTATE:
+					{
+						Number newAngle = getTransformPlaneAngle();
+						transfromSelectedEntities(Vector3(0.0, 0.0, 0.0), Vector3(0.0, 0.0, 0.0), newAngle - startingAngle);
+						startingAngle = newAngle;						
+					}
+					break;
+				}
+			}
+			break;
+			case InputEvent::EVENT_MOUSEUP:
+			{
+				transforming = false;
+			}
+			break;
+		}
+	}
+}
+
+TransformGizmo::~TransformGizmo() {
+
+}
+
+void TransformGizmo::Update() {
+	Number scale = getPosition().distance(targetCamera->getPosition()) * 0.1;
+	setScale(scale, scale, scale);
+}
+