#include "SceneInterface.h" #include "ShaderUtil.h" #include "PartitionedCube.h" #include "Plane.h" #include #include #include #include #include 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); }