💿🐜 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.
 

168 lines
4.4 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 "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;
}