/*
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "sandbox-state.hpp"
|
|
#include "game.hpp"
|
|
#include "ui/ui.hpp"
|
|
#include "graphics/lighting-render-pass.hpp"
|
|
#include "game/camera-rig.hpp"
|
|
#include "game/tool.hpp"
|
|
#include "game/lens.hpp"
|
|
#include "game/forceps.hpp"
|
|
#include "game/brush.hpp"
|
|
#include <cmath>
|
|
|
|
SandboxState::SandboxState(Game* game):
|
|
GameState(game)
|
|
{}
|
|
|
|
SandboxState::~SandboxState()
|
|
{}
|
|
|
|
void SandboxState::enter()
|
|
{
|
|
// Subscribe this state to input events
|
|
game->getEventDispatcher()->subscribe<MouseMovedEvent>(this);
|
|
game->getEventDispatcher()->subscribe<MouseButtonPressedEvent>(this);
|
|
game->getEventDispatcher()->subscribe<MouseButtonReleasedEvent>(this);
|
|
|
|
// Make HUD visible
|
|
//game->hudContainer->setVisible(true);
|
|
game->radialMenuContainer->setVisible(false);
|
|
|
|
// Show mouse
|
|
//game->mouse->setVisible(false);
|
|
|
|
game->fadeIn(1.0f, Vector3(0.0f), nullptr);
|
|
|
|
Vector3 focalPoint = Vector3(0.0f);
|
|
float focalDistance = 5.0f;
|
|
float elevation = glm::radians(30.0f);
|
|
float azimuth = glm::radians(-45.0f);
|
|
|
|
toolIndex = 0;
|
|
//game->selectTool(toolIndex);
|
|
//game->currentTool->setActive(false);
|
|
game->mouse->warp(game->window, game->w / 2, game->h / 2);
|
|
|
|
zoom = 0.5f;
|
|
noPick = false;
|
|
|
|
//game->boxSelect(100, 100, 500, 300);
|
|
}
|
|
|
|
void SandboxState::execute()
|
|
{
|
|
game->lightingPass->setTime(game->time);
|
|
bool menuClosed = false;
|
|
|
|
if (game->changeToolControl.isActive() && !game->changeToolControl.wasActive())
|
|
{
|
|
game->radialMenuContainer->setVisible(true);
|
|
game->hudContainer->setVisible(false);
|
|
|
|
savedMousePosition = game->mouse->getCurrentPosition();
|
|
selectorVector = Vector2(0.0f);
|
|
game->mouse->setRelativeMode(true);
|
|
}
|
|
else if (!game->changeToolControl.isActive() && game->changeToolControl.wasActive())
|
|
{
|
|
game->radialMenuContainer->setVisible(false);
|
|
//game->hudContainer->setVisible(true);
|
|
game->mouse->setRelativeMode(false);
|
|
game->mouse->warp(game->window, std::get<0>(savedMousePosition), std::get<1>(savedMousePosition));
|
|
menuClosed = true;
|
|
|
|
game->selectTool(toolIndex);
|
|
}
|
|
|
|
float speed = 3.0f * game->timestep;
|
|
Vector2 forward = Vector2(0, -1);
|
|
Vector2 right = Vector2(1, 0);
|
|
Vector2 direction = Vector2(0);
|
|
if (game->moveForwardControl.isActive())
|
|
{
|
|
direction += forward;
|
|
}
|
|
if (game->moveBackControl.isActive())
|
|
{
|
|
direction -= forward;
|
|
}
|
|
if (game->moveLeftControl.isActive())
|
|
{
|
|
direction -= right;
|
|
}
|
|
if (game->moveRightControl.isActive())
|
|
{
|
|
direction += right;
|
|
}
|
|
if (glm::length2(direction) != 0.0f)
|
|
{
|
|
direction = glm::normalize(direction);
|
|
}
|
|
|
|
float rotationAngle = glm::radians(180.0f) * game->timestep;
|
|
if (game->orbitCCWControl.isActive())
|
|
{
|
|
game->orbitCam->rotate(-rotationAngle);
|
|
}
|
|
if (game->orbitCWControl.isActive())
|
|
{
|
|
game->orbitCam->rotate(rotationAngle);
|
|
}
|
|
|
|
float zoomSpeed = 3.0f * game->timestep;
|
|
if (game->zoomInControl.isActive())
|
|
{
|
|
zoom += zoomSpeed * game->zoomInControl.getCurrentValue();
|
|
}
|
|
if (game->zoomOutControl.isActive())
|
|
{
|
|
zoom -= zoomSpeed * game->zoomOutControl.getCurrentValue();
|
|
}
|
|
zoom = std::max<float>(0.0f, std::min<float>(1.0f, zoom));
|
|
|
|
float minFocalDistance = 5.0f;
|
|
float maxFocalDistance = 200.0f;
|
|
float logMinFocalDistance = std::log(minFocalDistance);
|
|
float logMaxFocalDistance = std::log(maxFocalDistance);
|
|
float logFocalDistance = lerp(logMinFocalDistance, logMaxFocalDistance, 1.0f - zoom);
|
|
float focalDistance = std::exp(logFocalDistance);
|
|
|
|
float minFOV = glm::radians(30.0f);
|
|
float maxFOV = glm::radians(60.0f);
|
|
float logMinFOV = std::log(minFOV);
|
|
float logMaxFOV = std::log(maxFOV);
|
|
float logFOV = lerp(logMinFOV, logMaxFOV, 1.0f - zoom);
|
|
float fov = std::exp(logFOV);
|
|
|
|
float minClipNear = 1.0f;
|
|
float maxClipNear = 5.0f;
|
|
float minClipFar = 100.0f;
|
|
float maxClipFar = 5000.0f;
|
|
float logMinClipNear = std::log(minClipNear);
|
|
float logMaxClipNear = std::log(maxClipNear);
|
|
float logMinClipFar = std::log(minClipFar);
|
|
float logMaxClipFar = std::log(maxClipFar);
|
|
float logClipNear = lerp(logMinClipNear, logMaxClipNear, 1.0f - zoom);
|
|
float logClipFar = lerp(logMinClipFar, logMaxClipFar, 1.0f - zoom);
|
|
float clipNear = std::exp(logClipNear);
|
|
float clipFar = std::exp(logClipFar);
|
|
|
|
float minMovementSpeed = 3.5f * game->timestep;
|
|
float maxMovementSpeed = 100.0f * game->timestep;
|
|
float logMinMovementSpeed = std::log(minMovementSpeed);
|
|
float logMaxMovementSpeed = std::log(maxMovementSpeed);
|
|
float logMovementSpeed = lerp(logMinMovementSpeed, logMaxMovementSpeed, 1.0f - zoom);
|
|
float movementSpeed = std::exp(logMovementSpeed);
|
|
|
|
/*
|
|
game->orbitCam->setTargetFocalDistance(focalDistance);
|
|
game->orbitCam->getCamera()->setPerspective(fov, (float)game->w / (float)game->h, clipNear, clipFar);
|
|
game->orbitCam->move(direction * movementSpeed);
|
|
game->orbitCam->setFocalPoint(game->orbitCam->getTargetFocalPoint());
|
|
//game->orbitCam->setTargetElevation(elevation);
|
|
//
|
|
*/
|
|
|
|
if (game->cameraRig == game->freeCam)
|
|
{
|
|
game->freeCam->move(direction * movementSpeed);
|
|
}
|
|
|
|
if (game->cameraRig)
|
|
{
|
|
game->cameraRig->update(game->timestep);
|
|
}
|
|
|
|
float nearLabelDistance = 0.25f;
|
|
float farLabelDistance = 1.0f;
|
|
float logNearLabelDistance = std::log(nearLabelDistance);
|
|
float logFarLabelDistance = std::log(farLabelDistance);
|
|
float logLabelDistance = lerp(logNearLabelDistance, logFarLabelDistance, 1.0f - zoom);
|
|
float labelDistance = std::exp(logLabelDistance);
|
|
|
|
if (game->adjustCameraControl.isActive() && !game->adjustCameraControl.wasActive())
|
|
{
|
|
savedMousePosition = game->mouse->getCurrentPosition();
|
|
game->mouse->setRelativeMode(true);
|
|
}
|
|
|
|
if (!game->radialMenuContainer->isVisible() && !menuClosed)
|
|
{
|
|
// Picking
|
|
Vector3 pick;
|
|
std::tuple<int, int> mousePosition = game->mouse->getCurrentPosition();
|
|
|
|
if (game->adjustCameraControl.isActive() || game->adjustCameraControl.wasActive())
|
|
{
|
|
mousePosition = savedMousePosition;
|
|
}
|
|
|
|
std::get<1>(mousePosition) = game->h - std::get<1>(mousePosition);
|
|
Vector4 viewport(0.0f, 0.0f, game->w, game->h);
|
|
Vector3 mouseNear = game->cameraRig->getCamera()->unproject(Vector3(std::get<0>(mousePosition), std::get<1>(mousePosition), 0.0f), viewport);
|
|
Vector3 mouseFar = game->cameraRig->getCamera()->unproject(Vector3(std::get<0>(mousePosition), std::get<1>(mousePosition), 1.0f), viewport);
|
|
|
|
Ray pickingRay;
|
|
pickingRay.origin = mouseNear;
|
|
pickingRay.direction = glm::normalize(mouseFar - mouseNear);
|
|
|
|
Plane plane(Vector3(0.0f, 1.0f, 0.0f), Vector3(0.0f));
|
|
auto pickingIntersection = pickingRay.intersects(plane);
|
|
bool picked = std::get<0>(pickingIntersection);
|
|
if (picked)
|
|
{
|
|
pick = pickingRay.extrapolate(std::get<1>(pickingIntersection));
|
|
}
|
|
|
|
if (picked)
|
|
{
|
|
if (game->currentTool)
|
|
{
|
|
if (!noPick)
|
|
{
|
|
game->currentTool->setPick(pick);
|
|
}
|
|
game->currentTool->update(game->timestep);
|
|
}
|
|
|
|
if (game->dragCameraControl.isActive())
|
|
{
|
|
if (!game->dragCameraControl.wasActive())
|
|
{
|
|
dragMousePosition = mousePosition;
|
|
dragReferencePoint = pick;
|
|
dragOffset = dragReferencePoint;
|
|
}
|
|
else
|
|
{
|
|
Vector4 viewport(0.0f, 0.0f, game->w, game->h);
|
|
Vector3 dragMouseNear = game->cameraRig->getCamera()->unproject(Vector3(std::get<0>(dragMousePosition), std::get<1>(dragMousePosition), 0.0f), viewport);
|
|
Vector3 dragMouseFar = game->cameraRig->getCamera()->unproject(Vector3(std::get<0>(dragMousePosition), std::get<1>(dragMousePosition), 1.0f), viewport);
|
|
|
|
Ray dragRay;
|
|
dragRay.origin = dragMouseNear;
|
|
dragRay.direction = glm::normalize(dragMouseFar - dragMouseNear);
|
|
auto dragPickResult = pickingRay.intersects(plane);
|
|
|
|
Vector3 dragPick;
|
|
if (std::get<0>(dragPickResult))
|
|
{
|
|
dragPick = dragRay.extrapolate(std::get<1>(dragPickResult));
|
|
|
|
|
|
game->orbitCam->setTargetFocalPoint(game->orbitCam->getTargetFocalPoint() + dragOffset - pick);
|
|
|
|
game->orbitCam->setFocalPoint(game->orbitCam->getTargetFocalPoint());
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!game->adjustCameraControl.isActive() && game->adjustCameraControl.wasActive())
|
|
{
|
|
game->mouse->setRelativeMode(false);
|
|
game->mouse->warp(game->window, std::get<0>(savedMousePosition), std::get<1>(savedMousePosition));
|
|
noPick = false;
|
|
}
|
|
}
|
|
|
|
void SandboxState::exit()
|
|
{
|
|
// Unsubscribe this state from input events
|
|
game->getEventDispatcher()->unsubscribe<MouseMovedEvent>(this);
|
|
game->getEventDispatcher()->unsubscribe<MouseButtonPressedEvent>(this);
|
|
game->getEventDispatcher()->unsubscribe<MouseButtonReleasedEvent>(this);
|
|
|
|
// Make HUD invisible
|
|
game->hudContainer->setVisible(false);
|
|
}
|
|
|
|
void SandboxState::handleEvent(const MouseMovedEvent& event)
|
|
{
|
|
float dx = event.dx;
|
|
float dy = event.dy;
|
|
if (game->radialMenuContainer->isVisible())
|
|
{
|
|
selectorVector.x += event.dx * 0.5f;
|
|
selectorVector.y += event.dy * 0.5f;
|
|
|
|
float lengthSquared = glm::length2(selectorVector);
|
|
if (lengthSquared > 0.0f)
|
|
{
|
|
// Limit selector vector magnitude
|
|
float maxLength = 100.0f;
|
|
if (lengthSquared > maxLength * maxLength)
|
|
{
|
|
selectorVector = (selectorVector / std::sqrt(lengthSquared)) * maxLength;
|
|
lengthSquared = maxLength * maxLength;
|
|
}
|
|
|
|
float minLength = 3.0f;
|
|
if (lengthSquared >= minLength * minLength)
|
|
{
|
|
Vector2 selectorDirection = selectorVector / std::sqrt(lengthSquared);
|
|
|
|
float angle = std::atan2(-selectorDirection.y, selectorDirection.x) + twoPi<float>();
|
|
float sectorAngle = twoPi<float>() / 8.0f;
|
|
int sector = static_cast<int>((angle + sectorAngle * 0.5f) / sectorAngle);
|
|
game->radialMenuSelectorImage->setRotation(static_cast<float>(sector) * sectorAngle);
|
|
game->radialMenuImage->setRotation(static_cast<float>(sector) * sectorAngle);
|
|
toolIndex = (8 - ((sector - 4) % 8)) % 8;
|
|
}
|
|
}
|
|
}
|
|
else if (game->adjustCameraControl.isActive())
|
|
{
|
|
bool invertX = true;
|
|
bool invertY = false;
|
|
|
|
float rotationFactor = event.dx;
|
|
float elevationFactor = event.dy;
|
|
|
|
if (invertX)
|
|
{
|
|
rotationFactor *= -1.0f;
|
|
}
|
|
if (invertY)
|
|
{
|
|
elevationFactor *= -1.0f;
|
|
}
|
|
|
|
float rotation = glm::radians(22.5f) * rotationFactor * game->timestep;
|
|
|
|
float minElevation = glm::radians(4.0f);
|
|
float maxElevation = glm::radians(80.0f);
|
|
float elevation = game->orbitCam->getTargetElevation() + elevationFactor * 0.25f * game->timestep;
|
|
elevation = std::min<float>(maxElevation, std::max<float>(minElevation, elevation));
|
|
|
|
|
|
game->orbitCam->rotate(rotation);
|
|
game->orbitCam->setTargetElevation(elevation);
|
|
}
|
|
|
|
if (game->cameraRig == game->freeCam)
|
|
{
|
|
float angle = glm::radians(0.5f);
|
|
bool invertX = false;
|
|
bool invertY = false;
|
|
|
|
float pan = -dx * angle;
|
|
float tilt = -dy * angle;
|
|
|
|
if (invertX)
|
|
pan = -pan;
|
|
if (invertY)
|
|
tilt = -tilt;
|
|
game->freeCam->rotate(pan, tilt);
|
|
}
|
|
|
|
game->brush->setTiltParams(Vector2(event.x, event.y), Vector2(game->w, game->h));
|
|
}
|
|
|
|
void SandboxState::handleEvent(const MouseButtonPressedEvent& event)
|
|
{
|
|
if (event.button == 1)
|
|
{
|
|
game->lens->focus();
|
|
game->forceps->pinch();
|
|
game->brush->press();
|
|
}
|
|
}
|
|
|
|
void SandboxState::handleEvent(const MouseButtonReleasedEvent& event)
|
|
{
|
|
if (event.button == 1)
|
|
{
|
|
game->lens->unfocus();
|
|
game->forceps->release();
|
|
game->brush->release();
|
|
}
|
|
}
|
|
|