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

Added a SceneCurve class to render/place BezierCurves in the Scene, added bezier curve editing and SceneCurve save/load to IDE entity editor, added a message box popup to the IDE, fixed bounding box calculations in camera and light preview gizmos in the entity editor, fixed bounding box calculation in the entity editor grid

Ivan Safrin 11 лет назад
Родитель
Сommit
0b1b425be1

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

@@ -30,6 +30,7 @@ THE SOFTWARE.
 #include "PolyResource.h"
 #include "PolySceneSprite.h"
 #include "PolyBezierCurve.h"
+#include "PolySceneLine.h"
 #include "PolyScene.h"
 #include "PolySound.h"
 

+ 27 - 0
Core/Contents/Include/PolySceneLine.h

@@ -24,11 +24,38 @@ THE SOFTWARE.
 #include "PolyString.h"
 #include "PolyGlobals.h"
 #include "PolySceneMesh.h"
+#include "PolyBezierCurve.h"
 #include "PolyCoreServices.h"
 #include "PolyMesh.h"
 
 namespace Polycode {
 
+    
+    class _PolyExport SceneCurve : public SceneMesh {
+        public:
+        
+            SceneCurve();
+            SceneCurve(BezierCurve *curve);
+        
+            static SceneCurve *SceneCurveWithCurve(BezierCurve *curve);
+        
+            virtual ~SceneCurve();
+            void Update();
+        
+            virtual Entity *Clone(bool deepClone, bool ignoreEditorOnly) const;
+            virtual void applyClone(Entity *clone, bool deepClone, bool ignoreEditorOnly) const;
+ 
+        
+            BezierCurve *getCurve();
+        
+            bool renderCurve;
+            int curveResolution;
+        
+        protected:
+        
+            BezierCurve *curve;
+    };
+    
 	/**
 	* 3D line class. Can connect two SceneEntity classes with a line.
 	*/ 

+ 13 - 0
Core/Contents/Source/PolySceneEntityInstance.cpp

@@ -284,6 +284,19 @@ Entity *SceneEntityInstance::loadObjectEntryIntoEntity(ObjectEntry *entry, Entit
             String filePath = (*instanceEntry)["filePath"]->stringVal;
             SceneEntityInstance *instance = new SceneEntityInstance(parentScene, filePath);
             entity = instance;
+         } else if(entityType->stringVal == "SceneCurve") {
+			ObjectEntry *curveEntry = (*entry)["SceneCurve"];
+             
+             SceneCurve *curve = new SceneCurve();
+             
+            if(curveEntry) {
+                curve->renderCurve = (*curveEntry)["render"]->boolVal;
+                curve->curveResolution = (*curveEntry)["resolution"]->intVal;                
+                parseObjectIntoCurve((*curveEntry)["curve"], curve->getCurve());
+            }
+             
+             entity = curve;
+             
          } else if(entityType->stringVal == "SceneSprite") {
 
 			ObjectEntry *spriteEntry = (*entry)["SceneSprite"];

+ 73 - 0
Core/Contents/Source/PolySceneLine.cpp

@@ -25,6 +25,79 @@
 
 using namespace Polycode;
 
+using std::min;
+using std::max;
+
+SceneCurve::SceneCurve() : SceneMesh(Mesh::LINE_STRIP_MESH) {
+    curveResolution = 256;
+    renderCurve = true;
+    curve = new BezierCurve();
+}
+
+SceneCurve::SceneCurve(BezierCurve *curve) : SceneMesh(Mesh::LINE_STRIP_MESH) {
+    curveResolution = 256;
+    renderCurve = true;
+    this->curve = curve;
+}
+
+SceneCurve *SceneCurve::SceneCurveWithCurve(BezierCurve *curve) {
+    return new SceneCurve(curve);
+}
+
+Entity *SceneCurve::Clone(bool deepClone, bool ignoreEditorOnly) const {
+	SceneCurve *newCurve = new SceneCurve();
+	applyClone(newCurve, deepClone, ignoreEditorOnly);
+	return newCurve;
+}
+
+void SceneCurve::applyClone(Entity *clone, bool deepClone, bool ignoreEditorOnly) const {
+    SceneMesh::applyClone(clone, deepClone, ignoreEditorOnly);
+    
+    SceneCurve *cloneCurve = (SceneCurve*)clone;
+    cloneCurve->renderCurve = renderCurve;
+    cloneCurve->curveResolution = curveResolution;
+    
+    for(int i=0; i < curve->getNumControlPoints(); i++) {
+        BezierPoint *pt = curve->getControlPoint(i);
+        cloneCurve->getCurve()->addControlPoint(
+            pt->p1.x, pt->p1.y, pt->p1.z,
+            pt->p2.x, pt->p2.y, pt->p2.z,
+            pt->p3.x, pt->p3.y, pt->p3.z);
+    }
+}
+
+
+SceneCurve::~SceneCurve() {
+    delete curve;
+}
+
+BezierCurve *SceneCurve::getCurve() {
+    return curve;
+}
+
+void SceneCurve::Update() {
+    mesh->clearMesh();
+    Vector3 bBox;
+    
+    if(renderCurve) {
+
+        Number step = (1.0 / ((Number)curveResolution));
+        
+        for(Number offset=0.0; offset <= 1.0; offset += step) {
+            Vector3 pt = curve->getPointAt(offset);
+            mesh->addVertex(pt.x, pt.y, pt.z, offset, 0.0);
+            
+            bBox.x = max(bBox.x,(Number)fabs(pt.x));
+            bBox.y = max(bBox.y,(Number)fabs(pt.y));
+            bBox.z = max(bBox.z,(Number)fabs(pt.z));
+
+        }
+    }
+    
+    setLocalBoundingBox(bBox * 2.0);
+    mesh->dirtyArray(RenderDataArray::VERTEX_DATA_ARRAY);
+}
+
 SceneLine::SceneLine(Vector3 start, Vector3 end) : SceneMesh(Mesh::LINE_MESH) {
 	this->ent1 = NULL;
 	this->ent2 = NULL;

Разница между файлами не показана из-за своего большого размера
+ 3 - 3
IDE/Assets/ide_icons.ai


+ 1 - 0
IDE/Contents/Include/EntityEditorPropertyView.h

@@ -58,6 +58,7 @@ class EntityEditorPropertyView : public UIElement {
         SceneLabelSheet *labelSheet;
         SceneSpriteSheet *spriteSheet;
         SoundSheet *soundSheet;
+        SceneCurveSheet *curveSheet;
         CameraSheet *cameraSheet;
         EntityPropSheet *propSheet;
     

+ 58 - 0
IDE/Contents/Include/PolycodeEntityEditor.h

@@ -88,6 +88,61 @@ class PolycodeSceneEditorActionData : public PolycodeEditorActionData {
         bool reverse;
 };
 
+
+class DummyTargetEntity : public Entity {
+    public:
+        DummyTargetEntity();
+        ~DummyTargetEntity();
+    
+        Vector3 getSelectedPoint() const;
+        void selectPoint(Vector3 point);
+        virtual void setDummyTransform(Entity *dummy) {}
+    
+        virtual void handleDelete() {}
+        virtual void handleDeselect() {}
+        virtual void handleSelect() {}
+    
+        Entity *getPropertyEntity();
+    
+    protected:
+    
+        Vector3 selectedPoint;
+        Entity *propertyEntity;
+};
+
+class CurveDisplay : public DummyTargetEntity {
+    public:
+        CurveDisplay(Scene *parentScene, SceneCurve *curve);
+        ~CurveDisplay();
+    
+        void setDummyTransform(Entity *dummy);
+        void handleDelete();
+        void handleDeselect();
+        void handleSelect();
+    
+        void Update();
+        void handleEvent(Event *event);
+
+        static const int SELECT_MODE_P1 = 0;
+        static const int SELECT_MODE_P2 = 1;
+        static const int SELECT_MODE_P3 = 2;
+    
+        bool renderControlPoints;
+    
+    private:
+    
+        int selectMode;
+    
+        BezierPoint *targetPoint;
+    
+        CoreInput *coreInput;
+        SceneCurve *curve;
+        SceneMesh *mainPoints;
+        SceneMesh *controlPoints;
+        SceneMesh *controlPointLines;
+        Scene *parentScene;
+};
+
 class LightDisplay : public Entity {
 public:
     LightDisplay(SceneLight *light);
@@ -241,6 +296,9 @@ class EntityEditorMainView : public UIElement {
     
             EntityDistanceSorter distanceSorter;
     
+            Entity *dummyEntity;
+            DummyTargetEntity *dummyTargetEntity;
+    
 			Scene *mainScene;
             Entity *sceneObjectRoot;
     

+ 1 - 0
IDE/Contents/Include/PolycodeFrame.h

@@ -346,6 +346,7 @@ public:
 	
 	TextInputPopup *textInputPopup;
 	YesNoPopup *yesNoPopup;
+    MessagePopup *messagePopup;
 	YesNoCancelPopup *yesNoCancelPopup;
 	
 	Entity *welcomeEntity;	

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

@@ -812,6 +812,21 @@ class SceneLabelSheet : public PropSheet {
 		BoolProp *enableAA;
 };
 
+class SceneCurveSheet : public PropSheet {
+    public:
+        SceneCurveSheet();
+        ~SceneCurveSheet();
+    
+        void handleEvent(Event *event);
+        void setCurve(SceneCurve *curve);
+    
+        SceneCurve *curve;
+        ButtonProp *addPointProp;
+        BoolProp *renderProp;
+        NumberProp *numPointsProp;
+    
+};
+
 class SceneSpriteSheet : public PropSheet {
 	public:
 		SceneSpriteSheet();

+ 15 - 0
IDE/Contents/Include/ToolWindows.h

@@ -49,6 +49,20 @@ class TextInputPopup : public UIWindow {
 		UIButton *okButton;	
 };
 
+class MessagePopup : public UIWindow {
+    public:
+    MessagePopup();
+    ~MessagePopup();
+    
+    void setCaption(String caption);
+    void handleEvent(Event *event);
+    
+        String action;
+        UILabel *captionLabel;
+        UIButton *okButton;
+    
+};
+
 class YesNoPopup : public UIWindow {
 	public:
 		YesNoPopup();
@@ -66,6 +80,7 @@ class YesNoPopup : public UIWindow {
 		UIButton *okButton;	
 };
 
+
 class YesNoCancelPopup : public UIWindow {
 	public:
 		YesNoCancelPopup();

BIN
IDE/Contents/Resources/Images/entityEditor/curve_icon.png


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


+ 1 - 1
IDE/Contents/Source/EditorGrid.cpp

@@ -200,7 +200,7 @@ void EditorGrid::rebuildGrid() {
     zLine->setStart(Vector3(0.0, 0.0, gridSize * gridLen * 0.5));
     zLine->setEnd(Vector3(0.0, 0.0, gridSize * gridLen * -0.5));
     
-    grid->setLocalBoundingBox(gridSize * gridLen, 0.0, gridSize * gridLen);
+    grid->setLocalBoundingBox(grid->getMesh()->calculateBBox());
     
     grid->cacheToVertexBuffer(true);
 }

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

@@ -51,6 +51,9 @@ EntityEditorPropertyView::EntityEditorPropertyView() : UIElement() {
     entityProps->addPropSheet(labelSheet);
     labelSheet->addEventListener(this, PropEvent::EVENT_PROP_CHANGE);
     
+    curveSheet = new SceneCurveSheet();
+    entityProps->addPropSheet(curveSheet);
+    curveSheet->addEventListener(this, PropEvent::EVENT_PROP_CHANGE);
     
     lightSheet = new SceneLightSheet();
     entityProps->addPropSheet(lightSheet);
@@ -149,6 +152,9 @@ void EntityEditorPropertyView::setEntity(Entity *entity) {
     SceneLabel *sceneLabel = dynamic_cast<SceneLabel*>(entity);
     labelSheet->setSceneLabel(sceneLabel);
 
+    SceneCurve *sceneCurve = dynamic_cast<SceneCurve*>(entity);
+    curveSheet->setCurve(sceneCurve);
+    
     SceneSprite *sceneSprite = dynamic_cast<SceneSprite*>(entity);
     spriteSheet->setSprite(sceneSprite);
 

+ 346 - 10
IDE/Contents/Source/PolycodeEntityEditor.cpp

@@ -60,6 +60,217 @@ PolycodeSceneEditorActionDataEntry::PolycodeSceneEditorActionDataEntry(Entity *e
     this->entity = entity;
 }
 
+DummyTargetEntity::DummyTargetEntity() {
+    addTag("dummy_target");
+    propertyEntity = NULL;
+}
+
+DummyTargetEntity::~DummyTargetEntity() {
+    
+}
+
+Vector3 DummyTargetEntity::getSelectedPoint() const {
+    return selectedPoint;
+}
+
+void DummyTargetEntity::selectPoint(Vector3 point) {
+    selectedPoint = point;
+    InputEvent *rebroadcastEvent = new InputEvent();
+    rebroadcastEvent->mouseButton = CoreInput::MOUSE_BUTTON2;
+    dispatchEvent(rebroadcastEvent, InputEvent::EVENT_MOUSEDOWN);
+    
+}
+
+Entity *DummyTargetEntity::getPropertyEntity() {
+    return propertyEntity;
+}
+
+CurveDisplay::CurveDisplay(Scene *parentScene, SceneCurve *curve) : DummyTargetEntity () {
+    editorOnly = true;
+    curve->addChild(this);
+    this->curve = curve;
+    this->parentScene = parentScene;
+    targetPoint = NULL;
+    propertyEntity = curve;
+    
+    controlPointLines = new SceneMesh(Mesh::LINE_MESH);
+    controlPointLines->setColor(1.0, 1.0, 0.4, 1.0);
+    addChild(controlPointLines);
+    
+   
+    mainPoints = new SceneMesh(Mesh::POINT_MESH);
+    mainPoints->setColor(0.0, 0.5, 1.0, 1.0);
+    addChild(mainPoints);
+    mainPoints->pointSize = 10.0;
+    mainPoints->pointSmooth = true;
+
+    controlPoints = new SceneMesh(Mesh::POINT_MESH);
+    controlPoints->setColor(1.0, 0.7, 0.0, 1.0);
+    addChild(controlPoints);
+    controlPoints->pointSize = 8.0;
+    controlPoints->pointSmooth = true;
+    
+    renderControlPoints = false;
+    
+    coreInput = Services()->getCore()->getInput();
+    coreInput->addEventListener(this, InputEvent::EVENT_MOUSEDOWN);
+}
+
+void CurveDisplay::handleDelete() {
+    if(targetPoint) {
+        if(curve->getCurve()->getNumControlPoints() > 2) {
+            curve->getCurve()->removePoint(targetPoint);
+        } else {
+            globalFrame->messagePopup->setCaption("Curve must have at least two points.");
+            globalFrame->showModal(globalFrame->messagePopup);
+        }
+    }
+}
+
+void CurveDisplay::handleDeselect() {
+    renderControlPoints = false;
+}
+
+void CurveDisplay::handleSelect() {
+    renderControlPoints = true;
+}
+
+CurveDisplay::~CurveDisplay() {
+    Services()->getCore()->getInput()->removeAllHandlersForListener(this);
+}
+
+void CurveDisplay::handleEvent(Event *event) {
+    
+    InputEvent *inputEvent = (InputEvent*) event;
+    if(inputEvent->mouseButton == CoreInput::MOUSE_BUTTON2) {
+        
+        Ray ray = parentScene->projectRayFromCameraAndViewportCoordinate(parentScene->getDefaultCamera(), coreInput->getMousePosition());
+        
+        for(int i=0; i < curve->getCurve()->getNumControlPoints(); i++) {
+            Matrix4 parentMatrix = getConcatenatedMatrix();
+            Matrix4 pointTransform;
+            
+            Vector3 pt = curve->getCurve()->getControlPoint(i)->p2;
+            pt = parentMatrix * pt;
+            Number relativeSize = parentScene->getDefaultCamera()->getPosition().distance(pt) * 0.02;
+            Vector3 hitSize(relativeSize, relativeSize, relativeSize);
+            pointTransform.setPosition(pt.x, pt.y, pt.z);
+            if(ray.boxIntersect(hitSize, pointTransform) >= 0.0) {
+                selectMode = SELECT_MODE_P2;
+                targetPoint = curve->getCurve()->getControlPoint(i);
+                selectPoint(pt);
+            }
+            
+            if(renderControlPoints) {
+                pt = curve->getCurve()->getControlPoint(i)->p1;
+                pt = parentMatrix * pt;
+                relativeSize = parentScene->getDefaultCamera()->getPosition().distance(pt) * 0.02;
+                hitSize.set(relativeSize, relativeSize, relativeSize);
+                pointTransform.setPosition(pt.x, pt.y, pt.z);
+                if(ray.boxIntersect(hitSize, pointTransform) >= 0.0) {
+                    selectMode = SELECT_MODE_P1;
+                    targetPoint = curve->getCurve()->getControlPoint(i);
+                    selectPoint(pt);
+                }
+                
+                pt = curve->getCurve()->getControlPoint(i)->p3;
+                pt = parentMatrix * pt;
+                relativeSize = parentScene->getDefaultCamera()->getPosition().distance(pt) * 0.02;
+                hitSize.set(relativeSize, relativeSize, relativeSize);
+                pointTransform.setPosition(pt.x, pt.y, pt.z);
+                if(ray.boxIntersect(hitSize, pointTransform) >= 0.0) {
+                    selectMode = SELECT_MODE_P3;
+                    targetPoint = curve->getCurve()->getControlPoint(i);
+                    selectPoint(pt);
+                }
+            }
+        }
+    }
+}
+
+void CurveDisplay::setDummyTransform(Entity *dummy) {
+    if(targetPoint) {
+        Vector3 position = dummy->getPosition();
+        
+        Matrix4 parentMatrix = getConcatenatedMatrix().Inverse();
+        position = parentMatrix * position;
+        
+        Vector3 p1Offset = targetPoint->p1 - targetPoint->p2;
+        Vector3 p3Offset = targetPoint->p3 - targetPoint->p2;
+        
+        switch(selectMode) {
+            case SELECT_MODE_P1:
+            {
+                targetPoint->p1 = position;
+                
+                // transform the opposing point to match
+                Number p3Distance = targetPoint->p3.distance(targetPoint->p2);
+                Vector3 p3Normal = p1Offset * -1.0;
+                p3Normal.Normalize();
+                targetPoint->p3 = targetPoint->p2 + (p3Normal * p3Distance);
+            }
+            break;
+            case SELECT_MODE_P2:
+            {
+                targetPoint->p2 = position;
+                targetPoint->p1 = position+p1Offset;
+                targetPoint->p3 = position+p3Offset;
+            }
+            break;
+            case SELECT_MODE_P3:
+            {
+                targetPoint->p3 = position;
+                
+                // transform the opposing point to match
+                Number p1Distance = targetPoint->p1.distance(targetPoint->p2);
+                Vector3 p1Normal = p3Offset * -1.0;
+                p1Normal.Normalize();
+                targetPoint->p1 = targetPoint->p2 + (p1Normal * p1Distance);
+                
+            }
+            break;
+        }
+        
+        curve->getCurve()->recalculateDistances();
+    }
+}
+
+void CurveDisplay::Update() {
+    
+    mainPoints->getMesh()->clearMesh();
+    controlPoints->getMesh()->clearMesh();
+    controlPointLines->getMesh()->clearMesh();
+    
+    for(int i=0; i < curve->getCurve()->getNumControlPoints(); i++) {
+        
+        Vector3 pt2 = curve->getCurve()->getControlPoint(i)->p2;
+        mainPoints->getMesh()->addVertex(pt2.x, pt2.y, pt2.z);
+        
+        if(renderControlPoints) {
+            Vector3 pt1 = curve->getCurve()->getControlPoint(i)->p1;
+            controlPoints->getMesh()->addVertex(pt1.x, pt1.y, pt1.z);
+            
+            Vector3 pt3 = curve->getCurve()->getControlPoint(i)->p3;
+            controlPoints->getMesh()->addVertex(pt3.x, pt3.y, pt3.z);
+            
+            
+            controlPointLines->getMesh()->addVertex(pt1.x, pt1.y, pt1.z);
+            controlPointLines->getMesh()->addVertex(pt2.x, pt2.y, pt2.z);
+            
+            controlPointLines->getMesh()->addVertex(pt2.x, pt2.y, pt2.z);
+            controlPointLines->getMesh()->addVertex(pt3.x, pt3.y, pt3.z);
+        }
+    }
+    
+    mainPoints->setLocalBoundingBox(mainPoints->getMesh()->calculateBBox());
+    controlPoints->setLocalBoundingBox(controlPoints->getMesh()->calculateBBox());
+    controlPointLines->setLocalBoundingBox(controlPointLines->getMesh()->calculateBBox());
+    
+    mainPoints->getMesh()->dirtyArray(RenderDataArray::VERTEX_DATA_ARRAY);
+    controlPoints->getMesh()->dirtyArray(RenderDataArray::VERTEX_DATA_ARRAY);
+    controlPointLines->getMesh()->dirtyArray(RenderDataArray::VERTEX_DATA_ARRAY);
+}
+
 LightDisplay::LightDisplay(SceneLight *light) : Entity() {
     editorOnly = true;
     this->light = light;
@@ -87,6 +298,7 @@ LightDisplay::LightDisplay(SceneLight *light) : Entity() {
     fovMesh->addIndexedFace(0, 3);
     fovMesh->addIndexedFace(0, 4);
     
+    fovSceneMesh->setLocalBoundingBox(fovMesh->calculateBBox());
     
     light->addChild(this);
 }
@@ -113,6 +325,7 @@ void LightDisplay::Update() {
         fovMesh->getActualVertex(3)->set(sin(PI + (PI/2.0))*spotLightSize, cos(PI + (PI/2.0))*spotLightSize, -distance);
         fovMesh->getActualVertex(4)->set(sin(PI*2.0)*spotLightSize, cos(PI*2.0)*spotLightSize, -distance);
          fovMesh->dirtyArray(RenderDataArray::VERTEX_DATA_ARRAY);
+        fovSceneMesh->setLocalBoundingBox(fovMesh->calculateBBox());
     } else {
         spotSpot->enabled = false;
         fovSceneMesh->enabled = false;
@@ -146,6 +359,8 @@ CameraDisplay::CameraDisplay(Camera *camera) : Entity() {
     fovMesh->addIndexedFace(3, 4);
     fovMesh->addIndexedFace(4, 1);
     
+    fovSceneMesh->setLocalBoundingBox(fovMesh->calculateBBox());
+    
     addChild(fovSceneMesh);
     
     camera->addChild(this);
@@ -324,6 +539,7 @@ EntityEditorMainView::EntityEditorMainView(PolycodeEditor *editor) {
     objectRootInstance = NULL;
     lightsDisabled = false;
     beforeData = NULL;
+    dummyTargetEntity = NULL;
     setOwnsChildrenRecursive(true);
     
     this->editor = editor;
@@ -336,6 +552,9 @@ EntityEditorMainView::EntityEditorMainView(PolycodeEditor *editor) {
 	mainScene->clearColor.setColor(0.2, 0.2, 0.2, 1.0);	
 	mainScene->useClearColor = true;
 	mainScene->rootEntity.processInputEvents = true;
+    
+    dummyEntity = new Entity();
+    mainScene->addChild(dummyEntity);
 	   
     Number customFalloff = 0.006;
     // setup custom lights for disabled lighting
@@ -643,7 +862,12 @@ void EntityEditorMainView::setEditorMode(int newMode) {
 
 Entity *EntityEditorMainView::getSelectedEntity() {
     if(selectedEntities.size() > 0) {
-        return selectedEntities[selectedEntities.size()-1];
+        
+        if(selectedEntities[selectedEntities.size()-1] == dummyEntity) {
+            return dummyTargetEntity->getPropertyEntity();
+        } else {
+            return selectedEntities[selectedEntities.size()-1];
+        }
     } else {
         return NULL;
     }
@@ -691,6 +915,12 @@ bool EntityDistanceSorter::operator() (MultiselectorEntry i,MultiselectorEntry j
 
 void EntityEditorMainView::Update() {
     
+    // update dummy target if trasnforming dummy entity
+    
+    if(dummyTargetEntity) {
+        dummyTargetEntity->setDummyTransform(dummyEntity);
+    }
+    
     if(entitiesToSelect.size() != 0) {
         
         sort (entitiesToSelect.begin(), entitiesToSelect.end(), distanceSorter);
@@ -830,6 +1060,14 @@ void EntityEditorMainView::setEditorProps(Entity *entity) {
         }
     }
     
+    SceneCurve *sceneCurve = dynamic_cast<SceneCurve*>(entity);
+    if(sceneCurve) {
+        CurveDisplay *curveVis = new CurveDisplay(mainScene, sceneCurve);
+        curveVis->addEventListener(this, InputEvent::EVENT_MOUSEDOWN);
+        createIcon(entity, "curve_icon.png");
+    }
+    
+    
     if(emitter) {
         createIcon(entity, "emitter_icon.png");
     }
@@ -874,6 +1112,25 @@ void EntityEditorMainView::addEntityFromMenu(String command) {
         selectEntity(newEntity, false, false);
         return;
     }
+    
+    if(command == "add_curve") {
+        SceneCurve *curve = new SceneCurve();
+        
+        curve->getCurve()->addControlPoint(3.0, -1.0, 0.0,
+                                           2.0, 0.0, 0.0,
+                                           1.0, 1.0, 0.0);
+        curve->getCurve()->addControlPoint(
+                                           -1.0, 1.0, 0.0,
+                                           -2.0, 0.0, 0.0,
+                                           -3.0, -1.0, 0.0);
+        
+        sceneObjectRoot->addChild(curve);
+        setEditorProps(curve);
+        curve->setPosition(cursorPosition);
+        didPlaceEntity(curve);
+        selectEntity(curve, false, false);
+        return;
+    }
 
     if(command == "add_sound") {
         SceneSound *newSound = new SceneSound("default.wav", 1.0, 2.0);
@@ -1011,6 +1268,17 @@ void EntityEditorMainView::didPlaceEntity(Entity *entity) {
 
 void EntityEditorMainView::deleteSelected(bool doAction) {
 
+    for(int i=0; i < selectedEntities.size(); i++) {
+        if(selectedEntities[i] == dummyEntity) {
+            if(dummyTargetEntity) {
+                dummyTargetEntity->handleDelete();
+                dummyEntity->removeAllHandlers();
+                selectedEntities.clear();
+                transformGizmo->setTransformSelection(selectedEntities);
+                return;
+            }
+        }
+    }
     
     if(doAction) {
         PolycodeSceneEditorActionData *oldData = new PolycodeSceneEditorActionData();
@@ -1063,6 +1331,7 @@ void EntityEditorMainView::onLoseFocus() {
 
 void EntityEditorMainView::handleEvent(Event *event) {
     
+    
     if(event->getDispatcher() == transformGizmo) {
         if(event->getEventCode() == Event::CHANGE_EVENT) {
             TrasnformGizmoEvent *trasnformEvent = (TrasnformGizmoEvent*) event;
@@ -1242,6 +1511,7 @@ void EntityEditorMainView::handleEvent(Event *event) {
         addEntityMenu->addOption("Add Camera", "add_camera");
         addEntityMenu->addDivider();
         addEntityMenu->addOption("Add Empty", "add_empty");
+        addEntityMenu->addOption("Add Curve", "add_curve");
         addEntityMenu->fitToScreenVertical();
         addEntityMenu->addEventListener(this, UIEvent::OK_EVENT);
     } else if(event->getDispatcher() == input) {
@@ -1318,7 +1588,10 @@ void EntityEditorMainView::handleEvent(Event *event) {
         if(event->getEventCode() == InputEvent::EVENT_MOUSEDOWN && hasFocus && event->getDispatcher() != renderTextureShape) {
             InputEvent *inputEvent = (InputEvent*) event;
 
+    
             Entity* targetEntity = (Entity*) event->getDispatcher();
+            
+            
             if(inputEvent->mouseButton == CoreInput::MOUSE_BUTTON2 && targetEntity->visible) {
 
                 
@@ -1329,6 +1602,15 @@ void EntityEditorMainView::handleEvent(Event *event) {
                     }
                 }
                 
+                // check if dispatcher is a dummy target
+                DummyTargetEntity *dummyTarget = dynamic_cast<DummyTargetEntity*>(event->getDispatcher());
+                if(dummyTarget) {
+                    targetEntity = dummyEntity;
+                    dummyTargetEntity = dummyTarget;
+                    dummyEntity->setPosition(dummyTarget->getSelectedPoint());
+                }
+                
+                
                 MultiselectorEntry entry;
                 entry.entity = targetEntity;
                 entry.distance = inputEvent->hitDistance;
@@ -1401,6 +1683,7 @@ void EntityEditorMainView::selectAll(bool doAction) {
 
 void EntityEditorMainView::selectNone(bool doAction) {
     
+    
     if(doAction) {
         
         beforeData = new PolycodeSceneEditorActionData();
@@ -1415,6 +1698,7 @@ void EntityEditorMainView::selectNone(bool doAction) {
     for(int i=0; i < selectedEntities.size(); i++) {
         doEntityDeselect(selectedEntities[i]);
     }
+    cameraPreview->setCamera(mainScene, NULL);
     selectedEntities.clear();
     transformGizmo->setTransformSelection(selectedEntities);
     setBBox();
@@ -1449,6 +1733,20 @@ void EntityEditorMainView::doEntityDeselect(Entity *targetEntity) {
         sceneMesh->overlayWireframe = false;
     }
     
+    if(targetEntity == dummyEntity) {
+        if(dummyTargetEntity) {
+            dummyTargetEntity->handleDeselect();
+        }
+    }
+    
+    std::vector<Entity*> dummySelectChildren = targetEntity->getEntitiesByTag("dummy_target", true);
+    for(int i=0; i < dummySelectChildren.size(); i++) {
+        DummyTargetEntity *dummy = dynamic_cast<DummyTargetEntity*>(dummySelectChildren[i]);
+        if(dummy) {
+            dummy->handleDeselect();
+        }
+    }
+    
     SceneEntityInstance *instance = dynamic_cast<SceneEntityInstance*>(targetEntity);
     if(instance) {
         setOverlayWireframeRecursive(targetEntity, false);
@@ -1474,6 +1772,24 @@ void EntityEditorMainView::doEntitySelect(Entity *targetEntity) {
         sceneMesh->overlayWireframe = true;
     }
     
+    if(targetEntity == dummyEntity) {
+        if(dummyTargetEntity) {
+            dummyTargetEntity->handleSelect();
+        }
+    } else {
+        // clear the dummy target if dummy is not selected
+        dummyTargetEntity = NULL;
+    }
+    
+    std::vector<Entity*> dummySelectChildren = targetEntity->getEntitiesByTag("dummy_target", true);
+    for(int i=0; i < dummySelectChildren.size(); i++) {
+        DummyTargetEntity *dummy = dynamic_cast<DummyTargetEntity*>(dummySelectChildren[i]);
+        if(dummy) {
+            dummy->handleSelect();
+        }
+    }
+    
+    
     SceneEntityInstance *instance = dynamic_cast<SceneEntityInstance*>(targetEntity);
     if(instance) {
         setOverlayWireframeRecursive(targetEntity, true);
@@ -1880,17 +2196,37 @@ void PolycodeEntityEditor::saveEntityToObjectEntry(Entity *entity, ObjectEntry *
 
     }
     
-    if(dynamic_cast<SceneLabel*>(entity)) {
-        SceneLabel *label = (SceneLabel*) entity;
+    if(dynamic_cast<SceneSprite*>(entity)) {
         
         if(!(*(entry))["type"])
-            entry->addChild("type", "SceneLabel");
-        ObjectEntry *labelEntry = entry->addChild("SceneLabel");
-        labelEntry->addChild("text", label->getText());
-        labelEntry->addChild("font", label->getLabel()->getFont()->getFontName());
-        labelEntry->addChild("size", (Number)label->getLabel()->getSize());
-        labelEntry->addChild("actualHeight", label->getLabelActualHeight());
-        labelEntry->addChild("aaMode", (int)label->getLabel()->getAntialiasMode());
+            entry->addChild("type", "SceneSprite");
+        SceneSprite *sprite = (SceneSprite*) entity;
+        
+        ObjectEntry *spriteEntry = entry->addChild("SceneSprite");
+        
+        spriteEntry->addChild("sprite_set", sprite->getSpriteSet()->getName());
+        spriteEntry->addChild("sprite", sprite->getCurrentSprite()->getName());
+        spriteEntry->addChild("random_frame", sprite->getStartOnRandomFrame());
+        
+        String animName = "";
+        if(sprite->getCurrentSpriteState()) {
+            animName = sprite->getCurrentSpriteState()->getName();
+        }
+        spriteEntry->addChild("state", animName);
+        
+    }
+    
+    if(dynamic_cast<SceneCurve*>(entity)) {
+        SceneCurve *curve = (SceneCurve*) entity;
+        
+        if(!(*(entry))["type"])
+            entry->addChild("type", "SceneCurve");
+        
+        ObjectEntry *curveEntry = entry->addChild("SceneCurve");
+        curveEntry->addChild("render", curve->renderCurve);
+        curveEntry->addChild("resolution", curve->curveResolution);        
+        saveCurveToObject(curveEntry->addChild("curve"), curve->getCurve());
+        
     }
     
     if(dynamic_cast<SceneLight*>(entity)) {

+ 3 - 0
IDE/Contents/Source/PolycodeFrame.cpp

@@ -1409,6 +1409,9 @@ PolycodeFrame::PolycodeFrame(PolycodeEditorManager *editorManager) : UIElement()
 	
 	yesNoPopup = new YesNoPopup();
 	yesNoPopup->visible = false;
+    
+    messagePopup = new MessagePopup();
+    messagePopup->visible = false;
 	
 	yesNoCancelPopup = new YesNoCancelPopup();
 	yesNoCancelPopup->visible = false;

+ 64 - 0
IDE/Contents/Source/PolycodeProps.cpp

@@ -3400,6 +3400,70 @@ void CameraSheet::setCamera(Camera *camera) {
     }
 }
 
+SceneCurveSheet::SceneCurveSheet() : PropSheet("CURVE", "SceneCurve") {
+    curve = NULL;
+    enabled = false;
+    
+    addPointProp = new ButtonProp("Add Curve Point");
+    addProp(addPointProp);
+    addPointProp->getButton()->addEventListener(this, UIEvent::CLICK_EVENT);
+
+    renderProp = new BoolProp("Render");
+    addProp(renderProp);
+    renderProp->addEventListener(this, Event::CHANGE_EVENT);
+
+    numPointsProp = new NumberProp("Resolution");
+    addProp(numPointsProp);
+    numPointsProp->addEventListener(this, Event::CHANGE_EVENT);
+
+}
+
+SceneCurveSheet::~SceneCurveSheet() {
+    
+}
+
+void SceneCurveSheet::handleEvent(Event *event) {
+    if(!curve) {
+        return;
+    }
+    
+	if(event->getDispatcher() == renderProp) {
+        curve->renderCurve = renderProp->get();
+    } else if(event->getDispatcher() == numPointsProp) {
+        curve->curveResolution = (int)numPointsProp->get();
+    } else if(event->getDispatcher() == addPointProp->getButton()) {
+        
+        BezierPoint *lastPoint = curve->getCurve()->getControlPoint(curve->getCurve()->getNumControlPoints()-1);
+
+        Vector3 directionOffsetPoint = curve->getCurve()->getPointAt(0.9);
+        
+        Vector3 directionNormal = lastPoint->p2 - directionOffsetPoint;
+        directionNormal.Normalize();
+        
+        Vector3 newPoint1 = lastPoint->p2 + (directionNormal * 1.0);
+        Vector3 newPoint2 = lastPoint->p2 + (directionNormal * 2.0);
+        Vector3 newPoint3 = lastPoint->p2 + (directionNormal* 3.0);
+        
+        curve->getCurve()->addControlPoint(newPoint1.x, newPoint1.y, newPoint1.z,
+                                        newPoint2.x, newPoint2.y, newPoint2.z,
+                                        newPoint3.x, newPoint3.y, newPoint3.z);
+        
+    }
+    
+    PropSheet::handleEvent(event);
+}
+
+void SceneCurveSheet::setCurve(SceneCurve *curve) {
+    this->curve = curve;
+    if(curve) {
+        renderProp->set(curve->renderCurve);
+        numPointsProp->set(curve->curveResolution);
+        enabled = true;
+    } else {
+        enabled = false;
+    }
+}
+
 
 SceneSpriteSheet::SceneSpriteSheet() : PropSheet("SPRITE", "SceneSprite") {
 	sprite = NULL;

+ 41 - 0
IDE/Contents/Source/ToolWindows.cpp

@@ -76,6 +76,47 @@ TextInputPopup::~TextInputPopup() {
 	
 }
 
+MessagePopup::MessagePopup() : UIWindow("", 300, 80) {
+    captionLabel = new UILabel("This is a caption", 12);
+	addChild(captionLabel);
+	captionLabel->setPosition(padding, 35);
+    
+	okButton = new UIButton(L"OK", 100);
+	okButton->addEventListener(this, UIEvent::CLICK_EVENT);
+    addChild(okButton);
+	okButton->setPosition(120, 60);
+	
+	closeOnEscape = true;
+}
+
+MessagePopup::~MessagePopup() {
+    
+}
+
+void MessagePopup::setCaption(String caption) {
+	captionLabel->setText(caption);
+	
+	Number windowSize = captionLabel->getWidth() + 50;
+	if(windowSize < 400)
+		windowSize = 400;
+	setWindowSize(windowSize, 80);
+	captionLabel->setPosition(padding + (windowSize - captionLabel->getWidth()) / 2.0, 35);
+	okButton->setPosition(padding + ((windowSize - okButton->getWidth()) / 2.0), 60);
+}
+
+void MessagePopup::handleEvent(Event *event) {
+	if(event->getEventType() == "UIEvent") {
+		if(event->getEventCode() == UIEvent::CLICK_EVENT) {
+			if(event->getDispatcher() == okButton) {
+				dispatchEvent(new UIEvent(), UIEvent::OK_EVENT);
+				dispatchEvent(new UIEvent(), UIEvent::CLOSE_EVENT);
+			}
+		}
+	}
+	UIWindow::handleEvent(event);
+}
+
+
 YesNoPopup::YesNoPopup() : UIWindow(L"", 300, 80) {
 	
 	captionLabel = new UILabel("This is a caption", 12);	

+ 1 - 5
IDE/Contents/Source/TransformGizmo.cpp

@@ -1050,11 +1050,7 @@ void TransformGizmo::handleEvent(Event *event) {
                         {
                             Vector3 newPoint = getTransformPlanePosition();
                             Vector3 diff = (planeMatrix.Inverse() * newPoint) -(planeMatrix.Inverse() * startingPoint);
-                            diff = diff * getCompoundScale();
-                            
-                            printf("newPoint: %f,%f,%f\n", newPoint.x, newPoint.y, newPoint.z);
-                            printf("diff: %f,%f,%f (constraint: %f,%f,%f)\n", diff.x, diff.y, diff.z, transformConstraint.x, transformConstraint.y, transformConstraint.z);
-                            
+                            diff = diff * getCompoundScale();                                                        
                             transformSelectedEntities(transformConstraint * diff, Vector3(0.0, 0.0, 0.0), 0.0);
                             startingPoint = newPoint;
                         }

Некоторые файлы не были показаны из-за большого количества измененных файлов