/* * 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 "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 SandboxState::SandboxState(Game* game): GameState(game) {} SandboxState::~SandboxState() {} void SandboxState::enter() { // Subscribe this state to input events game->getEventDispatcher()->subscribe(this); game->getEventDispatcher()->subscribe(this); game->getEventDispatcher()->subscribe(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(0.0f, std::min(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 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(this); game->getEventDispatcher()->unsubscribe(this); game->getEventDispatcher()->unsubscribe(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 sectorAngle = twoPi / 8.0f; int sector = static_cast((angle + sectorAngle * 0.5f) / sectorAngle); game->radialMenuSelectorImage->setRotation(static_cast(sector) * sectorAngle); game->radialMenuImage->setRotation(static_cast(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(maxElevation, std::max(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(); } }