From 04823f591151f7e7e9b194b63722c5f2a4711717 Mon Sep 17 00:00:00 2001 From: Modnark <66146584+Modnark@users.noreply.github.com> Date: Mon, 10 Oct 2022 18:41:29 -0400 Subject: [PATCH 01/11] Add listeners for all menu buttons --- src/source/DataModelV2/GuiRootInstance.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/source/DataModelV2/GuiRootInstance.cpp b/src/source/DataModelV2/GuiRootInstance.cpp index fa83d96..72bb220 100644 --- a/src/source/DataModelV2/GuiRootInstance.cpp +++ b/src/source/DataModelV2/GuiRootInstance.cpp @@ -157,6 +157,8 @@ GuiRootInstance::GuiRootInstance() : _message(""), _messageTime(0) button->fontLocationRelativeTo = Vector2(10, 0); button->setAllColorsSame(); button->boxColorOvr = Color4(0.6F,0.6F,0.6F,0.4F); + button->name = "edit"; + button->setButtonListener(menuListener); button = makeTextButton(); button->boxBegin = Vector2(250, 0); @@ -171,6 +173,8 @@ GuiRootInstance::GuiRootInstance() : _message(""), _messageTime(0) button->fontLocationRelativeTo = Vector2(10, 0); button->setAllColorsSame(); button->boxColorOvr = Color4(0.6F,0.6F,0.6F,0.4F); + button->name = "view"; + button->setButtonListener(menuListener); button = makeTextButton(); button->boxBegin = Vector2(375, 0); @@ -185,6 +189,8 @@ GuiRootInstance::GuiRootInstance() : _message(""), _messageTime(0) button->fontLocationRelativeTo = Vector2(10, 0); button->setAllColorsSame(); button->boxColorOvr = Color4(0.6F,0.6F,0.6F,0.4F); + button->name = "insert"; + button->setButtonListener(menuListener); button = makeTextButton(); button->boxBegin = Vector2(500, 0); @@ -199,7 +205,8 @@ GuiRootInstance::GuiRootInstance() : _message(""), _messageTime(0) button->fontLocationRelativeTo = Vector2(10, 0); button->setAllColorsSame(); button->boxColorOvr = Color4(0.6F,0.6F,0.6F,0.4F); - + button->name = "format"; + button->setButtonListener(menuListener); //Menu button = makeTextButton(); From 5e74564956218773790611d0ddf82eb8352e495b Mon Sep 17 00:00:00 2001 From: Modnark <66146584+Modnark@users.noreply.github.com> Date: Mon, 10 Oct 2022 18:41:46 -0400 Subject: [PATCH 02/11] Add listener for View button --- src/source/Listener/MenuButtonListener.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/source/Listener/MenuButtonListener.cpp b/src/source/Listener/MenuButtonListener.cpp index 4f0b02b..fbd6d67 100644 --- a/src/source/Listener/MenuButtonListener.cpp +++ b/src/source/Listener/MenuButtonListener.cpp @@ -34,4 +34,19 @@ void MenuButtonListener::onButton1MouseClick(BaseButtonInstance* button) break; } } + else if(button->name == "view") + { + HMENU mainmenu = CreatePopupMenu(); + AppendMenu(mainmenu, MF_STRING, 103, "Image Server Model View"); + + POINT p; + GetCursorPos(&p); + int menuClick = TrackPopupMenu(mainmenu, TPM_LEFTBUTTON | TPM_RETURNCMD, p.x, p.y, 0, Globals::mainHwnd, 0); + switch (menuClick) + { + case 103: + g_dataModel->getThumbnailGenerator()->click("PNG", 512, 512, true); + break; + } + } } \ No newline at end of file From 7e9f34e1ace4027d7721b285e7776f8ea06bcbc4 Mon Sep 17 00:00:00 2001 From: Modnark <66146584+Modnark@users.noreply.github.com> Date: Mon, 10 Oct 2022 18:47:49 -0400 Subject: [PATCH 03/11] handle some errors in ThumbnailGenerator --- ThumbnailGeneratorInstance.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ThumbnailGeneratorInstance.cpp b/ThumbnailGeneratorInstance.cpp index 898f67c..209cc76 100644 --- a/ThumbnailGeneratorInstance.cpp +++ b/ThumbnailGeneratorInstance.cpp @@ -21,9 +21,15 @@ ThumbnailGeneratorInstance::~ThumbnailGeneratorInstance(void) {} */ std::string ThumbnailGeneratorInstance::click(std::string fileType, int cx, int cy, bool hideSky) { + if(!G3D::GImage::supportedFormat(fileType)) { + printf("%s is not a valid fileType.", fileType); + return ""; + } + RenderDevice* rd = g_usableApp->getRenderDevice(); GuiRootInstance* guiRoot = g_dataModel->getGuiRoot(); const G3D::GImage::Format format = G3D::GImage::stringToFormat(fileType); + int prevWidth = rd->width(); int prevHeight = rd->height(); G3D::GImage imgBuffer(cx, cy, 4); From adade066cc3eefe65d342caba818f6b54a703861 Mon Sep 17 00:00:00 2001 From: Modnark <66146584+Modnark@users.noreply.github.com> Date: Mon, 10 Oct 2022 20:01:30 -0400 Subject: [PATCH 04/11] Start OnTouch --- src/include/DataModelV2/PartInstance.h | 11 ++ src/include/Enum.h | 6 ++ src/source/DataModelV2/PartInstance.cpp | 130 +++++++++++++++++++----- 3 files changed, 120 insertions(+), 27 deletions(-) diff --git a/src/include/DataModelV2/PartInstance.h b/src/include/DataModelV2/PartInstance.h index 90f9f58..93b0548 100644 --- a/src/include/DataModelV2/PartInstance.h +++ b/src/include/DataModelV2/PartInstance.h @@ -24,13 +24,24 @@ public: Enum::SurfaceType::Value back; Enum::SurfaceType::Value left; Enum::SurfaceType::Value bottom; + + //Shapes Enum::Shape::Value shape; + //OnTocuh + Enum::ActionType::Value OnTouchAction; + Enum::Sound::Value OnTouchSound; + //Variables Color3 color; bool canCollide; dBodyID physBody; dGeomID physGeom[3]; + bool singleShot; + int touchesToTrigger; + int uniqueObjectsToTrigger; + int changeScore; + int changeTimer; //Getters Vector3 getPosition(); diff --git a/src/include/Enum.h b/src/include/Enum.h index 8d9fbe6..0f4c2a1 100644 --- a/src/include/Enum.h +++ b/src/include/Enum.h @@ -32,4 +32,10 @@ namespace Enum NoChange = 0, Increase = 1, Decrease = 2 }; } + namespace Sound + { + enum Value { + NoSound = 0, Victory = 1, Boing = 2 + }; + } } \ No newline at end of file diff --git a/src/source/DataModelV2/PartInstance.cpp b/src/source/DataModelV2/PartInstance.cpp index 87bf613..290fa0c 100644 --- a/src/source/DataModelV2/PartInstance.cpp +++ b/src/source/DataModelV2/PartInstance.cpp @@ -27,6 +27,13 @@ PartInstance::PartInstance(void) left = Enum::SurfaceType::Smooth; bottom = Enum::SurfaceType::Smooth; shape = Enum::Shape::Block; + + // OnTouch + singleShot = true; + touchesToTrigger = 1; + uniqueObjectsToTrigger = 1; + changeScore = 0; + changeTimer = 0; } bool PartInstance::isDragging() @@ -164,8 +171,6 @@ PartInstance::PartInstance(const PartInstance &oinst) PVInstance::PVInstance(oinst); physBody = NULL; glList = glGenLists(1); - //name = oinst.name; - //className = "Part"; name = oinst.name; canCollide = oinst.canCollide; setParent(oinst.parent); @@ -183,6 +188,15 @@ PartInstance::PartInstance(const PartInstance &oinst) bottom = oinst.bottom; shape = oinst.shape; changed = true; + + // OnTouch + singleShot = oinst.singleShot; + touchesToTrigger = oinst.touchesToTrigger; + uniqueObjectsToTrigger = oinst.uniqueObjectsToTrigger; + changeScore = oinst.changeScore; + changeTimer = oinst.changeTimer; + OnTouchAction = oinst.OnTouchAction; + OnTouchSound = oinst.OnTouchSound; } void PartInstance::setSize(Vector3 newSize) @@ -363,6 +377,7 @@ char pto[512]; char pto2[512]; #include +// Shape static Enum::Shape::Value strEnum(TCHAR* shape) { if(strcmp("Block", shape) == 0) @@ -386,6 +401,64 @@ static TCHAR* enumStr(int shape) return "Block"; } +// ActionType +static TCHAR* strActionType(int option) +{ + switch(option) + { + case Enum::ActionType::Nothing: + return "Nothing"; + case Enum::ActionType::Pause: + return "Pause"; + case Enum::ActionType::Lose: + return "Lose"; + case Enum::ActionType::Draw: + return "Draw"; + case Enum::ActionType::Win: + return "Win"; + } + return "Nothing"; +} + +static Enum::ActionType::Value EnumOnTouchActionType(TCHAR* option) +{ + if(strcmp("Nothing", option) == 0) + return Enum::ActionType::Nothing; + if(strcmp("Pause", option) == 0) + return Enum::ActionType::Pause; + if(strcmp("Lose", option) == 0) + return Enum::ActionType::Lose; + if(strcmp("Draw", option) == 0) + return Enum::ActionType::Draw; + return Enum::ActionType::Win; +} + +// SoundType +static TCHAR* strSoundType(int option) +{ + switch(option) + { + case Enum::Sound::NoSound: + return "NoSound"; + case Enum::Sound::Victory: + return "Victory"; + case Enum::Sound::Boing: + return "Boing"; + } + return "NoSound"; +} + +static Enum::Sound::Value EnumOnTouchSoundType(TCHAR* option) +{ + if(strcmp("Nothing", option) == 0) + return Enum::Sound::NoSound; + if(strcmp("Victory", option) == 0) + return Enum::Sound::Victory; + if(strcmp("Boing", option) == 0) + return Enum::Sound::Boing; + return Enum::Sound::NoSound; +} + void PartInstance::PropUpdate(LPPROPGRIDITEM &item) { setChanged(); @@ -412,13 +485,6 @@ void PartInstance::PropUpdate(LPPROPGRIDITEM &item) ss.ignore(); } - //if(vect.size() != 3) - //{ - //sprintf(pto, "%g, %g, %g", cFrame.translation.x, cFrame.translation.y, cFrame.translation.z, "what"); - //LPCSTR str = LPCSTR(pto); - //item->lpCurValue = (LPARAM)str; - //} - //else if(vect.size() == 3) { Vector3 pos(vect.at(0),vect.at(1),vect.at(2)); @@ -441,13 +507,6 @@ void PartInstance::PropUpdate(LPPROPGRIDITEM &item) ss.ignore(); } - /*if(vect.size() != 3) - { - sprintf(pto, "%g, %g, %g", cFrame.translation.x, cFrame.translation.y, cFrame.translation.z, "what"); - LPCSTR str = LPCSTR(pto); - item->lpCurValue = (LPARAM)str; - } - else*/ if(vect.size() == 3) { Vector3 size(vect.at(0),vect.at(1),vect.at(2)); @@ -459,6 +518,14 @@ void PartInstance::PropUpdate(LPPROPGRIDITEM &item) printf("%s", enumStr(strEnum((TCHAR*)item->lpCurValue))); setShape(strEnum((TCHAR*)item->lpCurValue)); } + else if(strcmp(item->lpszPropName, "Action") == 0) + { + OnTouchAction = EnumOnTouchActionType((TCHAR*)item->lpCurValue); + } + else if (strcmp(item->lpszPropName, "Sound") == 0) + { + OnTouchSound = EnumOnTouchSoundType((TCHAR*)item->lpCurValue); + } else PVInstance::PropUpdate(item); } @@ -467,44 +534,53 @@ std::vector PartInstance::getProperties() std::vector properties = PVInstance::getProperties(); - properties.push_back(createPGI( - "Properties", + properties.push_back(createPGI("Properties", "Color3", "The color of the selected part", RGB((color.r*255),(color.g*255),(color.b*255)), PIT_COLOR )); - properties.push_back(createPGI( - "Item", + properties.push_back(createPGI("Item", "Anchored", "Whether the block can move or not", (LPARAM)anchored, PIT_CHECK )); sprintf_s(pto, "%g, %g, %g", position.x, position.y, position.z); - properties.push_back(createPGI( - "Item", + properties.push_back(createPGI("Item", "Offset", "The position of the object in the workspace", (LPARAM)pto, PIT_EDIT )); sprintf_s(pto2, "%g, %g, %g", size.x, size.y, size.z); - properties.push_back(createPGI( - "Item", + properties.push_back(createPGI("Item", "Size", - "The position of the object in the workspace", + "The size of the object in the workspace", (LPARAM)pto2, PIT_EDIT )); - properties.push_back(createPGI( - "Item", + properties.push_back(createPGI("Item", "Shape", "The shape of the object in the workspace", (LPARAM)enumStr(shape), PIT_COMBO, TEXT("Ball\0Block\0Cylinder\0") )); + properties.push_back(createPGI("OnTouch", + "Action", + "What action is taken when touched", + (LPARAM)strActionType(OnTouchAction), + PIT_COMBO, + TEXT("Nothing\0Pause\0Lose\0Draw\0Win\0") + )); + properties.push_back(createPGI("OnTouch", + "Sound", + "What sound plays when touched", + (LPARAM)strSoundType(OnTouchSound), + PIT_COMBO, + TEXT("NoSound\0Victory\0Boing\0") + )); return properties; } From d2f3e718a72f44db6e21df592ac8f320db1a5346 Mon Sep 17 00:00:00 2001 From: Modnark <66146584+Modnark@users.noreply.github.com> Date: Tue, 11 Oct 2022 10:03:04 -0400 Subject: [PATCH 05/11] Very basic implementation of OnTouch --- content/sounds/bass.wav | Bin 0 -> 6380 bytes content/sounds/victory.wav | Bin 0 -> 26680 bytes src/include/DataModelV2/PartInstance.h | 25 ++++-- src/source/DataModelV2/LevelInstance.cpp | 4 +- src/source/DataModelV2/PartInstance.cpp | 107 +++++++++++++++++++++++ src/source/XplicitNgine/XplicitNgine.cpp | 27 ++++-- 6 files changed, 149 insertions(+), 14 deletions(-) create mode 100644 content/sounds/bass.wav create mode 100644 content/sounds/victory.wav diff --git a/content/sounds/bass.wav b/content/sounds/bass.wav new file mode 100644 index 0000000000000000000000000000000000000000..5f4b7913ba5c493f74c13fd17a7fc50ddfef659f GIT binary patch literal 6380 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 j4EMDkdDFij8hMhoP1wLdEqs&}Q*<@EXn3sb# getProperties(); virtual void PropUpdate(LPPROPGRIDITEM &pItem); @@ -87,4 +92,12 @@ private: bool dragging; Box itemBox; GLuint glList; + + // OnTouch + bool singleShot; + int touchesToTrigger; + int uniqueObjectsToTrigger; + int changeScore; + float changeTimer; + bool _touchedOnce; }; \ No newline at end of file diff --git a/src/source/DataModelV2/LevelInstance.cpp b/src/source/DataModelV2/LevelInstance.cpp index cd51b6d..9aea060 100644 --- a/src/source/DataModelV2/LevelInstance.cpp +++ b/src/source/DataModelV2/LevelInstance.cpp @@ -123,7 +123,7 @@ std::vector LevelInstance::getProperties() (LPARAM)scoreTxt, PIT_EDIT)); - properties.push_back(createPGI("Gameplay", + properties.push_back(createPGI("Gameplay", "TimerUpAction", "Some temporary string here", (LPARAM)strActionType(TimerUpAction), @@ -131,7 +131,7 @@ std::vector LevelInstance::getProperties() TEXT("Nothing\0Pause\0Lose\0Draw\0Win\0") )); - properties.push_back(createPGI("Gameplay", + properties.push_back(createPGI("Gameplay", "TimerAffectsScore", "Some temporary string here", (LPARAM)strAffectType(TimerAffectsScore), diff --git a/src/source/DataModelV2/PartInstance.cpp b/src/source/DataModelV2/PartInstance.cpp index 290fa0c..defcd56 100644 --- a/src/source/DataModelV2/PartInstance.cpp +++ b/src/source/DataModelV2/PartInstance.cpp @@ -4,6 +4,8 @@ #include #include #include "Faces.h" +#include "AudioPlayer.h" +#include "StringFunctions.h" PartInstance::PartInstance(void) { @@ -27,6 +29,7 @@ PartInstance::PartInstance(void) left = Enum::SurfaceType::Smooth; bottom = Enum::SurfaceType::Smooth; shape = Enum::Shape::Block; + _touchedOnce = false; // OnTouch singleShot = true; @@ -34,6 +37,7 @@ PartInstance::PartInstance(void) uniqueObjectsToTrigger = 1; changeScore = 0; changeTimer = 0; + singleShot = true; } bool PartInstance::isDragging() @@ -67,6 +71,32 @@ Vector3 PartInstance::getRotVelocity() return rotVelocity; } +// OnTouch +bool PartInstance::isSingleShot() +{ + return singleShot; +} + +int PartInstance::getTouchesToTrigger() +{ + return touchesToTrigger; +} + +int PartInstance::getUniqueObjectsToTrigger() +{ + return uniqueObjectsToTrigger; +} + +int PartInstance::getChangeScore() +{ + return changeScore; +} + +float PartInstance::getChangeTimer() +{ + return changeTimer; +} + void PartInstance::setVelocity(Vector3 v) { velocity = v; @@ -197,6 +227,8 @@ PartInstance::PartInstance(const PartInstance &oinst) changeTimer = oinst.changeTimer; OnTouchAction = oinst.OnTouchAction; OnTouchSound = oinst.OnTouchSound; + singleShot = oinst.singleShot; + _touchedOnce = false; } void PartInstance::setSize(Vector3 newSize) @@ -459,6 +491,46 @@ static Enum::Sound::Value EnumOnTouchSoundType(TCHAR* option) return Enum::Sound::NoSound; } +void PartInstance::onTouch() +{ + if(singleShot && _touchedOnce) + return; + + if(singleShot && !_touchedOnce) + _touchedOnce = true; + + g_dataModel->getLevel()->score += changeScore; + g_dataModel->getLevel()->timer += changeTimer; + + switch(OnTouchAction) + { + case Enum::ActionType::Nothing: + break; + case Enum::ActionType::Pause: + break; + case Enum::ActionType::Lose: + g_dataModel->getLevel()->loseCondition(); + break; + case Enum::ActionType::Draw: + break; + case Enum::ActionType::Win: + g_dataModel->getLevel()->winCondition(); + break; + } + + switch(OnTouchSound) + { + case Enum::Sound::NoSound: + break; + case Enum::Sound::Victory: + AudioPlayer::playSound(GetFileInPath("/content/sounds/victory.wav")); + break; + case Enum::Sound::Boing: + AudioPlayer::playSound(GetFileInPath("/content/sounds/boing.wav")); + break; + } +} + void PartInstance::PropUpdate(LPPROPGRIDITEM &item) { setChanged(); @@ -526,9 +598,25 @@ void PartInstance::PropUpdate(LPPROPGRIDITEM &item) { OnTouchSound = EnumOnTouchSoundType((TCHAR*)item->lpCurValue); } + else if (strcmp(item->lpszPropName, "ChangeScore") == 0) + { + changeScore = atoi((LPSTR)item->lpCurValue); + } + else if (strcmp(item->lpszPropName, "ChangeTimer") == 0) + { + changeTimer = atof((LPSTR)item->lpCurValue); + } + else if (strcmp(item->lpszPropName, "SingleShot") == 0) + { + singleShot = item->lpCurValue == TRUE; + } else PVInstance::PropUpdate(item); } +// This needs to be changed, buffer size of 12 is way too small +// Crash occurs if you put a huge number in +char changeTimerTxt[12]; +char changeScoreTxt[12]; std::vector PartInstance::getProperties() { std::vector properties = PVInstance::getProperties(); @@ -581,6 +669,25 @@ std::vector PartInstance::getProperties() PIT_COMBO, TEXT("NoSound\0Victory\0Boing\0") )); + + sprintf_s(changeScoreTxt, "%d", changeScore); + sprintf_s(changeTimerTxt, "%g", changeTimer); + properties.push_back(createPGI("OnTouch", + "ChangeScore", + "How the score is affected when touched", + (LPARAM)changeScoreTxt, + PIT_EDIT)); + properties.push_back(createPGI("OnTouch", + "ChangeTimer", + "How the timer is affected when touched", + (LPARAM)changeTimerTxt, + PIT_EDIT)); + properties.push_back(createPGI("OnTouch", + "SingleShot", + "Whether or not Action happens only once", + (LPARAM)singleShot, + PIT_CHECK + )); return properties; } diff --git a/src/source/XplicitNgine/XplicitNgine.cpp b/src/source/XplicitNgine/XplicitNgine.cpp index 7421fb7..8373c8f 100644 --- a/src/source/XplicitNgine/XplicitNgine.cpp +++ b/src/source/XplicitNgine/XplicitNgine.cpp @@ -25,10 +25,10 @@ XplicitNgine::~XplicitNgine() dCloseODE(); } -void XplicitNgine::resetBody(PartInstance* partInstance) -{ - deleteBody(partInstance); - createBody(partInstance); +void XplicitNgine::resetBody(PartInstance* partInstance) +{ + deleteBody(partInstance); + createBody(partInstance); } void collisionCallback(void *data, dGeomID o1, dGeomID o2) @@ -37,10 +37,12 @@ void collisionCallback(void *data, dGeomID o1, dGeomID o2) dBodyID b1 = dGeomGetBody(o1); dBodyID b2 = dGeomGetBody(o2); - + if (b1 && b2 && dAreConnected(b1, b2)) return; + + const int N = 4; dContact contact[N]; n = dCollide (o1,o2,N,&contact[0].geom,sizeof(dContact)); @@ -62,8 +64,17 @@ void collisionCallback(void *data, dGeomID o1, dGeomID o2) g_xplicitNgine->contactgroup, contact+i ); - + dJointAttach (c,b1,b2); + + if(b1 != NULL) + { + PartInstance* touched = (PartInstance*)dGeomGetData(o2); + if(touched != NULL) + { + touched->onTouch(); + } + } } } } @@ -123,6 +134,7 @@ void XplicitNgine::createBody(PartInstance* partInstance) partInstance->physBody = dBodyCreate(physWorld); dBodySetData(partInstance->physBody, partInstance); + // Create geom if(partInstance->shape == Enum::Shape::Block) { @@ -140,6 +152,9 @@ void XplicitNgine::createBody(PartInstance* partInstance) partInstance->physGeom[0] = dCreateSphere(physSpace, partSize[0]/2); } + if(partInstance->physGeom[0]) + dGeomSetData(partInstance->physGeom[0], partInstance); + dMass mass; mass.setBox(sqrt(partSize.x*2), sqrt(partSize.y*2), sqrt(partSize.z*2), 0.7F); dBodySetMass(partInstance->physBody, &mass); From d269b360ce5b32dc16f0c0fd4d007a3f5ac53ad3 Mon Sep 17 00:00:00 2001 From: Modnark <66146584+Modnark@users.noreply.github.com> Date: Tue, 11 Oct 2022 21:16:14 -0400 Subject: [PATCH 06/11] SoundService & SoundInstance Basic implementation. More work needs to be done. --- Blocks3D.vcproj | 16 ++++ src/include/DataModelV2/DataModelInstance.h | 20 ++++- src/include/DataModelV2/Instance.h | 1 - src/include/DataModelV2/SoundInstance.h | 30 +++++++ src/include/DataModelV2/SoundService.h | 16 ++++ src/source/DataModelV2/DataModelInstance.cpp | 9 ++- src/source/DataModelV2/PartInstance.cpp | 6 +- src/source/DataModelV2/SoundInstance.cpp | 52 ++++++++++++ src/source/DataModelV2/SoundService.cpp | 83 ++++++++++++++++++++ 9 files changed, 225 insertions(+), 8 deletions(-) create mode 100644 src/include/DataModelV2/SoundInstance.h create mode 100644 src/include/DataModelV2/SoundService.h create mode 100644 src/source/DataModelV2/SoundInstance.cpp create mode 100644 src/source/DataModelV2/SoundService.cpp diff --git a/Blocks3D.vcproj b/Blocks3D.vcproj index e67dd6c..c123448 100644 --- a/Blocks3D.vcproj +++ b/Blocks3D.vcproj @@ -505,6 +505,14 @@ RelativePath=".\src\source\DataModel\SelectionService.cpp" > + + + + @@ -878,6 +886,14 @@ RelativePath=".\src\include\DataModelV2\SelectionService.h" > + + + + diff --git a/src/include/DataModelV2/DataModelInstance.h b/src/include/DataModelV2/DataModelInstance.h index 9591ffa..bae7bd4 100644 --- a/src/include/DataModelV2/DataModelInstance.h +++ b/src/include/DataModelV2/DataModelInstance.h @@ -1,12 +1,17 @@ #pragma once + +// Instances #include "WorkspaceInstance.h" #include "LevelInstance.h" #include "PartInstance.h" -#include "ThumbnailGeneratorInstance.h" #include "SelectionService.h" -#include "rapidxml/rapidxml.hpp" #include "GuiRootInstance.h" +#include "ThumbnailGeneratorInstance.h" #include "XplicitNgine/XplicitNgine.h" +#include "SoundService.h" + +// Libraries +#include "rapidxml/rapidxml.hpp" class GuiRootInstance; @@ -25,10 +30,12 @@ public: bool readXMLFileStream(std::ifstream* file); void drawMessage(RenderDevice*); + // Instance getters WorkspaceInstance* getWorkspace(); LevelInstance* getLevel(); XplicitNgine* getEngine(); ThumbnailGeneratorInstance* getThumbnailGenerator(); + SoundService* getSoundService(); std::string message; std::string _loadedFileName; @@ -53,11 +60,16 @@ private: std::string _errMsg; bool _legacyLoad; float _modY; + + // Instances WorkspaceInstance* workspace; LevelInstance* level; GuiRootInstance* guiRoot; SelectionService* selectionService; - ThumbnailGeneratorInstance * thumbnailGenerator; + ThumbnailGeneratorInstance* thumbnailGenerator; + XplicitNgine* xplicitNgine; + SoundService* soundService; + bool running; - XplicitNgine * xplicitNgine; + }; diff --git a/src/include/DataModelV2/Instance.h b/src/include/DataModelV2/Instance.h index b8009bd..7e25dce 100644 --- a/src/include/DataModelV2/Instance.h +++ b/src/include/DataModelV2/Instance.h @@ -2,7 +2,6 @@ #include #include "propertyGrid.h" #include "map" -//#include "Properties/BoolProperty.h" class Instance { diff --git a/src/include/DataModelV2/SoundInstance.h b/src/include/DataModelV2/SoundInstance.h new file mode 100644 index 0000000..c70d168 --- /dev/null +++ b/src/include/DataModelV2/SoundInstance.h @@ -0,0 +1,30 @@ +#pragma once +#include "Instance.h" + +class SoundInstance : + public Instance +{ +public: + SoundInstance(void); + ~SoundInstance(void); + + // Getters + float getSoundVolume(); + std::string getSoundId(); + bool isPlayedOnRemove(); + bool isLooped(); + + // Setters + void setSoundVolume(float newVolume); + void setSoundId(std::string newSoundId); + void setIsPlayedOnRemove(bool isPlayed); + void setIsLooped(bool isLooped); + + // Functions + void play(); +private: + float soundVolume; + std::string soundId; + bool playOnRemove; + bool looped; +}; diff --git a/src/include/DataModelV2/SoundService.h b/src/include/DataModelV2/SoundService.h new file mode 100644 index 0000000..62b1ae5 --- /dev/null +++ b/src/include/DataModelV2/SoundService.h @@ -0,0 +1,16 @@ +#pragma once +#include "Instance.h" +#include "SoundInstance.h" + +class SoundService : + public Instance +{ +public: + SoundService(void); + ~SoundService(void); + + float getMusicVolume(); + void playSound(SoundInstance* sound); +private: + float musicVolume; +}; diff --git a/src/source/DataModelV2/DataModelInstance.cpp b/src/source/DataModelV2/DataModelInstance.cpp index 4da558f..f4fc9f0 100644 --- a/src/source/DataModelV2/DataModelInstance.cpp +++ b/src/source/DataModelV2/DataModelInstance.cpp @@ -14,14 +14,15 @@ using namespace std; using namespace rapidxml; - DataModelInstance::DataModelInstance(void) { + // Instances Instance::Instance(); workspace = new WorkspaceInstance(); guiRoot = new GuiRootInstance(); level = new LevelInstance(); thumbnailGenerator = new ThumbnailGeneratorInstance(); + soundService = new SoundService(); selectionService = new SelectionService(); selectionService->setPropertyWindow(g_usableApp->_propWindow); @@ -31,6 +32,7 @@ DataModelInstance::DataModelInstance(void) _modY=0; workspace->setParent(this); level->setParent(this); + _loadedFileName="..//skooter.rbxm"; listicon = 5; running = false; @@ -655,3 +657,8 @@ ThumbnailGeneratorInstance* DataModelInstance::getThumbnailGenerator() { return thumbnailGenerator; } + +SoundService* DataModelInstance::getSoundService() +{ + return soundService; +} \ No newline at end of file diff --git a/src/source/DataModelV2/PartInstance.cpp b/src/source/DataModelV2/PartInstance.cpp index defcd56..a38bbec 100644 --- a/src/source/DataModelV2/PartInstance.cpp +++ b/src/source/DataModelV2/PartInstance.cpp @@ -518,15 +518,17 @@ void PartInstance::onTouch() break; } + SoundService* sndService = g_dataModel->getSoundService(); + switch(OnTouchSound) { case Enum::Sound::NoSound: break; case Enum::Sound::Victory: - AudioPlayer::playSound(GetFileInPath("/content/sounds/victory.wav")); + sndService->playSound(dynamic_cast(sndService->findFirstChild("Victory"))); break; case Enum::Sound::Boing: - AudioPlayer::playSound(GetFileInPath("/content/sounds/boing.wav")); + sndService->playSound(dynamic_cast(sndService->findFirstChild("Boing"))); break; } } diff --git a/src/source/DataModelV2/SoundInstance.cpp b/src/source/DataModelV2/SoundInstance.cpp new file mode 100644 index 0000000..7f3072e --- /dev/null +++ b/src/source/DataModelV2/SoundInstance.cpp @@ -0,0 +1,52 @@ +#include "DataModelV2/SoundInstance.h" +#include "Globals.h" + +SoundInstance::SoundInstance() +{ + name = "Sound"; + className = "Sound"; + + soundVolume = 0.5; + soundId = ""; + playOnRemove = false; + looped = false; +} + +SoundInstance::~SoundInstance(void) +{ + if(isPlayedOnRemove()) + play(); +} + +// Functions +void SoundInstance::play() +{ + g_dataModel->getSoundService()->playSound(this); +} + +// Getters +float SoundInstance::getSoundVolume() +{ + return soundVolume; +} + +bool SoundInstance::isPlayedOnRemove() +{ + return playOnRemove; +} + +std::string SoundInstance::getSoundId() +{ + return soundId; +} + +bool SoundInstance::isLooped() +{ + return looped; +} + +// Setters +void SoundInstance::setSoundId(std::string newSoundId) +{ + soundId = newSoundId; +} \ No newline at end of file diff --git a/src/source/DataModelV2/SoundService.cpp b/src/source/DataModelV2/SoundService.cpp new file mode 100644 index 0000000..17c9ffd --- /dev/null +++ b/src/source/DataModelV2/SoundService.cpp @@ -0,0 +1,83 @@ +#include "DataModelV2/SoundService.h" +#include "StringFunctions.h" +#include "AudioPlayer.h" +#include "Globals.h" + +SoundService::SoundService() +{ + name = "SoundService"; + className = "SoundService"; + musicVolume = 0.3f; + + // Create stock sounds + SoundInstance* stockSound = new SoundInstance(); + + // Victory + stockSound = new SoundInstance(); + stockSound->setName("Victory"); + stockSound->setSoundId("/content/sounds/victory.wav"); + stockSound->setParent(this); + + // Boing + stockSound = new SoundInstance(); + stockSound->setName("Boing"); + stockSound->setSoundId("/content/sounds/bass.wav"); + stockSound->setParent(this); + + // Bomb + stockSound = new SoundInstance(); + stockSound->setName("Bomb"); + stockSound->setSoundId("/content/sounds/collide.wav"); + stockSound->setParent(this); + + // Ping + stockSound = new SoundInstance(); + stockSound->setName("Ping"); + stockSound->setSoundId("/content/sounds/electronicpingshort.wav"); + stockSound->setParent(this); + + // Break + stockSound = new SoundInstance(); + stockSound->setName("Break"); + stockSound->setSoundId("/content/sounds/glassbreak.wav"); + stockSound->setParent(this); + + // Splat + stockSound = new SoundInstance(); + stockSound->setName("Splat"); + stockSound->setSoundId("/content/sounds/splat.wav"); + stockSound->setParent(this); + + // Swoosh + stockSound = new SoundInstance(); + stockSound->setName("Swoosh"); + stockSound->setSoundId("/content/sounds/swoosh.wav"); + stockSound->setParent(this); + + // Snap + stockSound = new SoundInstance(); + stockSound->setName("Snap"); + stockSound->setSoundId("/content/sounds/snap.wav"); + stockSound->setParent(this); + + // Page + stockSound = new SoundInstance(); + stockSound->setName("Page"); + stockSound->setSoundId("/content/sounds/pageturn.wav"); + stockSound->setParent(this); +} + +SoundService::~SoundService(void) +{ +} + +void SoundService::playSound(SoundInstance* sound) +{ + std::string soundId = sound->getSoundId(); + AudioPlayer::playSound(GetFileInPath(soundId)); +} + +float SoundService::getMusicVolume() +{ + return musicVolume; +} \ No newline at end of file From 9df862f72e97a0636677ae3d2fa650d1651b4ea1 Mon Sep 17 00:00:00 2001 From: Modnark <66146584+Modnark@users.noreply.github.com> Date: Tue, 11 Oct 2022 21:27:42 -0400 Subject: [PATCH 07/11] Add required sounds --- content/sounds/collide.wav | Bin 0 -> 11070 bytes content/sounds/glassbreak.wav | Bin 0 -> 17502 bytes content/sounds/snap.wav | Bin 0 -> 2892 bytes content/sounds/splat.wav | Bin 0 -> 1886 bytes content/sounds/swoosh.wav | Bin 0 -> 1726 bytes 5 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 content/sounds/collide.wav create mode 100644 content/sounds/glassbreak.wav create mode 100644 content/sounds/snap.wav create mode 100644 content/sounds/splat.wav create mode 100644 content/sounds/swoosh.wav diff --git a/content/sounds/collide.wav b/content/sounds/collide.wav new file mode 100644 index 0000000000000000000000000000000000000000..ef4b9ecd529a28cfc0806e5786458b84f2be5030 GIT binary patch literal 11070 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%0AjE5F_D}-_S%(7;97)n@6wjlY- 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 Date: Tue, 11 Oct 2022 21:28:19 -0400 Subject: [PATCH 08/11] Add dynamic_cast for playSound makes it so developers don't need to dynamic_cast any time they want to play sound --- src/include/DataModelV2/SoundService.h | 2 +- src/source/DataModelV2/PartInstance.cpp | 4 ++-- src/source/DataModelV2/SoundService.cpp | 11 ++++++++--- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/include/DataModelV2/SoundService.h b/src/include/DataModelV2/SoundService.h index 62b1ae5..9063438 100644 --- a/src/include/DataModelV2/SoundService.h +++ b/src/include/DataModelV2/SoundService.h @@ -10,7 +10,7 @@ public: ~SoundService(void); float getMusicVolume(); - void playSound(SoundInstance* sound); + void playSound(Instance* sound); private: float musicVolume; }; diff --git a/src/source/DataModelV2/PartInstance.cpp b/src/source/DataModelV2/PartInstance.cpp index a38bbec..8fb5837 100644 --- a/src/source/DataModelV2/PartInstance.cpp +++ b/src/source/DataModelV2/PartInstance.cpp @@ -525,10 +525,10 @@ void PartInstance::onTouch() case Enum::Sound::NoSound: break; case Enum::Sound::Victory: - sndService->playSound(dynamic_cast(sndService->findFirstChild("Victory"))); + sndService->playSound(sndService->findFirstChild("Victory")); break; case Enum::Sound::Boing: - sndService->playSound(dynamic_cast(sndService->findFirstChild("Boing"))); + sndService->playSound(sndService->findFirstChild("Boing")); break; } } diff --git a/src/source/DataModelV2/SoundService.cpp b/src/source/DataModelV2/SoundService.cpp index 17c9ffd..46662d4 100644 --- a/src/source/DataModelV2/SoundService.cpp +++ b/src/source/DataModelV2/SoundService.cpp @@ -71,10 +71,15 @@ SoundService::~SoundService(void) { } -void SoundService::playSound(SoundInstance* sound) +void SoundService::playSound(Instance* sound) { - std::string soundId = sound->getSoundId(); - AudioPlayer::playSound(GetFileInPath(soundId)); + // Try to dynamic_cast it to SoundInstance + SoundInstance* sndInst = dynamic_cast(sound); + if(sndInst != NULL) + { + std::string soundId = sndInst->getSoundId(); + AudioPlayer::playSound(GetFileInPath(soundId)); + } } float SoundService::getMusicVolume() From d32b0ea4e4a75bf75e5c45b7820d233e408dffa3 Mon Sep 17 00:00:00 2001 From: Modnark <66146584+Modnark@users.noreply.github.com> Date: Tue, 11 Oct 2022 22:34:36 -0400 Subject: [PATCH 09/11] Add more sounds internally --- src/include/AudioPlayer.h | 3 +- src/include/Enum.h | 4 +- src/source/Application.cpp | 2 + src/source/AudioPlayer.cpp | 4 +- src/source/DataModelV2/DataModelInstance.cpp | 1 + src/source/DataModelV2/Instance.cpp | 3 -- src/source/DataModelV2/PartInstance.cpp | 52 +++++++++++++++++++- src/source/DataModelV2/SoundInstance.cpp | 1 + src/source/DataModelV2/SoundService.cpp | 2 + src/source/main.cpp | 2 - 10 files changed, 64 insertions(+), 10 deletions(-) diff --git a/src/include/AudioPlayer.h b/src/include/AudioPlayer.h index 7467064..7068099 100644 --- a/src/include/AudioPlayer.h +++ b/src/include/AudioPlayer.h @@ -6,6 +6,7 @@ class AudioPlayer public: AudioPlayer(void); ~AudioPlayer(void); - static void playSound(std::string); + static void init(); + static void playSound(std::string); }; diff --git a/src/include/Enum.h b/src/include/Enum.h index 0f4c2a1..0643d95 100644 --- a/src/include/Enum.h +++ b/src/include/Enum.h @@ -35,7 +35,9 @@ namespace Enum namespace Sound { enum Value { - NoSound = 0, Victory = 1, Boing = 2 + NoSound = 0, Victory = 1, Boing = 2, Bomb = 3, + Ping = 4, Break = 5, Splat = 6, Swoosh = 7, + Snap = 8, Page = 9 }; } } \ No newline at end of file diff --git a/src/source/Application.cpp b/src/source/Application.cpp index 5a7d908..1f31657 100644 --- a/src/source/Application.cpp +++ b/src/source/Application.cpp @@ -130,6 +130,8 @@ Application::Application(HWND parentWindow) : _propWindow(NULL) { //: GApp(setti return; } + AudioPlayer::init(); + _window = renderDevice->window(); _window->makeCurrent(); diff --git a/src/source/AudioPlayer.cpp b/src/source/AudioPlayer.cpp index 5c5e595..f23c280 100644 --- a/src/source/AudioPlayer.cpp +++ b/src/source/AudioPlayer.cpp @@ -4,7 +4,7 @@ #include #include #include -#define NUM_SOUNDS 10 +#define NUM_SOUNDS 32 static SDL_AudioSpec fmt; static bool initiated = false; @@ -23,7 +23,7 @@ void AudioPlayer::init() initiated = true; extern void mixaudio(void *unused, Uint8 *stream, int len); fmt.freq = 22050; - fmt.format = AUDIO_S16; + fmt.format = AUDIO_S16LSB; fmt.channels = 2; fmt.samples = 1024; /* A good value for games */ fmt.callback = mixaudio; diff --git a/src/source/DataModelV2/DataModelInstance.cpp b/src/source/DataModelV2/DataModelInstance.cpp index f4fc9f0..7eef1f9 100644 --- a/src/source/DataModelV2/DataModelInstance.cpp +++ b/src/source/DataModelV2/DataModelInstance.cpp @@ -32,6 +32,7 @@ DataModelInstance::DataModelInstance(void) _modY=0; workspace->setParent(this); level->setParent(this); + soundService->setParent(this); _loadedFileName="..//skooter.rbxm"; listicon = 5; diff --git a/src/source/DataModelV2/Instance.cpp b/src/source/DataModelV2/Instance.cpp index 4cb1279..98fceea 100644 --- a/src/source/DataModelV2/Instance.cpp +++ b/src/source/DataModelV2/Instance.cpp @@ -20,11 +20,8 @@ Instance::Instance(const Instance &oinst) className = oinst.className; canDelete = oinst.canDelete; listicon = oinst.listicon; - //setParent(oinst.parent); } - - void Instance::render(RenderDevice* rd) { for(size_t i = 0; i < children.size(); i++) diff --git a/src/source/DataModelV2/PartInstance.cpp b/src/source/DataModelV2/PartInstance.cpp index 8fb5837..0cb6dbf 100644 --- a/src/source/DataModelV2/PartInstance.cpp +++ b/src/source/DataModelV2/PartInstance.cpp @@ -476,6 +476,20 @@ static TCHAR* strSoundType(int option) return "Victory"; case Enum::Sound::Boing: return "Boing"; + case Enum::Sound::Splat: + return "Splat"; + case Enum::Sound::Snap: + return "Snap"; + case Enum::Sound::Bomb: + return "Bomb"; + case Enum::Sound::Break: + return "Break"; + case Enum::Sound::Ping: + return "Ping"; + case Enum::Sound::Swoosh: + return "Swoosh"; + case Enum::Sound::Page: + return "Page"; } return "NoSound"; } @@ -488,6 +502,21 @@ static Enum::Sound::Value EnumOnTouchSoundType(TCHAR* option) return Enum::Sound::Victory; if(strcmp("Boing", option) == 0) return Enum::Sound::Boing; + if(strcmp("Splat", option) == 0) + return Enum::Sound::Splat; + if(strcmp("Bomb", option) == 0) + return Enum::Sound::Bomb; + if(strcmp("Break", option) == 0) + return Enum::Sound::Break; + if(strcmp("Swoosh", option) == 0) + return Enum::Sound::Swoosh; + if(strcmp("Page", option) == 0) + return Enum::Sound::Page; + if(strcmp("Ping", option) == 0) + return Enum::Sound::Ping; + if(strcmp("Snap", option) == 0) + return Enum::Sound::Snap; + return Enum::Sound::NoSound; } @@ -530,6 +559,27 @@ void PartInstance::onTouch() case Enum::Sound::Boing: sndService->playSound(sndService->findFirstChild("Boing")); break; + case Enum::Sound::Break: + sndService->playSound(sndService->findFirstChild("Break")); + break; + case Enum::Sound::Snap: + sndService->playSound(sndService->findFirstChild("Snap")); + break; + case Enum::Sound::Bomb: + sndService->playSound(sndService->findFirstChild("Bomb")); + break; + case Enum::Sound::Splat: + sndService->playSound(sndService->findFirstChild("Splat")); + break; + case Enum::Sound::Page: + sndService->playSound(sndService->findFirstChild("Page")); + break; + case Enum::Sound::Ping: + sndService->playSound(sndService->findFirstChild("Ping")); + break; + case Enum::Sound::Swoosh: + sndService->playSound(sndService->findFirstChild("Swoosh")); + break; } } @@ -669,7 +719,7 @@ std::vector PartInstance::getProperties() "What sound plays when touched", (LPARAM)strSoundType(OnTouchSound), PIT_COMBO, - TEXT("NoSound\0Victory\0Boing\0") + TEXT("NoSound\0Victory\0Boing\0Break\0Snap\0Bomb\0Splat\0Page\0Ping\0Swoosh\0") )); sprintf_s(changeScoreTxt, "%d", changeScore); diff --git a/src/source/DataModelV2/SoundInstance.cpp b/src/source/DataModelV2/SoundInstance.cpp index 7f3072e..b53cc74 100644 --- a/src/source/DataModelV2/SoundInstance.cpp +++ b/src/source/DataModelV2/SoundInstance.cpp @@ -5,6 +5,7 @@ SoundInstance::SoundInstance() { name = "Sound"; className = "Sound"; + listicon = 8; soundVolume = 0.5; soundId = ""; diff --git a/src/source/DataModelV2/SoundService.cpp b/src/source/DataModelV2/SoundService.cpp index 46662d4..bd26307 100644 --- a/src/source/DataModelV2/SoundService.cpp +++ b/src/source/DataModelV2/SoundService.cpp @@ -8,6 +8,8 @@ SoundService::SoundService() name = "SoundService"; className = "SoundService"; musicVolume = 0.3f; + listicon = 8; + canDelete = false; // Create stock sounds SoundInstance* stockSound = new SoundInstance(); diff --git a/src/source/main.cpp b/src/source/main.cpp index 18a8bd3..856768b 100644 --- a/src/source/main.cpp +++ b/src/source/main.cpp @@ -159,8 +159,6 @@ int main(int argc, char** argv) { icc.dwICC = ICC_WIN95_CLASSES/*|ICC_COOL_CLASSES|ICC_DATE_CLASSES| ICC_PAGESCROLLER_CLASS|ICC_USEREX_CLASSES*/; InitCommonControlsEx(&icc); - - AudioPlayer::init(); HMODULE hThisInstance = GetModuleHandle(NULL); if (!createWindowClass("mainHWND",WndProc,hThisInstance)) From 2dc7f3e667fc0ac62e8aa1573d490ccbbbcff707 Mon Sep 17 00:00:00 2001 From: Modnark <66146584+Modnark@users.noreply.github.com> Date: Tue, 11 Oct 2022 22:38:34 -0400 Subject: [PATCH 10/11] solve merge conflict --- src/include/DataModelV2/PartInstance.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/include/DataModelV2/PartInstance.h b/src/include/DataModelV2/PartInstance.h index ffdf211..ffbfce4 100644 --- a/src/include/DataModelV2/PartInstance.h +++ b/src/include/DataModelV2/PartInstance.h @@ -16,7 +16,8 @@ public: //Rendering virtual void PartInstance::postRender(RenderDevice* rd); virtual void render(RenderDevice*); - + virtual void renderName(RenderDevice*); + //Surfaces Enum::SurfaceType::Value top; Enum::SurfaceType::Value front; From 0ac516618a471b82b7ddc0177d822b6cb2284eb5 Mon Sep 17 00:00:00 2001 From: Modnark <66146584+Modnark@users.noreply.github.com> Date: Wed, 12 Oct 2022 13:47:39 -0400 Subject: [PATCH 11/11] Add LightingInstance Still need to work on PropertyGrid for it --- Blocks3D.vcproj | 8 + ThumbnailGeneratorInstance.cpp | 2 +- src/include/Application.h | 4 - src/include/DataModelV2/DataModelInstance.h | 4 +- src/include/DataModelV2/LightingInstance.h | 44 ++++ src/source/Application.cpp | 146 +---------- src/source/DataModelV2/DataModelInstance.cpp | 13 + src/source/DataModelV2/LevelInstance.cpp | 1 + src/source/DataModelV2/LightingInstance.cpp | 260 +++++++++++++++++++ src/source/DataModelV2/PartInstance.cpp | 6 +- 10 files changed, 338 insertions(+), 150 deletions(-) create mode 100644 src/include/DataModelV2/LightingInstance.h create mode 100644 src/source/DataModelV2/LightingInstance.cpp diff --git a/Blocks3D.vcproj b/Blocks3D.vcproj index c123448..5634c0d 100644 --- a/Blocks3D.vcproj +++ b/Blocks3D.vcproj @@ -457,6 +457,10 @@ /> + + @@ -874,6 +878,10 @@ RelativePath=".\src\include\DataModelV2\LevelInstance.h" > + + diff --git a/ThumbnailGeneratorInstance.cpp b/ThumbnailGeneratorInstance.cpp index 209cc76..b2c078f 100644 --- a/ThumbnailGeneratorInstance.cpp +++ b/ThumbnailGeneratorInstance.cpp @@ -39,7 +39,7 @@ std::string ThumbnailGeneratorInstance::click(std::string fileType, int cx, int g_usableApp->resize3DView(cx, cy); if(hideSky) - g_usableApp->toggleSky(); + g_dataModel->getLighting()->suppressSky(true); g_usableApp->onGraphics(rd); rd->screenshotPic(imgBuffer, true, hideSky); diff --git a/src/include/Application.h b/src/include/Application.h index d72fd0f..fc84aeb 100644 --- a/src/include/Application.h +++ b/src/include/Application.h @@ -48,7 +48,6 @@ class Application { // : public GApp { int getMode(); void unSetMode(); - void toggleSky(); CameraController cameraController; UserInput* userInput; PropertyWindow* _propWindow; @@ -56,7 +55,6 @@ class Application { // : public GApp { RenderDevice* getRenderDevice(); void selectInstance(Instance* selectedInstance,PropertyWindow* propWindow); void setMode(int mode); - SkyRef getSky(); void resize3DView(int w, int h); Tool * tool; @@ -68,7 +66,6 @@ class Application { // : public GApp { RenderDevice* renderDevice; //void initGUI(); HWND _hWndMain; - SkyRef sky; bool quit; bool mouseOnScreen; bool rightButtonHolding; @@ -85,7 +82,6 @@ class Application { // : public GApp { GAppSettings _settings; double lightProjX, lightProjY, lightProjNear, lightProjFar; IEBrowser* webBrowser; - bool _hideSky; protected: Stopwatch m_graphicsWatch; Stopwatch m_logicWatch; diff --git a/src/include/DataModelV2/DataModelInstance.h b/src/include/DataModelV2/DataModelInstance.h index bae7bd4..aceaf86 100644 --- a/src/include/DataModelV2/DataModelInstance.h +++ b/src/include/DataModelV2/DataModelInstance.h @@ -9,6 +9,7 @@ #include "ThumbnailGeneratorInstance.h" #include "XplicitNgine/XplicitNgine.h" #include "SoundService.h" +#include "LightingInstance.h" // Libraries #include "rapidxml/rapidxml.hpp" @@ -36,6 +37,7 @@ public: XplicitNgine* getEngine(); ThumbnailGeneratorInstance* getThumbnailGenerator(); SoundService* getSoundService(); + LightingInstance* getLighting(); std::string message; std::string _loadedFileName; @@ -69,7 +71,7 @@ private: ThumbnailGeneratorInstance* thumbnailGenerator; XplicitNgine* xplicitNgine; SoundService* soundService; - + LightingInstance* lightingInstance; bool running; }; diff --git a/src/include/DataModelV2/LightingInstance.h b/src/include/DataModelV2/LightingInstance.h new file mode 100644 index 0000000..588b2ad --- /dev/null +++ b/src/include/DataModelV2/LightingInstance.h @@ -0,0 +1,44 @@ +#pragma once +#include "Instance.h" + +class LightingInstance : + public Instance +{ +public: + LightingInstance(void); + ~LightingInstance(void); + + // Getters + G3D::Color3 getTopAmbient(); + G3D::Color3 getBottomAmbient(); + G3D::Color3 getSpotLight(); + G3D::Color4 getClearColor(); + G3D::SkyRef getSky(); + G3D::LightingParameters getLightingParameters(); + + // Setters + void setTopAmbient(G3D::Color3 newValue); + void setBottomAmbient(G3D::Color3 newValue); + void setSpotLight(G3D::Color3 newValue); + void setClearColor(G3D::Color4 clearColor); + + // Functions + void drawSky(); + void suppressSky(bool doSuppress); + void update(); + void drawEffects(); + void drawOutlines(Vector3 from, Vector3 to, RenderDevice* rd, Vector3 size, Vector3 pos, CoordinateFrame c); + + // Properties + void PropUpdate(LPPROPGRIDITEM &pItem); + std::vector getProperties(); + +private: + G3D::Color3 topAmbient; + G3D::Color3 bottomAmbient; + G3D::Color3 spotLight; + G3D::Color4 clearColor; + G3D::SkyRef sky; + G3D::LightingParameters lighting; + bool _hideSky; +}; diff --git a/src/source/Application.cpp b/src/source/Application.cpp index 0e61e31..9f4818b 100644 --- a/src/source/Application.cpp +++ b/src/source/Application.cpp @@ -71,7 +71,6 @@ Application::Application(HWND parentWindow) : _propWindow(NULL) { //: GApp(setti CreateDirectory(tempPath.c_str(), NULL); _hWndMain = parentWindow; - _hideSky = false; HMODULE hThisInstance = GetModuleHandle(NULL); @@ -296,7 +295,6 @@ void Application::onInit() { void Application::onCleanup() { clearInstances(); - sky->~Sky(); } void Application::onLogic() { @@ -409,90 +407,10 @@ int Application::getMode() return _mode; } - -void Application::drawOutline(Vector3 from, Vector3 to, RenderDevice* rd, LightingParameters lighting, Vector3 size, Vector3 pos, CoordinateFrame c) -{ - rd->disableLighting(); - Color3 outline = Color3::cyan(); - float offsetSize = 0.05F; - //X - Draw::box(c.toWorldSpace(Box(Vector3(from.x - offsetSize, from.y + offsetSize, from.z + offsetSize), Vector3(to.x + offsetSize, from.y - offsetSize, from.z - offsetSize))), rd, outline, Color4::clear()); - Draw::box(c.toWorldSpace(Box(Vector3(from.x - offsetSize, to.y + offsetSize, from.z + offsetSize), Vector3(to.x + offsetSize, to.y - offsetSize, from.z - offsetSize))), rd, outline, Color4::clear()); - Draw::box(c.toWorldSpace(Box(Vector3(from.x - offsetSize, to.y + offsetSize, to.z + offsetSize), Vector3(to.x + offsetSize, to.y - offsetSize, to.z - offsetSize))), rd, outline, Color4::clear()); - Draw::box(c.toWorldSpace(Box(Vector3(from.x - offsetSize, from.y + offsetSize, to.z + offsetSize), Vector3(to.x + offsetSize, from.y - offsetSize, to.z - offsetSize))), rd, outline, Color4::clear()); - //Y - Draw::box(c.toWorldSpace(Box(Vector3(from.x + offsetSize, from.y - offsetSize + 0.1, from.z + offsetSize), Vector3(from.x - offsetSize, to.y + offsetSize - 0.1, from.z - offsetSize))), rd, outline, Color4::clear()); - Draw::box(c.toWorldSpace(Box(Vector3(to.x + offsetSize, from.y - offsetSize + 0.1, from.z + offsetSize), Vector3(to.x - offsetSize, to.y + offsetSize - 0.1, from.z - offsetSize))), rd, outline, Color4::clear()); - Draw::box(c.toWorldSpace(Box(Vector3(to.x + offsetSize, from.y - offsetSize + 0.1, to.z + offsetSize), Vector3(to.x - offsetSize, to.y + offsetSize-0.1, to.z - offsetSize))), rd, outline, Color4::clear()); - Draw::box(c.toWorldSpace(Box(Vector3(from.x + offsetSize, from.y - offsetSize + 0.1, to.z + offsetSize), Vector3(from.x - offsetSize, to.y + offsetSize - 0.1, to.z - offsetSize))), rd, outline, Color4::clear()); - - //Z - Draw::box(c.toWorldSpace(Box(Vector3(from.x + offsetSize, from.y + offsetSize, from.z - offsetSize), Vector3(from.x - offsetSize, from.y - offsetSize, to.z + offsetSize))), rd, outline, Color4::clear()); - Draw::box(c.toWorldSpace(Box(Vector3(from.x + offsetSize, to.y + offsetSize, from.z - offsetSize), Vector3(from.x - offsetSize, to.y - offsetSize, to.z + offsetSize))), rd, outline, Color4::clear()); - Draw::box(c.toWorldSpace(Box(Vector3(to.x + offsetSize, from.y + offsetSize, from.z - offsetSize), Vector3(to.x - offsetSize, from.y - offsetSize, to.z + offsetSize))), rd, outline, Color4::clear()); - Draw::box(c.toWorldSpace(Box(Vector3(to.x + offsetSize, to.y + offsetSize, from.z - offsetSize), Vector3(to.x - offsetSize, to.y - offsetSize, to.z + offsetSize))), rd, outline, Color4::clear()); - - if(_mode == ARROWS) - { - - AABox box; - c.toWorldSpace(Box(from, to)).getBounds(box); - float max = box.high().y - pos.y; - - Draw::arrow(pos, Vector3(0, 1.5+max, 0), rd); - Draw::arrow(pos, Vector3(0, (-1.5)-max, 0), rd); - - max = box.high().x - pos.x; - - Draw::arrow(pos, Vector3(1.5+max, 0, 0), rd); - Draw::arrow(pos, Vector3((-1.5)-max, 0, 0), rd); - - max = box.high().z - pos.z; - - Draw::arrow(pos, Vector3(0, 0, 1.5+max), rd); - Draw::arrow(pos, Vector3(0, 0, (-1.5)-max), rd); - - - - } - else if(_mode == RESIZE) - { - Color3 sphereColor = outline; - Vector3 gamepoint = pos; - Vector3 camerapoint = rd->getCameraToWorldMatrix().translation; - float distance = pow(pow((double)gamepoint.x - (double)camerapoint.x, 2) + pow((double)gamepoint.y - (double)camerapoint.y, 2) + pow((double)gamepoint.z - (double)camerapoint.z, 2), 0.5); - if(distance < 200) - { - - float multiplier = distance * 0.025F/2; - if(multiplier < 0.25F) - multiplier = 0.25F; - Vector3 position = pos + (c.lookVector()*((size.z)+1)); - Draw::sphere(Sphere(position, multiplier), rd, sphereColor, Color4::clear()); - position = pos - (c.lookVector()*((size.z)+1)); - Draw::sphere(Sphere(position, multiplier), rd, sphereColor, Color4::clear()); - - position = pos + (c.rightVector()*((size.x)+1)); - Draw::sphere(Sphere(position, multiplier), rd, sphereColor, Color4::clear()); - position = pos - (c.rightVector()*((size.x)+1)); - Draw::sphere(Sphere(position, multiplier), rd, sphereColor, Color4::clear()); - - position = pos + (c.upVector()*((size.y)+1)); - Draw::sphere(Sphere(position, multiplier), rd, sphereColor, Color4::clear()); - position = pos - (c.upVector()*((size.y)+1)); - Draw::sphere(Sphere(position, multiplier), rd, sphereColor, Color4::clear()); - } - } - rd->enableLighting(); -} - void Application::exitApplication() { } - - - void Application::onGraphics(RenderDevice* rd) { G3D::uint8 num = 0; @@ -521,57 +439,11 @@ void Application::onGraphics(RenderDevice* rd) { ScreenToClient(_hWndMain, &mousepos); } - LightingParameters lighting(G3D::toSeconds(2, 00, 00, PM)); - lighting.ambient = Color3(0.6F,0.6F,0.6F); - renderDevice->setProjectionAndCameraMatrix(*cameraController.getCamera()); + renderDevice->setProjectionAndCameraMatrix(*cameraController.getCamera()); - // TODO: stick this into its own rendering thing - if(!_hideSky) { - renderDevice->clear(sky.isNull(), true, true); - if (sky.notNull()) sky->render(renderDevice, lighting); - } else { - rd->setColorClearValue(Color4(0.0f, 0.0f, 0.0f, 0.0f)); - renderDevice->clear(true, true, true); - toggleSky(); - } - - // Setup lighting - renderDevice->enableLighting(); + // Moved a lot of code to lighting + g_dataModel->getLighting()->update(); - renderDevice->setShadeMode(RenderDevice::SHADE_SMOOTH); - renderDevice->setAmbientLightColor(Color3(1,1,1)); - - renderDevice->setLight(0, GLight::directional(lighting.lightDirection, lighting.lightColor, true, true)); - renderDevice->setAmbientLightColor(lighting.ambient); - - rd->beforePrimitive(); - CoordinateFrame forDraw = rd->getObjectToWorldMatrix(); - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - glEnableClientState(GL_NORMAL_ARRAY); - _dataModel->getWorkspace()->render(rd); - _dataModel->getWorkspace()->renderName(rd); - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - rd->setObjectToWorldMatrix(forDraw); - rd->afterPrimitive(); - - for(size_t i = 0; i < _dataModel->getSelectionService()->getSelection().size(); i++) - { - if(PartInstance* part = dynamic_cast(g_dataModel->getSelectionService()->getSelection()[i])) - { - Vector3 size = part->getSize(); - Vector3 pos = part->getPosition(); - drawOutline(Vector3(0+size.x/2, 0+size.y/2, 0+size.z/2) ,Vector3(0-size.x/2,0-size.y/2,0-size.z/2), rd, lighting, Vector3(size.x/2, size.y/2, size.z/2), Vector3(pos.x, pos.y, pos.z), part->getCFrame()); - } - } - - renderDevice->disableLighting(); - - if (sky.notNull()) { - sky->renderLensFlare(renderDevice, lighting); - } renderDevice->push2D(); _dataModel->getGuiRoot()->renderGUI(renderDevice, m_graphicsWatch.FPS()); renderDevice->pop2D(); @@ -655,7 +527,6 @@ void Application::run() { cameraSound = GetFileInPath("/content/sounds/SWITCH3.wav"); clickSound = GetFileInPath("/content/sounds/switch.wav"); dingSound = GetFileInPath("/content/sounds/electronicpingshort.wav"); - sky = Sky::create(NULL, ExePath() + "/content/sky/"); RealTime now=0, lastTime=0; double simTimeRate = 1.0f; float fps=30.0f; @@ -734,17 +605,6 @@ void Application::resizeWithParent(HWND parentWindow) } -// These should be moved into a "Lighting" class -G3D::SkyRef Application::getSky() -{ - return sky; -} - -void Application::toggleSky() -{ - _hideSky = !_hideSky; -} - void Application::resize3DView(int w, int h) { Rect2D newViewport = Rect2D::xywh(0, 0, w, h); diff --git a/src/source/DataModelV2/DataModelInstance.cpp b/src/source/DataModelV2/DataModelInstance.cpp index 7eef1f9..79f0c84 100644 --- a/src/source/DataModelV2/DataModelInstance.cpp +++ b/src/source/DataModelV2/DataModelInstance.cpp @@ -1,8 +1,12 @@ #include + +// Instances #include "DataModelV2/GuiRootInstance.h" #include "DataModelV2/ToggleImageButtonInstance.h" #include "DataModelV2/DataModelInstance.h" #include "DataModelV2/ThumbnailGeneratorInstance.h" +#include "DataModelV2/LightingInstance.h" + #include #include #include @@ -23,6 +27,7 @@ DataModelInstance::DataModelInstance(void) level = new LevelInstance(); thumbnailGenerator = new ThumbnailGeneratorInstance(); soundService = new SoundService(); + lightingInstance = new LightingInstance(); selectionService = new SelectionService(); selectionService->setPropertyWindow(g_usableApp->_propWindow); @@ -30,9 +35,12 @@ DataModelInstance::DataModelInstance(void) showMessage = false; canDelete = false; _modY=0; + + // Parent stuff workspace->setParent(this); level->setParent(this); soundService->setParent(this); + lightingInstance->setParent(this); _loadedFileName="..//skooter.rbxm"; listicon = 5; @@ -662,4 +670,9 @@ ThumbnailGeneratorInstance* DataModelInstance::getThumbnailGenerator() SoundService* DataModelInstance::getSoundService() { return soundService; +} + +LightingInstance* DataModelInstance::getLighting() +{ + return lightingInstance; } \ No newline at end of file diff --git a/src/source/DataModelV2/LevelInstance.cpp b/src/source/DataModelV2/LevelInstance.cpp index 9aea060..53c20a4 100644 --- a/src/source/DataModelV2/LevelInstance.cpp +++ b/src/source/DataModelV2/LevelInstance.cpp @@ -140,6 +140,7 @@ std::vector LevelInstance::getProperties() )); return properties; } + void LevelInstance::PropUpdate(LPPROPGRIDITEM &pItem) { if(strcmp(pItem->lpszPropName, "InitialTimerValue") == 0) diff --git a/src/source/DataModelV2/LightingInstance.cpp b/src/source/DataModelV2/LightingInstance.cpp new file mode 100644 index 0000000..489ff9a --- /dev/null +++ b/src/source/DataModelV2/LightingInstance.cpp @@ -0,0 +1,260 @@ +#include "DataModelV2/LightingInstance.h" +#include "Application.h" +#include "Globals.h" +#include "StringFunctions.h" +#include "Listener/ModeSelectionListener.h" + +LightingInstance::LightingInstance(void) +{ + Instance::Instance(); + name = "Lighting"; + className = "Lighting"; + listicon = 10; + canDelete = false; + + _hideSky = false; + + lighting.setTime(G3D::toSeconds(2, 00, 00, PM)); + + // Maybe this is Top and Bottom Ambient? + lighting.ambient = Color3(0.5F, 0.5F, 0.5F); + lighting.lightColor = Color3(0.8F, 0.8F, 0.8F); + + sky = Sky::create(NULL, ExePath() + "/content/sky/"); + clearColor = Color4(0.0F, 0.0F, 0.0F, 0.0F); +} + +LightingInstance::~LightingInstance(void) +{ + sky->~Sky(); +} + +// Getters +G3D::SkyRef LightingInstance::getSky() +{ + return sky; +} + +G3D::LightingParameters LightingInstance::getLightingParameters() +{ + return lighting; +} + +std::vector LightingInstance::getProperties() +{ + std::vector properties = Instance::getProperties(); + + properties.push_back(createPGI("Appearance", + "TopAmbient", + "The color of the TopAmbient for 3D Objects", + RGB((topAmbient.r*255),(topAmbient.g*255),(topAmbient.b*255)), + PIT_COLOR + )); + + properties.push_back(createPGI("Appearance", + "BottomAmbient", + "The color of the BottomAmbient for 3D Objects", + RGB((bottomAmbient.r*255),(bottomAmbient.g*255),(bottomAmbient.b*255)), + PIT_COLOR + )); + + properties.push_back(createPGI("Appearance", + "SpotLight", + "The color of the SpotLight", + RGB((spotLight.r*255),(spotLight.g*255),(spotLight.b*255)), + PIT_COLOR + )); + + properties.push_back(createPGI("Appearance", + "ClearColor", + "", + RGB((clearColor.r*255),(clearColor.g*255),(clearColor.b*255)), + PIT_COLOR + )); + return properties; +} + + +void LightingInstance::PropUpdate(LPPROPGRIDITEM &item) +{ + if(strcmp(item->lpszPropName, "TopAmbient") == 0) + { + topAmbient = Color3( + GetRValue(item->lpCurValue)/255.0F, + GetGValue(item->lpCurValue)/255.0F, + GetBValue(item->lpCurValue)/255.0F + ); + } + if(strcmp(item->lpszPropName, "BottomAmbient") == 0) + { + bottomAmbient = Color3( + GetRValue(item->lpCurValue)/255.0F, + GetGValue(item->lpCurValue)/255.0F, + GetBValue(item->lpCurValue)/255.0F + ); + } + if(strcmp(item->lpszPropName, "SpotLight") == 0) + { + spotLight = Color3( + GetRValue(item->lpCurValue)/255.0F, + GetGValue(item->lpCurValue)/255.0F, + GetBValue(item->lpCurValue)/255.0F + ); + } + if(strcmp(item->lpszPropName, "ClearColor") == 0) + { + clearColor = Color3( + GetRValue(item->lpCurValue)/255.0F, + GetGValue(item->lpCurValue)/255.0F, + GetBValue(item->lpCurValue)/255.0F + ); + } + + else + Instance::PropUpdate(item); +} + + +// Functions +void LightingInstance::suppressSky(bool doSuppress) +{ + _hideSky = doSuppress; +} + +void LightingInstance::update() +{ + RenderDevice* rd = g_usableApp->getRenderDevice(); + + + if(!_hideSky) { + rd->clear(sky.isNull(), true, true); + if (sky.notNull()) sky->render(rd, lighting); + } else { + rd->setColorClearValue(clearColor); + rd->clear(true, true, true); + suppressSky(false); + } + + // Setup lighting + rd->enableLighting(); + + rd->setShadeMode(RenderDevice::SHADE_SMOOTH); + rd->setAmbientLightColor(Color3(1,1,1)); + + rd->setLight(0, GLight::directional(lighting.lightDirection, lighting.lightColor, true, true)); + rd->setAmbientLightColor(lighting.ambient); + + rd->beforePrimitive(); + CoordinateFrame forDraw = rd->getObjectToWorldMatrix(); + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + glEnableClientState(GL_NORMAL_ARRAY); + g_dataModel->getWorkspace()->render(rd); + g_dataModel->getWorkspace()->renderName(rd); + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + rd->setObjectToWorldMatrix(forDraw); + rd->afterPrimitive(); + + // Draw outlines + for(size_t i = 0; i < g_dataModel->getSelectionService()->getSelection().size(); i++) + { + if(PartInstance* part = dynamic_cast(g_dataModel->getSelectionService()->getSelection()[i])) + { + Vector3 size = part->getSize(); + Vector3 pos = part->getPosition(); + drawOutlines( + Vector3(0+size.x/2, 0+size.y/2, 0+size.z/2) , + Vector3(0-size.x/2,0-size.y/2,0-size.z/2), + rd, + Vector3(size.x/2, size.y/2, size.z/2), + Vector3(pos.x, pos.y, pos.z), + part->getCFrame() + ); + } + } + + rd->disableLighting(); + + drawEffects(); +} + +void LightingInstance::drawEffects() +{ + RenderDevice* rd = g_usableApp->getRenderDevice(); + if (sky.notNull()) { + sky->renderLensFlare(rd, lighting); + } +} + +void LightingInstance::drawOutlines(Vector3 from, Vector3 to, RenderDevice* rd, Vector3 size, Vector3 pos, CoordinateFrame c) +{ + Color3 outline = Color3::cyan(); + float offsetSize = 0.05F; + + //X + Draw::box(c.toWorldSpace(Box(Vector3(from.x - offsetSize, from.y + offsetSize, from.z + offsetSize), Vector3(to.x + offsetSize, from.y - offsetSize, from.z - offsetSize))), rd, outline, Color4::clear()); + Draw::box(c.toWorldSpace(Box(Vector3(from.x - offsetSize, to.y + offsetSize, from.z + offsetSize), Vector3(to.x + offsetSize, to.y - offsetSize, from.z - offsetSize))), rd, outline, Color4::clear()); + Draw::box(c.toWorldSpace(Box(Vector3(from.x - offsetSize, to.y + offsetSize, to.z + offsetSize), Vector3(to.x + offsetSize, to.y - offsetSize, to.z - offsetSize))), rd, outline, Color4::clear()); + Draw::box(c.toWorldSpace(Box(Vector3(from.x - offsetSize, from.y + offsetSize, to.z + offsetSize), Vector3(to.x + offsetSize, from.y - offsetSize, to.z - offsetSize))), rd, outline, Color4::clear()); + //Y + Draw::box(c.toWorldSpace(Box(Vector3(from.x + offsetSize, from.y - offsetSize + 0.1, from.z + offsetSize), Vector3(from.x - offsetSize, to.y + offsetSize - 0.1, from.z - offsetSize))), rd, outline, Color4::clear()); + Draw::box(c.toWorldSpace(Box(Vector3(to.x + offsetSize, from.y - offsetSize + 0.1, from.z + offsetSize), Vector3(to.x - offsetSize, to.y + offsetSize - 0.1, from.z - offsetSize))), rd, outline, Color4::clear()); + Draw::box(c.toWorldSpace(Box(Vector3(to.x + offsetSize, from.y - offsetSize + 0.1, to.z + offsetSize), Vector3(to.x - offsetSize, to.y + offsetSize-0.1, to.z - offsetSize))), rd, outline, Color4::clear()); + Draw::box(c.toWorldSpace(Box(Vector3(from.x + offsetSize, from.y - offsetSize + 0.1, to.z + offsetSize), Vector3(from.x - offsetSize, to.y + offsetSize - 0.1, to.z - offsetSize))), rd, outline, Color4::clear()); + + //Z + Draw::box(c.toWorldSpace(Box(Vector3(from.x + offsetSize, from.y + offsetSize, from.z - offsetSize), Vector3(from.x - offsetSize, from.y - offsetSize, to.z + offsetSize))), rd, outline, Color4::clear()); + Draw::box(c.toWorldSpace(Box(Vector3(from.x + offsetSize, to.y + offsetSize, from.z - offsetSize), Vector3(from.x - offsetSize, to.y - offsetSize, to.z + offsetSize))), rd, outline, Color4::clear()); + Draw::box(c.toWorldSpace(Box(Vector3(to.x + offsetSize, from.y + offsetSize, from.z - offsetSize), Vector3(to.x - offsetSize, from.y - offsetSize, to.z + offsetSize))), rd, outline, Color4::clear()); + Draw::box(c.toWorldSpace(Box(Vector3(to.x + offsetSize, to.y + offsetSize, from.z - offsetSize), Vector3(to.x - offsetSize, to.y - offsetSize, to.z + offsetSize))), rd, outline, Color4::clear()); + + if(g_usableApp->getMode() == ARROWS) + { + AABox box; + c.toWorldSpace(Box(from, to)).getBounds(box); + float max = box.high().y - pos.y; + + Draw::arrow(pos, Vector3(0, 1.5+max, 0), rd); + Draw::arrow(pos, Vector3(0, (-1.5)-max, 0), rd); + + max = box.high().x - pos.x; + + Draw::arrow(pos, Vector3(1.5+max, 0, 0), rd); + Draw::arrow(pos, Vector3((-1.5)-max, 0, 0), rd); + + max = box.high().z - pos.z; + + Draw::arrow(pos, Vector3(0, 0, 1.5+max), rd); + Draw::arrow(pos, Vector3(0, 0, (-1.5)-max), rd); + } + else if(g_usableApp->getMode() == RESIZE) + { + Color3 sphereColor = outline; + Vector3 gamepoint = pos; + Vector3 camerapoint = rd->getCameraToWorldMatrix().translation; + float distance = pow(pow((double)gamepoint.x - (double)camerapoint.x, 2) + pow((double)gamepoint.y - (double)camerapoint.y, 2) + pow((double)gamepoint.z - (double)camerapoint.z, 2), 0.5); + if(distance < 200) + { + + float multiplier = distance * 0.025F/2; + if(multiplier < 0.25F) + multiplier = 0.25F; + Vector3 position = pos + (c.lookVector()*((size.z)+1)); + Draw::sphere(Sphere(position, multiplier), rd, sphereColor, Color4::clear()); + position = pos - (c.lookVector()*((size.z)+1)); + Draw::sphere(Sphere(position, multiplier), rd, sphereColor, Color4::clear()); + + position = pos + (c.rightVector()*((size.x)+1)); + Draw::sphere(Sphere(position, multiplier), rd, sphereColor, Color4::clear()); + position = pos - (c.rightVector()*((size.x)+1)); + Draw::sphere(Sphere(position, multiplier), rd, sphereColor, Color4::clear()); + + position = pos + (c.upVector()*((size.y)+1)); + Draw::sphere(Sphere(position, multiplier), rd, sphereColor, Color4::clear()); + position = pos - (c.upVector()*((size.y)+1)); + Draw::sphere(Sphere(position, multiplier), rd, sphereColor, Color4::clear()); + } + } +} \ No newline at end of file diff --git a/src/source/DataModelV2/PartInstance.cpp b/src/source/DataModelV2/PartInstance.cpp index df70ce1..8463f2b 100644 --- a/src/source/DataModelV2/PartInstance.cpp +++ b/src/source/DataModelV2/PartInstance.cpp @@ -593,7 +593,11 @@ void PartInstance::PropUpdate(LPPROPGRIDITEM &item) setChanged(); if(strcmp(item->lpszPropName, "Color3") == 0) { - color = Color3(GetRValue(item->lpCurValue)/255.0F,GetGValue(item->lpCurValue)/255.0F,GetBValue(item->lpCurValue)/255.0F); + color = Color3( + GetRValue(item->lpCurValue)/255.0F, + GetGValue(item->lpCurValue)/255.0F, + GetBValue(item->lpCurValue)/255.0F + ); } else if(strcmp(item->lpszPropName, "Anchored") == 0) {