/*
|
|
* 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 "brush.hpp"
|
|
#include "camera-rig.hpp"
|
|
#include <stdexcept>
|
|
|
|
Brush::Brush(const Model* model, Animator* animator):
|
|
wasActive(false)
|
|
{
|
|
// Setup model instance
|
|
modelInstance.setModel(model);
|
|
|
|
pressedDistance = -0.25f;
|
|
releasedDistance = 0.5f;
|
|
pressDuration = 0.25f;
|
|
releaseDuration = 0.175f;
|
|
|
|
tipDistance = releasedDistance;
|
|
lastTipDistance = tipDistance;
|
|
painting = false;
|
|
speed = 0.0f;
|
|
mousePosition = Vector2(0.0f);
|
|
lastMousePosition = mousePosition;
|
|
screenDimensions = Vector2(1.0f);
|
|
|
|
// Construct press animation clip
|
|
AnimationChannel<float>* channel;
|
|
pressClip.setInterpolator(easeOutCubic<float>);
|
|
channel = pressClip.addChannel(0);
|
|
channel->insertKeyframe(0.0f, 0.0f);
|
|
channel->insertKeyframe(pressDuration, 1.0f);
|
|
|
|
// Construct release animation clip
|
|
releaseClip.setInterpolator(easeOutCubic<float>);
|
|
channel = releaseClip.addChannel(0);
|
|
channel->insertKeyframe(0.0f, 0.0f);
|
|
channel->insertKeyframe(releaseDuration, 1.0f);
|
|
|
|
// Setup press animation callbacks
|
|
pressAnimation.setTimeFrame(pressClip.getTimeFrame());
|
|
pressAnimation.setClip(&pressClip);
|
|
pressAnimation.setAnimateCallback
|
|
(
|
|
[this](std::size_t id, float t)
|
|
{
|
|
this->tipDistance = lerp(lastTipDistance, pressedDistance, t);
|
|
}
|
|
);
|
|
pressAnimation.setEndCallback
|
|
(
|
|
[this]()
|
|
{
|
|
this->painting = true;
|
|
}
|
|
);
|
|
|
|
// Setup release animation callbacks
|
|
releaseAnimation.setTimeFrame(releaseClip.getTimeFrame());
|
|
releaseAnimation.setClip(&releaseClip);
|
|
releaseAnimation.setAnimateCallback
|
|
(
|
|
[this](std::size_t id, float t)
|
|
{
|
|
this->tipDistance = lerp(lastTipDistance, releasedDistance, t);
|
|
}
|
|
);
|
|
|
|
// Add animations to animator
|
|
animator->addAnimation(&pressAnimation);
|
|
animator->addAnimation(&releaseAnimation);
|
|
}
|
|
|
|
Brush::~Brush()
|
|
{}
|
|
|
|
void Brush::update(float dt)
|
|
{
|
|
Vector2 screenCenter = Vector2(screenDimensions.x * 0.5f, screenDimensions.y * 0.5f);
|
|
|
|
// Calculate mouse movement speed
|
|
Vector2 mouseDifference = (mousePosition - lastMousePosition) / std::min<float>(screenDimensions.x, screenDimensions.y);
|
|
Vector2 mouseDirection(0.0f);
|
|
float mouseSpeed = glm::length2(mouseDifference);
|
|
if (mouseSpeed != 0.0f)
|
|
{
|
|
mouseSpeed = std::sqrt(mouseSpeed);
|
|
mouseDirection = mouseDifference * (1.0f / mouseSpeed);
|
|
}
|
|
|
|
this->lastMousePosition = this->mousePosition;
|
|
|
|
Vector3 tiltDirection = Vector3(mouseDirection.x, 0.0f, mouseDirection.y);
|
|
float tiltMagnitude = std::min<float>(0.5f, mouseSpeed * 10.0f);
|
|
if (!tiltMagnitude)
|
|
{
|
|
tiltDirection = Vector3(0, 1, 0);
|
|
}
|
|
|
|
Vector2 tiltForce = mouseDirection * mouseSpeed;
|
|
velocity += tiltForce;
|
|
|
|
Quaternion tilt = glm::normalize(glm::slerp(Quaternion(1, 0, 0, 0), glm::normalize(glm::rotation(Vector3(0, 1, 0), tiltDirection)), tiltMagnitude * 0.0f));
|
|
|
|
|
|
Quaternion alignment = glm::angleAxis(orbitCam->getAzimuth(), Vector3(0, 1, 0));
|
|
Quaternion rotation = glm::normalize(alignment * tilt);
|
|
Vector3 translation = pick + rotation * Vector3(0, tipDistance, 0);
|
|
|
|
// Set tool position
|
|
modelInstance.setTranslation(translation);
|
|
modelInstance.setRotation(rotation);
|
|
|
|
if (active && !wasActive)
|
|
{
|
|
modelInstance.resetTweens();
|
|
modelInstance.setActive(true);
|
|
}
|
|
else if (!active && wasActive)
|
|
{
|
|
modelInstance.setActive(false);
|
|
}
|
|
|
|
wasActive = active;
|
|
}
|
|
|
|
void Brush::press()
|
|
{
|
|
lastTipDistance = tipDistance;
|
|
|
|
releaseAnimation.stop();
|
|
pressAnimation.rewind();
|
|
pressAnimation.play();
|
|
}
|
|
|
|
void Brush::release()
|
|
{
|
|
lastTipDistance = tipDistance;
|
|
|
|
pressAnimation.stop();
|
|
releaseAnimation.rewind();
|
|
releaseAnimation.play();
|
|
painting = false;
|
|
}
|
|
|
|
|
|
void Brush::setTiltParams(const Vector2& mousePosition, const Vector2& screenDimensions)
|
|
{
|
|
this->mousePosition = mousePosition;
|
|
this->screenDimensions = screenDimensions;
|
|
}
|
|
|