💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

402 lines
12 KiB

/*
* 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();
}
}