diff --git a/data b/data index c3fb5da..80851f2 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit c3fb5da7ac7e7cf776dd00296ecb865fcf4b7b1e +Subproject commit 80851f29bad4062b4505549f572f853db7c50983 diff --git a/src/application.cpp b/src/application.cpp index fd8ecea..a7b483d 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -558,14 +558,13 @@ int Application::execute() // Update frame time label if (frameTimeLabel->isVisible()) { - /* - std::u32string frameTimeString; - std::basic_stringstream stream; + std::u32string label; + std::stringstream stream; stream.precision(2); stream << std::fixed << meanFrameTime; - stream >> frameTimeString; - frameTimeLabel->setText(frameTimeString); - */ + std::string streamstring = stream.str(); + label.assign(streamstring.begin(), streamstring.end()); + frameTimeLabel->setText(label); } } @@ -773,6 +772,7 @@ bool Application::loadScene() // Unbind shadow map depth texture glBindTexture(GL_TEXTURE_2D, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); // Setup shadow map render target shadowMapRenderTarget.width = shadowMapResolution; @@ -788,23 +788,109 @@ bool Application::loadScene() shadowMapCompositor.addPass(&shadowMapPass); shadowMapCompositor.load(nullptr); + // Post-processing framebuffers + { + // Generate color texture + glGenTextures(1, &framebufferAColorTexture); + glBindTexture(GL_TEXTURE_2D, framebufferAColorTexture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, static_cast(resolution.x), static_cast(resolution.y), 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + // Generate depth texture + glGenTextures(1, &framebufferADepthTexture); + glBindTexture(GL_TEXTURE_2D, framebufferADepthTexture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, static_cast(resolution.x), static_cast(resolution.y), 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS); + //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); + + // Generate framebuffer + glGenFramebuffers(1, &framebufferA); + glBindFramebuffer(GL_FRAMEBUFFER, framebufferA); + + // Attach textures to framebuffer + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, framebufferAColorTexture, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, framebufferADepthTexture, 0); + glDrawBuffer(GL_COLOR_ATTACHMENT0); + //glReadBuffer(GL_COLOR_ATTACHMENT0); + + // Unbind framebuffer and texture + glBindTexture(GL_TEXTURE_2D, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + // Setup render target + framebufferARenderTarget.width = static_cast(resolution.x); + framebufferARenderTarget.height = static_cast(resolution.y); + framebufferARenderTarget.framebuffer = framebufferA; + } + + { + // Generate color texture + glGenTextures(1, &framebufferBColorTexture); + glBindTexture(GL_TEXTURE_2D, framebufferBColorTexture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, static_cast(resolution.x), static_cast(resolution.y), 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + // Generate framebuffer + glGenFramebuffers(1, &framebufferA); + glBindFramebuffer(GL_FRAMEBUFFER, framebufferA); + + // Attach textures to framebuffer + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, framebufferBColorTexture, 0); + glDrawBuffer(GL_COLOR_ATTACHMENT0); + //glReadBuffer(GL_COLOR_ATTACHMENT0); + + // Unbind framebuffer and texture + glBindTexture(GL_TEXTURE_2D, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + // Setup render target + framebufferBRenderTarget.width = static_cast(resolution.x); + framebufferBRenderTarget.height = static_cast(resolution.y); + framebufferBRenderTarget.framebuffer = framebufferA; + } + // Setup skybox pass - skyboxPass.setRenderTarget(&defaultRenderTarget); + skyboxPass.setRenderTarget(&framebufferARenderTarget); // Setup clear depth pass - clearDepthPass.setRenderTarget(&defaultRenderTarget); + clearDepthPass.setRenderTarget(&framebufferARenderTarget); clearDepthPass.setClear(false, true, false); clearDepthPass.setClearDepth(1.0f); // Setup soil pass - soilPass.setRenderTarget(&defaultRenderTarget); + soilPass.setRenderTarget(&framebufferARenderTarget); // Setup lighting pass - lightingPass.setRenderTarget(&defaultRenderTarget); + lightingPass.setRenderTarget(&framebufferARenderTarget); lightingPass.setShadowMap(shadowMapDepthTexture); lightingPass.setShadowCamera(&sunlightCamera); lightingPass.setShadowMapPass(&shadowMapPass); + // Setup blur passes + horizontalBlurPass.setRenderTarget(&framebufferBRenderTarget); + horizontalBlurPass.setTexture(framebufferAColorTexture); + horizontalBlurPass.setDirection(Vector2(0.0f, 0.0f)); + verticalBlurPass.setRenderTarget(&framebufferARenderTarget); + verticalBlurPass.setTexture(framebufferBColorTexture); + verticalBlurPass.setDirection(Vector2(0.0f, 0.0f)); + horizontalBlurPass2.setRenderTarget(&framebufferBRenderTarget); + horizontalBlurPass2.setTexture(framebufferAColorTexture); + horizontalBlurPass2.setDirection(Vector2(0.0f, 0.0f)); + verticalBlurPass2.setRenderTarget(&defaultRenderTarget); + verticalBlurPass2.setTexture(framebufferBColorTexture); + verticalBlurPass2.setDirection(Vector2(0.0f, 0.0f)); + + // Setup debug pass debugPass.setRenderTarget(&defaultRenderTarget); @@ -812,6 +898,10 @@ bool Application::loadScene() defaultCompositor.addPass(&skyboxPass); defaultCompositor.addPass(&soilPass); defaultCompositor.addPass(&lightingPass); + defaultCompositor.addPass(&horizontalBlurPass); + defaultCompositor.addPass(&verticalBlurPass); + defaultCompositor.addPass(&horizontalBlurPass2); + defaultCompositor.addPass(&verticalBlurPass2); //defaultCompositor.addPass(&debugPass); defaultCompositor.load(nullptr); @@ -959,10 +1049,17 @@ bool Application::loadUI() // Create "Press any key" element anyKeyLabel = new UILabel(); - + anyKeyLabel->setLayerOffset(ANTKEEPER_UI_LAYER_MENU); anyKeyLabel->setVisible(false); uiRootElement->addChild(anyKeyLabel); + // Create copyright element + copyrightLabel = new UILabel(); + copyrightLabel->setLayerOffset(ANTKEEPER_UI_LAYER_MENU); + copyrightLabel->setVisible(false); + copyrightLabel->setTintColor(Vector4(1.0f, 1.0f, 1.0f, 0.15f)); + uiRootElement->addChild(copyrightLabel); + rectangularPaletteImage = new UIImage(); rectangularPaletteImage->setTexture(rectangularPaletteTexture); rectangularPaletteImage->setVisible(false); @@ -1017,13 +1114,52 @@ bool Application::loadUI() pieMenu->getContainer()->setActive(true); // Setup screen fade in/fade out tween - fadeInTween = new Tween(EaseFunction::IN_CUBIC, 0.0f, 2.0f, Vector4(0.0f, 0.0f, 0.0f, 1.0f), Vector4(0.0f, 0.0f, 0.0f, -1.0f)); + fadeInTween = new Tween(EaseFunction::IN_QUINT, 0.0f, 2.0f, Vector4(0.0f, 0.0f, 0.0f, 1.0f), Vector4(0.0f, 0.0f, 0.0f, -1.0f)); fadeInTween->setUpdateCallback(std::bind(&UIElement::setTintColor, blackoutImage, std::placeholders::_1)); tweener->addTween(fadeInTween); - fadeOutTween = new Tween(EaseFunction::OUT_CUBIC, 0.0f, 2.0f, Vector4(0.0f, 0.0f, 0.0f, 0.0f), Vector4(0.0f, 0.0f, 0.0f, 1.0f)); + fadeOutTween = new Tween(EaseFunction::OUT_QUINT, 0.0f, 2.0f, Vector4(0.0f, 0.0f, 0.0f, 0.0f), Vector4(0.0f, 0.0f, 0.0f, 1.0f)); fadeOutTween->setUpdateCallback(std::bind(&UIElement::setTintColor, blackoutImage, std::placeholders::_1)); tweener->addTween(fadeOutTween); + // Setup darken fade in/fade out tweens + darkenFadeInTween = new Tween(EaseFunction::OUT_CUBIC, 0.0f, 0.15f, Vector4(0.0f, 0.0f, 0.0f, 0.0f), Vector4(0.0f, 0.0f, 0.0f, 0.4f)); + darkenFadeInTween->setStartCallback(std::bind(&UIElement::setVisible, darkenImage, true)); + darkenFadeInTween->setUpdateCallback(std::bind(&UIElement::setTintColor, darkenImage, std::placeholders::_1)); + tweener->addTween(darkenFadeInTween); + darkenFadeOutTween = new Tween(EaseFunction::OUT_CUBIC, 0.0f, 0.15f, Vector4(0.0f, 0.0f, 0.0f, 0.4f), Vector4(0.0f, 0.0f, 0.0f, -0.4f)); + darkenFadeOutTween->setUpdateCallback(std::bind(&UIElement::setTintColor, darkenImage, std::placeholders::_1)); + darkenFadeOutTween->setEndCallback(std::bind(&UIElement::setVisible, darkenImage, false)); + tweener->addTween(darkenFadeOutTween); + + // Setup blur fade in/fade out tweens + blurFadeInTween = new Tween(EaseFunction::OUT_CUBIC, 0.0f, 0.15f, 0.0f, 1.0f); + blurFadeInTween->setUpdateCallback + ( + [this](float t) + { + float factor = blurFadeInTween->getTweenValue(); + horizontalBlurPass.setDirection(Vector2(1.0f, 0.0f) * t); + horizontalBlurPass2.setDirection(Vector2(3.0f, 0.0f) * t); + verticalBlurPass.setDirection(Vector2(0.0f, 1.0f) * t); + verticalBlurPass2.setDirection(Vector2(0.0f, 3.0f) * t); + } + ); + tweener->addTween(blurFadeInTween); + + blurFadeOutTween = new Tween(EaseFunction::OUT_CUBIC, 0.0f, 0.15f, 1.0f, -1.0f); + blurFadeOutTween->setUpdateCallback + ( + [this](float t) + { + float factor = blurFadeInTween->getTweenValue(); + horizontalBlurPass.setDirection(Vector2(1.0f, 0.0f) * t); + horizontalBlurPass2.setDirection(Vector2(3.0f, 0.0f) * t); + verticalBlurPass.setDirection(Vector2(0.0f, 1.0f) * t); + verticalBlurPass2.setDirection(Vector2(0.0f, 3.0f) * t); + } + ); + tweener->addTween(blurFadeOutTween); + // Setup splash screen tween splashFadeInTween = new Tween(EaseFunction::IN_CUBIC, 0.0f, 0.5f, Vector4(1.0f, 1.0f, 1.0f, 0.0f), Vector4(0.0f, 0.0f, 0.0f, 1.0f)); splashFadeInTween->setUpdateCallback(std::bind(&UIElement::setTintColor, splashImage, std::placeholders::_1)); @@ -1097,6 +1233,9 @@ bool Application::loadUI() mainMenu->getUIContainer()->setAnchor(Vector2(0.5f, 0.8f)); mainMenu->getUIContainer()->setLayerOffset(ANTKEEPER_UI_LAYER_MENU); mainMenu->setLineSpacing(1.0f); + mainMenu->getUIContainer()->setActive(false); + mainMenu->getUIContainer()->setVisible(false); + uiRootElement->addChild(mainMenu->getUIContainer()); mainMenuContinueItem = mainMenu->addItem(); mainMenuContinueItem->setActivatedCallback(std::bind(&Application::continueGame, this)); @@ -1122,10 +1261,6 @@ bool Application::loadUI() mainMenuExitItem = mainMenu->addItem(); mainMenuExitItem->setActivatedCallback(std::bind(&Application::close, this, EXIT_SUCCESS)); - - mainMenu->getUIContainer()->setActive(false); - mainMenu->getUIContainer()->setVisible(false); - uiRootElement->addChild(mainMenu->getUIContainer()); } // Levels menu @@ -1454,6 +1589,7 @@ bool Application::loadGame() lens = new Lens(lensModel); lens->setCameraController(surfaceCam); + lens->setSunDirection(glm::normalize(-sunlightCamera.getTranslation())); brush = new Brush(brushModel); brush->setCameraController(surfaceCam); @@ -1487,6 +1623,10 @@ void Application::resizeUI() frameTimeLabel->setTranslation(Vector2(0.0f)); anyKeyLabel->setAnchor(Vector2(0.5f, 1.0f)); anyKeyLabel->setTranslation(Vector2(0.0f, (int)(-resolution.y * (1.0f / 4.0f) - menuFont->getMetrics().getHeight() * 0.5f))); + + copyrightLabel->setAnchor(Vector2(0.0f, 1.0f)); + copyrightLabel->setTranslation(Vector2(resolution.x, -resolution.y) * 0.02f); + rectangularPaletteImage->setAnchor(Vector2(0.0f, 1.0f)); rectangularPaletteImage->setDimensions(Vector2(rectangularPaletteTexture->getWidth(), rectangularPaletteTexture->getHeight())); rectangularPaletteImage->setTranslation(Vector2(16.0f, -16.0f)); @@ -1581,6 +1721,7 @@ void Application::restringUI() levelNameLabel->setFont(levelNameFont); frameTimeLabel->setFont(copyrightFont); anyKeyLabel->setFont(menuFont); + copyrightLabel->setFont(copyrightFont); mainMenu->setFont(menuFont); levelsMenu->setFont(menuFont); optionsMenu->setFont(menuFont); @@ -1589,6 +1730,7 @@ void Application::restringUI() // Title screen anyKeyLabel->setText(stringMap["press-any-key"]); + copyrightLabel->setText(stringMap["copyright"]); // Main menu mainMenuContinueItem->setName(stringMap["continue"]); @@ -1921,7 +2063,13 @@ void Application::pauseSimulation() { simulationPaused = true; - darkenImage->setVisible(true); + darkenFadeOutTween->stop(); + darkenFadeInTween->reset(); + darkenFadeInTween->start(); + + blurFadeOutTween->stop(); + blurFadeInTween->reset(); + blurFadeInTween->start(); openMenu(pauseMenu); pauseMenu->select(0); @@ -1931,7 +2079,13 @@ void Application::unpauseSimulation() { simulationPaused = false; - darkenImage->setVisible(false); + darkenFadeInTween->stop(); + darkenFadeOutTween->reset(); + darkenFadeOutTween->start(); + + blurFadeInTween->stop(); + blurFadeOutTween->reset(); + blurFadeOutTween->start(); closeMenu(); } diff --git a/src/application.hpp b/src/application.hpp index cf2e4b9..74bb643 100644 --- a/src/application.hpp +++ b/src/application.hpp @@ -178,6 +178,16 @@ public: ShadowMapRenderPass shadowMapPass; Compositor shadowMapCompositor; + GLuint framebufferAColorTexture; + GLuint framebufferADepthTexture; + GLuint framebufferA; + RenderTarget framebufferARenderTarget; + + GLuint framebufferBColorTexture; + GLuint framebufferBDepthTexture; + GLuint framebufferB; + RenderTarget framebufferBRenderTarget; + ClearRenderPass clearDepthPass; SoilRenderPass soilPass; LightingRenderPass lightingPass; @@ -194,6 +204,10 @@ public: TextureLoader* textureLoader; MaterialLoader* materialLoader; ModelLoader* modelLoader; + BlurRenderPass horizontalBlurPass; + BlurRenderPass verticalBlurPass; + BlurRenderPass horizontalBlurPass2; + BlurRenderPass verticalBlurPass2; // Controls Control* bindingControl; @@ -277,7 +291,8 @@ public: UIImage* titleImage; UIImage* darkenImage; UILabel* frameTimeLabel; - UILabel* anyKeyLabel; + UILabel* anyKeyLabel; + UILabel* copyrightLabel; UIImage* rectangularPaletteImage; UIImage* foodIndicatorImage; UIImage* contextButtonImage0; @@ -291,9 +306,13 @@ public: Tweener* tweener; Tween* fadeInTween; Tween* fadeOutTween; + Tween* darkenFadeInTween; + Tween* darkenFadeOutTween; + Tween* blurFadeInTween; + Tween* blurFadeOutTween; Tween* splashFadeInTween; - Tween* splashHangTween; Tween* splashFadeOutTween; + Tween* splashHangTween; Tween* titleFadeInTween; Tween* titleFadeOutTween; Tween* anyKeyFadeInTween; @@ -303,6 +322,7 @@ public: Tween* menuActivateTween; Tween* cameraTranslationTween; Tween* forcepsSwoopTween; + // Menus Menu* activeMenu; diff --git a/src/game/tool.cpp b/src/game/tool.cpp index dcdb166..9244e14 100644 --- a/src/game/tool.cpp +++ b/src/game/tool.cpp @@ -349,11 +349,36 @@ Lens::Lens(const Model* model) // Setup model instance modelInstance.setModel(model); - hoverDistance = 12.0f; + unfocusedDistance = 15.0f; + focusedDistance = 12.0f; + focused = false; + sunDirection = Vector3(0, -1, 0); + + // Setup timing + float descentDuration = 0.75f; + float ascentDuration = 0.25f; + + // Allocate tweener and and setup tweens + tweener = new Tweener(); + descentTween = new Tween(EaseFunction::OUT_CUBIC, 0.0f, descentDuration, unfocusedDistance, focusedDistance - unfocusedDistance); + ascentTween = new Tween(EaseFunction::OUT_CUBIC, 0.0f, ascentDuration, focusedDistance, unfocusedDistance - focusedDistance); + descentTween->setEndCallback + ( + [this](float t) + { + focused = true; + } + ); + tweener->addTween(descentTween); + tweener->addTween(ascentTween); } Lens::~Lens() -{} +{ + delete descentTween; + delete ascentTween; + delete tweener; +} void Lens::update(float dt) { @@ -375,14 +400,48 @@ void Lens::update(float dt) */ modelInstance.setActive(active); - Quaternion alignment = glm::angleAxis(cameraController->getAzimuth() + glm::radians(90.0f), Vector3(0, 1, 0)); + // Update tweener + tweener->update(dt); + + float lensDistance = (focused) ? focusedDistance : unfocusedDistance; + if (!ascentTween->isStopped()) + { + lensDistance = ascentTween->getTweenValue(); + } + else if (!descentTween->isStopped()) + { + lensDistance = descentTween->getTweenValue(); + } + + //Quaternion alignment = glm::angleAxis(cameraController->getAzimuth() + glm::radians(90.0f), Vector3(0, 1, 0)); + Quaternion alignment = glm::rotation(Vector3(0, 1, 0), -sunDirection) * glm::angleAxis(glm::radians(90.0f), Vector3(0, 1, 0)); Quaternion rotation = glm::normalize(alignment); - Vector3 translation = pick + Vector3(0, hoverDistance, 0); + Vector3 translation = pick + sunDirection * -lensDistance; modelInstance.setTranslation(translation); modelInstance.setRotation(rotation); } +void Lens::focus() +{ + ascentTween->stop(); + descentTween->reset(); + descentTween->start(); +} + +void Lens::unfocus() +{ + descentTween->stop(); + focused = false; + ascentTween->reset(); + ascentTween->start(); +} + +void Lens::setSunDirection(const Vector3& direction) +{ + sunDirection = direction; +} + Brush::Brush(const Model* model) { // Allocate pose and initialize to bind pose @@ -394,22 +453,106 @@ Brush::Brush(const Model* model) modelInstance.setModel(model); modelInstance.setPose(pose); - hoverDistance = 0.0f; + hoverDistance = 0.5f; + + // Setup timing + float descentDuration = 0.1f; + float ascentDuration = 0.1f; + + // Allocate tweener and and setup tweens + tweener = new Tweener(); + descentTween = new Tween(EaseFunction::OUT_CUBIC, 0.0f, descentDuration, hoverDistance, -hoverDistance); + ascentTween = new Tween(EaseFunction::OUT_CUBIC, 0.0f, ascentDuration, 0.0f, hoverDistance); + descentTween->setEndCallback + ( + [this](float t) + { + descended = true; + } + ); + tweener->addTween(descentTween); + tweener->addTween(ascentTween); + descended = false; + + oldPick = pick; + tiltAngle = 0.0f; + targetTiltAngle = 0.0f; + tiltAxis = Vector3(1.0f, 0.0f, 0.0f); + targetTiltAxis = tiltAxis; } Brush::~Brush() { delete pose; + delete descentTween; + delete ascentTween; + delete tweener; } void Brush::update(float dt) { modelInstance.setActive(active); + // Update tweener + tweener->update(dt); + + float brushDistance = (descended) ? 0.0f : hoverDistance; + if (!ascentTween->isStopped()) + { + brushDistance = ascentTween->getTweenValue(); + } + else if (!descentTween->isStopped()) + { + brushDistance = descentTween->getTweenValue(); + } + + targetTiltAngle = 0.0f; + if (descended) + { + Vector3 difference = pick - oldPick; + float distanceSquared = glm::dot(difference, difference); + + if (distanceSquared > 0.005f) + { + float maxDistance = 0.25f; + float maxTiltAngle = glm::radians(45.0f); + float distance = std::sqrt(distanceSquared); + float tiltFactor = std::min(maxDistance, distance) / maxDistance; + + targetTiltAngle = maxTiltAngle * tiltFactor; + targetTiltAxis = glm::normalize(Vector3(difference.z, 0.0f, -difference.x)); + } + } + + float angleInterpolationFactor = 0.1f / (1.0 / 60.0f) * dt; + float axisInterpolationFactor = 0.2f / (1.0 / 60.0f) * dt; + tiltAngle = glm::mix(tiltAngle, targetTiltAngle, angleInterpolationFactor); + tiltAxis = glm::mix(tiltAxis, targetTiltAxis, axisInterpolationFactor); + + Quaternion tilt = glm::angleAxis(tiltAngle, tiltAxis); + Quaternion alignment = glm::angleAxis(cameraController->getAzimuth(), Vector3(0, 1, 0)); - Quaternion rotation = glm::normalize(alignment); - Vector3 translation = pick + Vector3(0, hoverDistance, 0); + Quaternion rotation = glm::normalize(tilt); + Vector3 translation = pick + Vector3(0, brushDistance, 0); modelInstance.setTranslation(translation); modelInstance.setRotation(rotation); + + oldPick = pick; +} + +void Brush::press() +{ + ascentTween->stop(); + descentTween->reset(); + descentTween->start(); + +} + +void Brush::release() +{ + descentTween->stop(); + descended = false; + ascentTween->reset(); + ascentTween->start(); } diff --git a/src/game/tool.hpp b/src/game/tool.hpp index e4234e0..5de2733 100644 --- a/src/game/tool.hpp +++ b/src/game/tool.hpp @@ -223,8 +223,19 @@ public: */ virtual void update(float dt); + void focus(); + void unfocus(); + + void setSunDirection(const Vector3& direction); + private: - float hoverDistance; + float unfocusedDistance; + float focusedDistance; + bool focused; + Vector3 sunDirection; + Tweener* tweener; + Tween* descentTween; + Tween* ascentTween; }; /** @@ -238,9 +249,22 @@ public: virtual void update(float dt); + void press(); + void release(); + private: Pose* pose; float hoverDistance; + bool descended; + Vector3 oldPick; + + Tweener* tweener; + Tween* descentTween; + Tween* ascentTween; + float tiltAngle; + float targetTiltAngle; + Vector3 tiltAxis; + Vector3 targetTiltAxis; }; #endif // TOOL_HPP diff --git a/src/render-passes.cpp b/src/render-passes.cpp index 84ff400..5615e5c 100644 --- a/src/render-passes.cpp +++ b/src/render-passes.cpp @@ -87,6 +87,105 @@ void ClearRenderPass::setClearStencil(int index) this->index = index; } +BlurRenderPass::BlurRenderPass(): + textureID(0) +{ + textureParam = parameterSet.addParameter("blurTexture", ShaderParameter::Type::INT, 1); + resolutionParam = parameterSet.addParameter("resolution", ShaderParameter::Type::VECTOR_2, 1); + directionParam = parameterSet.addParameter("direction", ShaderParameter::Type::VECTOR_2, 1); +} + +bool BlurRenderPass::load(const RenderContext* renderContext) +{ + // Load shader + shaderLoader.undefine(); + shaderLoader.define("VERTEX_POSITION", EMERGENT_VERTEX_POSITION); + shader = shaderLoader.load("data/shaders/blur.glsl", ¶meterSet); + if (!shader) + { + return false; + } + + const float quadVertexData[] = + { + -1.0f, 1.0f, 0.0f, + -1.0f, -1.0f, 0.0f, + 1.0f, -1.0f, 0.0f, + 1.0f, 1.0f, 0.0f + }; + + const std::uint32_t quadIndexData[] = + { + 0, 1, 3, + 3, 1, 2 + }; + + quadVertexCount = 4; + quadIndexCount = 6; + + // Create AABB geometry + glGenVertexArrays(1, &quadVAO); + glBindVertexArray(quadVAO); + glGenBuffers(1, &quadVBO); + glBindBuffer(GL_ARRAY_BUFFER, quadVBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * quadVertexCount, quadVertexData, GL_STATIC_DRAW); + glEnableVertexAttribArray(EMERGENT_VERTEX_POSITION); + glVertexAttribPointer(EMERGENT_VERTEX_POSITION, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (char*)0 + 0*sizeof(float)); + glGenBuffers(1, &quadIBO); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quadIBO); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(std::uint32_t) * quadIndexCount, quadIndexData, GL_STATIC_DRAW); + + return true; +} + +void BlurRenderPass::unload() +{ + delete shader; + shader = nullptr; + + glDeleteBuffers(1, &quadIBO); + glDeleteBuffers(1, &quadVBO); + glDeleteVertexArrays(1, &quadVAO); + + parameterSet.removeParameters(); +} + +void BlurRenderPass::render(RenderContext* renderContext) +{ + // Bind framebuffer and setup viewport + glBindFramebuffer(GL_FRAMEBUFFER, renderTarget->framebuffer); + glViewport(0, 0, renderTarget->width, renderTarget->height); + + // Clear the framebuffer + glClear(GL_COLOR_BUFFER_BIT); + + // Disable depth testing + glDisable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); + + // Disable culling + glDisable(GL_CULL_FACE); + + // Bind shader + shader->bind(); + + // Bind texture + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, textureID); + + // Pass texture unit to shader + shader->setParameter(textureParam, 0); + shader->setParameter(resolutionParam, Vector2(renderTarget->width, renderTarget->height)); + shader->setParameter(directionParam, direction); + + // Render quad + glBindVertexArray(quadVAO); + glDrawElementsBaseVertex(GL_TRIANGLES, quadIndexCount, GL_UNSIGNED_INT, (void*)0, 0); + + // Unbind texture + glBindTexture(GL_TEXTURE_2D, 0); +} + ShadowMapRenderPass::ShadowMapRenderPass(): unskinnedShader(nullptr), skinnedShader(nullptr), @@ -197,14 +296,14 @@ void ShadowMapRenderPass::render(RenderContext* renderContext) glBindFramebuffer(GL_FRAMEBUFFER, renderTarget->framebuffer); glViewport(0, 0, renderTarget->width, renderTarget->height); - // Clear the framebuffer depth - glClear(GL_DEPTH_BUFFER_BIT); - // Enable depth testing glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); glDepthFunc(GL_LESS); + // Clear the framebuffer depth + glClear(GL_DEPTH_BUFFER_BIT); + // Draw front and back faces glDisable(GL_CULL_FACE); diff --git a/src/render-passes.hpp b/src/render-passes.hpp index 607580e..56f43b2 100644 --- a/src/render-passes.hpp +++ b/src/render-passes.hpp @@ -51,6 +51,38 @@ private: int index; }; +/** + * Blurs a texture + */ +class BlurRenderPass: public RenderPass +{ +public: + BlurRenderPass(); + virtual bool load(const RenderContext* renderContext); + virtual void unload(); + virtual void render(RenderContext* renderContext); + + inline void setTexture(GLuint textureID) { this->textureID = textureID; } + inline void setDirection(Vector2 direction) { this->direction = direction; } + +private: + ShaderParameterSet parameterSet; + const ShaderParameter* textureParam; + const ShaderParameter* resolutionParam; + const ShaderParameter* directionParam; + ShaderLoader shaderLoader; + Shader* shader; + + GLuint textureID; + Vector2 direction; + + int quadVertexCount; + int quadIndexCount; + GLuint quadVAO; + GLuint quadVBO; + GLuint quadIBO; +}; + /** * Renders the distance from the view frustum's near clipping plane to scene geometry. The render target should have a depth only framebuffer. */ diff --git a/src/states/game-state.cpp b/src/states/game-state.cpp index 2facf9e..5ff9e3a 100644 --- a/src/states/game-state.cpp +++ b/src/states/game-state.cpp @@ -75,7 +75,7 @@ void GameState::enter() // Spawn ants Navmesh* navmesh = application->currentLevel->terrain.getSurfaceNavmesh(); - for (int i = 0; i < 50; ++i) + for (int i = 0; i < 200; ++i) { Navmesh::Triangle* triangle = (*navmesh->getTriangles())[0]; @@ -250,51 +250,50 @@ void GameState::execute() application->surfaceCam->update(application->dt); // Picking - glm::ivec2 mousePosition = application->mouse->getCurrentPosition(); - mousePosition.y = application->resolution.y - mousePosition.y; - Vector4 viewport(0.0f, 0.0f, application->resolution.x, application->resolution.y); - Vector3 mouseNear = application->camera.unproject(Vector3(mousePosition.x, mousePosition.y, 0.0f), viewport); - Vector3 mouseFar = application->camera.unproject(Vector3(mousePosition.x, mousePosition.y, 1.0f), viewport); - - pickingRay.origin = mouseNear; - pickingRay.direction = glm::normalize(mouseFar - mouseNear); - - std::list triangles; - application->currentLevel->terrain.getSurfaceOctree()->query(pickingRay, &triangles); - - auto result = intersects(pickingRay, triangles); - if (std::get<0>(result)) + if (!application->simulationPaused) { - pick = pickingRay.extrapolate(std::get<1>(result)); + glm::ivec2 mousePosition = application->mouse->getCurrentPosition(); + mousePosition.y = application->resolution.y - mousePosition.y; + Vector4 viewport(0.0f, 0.0f, application->resolution.x, application->resolution.y); + Vector3 mouseNear = application->camera.unproject(Vector3(mousePosition.x, mousePosition.y, 0.0f), viewport); + Vector3 mouseFar = application->camera.unproject(Vector3(mousePosition.x, mousePosition.y, 1.0f), viewport); - std::size_t triangleIndex = std::get<3>(result); - pickTriangle = (*application->currentLevel->terrain.getSurfaceNavmesh()->getTriangles())[triangleIndex]; + pickingRay.origin = mouseNear; + pickingRay.direction = glm::normalize(mouseFar - mouseNear); - /* - float forcepsDistance = application->forcepsSwoopTween->getTweenValue(); + std::list triangles; + application->currentLevel->terrain.getSurfaceOctree()->query(pickingRay, &triangles); - //Quaternion rotation = glm::rotation(Vector3(0, 1, 0), triangle->normal); - Quaternion rotation = glm::angleAxis(application->surfaceCam->getAzimuth(), Vector3(0, 1, 0)) * - glm::angleAxis(glm::radians(15.0f), Vector3(0, 0, -1)); + auto result = intersects(pickingRay, triangles); + if (std::get<0>(result)) + { + pick = pickingRay.extrapolate(std::get<1>(result)); + + std::size_t triangleIndex = std::get<3>(result); + pickTriangle = (*application->currentLevel->terrain.getSurfaceNavmesh()->getTriangles())[triangleIndex]; + + /* + float forcepsDistance = application->forcepsSwoopTween->getTweenValue(); + + //Quaternion rotation = glm::rotation(Vector3(0, 1, 0), triangle->normal); + Quaternion rotation = glm::angleAxis(application->surfaceCam->getAzimuth(), Vector3(0, 1, 0)) * + glm::angleAxis(glm::radians(15.0f), Vector3(0, 0, -1)); + + Vector3 translation = pick + rotation * Vector3(0, forcepsDistance, 0); + + // Set tool position + application->forcepsModelInstance.setTranslation(translation); + application->forcepsModelInstance.setRotation(rotation); + */ + } - Vector3 translation = pick + rotation * Vector3(0, forcepsDistance, 0); + // Update tools + if (application->currentTool != nullptr) + { + application->currentTool->setPick(pick); + application->currentTool->update(application->dt); + } - // Set tool position - application->forcepsModelInstance.setTranslation(translation); - application->forcepsModelInstance.setRotation(rotation); - */ - } - - // Update tools - if (application->currentTool != nullptr) - { - application->currentTool->setPick(pick); - application->currentTool->update(application->dt); - } - - // Update colony - if (!application->simulationPaused) - { application->colony->update(application->dt); } } @@ -329,16 +328,39 @@ void GameState::exit() void GameState::mouseButtonPressed(int button, int x, int y) { - if (button == 1 && application->forceps->isActive()) + if (button == 1) { - application->forceps->pinch(); + if (application->forceps->isActive()) + { + application->forceps->pinch(); + } + else if (application->brush->isActive()) + { + application->brush->press(); + } + else if (application->lens->isActive()) + { + application->lens->focus(); + } } + } void GameState::mouseButtonReleased(int button, int x, int y) { - if (button == 1 && application->forceps->isActive()) + if (button == 1) { - application->forceps->release(); + if (application->forceps->isActive()) + { + application->forceps->release(); + } + else if (application->brush->isActive()) + { + application->brush->release(); + } + else if (application->lens->isActive()) + { + application->lens->unfocus(); + } } } diff --git a/src/states/title-state.cpp b/src/states/title-state.cpp index 77f43b0..6cd3cc7 100644 --- a/src/states/title-state.cpp +++ b/src/states/title-state.cpp @@ -40,7 +40,7 @@ void TitleState::enter() windowResized(application->resolution.x, application->resolution.y); application->camera.setPerspective( - glm::radians(25.0f), + glm::radians(30.0f), application->resolution.x / application->resolution.y, 0.1f, 1000.0f); @@ -63,9 +63,13 @@ void TitleState::enter() // Show title application->titleImage->setVisible(true); application->titleImage->setTintColor(Vector4(1.0f)); + application->copyrightLabel->setVisible(true); - // Open main menu - application->openMenu(application->mainMenu); + // Show "Press any key" + application->anyKeyLabel->setVisible(true); + application->anyKeyLabel->setActive(true); + application->anyKeyFadeInTween->reset(); + application->anyKeyFadeInTween->start(); // Position options menu application->optionsMenu->getUIContainer()->setAnchor(Vector2(0.5f, 0.8f)); @@ -79,60 +83,79 @@ void TitleState::enter() void TitleState::execute() { - // Navigate menu - if (application->activeMenu != nullptr) + if (application->anyKeyLabel->isActive()) { - MenuItem* selectedItem = application->activeMenu->getSelectedItem(); + InputEvent event; + application->inputManager->listen(&event); - if (application->menuDown.isTriggered() && !application->menuDown.wasTriggered()) + if (event.type != InputEvent::Type::NONE) + { + application->anyKeyLabel->setVisible(false); + application->anyKeyLabel->setActive(false); + application->anyKeyFadeInTween->stop(); + application->anyKeyFadeOutTween->stop(); + application->inputManager->update(); + + application->openMenu(application->mainMenu); + } + } + else + { + // Navigate menu + if (application->activeMenu != nullptr) { - if (selectedItem != nullptr) + MenuItem* selectedItem = application->activeMenu->getSelectedItem(); + + if (application->menuDown.isTriggered() && !application->menuDown.wasTriggered()) { - if (selectedItem->getItemIndex() < application->activeMenu->getItemCount() - 1) + if (selectedItem != nullptr) { - application->selectMenuItem(selectedItem->getItemIndex() + 1); + if (selectedItem->getItemIndex() < application->activeMenu->getItemCount() - 1) + { + application->selectMenuItem(selectedItem->getItemIndex() + 1); + } + else + { + application->selectMenuItem(0); + } } else { application->selectMenuItem(0); } } - else + else if (application->menuUp.isTriggered() && !application->menuUp.wasTriggered()) { - application->selectMenuItem(0); - } - } - else if (application->menuUp.isTriggered() && !application->menuUp.wasTriggered()) - { - if (selectedItem != nullptr) - { - if (selectedItem->getItemIndex() > 0) + if (selectedItem != nullptr) { - application->selectMenuItem(selectedItem->getItemIndex() - 1); + if (selectedItem->getItemIndex() > 0) + { + application->selectMenuItem(selectedItem->getItemIndex() - 1); + } + else + { + application->selectMenuItem(application->activeMenu->getItemCount() - 1); + } } else { application->selectMenuItem(application->activeMenu->getItemCount() - 1); } } - else + + if (application->menuLeft.isTriggered() && !application->menuLeft.wasTriggered()) { - application->selectMenuItem(application->activeMenu->getItemCount() - 1); + application->decrementMenuItem(); + } + else if (application->menuRight.isTriggered() && !application->menuRight.wasTriggered()) + { + application->incrementMenuItem(); + } + + if (application->menuSelect.isTriggered() && !application->menuSelect.wasTriggered()) + { + application->activateMenuItem(); } - } - - if (application->menuLeft.isTriggered() && !application->menuLeft.wasTriggered()) - { - application->decrementMenuItem(); - } - else if (application->menuRight.isTriggered() && !application->menuRight.wasTriggered()) - { - application->incrementMenuItem(); - } - - if (application->menuSelect.isTriggered() && !application->menuSelect.wasTriggered()) - { - application->activateMenuItem(); } } @@ -159,9 +182,9 @@ void TitleState::exit() // Hide UI application->titleImage->setVisible(false); + application->copyrightLabel->setVisible(false); application->anyKeyLabel->setVisible(false); application->darkenImage->setVisible(false); - // Remove clear scene application->backgroundLayer->removeObject(&application->bgCamera);