diff --git a/Content/RNR/materials/partinstanced.material b/Content/RNR/materials/partinstanced.material index c74c162..7ec2dcb 100644 --- a/Content/RNR/materials/partinstanced.material +++ b/Content/RNR/materials/partinstanced.material @@ -16,6 +16,7 @@ material materials/partinstanced rtshader_system { + transform_stage instanced lighting_stage per_pixel } } diff --git a/Content/RNR/textures/studio/icons/Player.png b/Content/RNR/textures/studio/icons/Player.png new file mode 100644 index 0000000..f3ae274 Binary files /dev/null and b/Content/RNR/textures/studio/icons/Player.png differ diff --git a/Content/RNR/textures/studio/icons/Players.png b/Content/RNR/textures/studio/icons/Players.png new file mode 100644 index 0000000..d22f336 Binary files /dev/null and b/Content/RNR/textures/studio/icons/Players.png differ diff --git a/Content/RNR/textures/studio/icons/play.png b/Content/RNR/textures/studio/icons/play.png new file mode 100644 index 0000000..66fd4b7 Binary files /dev/null and b/Content/RNR/textures/studio/icons/play.png differ diff --git a/Projects/Client/Common/Source/OgreWidget.cpp b/Projects/Client/Common/Source/OgreWidget.cpp index 680bf72..911fa75 100644 --- a/Projects/Client/Common/Source/OgreWidget.cpp +++ b/Projects/Client/Common/Source/OgreWidget.cpp @@ -59,9 +59,10 @@ namespace RNR ogreCamera = ogreSceneManager->createCamera("myCam"); ogreCamera->setNearClipDistance(0.1); // specific to this sample - ogreCamera->setFarClipDistance(5000.f); + ogreCamera->setFarClipDistance(1000.f); ogreCamera->setAutoAspectRatio(true); ogreCamera->setFOVy(Ogre::Degree(70.f)); + ogreCamera->setUseRenderingDistance(true); camNode->attachObject(ogreCamera); ogreViewport = ogreWindow->addViewport(ogreCamera); diff --git a/Projects/Client/Studio/Header/MainWindow.hpp b/Projects/Client/Studio/Header/MainWindow.hpp index e437512..abaf421 100644 --- a/Projects/Client/Studio/Header/MainWindow.hpp +++ b/Projects/Client/Studio/Header/MainWindow.hpp @@ -39,6 +39,7 @@ class MainWindow : public QMainWindow void selectInstance(QTreeWidgetItem *item, int column); void run(); void pause(); + void playSolo(); void dbg_pointlight(); protected: diff --git a/Projects/Client/Studio/Source/MainWindow.cpp b/Projects/Client/Studio/Source/MainWindow.cpp index 83aad9d..41163b6 100644 --- a/Projects/Client/Studio/Source/MainWindow.cpp +++ b/Projects/Client/Studio/Source/MainWindow.cpp @@ -1,7 +1,10 @@ #include #include #include +#include +#include #include +#include MainWindow::MainWindow() { @@ -111,6 +114,7 @@ void MainWindow::createToolbar() QAction* run_action = toolbar->addAction(QIcon("content/textures/studio/icons/run.png"), "", this, SLOT(run())); QAction* pause_action = toolbar->addAction(QIcon("content/textures/studio/icons/pause.png"), "", this, SLOT(pause())); + QAction* playSolo_action = toolbar->addAction(QIcon("content/textures/studio/icons/play.png"), "", this, SLOT(playSolo())); #ifndef NDEBUG toolbar->addSeparator(); @@ -128,9 +132,35 @@ void MainWindow::pause() this->ogreWidget->world->getRunService()->pause(); } +void MainWindow::playSolo() +{ + this->ogreWidget->world->getRunService()->run(); + + RNR::Players* players = (RNR::Players*)this->ogreWidget->world->getDatamodel()->getService("Players"); + RNR::Player* player = players->createLocalPlayer(0); + player->setName(QInputDialog::getText(this, "Player Name", "Enter your player name").toLocal8Bit().data()); + + updateTree(ogreWidget->world->getDatamodel()); +} + void MainWindow::dbg_pointlight() { - + if(!ogreWidget->selectedInstance) + { + QMessageBox::about(this, "selectedInstance = NULL", "Please select an instance in the explorer"); + return; + } + + printf("MainWindow::dbg_pointlight: inserting Light\n"); + RNR::Light* dbg_light = new RNR::Light(); + dbg_light->setParent(ogreWidget->selectedInstance); + + double r = QInputDialog::getDouble(this, "Red", "Set red component [0.0-1.0]", 1.0, 0.0, 1.0, 2); + double g = QInputDialog::getDouble(this, "Green", "Set green component [0.0-1.0]", 1.0, 0.0, 1.0, 2); + double b = QInputDialog::getDouble(this, "Blue", "Set blue component [0.0-1.0]", 1.0, 0.0, 1.0, 2); + dbg_light->setColor(Ogre::Vector3(r,g,b)); + + updateTree(ogreWidget->world->getDatamodel()); } void MainWindow::closeEvent(QCloseEvent* event) diff --git a/Projects/Client/Studio/Source/PropertyViewer.cpp b/Projects/Client/Studio/Source/PropertyViewer.cpp index 2f09d6d..691da6a 100644 --- a/Projects/Client/Studio/Source/PropertyViewer.cpp +++ b/Projects/Client/Studio/Source/PropertyViewer.cpp @@ -3,6 +3,8 @@ #include #include +#include + PropertyViewer::PropertyViewer() : QWidget() { prop_table = new QTableWidget(); @@ -88,6 +90,17 @@ void PropertyViewer::view(RNR::Instance* instance) new_property_itemval->setData(Qt::DecorationRole, QPixmap::fromImage(image)); } break; + case RNR::PROPERTY_BRICKCOLOR: + { + int brickcolor = *(int*)property.rawGetter(); + Ogre::Vector3 color = RNR::BrickColor::color(brickcolor); + new_property_itemval->setBackground(QBrush(QColor( + (int)floorf(color.x * 255), + (int)floorf(color.y * 255), + (int)floorf(color.z * 255) + ))); + } + break; } prop_table->setItem(property_count, 0, new_property_item); diff --git a/Projects/Engine/CMakeLists.txt b/Projects/Engine/CMakeLists.txt index 09cd9a0..78f0797 100644 --- a/Projects/Engine/CMakeLists.txt +++ b/Projects/Engine/CMakeLists.txt @@ -4,6 +4,8 @@ add_library(Engine STATIC Header/Helpers/XML.hpp Header/Helpers/NormalId.hpp Header/App/Script/ReflectionProperty.hpp + Header/App/Script/Script.hpp + Header/App/Script/ScriptContext.hpp Header/App/GUI/GuiBase3d.hpp Header/App/GUI/InstanceAdornment.hpp Header/App/GUI/SelectionBox.hpp @@ -26,6 +28,8 @@ add_library(Engine STATIC Header/App/BrickColor.hpp Header/App/InputManager.hpp Header/Network/GUID.hpp + Header/Network/Player.hpp + Header/Network/Players.hpp Header/Rendering/Adorn.hpp Source/Helpers/Name.cpp @@ -33,6 +37,7 @@ add_library(Engine STATIC Source/Helpers/XML.cpp Source/Helpers/NormalId.cpp Source/App/Script/ReflectionProperty.cpp + Source/App/Script/Script.cpp Source/App/GUI/GuiBase3d.cpp Source/App/GUI/InstanceAdornment.cpp Source/App/GUI/SelectionBox.cpp @@ -55,6 +60,8 @@ add_library(Engine STATIC Source/App/InputManager.cpp Source/App/V8/World/World.cpp Source/Network/GUID.cpp + Source/Network/Player.cpp + Source/Network/Players.cpp Source/Rendering/Adorn.cpp ) diff --git a/Projects/Engine/Header/App/BrickColor.hpp b/Projects/Engine/Header/App/BrickColor.hpp index 2dfe81e..d7ae92b 100644 --- a/Projects/Engine/Header/App/BrickColor.hpp +++ b/Projects/Engine/Header/App/BrickColor.hpp @@ -18,6 +18,7 @@ namespace RNR BrickColor(int color_id, std::string name, Ogre::Vector3 color); static Ogre::Vector3 color(int brickcolor); static bool valid(int brickcolor); + static std::string name(int brickcolor); static Ogre::MaterialPtr material(int brickcolor); }; } \ No newline at end of file diff --git a/Projects/Engine/Header/App/GUI/TopMenuBar.hpp b/Projects/Engine/Header/App/GUI/TopMenuBar.hpp index 8f3f10c..12734fd 100644 --- a/Projects/Engine/Header/App/GUI/TopMenuBar.hpp +++ b/Projects/Engine/Header/App/GUI/TopMenuBar.hpp @@ -1,12 +1,26 @@ #pragma once #include +#include +#include +#include +#include +#include namespace RNR { + class World; + class TopMenuBar { + Ogre::TextAreaOverlayElement* m_debugText; + Ogre::TextAreaOverlayElement* m_playerList; + Ogre::OverlayContainer* m_playerPanel; + Ogre::OverlayManager* m_overlayManager; + World* m_world; public: - TopMenuBar(); + TopMenuBar(World* world); + + void frame(); }; } \ No newline at end of file diff --git a/Projects/Engine/Header/App/Script/ReflectionProperty.hpp b/Projects/Engine/Header/App/Script/ReflectionProperty.hpp index 56d2231..1f5fbb9 100644 --- a/Projects/Engine/Header/App/Script/ReflectionProperty.hpp +++ b/Projects/Engine/Header/App/Script/ReflectionProperty.hpp @@ -41,6 +41,7 @@ namespace RNR PROPERTY_CFRAME, PROPERTY_INSTANCE, PROPERTY_FLOAT, + PROPERTY_BRICKCOLOR, }; class ReflectionProperty diff --git a/Projects/Engine/Header/App/Script/ScriptContext.hpp b/Projects/Engine/Header/App/Script/ScriptContext.hpp new file mode 100644 index 0000000..8411fbf --- /dev/null +++ b/Projects/Engine/Header/App/Script/ScriptContext.hpp @@ -0,0 +1,9 @@ +#pragma once + +namespace RNR +{ + class ScriptContext + { + + }; +} \ No newline at end of file diff --git a/Projects/Engine/Header/App/V8/DataModel/Light.hpp b/Projects/Engine/Header/App/V8/DataModel/Light.hpp index f85bfb2..e4c591b 100644 --- a/Projects/Engine/Header/App/V8/DataModel/Light.hpp +++ b/Projects/Engine/Header/App/V8/DataModel/Light.hpp @@ -12,5 +12,16 @@ namespace RNR bool m_shadows; public: Light(); + + virtual void setupLight(Ogre::Light* light); + virtual void onSetParent(RNR::Instance* newParent); + virtual std::string getClassName() { return std::string("Light"); } + + void setColor(Ogre::Vector3 color) { m_color = color; setupLight((Ogre::Light*)getObject()); } + Ogre::Vector3 getColor() { return m_color; } + void setEnabled(bool enabled) { m_enabled = enabled; setupLight((Ogre::Light*)getObject()); } + bool getEnabled() { return m_enabled; } + void setShadows(bool shadows) { m_shadows = shadows; setupLight((Ogre::Light*)getObject()); } + bool getShadows() { return m_shadows; } }; } \ No newline at end of file diff --git a/Projects/Engine/Header/App/V8/DataModel/PartInstance.hpp b/Projects/Engine/Header/App/V8/DataModel/PartInstance.hpp index c88c466..ca1657d 100644 --- a/Projects/Engine/Header/App/V8/DataModel/PartInstance.hpp +++ b/Projects/Engine/Header/App/V8/DataModel/PartInstance.hpp @@ -11,6 +11,8 @@ namespace RNR { protected: int m_brickColor; + float m_transparency; + float m_reflectance; Ogre::Matrix4 m_matrix; Ogre::Vector3 m_position; Ogre::Vector3 m_size; @@ -28,6 +30,13 @@ namespace RNR Ogre::Vector3 getSize() { return m_size; } Ogre::Vector4 getColor() { return m_color; } + void setReflectance(float reflectance) { m_reflectance = reflectance; } + float getReflectance() { return m_reflectance; } + void setTransparency(float transparency) { m_transparency = transparency; } + float getTransparency() { return m_transparency; } + + Ogre::Vector3 getOgreCenter() { return m_position + (m_size / 2.f); } + void setBrickColor(int brickcolor) { m_brickColor = brickcolor; } int getBrickColor() { return m_brickColor; } }; diff --git a/Projects/Engine/Header/App/V8/DataModel/Workspace.hpp b/Projects/Engine/Header/App/V8/DataModel/Workspace.hpp index bc19c8d..792e7ab 100644 --- a/Projects/Engine/Header/App/V8/DataModel/Workspace.hpp +++ b/Projects/Engine/Header/App/V8/DataModel/Workspace.hpp @@ -11,26 +11,38 @@ namespace RNR { class Camera; + enum WorkspaceBatchingMode + { + BATCH_INSTANCED, + BATCH_STATIC_GEOMETRY, + }; + class Workspace : public ModelInstance { + friend class TopMenuBar; public: Workspace(); virtual std::string getClassName() { return "Workspace"; } - virtual void onChildAdded(RNR::Instance* childAdded); - virtual void onChildRemoved(RNR::Instance* childRemoved); + virtual void onDescendantAdded(RNR::Instance* childAdded); + virtual void onDescendantRemoved(RNR::Instance* childRemoved); void buildGeom(); Camera* getCurrentCamera() const; void setCurrentCamera(Camera *value); + void setDirty() { m_geomDirty = true; } private: + enum WorkspaceBatchingMode m_batchMode; + virtual void addProperties(std::vector& properties); virtual void deserializeProperty(char* prop_name, pugi::xml_node prop); + void buildGeomInstance(Instance* instance); bool m_geomDirty; Ogre::StaticGeometry* m_geom; + Ogre::InstanceManager* m_instanceManager; Ogre::SceneNode* m_worldspawn; Ogre::Entity* m_partEntity; diff --git a/Projects/Engine/Header/App/V8/Tree/Instance.hpp b/Projects/Engine/Header/App/V8/Tree/Instance.hpp index e1cb17f..23f10c6 100644 --- a/Projects/Engine/Header/App/V8/Tree/Instance.hpp +++ b/Projects/Engine/Header/App/V8/Tree/Instance.hpp @@ -30,6 +30,9 @@ namespace RNR RNR::Instance* m_parent; std::vector m_children; bool m_archivable; + + void descendantAddedChildren(Instance* p, Instance* c); + void descendantRemovedChildren(Instance* p, Instance* c); public: Instance(); @@ -69,6 +72,9 @@ namespace RNR int numChildren() { return this->m_children.size(); }; virtual void onChildAdded(RNR::Instance* childAdded); + virtual void onDescendantAdded(RNR::Instance* descendantAdded); // make sure this is called in any derived versions of this virtual void onChildRemoved(RNR::Instance* childRemoved); + virtual void onDescendantRemoved(RNR::Instance* descendantRemoved); // make sure this is called in any derived versions of this + virtual void onSetParent(RNR::Instance* newParent); }; } \ No newline at end of file diff --git a/Projects/Engine/Header/App/V8/World/World.hpp b/Projects/Engine/Header/App/V8/World/World.hpp index 4c2da01..ff2e87f 100644 --- a/Projects/Engine/Header/App/V8/World/World.hpp +++ b/Projects/Engine/Header/App/V8/World/World.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -18,6 +19,7 @@ namespace RNR struct WorldUndeserialized { Instance* instance; + Instance* parent; pugi::xml_node node; }; @@ -29,6 +31,7 @@ namespace RNR DataModel* m_datamodel; Workspace* m_workspace; RunService* m_runService; + Players* m_players; Ogre::Root* m_ogreRoot; Ogre::SceneManager* m_ogreSceneManager; TopMenuBar* m_tmb; diff --git a/Projects/Engine/Header/Network/Player.hpp b/Projects/Engine/Header/Network/Player.hpp new file mode 100644 index 0000000..6354492 --- /dev/null +++ b/Projects/Engine/Header/Network/Player.hpp @@ -0,0 +1,19 @@ +#pragma once +#include +#include + +namespace RNR +{ + class Player : public Instance + { + ModelInstance* m_character; + int m_userId; + public: + Player(); + + ModelInstance* getCharacter() { return m_character; } + void setCharacter(ModelInstance* model) { m_character = model; } + virtual std::string getClassName() { return "Player"; } + virtual void addProperties(std::vector& properties); + }; +} \ No newline at end of file diff --git a/Projects/Engine/Header/Network/Players.hpp b/Projects/Engine/Header/Network/Players.hpp new file mode 100644 index 0000000..1539efa --- /dev/null +++ b/Projects/Engine/Header/Network/Players.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include +#include + +namespace RNR +{ + class Players : public Instance + { + private: + Player* m_localPlayer; + public: + Players(); + + virtual std::string getClassName() { return "Players"; } + + Player* getLocalPlayer() { return m_localPlayer; }; + Player* createLocalPlayer(int userId); + virtual void addProperties(std::vector& properties); + }; +} \ No newline at end of file diff --git a/Projects/Engine/Source/App/BrickColor.cpp b/Projects/Engine/Source/App/BrickColor.cpp index 870422a..b8b3b4f 100644 --- a/Projects/Engine/Source/App/BrickColor.cpp +++ b/Projects/Engine/Source/App/BrickColor.cpp @@ -151,4 +151,16 @@ namespace RNR } return false; } + + std::string BrickColor::name(int brickcolor) + { + for(int i = 0; i < sizeof(brickcolors) / sizeof(BrickColor); i++) + { + if(brickcolors[i].color_id == brickcolor) + { + return brickcolors[i].color_name; + } + } + return brickcolors[0].color_name; + } } \ No newline at end of file diff --git a/Projects/Engine/Source/App/GUI/TopMenuBar.cpp b/Projects/Engine/Source/App/GUI/TopMenuBar.cpp index daf8853..59164a8 100644 --- a/Projects/Engine/Source/App/GUI/TopMenuBar.cpp +++ b/Projects/Engine/Source/App/GUI/TopMenuBar.cpp @@ -1,44 +1,152 @@ #include -#include -#include -#include -#include -#include +#include namespace RNR { - TopMenuBar::TopMenuBar() + TopMenuBar::TopMenuBar(World* world) { - Ogre::OverlayManager* overlayManager = Ogre::OverlayManager::getSingletonPtr(); + m_world = world; + + m_overlayManager = Ogre::OverlayManager::getSingletonPtr(); Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().create("Background", "General"); - material->getTechnique(0)->getPass(0)->createTextureUnitState("placeholder.png"); + material->getTechnique(0)->getPass(0)->createTextureUnitState("textures/placeholder.png"); + material->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setColourOperationEx(Ogre::LBX_MODULATE, Ogre::LBS_MANUAL, Ogre::LBS_CURRENT, Ogre::ColourValue(0.5, 0.5, 0.5)); material->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setAlphaOperation(Ogre::LBX_MODULATE, Ogre::LBS_MANUAL, Ogre::LBS_CURRENT, 0.5f); - material->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setColourOperationEx(Ogre::LBX_MODULATE, Ogre::LBS_MANUAL, Ogre::LBS_CURRENT, Ogre::ColourValue(1.0, 1.0, 1.0)); material->getTechnique(0)->getPass(0)->setDepthCheckEnabled(false); material->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false); material->getTechnique(0)->getPass(0)->setLightingEnabled(false); + material->getTechnique(0)->getPass(0)->setSceneBlending(Ogre::SceneBlendType::SBT_TRANSPARENT_COLOUR); - Ogre::OverlayContainer* panel = static_cast(overlayManager->createOverlayElement("Panel", "PanelName")); + Ogre::OverlayContainer* panel = static_cast(m_overlayManager->createOverlayElement("Panel", "TopMenuBarPanel")); panel->setMetricsMode(Ogre::GMM_PIXELS); panel->setPosition(0,0); - panel->setDimensions(320, 24); + panel->setDimensions(128 * 5, 20); panel->setMaterial(material); - Ogre::TextAreaOverlayElement* textArea = static_cast(overlayManager->createOverlayElement("TextArea", "TextAreaName")); - textArea->setMetricsMode(Ogre::GMM_PIXELS); - textArea->setPosition(0, 0); - textArea->setDimensions(320, 24); - textArea->setCaption("Hello, World!"); - textArea->setCharHeight(24); - textArea->setFontName("ComicSans"); - textArea->setColour(Ogre::ColourValue(0.f,0.f,0.f)); + Ogre::ColourValue text_color = Ogre::ColourValue(0.25, 0.25, 0.25); - Ogre::Overlay* overlay = overlayManager->create("OverlayName"); + Ogre::TextAreaOverlayElement* toolsTextArea = static_cast(m_overlayManager->createOverlayElement("TextArea", "TopMenuBarTools")); + toolsTextArea->setMetricsMode(Ogre::GMM_PIXELS); + toolsTextArea->setPosition(0, 0); + toolsTextArea->setDimensions(128, 24); + toolsTextArea->setCaption("Tools"); + toolsTextArea->setCharHeight(24); + toolsTextArea->setFontName("ComicSans"); + toolsTextArea->setColour(text_color); + + Ogre::TextAreaOverlayElement* insertTextArea = static_cast(m_overlayManager->createOverlayElement("TextArea", "TopMenuBarInsert")); + insertTextArea->setMetricsMode(Ogre::GMM_PIXELS); + insertTextArea->setPosition(128, 0); + insertTextArea->setDimensions(128, 24); + insertTextArea->setCaption("Insert"); + insertTextArea->setCharHeight(24); + insertTextArea->setFontName("ComicSans"); + insertTextArea->setColour(text_color); + + Ogre::TextAreaOverlayElement* fullscreenTextArea = static_cast(m_overlayManager->createOverlayElement("TextArea", "TopMenuBarFullscreen")); + fullscreenTextArea->setMetricsMode(Ogre::GMM_PIXELS); + fullscreenTextArea->setPosition(128*2, 0); + fullscreenTextArea->setDimensions(128, 24); + fullscreenTextArea->setCaption("Fullscreen"); + fullscreenTextArea->setCharHeight(24); + fullscreenTextArea->setFontName("ComicSans"); + fullscreenTextArea->setColour(text_color); + + Ogre::TextAreaOverlayElement* helpTextArea = static_cast(m_overlayManager->createOverlayElement("TextArea", "TopMenuBarHelp")); + helpTextArea->setMetricsMode(Ogre::GMM_PIXELS); + helpTextArea->setPosition(128*3, 0); + helpTextArea->setDimensions(128, 24); + helpTextArea->setCaption("Help..."); + helpTextArea->setCharHeight(24); + helpTextArea->setFontName("ComicSans"); + helpTextArea->setColour(text_color); + + Ogre::TextAreaOverlayElement* exitTextArea = static_cast(m_overlayManager->createOverlayElement("TextArea", "TopMenuBarExit")); + exitTextArea->setMetricsMode(Ogre::GMM_PIXELS); + exitTextArea->setPosition(128*4, 0); + exitTextArea->setDimensions(128, 24); + exitTextArea->setCaption("Exit"); + exitTextArea->setCharHeight(24); + exitTextArea->setFontName("ComicSans"); + exitTextArea->setColour(text_color); + + panel->addChild(toolsTextArea); + panel->addChild(insertTextArea); + panel->addChild(fullscreenTextArea); + panel->addChild(helpTextArea); + panel->addChild(exitTextArea); + + m_debugText = static_cast(m_overlayManager->createOverlayElement("TextArea", "DebugTextArea")); + m_debugText->setMetricsMode(Ogre::GMM_PIXELS); + m_debugText->setPosition(0, 300); + m_debugText->setDimensions(420, 500); + m_debugText->setCaption("Debug text!"); + m_debugText->setCharHeight(16); + m_debugText->setFontName("ComicSans"); + m_debugText->setColour(Ogre::ColourValue(0.5f,0.f,0.5f)); + + panel->addChild(m_debugText); + + m_playerPanel = static_cast(m_overlayManager->createOverlayElement("Panel", "PlayerListPanel")); + m_playerPanel->setMetricsMode(Ogre::GMM_PIXELS); + m_playerPanel->setDimensions(128, 20); + m_playerPanel->setMaterial(material); + + m_playerList = static_cast(m_overlayManager->createOverlayElement("TextArea", "PlayerListTextArea")); + m_playerList->setMetricsMode(Ogre::GMM_PIXELS); + m_playerList->setPosition(0, 0); + m_playerList->setDimensions(1000, 1000); + m_playerList->setCaption("Player List"); + m_playerList->setCharHeight(24); + m_playerList->setFontName("ComicSans"); + m_playerList->setColour(Ogre::ColourValue(1.0f, 1.0f, 1.0f)); + + m_playerPanel->addChild(m_playerList); + m_playerPanel->setVisible(false); + + Ogre::Overlay* overlay = m_overlayManager->create("TopMenuBarOverlay"); overlay->add2D(panel); + overlay->add2D(m_playerPanel); overlay->setZOrder(500); - panel->addChild(textArea); - overlay->show(); } + + void TopMenuBar::frame() + { + Workspace* workspace = m_world->getWorkspace(); + + char debugtext[512]; + char render_debugtext[255]; + switch(workspace->m_batchMode) + { + case BATCH_INSTANCED: + snprintf(render_debugtext, 255, "using BATCH_INSTANCED"); + break; + case BATCH_STATIC_GEOMETRY: + snprintf(render_debugtext, 255, "using BATCH_STATIC_GEOMETRY\nGeom Regions: %i", workspace->m_geom->getRegions().size()); + break; + } + snprintf(debugtext, 512, "Render\nLast DT = %f\n%s\n",m_world->getLastDelta(),render_debugtext,m_world->getOgreSceneManager()); + m_debugText->setCaption(debugtext); + + Players* players = (Players*)m_world->getDatamodel()->getService("Players"); + auto player_list = players->getChildren(); + if(player_list->size() == 0) + { + m_playerPanel->setVisible(false); + } + else + { + m_playerPanel->setVisible(true); + m_playerPanel->setPosition(m_overlayManager->getViewportWidth() - 128 - 5,5); + std::string player_list_text = "Player List\n"; + for(auto player : *player_list) + { + player_list_text += player->getName() + "\n"; + } + m_playerList->setCaption(player_list_text); + m_playerPanel->setDimensions(128, 20 * (player_list->size() + 1)); + } + } } \ No newline at end of file diff --git a/Projects/Engine/Source/App/Script/ReflectionProperty.cpp b/Projects/Engine/Source/App/Script/ReflectionProperty.cpp index 77dfa92..6342ee6 100644 --- a/Projects/Engine/Source/App/Script/ReflectionProperty.cpp +++ b/Projects/Engine/Source/App/Script/ReflectionProperty.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include @@ -64,6 +65,8 @@ namespace RNR cframe_rotation.z, cframe_rotation.w); } + case PROPERTY_BRICKCOLOR: + return std::string(BrickColor::name(*(int*)m_getter(m_object))); default: return std::string("???"); } diff --git a/Projects/Engine/Source/App/V8/DataModel/Light.cpp b/Projects/Engine/Source/App/V8/DataModel/Light.cpp index 49133ca..9d51261 100644 --- a/Projects/Engine/Source/App/V8/DataModel/Light.cpp +++ b/Projects/Engine/Source/App/V8/DataModel/Light.cpp @@ -1,4 +1,6 @@ #include +#include +#include namespace RNR { @@ -7,6 +9,43 @@ namespace RNR m_brightness = 1.f; m_enabled = true; m_shadows = true; - m_color = Ogre::Vector3(1.f,1.f,1.f); + m_color = Ogre::Vector3(75.f/255.f,151.f/255.f,75.f/255.f); + + setNode(world->getOgreSceneManager()->getRootSceneNode()->createChildSceneNode()); + setObject(world->getOgreSceneManager()->createLight(Ogre::Light::LT_POINT)); + getNode()->attachObject(getObject()); + + Ogre::Light* light_object = (Ogre::Light*)getObject(); + } + + void Light::onSetParent(Instance* newParent) + { + Ogre::Light* light_object = (Ogre::Light*)getObject(); + + if(!newParent) + { + light_object->setVisible(false); + return; + } + + PartInstance* part = dynamic_cast(newParent); + if(!part) + { + light_object->setVisible(false); + return; + } + + getNode()->setPosition(part->getPosition()); + setupLight(light_object); + } + + void Light::setupLight(Ogre::Light* light) + { + light->setVisible(m_enabled); + light->setCastShadows(m_shadows); + light->setDiffuseColour(Ogre::ColourValue(m_color.x, m_color.y, m_color.z)); + //light->setAttenuation(100, 1.0, 0.045, 0.0075); + light->setRenderingDistance(500.f); + light->setShadowFarDistance(100); } } \ No newline at end of file diff --git a/Projects/Engine/Source/App/V8/DataModel/PartInstance.cpp b/Projects/Engine/Source/App/V8/DataModel/PartInstance.cpp index 8ef18f8..bec7c7c 100644 --- a/Projects/Engine/Source/App/V8/DataModel/PartInstance.cpp +++ b/Projects/Engine/Source/App/V8/DataModel/PartInstance.cpp @@ -9,6 +9,12 @@ namespace RNR setName("Part"); m_color = Ogre::Vector4(0.63, 0.64, 0.63, 1.0); + m_transparency = 0.0; + m_reflectance = 0.0; + + setNode(world->getOgreSceneManager()->getRootSceneNode()->createChildSceneNode()); + setObject(world->getOgreSceneManager()->createEntity("fonts/Cube.mesh")); + getNode()->attachObject(getObject()); updateMatrix(); } @@ -17,6 +23,17 @@ namespace RNR { m_matrix = m_cframe.getMatrix(); m_position = m_cframe.getPosition(); + + getNode()->setOrientation(Ogre::Quaternion(m_cframe.getRotation())); + getNode()->setPosition(m_position); + getNode()->setScale(m_size); + + Ogre::Entity* entity = (Ogre::Entity*)getObject(); + for(auto& subentity : entity->getSubEntities()) + { + subentity->setMaterial(BrickColor::material(m_brickColor)); + subentity->getMaterial()->setShininess(64); + } } void PartInstance::deserializeProperty(char* prop_name, pugi::xml_node node) @@ -33,8 +50,17 @@ namespace RNR printf("PartInstance::deserializeProperty: BrickColor not valid number (%i)\n", getBrickColor()); } } + else if(prop_name == std::string("Reflectance")) + { + setReflectance(node.text().as_float()); + } + else if(prop_name == std::string("Transparency")) + { + setTransparency(node.text().as_float()); + } else PVInstance::deserializeProperty(prop_name, node); + updateMatrix(); } void PartInstance::addProperties(std::vector& properties) @@ -44,6 +70,18 @@ namespace RNR ACCESS_NONE, OPERATION_READWRITE, PROPERTY_VECTOR3, REFLECTION_GETTER(PartInstance* instance = (PartInstance*)object; return &instance->m_size; ), REFLECTION_SETTER(PartInstance* instance = (PartInstance*)object; instance->setSize(*(Ogre::Vector3*)value); ) }, + { this, std::string("BrickColor"), std::string(""), + ACCESS_NONE, OPERATION_READWRITE, PROPERTY_BRICKCOLOR, + REFLECTION_GETTER(PartInstance* instance = (PartInstance*)object; return &instance->m_brickColor; ), + REFLECTION_SETTER(PartInstance* instance = (PartInstance*)object; instance->setBrickColor(*(int*)value); ) }, + { this, std::string("Reflectance"), std::string(""), + ACCESS_NONE, OPERATION_READWRITE, PROPERTY_FLOAT, + REFLECTION_GETTER(PartInstance* instance = (PartInstance*)object; return &instance->m_reflectance; ), + REFLECTION_SETTER(PartInstance* instance = (PartInstance*)object; instance->setReflectance(*(float*)value); ) }, + { this, std::string("Transparency"), std::string(""), + ACCESS_NONE, OPERATION_READWRITE, PROPERTY_FLOAT, + REFLECTION_GETTER(PartInstance* instance = (PartInstance*)object; return &instance->m_transparency; ), + REFLECTION_SETTER(PartInstance* instance = (PartInstance*)object; instance->setTransparency(*(float*)value); ) }, }; PVInstance::addProperties(properties); diff --git a/Projects/Engine/Source/App/V8/DataModel/Workspace.cpp b/Projects/Engine/Source/App/V8/DataModel/Workspace.cpp index 8c76c52..b314c73 100644 --- a/Projects/Engine/Source/App/V8/DataModel/Workspace.cpp +++ b/Projects/Engine/Source/App/V8/DataModel/Workspace.cpp @@ -8,81 +8,69 @@ namespace RNR Workspace::Workspace() : ModelInstance() { setName("Workspace"); + m_batchMode = BATCH_STATIC_GEOMETRY; + m_worldspawn = world->getOgreSceneManager()->getRootSceneNode()->createChildSceneNode(); - m_geom = world->getOgreSceneManager()->createStaticGeometry("workspaceGeom"); - m_geom->setCastShadows(true); - m_partEntity = world->getOgreSceneManager()->createEntity("fonts/Cube.mesh"); - m_partEntity->setCastShadows(true); - - for(int i = 0; i < m_partEntity->getNumSubEntities(); i++) + + switch(m_batchMode) { - Ogre::SubEntity* surface = m_partEntity->getSubEntity(i); - Ogre::TextureUnitState* texture = surface->getMaterial()->getTechnique(0)->getPass(0)->createTextureUnitState("textures/stud_top.png"); - - surface->getMaterial()->setShininess(1.0); + case BATCH_INSTANCED: + m_instanceManager = world->getOgreSceneManager()->createInstanceManager("workspaceInstanceManager", "fonts/Cube.mesh", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::InstanceManager::InstancingTechnique::HWInstancingBasic, 255); + break; + case BATCH_STATIC_GEOMETRY: + m_geom = world->getOgreSceneManager()->createStaticGeometry("workspaceGeom"); + m_geom->setRegionDimensions(Ogre::Vector3(512,512,512)); + m_geom->setCastShadows(true); + break; } } - void Workspace::onChildAdded(Instance* childAdded) + void Workspace::onDescendantAdded(Instance* childAdded) { - m_geomDirty = true; + PartInstance* part = dynamic_cast(childAdded); + if(part) + { + Ogre::SceneNode* child_node = childAdded->getNode(); + switch(m_batchMode) + { + case BATCH_INSTANCED: + { + Ogre::Entity* childEntity = (Ogre::Entity*)childAdded->getObject(); + Ogre::InstancedEntity* replica = m_instanceManager->createInstancedEntity(childEntity->getSubEntity(0)->getMaterialName()); + replica->setPosition(part->getPosition()); + replica->setOrientation(part->getCFrame().getRotation()); + replica->setScale(part->getSize()); + childAdded->setObject(replica); + } + break; + case BATCH_STATIC_GEOMETRY: + m_geom->addEntity((Ogre::Entity*)childAdded->getObject(), + part->getPosition(), + part->getCFrame().getRotation(), + part->getSize()); + break; + } + child_node->setVisible(false); + m_geomDirty = true; + } } void Workspace::buildGeomInstance(Instance* instance) { - PartInstance* child_part = dynamic_cast(instance); - if(child_part) - { - Ogre::Vector3 part_size = child_part->getSize(); - for(int i = 0; i < m_partEntity->getNumSubEntities(); i++) - { - m_partEntity->setMaterial(BrickColor::material(child_part->getBrickColor())); - /* - Ogre::SubMesh* surface = m_partEntity->getMesh()->getSubMesh(i); - surface->setMaterial(); - Ogre::TextureUnitState* texture = surface->getMaterial()->getTechnique(0)->getPass(0)->getTextureUnitState(0); - - Ogre::Vector2 uvs; - std::string surf_name = std::string(surface->getMaterialName().c_str()); - if(surf_name == "TopMaterial") - uvs = Ogre::Vector2(part_size.x, part_size.z); - else if(surf_name == "BottomMaterial") - uvs = Ogre::Vector2(-part_size.x, part_size.z); - else if(surf_name == "LeftMaterial") - uvs = Ogre::Vector2(part_size.y, part_size.z); - else if(surf_name == "RightMaterial") - uvs = Ogre::Vector2(-part_size.y, part_size.z); - else if(surf_name == "BackMaterial") - uvs = Ogre::Vector2(part_size.x, part_size.z); - else if(surf_name == "FrontMaterial") - uvs = Ogre::Vector2(-part_size.x, part_size.z);*/ - - - } - m_geom->addEntity(m_partEntity, - child_part->getCFrame().getPosition(), - Ogre::Quaternion(child_part->getCFrame().getRotation()), - child_part->getSize()); - } - for(auto& child : *instance->getChildren()) - buildGeomInstance(child); } void Workspace::buildGeom() { - if(!m_geomDirty) + if(!m_geomDirty || m_batchMode != BATCH_STATIC_GEOMETRY) return; - m_geom->reset(); - for(auto& child : *getChildren()) - buildGeomInstance(child); m_geom->build(); m_geomDirty = false; } - void Workspace::onChildRemoved(Instance* childRemoved) + void Workspace::onDescendantRemoved(Instance* childRemoved) { - m_geomDirty = true; + m_geomDirty = true; } Camera* Workspace::getCurrentCamera() const diff --git a/Projects/Engine/Source/App/V8/Tree/Instance.cpp b/Projects/Engine/Source/App/V8/Tree/Instance.cpp index 21e757a..c3680ca 100644 --- a/Projects/Engine/Source/App/V8/Tree/Instance.cpp +++ b/Projects/Engine/Source/App/V8/Tree/Instance.cpp @@ -132,6 +132,9 @@ namespace RNR { children->erase(child_it); m_parent->onChildRemoved(this); + m_parent->onDescendantRemoved(this); + for(auto& child : m_children) + descendantRemovedChildren(m_parent, child); if (m_parent->numChildren() == 0) { @@ -140,24 +143,59 @@ namespace RNR } } + onSetParent(newParent); m_parent = newParent; + if(m_parent) { m_parent->m_children.push_back(this); newParent->onChildAdded(this); + newParent->onDescendantAdded(this); + for(auto& child : m_children) + descendantAddedChildren(m_parent, child); } } } + void Instance::descendantAddedChildren(Instance* p, Instance* c) + { + for(auto& child : *c->getChildren()) + descendantAddedChildren(p, child); + p->onDescendantAdded(c); + } + + void Instance::descendantRemovedChildren(Instance* p, Instance* c) + { + for(auto& child : *c->getChildren()) + descendantRemovedChildren(p, child); + p->onDescendantRemoved(c); + } + void Instance::onChildAdded(Instance* childAdded) { // } + void Instance::onDescendantAdded(Instance* descendantAdded) + { + if(m_parent) + m_parent->onDescendantAdded(descendantAdded); + } void Instance::onChildRemoved(RNR::Instance* childRemoved) { - + + } + + void Instance::onDescendantRemoved(Instance* descendantRemoved) + { + if(m_parent) + m_parent->onDescendantRemoved(descendantRemoved); + } + + void Instance::onSetParent(Instance* newParent) + { + } bool Instance::isA(std::string type) diff --git a/Projects/Engine/Source/App/V8/World/World.cpp b/Projects/Engine/Source/App/V8/World/World.cpp index 2da69ed..38bc843 100644 --- a/Projects/Engine/Source/App/V8/World/World.cpp +++ b/Projects/Engine/Source/App/V8/World/World.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -24,6 +25,8 @@ namespace RNR m_instanceFactory->registerInstance("Workspace", InstanceFactory::instanceBuilder); m_instanceFactory->registerInstance("Humanoid", InstanceFactory::instanceBuilder); m_instanceFactory->registerInstance("RunService", InstanceFactory::instanceBuilder); + m_instanceFactory->registerInstance("Players", InstanceFactory::instanceBuilder); + m_instanceFactory->registerInstance("Player", InstanceFactory::instanceBuilder); m_ogreRoot = ogre; m_ogreSceneManager = ogreSceneManager; @@ -31,8 +34,9 @@ namespace RNR m_datamodel->setName("DataModel"); m_workspace = (Workspace*)m_datamodel->getService("Workspace"); m_runService = (RunService*)m_datamodel->getService("RunService"); + m_players = (Players*)m_datamodel->getService("Players"); - m_tmb = new TopMenuBar(); + m_tmb = new TopMenuBar(this); Camera* start_cam = new Camera(); start_cam->setParent(m_workspace); @@ -70,9 +74,9 @@ namespace RNR m_refs[referent.as_string()] = instance; WorldUndeserialized s; s.instance = instance; + s.parent = parent; s.node = node; m_undeserialized.push(s); - instance->setParent(parent); for(pugi::xml_node item = node.child("Item"); item; item = item.next_sibling("Item")) xmlAddItem(item, instance); @@ -111,6 +115,7 @@ namespace RNR s.instance->deserializeXmlProperty(prop); } + s.instance->setParent(s.parent); if(s.instance->getClassName() == "Model") { ModelInstance* m = (ModelInstance*)s.instance; @@ -129,6 +134,7 @@ namespace RNR { if(m_inputManager) m_inputManager->frame(); + m_tmb->frame(); } double World::step(float timestep) diff --git a/Projects/Engine/Source/Network/Player.cpp b/Projects/Engine/Source/Network/Player.cpp new file mode 100644 index 0000000..352b7fe --- /dev/null +++ b/Projects/Engine/Source/Network/Player.cpp @@ -0,0 +1,25 @@ +#include +#include + +namespace RNR +{ + Player::Player() + { + setName("Player"); + setParent(world->getDatamodel()->getService("Players")); + + m_character = NULL; + } + + void Player::addProperties(std::vector& properties) + { + ReflectionProperty _properties[] = { + { this, std::string("Character"), std::string(""), + ACCESS_NONE, OPERATION_READWRITE, PROPERTY_INSTANCE, + REFLECTION_GETTER(Player* instance = (Player*)object; return instance->m_character; ), + REFLECTION_SETTER(Player* instance = (Player*)object; instance->setCharacter((ModelInstance*)value); ) }, + }; + + properties.insert(properties.end(), _properties, _properties+(sizeof(_properties)/sizeof(ReflectionProperty))); + } +} diff --git a/Projects/Engine/Source/Network/Players.cpp b/Projects/Engine/Source/Network/Players.cpp new file mode 100644 index 0000000..186610b --- /dev/null +++ b/Projects/Engine/Source/Network/Players.cpp @@ -0,0 +1,34 @@ +#include + +namespace RNR +{ + Players::Players() + { + setName("Players"); + m_localPlayer = 0; + } + + Player* Players::createLocalPlayer(int userId) + { + if(m_localPlayer) + { + printf("Players::createLocalPlayer: attempt to create another local player\n", userId); + return m_localPlayer; + } + printf("Players::createLocalPlayer: created player %i\n", userId); + m_localPlayer = new Player(); + return m_localPlayer; + } + + void Players::addProperties(std::vector& properties) + { + ReflectionProperty _properties[] = { + { this, std::string("LocalPlayer"), std::string(""), + ACCESS_NONE, OPERATION_READ, PROPERTY_INSTANCE, + REFLECTION_GETTER(Players* instance = (Players*)object; return instance->m_localPlayer; ), + REFLECTION_SETTER( ) }, + }; + + properties.insert(properties.end(), _properties, _properties+(sizeof(_properties)/sizeof(ReflectionProperty))); + } +} \ No newline at end of file diff --git a/README.md b/README.md index ac204a1..fc79773 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![Star](https://img.shields.io/github/stars/lrre-foss/RNR?style=social)](https://github.com/lrre-foss/RNR/stargazers) [Discord](https://discord.gg/89WagAUr) -RNR (**R**NR's **N**ot **R**oblox) is a project that aims to recreate the look and feel of classic Roblox with new features while remaining fully compatible with clients from that era. It is built upon an engine that closely resembles Roblox's own at the time, referencing disassemblies of legacy client binaries. +RNR (**R**NR's **N**ot **R**oblox) is a project that aims to recreate the look and feel of classic Roblox with new features while remaining partially compatible with clients from that era. It is built upon an engine that closely resembles Roblox's own at the time, referencing disassemblies of legacy client binaries. Interested in contributing? [Feel free to make a pull request!](https://github.com/lrre-foss/RNR/pulls) @@ -13,7 +13,6 @@ There are several goals that RNR seeks to accomplish, them being; - Easy-to-use (simple CLI options to launch and host games, as well as a level editor with a modern UI) - Fully compatible with Roblox versions up to 0.3.744.0 (dated April 2008) in areas such as hosting, joining, levels, etc. - Incorporates all the various facets of the Roblox engine, plus a little bit extra (e.g. a network replication whitelist, fancy shader support, etc.) -- Made using clean-room reverse engineering - Uses Roblox's [Luau](https://luau-lang.org/) as its scripting language while remaining fully compatible with classic Roblox scripts written using Lua 5.1 - As free and open-source as possible (with client code licensed under the GPL and the engine itself being released into the public domain, void of any copyright) - Patching all the security vulnerabilities and fixing bugs/inefficiencies that legacy Roblox clients had