392 lines
11 KiB
C++
392 lines
11 KiB
C++
#include "SceneInterface.h"
|
|
|
|
#include "ShaderUtil.h"
|
|
|
|
#include "PartitionedCube.h"
|
|
|
|
#include "Plane.h"
|
|
|
|
#include <glm.hpp>
|
|
#include <ext.hpp>
|
|
#include <gtx/string_cast.hpp>
|
|
|
|
|
|
#include <GLFW/glfw3.h>
|
|
|
|
|
|
#include <iostream>
|
|
|
|
void SceneInterface::Initialize(GLFWwindow* window)
|
|
{
|
|
_inputSystem.SetWindow(window);
|
|
|
|
_inputSystem.ObserveKey(GLFW_KEY_SPACE);
|
|
_inputSystem.ObserveKey(GLFW_KEY_UP);
|
|
_inputSystem.ObserveKey(GLFW_KEY_DOWN);
|
|
_inputSystem.ObserveKey(GLFW_KEY_LEFT);
|
|
_inputSystem.ObserveKey(GLFW_KEY_RIGHT);
|
|
|
|
_inputSystem.ObserveKey(GLFW_KEY_LEFT_SHIFT);
|
|
|
|
_inputSystem.ObserveKey(GLFW_KEY_KP_1);
|
|
_inputSystem.ObserveKey(GLFW_KEY_KP_2);
|
|
_inputSystem.ObserveKey(GLFW_KEY_KP_3);
|
|
_inputSystem.ObserveKey(GLFW_KEY_KP_4);
|
|
_inputSystem.ObserveKey(GLFW_KEY_KP_5);
|
|
_inputSystem.ObserveKey(GLFW_KEY_KP_6);
|
|
_inputSystem.ObserveKey(GLFW_KEY_KP_7);
|
|
_inputSystem.ObserveKey(GLFW_KEY_KP_8);
|
|
_inputSystem.ObserveKey(GLFW_KEY_KP_9);
|
|
|
|
_wasMouseDown = false;
|
|
|
|
this->_shaderProgram = ShaderUtil::CreateShaderProgram("cube.vert", "cube.frag");
|
|
this->_transformLocation = glGetUniformLocation(this->_shaderProgram, "transformation");
|
|
|
|
glGenVertexArrays(1, &this->_arrayBufferObject);
|
|
glGenBuffers(1, &this->_vertexBufferObject);
|
|
|
|
glBindVertexArray(_arrayBufferObject);
|
|
glBindBuffer(GL_ARRAY_BUFFER, this->_vertexBufferObject);
|
|
|
|
glVertexAttribPointer(glGetAttribLocation(_shaderProgram, "position"), 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), (void*)offsetof(VertexData, position));
|
|
glEnableVertexAttribArray(0);
|
|
glVertexAttribPointer(glGetAttribLocation(_shaderProgram, "color"), 4, GL_FLOAT, GL_FALSE, sizeof(VertexData), (void*)offsetof(VertexData, color));
|
|
glEnableVertexAttribArray(1);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
glBindVertexArray(0);
|
|
}
|
|
|
|
glm::vec3 basisCoordinateVectors[] = {
|
|
glm::vec3(1.0f, 0.0f, 0.0f),
|
|
glm::vec3(0.0f, 1.0f, 0.0f),
|
|
glm::vec3(0.0f, 0.0f, 1.0f)
|
|
};
|
|
|
|
glm::ivec3 orthogonalise(const glm::vec3& value) {
|
|
int minimum = 0;
|
|
for(int i=0;i<3;i++) {
|
|
if (abs(value[i])>abs(value[minimum]))
|
|
minimum = i;
|
|
}
|
|
|
|
glm::ivec3 orthogon = glm::vec3(0.0f);
|
|
|
|
orthogon[minimum] = glm::sign(value[minimum]);
|
|
|
|
return orthogon;
|
|
}
|
|
|
|
void roundAllScalars(glm::mat3& transforms) {
|
|
for(int x=0;x<3;x++) {
|
|
for(int y=0;y<3;y++) {
|
|
transforms[x][y] = round(transforms[x][y]);
|
|
}
|
|
}
|
|
}
|
|
|
|
glm::imat3x3 orthogonaliseMatrix(const glm::mat3& value) {
|
|
glm::mat3 temp = value;
|
|
|
|
roundAllScalars(temp);
|
|
|
|
glm::imat3x3 result;
|
|
|
|
for(int i=0;i<3;i++) {
|
|
result[i] = orthogonalise(value[i]);
|
|
|
|
for(int adjacent=i+1;adjacent<3;adjacent++) {
|
|
result[adjacent] = result[adjacent] * ( glm::abs(result[i]) * - 1 ) + 2;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void IntersectLinePlane(const glm::vec3& lineStart, const glm::vec3& lineDirection, const glm::vec3& planeOrigin, const glm::vec3& planeNormal, float& distance) {
|
|
glm::vec3 w = lineStart - planeOrigin;
|
|
|
|
float intersectionDistance = glm::dot(planeOrigin - lineStart, planeNormal) / glm::dot(lineDirection, planeNormal);
|
|
if (intersectionDistance > 0) {
|
|
distance = intersectionDistance;
|
|
}
|
|
}
|
|
|
|
void SceneInterface::EnqueueAction(const Action& action) {
|
|
_actions.push(action);
|
|
}
|
|
|
|
void SceneInterface::Update(float deltaTime)
|
|
{
|
|
_cube.Update(deltaTime);
|
|
_inputSystem.Update();
|
|
|
|
if (_inputSystem.WasKeyPressed(GLFW_KEY_SPACE))
|
|
_orientation = glm::quat(1.0f, glm::vec3(0.0f, 0.0f, 0.0f));
|
|
|
|
glm::fvec2 velocity(0.0f, 0.0f);
|
|
if (_inputSystem.IsKeyPressed(GLFW_KEY_UP))
|
|
velocity.x = glm::radians(90.0f);
|
|
if (_inputSystem.IsKeyPressed(GLFW_KEY_DOWN))
|
|
velocity.x = glm::radians(-90.0f);
|
|
|
|
if (_inputSystem.IsKeyPressed(GLFW_KEY_RIGHT))
|
|
velocity.y = glm::radians(90.0f);
|
|
if (_inputSystem.IsKeyPressed(GLFW_KEY_LEFT))
|
|
velocity.y = glm::radians(-90.0f);
|
|
|
|
glm::quat velocityQuaternion = glm::quat(0.0f, glm::vec3(velocity.x, velocity.y, 0.0f));
|
|
|
|
_orientation += 0.5f * (float)deltaTime * velocityQuaternion * _orientation;
|
|
_orientation = glm::normalize(_orientation);
|
|
|
|
// int spinIndex = 0;
|
|
|
|
// Gather Axis (+x, +y)
|
|
glm::ivec3 spinAxis;
|
|
if (_inputSystem.IsKeyPressed(GLFW_KEY_LEFT_SHIFT))
|
|
spinAxis = glm::ivec3(1, 0, 0);
|
|
else
|
|
spinAxis = glm::ivec3(0, 1, 0);
|
|
|
|
// Numpad
|
|
int rotationKey = -1;
|
|
for(int i=1;i<10;i++) {
|
|
if (_inputSystem.WasKeyPressed(GLFW_KEY_KP_0 + i)) {
|
|
rotationKey = i;
|
|
}
|
|
}
|
|
|
|
if (rotationKey != -1) {
|
|
bool reverseVertical = spinAxis.x == 1 && (rotationKey == 7 || rotationKey == 8 || rotationKey == 9);
|
|
bool reverseHorizontal = spinAxis.y == 1 && (rotationKey == 1 || rotationKey == 4 || rotationKey == 7);
|
|
|
|
static const int keyToIndex[2][9] = { { -1, 0, 1, 0, 0, 0, -1, 0, 1 }, { -1, 0, -1, 0, 0, 0, 1, 0, 1 } };
|
|
|
|
bool reverse = reverseVertical || reverseHorizontal;
|
|
|
|
// spin which lookup
|
|
int axisIndex = spinAxis.x == 0; // x => 0, y => 1
|
|
int spinIndex = keyToIndex[axisIndex][rotationKey - 1];
|
|
|
|
if (reverse)
|
|
spinAxis *= -1;
|
|
|
|
// _cube.TransformAnimation(cubeSpinAxis, spinIndex, rotation, 1.0f);
|
|
|
|
EnqueueAction(Action(spinAxis, spinIndex, 1.0f));
|
|
|
|
std::cout << glm::to_string(spinAxis) << " " << spinIndex << std::endl;
|
|
}
|
|
|
|
if (!_wasMouseDown && _inputSystem.IsLeftMouseDown()) {
|
|
OnDragStart();
|
|
}
|
|
else if (_wasMouseDown && !_inputSystem.IsLeftMouseDown()) {
|
|
OnDragStop();
|
|
}
|
|
else if (_wasMouseDown && _inputSystem.IsLeftMouseDown()) {
|
|
OnDrag(deltaTime);
|
|
}
|
|
|
|
_wasMouseDown = _inputSystem.IsLeftMouseDown();
|
|
|
|
currentAction.duration -= deltaTime;
|
|
if (currentAction.duration <= 0.0f && _actions.size() > 0) {
|
|
Action& action = _actions.front();
|
|
_actions.pop();
|
|
|
|
ApplyAction(action);
|
|
}
|
|
}
|
|
|
|
void SceneInterface::OnDragStart() {
|
|
_inputSystem.GetMousePos(_initialMouseLocation);
|
|
|
|
Plane planes[6];
|
|
|
|
glm::vec3 lineStart;
|
|
glm::vec3 lineDirection;
|
|
glm::mat4 viewPerspective = _perspective * _view;
|
|
|
|
_inputSystem.GetPickingRay(viewPerspective, lineStart, lineDirection);
|
|
|
|
glm::mat4 transform = glm::mat4(1.0f);
|
|
|
|
for(int axis=0;axis<3;axis++) {
|
|
for(int direction=-1;direction<=1;direction+=2) {
|
|
Plane plane(transform, axis, direction);
|
|
|
|
if (glm::dot(plane.Normal(), lineDirection) > 0)
|
|
continue;
|
|
|
|
float intersectionDistance = -1.0f;
|
|
IntersectLinePlane(lineStart, lineDirection, plane.Origin(), plane.Normal(), intersectionDistance);
|
|
|
|
if (intersectionDistance == -1.0f) {
|
|
continue;
|
|
}
|
|
|
|
const glm::mat4& planeTransform = plane.Transform();
|
|
glm::vec4 intersectionPoint = glm::vec4(lineStart + lineDirection * intersectionDistance, 1.0f);
|
|
glm::vec4 intersectionPlane = glm::inverse(planeTransform) * intersectionPoint;
|
|
|
|
bool onPlane = abs(intersectionPlane.x) < 1.501f && abs(intersectionPlane.y) < 1.501f;
|
|
|
|
if (!onPlane) {
|
|
continue;
|
|
}
|
|
|
|
_plane = plane;
|
|
|
|
_mousePositionPlane = intersectionPlane;
|
|
}
|
|
}
|
|
}
|
|
|
|
void SceneInterface::OnDrag(double deltaTime) {
|
|
glm::vec2 currentMousePosition;
|
|
|
|
_inputSystem.GetMousePos(currentMousePosition);
|
|
|
|
glm::vec3 lineStart;
|
|
glm::vec3 lineDirection;
|
|
glm::mat4 transform = _perspective * _view;
|
|
_inputSystem.GetPickingRay(transform, lineStart, lineDirection);
|
|
|
|
float intersectionDistance = -1.0f;
|
|
IntersectLinePlane(lineStart, lineDirection, _plane.Origin(), _plane.Normal(), intersectionDistance);
|
|
|
|
if (intersectionDistance == -1.0f) {
|
|
return;
|
|
}
|
|
|
|
const glm::mat4& planeTransform = _plane.Transform();
|
|
glm::vec2 intersectionPlane = glm::inverse(planeTransform) * (glm::vec4(lineStart + lineDirection * intersectionDistance, 1.0f));
|
|
glm::vec2 directionPlane = intersectionPlane - _mousePositionPlane;
|
|
|
|
float dragAbsDistance = abs(glm::distance(glm::vec2(0.0f), directionPlane));
|
|
|
|
if (dragAbsDistance >= MIN_DRAG_MAGNITUDE) {
|
|
glm::vec3 mousePosition = glm::inverse(planeTransform) * glm::vec4(_mousePositionPlane, 0.0f, 1.0f);
|
|
|
|
glm::vec3 direction = glm::inverse(planeTransform) * glm::vec4(directionPlane, 0.0f, 0.0f);
|
|
|
|
direction = glm::normalize(direction);
|
|
|
|
glm::vec3 axisSingle = glm::cross(_plane.Normal(), direction);
|
|
axisSingle = orthogonalise(axisSingle);
|
|
|
|
float projection = glm::dot(mousePosition, axisSingle);
|
|
|
|
int index = floor((projection + 0.5f));
|
|
|
|
glm::ivec3 axis = orthogonalise(axisSingle);
|
|
|
|
std::cout << glm::to_string(axisSingle) << std::endl;
|
|
std::cout << glm::to_string(direction) << std::endl;
|
|
std::cout << glm::to_string(axis) << std::endl;
|
|
|
|
_cube.TransformTemp(axis, index, glm::rotate(glm::mat4(1.0f), glm::radians(abs(glm::distance(glm::vec2(0.0f), directionPlane))), axisSingle));
|
|
}
|
|
}
|
|
|
|
void SceneInterface::OnDragStop() {
|
|
|
|
}
|
|
|
|
void SceneInterface::ApplyAction(const Action& action) {
|
|
currentAction = action;
|
|
|
|
glm::mat3 cubeMat = _cube.Transform() * glm::mat4_cast(_orientation);
|
|
|
|
glm::mat3 orthogonalized = cubeMat;
|
|
for(int column=0;column<3;column++) {
|
|
int nearestCardinalisedAxis = 0;
|
|
for(int i=0;i<3;i++) {
|
|
if (glm::abs(orthogonalized[column][i]) > glm::abs(orthogonalized[column][nearestCardinalisedAxis])) {
|
|
nearestCardinalisedAxis = i;
|
|
}
|
|
}
|
|
|
|
for(int columnToPlace=0;columnToPlace<3;columnToPlace++) {
|
|
for(int i=0;i<3;i++) {
|
|
if (columnToPlace == column) {
|
|
if (nearestCardinalisedAxis == i) {
|
|
orthogonalized[columnToPlace][i] = glm::sign(orthogonalized[columnToPlace][i]);
|
|
}
|
|
else {
|
|
orthogonalized[columnToPlace][i] = 0.0f;
|
|
}
|
|
}
|
|
else {
|
|
if (nearestCardinalisedAxis == i) {
|
|
orthogonalized[columnToPlace][i] = 0.0f;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
glm::vec3 axis = action.axis;
|
|
|
|
int direction = axis.x + axis.y + axis.z;
|
|
|
|
axis = glm::inverse(orthogonalized) * axis;
|
|
|
|
int index = action.index;
|
|
index *= direction;
|
|
|
|
glm::mat4 rotationMat = glm::rotate(glm::mat4(1.0f), glm::radians(90.0f), axis);
|
|
for(int i=0;i<3;i++) {
|
|
for(int g=0;g<3;g++) {
|
|
rotationMat[i][g] = round(rotationMat[i][g]);
|
|
}
|
|
}
|
|
glm::imat3x3 rotation = glm::imat3x3(rotationMat);
|
|
|
|
_cube.TransformAnimation(axis, index, rotation, action.duration);
|
|
}
|
|
|
|
void SceneInterface::Render(float aspectRatio) {
|
|
glUseProgram(_shaderProgram);
|
|
glBindVertexArray(this->_arrayBufferObject);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, this->_vertexBufferObject);
|
|
|
|
_view = glm::lookAt(glm::vec3(0.0f, 0.0f, 4.75f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f)) * glm::mat4_cast(_orientation);
|
|
_perspective = glm::perspective(glm::radians(45.0f), aspectRatio, 0.1f, 100.0f);
|
|
|
|
auto transformation = _perspective * _view;
|
|
|
|
// std::cout << "perspective: " << glm::to_string(glm::perspective(glm::radians(45.0f), aspectRatio, 0.1f, 100.0f)) << std::endl;
|
|
// std::cout << "view : " << glm::to_string(glm::lookAt(glm::vec3(0.0f, 0.0f, -3.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f))) << std::endl;
|
|
// std::cout << "model : " << glm::to_string(_cube.Transform()) << std::endl;
|
|
|
|
for(int i=0;i<_cube.ChildPartitionsCount;i++) {
|
|
const PartitionedCube* cube = _cube.Children()[i];
|
|
|
|
const MeshData& meshData = cube->MeshData();
|
|
|
|
const glm::vec3& position = meshData.data[0].position;
|
|
|
|
auto localTransform = transformation * cube->Transform();
|
|
|
|
glUniformMatrix4fv(_transformLocation, 1, GL_FALSE, glm::value_ptr(localTransform));
|
|
glBufferData(GL_ARRAY_BUFFER, sizeof(VertexData) * meshData.vertexIndex, meshData.data.data(), GL_STATIC_DRAW);
|
|
glDrawArrays(GL_TRIANGLES, 0, meshData.vertexIndex);
|
|
}
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
glBindVertexArray(0);
|
|
glUseProgram(0);
|
|
}
|
|
|
|
void SceneInterface::ClearResources()
|
|
{
|
|
glDeleteBuffers(1, &_vertexBufferObject);
|
|
glDeleteVertexArrays(1, &_arrayBufferObject);
|
|
glDeleteProgram(_shaderProgram);
|
|
}
|