/* * Copyright (C) 2017-2019 Christopher J. Howard * * This file is part of Antkeeper Source Code. * * Antkeeper Source Code is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Antkeeper Source Code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Antkeeper Source Code. If not, see . */ #include "lens.hpp" #include "camera-rig.hpp" #include "../entity/systems/particle-system.hpp" Lens::Lens(const Model* model, Animator* animator): wasActive(false), particleSystem(nullptr) { // Setup model instance modelInstance.setModel(model); modelInstance.setCullingEnabled(false); // Setup spotlight spotlight.setColor(Vector3(1.0f)); spotlight.setIntensity(1000.0f); spotlight.setAttenuation(Vector3(1, 0, 1)); spotlight.setCutoff(std::cos(glm::radians(45.0f))); spotlight.setExponent(150.0f); spotlight.setActive(false); unfocusedDistance = 18.0f; unfocusDuration = 0.25f; focusedDistance = 12.0f; focusDuration = 0.75f; lensDistance = unfocusedDistance; focused = false; lastDistance = unfocusedDistance; sunDirection = Vector3(0, -1, 0); // Construct focus animation clip AnimationChannel* channel; focusClip.setInterpolator(easeOutCubic); channel = focusClip.addChannel(0); channel->insertKeyframe(0.0f, 0.0f); channel->insertKeyframe(focusDuration, 1.0f); // Construct unfocus animation clip unfocusClip.setInterpolator(easeOutCubic); channel = unfocusClip.addChannel(0); channel->insertKeyframe(0.0f, 0.0f); channel->insertKeyframe(unfocusDuration, 1.0f); // Setup focus animation callbacks focusAnimation.setTimeFrame(focusClip.getTimeFrame()); focusAnimation.setClip(&focusClip); focusAnimation.setAnimateCallback ( [this](std::size_t id, float distance) { this->lensDistance = lerp(lastDistance, focusedDistance, distance); } ); focusAnimation.setEndCallback ( [this]() { this->focused = true; } ); // Setup unfocus animation callbacks unfocusAnimation.setTimeFrame(unfocusClip.getTimeFrame()); unfocusAnimation.setClip(&unfocusClip); unfocusAnimation.setAnimateCallback ( [this](std::size_t id, float distance) { this->lensDistance = lerp(lastDistance, unfocusedDistance, distance); } ); // Add animations to animator animator->addAnimation(&focusAnimation); animator->addAnimation(&unfocusAnimation); } Lens::~Lens() {} void Lens::update(float dt) { //Quaternion alignment = glm::rotation(Vector3(0, 1, 0), -sunDirection) * glm::angleAxis(glm::radians(90.0f), Vector3(0, 1, 0)); Quaternion alignment = glm::rotation(Vector3(0, 1, 0), -sunDirection) * glm::angleAxis(orbitCam->getAzimuth() + glm::radians(90.0f), Vector3(0, 1, 0)); Quaternion rotation = glm::normalize(alignment); Vector3 translation = pick + sunDirection * -lensDistance; modelInstance.setTranslation(translation); modelInstance.setRotation(rotation); float t = (1.0 - (lensDistance - focusedDistance) / (unfocusedDistance - focusedDistance)); float unfocusedIntensity = 250.0f * 2.0f; float focusedIntensity = 1000.0f * 2.0f; float intensity = easeInExpo(unfocusedIntensity, focusedIntensity, t); float unfocusedExponent = 100.0f; float focusedExponent = 5000.0f; float exponent = easeInExpo(unfocusedExponent, focusedExponent, t); spotlight.setIntensity(intensity); spotlight.setExponent(exponent); spotlight.setTranslation(pick + sunDirection * -lensDistance); spotlight.setDirection(sunDirection); if (active && !wasActive) { modelInstance.resetTweens(); spotlight.resetTweens(); modelInstance.setActive(true); spotlight.setActive(true); } else if (!active && wasActive) { modelInstance.setActive(false); spotlight.setActive(false); } if (active && focused) { int count = 10; for (int i = 0; i < count; ++i) particleSystem->emit(pick); } wasActive = active; } void Lens::focus() { lastDistance = lensDistance; unfocusAnimation.stop(); focusAnimation.rewind(); focusAnimation.play(); } void Lens::unfocus() { lastDistance = lensDistance; focusAnimation.stop(); unfocusAnimation.rewind(); unfocusAnimation.play(); focused = false; } void Lens::setSunDirection(const Vector3& direction) { sunDirection = direction; } void Lens::setParticleSystem(ParticleSystem* particleSystem) { this->particleSystem = particleSystem; }