diff --git a/Content/RNR/materials/InstancedMaterial.material b/Content/RNR/materials/InstancedMaterial.material index 8d177d2..71aa535 100644 --- a/Content/RNR/materials/InstancedMaterial.material +++ b/Content/RNR/materials/InstancedMaterial.material @@ -1,3 +1,10 @@ +vertex_program InstancedMaterial/VertexProgram glsl +{ + source shaders/InstancedShaer_f.glsl + syntax glsl330 + +} + // generated by blender2ogre 0.8.3 on 2023-07-20 04:32:47 material InstancedMaterial { receive_shadows on diff --git a/Content/RNR/materials/partinstanced.material b/Content/RNR/materials/partinstanced.material index 1d00859..93f0f89 100644 --- a/Content/RNR/materials/partinstanced.material +++ b/Content/RNR/materials/partinstanced.material @@ -19,11 +19,10 @@ material materials/PartInstanced technique { - shadow_caster_material materials/PartInstanced/shadow_caster pass { - specular 1 1 1 1 12.5 + specular 1 1 1 1 64.5 lighting on texture_unit diff --git a/Content/RNR/materials/shaders/InstancedShader_f.glsl b/Content/RNR/materials/shaders/InstancedShader_f.glsl new file mode 100644 index 0000000..e69de29 diff --git a/Content/RNR/meshes/Cube.scene b/Content/RNR/meshes/Cube.scene index e56d34d..55ed676 100644 --- a/Content/RNR/meshes/Cube.scene +++ b/Content/RNR/meshes/Cube.scene @@ -1,7 +1,7 @@ - - + + @@ -13,26 +13,7 @@ - - - - - - - - - - - - - - - - - - - - + diff --git a/Content/RNR/textures/studio/icons/PointLight.png b/Content/RNR/textures/studio/icons/PointLight.png index c23f421..b6e47c8 100644 Binary files a/Content/RNR/textures/studio/icons/PointLight.png and b/Content/RNR/textures/studio/icons/PointLight.png differ diff --git a/Content/RNR/textures/studio/icons/Weld.png b/Content/RNR/textures/studio/icons/Weld.png new file mode 100644 index 0000000..46285cc Binary files /dev/null and b/Content/RNR/textures/studio/icons/Weld.png differ diff --git a/Projects/Engine/CMakeLists.txt b/Projects/Engine/CMakeLists.txt index 26a1592..70240c2 100644 --- a/Projects/Engine/CMakeLists.txt +++ b/Projects/Engine/CMakeLists.txt @@ -28,6 +28,7 @@ add_library(Engine STATIC Header/App/V8/Tree/ModelInstance.hpp Header/App/V8/World/World.hpp Header/App/V8/World/Weld.hpp + Header/App/V8/World/JointsService.hpp Header/App/V8/World/ComPlicitNgine.hpp Header/App/CoordinateFrame.hpp Header/App/BrickColor.hpp @@ -67,6 +68,7 @@ add_library(Engine STATIC Source/App/InputManager.cpp Source/App/V8/World/World.cpp Source/App/V8/World/Weld.cpp + Source/App/V8/World/JointsService.cpp Source/App/V8/World/ComPlicitNgine.cpp Source/Network/GUID.cpp Source/Network/Player.cpp diff --git a/Projects/Engine/Header/App/V8/DataModel/PartInstance.hpp b/Projects/Engine/Header/App/V8/DataModel/PartInstance.hpp index 1d136c0..4e96971 100644 --- a/Projects/Engine/Header/App/V8/DataModel/PartInstance.hpp +++ b/Projects/Engine/Header/App/V8/DataModel/PartInstance.hpp @@ -1,12 +1,42 @@ #pragma once #include #include +#include #include #define STUD_HEIGHT 1.18 namespace RNR { + enum PartSurfaceType + { + SURFACE_SMOOTH, + SURFACE_GLUE, + SURFACE_WELD, + SURFACE_STUDS, + SURFACE_INLET, + SURFACE_UNIVERSAL, + SURFACE_HINGE, + SURFACE_MOTOR, + SURFACE_STEPPINGMOTOR, + SURFACE_UNJOINABLE, + __SURFACE_COUNT, + }; + + struct PartSurfaceInfo + { + public: + NormalId face; + PartSurfaceType type; + + Ogre::Vector2 start; + Ogre::Vector2 end; + float plane; + + bool intersects(PartSurfaceInfo other); + bool links(PartSurfaceInfo other); + }; + class PartInstance : public PVInstance { protected: @@ -14,6 +44,7 @@ namespace RNR float m_transparency; float m_reflectance; bool m_anchored; + PartSurfaceInfo m_surfaces[__NORM_COUNT]; Ogre::Matrix4 m_matrix; Ogre::Vector3 m_position; Ogre::Vector3 m_size; @@ -25,9 +56,11 @@ namespace RNR PartInstance(); void updateMatrix(); + PartSurfaceInfo& getSurface(NormalId normal) { return m_surfaces[normal]; }; + void setSurface(NormalId normal, PartSurfaceInfo surface) { m_surfaces[normal] = surface; } virtual std::string getClassName() { return "Part"; } - void setSize(Ogre::Vector3 size) { m_size = size; } + void setSize(Ogre::Vector3 size) { m_size = size; updateSurfaces(); } Ogre::Vector3 getSize() { return m_size; } Ogre::Vector4 getColor() { return m_color; } @@ -38,6 +71,10 @@ namespace RNR void setAnchored(bool anchored) { m_anchored = anchored; } bool getAnchored() { return m_anchored; } + void makeJoints(); + void breakJoints(); + void updateSurfaces(); + Ogre::Vector3 getOgreCenter() { return m_position + (m_size / 2.f); } void setBrickColor(int brickcolor) { m_brickColor = brickcolor; } diff --git a/Projects/Engine/Header/App/V8/DataModel/RunService.hpp b/Projects/Engine/Header/App/V8/DataModel/RunService.hpp index 01628e6..dc7eb80 100644 --- a/Projects/Engine/Header/App/V8/DataModel/RunService.hpp +++ b/Projects/Engine/Header/App/V8/DataModel/RunService.hpp @@ -14,7 +14,7 @@ namespace RNR virtual void addProperties(std::vector& properties); public: RunService(); - + virtual std::string getClassName() { return "RunService"; } bool getRunning() { return m_running; } diff --git a/Projects/Engine/Header/App/V8/DataModel/Workspace.hpp b/Projects/Engine/Header/App/V8/DataModel/Workspace.hpp index 3670e45..2e99f96 100644 --- a/Projects/Engine/Header/App/V8/DataModel/Workspace.hpp +++ b/Projects/Engine/Header/App/V8/DataModel/Workspace.hpp @@ -30,6 +30,7 @@ namespace RNR virtual void onDescendantRemoved(RNR::Instance* childRemoved); void buildGeom(); + void makeJoints(); Camera* getCurrentCamera() const; void setCurrentCamera(Camera *value); diff --git a/Projects/Engine/Header/App/V8/World/JointsService.hpp b/Projects/Engine/Header/App/V8/World/JointsService.hpp new file mode 100644 index 0000000..4669d5b --- /dev/null +++ b/Projects/Engine/Header/App/V8/World/JointsService.hpp @@ -0,0 +1,23 @@ +#pragma once +#include +#include +#include + +namespace RNR +{ + class JointsService : public Instance + { + public: + JointsService(); + virtual std::string getClassName() { return "JointsService"; } + Snap* snap(PartInstance* a, PartInstance* b); + + void makeJoints(Instance* w, PartInstance* p); + void makeJoints(PartInstance* p); + + void fixWelds(); + + void breakJoints(PartInstance* b); + bool isWelded(PartInstance* a, PartInstance* b); + }; +} \ No newline at end of file diff --git a/Projects/Engine/Header/App/V8/World/Weld.hpp b/Projects/Engine/Header/App/V8/World/Weld.hpp index 2a57949..d287e93 100644 --- a/Projects/Engine/Header/App/V8/World/Weld.hpp +++ b/Projects/Engine/Header/App/V8/World/Weld.hpp @@ -14,15 +14,28 @@ namespace RNR PartInstance* m_bInstance; btFixedConstraint* m_constraint; + + virtual void addProperties(std::vector& properties); + virtual void deserializeProperty(char* prop_name, pugi::xml_node prop); public: Weld(); ~Weld(); virtual std::string getClassName() { return "Weld"; } void weld(PartInstance* a, PartInstance* b); - void create(); + bool create(); void destroy(); bool getBroken(); + PartInstance* getPartA() { return m_aInstance; } + PartInstance* getPartB() { return m_bInstance; } + }; + + class Snap : public Weld + { + // they're basically the same + public: + virtual std::string getClassName() { return "Snap"; } + virtual std::string getExplorerIcon() { return "Weld"; } }; } \ No newline at end of file diff --git a/Projects/Engine/Header/Helpers/NormalId.hpp b/Projects/Engine/Header/Helpers/NormalId.hpp index b31ed84..4004871 100644 --- a/Projects/Engine/Header/Helpers/NormalId.hpp +++ b/Projects/Engine/Header/Helpers/NormalId.hpp @@ -5,13 +5,14 @@ namespace RNR { enum NormalId { - NORM_X, - NORM_Y, - NORM_Z, - NORM_X_NEG, - NORM_Y_NEG, - NORM_Z_NEG, - NORM_UNDEFINED + NORM_X, NORM_RIGHT = NORM_X, + NORM_Y, NORM_UP = NORM_Y, + NORM_Z, NORM_BACK = NORM_Z, + NORM_X_NEG, NORM_LEFT = NORM_X_NEG, + NORM_Y_NEG, NORM_DOWN = NORM_Y_NEG, + NORM_Z_NEG, NORM_FRONT = NORM_Z_NEG, + __NORM_COUNT, + NORM_UNDEFINED, }; bool validNormalId(NormalId normalId); diff --git a/Projects/Engine/Source/App/V8/DataModel/PartInstance.cpp b/Projects/Engine/Source/App/V8/DataModel/PartInstance.cpp index f8a7cef..ac11fa6 100644 --- a/Projects/Engine/Source/App/V8/DataModel/PartInstance.cpp +++ b/Projects/Engine/Source/App/V8/DataModel/PartInstance.cpp @@ -4,6 +4,36 @@ namespace RNR { + bool PartSurfaceInfo::intersects(PartSurfaceInfo other) + { + if(other.plane != plane) + return false; + if(start.x > other.end.x || other.start.x > end.x) + return false; + if(end.y > other.start.y || other.end.y > start.y) + return false; + return true; + } + + bool PartSurfaceInfo::links(PartSurfaceInfo other) + { + bool allowed_surf[__SURFACE_COUNT][__SURFACE_COUNT] = { + // SMOOTH, GLUE, WELD, STUDS, INLET, UNIVERSAL, HINGE, MOTOR, STEPPINGMOTOR, UNJOINABLE + { false, false, false, false, false, false, false, false, false, false }, // SMOOTH + { true, true, true, true, true, true, false, false, false, false }, // GLUE + { true, true, true, true, true, true, false, false, false, false }, // WELD + { false, false, false, false, true, true, false, false, false, false }, // STUDS + { false, false, false, true, false, true, false, false, false, false }, // INLET + { false, false, true, true, true, true, false, false, false, false }, // UNIVERSAL + { true, true, true, true, true, true, false, false, false, false }, // HINGE + { true, true, true, true, true, true, false, false, false, false }, // MOTOR + { true, true, true, true, true, true, false, false, false, false }, // STEPPINGMOTOR + { false, false, false, false, false, false, false, false, false, false }, // UNJOINABLE + }; + + return allowed_surf[type][other.type]; + } + PartInstance::PartInstance() : m_matrix(), PVInstance(), m_size(2.f, STUD_HEIGHT, 4.f) { setName("Part"); @@ -16,6 +46,23 @@ namespace RNR setObject(world->getOgreSceneManager()->createEntity("meshes/Cube.mesh")); getNode()->attachObject(getObject()); + for(int i = 0; i < __NORM_COUNT; i++) + { + NormalId n = (NormalId)i; + switch(n) + { + case NORM_UP: + m_surfaces[i].type = SURFACE_STUDS; + break; + case NORM_DOWN: + m_surfaces[i].type = SURFACE_INLET; + break; + default: + m_surfaces[i].type = SURFACE_SMOOTH; + break; + } + } + updateMatrix(); } @@ -52,6 +99,51 @@ namespace RNR entity->setCastShadows(true); } + void PartInstance::updateSurfaces() + { + for(int i = 0; i < __NORM_COUNT; i++) + { + m_surfaces[i].face = (NormalId)i; + PartSurfaceInfo& surf = m_surfaces[i]; + Ogre::Vector3 size = ((getSize() / 2.f) * getRotation()); + Ogre::Vector3 pos = getPosition(); + switch(m_surfaces[i].face) + { + case NORM_DOWN: + surf.start = Ogre::Vector2(pos.x-size.x,pos.z-size.z); + surf.end = Ogre::Vector2(pos.x+size.x,pos.z+size.z); + surf.plane = pos.y - size.y; + break; + case NORM_UP: + surf.start = Ogre::Vector2(pos.x-size.x,pos.z-size.z); + surf.end = Ogre::Vector2(pos.x+size.x,pos.z+size.z); + surf.plane = pos.y + size.y; + break; + case NORM_LEFT: + surf.start = Ogre::Vector2(pos.z-size.z,pos.y-size.y); + surf.end = Ogre::Vector2(pos.z+size.z,pos.y+size.y); + surf.plane = pos.z - size.z; + break; + case NORM_RIGHT: + surf.start = Ogre::Vector2(pos.z-size.z,pos.y-size.y); + surf.end = Ogre::Vector2(pos.z+size.z,pos.y+size.y); + surf.plane = pos.z + size.z; + break; + case NORM_FRONT: + surf.start = Ogre::Vector2(pos.z-size.z,pos.y-size.y); + surf.end = Ogre::Vector2(pos.z+size.z,pos.y+size.y); + surf.plane = pos.x + size.x; + break; + case NORM_BACK: + surf.start = Ogre::Vector2(pos.z-size.z,pos.y-size.y); + surf.end = Ogre::Vector2(pos.z+size.z,pos.y+size.y); + surf.plane = pos.x - size.x; + break; + } + } + + } + void PartInstance::deserializeProperty(char* prop_name, pugi::xml_node node) { if(prop_name == std::string("size")) diff --git a/Projects/Engine/Source/App/V8/DataModel/Workspace.cpp b/Projects/Engine/Source/App/V8/DataModel/Workspace.cpp index 441bf13..3f8fca7 100644 --- a/Projects/Engine/Source/App/V8/DataModel/Workspace.cpp +++ b/Projects/Engine/Source/App/V8/DataModel/Workspace.cpp @@ -16,6 +16,7 @@ namespace RNR { case BATCH_INSTANCED: m_instanceManager = world->getOgreSceneManager()->createInstanceManager("workspaceInstanceManager", "meshes/Cube_Instanced.mesh", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::InstanceManager::InstancingTechnique::HWInstancingBasic, 255); + m_instanceManager->setNumCustomParams(2); break; case BATCH_STATIC_GEOMETRY: m_geom = world->getOgreSceneManager()->createStaticGeometry("workspaceGeom"); @@ -43,6 +44,7 @@ namespace RNR replica->setOrientation(part->getCFrame().getRotation()); replica->setScale(part->getSize()); replica->setCastShadows(true); + replica->setCustomParam(0, Ogre::Vector4f(part->getSize().x, part->getSize().y, part->getSize().z, 0)); m_worldspawn->attachObject(replica); childAdded->setObject(replica); child_node->setVisible(false); @@ -56,6 +58,7 @@ namespace RNR child_node->setVisible(false); m_geomDirty = true; break; + default: case BATCH_DONT: child_node->setVisible(true); break; diff --git a/Projects/Engine/Source/App/V8/World/JointsService.cpp b/Projects/Engine/Source/App/V8/World/JointsService.cpp new file mode 100644 index 0000000..108bedb --- /dev/null +++ b/Projects/Engine/Source/App/V8/World/JointsService.cpp @@ -0,0 +1,112 @@ +#include +#include + +namespace RNR +{ + JointsService::JointsService() + { + setName("JointsService"); + } + + Snap* JointsService::snap(PartInstance* a, PartInstance* b) + { + Snap* snap = new Snap(); + snap->weld(a, b); + snap->setParent(this); + return snap; + } + + void JointsService::fixWelds() + { + for(auto& child : *getChildren()) + { + Weld* weld = dynamic_cast(child); + weld->create(); + } + } + + void JointsService::makeJoints(Instance* w, PartInstance* p) + { + for(auto& child : *w->getChildren()) + { + if(child == p) + continue; + PartInstance* child_p = dynamic_cast(child); + if(child_p) + { + if(isWelded(child_p, p)) + continue; + if(p == child_p) + continue; + child_p->updateSurfaces(); + for(int i = 0; i < __NORM_COUNT; i++) + { + NormalId n = (NormalId)i; + NormalId n_opp = normalIdOpposite(n); + PartSurfaceInfo n_surf = p->getSurface(n); + PartSurfaceInfo n_opp_surf = child_p->getSurface(n_opp); + if(n_surf.plane != n_opp_surf.plane) + continue; + if(n_surf.intersects(n_opp_surf)) + { + if(n_surf.links(n_opp_surf)) + { + // determine link + switch(n_surf.type) + { + case SURFACE_WELD: + case SURFACE_STUDS: + case SURFACE_INLET: + snap(p, child_p); + break; + } + } + } + } + } + makeJoints(child, p); + } + } + + void JointsService::makeJoints(PartInstance* p) + { + p->updateSurfaces(); + makeJoints(world->getWorkspace(), p); + } + + void JointsService::breakJoints(PartInstance* p) + { + for(auto& child : *getChildren()) + { + Snap* snap = dynamic_cast(child); + if(snap) + { + bool brk = false; + if(snap->getPartA() == p) + brk = true; + else if(snap->getPartB() == p) + brk = true; + if(brk) + { + + } + } + } + } + + bool JointsService::isWelded(PartInstance* a, PartInstance* b) + { + for(auto& child : *getChildren()) + { + Weld* snap = dynamic_cast(child); + if(snap) + { + if(snap->getPartA() == a && snap->getPartB() == b) + return true; + else if(snap->getPartA() == b && snap->getPartB() == a) + return true; + } + } + return false; + } +} \ No newline at end of file diff --git a/Projects/Engine/Source/App/V8/World/Weld.cpp b/Projects/Engine/Source/App/V8/World/Weld.cpp index ec0b13c..94df347 100644 --- a/Projects/Engine/Source/App/V8/World/Weld.cpp +++ b/Projects/Engine/Source/App/V8/World/Weld.cpp @@ -22,20 +22,21 @@ namespace RNR m_bBody = world->getComPlicitNgine()->getBody(b); } - void Weld::create() + bool Weld::create() { if(!m_aBody || !m_bBody) { printf("Weld::create: invalid body\n"); - return; + return false; } - btTransform frameInA, frameInB; - frameInA = btTransform::getIdentity(); - frameInB = btTransform::getIdentity(); + btTransform frameInA, frameInB; + frameInA = btTransform::getIdentity(); + frameInB = btTransform::getIdentity(); m_constraint = new btFixedConstraint(*m_aBody, *m_bBody, frameInA, frameInB); printf("Weld::create: welded\n"); + return true; } void Weld::destroy() @@ -50,4 +51,25 @@ namespace RNR return false; } + + void Weld::addProperties(std::vector& properties) + { + ReflectionProperty _properties[] = { + { this, std::string("Part0"), std::string(""), + ACCESS_NONE, OPERATION_READWRITE, PROPERTY_INSTANCE, + REFLECTION_GETTER(Weld* instance = (Weld*)object; return instance->m_aInstance; ), + REFLECTION_SETTER(Weld* instance = (Weld*)object; ) }, + { this, std::string("Part1"), std::string(""), + ACCESS_NONE, OPERATION_READWRITE, PROPERTY_INSTANCE, + REFLECTION_GETTER(Weld* instance = (Weld*)object; return instance->m_bInstance; ), + REFLECTION_SETTER(Weld* instance = (Weld*)object; ) }, + }; + + properties.insert(properties.end(), _properties, _properties+(sizeof(_properties)/sizeof(ReflectionProperty))); + } + + void Weld::deserializeProperty(char* prop_name, pugi::xml_node prop) + { + + } } \ No newline at end of file diff --git a/Projects/Engine/Source/App/V8/World/World.cpp b/Projects/Engine/Source/App/V8/World/World.cpp index 34fdde8..6626436 100644 --- a/Projects/Engine/Source/App/V8/World/World.cpp +++ b/Projects/Engine/Source/App/V8/World/World.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -37,6 +38,7 @@ namespace RNR m_instanceFactory->registerInstance("Players", InstanceFactory::instanceBuilder); m_instanceFactory->registerInstance("Player", InstanceFactory::instanceBuilder); m_instanceFactory->registerInstance("Lighting", InstanceFactory::instanceBuilder); + m_instanceFactory->registerInstance("JointsService", InstanceFactory::instanceBuilder); m_ogreRoot = ogre; m_ogreSceneManager = ogreSceneManager; @@ -107,6 +109,7 @@ namespace RNR { m_refs.clear(); + JointsService* joints = (JointsService*)m_datamodel->getService("JointsService"); Camera* old_camera = m_workspace->getCurrentCamera(); if(old_camera) { @@ -144,13 +147,19 @@ namespace RNR ModelInstance* m = (ModelInstance*)s.instance; m->build(); } + else if(s.instance->getClassName() == "Part") + { + PartInstance* p = (PartInstance*)s.instance; + joints->makeJoints(p); + } } } else { printf("World::load: XML parsed with errors, description '%s', offset %i\n", result.description(), result.offset); - } + } m_workspace->build(); + joints->fixWelds(); } void World::preRender(float timestep)