diff --git a/data b/data index a9efe78..4477e2f 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit a9efe788f89a3b1bf6381d1be2ffec4d3adc52bc +Subproject commit 4477e2f006acafe4058764a7ccd95694e0f61502 diff --git a/lib/emergent b/lib/emergent index 0fb5711..19d7fcd 160000 --- a/lib/emergent +++ b/lib/emergent @@ -1 +1 @@ -Subproject commit 0fb571191709569af7e342e281721ffa8cafd736 +Subproject commit 19d7fcdb76c3516702a8723b2d125ed07e6dc0c9 diff --git a/src/application.cpp b/src/application.cpp index 21360f9..bc93ba2 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -591,9 +591,10 @@ bool Application::loadModels() antHillModel = modelLoader->load("data/models/ant-hill.mdl"); nestModel = modelLoader->load("data/models/nest.mdl"); forcepsModel = modelLoader->load("data/models/forceps.mdl"); + lensModel = modelLoader->load("data/models/lens.mdl"); biomeFloorModel = modelLoader->load("data/models/desert-floor.mdl"); - if (!antModel || !antHillModel || !nestModel || !forcepsModel) + if (!antModel || !antHillModel || !nestModel || !forcepsModel || !lensModel) { return false; } @@ -1064,10 +1065,10 @@ bool Application::loadUI() // Create pie menu pieMenu = new PieMenu(tweener); - pieMenu->addOption(arcNorthTexture, toolLensTexture, std::bind(&std::printf, "0 on\n"), std::bind(&std::printf, "0 off\n")); - pieMenu->addOption(arcEastTexture, toolForcepsTexture, std::bind(&std::printf, "1 on\n"), std::bind(&std::printf, "1 off\n")); - pieMenu->addOption(arcSouthTexture, toolTrowelTexture, std::bind(&std::printf, "2 on\n"), std::bind(&std::printf, "2 off\n")); - pieMenu->addOption(arcWestTexture, toolBrushTexture, std::bind(&std::printf, "3 on\n"), std::bind(&std::printf, "3 off\n")); + pieMenu->addOption(arcNorthTexture, toolLensTexture, std::bind(&Application::selectTool, this, lens), std::bind(&Application::deselectTool, this, lens)); + pieMenu->addOption(arcEastTexture, toolForcepsTexture, std::bind(&Application::selectTool, this, forceps), std::bind(&Application::deselectTool, this, forceps)); + pieMenu->addOption(arcSouthTexture, toolTrowelTexture, std::bind(&Application::selectTool, this, nullptr), std::bind(&Application::deselectTool, this, nullptr)); + pieMenu->addOption(arcWestTexture, toolBrushTexture, std::bind(&Application::selectTool, this, forceps), std::bind(&Application::deselectTool, this, nullptr)); uiRootElement->addChild(pieMenu->getContainer()); pieMenu->resize(); pieMenu->getContainer()->setVisible(false); @@ -1403,11 +1404,16 @@ bool Application::loadGame() colony = new Colony(); colony->setAntModel(antModel); + currentTool = nullptr; + // Create tools forceps = new Forceps(forcepsModel); forceps->setColony(colony); forceps->setCameraController(surfaceCam); + lens = new Lens(lensModel); + lens->setCameraController(surfaceCam); + return true; } @@ -1508,6 +1514,25 @@ void Application::enterLevelSelection() changeState(levelSelectState); } +void Application::deselectTool(Tool* tool) +{ + if (tool != nullptr) + { + tool->setActive(false); + return; + } +} + +void Application::selectTool(Tool* tool) +{ + if (tool != nullptr) + { + tool->setActive(true); + } + + currentTool = tool; +} + void Application::selectWorld(std::size_t index) { // Set current world and level diff --git a/src/application.hpp b/src/application.hpp index eefddf9..0d73528 100644 --- a/src/application.hpp +++ b/src/application.hpp @@ -52,7 +52,9 @@ class ModelLoader; class MaterialLoader; class Toolbar; class PieMenu; +class Tool; class Forceps; +class Lens; /** * Encapsulates the state of the application. @@ -106,6 +108,9 @@ public: void enterLevelSelection(); + void deselectTool(Tool* tool); + void selectTool(Tool* tool); + void pauseSimulation(); @@ -360,6 +365,7 @@ public: Model* antHillModel; Model* nestModel; Model* forcepsModel; + Model* lensModel; Model* biomeFloorModel; // Game variables @@ -383,7 +389,9 @@ public: bool cameraOverheadView; bool cameraNestView; int toolIndex; + Tool* currentTool; Forceps* forceps; + Lens* lens; bool simulationPaused; // Debug diff --git a/src/game/tool.cpp b/src/game/tool.cpp index 801aeb7..7a2cc98 100644 --- a/src/game/tool.cpp +++ b/src/game/tool.cpp @@ -5,6 +5,28 @@ #include #include +Tool::Tool(): + active(false), + pick(0.0f), + cameraController(nullptr) +{ + modelInstance.setActive(active); +} + +Tool::~Tool() +{} + +void Tool::setActive(bool active) +{ + this->active = active; + modelInstance.setActive(active); +} + +void Tool::setCameraController(const SurfaceCameraController* cameraController) +{ + this->cameraController = cameraController; +} + Forceps::Forceps(const Model* model) { // Allocate pose and initialize to bind pose @@ -229,16 +251,6 @@ void Forceps::setColony(Colony* colony) this->colony = colony; } -void Forceps::setCameraController(const SurfaceCameraController* cameraController) -{ - this->cameraController = cameraController; -} - -void Forceps::setPick(const Vector3& pick) -{ - this->pick = pick; -} - void Forceps::pinch() { // Change state to pinching @@ -326,3 +338,41 @@ void Forceps::release() ascentTween->reset(); ascentTween->stop(); } + +Lens::Lens(const Model* model) +{ + // Setup model instance + modelInstance.setModel(model); + + hoverDistance = 12.0f; +} + +Lens::~Lens() +{} + +void Lens::update(float dt) +{ + /* + // Rotate to face camera + hoverDistance = 30.0f; + Vector3 direction = glm::normalize(cameraController->getCamera()->getTranslation() - pick); + //direction = cameraController->getCamera()->getForward(); + float distance = glm::distance(pick, cameraController->getCamera()->getTranslation()); + + Quaternion alignment = glm::angleAxis(cameraController->getAzimuth() + glm::radians(90.0f), Vector3(0, 1, 0)); + Quaternion tilt = glm::rotation(Vector3(0, 1, 0), -direction); + Quaternion rotation = glm::normalize(tilt * alignment); + + Vector3 translation = pick + rotation * Vector3(0, -distance + hoverDistance, 0); + + modelInstance.setTranslation(translation); + modelInstance.setRotation(rotation); + */ + + Quaternion alignment = glm::angleAxis(cameraController->getAzimuth() + glm::radians(90.0f), Vector3(0, 1, 0)); + Quaternion rotation = glm::normalize(alignment); + Vector3 translation = pick + Vector3(0, hoverDistance, 0); + + modelInstance.setTranslation(translation); + modelInstance.setRotation(rotation); +} diff --git a/src/game/tool.hpp b/src/game/tool.hpp index dd1865f..d600f5c 100644 --- a/src/game/tool.hpp +++ b/src/game/tool.hpp @@ -35,9 +35,77 @@ class SurfaceCameraController; class Tool { public: + /** + * Creates an instance of Tool. + */ + Tool(); + + /** + * Destroys an instance of Tool. + */ + virtual ~Tool(); + + /** + * Updates the tool. + * + * @param dt Application timestep. + */ virtual void update(float dt) = 0; + + /** + * Activates or deactivates the tool. + */ + void setActive(bool active); + + /** + * Sets the picking position. + * + * @param pick Picking position + */ + void setPick(const Vector3& pick); + + /** + * Sets the camera. + * + * @param camera Pointer to the camera. + */ + void setCameraController(const SurfaceCameraController* cameraController); + + bool isActive() const; + + /** + * Returns the model instance. + */ + const ModelInstance* getModelInstance() const; + ModelInstance* getModelInstance(); + +protected: + ModelInstance modelInstance; + bool active; + Vector3 pick; + const SurfaceCameraController* cameraController; }; +inline bool Tool::isActive() const +{ + return active; +} + +inline void Tool::setPick(const Vector3& pick) +{ + this->pick = pick; +} + +inline const ModelInstance* Tool::getModelInstance() const +{ + return &modelInstance; +} + +inline ModelInstance* Tool::getModelInstance() +{ + return &modelInstance; +} + /** * The forceps tool can pick up ants and place them anywhere in the world. @@ -67,6 +135,8 @@ public: /** * Updates the forceps. + * + * @param dt Application timestep. */ virtual void update(float dt); @@ -87,20 +157,6 @@ public: */ void setColony(Colony* colony); - /** - * Sets the camera. - * - * @param camera Pointer to the camera. - */ - void setCameraController(const SurfaceCameraController* cameraController); - - /** - * Sets the picking position. - * - * @param pick Picking position - */ - void setPick(const Vector3& pick); - /** * Returns the current state of the forceps. */ @@ -110,16 +166,9 @@ public: * Returns the suspended ant, if any. */ Ant* getSuspendedAnt() const; - - /** - * Returns the model instance. - */ - const ModelInstance* getModelInstance() const; - ModelInstance* getModelInstance(); private: Forceps::State state; - ModelInstance modelInstance; Pose* pose; const Animation* pinchAnimation; const Animation* releaseAnimation; @@ -137,8 +186,6 @@ private: Colony* colony; Ant* targetedAnt; Ant* suspendedAnt; - const SurfaceCameraController* cameraController; - Vector3 pick; }; inline Forceps::State Forceps::getState() const @@ -151,23 +198,33 @@ inline Ant* Forceps::getSuspendedAnt() const return suspendedAnt; } -inline const ModelInstance* Forceps::getModelInstance() const -{ - return &modelInstance; -} - -inline ModelInstance* Forceps::getModelInstance() -{ - return &modelInstance; -} - /** * The lens tool can be used to burn ants. */ class Lens: public Tool { public: + /** + * Creates an instance of Lens. + * + * @param model Lens model + */ + Lens(const Model* model); + + /** + * Destroys an instance of Lens. + */ + ~Lens(); + + /** + * Updates the lens. + * + * @param dt Application timestep. + */ virtual void update(float dt); + +private: + float hoverDistance; }; /** diff --git a/src/material-loader.cpp b/src/material-loader.cpp index 35711bb..4b987de 100644 --- a/src/material-loader.cpp +++ b/src/material-loader.cpp @@ -135,6 +135,16 @@ PhysicalMaterial* MaterialLoader::load(const std::string& filename) { std::stringstream(arguments[0]) >> material->roughness; } + else if (command == "translucent" && arguments.size() == 1) + { + int translucent = 0; + std::stringstream(arguments[0]) >> translucent; + + if (translucent) + { + material->flags |= static_cast(PhysicalMaterial::Flags::TRANSLUCENT); + } + } else if (command == "albedo-opacity-map") { material->albedoOpacityMap = loadTexture(argumentList); diff --git a/src/materials.hpp b/src/materials.hpp index c0acfbe..8817e98 100644 --- a/src/materials.hpp +++ b/src/materials.hpp @@ -55,6 +55,7 @@ public: OBJECT = 0x01, TERRAIN = 0x02, SOIL = 0x04, + TRANSLUCENT = 0x08 }; PhysicalMaterial(): diff --git a/src/render-passes.cpp b/src/render-passes.cpp index eb3d32b..c9d46e1 100644 --- a/src/render-passes.cpp +++ b/src/render-passes.cpp @@ -44,7 +44,7 @@ void ShadowMapRenderPass::unload() depthShader = nullptr; } -void ShadowMapRenderPass::render(const RenderContext* renderContext) +void ShadowMapRenderPass::render(RenderContext* renderContext) { // Bind framebuffer and setup viewport glBindFramebuffer(GL_FRAMEBUFFER, renderTarget->framebuffer); @@ -128,7 +128,7 @@ void ClippingRenderPass::unload() shader = nullptr; } -void ClippingRenderPass::render(const RenderContext* renderContext) +void ClippingRenderPass::render(RenderContext* renderContext) { glEnable(GL_CLIP_DISTANCE0); glEnable(GL_STENCIL_TEST); @@ -232,7 +232,7 @@ void SoilRenderPass::unload() horizonCTexture = nullptr; } -void SoilRenderPass::render(const RenderContext* renderContext) +void SoilRenderPass::render(RenderContext* renderContext) { // Bind shader shader->bind(); @@ -400,7 +400,7 @@ void LightingRenderPass::unload() specularCubemap = nullptr; } -void LightingRenderPass::render(const RenderContext* renderContext) +void LightingRenderPass::render(RenderContext* renderContext) { /* time += 1.0f / 60.f; @@ -787,7 +787,7 @@ void LightingRenderPass::render(const RenderContext* renderContext) */ const Camera& camera = *(renderContext->camera); - const std::list* operations = renderContext->queue->getOperations(); + std::list* operations = renderContext->queue->getOperations(); // Enable depth testing glEnable(GL_DEPTH_TEST); @@ -820,6 +820,9 @@ void LightingRenderPass::render(const RenderContext* renderContext) Texture* metalnessRoughnessMap = nullptr; Texture* normalOcclusionMap = nullptr; + // Sort operations + operations->sort(RenderOpCompare()); + // Render operations for (const RenderOperation& operation: *operations) { @@ -992,6 +995,54 @@ bool LightingRenderPass::loadShader(const RenderOperation& operation) return false; } +bool LightingRenderPass::RenderOpCompare::operator()(const RenderOperation& opA, const RenderOperation& opB) const +{ + // Skip render operations with unsupported materials + if (opA.material->getMaterialFormatID() != static_cast(MaterialFormat::PHYSICAL)) + { + return false; + } + else if (opB.material->getMaterialFormatID() != static_cast(MaterialFormat::PHYSICAL)) + { + return true; + } + + // Cast materials + const PhysicalMaterial* materialA = static_cast(opA.material); + const PhysicalMaterial* materialB = static_cast(opB.material); + + // Determine transparency + bool transparentA = materialA->flags & (unsigned int)PhysicalMaterial::Flags::TRANSLUCENT; + bool transparentB = materialB->flags & (unsigned int)PhysicalMaterial::Flags::TRANSLUCENT; + + if (transparentA) + { + if (transparentB) + { + // A and B are both transparent, sort by depth + return (opA.depth <= opB.depth); + } + else + { + // A is transparent, B is opaque. Render B first + return false; + } + } + else + { + if (transparentB) + { + // A is opaque, B is transparent. Render A first + return true; + } + else + { + // A and B are both opaque, sort by material + return (opA.material < opB.material); + } + } +} + DebugRenderPass::DebugRenderPass() { modelViewProjectionParam = parameterSet.addParameter("modelViewProjectionMatrix", ShaderParameter::Type::MATRIX_4, 1); @@ -1052,7 +1103,7 @@ void DebugRenderPass::unload() glDeleteVertexArrays(1, &aabbVAO); } -void DebugRenderPass::render(const RenderContext* renderContext) +void DebugRenderPass::render(RenderContext* renderContext) { const Camera& camera = *(renderContext->camera); @@ -1148,7 +1199,7 @@ void UIRenderPass::unload() untexturedUIShader = nullptr; } -void UIRenderPass::render(const RenderContext* renderContext) +void UIRenderPass::render(RenderContext* renderContext) { const Camera& camera = *(renderContext->camera); @@ -1265,7 +1316,7 @@ void VignetteRenderPass::unload() glDeleteTextures(1, &bayerTextureID); } -void VignetteRenderPass::render(const RenderContext* renderContext) +void VignetteRenderPass::render(RenderContext* renderContext) { glDisable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); @@ -1359,7 +1410,7 @@ void SkyboxRenderPass::unload() glDeleteVertexArrays(1, &quadVAO); } -void SkyboxRenderPass::render(const RenderContext* renderContext) +void SkyboxRenderPass::render(RenderContext* renderContext) { if (!cubemap) { diff --git a/src/render-passes.hpp b/src/render-passes.hpp index ae016ec..91b10af 100644 --- a/src/render-passes.hpp +++ b/src/render-passes.hpp @@ -36,7 +36,7 @@ public: virtual bool load(const RenderContext* renderContext); virtual void unload(); - virtual void render(const RenderContext* renderContext); + virtual void render(RenderContext* renderContext); private: ShaderParameterSet parameterSet; @@ -55,7 +55,7 @@ public: ClippingRenderPass(); virtual bool load(const RenderContext* renderContext); virtual void unload(); - virtual void render(const RenderContext* renderContext); + virtual void render(RenderContext* renderContext); void setClippingPlane(const Plane& plane); @@ -89,7 +89,7 @@ public: SoilRenderPass(); virtual bool load(const RenderContext* renderContext); virtual void unload(); - virtual void render(const RenderContext* renderContext); + virtual void render(RenderContext* renderContext); inline void setHorizonOTexture(Texture* texture) { horizonOTexture = texture; } inline void setHorizonATexture(Texture* texture) { horizonATexture = texture; } @@ -122,12 +122,19 @@ public: virtual bool load(const RenderContext* renderContext); virtual void unload(); - virtual void render(const RenderContext* renderContext); + virtual void render(RenderContext* renderContext); inline void setShadowMap(GLuint shadowMap) { this->shadowMap = shadowMap; } inline void setShadowCamera(const Camera* camera) { this->shadowCamera = camera; } private: + class RenderOpCompare + { + public: + // Sort render opations + bool operator()(const RenderOperation& opA, const RenderOperation& opB) const; + }; + bool loadShader(const RenderOperation& operation); ShaderParameterSet parameterSet; @@ -173,7 +180,7 @@ public: DebugRenderPass(); virtual bool load(const RenderContext* renderContext); virtual void unload(); - virtual void render(const RenderContext* renderContext); + virtual void render(RenderContext* renderContext); //void setDrawBounds(bool enabled); //void setDrawSkeletons(bool enabled); @@ -203,7 +210,7 @@ public: UIRenderPass(); virtual bool load(const RenderContext* renderContext); virtual void unload(); - virtual void render(const RenderContext* renderContext); + virtual void render(RenderContext* renderContext); private: ShaderParameterSet parameterSet; @@ -226,7 +233,7 @@ public: VignetteRenderPass(); virtual bool load(const RenderContext* renderContext); virtual void unload(); - virtual void render(const RenderContext* renderContext); + virtual void render(RenderContext* renderContext); private: ShaderParameterSet parameterSet; @@ -249,7 +256,7 @@ public: inline void setCubemap(Texture* cubemap) { this->cubemap = cubemap; } virtual bool load(const RenderContext* renderContext); virtual void unload(); - virtual void render(const RenderContext* renderContext); + virtual void render(RenderContext* renderContext); private: ShaderParameterSet parameterSet; diff --git a/src/states/loading-state.cpp b/src/states/loading-state.cpp index 1ddae14..591d2e7 100644 --- a/src/states/loading-state.cpp +++ b/src/states/loading-state.cpp @@ -56,8 +56,8 @@ void LoadingState::enter() std::cout << "success" << std::endl; } - std::cout << "Loading UI... "; - if (!application->loadUI()) + std::cout << "Loading models... "; + if (!application->loadModels()) { std::cout << "failed" << std::endl; failure = true; @@ -67,8 +67,8 @@ void LoadingState::enter() std::cout << "success" << std::endl; } - std::cout << "Loading models... "; - if (!application->loadModels()) + std::cout << "Loading game... "; + if (!application->loadGame()) { std::cout << "failed" << std::endl; failure = true; @@ -78,8 +78,8 @@ void LoadingState::enter() std::cout << "success" << std::endl; } - std::cout << "Loading game... "; - if (!application->loadGame()) + std::cout << "Loading UI... "; + if (!application->loadUI()) { std::cout << "failed" << std::endl; failure = true; diff --git a/src/states/play-state.cpp b/src/states/play-state.cpp index 18650c3..e782aeb 100644 --- a/src/states/play-state.cpp +++ b/src/states/play-state.cpp @@ -51,6 +51,7 @@ void PlayState::enter() // Add tools to scene application->defaultLayer->addObject(application->forceps->getModelInstance()); + application->defaultLayer->addObject(application->lens->getModelInstance()); // Add terrain to scene application->defaultLayer->addObject(&application->currentLevel->terrainSurface); @@ -196,8 +197,11 @@ void PlayState::execute() } // Update tools - application->forceps->setPick(pick); - application->forceps->update(application->dt); + if (application->currentTool != nullptr) + { + application->currentTool->setPick(pick); + application->currentTool->update(application->dt); + } // Update colony if (!application->simulationPaused) @@ -229,6 +233,7 @@ void PlayState::exit() application->defaultLayer->removeObject(&application->currentLevel->terrainSubsurface); application->defaultLayer->removeObject(&application->biomeFloorModelInstance); application->defaultLayer->removeObject(application->forceps->getModelInstance()); + application->defaultLayer->removeObject(application->lens->getModelInstance()); for (std::size_t i = 0; i < application->colony->getAntCount(); ++i) { Ant* ant = application->colony->getAnt(i); @@ -251,7 +256,7 @@ void PlayState::exit() void PlayState::mouseButtonPressed(int button, int x, int y) { - if (button == 1) + if (button == 1 && application->forceps->isActive()) { application->forceps->pinch(); } @@ -259,7 +264,7 @@ void PlayState::mouseButtonPressed(int button, int x, int y) void PlayState::mouseButtonReleased(int button, int x, int y) { - if (button == 1) + if (button == 1 && application->forceps->isActive()) { application->forceps->release(); }