diff --git a/camera.cpp b/camera.cpp index 788c7e1..a96a879 100644 --- a/camera.cpp +++ b/camera.cpp @@ -29,6 +29,7 @@ Camera::Camera(float a_fov, float a_width, float a_height, float a_near, float a near = a_near; far = a_far; mat4x4_perspective(projection, fov, aspect, near, far); + mat4x4_ortho(projection, -3 * aspect, 3 * aspect, -3, 3, near, far); yaw = 0.0f; pitch = 0.0f; @@ -121,6 +122,7 @@ void Camera::framebufferSizeCallback(GLFWwindow* window, int width, int height) this->height = height; this->aspect = (float)width / (float)height; mat4x4_perspective(this->projection, this->fov, this->aspect, this->near, this->far); + mat4x4_ortho(this->projection, -3 * this->aspect, 3 * this->aspect, -3, 3, this->near, this->far); } void Camera::setMousePressed(bool pressed) { diff --git a/control.cpp b/control.cpp index 3f65850..adb754d 100644 --- a/control.cpp +++ b/control.cpp @@ -26,8 +26,8 @@ #include #include #include -#define RYML_SINGLE_HDR_DEFINE_NOW -#include +// #define RYML_SINGLE_HDR_DEFINE_NOW +// #include #ifdef _WIN32 #include @@ -65,39 +65,6 @@ PuzzleController::PuzzleController(PuzzleRenderer* renderer) { std::random_device rd; rng.seed(rd()); scrambleIndex = -1; - - std::ifstream file("scramble.txt"); - if (!file.fail()) { - file >> std::ws; - std::vector> moves; - std::array move; - char comma; - while (true) { - file >> move[0] >> comma >> move[1]; - if (file.eof()) { - break; - } - if (comma == ',') { - moves.push_back(move); - } - } - for (size_t i = 0; i < moves.size(); i++) { - CellLocation cell = (CellLocation)moves[i][0]; - if (moves[i][1] == -1) { - startGyro(cell); - } else { - startCellMove(cell, (RotateDirection)moves[i][1]); - } - while (renderer->pendingMoves.size()) { - MoveEntry entry = renderer->pendingMoves.front(); - renderer->pendingMoves.pop(); - performMove(entry); - scramble.push_back(entry); - } - } - renderer->animating = false; - getScrambleTwists(); - } } PuzzleController::~PuzzleController() { @@ -105,13 +72,7 @@ PuzzleController::~PuzzleController() { } void PuzzleController::performMove(MoveEntry entry) { - switch (entry.type) { - case TURN: puzzle->rotateCell(entry.cell, entry.direction); break; - case ROTATE: puzzle->rotatePuzzle(entry.direction); break; - case GYRO: puzzle->gyroCell(entry.cell); break; - case GYRO_OUTER: puzzle->gyroOuterSlice(); break; - case GYRO_MIDDLE: puzzle->gyroMiddleSlice(entry.location); break; - } + // todo } bool PuzzleController::updatePuzzle(GLFWwindow *window, double dt) { @@ -132,222 +93,14 @@ bool PuzzleController::updatePuzzle(GLFWwindow *window, double dt) { return updated || renderer->animating; } -bool PuzzleController::checkMiddleGyro(int key, bool flip) { - if (key == GLFW_KEY_M || key == GLFW_KEY_PERIOD) { - int direction = (key == GLFW_KEY_M) ? -1 : 1; - if (flip) direction *= -1; - if (puzzle->canGyroMiddle(direction)) { - MoveEntry entry; - entry.type = GYRO_MIDDLE; - entry.animLength = 1.0f; - entry.location = direction; - renderer->scheduleMove(entry); - return true; - } - } else if (key == GLFW_KEY_COMMA) { - MoveEntry entry; - entry.type = GYRO_MIDDLE; - entry.animLength = 1.0f; - entry.location = 0; - renderer->scheduleMove(entry); - return true; - } - return false; -} - -bool PuzzleController::checkCellKeys(GLFWwindow* window, CellLocation* cell, bool flip) { - bool foundCell = false; - for (int i = 0; i < 8; i++) { - if (glfwGetKey(window, cellKeys[i])) { - foundCell = true; - if (flip && i != 0 && i != 1 && i != 4 && i != 5) { - // Do not flip IN, OUT, UP, DOWN - *cell = (CellLocation)(i / 2 * 2 + 1 - i % 2); - } else { - *cell = (CellLocation)i; - } - } - } - return foundCell; -} - -bool PuzzleController::checkDirectionKey(int key, RotateDirection* direction, bool flip) { - bool foundDirection = false; - for (int i = 0; i < 6; i++) { - if (key == directionKeys[i]) { - // Move outer layer - foundDirection = true; - if (flip && i != 2 && i != 3) { - // Do not flip XZ or ZX - *direction = (RotateDirection)(i / 2 * 2 + 1 - i % 2); - } else { - *direction = (RotateDirection)i; - } - } - } - return foundDirection; -} - -bool PuzzleController::checkDirectionalMove(GLFWwindow* window, int key, bool flip) { - CellLocation cell; - RotateDirection direction; - if (checkCellKeys(window, &cell, flip)) { - if (key == GLFW_KEY_SPACE) { - startGyro(cell); - return true; - } - - if (checkDirectionKey(key, &direction, flip)) { - if (puzzle->canRotateCell(cell, direction)) { - startCellMove(cell, direction); - return true; - } - } - } else if (checkDirectionKey(key, &direction, flip)) { - if (puzzle->canRotatePuzzle(direction)) { - // whole puzzle rotation - MoveEntry entry; - entry.type = ROTATE; - entry.animLength = 1.0f; - entry.direction = direction; - renderer->scheduleMove(entry); - return true; - } - } - return false; -} - -void PuzzleController::startGyro(CellLocation cell) { - MoveEntry entry; - int direction = 0; - switch (cell) { - case LEFT: - case RIGHT: - entry.type = GYRO; - entry.animLength = 4.0f; - entry.cell = cell; - renderer->scheduleMove(entry); - break; - case UP: - case DOWN: - if (puzzle->middleSliceDir == FRONT) { - entry.type = GYRO_MIDDLE; - entry.animLength = 1.0f; - entry.location = 0; - renderer->scheduleMove(entry); - } - - if (puzzle->middleSlicePos == 0) { - direction = puzzle->outerSlicePos; - } else if (puzzle->middleSlicePos == 2 * puzzle->outerSlicePos) { - direction = -puzzle->outerSlicePos; - } else if (puzzle->middleSlicePos == -puzzle->outerSlicePos) { - entry.type = GYRO_OUTER; - entry.animLength = 2.0f; - entry.location = -1 * puzzle->outerSlicePos; - renderer->scheduleMove(entry); - direction = 0; - } else if (puzzle->middleSlicePos == puzzle->outerSlicePos) { - direction = 0; - } - - if (direction != 0) { - entry.type = GYRO_MIDDLE; - entry.animLength = 1.0f; - entry.location = direction; - renderer->scheduleMove(entry); - } - - entry.type = GYRO; - entry.animLength = 3.0f; - entry.cell = cell; - renderer->scheduleMove(entry); - break; - case FRONT: - case BACK: - if (puzzle->middleSliceDir == UP) { - entry.type = GYRO_MIDDLE; - entry.animLength = 1.0f; - entry.location = 0; - renderer->scheduleMove(entry); - } - - if (puzzle->middleSlicePos == 0) { - direction = puzzle->outerSlicePos; - } else if (puzzle->middleSlicePos == 2 * puzzle->outerSlicePos) { - direction = -puzzle->outerSlicePos; - } else if (puzzle->middleSlicePos == -puzzle->outerSlicePos) { - entry.type = GYRO_OUTER; - entry.animLength = 2.0f; - entry.location = -1 * puzzle->outerSlicePos; - renderer->scheduleMove(entry); - direction = 0; - } else if (puzzle->middleSlicePos == puzzle->outerSlicePos) { - direction = 0; - } - - if (direction != 0) { - entry.type = GYRO_MIDDLE; - entry.animLength = 1.0f; - entry.location = direction; - renderer->scheduleMove(entry); - } - - entry.type = GYRO; - entry.animLength = 3.0f; - entry.cell = cell; - renderer->scheduleMove(entry); - break; - case IN: - case OUT: - return; - } -} - -void PuzzleController::startCellMove(CellLocation cell, RotateDirection direction) { - MoveEntry entry; - if ((cell == UP || cell == DOWN) && puzzle->middleSliceDir == FRONT) { - entry.type = GYRO_MIDDLE; - entry.animLength = 1.0f; - entry.location = 0; - renderer->scheduleMove(entry); - } else if ((cell == FRONT || cell == BACK) && puzzle->middleSliceDir == UP) { - entry.type = GYRO_MIDDLE; - entry.animLength = 1.0f; - entry.location = 0; - renderer->scheduleMove(entry); - } - - float length; - if (cell == UP || cell == DOWN || cell == FRONT || cell == BACK) { - length = 2.0f; - } else { - length = 1.0f; - } - - entry.type = TURN; - entry.animLength = length; - entry.cell = cell; - entry.direction = direction; - renderer->scheduleMove(entry); -} - void PuzzleController::keyCallback(GLFWwindow* window, int key, int action, int mods, bool flip) { if (renderer->animating) return; if (action == GLFW_PRESS) { status.clear(); if (mods == 0) { - if (checkMiddleGyro(key, flip)) return; - if (checkDirectionalMove(window, key, flip)) return; + // todo - if (key == GLFW_KEY_SPACE) { - // gyro outer layer - MoveEntry entry; - entry.type = GYRO_OUTER; - entry.animLength = 2.0f; - entry.location = -1 * puzzle->outerSlicePos; - renderer->scheduleMove(entry); - } else if (key == GLFW_KEY_Z) { + if (key == GLFW_KEY_Z) { undoMove(); } else if (key == GLFW_KEY_Y) { redoMove(); @@ -383,119 +136,8 @@ void PuzzleController::redoMove() { } } -void rotate4in8(std::array& cells, std::array indices) { - int temp = cells[indices[0]]; - for (int i = 0; i < 3; i++) { - cells[indices[i]] = cells[indices[i + 1]]; - } - cells[indices[3]] = temp; -} - -void rotate8bycell(std::array& cells, CellLocation cell) { - if (cell == RIGHT) { - rotate4in8(cells, {0, 6, 1, 7}); - } else if (cell == LEFT) { - rotate4in8(cells, {1, 6, 0, 7}); - } else if (cell == UP) { - rotate4in8(cells, {2, 6, 3, 7}); - } else if (cell == DOWN) { - rotate4in8(cells, {3, 6, 2, 7}); - } else if (cell == FRONT) { - rotate4in8(cells, {4, 6, 5, 7}); - } else if (cell == BACK) { - rotate4in8(cells, {5, 6, 4, 7}); - } -} - void PuzzleController::scramblePuzzle(int scrambleLength) { - static std::discrete_distribution typeDist({2, 3}); - static std::uniform_int_distribution directionDist(0, 5); - static std::discrete_distribution cellDist({2, 2, 6, 6, 1, 1, 1, 1}); - // FBUD only for visual effect, functionally unneeded - static std::uniform_int_distribution boolDist(0, 1); - MoveEntry entry; - entry.type = TURN; - if (scrambleLength == 0) { - scrambleLength = 45; - } - CellLocation lastCell = (CellLocation)-1; - for (int i = 0; i < scrambleLength; i++) { - if (typeDist(rng) == 0 && entry.type != GYRO) { - // don't include gyros in scramble length - i--; - entry.type = GYRO; - entry.cell = (CellLocation)(2 + directionDist(rng)); - } else { - entry.type = TURN; - while (true) { - entry.cell = (CellLocation)cellDist(rng); - if (entry.cell != lastCell) break; - if (entry.cell == LEFT || entry.cell == RIGHT) break; - } - lastCell = entry.cell; - switch (entry.cell) { - case IN: - case OUT: - // YZ or ZY - entry.direction = (RotateDirection)boolDist(rng); - break; - case UP: - case DOWN: - // XZ or ZX - entry.direction = (RotateDirection)(2 + boolDist(rng)); - break; - case FRONT: - case BACK: - // XY or YX - entry.direction = (RotateDirection)(4 + boolDist(rng)); - break; - case LEFT: - case RIGHT: - // any - entry.direction = (RotateDirection)directionDist(rng); - break; - } - } - scramble.push_back(entry); - } - - bool reorient = false; - if (reorient) { - // R, L, U, D, F, B, O, I - // Reorient to HSC default orientation - std::array cells = {0, 1, 4, 5, 3, 2, 6, 7}; - for (size_t i = 0; i < scramble.size(); i++) { - if (scramble[i].type == GYRO) { - rotate8bycell(cells, scramble[i].cell); - } - } - entry.type = GYRO; - std::array colorsToFix = {4, 2, 7}; - for (int i = 0; i < 3; i++) { - int index = std::distance(cells.begin(), std::find(cells.begin(), cells.end(), colorsToFix[i])); - if (index != colorsToFix[i]) { - // Move to I - if (index == 6) { - entry.cell = LEFT; - scramble.push_back(entry); - scramble.push_back(entry); - rotate8bycell(cells, entry.cell); - rotate8bycell(cells, entry.cell); - } else if (index < 6) { - entry.cell = (CellLocation)(2 + index); - scramble.push_back(entry); - rotate8bycell(cells, entry.cell); - } - // Move to desired location (gyro opposite) - if (colorsToFix[i] != 7) { - // Don't gyro if inner - entry.cell = (CellLocation)(2 + colorsToFix[i] + 1); - scramble.push_back(entry); - rotate8bycell(cells, entry.cell); - } - } - } - } + // todo getScrambleTwists(); scrambleIndex = 0; @@ -513,54 +155,12 @@ void PuzzleController::performScramble() { scrambleIndex = -1; renderer->animationSpeed = origRenderSpeed; } else { - if (scramble[scrambleIndex].type == GYRO) { - startGyro(scramble[scrambleIndex].cell); - } else { - startCellMove(scramble[scrambleIndex].cell, scramble[scrambleIndex].direction); - } + // todo } } void PuzzleController::getScrambleTwists() { - std::map> gyroMoves = { - {RIGHT, {2, 4}}, // U cell turns F - {LEFT, {2, 5}}, // U cell turns B - {UP, {4, 0}}, // F cell turns R - {DOWN, {4, 1}}, // F cell turns L - {FRONT, {2, 1}}, // U cell turns R - {BACK, {2, 0}} // U cell turns L - }; - std::ostringstream hscScramble; - hscScramble << 0 << "," << 0 << "," << 7 << " "; - for (size_t i = 0; i < scramble.size(); i++) { - if (scramble[i].type == GYRO) { - hscScramble << gyroMoves[scramble[i].cell].first << "," << gyroMoves[scramble[i].cell].second; - hscScramble << "," << 7 << " "; - } else { - int cell, direction; - if (scramble[i].cell == IN) { - cell = 7; - } else if (scramble[i].cell == OUT) { - cell = 6; - } else { - cell = (int)scramble[i].cell - 2; - } - direction = (int)scramble[i].direction; - if (cell >= 2 && cell < 6) direction += 6; - hscScramble << cell << "," << direction << "," << 1 << " "; - } - } - - std::ostringstream physScramble; - for (size_t i = 0; i < scramble.size(); i++) { - if (scramble[i].type == GYRO) { - physScramble << (int)scramble[i].cell << "," << -1 << " "; - } else { - physScramble << scramble[i].cell << "," << (int)scramble[i].direction << " "; - } - } - std::cout << "scramble: >\n " << hscScramble.str() << std::endl; - std::cout << "phys_scramble: >\n " << physScramble.str() << std::endl; + // todo } void PuzzleController::openFile(std::string filename) { @@ -660,13 +260,7 @@ bool MoveHistory::isOpposite(MoveEntry entry1, MoveEntry entry2) { case GYRO: return isOppositeParity((int)entry1.cell, (int)entry2.cell); case TURN: - return entry1.cell == entry2.cell && isOppositeParity((int)entry1.direction, (int)entry2.direction); - case ROTATE: - return isOppositeParity((int)entry1.direction, (int)entry2.direction); - case GYRO_OUTER: - return entry1.location == -entry2.location; - case GYRO_MIDDLE: - return entry1.location == -entry2.location; + return entry1.cell == entry2.cell && isOppositeParity((int)entry1.direction, (int)entry2.direction) && entry1.slices == entry2.slices; default: // should not run return false; @@ -684,25 +278,8 @@ MoveEntry MoveHistory::getOpposite(MoveEntry entry) { case TURN: opposite.cell = entry.cell; opposite.direction = (RotateDirection)getOppositeParity((int)entry.direction); - break; - case ROTATE: - opposite.direction = (RotateDirection)getOppositeParity((int)entry.direction); - break; - case GYRO_OUTER: - opposite.location = -entry.location; - break; - case GYRO_MIDDLE: - opposite.location = -entry.location; + opposite.slices = entry.slices; break; } return opposite; } - -bool PuzzleController::checkOutline(GLFWwindow *window, Shader *shader, bool flip) { - CellLocation cell; - if (checkCellKeys(window, &cell, flip)) { - renderer->renderCellOutline(shader, cell); - return true; - } - return false; -} diff --git a/control.h b/control.h index efb87a0..66510c0 100644 --- a/control.h +++ b/control.h @@ -56,15 +56,8 @@ class PuzzleController { PuzzleController(PuzzleRenderer* renderer); ~PuzzleController(); bool updatePuzzle(GLFWwindow* window, double dt); - bool checkMiddleGyro(int key, bool flip); - bool checkDirectionalMove(GLFWwindow* window, int key, bool flip); - void startGyro(CellLocation cell); - bool checkCellKeys(GLFWwindow* window, CellLocation* cell, bool flip); - bool checkDirectionKey(int key, RotateDirection* direction, bool flip); - void startCellMove(CellLocation cell, RotateDirection direction); void keyCallback(GLFWwindow* window, int key, int action, int mods, bool flip); std::string getStatus(); - bool checkOutline(GLFWwindow *window, Shader *shader, bool flip); void performMove(MoveEntry entry); void performScramble(); void getScrambleTwists(); diff --git a/header.mak b/header.mak index 2459893..9eb231d 100644 --- a/header.mak +++ b/header.mak @@ -1,4 +1,4 @@ -CPPFLAGS = -Wall -Wextra -Werror -pedantic -Wno-unused-parameter -Wno-unknown-pragmas -Iinclude -Iimgui/ -Iimgui/backends/ -Infd/src/include/ +CPPFLAGS = -Wall -Wextra -Werror -pedantic -Wno-unused-parameter -Wno-unknown-pragmas -Wno-unused-but-set-variable -Iinclude -Iimgui/ -Iimgui/backends/ -Infd/src/include/ CXXFLAGS = --std=c++11 ifeq ($(OS),Windows_NT) CCLIBFLAGS = -Llib -lglfw3 -lopengl32 -lgdi32 -lshell32 -lole32 -luuid diff --git a/pieces.cpp b/pieces.cpp index 95cf4be..ad31260 100644 --- a/pieces.cpp +++ b/pieces.cpp @@ -20,14 +20,14 @@ #include "pieces.h" vec3 Pieces::colors[8] = { - {0.53f, 0.0f, 0.67f}, - {1.0f, 0.33f, 0.87f}, - {0.87f, 0.13f, 0.0f}, - {1.0f, 0.5f, 0.0f}, + {0.53f, 0.13f, 0.8f}, + {1.0f, 0.4f, 1.0f}, + {0.8f, 0.2f, 0.2f}, + {1.0f, 0.6f, 0.18f}, {1.0f, 1.0f, 1.0f}, - {1.0f, 0.87f, 0.0f}, - {0.0f, 0.8f, 0.0f}, - {0.0f, 0.27f, 0.87f}, + {1.0f, 1.0f, 0.0f}, + {0.53f, 0.93f, 0.4f}, + {0.2f, 0.67f, 1.0f}, }; PieceType Pieces::mesh1c = { @@ -77,292 +77,3 @@ PieceType Pieces::mesh1c = { 0.0f, -1.0f, 0.0f, } }; - -PieceType Pieces::mesh2c = { - { - // X Y Z Color - // Top face - -0.5f, 0.5f, 0.5f, 0.0f, - 0.0f, 0.5f, 0.5f, 0.0f, - 0.5f, 0.5f, 0.5f, 0.0f, - 0.5f, 0.5f, 0.0f, 0.0f, - 0.5f, 0.5f, -0.5f, 0.0f, - 0.0f, 0.5f, -0.5f, 0.0f, - -0.5f, 0.5f, -0.5f, 0.0f, - -0.5f, 0.5f, 0.0f, 0.0f, - 0.0f, 0.5f, 0.5f, 1.0f, - 0.5f, 0.5f, 0.0f, 1.0f, - 0.0f, 0.5f, -0.5f, 1.0f, - -0.5f, 0.5f, 0.0f, 1.0f, - - // Top slice - -0.5f, 0.0f, 0.5f, 0.0f, - 0.5f, 0.0f, 0.5f, 0.0f, - 0.5f, 0.0f, -0.5f, 0.0f, - -0.5f, 0.0f, -0.5f, 0.0f, - - // Bottom slice - -0.5f, 0.0f, 0.5f, 1.0f, - 0.5f, 0.0f, 0.5f, 1.0f, - 0.5f, 0.0f, -0.5f, 1.0f, - -0.5f, 0.0f, -0.5f, 1.0f, - - // Bottom face - 0.0f, -0.5f, 0.5f, 0.0f, - 0.5f, -0.5f, 0.0f, 0.0f, - 0.0f, -0.5f, -0.5f, 0.0f, - -0.5f, -0.5f, 0.0f, 0.0f, - -0.5f, -0.5f, 0.5f, 1.0f, - 0.0f, -0.5f, 0.5f, 1.0f, - 0.5f, -0.5f, 0.5f, 1.0f, - 0.5f, -0.5f, 0.0f, 1.0f, - 0.5f, -0.5f, -0.5f, 1.0f, - 0.0f, -0.5f, -0.5f, 1.0f, - -0.5f, -0.5f, -0.5f, 1.0f, - -0.5f, -0.5f, 0.0f, 1.0f, - }, - { - 7, 0, 1, - 1, 2, 3, - 3, 4, 5, - 5, 6, 7, - 8, 9, 10, - 8, 10, 11, - 0, 12, 13, - 0, 13, 2, - 2, 13, 14, - 2, 14, 4, - 4, 14, 15, - 4, 15, 6, - 6, 15, 12, - 6, 12, 0, - 16, 26, 17, - 16, 24, 26, - 17, 28, 18, - 17, 26, 28, - 18, 30, 19, - 18, 28, 30, - 19, 24, 16, - 19, 30, 24, - 25, 24, 31, - 27, 26, 25, - 29, 28, 27, - 31, 30, 29, - 20, 22, 21, - 20, 23, 22, - }, - { - 0, 2, 2, 4, 4, 6, 6, 0, - 1, 3, 3, 5, 5, 7, 7, 1, - 0, 12, 2, 13, 4, 14, 6, 15, - 12, 13, 13, 14, 14, 15, 15, 12, - 16, 24, 17, 26, 18, 28, 19, 30, - 24, 26, 26, 28, 28, 30, 30, 24, - 25, 27, 27, 29, 29, 31, 31, 25, - }, - { - // X Y Z - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 1.0f, - 0.0f, 0.0f, 1.0f, - 1.0f, 0.0f, 0.0f, - 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, -1.0f, - 0.0f, 0.0f, -1.0f, - -1.0f, 0.0f, 0.0f, - -1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, - 0.0f, 0.0f, 1.0f, - 1.0f, 0.0f, 0.0f, - 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, -1.0f, - 0.0f, 0.0f, -1.0f, - -1.0f, 0.0f, 0.0f, - -1.0f, 0.0f, 0.0f, - 0.0f, -1.0f, 0.0f, - 0.0f, -1.0f, 0.0f, - 0.0f, -1.0f, 0.0f, - 0.0f, -1.0f, 0.0f, - 0.0f, -1.0f, 0.0f, - 0.0f, -1.0f, 0.0f, - } -}; - -PieceType Pieces::mesh3c = { - { - // X Y Z Color - // Top face - -0.5f, 0.5f, 0.5f, 0.0f, - 0.5f, 0.5f, 0.5f, 0.0f, - 0.5f, 0.5f, -0.5f, 0.0f, - -0.5f, 0.5f, -0.5f, 0.0f, - 0.0f, 0.5f, 0.0f, 0.0f, - -0.5f, 0.5f, 0.5f, 1.0f, - 0.5f, 0.5f, 0.5f, 1.0f, - 0.5f, 0.5f, -0.5f, 1.0f, - -0.5f, 0.5f, -0.5f, 1.0f, - 0.0f, 0.5f, 0.0f, 1.0f, - - // Bottom face - -0.5f, -0.5f, 0.5f, 0.0f, - 0.5f, -0.5f, 0.5f, 0.0f, - 0.5f, -0.5f, -0.5f, 0.0f, - -0.5f, -0.5f, -0.5f, 0.0f, - 0.0f, -0.5f, 0.0f, 0.0f, - -0.5f, -0.5f, 0.5f, 1.0f, - 0.5f, -0.5f, 0.5f, 1.0f, - 0.5f, -0.5f, -0.5f, 1.0f, - -0.5f, -0.5f, -0.5f, 1.0f, - 0.0f, -0.5f, 0.0f, 1.0f, - - // Red vertices - -0.5f, 0.5f, 0.5f, 2.0f, - 0.5f, 0.5f, 0.5f, 2.0f, - 0.5f, 0.5f, -0.5f, 2.0f, - -0.5f, 0.5f, -0.5f, 2.0f, - -0.5f, -0.5f, 0.5f, 2.0f, - 0.5f, -0.5f, 0.5f, 2.0f, - 0.5f, -0.5f, -0.5f, 2.0f, - -0.5f, -0.5f, -0.5f, 2.0f, - - // Other faces - 0.0f, 0.0f, -0.5f, 1.0f, - 0.0f, 0.0f, -0.5f, 2.0f, - 0.5f, 0.0f, 0.0f, 0.0f, - 0.5f, 0.0f, 0.0f, 2.0f, - 0.0f, 0.0f, 0.5f, 1.0f, - 0.0f, 0.0f, 0.5f, 2.0f, - -0.5f, 0.0f, 0.0f, 0.0f, - -0.5f, 0.0f, 0.0f, 2.0f, - }, - { - 5, 6, 9, - 7, 8, 9, - 0, 4, 3, - 1, 2, 4, - 15, 19, 16, - 17, 19, 18, - 10, 13, 14, - 11, 14, 12, - 8, 7, 28, - 18, 28, 17, - 23, 29, 27, - 22, 26, 29, - 6, 5, 32, - 16, 32, 15, - 21, 33, 25, - 33, 20, 24, - 2, 1, 30, - 12, 30, 11, - 22, 31, 26, - 21, 25, 31, - 0, 3, 34, - 10, 34, 13, - 20, 35, 24, - 35, 23, 27, - }, - { - 0, 1, 1, 2, 2, 3, 3, 0, 0, 2, 1, 3, - 10, 11, 11, 12, 12, 13, 13, 10, 10, 12, 11, 13, - 0, 10, 1, 11, 2, 12, 3, 13, - 0, 11, 1, 10, 2, 13, 3, 12, - 1, 12, 2, 11, 3, 10, 0, 13 - }, - { - // X Y Z - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, -1.0f, 0.0f, - 0.0f, -1.0f, 0.0f, - 0.0f, -1.0f, 0.0f, - 0.0f, -1.0f, 0.0f, - 0.0f, 0.0f, -1.0f, - 0.0f, 0.0f, -1.0f, - 0.0f, 0.0f, -1.0f, - 0.0f, 0.0f, -1.0f, - 0.0f, 0.0f, 1.0f, - 0.0f, 0.0f, 1.0f, - 0.0f, 0.0f, 1.0f, - 0.0f, 0.0f, 1.0f, - 1.0f, 0.0f, 0.0f, - 1.0f, 0.0f, 0.0f, - 1.0f, 0.0f, 0.0f, - 1.0f, 0.0f, 0.0f, - -1.0f, 0.0f, 0.0f, - -1.0f, 0.0f, 0.0f, - -1.0f, 0.0f, 0.0f, - -1.0f, 0.0f, 0.0f, - } -}; - -PieceType Pieces::mesh4c = { - { - // X Y Z Color - // URF corner - 0.5f, 0.5f, 0.5f, 0.0f, - -0.5f, 0.5f, 0.5f, 0.0f, - 0.5f, 0.5f, -0.5f, 0.0f, - 0.5f, -0.5f, 0.5f, 0.0f, - - // ULB corner - -0.5f, 0.5f, -0.5f, 1.0f, - 0.5f, 0.5f, -0.5f, 1.0f, - -0.5f, 0.5f, 0.5f, 1.0f, - -0.5f, -0.5f, -0.5f, 1.0f, - - // DRB corner - 0.5f, -0.5f, -0.5f, 2.0f, - 0.5f, -0.5f, 0.5f, 2.0f, - 0.5f, 0.5f, -0.5f, 2.0f, - -0.5f, -0.5f, -0.5f, 2.0f, - - // DLF corner - -0.5f, -0.5f, 0.5f, 3.0f, - -0.5f, 0.5f, 0.5f, 3.0f, - 0.5f, -0.5f, 0.5f, 3.0f, - -0.5f, -0.5f, -0.5f, 3.0f, - }, - { - 0, 2, 1, - 0, 3, 2, - 0, 1, 3, - 4, 6, 5, - 4, 7, 6, - 4, 5, 7, - 8, 10, 9, - 8, 11, 10, - 8, 9, 11, - 12, 14, 13, - 12, 15, 14, - 12, 13, 15, - }, - { - 4, 2, 2, 0, 0, 1, 1, 4, - 7, 8, 8, 3, 3, 12, 12, 7, - 4, 7, 2, 8, 0, 3, 1, 12, - 1, 2, 2, 3, 3, 1, - 7, 1, 7, 2, 7, 3, - }, - { - // X Y Z - 0.0f, 1.0f, 0.0f, - 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, - 0.0f, 1.0f, 0.0f, - -1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, -1.0f, - 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, -1.0f, - 0.0f, -1.0f, 0.0f, - 0.0f, 0.0f, 1.0f, - 0.0f, -1.0f, 0.0f, - -1.0f, 0.0f, 0.0f, - } -}; diff --git a/puzzle.cpp b/puzzle.cpp index 3827de2..bc5137e 100644 --- a/puzzle.cpp +++ b/puzzle.cpp @@ -18,6 +18,7 @@ **************************************************************************/ #include "puzzle.h" +#include std::array Puzzle::scheme = {PURPLE, PINK, RED, ORANGE, WHITE, YELLOW, GREEN, BLUE}; @@ -26,499 +27,77 @@ Puzzle::Puzzle() { } void Puzzle::resetPuzzle() { - initSlice(innerSlice, scheme[0], {scheme[4], scheme[5], scheme[6], scheme[7]}); - initSlice(outerSlice, scheme[1], {scheme[4], scheme[5], scheme[6], scheme[7]}); - initCell(rightCell, scheme[2], {scheme[1], scheme[0], scheme[4], scheme[5], scheme[6], scheme[7]}); - initCell(leftCell, scheme[3], {scheme[0], scheme[1], scheme[4], scheme[5], scheme[6], scheme[7]}); - - middleSlicePos = 0; - outerSlicePos = 1; - middleSliceDir = FRONT; - topCell = {scheme[4], UNUSED, UNUSED, UNUSED}; - bottomCell = {scheme[5], UNUSED, UNUSED, UNUSED}; - frontCell[0] = {scheme[6], scheme[5], UNUSED, UNUSED}; - frontCell[1] = {scheme[6], UNUSED, UNUSED, UNUSED}; - frontCell[2] = {scheme[6], scheme[4], UNUSED, UNUSED}; - backCell[0] = {scheme[7], scheme[5], UNUSED, UNUSED}; - backCell[1] = {scheme[7], UNUSED, UNUSED, UNUSED}; - backCell[2] = {scheme[7], scheme[4], UNUSED, UNUSED}; -} - -void Puzzle::initCell(CellData& cell, Color center, std::array faces) { - cell[1][1][1] = {center, UNUSED, UNUSED, UNUSED}; - - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 2; j++) { - std::array pos = {1, 1, 1}; - pos[i] = 2 - j * 2; - cell[pos[0]][pos[1]][pos[2]] = {center, faces[i * 2 + j], UNUSED, UNUSED}; - } - } - - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 2; j++) { - for (int k = 0; k < 2; k++) { - std::array pos = {1, 1, 1}; - pos[i] = 2 - k * 2; - pos[(i + 1) % 3] = 2 - j * 2; - std::array colors = {center, center, center}; - colors[(i + 1) % 3] = faces[2 + j + ((i<2) ? i : -1) * 2]; - colors[(i + 2) % 3] = faces[k + i * 2]; - cell[pos[0]][pos[1]][pos[2]] = {colors[0], colors[1], colors[2], UNUSED}; + for (int i = 0; i < 8; i++) { + for (int j = 0; j < 3; j++) { + for (int k = 0; k < 3; k++) { + for (int l = 0; l < 3; l++) { + cells[i][j][k][l] = (Color)((k*3+l)%8); + } } } } - for (int i = 0; i < 2; i++) { - for (int j = 0; j < 2; j++) { - for (int k = 0; k < 2; k++) { - std::array pos = {2 - i * 2, 2 - j * 2, 2 - k * 2}; - std::array colors = {center, faces[2 + j], UNUSED, UNUSED}; - int flip = i * 5 + (-2 * i + 1) * ((j + k) % 2 + 2); - colors[flip] = faces[i]; - colors[5 - flip] = faces[4 + k]; - cell[pos[0]][pos[1]][pos[2]] = {colors[0], colors[1], colors[2], colors[3]}; - } - } - } + rotateCell(RIGHT, ZY); } -void Puzzle::initSlice(SliceData& slice, Color center, std::array faces) { - slice[1][1] = {center, UNUSED, UNUSED, UNUSED}; - - for (int i = 1; i < 3; i++) { +void Puzzle::rotateSlice(int cell, int axis, int slice, int direction) { + Color temp; + std::array corners; + corners[4] = &temp; + for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { - std::array pos = {1, 1, 1}; - pos[i] = 2 - j * 2; - slice[pos[1]][pos[2]] = {center, faces[i * 2 - 2 + j], UNUSED, UNUSED}; - } - } - - for (int j = 0; j < 2; j++) { - for (int k = 0; k < 2; k++) { - std::array pos = {1, 2 - k * 2, 2 - j * 2}; - slice[pos[1]][pos[2]] = {faces[k], center, faces[2 + j], UNUSED}; + int coord1 = 2 * ((i + j) % 2); + int coord2 = 2 * i; + std::array pos; + pos[axis] = 2; + pos[(axis + 1) % 3] = coord1; + pos[(axis + 2) % 3] = coord2; + corners[i*2+j] = &cells[cell][pos[0]][pos[1]][pos[2]]; } } -} - -bool Puzzle::canRotateCell(CellLocation cell, RotateDirection direction) { - switch (cell) { - case IN: - case OUT: - return (direction == YZ || direction == ZY); - case UP: - case DOWN: - return (direction == XZ || direction == ZX); - case FRONT: - case BACK: - return (direction == XY || direction == YX); - case LEFT: - case RIGHT: - return true; - } - return false; -} - -void Puzzle::rotateCell(CellLocation cell, RotateDirection direction) { - if (!canRotateCell(cell, direction)) return; - switch (cell) { - case IN: - rotateSlice(leftCell[2], direction, 2); - rotateSlice(innerSlice, direction, 1); - rotateSlice(rightCell[0], direction, 0); - break; - case OUT: - rotateSlice(rightCell[2], direction, 2); - rotateSlice(outerSlice, direction, 1); - rotateSlice(leftCell[0], direction, 0); - break; - case LEFT: - if (direction == YZ || direction == ZY) { - rotateCellX(leftCell, direction); - } else if (direction == XZ || direction == ZX) { - rotateCellY(leftCell, direction); - } else { - rotateCellZ(leftCell, direction); - } - break; - case RIGHT: - if (direction == YZ || direction == ZY) { - rotateCellX(rightCell, direction); - } else if (direction == XZ || direction == ZX) { - rotateCellY(rightCell, direction); - } else { - rotateCellZ(rightCell, direction); - } - break; - default: - rotatePSliceCell(cell); - break; - } -} - -void Puzzle::rotateCellX(CellData& cell, RotateDirection direction) { - rotateSlice(cell[0], direction, 0); - rotateSlice(cell[1], direction, 1); - rotateSlice(cell[2], direction, 2); -} - -void Puzzle::rotateSlice(SliceData& slice, RotateDirection direction, int sliceNum) { - int front = (direction == YZ) ? 2 : 0; - int back = 2 - front; - Piece temp; - - // Rotate slice edges - temp = slice[2][1]; - std::array edges = {&slice[2][1], &slice[1][back], &slice[0][1], &slice[1][front], &temp}; - for (int i = 0; i < 4; i++) { - *edges[i] = *edges[i + 1]; - } - - // Rotate slice corners - temp = slice[2][front]; - std::array corners = {&slice[2][front], &slice[2][back], &slice[0][back], &slice[0][front], &temp}; + if (direction == -1) std::swap(corners[1], corners[3]); + temp = *corners[0]; for (int i = 0; i < 4; i++) { *corners[i] = *corners[i + 1]; } - switch (sliceNum) { - case 1: - // Fix 3c stickers - for (int i = 0; i < 4; i++) { - std::swap(corners[i]->a, corners[i]->c); - } - break; - case 0: - case 2: - // Fix 3c stickers - for (int i = 0; i < 4; i++) { - std::swap(edges[i]->a, edges[i]->c); - } - - // Fix 4c stickers - int starting = (sliceNum / 2 + ((direction == YZ) ? 1 : 0)) % 2; - for (int i = starting; i < 4; i += 2) { - Color tempcol = corners[i]->b; - corners[i]->b = corners[i]->c; - corners[i]->c = corners[i]->d; - corners[i]->d = tempcol; - } - for (int i = 1 - starting; i < 4; i += 2) { - Color tempcol = corners[i]->b; - corners[i]->b = corners[i]->d; - corners[i]->d = corners[i]->c; - corners[i]->c = tempcol; - } - break; - } -} - -void Puzzle::rotateCellY(CellData& cell, RotateDirection direction) { - int right = (direction == XZ) ? 2 : 0; - int left = 2 - right; - Piece temp; - - for (int i = 0; i < 3; i++) { - // Rotate slice edges - temp = cell[2][i][1]; - std::array edges = {&cell[2][i][1], &cell[1][i][left], &cell[0][i][1], &cell[1][i][right], &temp}; - for (int j = 0; j < 4; j++) { - *edges[j] = *edges[j + 1]; - } - - // Rotate slice corners - temp = cell[2][i][right]; - std::array corners = {&cell[2][i][right], &cell[2][i][left], &cell[0][i][left], &cell[0][i][right], &temp}; - for (int j = 0; j < 4; j++) { - *corners[j] = *corners[j + 1]; - } - - // Fix 3c stickers - if (i == 1) { - for (int j = 0; j < 4; j++) { - std::swap(corners[j]->a, corners[j]->b); - } - } else { - for (int j = 0; j < 4; j++) { - std::swap(edges[j]->a, edges[j]->b); - } - } - } -} - -void Puzzle::rotateCellZ(CellData& cell, RotateDirection direction) { - int top = (direction == XY) ? 2 : 0; - int bottom = 2 - top; - Piece temp; - - for (int i = 0; i < 3; i++) { - // Rotate slice edges - temp = cell[2][1][i]; - std::array edges = {&cell[2][1][i], &cell[1][bottom][i], &cell[0][1][i], &cell[1][top][i], &temp}; - for (int j = 0; j < 4; j++) { - *edges[j] = *edges[j + 1]; - } - - // Rotate slice corners - temp = cell[2][top][i]; - std::array corners = {&cell[2][top][i], &cell[2][bottom][i], &cell[0][bottom][i], &cell[0][top][i], &temp}; - for (int j = 0; j < 4; j++) { - *corners[j] = *corners[j + 1]; - } - - // Fix 3c stickers - if (i == 1) { - for (int j = 0; j < 4; j++) { - std::swap(corners[j]->b, corners[j]->c); - } - } else { - for (int j = 0; j < 4; j++) { - std::swap(edges[j]->b, edges[j]->c); - } - // Fix 4c stickers - int starting = (i / 2 + ((direction == YX) ? 1 : 0)) % 2; - for (int i = starting; i < 4; i += 2) { - Color tempcol = corners[i]->b; - corners[i]->b = corners[i]->c; - corners[i]->c = corners[i]->d; - corners[i]->d = tempcol; - } - for (int i = 1 - starting; i < 4; i += 2) { - Color tempcol = corners[i]->b; - corners[i]->b = corners[i]->d; - corners[i]->d = corners[i]->c; - corners[i]->c = tempcol; - } - } - } -} - -void Puzzle::rotatePSliceCell(CellLocation cell) { - int side; - switch (cell) { - case FRONT: - case BACK: - side = 1 - (int)cell % 2 * 2; - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - std::swap(leftCell[i][j][1 + side], rightCell[2 - i][2 - j][1 + side]); - } - } - std::swap(innerSlice[0][1 + side], innerSlice[2][1 + side]); - std::swap(outerSlice[0][1 + side], outerSlice[2][1 + side]); - if (cell == FRONT) { - std::swap(frontCell[0], frontCell[2]); - } else { - std::swap(backCell[0], backCell[2]); - } - break; - case UP: - case DOWN: - side = 1 - (int)cell % 2 * 2; - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - std::swap(leftCell[i][1 + side][j], rightCell[2 - i][1 + side][2 - j]); - } - } - std::swap(innerSlice[1 + side][0], innerSlice[1 + side][2]); - std::swap(outerSlice[1 + side][0], outerSlice[1 + side][2]); - std::swap(frontCell[1 + side], backCell[1 + side]); - break; - default: - return; - } -} - -void Puzzle::gyroCell(CellLocation cell) { - switch (cell) { - case RIGHT: - case LEFT: - gyroCellX(cell); - break; - case UP: - case DOWN: - gyroCellY(cell); - break; - case FRONT: - case BACK: - gyroCellZ(cell); - break; - case IN: - case OUT: - return; - } -} - -void Puzzle::gyroCellX(CellLocation cell) { - int parity = 1 - ((int)cell % 2) * 2; - SliceData temp = leftCell[1]; - std::array slices = {&leftCell[1], &innerSlice, &rightCell[1], &outerSlice, &temp}; - if (cell == LEFT) std::swap(slices[1], slices[3]); - for (int i = 0; i < 4; i++) { - *slices[i] = *slices[i + 1]; - } - temp = leftCell[0]; - slices = {&leftCell[0], &leftCell[2], &rightCell[0], &rightCell[2], &temp}; - if (cell == LEFT) std::swap(slices[1], slices[3]); + std::array edges; + edges[4] = &temp; + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 2; j++) { + int coord1 = 1 + j; + int coord2 = 2 * i; + std::array pos; + pos[axis] = 2; + pos[(axis + coord1) % 3] = coord2; + pos[(axis + 3 - coord1) % 3] = 1; + edges[i*2+j] = &cells[cell][pos[0]][pos[1]][pos[2]]; + std::cout << pos[0] << " " << pos[1] << " " << pos[2] << std::endl; + } + } + if (direction == -1) std::swap(edges[1], edges[3]); + temp = *edges[0]; for (int i = 0; i < 4; i++) { - *slices[i] = *slices[i + 1]; - } - middleSlicePos -= parity; - if ((outerSlicePos == parity && middleSlicePos == -2 * parity) || - (outerSlicePos == -parity && middleSlicePos == -3 * parity)) { - middleSlicePos += 4 * parity; - } - for (int i = 0; i < 3; i += 2) { - std::swap(leftCell[i][1][1].a, leftCell[i][1][1].b); - std::swap(rightCell[i][1][1].a, rightCell[i][1][1].b); - } - for (int i = 1; i < 3; i++) { - for (int j = 0; j < 3; j += 2) { - for (int k = 0; k < 3; k += 2) { - std::array pos = {1, 1, 1}; - pos[(i + 1) % 3] = j; - pos[(i + 2) % 3] = k; - std::swap(leftCell[pos[0]][pos[1]][pos[2]].a, leftCell[pos[0]][pos[1]][pos[2]].c); - std::swap(rightCell[pos[0]][pos[1]][pos[2]].a, rightCell[pos[0]][pos[1]][pos[2]].c); - } - } - } - for (int i = 0; i < 3; i += 2) { - for (int j = 0; j < 3; j += 2) { - for (int k = 0; k < 3; k += 2) { - int twist = (i + j + k) % 4; - if (twist == 2) { - std::swap(leftCell[i][j][k].a, leftCell[i][j][k].d); - std::swap(leftCell[i][j][k].d, leftCell[i][j][k].c); - std::swap(rightCell[i][j][k].a, rightCell[i][j][k].d); - std::swap(rightCell[i][j][k].d, rightCell[i][j][k].c); - } else { - std::swap(leftCell[i][j][k].a, leftCell[i][j][k].c); - std::swap(leftCell[i][j][k].c, leftCell[i][j][k].d); - std::swap(rightCell[i][j][k].a, rightCell[i][j][k].c); - std::swap(rightCell[i][j][k].c, rightCell[i][j][k].d); - } - } - } - } -} - -void Puzzle::gyroCellY(CellLocation cell) { - std::array slices = {&innerSlice, &outerSlice}; - int inner = cell % 2; - int outer = 1 - inner; - rotateCellZ(leftCell, (RotateDirection)(4 + inner)); - rotateCellZ(rightCell, (RotateDirection)(4 + outer)); - - // Cycle center strip - std::array topPieces = {&backCell[2], &topCell, &frontCell[2]}; - std::array bottomPieces = {&backCell[0], &bottomCell, &frontCell[0]}; - for (int i = 0; i < 3; i++) { - Piece temp = *topPieces[i]; - std::array pieces = {topPieces[i], &(*slices[outer])[1][i], bottomPieces[i], &(*slices[inner])[1][i], &temp}; - for (int j = 0; j < 4; j++) { - *pieces[j] = *pieces[j + 1]; - if (i != 1) { - std::swap(pieces[j]->a, pieces[j]->b); - } - } - } - - // Cycle edge strip - for (int i = 0; i < 3; i++) { - Piece temp = (*slices[inner])[2][i]; - std::array pieces = {&(*slices[inner])[2][i], &(*slices[outer])[2][i], &(*slices[outer])[0][i], &(*slices[inner])[0][i], &temp}; - for (int j = 0; j < 4; j++) { - *pieces[j] = *pieces[j + 1]; - std::swap(pieces[j]->a, pieces[j]->b); - } - } -} - -void Puzzle::gyroCellZ(CellLocation cell) { - std::array slices = {&innerSlice, &outerSlice}; - int inner = cell % 2; - int outer = 1 - inner; - rotateCellY(leftCell, (RotateDirection)(2 + outer)); - rotateCellY(rightCell, (RotateDirection)(2 + inner)); - - // Cycle center strip - for (int i = 0; i < 3; i++) { - Piece temp = frontCell[i]; - std::array pieces = {&frontCell[i], &(*slices[outer])[i][1], &backCell[i], &(*slices[inner])[i][1], &temp}; - for (int j = 0; j < 4; j++) { - *pieces[j] = *pieces[j + 1]; - } - } - - // Cycle edge strip - for (int i = 0; i < 3; i++) { - Piece temp = (*slices[inner])[i][2]; - std::array pieces = {&(*slices[inner])[i][2], &(*slices[outer])[i][2], &(*slices[outer])[i][0], &(*slices[inner])[i][0], &temp}; - for (int j = 0; j < 4; j++) { - *pieces[j] = *pieces[j + 1]; - if (i == 1) { - std::swap(pieces[j]->a, pieces[j]->b); - } else { - std::swap(pieces[j]->b, pieces[j]->c); - } - } - } -} - -bool Puzzle::canGyroMiddle(int direction) { - if (outerSlicePos == 1) { - return middleSlicePos + direction <= 2 && middleSlicePos + direction >= -1; - } else { - return middleSlicePos + direction <= 1 && middleSlicePos + direction >= -2; + *edges[i] = *edges[i + 1]; } } -void Puzzle::gyroOuterSlice() { - if (outerSlicePos * 2 == middleSlicePos) middleSlicePos *= -1; - outerSlicePos *= -1; -} - -void Puzzle::gyroMiddleSlice(int direction) { - if (direction == 0) { - if (middleSliceDir == UP) { - middleSliceDir = FRONT; - } else { - middleSliceDir = UP; - } - } else { - middleSlicePos += direction; +int adjacentCell(int cell, int axis) { + if (cell/2 - 1 == axis) { + return cell % 1; + } else if (cell/2 == 0) { + return 1 - (cell % 2); } + return (axis + 1) * 2; } -bool Puzzle::canRotatePuzzle(RotateDirection direction) { - return direction == YZ || direction == ZY; -} - -void Puzzle::rotatePuzzle(RotateDirection direction) { - rotateCellX(leftCell, direction); - rotateCellX(rightCell, direction); - rotateSlice(innerSlice, direction, 1); - rotateSlice(outerSlice, direction, 1); - - Piece temp = topCell; - std::array edges = {&topCell, &backCell[1], &bottomCell, &frontCell[1], &temp}; - if (direction == ZY) { - std::swap(edges[1], edges[3]); - } - for (int i = 0; i < 4; i++) { - *edges[i] = *edges[i + 1]; - } - - int up = (int)direction * 2; - int down = 2 - up; - temp = frontCell[up]; - std::array corners = {&frontCell[up], &backCell[up], &backCell[down], &frontCell[down], &temp}; +void Puzzle::rotateCell(CellLocation cell, RotateDirection direction, int slices) { + int axis1 = ((int)direction / 2 + 1 + (int)direction % 2) % 3; + int axis2 = ((int)direction / 2 + 2 - (int)direction % 2) % 3; + int cell1 = adjacentCell(cell, axis1); + int cell2 = adjacentCell(cell, axis2); + std::array rotating = {cell1, cell2, oppositeCell(cell1), oppositeCell(cell2), cell1}; for (int i = 0; i < 4; i++) { - *corners[i] = *corners[i + 1]; - std::swap(corners[i]->a, corners[i]->b); + rotateSlice(rotating[i], direction/2, 2); } - - gyroMiddleSlice(0); } diff --git a/puzzle.h b/puzzle.h index de3e684..154358d 100644 --- a/puzzle.h +++ b/puzzle.h @@ -38,15 +38,7 @@ typedef enum : int { ZY, YZ, XZ, ZX, YX, XY } RotateDirection; -typedef struct { - // Unused depending on piece type - Color a; - Color b; - Color c; - Color d; -} Piece; - -typedef std::array, 3> SliceData; +typedef std::array, 3> SliceData; typedef std::array CellData; class Puzzle { @@ -56,46 +48,10 @@ class Puzzle { static std::array scheme; Puzzle(); void resetPuzzle(); - bool canRotateCell(CellLocation cell, RotateDirection direction); - void rotateCell(CellLocation cell, RotateDirection direction); - void gyroCell(CellLocation cell); - void gyroOuterSlice(); - bool canGyroMiddle(int direction); - void gyroMiddleSlice(int direction); - bool canRotatePuzzle(RotateDirection direction); - void rotatePuzzle(RotateDirection direction); private: - // [x][y][z] - CellData leftCell; - // [x][y][z] - CellData rightCell; - // [y][z] - SliceData innerSlice; - // [y][z] - SliceData outerSlice; - // Measured from innerSlice, if 2 or -2 must match outerSlicePos - int middleSlicePos; - // Only 1 or -1 - int outerSlicePos; - // Either FRONT or UP - CellLocation middleSliceDir; - Piece topCell; - Piece bottomCell; - std::array frontCell; - std::array backCell; - - void initCell(CellData& cell, Color center, const std::array faces); - void initSlice(SliceData& slice, Color center, const std::array faces); - - void rotateSlice(SliceData& slice, RotateDirection direction, int sliceNum); - void rotateCellX(CellData& cell, RotateDirection direction); - void rotateCellY(CellData& cell, RotateDirection direction); - void rotateCellZ(CellData& cell, RotateDirection direction); - void rotatePSliceCell(CellLocation cell); - void gyroCellX(CellLocation cell); - void gyroCellY(CellLocation cell); - void gyroCellZ(CellLocation cell); + std::array cells; + void rotateSlice(int cell, int axis, int slice); }; #endif // puzzle.h diff --git a/render.cpp b/render.cpp index 68d6335..796ca4e 100644 --- a/render.cpp +++ b/render.cpp @@ -26,12 +26,6 @@ #include #include -void mat4x4_scale_pos(mat4x4 M, float k) { - for (int i = 0; i < 3; i++) { - M[3][i] *= k; - } -} - float smoothstep(float t) { return t * t * (3 - 2 * t); } @@ -153,981 +147,85 @@ Shader::~Shader() { PuzzleRenderer::PuzzleRenderer(Puzzle *puzzle) { this->puzzle = puzzle; - mousePressed = false; - spacing = 0.0f; - sensitivity = 0.01f; animating = false; animationProgress = 0.0f; animationSpeed = 4.0f; mat4x4_identity(model); - - meshes[0] = new PieceMesh(Pieces::mesh1c); - meshes[1] = new PieceMesh(Pieces::mesh2c); - meshes[2] = new PieceMesh(Pieces::mesh3c); - meshes[3] = new PieceMesh(Pieces::mesh4c); -} - -PuzzleRenderer::~PuzzleRenderer() { - for (int i = 0; i < 4; i++) { - delete meshes[i]; - } -} - -float PuzzleRenderer::getSpacing() { - return spacing; -} - -void PuzzleRenderer::setSpacing(float spacing) { - this->spacing = spacing; - if (this->spacing < 0.0f) { - this->spacing = 0.0f; - } else if (this->spacing > 1.5f) { - this->spacing = 1.5f; - } -} - -void PuzzleRenderer::render1c(Shader *shader, const std::array pos, Color color) { - shader->use(); - shader->setVec3("pieceColors[0]", Pieces::colors[color]); - - float scale = getSpacing() + 1.0f; - mat4x4 model; - mat4x4_dup(model, this->model); - mat4x4_translate_in_place(model, pos[0], pos[1], pos[2]); - mat4x4_scale_pos(model, scale); - shader->setMat4("model", model); - - shader->setInt("border", 0); - meshes[0]->renderFaces(shader); - shader->setInt("border", 1); - meshes[0]->renderEdges(); -} - -void PuzzleRenderer::render2c(Shader *shader, const std::array pos, const std::array colors, CellLocation dir) { - shader->use(); - shader->setVec3("pieceColors[0]", Pieces::colors[colors[0]]); - shader->setVec3("pieceColors[1]", Pieces::colors[colors[1]]); - - float scale = getSpacing() + 1.0f; - mat4x4 model; - mat4x4_dup(model, this->model); - mat4x4_translate_in_place(model, pos[0], pos[1], pos[2]); - mat4x4_scale_pos(model, scale); - - switch (dir) { - case UP: break; - case DOWN: mat4x4_rotate(model, model, 1, 0, 0, M_PI); break; - case RIGHT: mat4x4_rotate(model, model, 0, 0, 1, -M_PI_2); break; - case LEFT: mat4x4_rotate(model, model, 0, 0, 1, M_PI_2); break; - case FRONT: mat4x4_rotate(model, model, 1, 0, 0, M_PI_2); break; - case BACK: mat4x4_rotate(model, model, 1, 0, 0, -M_PI_2); break; - case IN: - case OUT: - return; - } - - shader->setMat4("model", model); - - shader->setInt("border", 0); - meshes[1]->renderFaces(shader); - shader->setInt("border", 1); - meshes[1]->renderEdges(); -} - -void PuzzleRenderer::render3c(Shader *shader, const std::array pos, const std::array colors) { - shader->use(); - shader->setVec3("pieceColors[0]", Pieces::colors[colors[0]]); - shader->setVec3("pieceColors[1]", Pieces::colors[colors[1]]); - shader->setVec3("pieceColors[2]", Pieces::colors[colors[2]]); - - float scale = getSpacing() + 1.0f; - mat4x4 model; - mat4x4_dup(model, this->model); - mat4x4_translate_in_place(model, pos[0], pos[1], pos[2]); - mat4x4_scale_pos(model, scale); - shader->setMat4("model", model); - - shader->setInt("border", 0); - meshes[2]->renderFaces(shader); - shader->setInt("border", 1); - meshes[2]->renderEdges(); -} - -void PuzzleRenderer::render4c(Shader *shader, const std::array pos, const std::array colors, int orientation) { - shader->use(); - shader->setVec3("pieceColors[0]", Pieces::colors[colors[0]]); - shader->setVec3("pieceColors[1]", Pieces::colors[colors[1]]); - shader->setVec3("pieceColors[2]", Pieces::colors[colors[2]]); - shader->setVec3("pieceColors[3]", Pieces::colors[colors[3]]); - - float scale = getSpacing() + 1.0f; - mat4x4 model; - mat4x4_dup(model, this->model); - mat4x4_translate_in_place(model, pos[0], pos[1], pos[2]); - mat4x4_scale_pos(model, scale); - if (orientation > 3) { - orientation -= 4; - mat4x4_rotate(model, model, 1, 0, 0, M_PI); - mat4x4_rotate(model, model, 0, 1, 0, -M_PI_2 * (orientation - 1)); - } else { - mat4x4_rotate(model, model, 0, 1, 0, M_PI_2 * orientation); - } - shader->setMat4("model", model); - - shader->setInt("border", 0); - meshes[3]->renderFaces(shader); - shader->setInt("border", 1); - meshes[3]->renderEdges(); -} - -void PuzzleRenderer::setMousePressed(bool pressed) { - mousePressed = pressed; -} - -bool PuzzleRenderer::updateMouse(GLFWwindow* window, double dt) { - // in case mousePressed flips - bool updated; - if (mousePressed) { - double curX, curY; - glfwGetCursorPos(window, &curX, &curY); - if (lastY != -1.0f) { - setSpacing(spacing - (curY - lastY) * sensitivity); - } - updated = (curY - lastY) != 0; - lastY = curY; - } else { - updated = (lastY != -1.0f); - lastY = -1.0f; - } - return updated; -} - -bool checkFilter(std::array filter, std::array pos) { - return ((filter[0] == -1 || filter[0] == pos[0] + 1) && - (filter[1] == -1 || filter[1] == pos[1] + 1)); -} - -bool checkFilter(std::array filter, std::array pos) { - return ((filter[0] == -1 || filter[0] == pos[0] + 1) && - (filter[1] == -1 || filter[1] == pos[1] + 1) && - (filter[2] == -1 || filter[2] == pos[2] + 1)); -} - -void PuzzleRenderer::renderCell(Shader *shader, const std::array, 3>, 3>& cell, float offset, std::array sliceFilter) { - if (checkFilter(sliceFilter, {0, 0, 0})) { - render1c(shader, {offset, 0, 0}, cell[1][1][1].a); - } - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 2; j++) { - std::array pos = {0, 0, 0}; - pos[i] += j * -2 + 1; - if (checkFilter(sliceFilter, pos)) { - Piece piece = cell[pos[0] + 1][pos[1] + 1][pos[2] + 1]; - CellLocation orientation = (CellLocation)(i * 2 + j + 2); - render2c(shader, {(float)pos[0] + offset, (float)pos[1], (float)pos[2]}, {piece.a, piece.b}, orientation); - } - } - } - - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 2; j++) { - for (int k = 0; k < 2; k++) { - std::array pos = {0, 0, 0}; - pos[i] = k * -2 + 1; - pos[(i + 1) % 3] = j * -2 + 1; - if (checkFilter(sliceFilter, pos)) { - Piece piece = cell[pos[0] + 1][pos[1] + 1][pos[2] + 1]; - render3c(shader, {(float)pos[0] + offset, (float)pos[1], (float)pos[2]}, {piece.a, piece.b, piece.c}); - } - } - } - } - - for (int i = 0; i < 2; i++) { - for (int j = 0; j < 2; j++) { - for (int k = 0; k < 2; k++) { - std::array pos = {i * -2 + 1, j * -2 + 1, k * -2 + 1}; - int orientation = (i + k) + 2*i*(1 - k); - if (checkFilter(sliceFilter, pos)) { - Piece piece = cell[pos[0] + 1][pos[1] + 1][pos[2] + 1]; - render4c(shader, {(float)pos[0] + offset, (float)pos[1], (float)pos[2]}, {piece.a, piece.b, piece.c, piece.d}, 4*j + orientation); - } - } - } - } -} - -void PuzzleRenderer::renderSlice(Shader *shader, const std::array, 3>& slice, float offset, std::array stripFilter) { - if (checkFilter(stripFilter, {0, 0})) { - render1c(shader, {offset, 0, 0}, slice[1][1].a); - } - for (int i = 1; i < 3; i++) { - for (int j = 0; j < 2; j++) { - std::array pos = {0, 0, 0}; - pos[i] += j * -2 + 1; - if (checkFilter(stripFilter, {pos[1], pos[2]})) { - Piece piece = slice[pos[1] + 1][pos[2] + 1]; - CellLocation orientation = (CellLocation)(i * 2 + j + 2); - render2c(shader, {(float)pos[0] + offset, (float)pos[1], (float)pos[2]}, {piece.a, piece.b}, orientation); - } - } - } - - for (int j = 0; j < 2; j++) { - for (int k = 0; k < 2; k++) { - std::array pos = {0, 0, 0}; - pos[1] = k * -2 + 1; - pos[2] = j * -2 + 1; - if (checkFilter(stripFilter, {pos[1], pos[2]})) { - Piece piece = slice[pos[1] + 1][pos[2] + 1]; - render3c(shader, {(float)pos[0] + offset, (float)pos[1], (float)pos[2]}, {piece.a, piece.b, piece.c}); - } - } - } -} - -void PuzzleRenderer::renderMiddleSlice(Shader *shader, bool addOffsetX, float offsetYZ, CellLocation filter) { - float offset = (addOffsetX ? -0.5 * puzzle->outerSlicePos : 0.0f) + 2 * puzzle->middleSlicePos; - if (filter == UP || filter == (CellLocation)-1) { - render1c(shader, {offset, 2 + offsetYZ, 0}, puzzle->topCell.a); - } - if (filter == DOWN || filter == (CellLocation)-1) { - render1c(shader, {offset, -2 - offsetYZ, 0}, puzzle->bottomCell.a); - } - if (filter == FRONT || filter == (CellLocation)-1) { - render1c(shader, {offset, 0, 2 + offsetYZ}, puzzle->frontCell[1].a); - } - if (filter == BACK || filter == (CellLocation)-1) { - render1c(shader, {offset, 0, -2 - offsetYZ}, puzzle->backCell[1].a); - } - - if (puzzle->middleSliceDir == FRONT) { - if (filter == FRONT || filter == (CellLocation)-1) { - render2c(shader, {offset, 1, 2 + offsetYZ}, {puzzle->frontCell[2].a, puzzle->frontCell[2].b}, UP); - render2c(shader, {offset, -1, 2 + offsetYZ}, {puzzle->frontCell[0].a, puzzle->frontCell[0].b}, DOWN); - } - if (filter == BACK || filter == (CellLocation)-1) { - render2c(shader, {offset, 1, -2 - offsetYZ}, {puzzle->backCell[2].a, puzzle->backCell[2].b}, UP); - render2c(shader, {offset, -1, -2 - offsetYZ}, {puzzle->backCell[0].a, puzzle->backCell[0].b}, DOWN); - } - } else { - if (filter == UP || filter == (CellLocation)-1) { - render2c(shader, {offset, 2 + offsetYZ, 1}, {puzzle->frontCell[2].a, puzzle->frontCell[2].b}, BACK); - render2c(shader, {offset, 2 + offsetYZ, -1}, {puzzle->backCell[2].a, puzzle->backCell[2].b}, FRONT); - } - if (filter == DOWN || filter == (CellLocation)-1) { - render2c(shader, {offset, -2 - offsetYZ, -1}, {puzzle->backCell[0].a, puzzle->backCell[0].b}, FRONT); - render2c(shader, {offset, -2 - offsetYZ, 1}, {puzzle->frontCell[0].a, puzzle->frontCell[0].b}, BACK); - } - } + mesh = new PieceMesh(Pieces::mesh1c); } void PuzzleRenderer::renderPuzzle(Shader *shader) { glLineWidth(2); if (pendingMoves.size() == 0) { renderNoAnimation(shader); - } else if (pendingMoves.front().type == TURN) { + } /* else if (pendingMoves.front().type == TURN) { MoveEntry move = pendingMoves.front(); - switch (move.cell) { - case LEFT: renderLeftAnimation(shader, move.direction); break; - case RIGHT: renderRightAnimation(shader, move.direction); break; - case IN: renderInnerAnimation(shader, move.direction); break; - case OUT: renderOuterAnimation(shader, move.direction); break; - case FRONT: renderFrontBackAnimation(shader, FRONT, move.direction); break; - case BACK: renderFrontBackAnimation(shader, BACK, move.direction); break; - case UP: renderUpDownAnimation(shader, UP, move.direction); break; - case DOWN: renderUpDownAnimation(shader, DOWN, move.direction); break; - } - } else if (pendingMoves.front().type == ROTATE) { - renderRotateAnimation(shader, pendingMoves.front().direction); + renderTurnAnimation(shader, move.cell, move.direction, move.slices); } else if (pendingMoves.front().type == GYRO) { MoveEntry move = pendingMoves.front(); - switch (move.cell) { - case LEFT: - case RIGHT: - renderGyroXAnimation(shader, move.cell); - break; - case UP: - case DOWN: - renderGyroYAnimation(shader, move.cell); - break; - case FRONT: - case BACK: - renderGyroZAnimation(shader, move.cell); - break; - default: - return; - } - } else if (pendingMoves.front().type == GYRO_OUTER) { - renderOuterGyroAnimation(shader, pendingMoves.front().location); - } else if (pendingMoves.front().type == GYRO_MIDDLE) { - renderPGyroAnimation(shader, pendingMoves.front().location); - } + renderGyroAnimation(shader, move.cell); + } */ } void PuzzleRenderer::renderNoAnimation(Shader *shader) { - float offset = puzzle->outerSlicePos * -0.5f; - mat4x4_identity(model); - renderSlice(shader, puzzle->outerSlice, 3.5f * puzzle->outerSlicePos); - renderCell(shader, puzzle->leftCell, -2.0f + offset); - renderCell(shader, puzzle->rightCell, 2.0f + offset); - renderSlice(shader, puzzle->innerSlice, offset); - renderMiddleSlice(shader, true, 0.0f); -} - -void PuzzleRenderer::renderLeftAnimation(Shader *shader, RotateDirection direction) { - if (puzzle->outerSlicePos == 1) { - float offset = 2 * animationProgress * (animationProgress - 1.0f); - std::array axis = {0, 0, 0}; - axis[(int)direction / 2] = -1 + (int)direction % 2 * 2; - - mat4x4_translate(model, -2.5f + offset, 0, 0); - mat4x4_rotate(model, model, axis[0], axis[1], axis[2], M_PI_2 * animationProgress); - renderCell(shader, puzzle->leftCell, 0.0f); - - mat4x4_identity(model); - if (puzzle->middleSlicePos == -1) renderMiddleSlice(shader, true, -offset); - - mat4x4_translate(model, -offset, 0, 0); - renderCell(shader, puzzle->rightCell, 1.5f); - renderSlice(shader, puzzle->innerSlice, -0.5f); - renderSlice(shader, puzzle->outerSlice, 3.5f); - if (puzzle->middleSlicePos >= 0) renderMiddleSlice(shader, true, 0.0f); - } else { - float offset = 4 * animationProgress * (animationProgress - 1.0f); - std::array axis = {0, 0, 0}; - axis[(int)direction / 2] = -1 + (int)direction % 2 * 2; - - mat4x4_translate(model, -1.5f, 0, 0); - mat4x4_rotate(model, model, axis[0], axis[1], axis[2], M_PI_2 * animationProgress); - renderCell(shader, puzzle->leftCell, 0.0f); - - mat4x4_identity(model); - if (puzzle->middleSlicePos == -1) renderMiddleSlice(shader, true, -offset); - - mat4x4_translate(model, offset, 0, 0); - renderSlice(shader, puzzle->outerSlice, -3.5f); - if (puzzle->middleSlicePos == -2) renderMiddleSlice(shader, true, 0.0f); - - mat4x4_translate(model, -offset, 0, 0); - renderCell(shader, puzzle->rightCell, 2.5f); - renderSlice(shader, puzzle->innerSlice, 0.5f); - if (puzzle->middleSlicePos >= 0) renderMiddleSlice(shader, true, 0.0f); - } -} - -void PuzzleRenderer::renderRightAnimation(Shader *shader, RotateDirection direction) { - if (puzzle->outerSlicePos == -1) { - float offset = 2 * animationProgress * (animationProgress - 1.0f); - std::array axis = {0, 0, 0}; - axis[(int)direction / 2] = -1 + (int)direction % 2 * 2; - - mat4x4_translate(model, 2.5f - offset, 0, 0); - mat4x4_rotate(model, model, axis[0], axis[1], axis[2], M_PI_2 * animationProgress); - renderCell(shader, puzzle->rightCell, 0.0f); - - mat4x4_identity(model); - if (puzzle->middleSlicePos == 1) renderMiddleSlice(shader, true, -offset); - - mat4x4_translate(model, offset, 0, 0); - renderCell(shader, puzzle->leftCell, -1.5f); - renderSlice(shader, puzzle->innerSlice, 0.5f); - renderSlice(shader, puzzle->outerSlice, -3.5f); - if (puzzle->middleSlicePos <= 0) renderMiddleSlice(shader, true, 0.0f); - } else { - float offset = 4 * animationProgress * (animationProgress - 1.0f); - std::array axis = {0, 0, 0}; - axis[(int)direction / 2] = -1 + (int)direction % 2 * 2; - - mat4x4_translate(model, 1.5f, 0, 0); - mat4x4_rotate(model, model, axis[0], axis[1], axis[2], M_PI_2 * animationProgress); - renderCell(shader, puzzle->rightCell, 0.0f); - - mat4x4_identity(model); - if (puzzle->middleSlicePos == 1) renderMiddleSlice(shader, true, -offset); - - mat4x4_translate(model, -offset, 0, 0); - renderSlice(shader, puzzle->outerSlice, 3.5f); - if (puzzle->middleSlicePos == 2) renderMiddleSlice(shader, true, 0.0f); - - mat4x4_translate(model, offset, 0, 0); - renderCell(shader, puzzle->leftCell, -2.5f); - renderSlice(shader, puzzle->innerSlice, -0.5f); - if (puzzle->middleSlicePos <= 0) renderMiddleSlice(shader, true, 0.0f); - } -} - -void PuzzleRenderer::renderInnerAnimation(Shader *shader, RotateDirection direction) { - float offset = puzzle->outerSlicePos * -0.5f; - mat4x4_identity(model); - renderSlice(shader, puzzle->outerSlice, 3.5f * puzzle->outerSlicePos); - renderCell(shader, puzzle->leftCell, -2.0f + offset, {0, -1, -1}); - renderCell(shader, puzzle->leftCell, -2.0f + offset, {1, -1, -1}); - renderCell(shader, puzzle->rightCell, 2.0f + offset, {1, -1, -1}); - renderCell(shader, puzzle->rightCell, 2.0f + offset, {2, -1, -1}); - - float offsetYZ = -4 * animationProgress * (animationProgress - 1.0f); - if (puzzle->middleSlicePos == 0) { - renderMiddleSlice(shader, true, offsetYZ); - } else { - renderMiddleSlice(shader, true, 0.0f); - } - - int parity = (int)direction % 2 * 2 - 1; - mat4x4_rotate(model, model, 1, 0, 0, M_PI_2 * animationProgress * parity); - renderSlice(shader, puzzle->innerSlice, offset); - renderCell(shader, puzzle->leftCell, -2.0f + offset, {2, -1, -1}); - renderCell(shader, puzzle->rightCell, 2.0f + offset, {0, -1, -1}); -} - -void PuzzleRenderer::renderOuterAnimation(Shader *shader, RotateDirection direction) { - float offset = puzzle->outerSlicePos * -0.5f; - mat4x4_identity(model); - renderSlice(shader, puzzle->innerSlice, offset); - renderCell(shader, puzzle->leftCell, -2.0f + offset, {1, -1, -1}); - renderCell(shader, puzzle->leftCell, -2.0f + offset, {2, -1, -1}); - renderCell(shader, puzzle->rightCell, 2.0f + offset, {0, -1, -1}); - renderCell(shader, puzzle->rightCell, 2.0f + offset, {1, -1, -1}); - - float offsetYZ = -4 * animationProgress * (animationProgress - 1.0f); - if (puzzle->middleSlicePos == 2 * puzzle->outerSlicePos) { - renderMiddleSlice(shader, true, offsetYZ); - } else { - renderMiddleSlice(shader, true, 0.0f); - } - - int parity = (int)direction % 2 * 2 - 1; - mat4x4_rotate(model, model, 1, 0, 0, M_PI_2 * animationProgress * parity); - renderSlice(shader, puzzle->outerSlice, 3.5f * puzzle->outerSlicePos); - renderCell(shader, puzzle->leftCell, -2.0f + offset, {0, -1, -1}); - renderCell(shader, puzzle->rightCell, 2.0f + offset, {2, -1, -1}); -} - -void PuzzleRenderer::renderFrontBackAnimation(Shader *shader, CellLocation cell, RotateDirection direction) { - int orientation = 1 - (int)cell % 2 * 2; - float offset = puzzle->outerSlicePos * -0.5f; - mat4x4_identity(model); - for (int i = 0; i < 3; i++) { - if (i == 1 + orientation) continue; - renderSlice(shader, puzzle->outerSlice, 3.5f * puzzle->outerSlicePos, {-1, i}); - renderCell(shader, puzzle->leftCell, -2.0f + offset, {-1, -1, i}); - renderCell(shader, puzzle->rightCell, 2.0f + offset, {-1, -1, i}); - renderSlice(shader, puzzle->innerSlice, offset, {-1, i}); - } - renderMiddleSlice(shader, true, 0.0f, (CellLocation)((int)cell / 2 * 2 + 1 - int(cell) % 2)); - renderMiddleSlice(shader, true, 0.0f, UP); - renderMiddleSlice(shader, true, 0.0f, DOWN); - - if (animationProgress < 1.0f) { - float offsetZ = orientation * -4 * animationProgress * (animationProgress - 1.0f); - float axis = (int)direction % 2 * 2 - 1; - mat4x4_translate(model, -0.5f * puzzle->outerSlicePos, 0, offsetZ); - mat4x4_rotate(model, model, 0, 0, axis, M_PI * animationProgress); - mat4x4_translate_in_place(model, 0.5f * puzzle->outerSlicePos, 0, 0); - renderSlice(shader, puzzle->outerSlice, 3.5f * puzzle->outerSlicePos, {-1, 1 + orientation}); - renderCell(shader, puzzle->leftCell, -2.0f + offset, {-1, -1, 1 + orientation}); - renderCell(shader, puzzle->rightCell, 2.0f + offset, {-1, -1, 1 + orientation}); - renderSlice(shader, puzzle->innerSlice, offset, {-1, 1 + orientation}); - renderMiddleSlice(shader, true, 0.0f, cell); - } else { - mat4x4 base; - mat4x4_translate(base, -0.5f * puzzle->outerSlicePos, 0, 0); - mat4x4_rotate(base, base, 0, 0, 1, M_PI); - mat4x4_translate_in_place(base, 0.5f * puzzle->outerSlicePos, 0, 0); - - mat4x4_dup(model, base); - renderCell(shader, puzzle->leftCell, -2.0f + offset, {-1, -1, 1 + orientation}); - renderCell(shader, puzzle->rightCell, 2.0f + offset, {-1, -1, 1 + orientation}); - renderSlice(shader, puzzle->innerSlice, offset, {-1, 1 + orientation}); - if (puzzle->middleSlicePos == 0) { - renderMiddleSlice(shader, true, 0, cell); - } - - float offsetX = smoothstep(animationProgress - 1.0f); - float offsetZ = 16 * std::pow(animationProgress - 1.0f, 2) * std::pow(animationProgress - 2.0f, 2); - offsetZ *= orientation; - if (std::abs(puzzle->middleSlicePos) == 1) { - mat4x4_dup(model, base); - mat4x4_translate_in_place(model, -4 * puzzle->middleSlicePos * offsetX, 0, offsetZ); - renderMiddleSlice(shader, true, 0, cell); - } - mat4x4_dup(model, base); - mat4x4_translate_in_place(model, -8 * offsetX * puzzle->outerSlicePos, 0, 4 * offsetZ); - renderSlice(shader, puzzle->outerSlice, 3.5f * puzzle->outerSlicePos, {-1, 1 + orientation}); - if (puzzle->middleSlicePos == 2 * puzzle->outerSlicePos) { - renderMiddleSlice(shader, true, 0, cell); - } - } -} - -void PuzzleRenderer::renderUpDownAnimation(Shader *shader, CellLocation cell, RotateDirection direction) { - int orientation = 1 - (int)cell % 2 * 2; - float offset = puzzle->outerSlicePos * -0.5f; - mat4x4_identity(model); - for (int i = 0; i < 3; i++) { - if (i == 1 + orientation) continue; - renderSlice(shader, puzzle->outerSlice, 3.5f * puzzle->outerSlicePos, {i, -1}); - renderCell(shader, puzzle->leftCell, -2.0f + offset, {-1, i, -1}); - renderCell(shader, puzzle->rightCell, 2.0f + offset, {-1, i, -1}); - renderSlice(shader, puzzle->innerSlice, offset, {i, -1}); - } - renderMiddleSlice(shader, true, 0.0f, (CellLocation)((int)cell / 2 * 2 + 1 - int(cell) % 2)); - renderMiddleSlice(shader, true, 0.0f, FRONT); - renderMiddleSlice(shader, true, 0.0f, BACK); - - if (animationProgress < 1.0f) { - float offsetY = orientation * -4 * animationProgress * (animationProgress - 1.0f); - float axis = (int)direction % 2 * 2 - 1; - mat4x4_translate(model, -0.5f * puzzle->outerSlicePos, offsetY, 0); - mat4x4_rotate(model, model, 0, axis, 0, M_PI * animationProgress); - mat4x4_translate_in_place(model, 0.5f * puzzle->outerSlicePos, 0, 0); - renderSlice(shader, puzzle->outerSlice, 3.5f * puzzle->outerSlicePos, {1 + orientation, -1}); - renderCell(shader, puzzle->leftCell, -2.0f + offset, {-1, 1 + orientation, -1}); - renderCell(shader, puzzle->rightCell, 2.0f + offset, {-1, 1 + orientation, -1}); - renderSlice(shader, puzzle->innerSlice, offset, {1 + orientation, -1}); - renderMiddleSlice(shader, true, 0.0f, cell); - } else { - mat4x4 base; - mat4x4_translate(base, -0.5f * puzzle->outerSlicePos, 0, 0); - mat4x4_rotate(base, base, 0, 1, 0, M_PI); - mat4x4_translate_in_place(base, 0.5f * puzzle->outerSlicePos, 0, 0); - - mat4x4_dup(model, base); - renderCell(shader, puzzle->leftCell, -2.0f + offset, {-1, 1 + orientation, -1}); - renderCell(shader, puzzle->rightCell, 2.0f + offset, {-1, 1 + orientation, -1}); - renderSlice(shader, puzzle->innerSlice, offset, {1 + orientation, -1}); - if (puzzle->middleSlicePos == 0) { - renderMiddleSlice(shader, true, 0, cell); - } - - float offsetX = smoothstep(animationProgress - 1.0f); - float offsetY = 16 * std::pow(animationProgress - 1.0f, 2) * std::pow(animationProgress - 2.0f, 2); - offsetY *= orientation; - if (std::abs(puzzle->middleSlicePos) == 1) { - mat4x4_dup(model, base); - mat4x4_translate_in_place(model, -4 * puzzle->middleSlicePos * offsetX, offsetY, 0); - renderMiddleSlice(shader, true, 0, cell); - } - mat4x4_dup(model, base); - mat4x4_translate_in_place(model, -8 * offsetX * puzzle->outerSlicePos, 4 * offsetY, 0); - renderSlice(shader, puzzle->outerSlice, 3.5f * puzzle->outerSlicePos, {1 + orientation, -1}); - if (puzzle->middleSlicePos == 2 * puzzle->outerSlicePos) { - renderMiddleSlice(shader, true, 0, cell); - } - } -} - -void PuzzleRenderer::renderRotateAnimation(Shader *shader, RotateDirection direction) { - int parity = (int)direction * 2 - 1; + static float a = 0.0f; + // a += 0.1f; + mat4x4 base; + mat4x4_identity(base); + mat4x4 model; mat4x4_identity(model); - mat4x4_rotate(model, model, 1, 0, 0, parity * M_PI_2 * animationProgress); - - float offset = puzzle->outerSlicePos * -0.5f; - renderSlice(shader, puzzle->outerSlice, 3.5f * puzzle->outerSlicePos); - renderCell(shader, puzzle->leftCell, -2.0f + offset); - renderCell(shader, puzzle->rightCell, 2.0f + offset); - renderSlice(shader, puzzle->innerSlice, offset); - renderMiddleSlice(shader, true, 0.0f); -} - -void PuzzleRenderer::renderGyroXAnimation(Shader *shader, CellLocation cell) { - int mainDir = (int)cell % 2 * -2 + 1; - int moveSlice = (1 - mainDir * puzzle->outerSlicePos) / 2; - std::array cells = {&puzzle->leftCell, &puzzle->rightCell}; - int left = (int)cell % 2; - int right = 1 - left; - if (animationProgress < 2.0f) { - int middleMove = -1 + 3 * moveSlice; - float mainOffsetX, mainOffsetY, slicePosX, slicePosY; - if (animationProgress < 0.5f) { - slicePosX = -0.5f * puzzle->outerSlicePos - 2 * mainDir; - slicePosY = -16 * animationProgress * (animationProgress - 1.0f); - mainOffsetX = -0.5f * puzzle->outerSlicePos; - mainOffsetY = 2 * animationProgress * (animationProgress - 1.0f); - } else if (animationProgress < 1.5f) { - slicePosX = -0.5f * puzzle->outerSlicePos + mainDir * (smoothstep(animationProgress - 0.5f) * 6 - 2); - slicePosY = 4.0f; - mainOffsetX = -0.5f * puzzle->outerSlicePos - mainDir * smoothstep(animationProgress - 0.5f) * 2; - mainOffsetY = -0.5f; - } else { - slicePosX = -0.5f * puzzle->outerSlicePos + 4 * mainDir; - slicePosY = -16 * (animationProgress - 1.0f) * (animationProgress - 2.0f); - mainOffsetX = -0.5f * puzzle->outerSlicePos - 2 * mainDir; - mainOffsetY = 2 * (animationProgress - 1.0f) * (animationProgress - 2.0f); - } - mat4x4_translate(model, slicePosX, slicePosY, 0); - renderCell(shader, *cells[left], 0.0f, {1 - mainDir, -1, -1}); - if (mainDir * puzzle->outerSlicePos == 1) { - renderCell(shader, *cells[left], 0.0f, {1, -1, -1}); - } else { - renderSlice(shader, puzzle->outerSlice, 2.0f * puzzle->outerSlicePos); - } - // Undo X offset made by renderMiddleSlice - float reset = -2 * puzzle->middleSlicePos; - mat4x4_translate_in_place(model, reset - mainDir + puzzle->outerSlicePos, 0, 0); - if (puzzle->middleSlicePos == middleMove * puzzle->outerSlicePos) renderMiddleSlice(shader, false, 0.0f); - - mat4x4_translate(model, mainOffsetX, mainOffsetY, 0); - if (mainDir * puzzle->outerSlicePos == 1) { - renderSlice(shader, puzzle->outerSlice, 4.0f * puzzle->outerSlicePos); - } else { - renderCell(shader, *cells[left], 2.0f * puzzle->outerSlicePos, {1, -1, -1}); - } - renderCell(shader, *cells[left], -2.0f * mainDir, {1 + mainDir, -1, -1}); - renderCell(shader, *cells[right], 2.0f * mainDir); - renderSlice(shader, puzzle->innerSlice, 0.0f); - if (puzzle->middleSlicePos != middleMove * puzzle->outerSlicePos) renderMiddleSlice(shader, false, 0.0f); - } else { - float offset = (cosf(M_PI * (animationProgress + 1.0f)) + 1) / 8; - mat4x4_identity(model); - - std::array slices = { - &(*cells[left])[2], &puzzle->innerSlice, &(*cells[right])[0], &(*cells[right])[1], - &(*cells[right])[2], &puzzle->outerSlice, &(*cells[left])[0], &(*cells[left])[1] - }; - if (left == 1) { - std::swap(slices[1], slices[5]); - } - if (puzzle->outerSlicePos == -1) { - std::rotate(slices.rbegin(), slices.rbegin() + 1, slices.rend()); - } - for (int i = (puzzle->outerSlicePos + 1) / 2; i < 8; i += 2) { - renderSlice(shader, *slices[i], i - 3.5 + offset * (-9 + 2 * i)); - } - - int newMiddlePos; - if (puzzle->outerSlicePos == -1) { - newMiddlePos = (puzzle->middleSlicePos - mainDir + 6) % 4 - 2; - } else { - newMiddlePos = (puzzle->middleSlicePos - mainDir + 5) % 4 - 1; - } - float newMiddleOffset = -2 * puzzle->middleSlicePos + newMiddlePos * 2 + offset * (4 * newMiddlePos - 2 - puzzle->outerSlicePos); - float rotProgress = smoothstep((animationProgress - 2.0f) / 2); - mat4x4_translate(model, newMiddleOffset, 0, 0); - renderMiddleSlice(shader, true, 0.0f); - - for (int i = (1 - puzzle->outerSlicePos) / 2; i < 8; i += 2) { - CellLocation direction = (CellLocation)(i / 2 % 2 + 2); - mat4x4 baseModel; - mat4x4_translate(baseModel, i - 3.5 + offset * (-9 + 2 * i), 0, 0); - - mat4x4_dup(model, baseModel); - render2c(shader, {0, 0, 0}, {(*slices[i])[1][1].a, (*slices[i])[1][1].b}, direction); - - int flipRot = i / 2 % 2 * 2 - 1; - for (int j = 0; j < 2; j++) { - for (int k = -1; k < 2; k += 2) { - std::array pos = {0, 0}; - pos[j] = k; - Piece piece = (*slices[i])[pos[0] + 1][pos[1] + 1]; - pos[j] = k * (1 + offset * 4); - mat4x4_dup(model, baseModel); - mat4x4_translate_in_place(model, 0, pos[0], pos[1]); - mat4x4_rotate(model, model, flipRot * mainDir, 0, 0, M_PI_2 * rotProgress); - render3c(shader, {0, 0, 0}, {piece.a, piece.b, piece.c}); - } - } - - for (int j = -1; j < 2; j += 2) { - for (int k = -1; k < 2; k += 2) { - std::array pos = {(float)j, (float)k}; - Piece piece = (*slices[i])[pos[0] + 1][pos[1] + 1]; - pos[0] *= (1 + offset * 4); - pos[1] *= (1 + offset * 4); - int orientation = 2 - 2 * j + (3 + flipRot * (k + 2)) / 2; - mat4x4_dup(model, baseModel); - mat4x4_translate_in_place(model, 0, pos[0], pos[1]); - mat4x4_rotate(model, model, 0, k * flipRot, 0, M_PI * rotProgress); - mat4x4_rotate(model, model, j * k, 0, 0, M_PI_2 * rotProgress); - render4c(shader, {0, 0, 0}, {piece.a, piece.b, piece.c, piece.d}, orientation); - } - } - } - } -} - -void PuzzleRenderer::renderGyroYAnimation(Shader *shader, CellLocation cell) { - int direction = puzzle->outerSlicePos * ((int)cell % 2 * -2 + 1); - std::array cells = {&puzzle->leftCell, &puzzle->rightCell}; - int left = (1 - puzzle->outerSlicePos) / 2; - int right = 1 - left; - if (animationProgress < 1.0f) { - float halfOffset = -2 * animationProgress * (animationProgress - 1.0f); - - mat4x4_translate(model, puzzle->outerSlicePos * -(halfOffset + 2.5f), 0, 0); - mat4x4_rotate(model, model, 0, 0, -direction, M_PI_2 * animationProgress); - renderCell(shader, *cells[left], 0); - - mat4x4_translate(model, puzzle->outerSlicePos * (halfOffset + 1.5f), 0, 0); - mat4x4_rotate(model, model, 0, 0, direction, M_PI_2 * animationProgress); - mat4x4_translate_in_place(model, puzzle->outerSlicePos * -1.5f, 0, 0); - renderSlice(shader, puzzle->innerSlice, puzzle->outerSlicePos * -0.5f); - renderMiddleSlice(shader, true, 0.0f); - renderCell(shader, *cells[right], puzzle->outerSlicePos * 1.5f); - renderSlice(shader, puzzle->outerSlice, puzzle->outerSlicePos * 3.5f); - } else { - mat4x4_translate(model, puzzle->outerSlicePos * -2.5f, 0, 0); - mat4x4_rotate(model, model, 0, 0, -direction, M_PI_2); - renderCell(shader, *cells[left], 0); - - mat4x4 base; - mat4x4_translate(base, puzzle->outerSlicePos * 1.5f, 0, 0); - mat4x4_rotate(base, base, 0, 0, direction, M_PI_2); - mat4x4_translate_in_place(base, puzzle->outerSlicePos * -1.5f, 0, 0); - - mat4x4_dup(model, base); - renderSlice(shader, puzzle->innerSlice, puzzle->outerSlicePos * -0.5f, {1, -1}); - renderMiddleSlice(shader, true, 0.0f); - renderCell(shader, *cells[right], puzzle->outerSlicePos * 1.5f); - renderSlice(shader, puzzle->outerSlice, puzzle->outerSlicePos * 3.5f, {1, -1}); - - float stripYRotation = std::min(1.0f, std::max(0.0f, (animationProgress - 1.0f) * 2)); - float stripXOffset = std::min(1.0f, std::max(0.0f, (animationProgress - 1.5f) * 2)); - stripYRotation = -M_PI_2 * stripYRotation * puzzle->outerSlicePos; - stripXOffset = (stripXOffset + 0.5f) * puzzle->outerSlicePos; - int stripFilter = (animationProgress < 2.0f) ? -1 : 1; - for (int i = -1; i < 2; i += 2) { - mat4x4_dup(model, base); - mat4x4_translate_in_place(model, puzzle->outerSlicePos * -0.5f + stripXOffset, i * 1.5f, 0); - mat4x4_rotate(model, model, 0, 0, i, stripYRotation); - mat4x4_translate_in_place(model, puzzle->outerSlicePos * -0.5f, -i * 1.5f, 0); - renderSlice(shader, puzzle->innerSlice, 0, {1 + i, stripFilter}); - mat4x4_dup(model, base); - mat4x4_translate_in_place(model, puzzle->outerSlicePos * 3.5f - stripXOffset, i * 1.5f, 0); - mat4x4_rotate(model, model, 0, 0, i, -stripYRotation); - mat4x4_translate_in_place(model, puzzle->outerSlicePos * 0.5f, -i * 1.5f, 0); - renderSlice(shader, puzzle->outerSlice, 0, {1 + i, stripFilter}); - } - - if (animationProgress > 2.0f) { - mat4x4_identity(model); - for (int i = -1; i < 2; i += 2) { - for (int j = -1; j < 2; j += 2) { - float offsetX = puzzle->outerSlicePos * 1.5f - 2 * direction * j; - float offsetY = puzzle->outerSlicePos * direction; - float offsetZ = i * (1 + sinf(M_PI * (animationProgress - 2.0f))); - float angle = M_PI_2 * smoothstep(animationProgress - 2.0f); - - Piece piece = puzzle->outerSlice[j + 1][i + 1]; - mat4x4_translate(model, offsetX, offsetY, offsetZ); - mat4x4_rotate(model, model, 0, -j, 0, angle); - render3c(shader, {0, 0, 0}, {piece.a, piece.b, piece.c}); - - piece = puzzle->innerSlice[j + 1][i + 1]; - mat4x4_translate(model, offsetX, -offsetY, offsetZ); - mat4x4_rotate(model, model, 0, -j, 0, angle); - render3c(shader, {0, 0, 0}, {piece.a, piece.b, piece.c}); - } - } - } - } -} - -void PuzzleRenderer::renderGyroZAnimation(Shader *shader, CellLocation cell) { - int direction = puzzle->outerSlicePos * ((int)cell % 2 * 2 - 1); - std::array cells = {&puzzle->leftCell, &puzzle->rightCell}; - int left = (1 - puzzle->outerSlicePos) / 2; - int right = 1 - left; - if (animationProgress < 1.0f) { - float halfOffset = -2 * animationProgress * (animationProgress - 1.0f); - - mat4x4_translate(model, puzzle->outerSlicePos * -(halfOffset + 2.5f), 0, 0); - mat4x4_rotate(model, model, 0, -direction, 0, M_PI_2 * animationProgress); - renderCell(shader, *cells[left], 0); - - mat4x4_translate(model, puzzle->outerSlicePos * (halfOffset + 1.5f), 0, 0); - mat4x4_rotate(model, model, 0, direction, 0, M_PI_2 * animationProgress); - mat4x4_translate_in_place(model, puzzle->outerSlicePos * -1.5f, 0, 0); - renderSlice(shader, puzzle->innerSlice, puzzle->outerSlicePos * -0.5f); - renderMiddleSlice(shader, true, 0.0f); - renderCell(shader, *cells[right], puzzle->outerSlicePos * 1.5f); - renderSlice(shader, puzzle->outerSlice, puzzle->outerSlicePos * 3.5f); - } else { - mat4x4_translate(model, puzzle->outerSlicePos * -2.5f, 0, 0); - mat4x4_rotate(model, model, 0, -direction, 0, M_PI_2); - renderCell(shader, *cells[left], 0); - - mat4x4 base; - mat4x4_translate(base, puzzle->outerSlicePos * 1.5f, 0, 0); - mat4x4_rotate(base, base, 0, direction, 0, M_PI_2); - mat4x4_translate_in_place(base, puzzle->outerSlicePos * -1.5f, 0, 0); - - mat4x4_dup(model, base); - renderSlice(shader, puzzle->innerSlice, puzzle->outerSlicePos * -0.5f, {-1, 1}); - renderMiddleSlice(shader, true, 0.0f); - renderCell(shader, *cells[right], puzzle->outerSlicePos * 1.5f); - renderSlice(shader, puzzle->outerSlice, puzzle->outerSlicePos * 3.5f, {-1, 1}); - - float stripZRotation = std::min(1.0f, std::max(0.0f, (animationProgress - 1.0f) * 2)); - float stripXOffset = std::min(1.0f, std::max(0.0f, (animationProgress - 1.5f) * 2)); - stripZRotation = M_PI_2 * stripZRotation * puzzle->outerSlicePos; - stripXOffset = (stripXOffset + 0.5f) * puzzle->outerSlicePos; - int stripFilter = (animationProgress < 2.0f) ? -1 : 1; - for (int i = -1; i < 2; i += 2) { - mat4x4_dup(model, base); - mat4x4_translate_in_place(model, puzzle->outerSlicePos * -0.5f + stripXOffset, 0, i * 1.5f); - mat4x4_rotate(model, model, 0, i, 0, stripZRotation); - mat4x4_translate_in_place(model, puzzle->outerSlicePos * -0.5f, 0, -i * 1.5f); - renderSlice(shader, puzzle->innerSlice, 0, {stripFilter, 1 + i}); - mat4x4_dup(model, base); - mat4x4_translate_in_place(model, puzzle->outerSlicePos * 3.5f - stripXOffset, 0, i * 1.5f); - mat4x4_rotate(model, model, 0, i, 0, -stripZRotation); - mat4x4_translate_in_place(model, puzzle->outerSlicePos * 0.5f, 0, -i * 1.5f); - renderSlice(shader, puzzle->outerSlice, 0, {stripFilter, 1 + i}); - } - - if (animationProgress > 2.0f) { - mat4x4_identity(model); - for (int i = -1; i < 2; i += 2) { - for (int j = -1; j < 2; j += 2) { - float offsetX = puzzle->outerSlicePos * 1.5f + 2 * direction * j; - float offsetY = i * (1 + sinf(M_PI * (animationProgress - 2.0f))); - float offsetZ = puzzle->outerSlicePos * direction; - float angle = M_PI_2 * smoothstep(animationProgress - 2.0f); - - Piece piece = puzzle->innerSlice[i + 1][j + 1]; - mat4x4_translate(model, offsetX, offsetY, offsetZ); - mat4x4_rotate(model, model, 0, 0, -j, angle); - render3c(shader, {0, 0, 0}, {piece.a, piece.b, piece.c}); - - piece = puzzle->outerSlice[i + 1][j + 1]; - mat4x4_translate(model, offsetX, offsetY, -offsetZ); - mat4x4_rotate(model, model, 0, 0, -j, angle); - render3c(shader, {0, 0, 0}, {piece.a, piece.b, piece.c}); + int rotaxis1 = 3, rotaxis2 = 2; // ZX rotation + model[rotaxis1][rotaxis1] = std::cos(a); + model[rotaxis1][rotaxis2] = std::sin(a); + model[rotaxis2][rotaxis1] = -std::sin(a); + model[rotaxis2][rotaxis2] = std::cos(a); + int rotcell = 2, rotcellopp = 3; + int slices = 4; + + float faceSpacing = 4.5; + shader->use(); + for (int i = 0; i < 8; i++) { + for (int j = 0; j < 3; j++) { + for (int k = 0; k < 3; k++) { + for (int l = 0; l < 3; l++) { + vec3 pos = {(float)j - 1, (float)k - 1, (float)l - 1}; + float posW; + int dimSwap; + if (i == 0) { + dimSwap = 3; + posW = -faceSpacing; + } else if (i == 1) { + dimSwap = 3; + posW = faceSpacing; + } else { + dimSwap = i / 2 - 1; + if (i % 2 == 1) { + pos[dimSwap] = -pos[dimSwap]; + } + posW = pos[dimSwap]; + pos[dimSwap] = faceSpacing * (i % 2 * -2 + 1); + } + + if (i == rotcell || (i != rotcellopp && slices & (1 << (int)(pos[rotcell/2-1] + 1)))) { + shader->setMat4("model", model); + } else { + shader->setMat4("model", base); + } + + shader->setFloat("posw", posW); + shader->setVec3("pos", pos); + shader->setVec3("pieceColors[0]", Pieces::colors[puzzle->cells[i][j][k][l]]); + shader->setInt("swap", dimSwap); + shader->setInt("border", 0); + mesh->renderFaces(shader); + shader->setInt("border", 1); + mesh->renderEdges(); } } } } } -void PuzzleRenderer::renderOuterGyroAnimation(Shader *shader, int location) { - float mainOffsetX, mainOffsetY, slicePosX, slicePosY; - if (animationProgress < 0.5f) { - slicePosX = puzzle->outerSlicePos * 3.5f; - slicePosY = -16 * animationProgress * (animationProgress - 1.0f); - mainOffsetX = puzzle->outerSlicePos * -0.5f; - mainOffsetY = 2 * animationProgress * (animationProgress - 1.0f); - } else if (animationProgress < 1.5f) { - slicePosX = (3.5 - smoothstep(animationProgress - 0.5f) * 7) * puzzle->outerSlicePos; - slicePosY = 4.0f; - mainOffsetX = (-0.5 + smoothstep(animationProgress - 0.5f)) * puzzle->outerSlicePos; - mainOffsetY = -0.5f; - } else { - slicePosX = puzzle->outerSlicePos * -3.5f; - slicePosY = -16 * (animationProgress - 1.0f) * (animationProgress - 2.0f); - mainOffsetX = puzzle->outerSlicePos * 0.5f; - mainOffsetY = 2 * (animationProgress - 1.0f) * (animationProgress - 2.0f); - } - mat4x4_translate(model, slicePosX, slicePosY, 0); - renderSlice(shader, puzzle->outerSlice, 0.0f); - // Undo X offset made by renderMiddleSlice - mat4x4_translate_in_place(model, -2 * puzzle->middleSlicePos, 0, 0); - if (puzzle->outerSlicePos * 2 == puzzle->middleSlicePos) renderMiddleSlice(shader, false, 0.0f); - - mat4x4_translate(model, mainOffsetX, mainOffsetY, 0); - renderCell(shader, puzzle->leftCell, -2.0f); - renderCell(shader, puzzle->rightCell, 2.0f); - renderSlice(shader, puzzle->innerSlice, 0.0f); - if (puzzle->outerSlicePos * 2 != puzzle->middleSlicePos) renderMiddleSlice(shader, false, 0.0f); -} - -void PuzzleRenderer::renderPGyroAnimation(Shader *shader, int direction) { - if (direction == 0) { - renderPGyroDirAnimation(shader); - } else { - renderPGyroPosAnimation(shader, direction); - } -} - -void PuzzleRenderer::renderPGyroDirAnimation(Shader *shader) { - float offset = puzzle->outerSlicePos * -0.5f; - mat4x4_identity(model); - renderSlice(shader, puzzle->outerSlice, 3.5f * puzzle->outerSlicePos); - renderCell(shader, puzzle->leftCell, -2.0f + offset); - renderCell(shader, puzzle->rightCell, 2.0f + offset); - renderSlice(shader, puzzle->innerSlice, offset); - - offset += 2 * puzzle->middleSlicePos; - render1c(shader, {offset, 2, 0}, puzzle->topCell.a); - render1c(shader, {offset, -2, 0}, puzzle->bottomCell.a); - render1c(shader, {offset, 0, 2}, puzzle->frontCell[1].a); - render1c(shader, {offset, 0, -2}, puzzle->backCell[1].a); - - float parity = (puzzle->middleSliceDir == UP) ? 1.0f : -1.0f; - std::array targets = {DOWN, DOWN, UP, UP, FRONT, BACK, FRONT, BACK}; - if (puzzle->middleSliceDir == UP) { - std::rotate(targets.begin(), targets.begin() + 4, targets.end()); - } - if (animationProgress < 0.5f) { - std::array, 3> cells; - cells[0] = puzzle->backCell; - cells[2] = puzzle->frontCell; - - for (int i = -1; i < 2; i += 2) { - for (int j = -1; j < 2; j += 2) { - CellLocation target = targets[i + 1 + (j + 1) / 2]; - mat4x4_translate(model, 0, 1.5 * i, 1.5 * j); - mat4x4_rotate(model, model, i * j, 0, 0, parity * M_PI * animationProgress); - mat4x4_translate_in_place(model, 0, i * parity * 0.5, j * -parity * 0.5); - render2c(shader, {offset, 0, 0}, {cells[j + 1][i + 1].a, cells[j + 1][i + 1].b}, target); - } - } - } else { - float glide = 1 - 4 * animationProgress * (animationProgress - 1.0f); - float glideY = (puzzle->middleSliceDir == UP) ? glide : 2; - float glideZ = (puzzle->middleSliceDir != UP) ? glide : 2; - render2c(shader, {offset, -glideY, -glideZ}, {puzzle->backCell[0].a, puzzle->backCell[0].b}, targets[4]); - render2c(shader, {offset, -glideY, glideZ}, {puzzle->frontCell[0].a, puzzle->frontCell[0].b}, targets[5]); - render2c(shader, {offset, glideY, -glideZ}, {puzzle->backCell[2].a, puzzle->backCell[2].b}, targets[6]); - render2c(shader, {offset, glideY, glideZ}, {puzzle->frontCell[2].a, puzzle->frontCell[2].b}, targets[7]); - } -} - -void PuzzleRenderer::renderPGyroPosAnimation(Shader *shader, int direction) { - float offset = puzzle->outerSlicePos * -0.5f; - mat4x4_identity(model); - renderSlice(shader, puzzle->outerSlice, 3.5f * puzzle->outerSlicePos); - renderCell(shader, puzzle->leftCell, -2.0f + offset); - renderCell(shader, puzzle->rightCell, 2.0f + offset); - renderSlice(shader, puzzle->innerSlice, offset); - - offset += 2 * puzzle->middleSlicePos; - float arcX = direction + -direction * cos(M_PI * animationProgress); - float arcY = sin(M_PI * animationProgress); - - mat4x4_translate(model, offset + arcX, 2 + arcY, 0); - mat4x4_rotate(model, model, 0, 0, -1, direction * M_PI * animationProgress); - render1c(shader, {0, 0, 0}, puzzle->topCell.a); - if (puzzle->middleSliceDir == UP) { - render2c(shader, {0, 0, 1}, {puzzle->frontCell[2].a, puzzle->frontCell[2].b}, BACK); - render2c(shader, {0, 0, -1}, {puzzle->backCell[2].a, puzzle->backCell[2].b}, FRONT); - } - - mat4x4_translate(model, offset + arcX, -2 - arcY, 0); - mat4x4_rotate(model, model, 0, 0, -1, -direction * M_PI * animationProgress); - render1c(shader, {0, 0, 0}, puzzle->bottomCell.a); - if (puzzle->middleSliceDir == UP) { - render2c(shader, {0, 0, 1}, {puzzle->frontCell[0].a, puzzle->frontCell[0].b}, BACK); - render2c(shader, {0, 0, -1}, {puzzle->backCell[0].a, puzzle->backCell[0].b}, FRONT); - } - - mat4x4_translate(model, offset + arcX, 0, 2 + arcY); - mat4x4_rotate(model, model, 0, 1, 0, direction * M_PI * animationProgress); - render1c(shader, {0, 0, 0}, puzzle->frontCell[1].a); - if (puzzle->middleSliceDir == FRONT) { - render2c(shader, {0, 1, 0}, {puzzle->frontCell[2].a, puzzle->frontCell[2].b}, UP); - render2c(shader, {0, -1, 0}, {puzzle->frontCell[0].a, puzzle->frontCell[0].b}, DOWN); - } - - mat4x4_translate(model, offset + arcX, 0, -2 - arcY); - mat4x4_rotate(model, model, 0, 1, 0, -direction * M_PI * animationProgress); - render1c(shader, {0, 0, 0}, puzzle->backCell[1].a); - if (puzzle->middleSliceDir == FRONT) { - render2c(shader, {0, 1, 0}, {puzzle->backCell[2].a, puzzle->backCell[2].b}, UP); - render2c(shader, {0, -1, 0}, {puzzle->backCell[0].a, puzzle->backCell[0].b}, DOWN); - } -} - bool PuzzleRenderer::updateAnimations(GLFWwindow* window, double dt, MoveEntry *entry) { if (pendingMoves.size() == 0) { animating = false; @@ -1149,107 +247,3 @@ void PuzzleRenderer::scheduleMove(MoveEntry entry) { pendingMoves.push(entry); animating = true; } - -void PuzzleRenderer::renderCellOutline(Shader *shader, CellLocation cell) { - if (animating) return; - shader->use(); - shader->setInt("border", 0); - shader->setInt("outline", 1); - shader->setFloat("time", 2 * M_PI * glfwGetTime()); - glLineWidth(4); - - float offset = puzzle->outerSlicePos * -0.5f; - float scale = 3.0f + 2 * getSpacing(); - float posScale = 1.0f + getSpacing(); - float flip; - switch (cell) { - case LEFT: - case IN: - case RIGHT: - if (cell == LEFT) offset -= 2.0f; - if (cell == RIGHT) offset += 2.0f; - - mat4x4_translate(model, offset, 0, 0); - mat4x4_scale_pos(model, posScale); - mat4x4_scale_aniso(model, model, scale, scale, scale); - shader->setMat4("model", model); - meshes[0]->renderEdges(); - break; - case OUT: - offset = puzzle->outerSlicePos * -3.5f; - mat4x4_translate(model, offset, 0, 0); - mat4x4_scale_pos(model, posScale); - mat4x4_scale_aniso(model, model, 1.0f, scale, scale); - shader->setMat4("model", model); - meshes[0]->renderEdges(); - - offset = puzzle->outerSlicePos * 3.0f; - mat4x4_translate(model, offset, 0, 0); - mat4x4_scale_pos(model, posScale); - mat4x4_scale_aniso(model, model, 2.0f, scale, scale); - shader->setMat4("model", model); - meshes[0]->renderEdges(); - break; - case UP: - case DOWN: - flip = (cell == UP) ? 1.0f : -1.0f; - mat4x4_translate(model, 0, flip, 0); - mat4x4_scale_pos(model, posScale); - mat4x4_scale_aniso(model, model, 8.0f + 7 * getSpacing(), 1.0f, scale); - shader->setMat4("model", model); - meshes[0]->renderEdges(); - - offset += 2 * puzzle->middleSlicePos; - if (puzzle->middleSliceDir == UP) { - mat4x4_translate(model, offset, 2.0f * flip, 0); - mat4x4_scale_pos(model, posScale); - mat4x4_scale_aniso(model, model, 1.0f, 1.0f, scale); - shader->setMat4("model", model); - meshes[0]->renderEdges(); - } else { - mat4x4_translate(model, offset, 2.0f * flip, 0); - mat4x4_scale_pos(model, posScale); - shader->setMat4("model", model); - meshes[0]->renderEdges(); - - for (int i = -1; i < 2; i += 2) { - mat4x4_translate(model, offset, flip, i * 2); - mat4x4_scale_pos(model, posScale); - shader->setMat4("model", model); - meshes[0]->renderEdges(); - } - } - break; - case FRONT: - case BACK: - flip = (cell == FRONT) ? 1.0f : -1.0f; - mat4x4_translate(model, 0, 0, flip); - mat4x4_scale_pos(model, posScale); - mat4x4_scale_aniso(model, model, 8.0f + 7 * getSpacing(), scale, 1.0f); - shader->setMat4("model", model); - meshes[0]->renderEdges(); - - offset += 2 * puzzle->middleSlicePos; - if (puzzle->middleSliceDir == FRONT) { - mat4x4_translate(model, offset, 0, 2.0f * flip); - mat4x4_scale_pos(model, posScale); - mat4x4_scale_aniso(model, model, 1.0f, scale, 1.0f); - shader->setMat4("model", model); - meshes[0]->renderEdges(); - } else { - mat4x4_translate(model, offset, 0, 2.0f * flip); - mat4x4_scale_pos(model, posScale); - shader->setMat4("model", model); - meshes[0]->renderEdges(); - - for (int i = -1; i < 2; i += 2) { - mat4x4_translate(model, offset, i * 2, flip); - mat4x4_scale_pos(model, posScale); - shader->setMat4("model", model); - meshes[0]->renderEdges(); - } - } - break; - } - shader->setInt("outline", 0); -} diff --git a/render.h b/render.h index 350b649..f3df495 100644 --- a/render.h +++ b/render.h @@ -57,7 +57,7 @@ class PieceMesh { }; typedef enum { - GYRO, TURN, ROTATE, GYRO_OUTER, GYRO_MIDDLE + GYRO, TURN } MoveType; struct MoveEntry { @@ -65,60 +65,27 @@ struct MoveEntry { float animLength; CellLocation cell; // for GYRO, TURN RotateDirection direction; // for TURN - int location; // for slice gyros (-1/0/1 for middle gyros) + int slices; // for TURN, bit field }; class PuzzleRenderer { public: friend class PuzzleController; PuzzleRenderer(Puzzle *puzzle); - ~PuzzleRenderer(); - float getSpacing(); - void setSpacing(float spacing); - void render1c(Shader *shader, const std::array pos, Color color); - void render2c(Shader *shader, const std::array pos, const std::array colors, CellLocation dir); - void render3c(Shader *shader, const std::array pos, const std::array colors); - void render4c(Shader *shader, const std::array pos, const std::array colors, int orientation); void renderPuzzle(Shader *shader); - void renderCell(Shader *shader, const std::array, 3>, 3>& cell, float offset, std::array sliceFilter = {-1, -1, -1}); - void renderSlice(Shader *shader, const std::array, 3>& slice, float offset, std::array stripFilter = {-1, -1}); - void renderMiddleSlice(Shader *shader, bool addOffsetX, float offsetYZ, CellLocation filter = (CellLocation)-1); - - void renderCellOutline(Shader *shader, CellLocation cell); - void setMousePressed(bool pressed); - bool updateMouse(GLFWwindow* window, double dt); bool updateAnimations(GLFWwindow *window, double dt, MoveEntry* entry); void scheduleMove(MoveEntry entry); private: Puzzle *puzzle; - PieceMesh *meshes[4]; - float spacing; - - bool mousePressed; - float sensitivity; - float lastY; mat4x4 model; + PieceMesh *mesh; std::queue pendingMoves; bool animating; float animationSpeed; float animationProgress; void renderNoAnimation(Shader *shader); - void renderLeftAnimation(Shader *shader, RotateDirection direction); - void renderRightAnimation(Shader *shader, RotateDirection direction); - void renderInnerAnimation(Shader *shader, RotateDirection direction); - void renderOuterAnimation(Shader *shader, RotateDirection direction); - void renderFrontBackAnimation(Shader *shader, CellLocation cell, RotateDirection direction); - void renderUpDownAnimation(Shader *shader, CellLocation cell, RotateDirection direction); - void renderRotateAnimation(Shader *shader, RotateDirection direction); - void renderGyroXAnimation(Shader *shader, CellLocation cell); - void renderGyroYAnimation(Shader *shader, CellLocation cell); - void renderGyroZAnimation(Shader *shader, CellLocation cell); - void renderOuterGyroAnimation(Shader *shader, int location); - void renderPGyroAnimation(Shader *shader, int direction); - void renderPGyroPosAnimation(Shader *shader, int direction); - void renderPGyroDirAnimation(Shader *shader); }; #endif // render.h diff --git a/shaders.cpp b/shaders.cpp index 0825fe8..9b912a4 100644 --- a/shaders.cpp +++ b/shaders.cpp @@ -31,14 +31,27 @@ layout (location = 0) in vec3 aPos; layout (location = 1) in float aColIdx; out float colorIndex; out vec3 meshPos; +out float fragW; +uniform vec3 pos; +uniform float posw; +uniform int swap; uniform mat4 model; uniform mat4 view; uniform mat4 projection; uniform int outline; void main() { - gl_Position = projection * view * model * vec4(aPos, 1.0); + mat4 dimSwap = mat4(1.0); + dimSwap[swap][swap] = 0; + dimSwap[3][3] = 0; + dimSwap[3][swap] = 1; + dimSwap[swap][3] = 1; + float resigned = abs(sign(swap - 3)) * sign(pos[swap]) + (1 - abs(sign(swap - 3))) * -sign(posw); + vec4 world = model * (dimSwap * vec4(resigned * aPos * 0.7, 0.0) + vec4(pos, posw)); + fragW = world.w; + world = vec4(world.xyz, 3 - world.w/2); + gl_Position = projection * view * world; if (outline == 1) { gl_Position.z -= 1e-4; } @@ -58,6 +71,7 @@ precision mediump int; #define MAX_TRIANGLES 36 in float colorIndex; in vec3 meshPos; +in float fragW; out vec4 FragColor; uniform int border; @@ -70,12 +84,9 @@ uniform vec3[MAX_TRIANGLES] normals; vec3 lightDir = vec3(-0.3f, -0.7f, -0.5f); vec3 lightColor = vec3(1.0f, 1.0f, 1.0f); -)" -#ifndef __EMSCRIPTEN__ -"#define LIGHTING" -#endif -R"( + void main() { + if (fragW > 3) discard; if (border == 1) { FragColor = vec4(vec3(0.0f), 1.0f); } else if (outline == 1) { diff --git a/window.cpp b/window.cpp index 98a3e65..ba4d5f3 100644 --- a/window.cpp +++ b/window.cpp @@ -146,14 +146,15 @@ EM_BOOL onCanvasSizeChanged(int event_type, const EmscriptenUiEvent* ui_event, v void Window::run() { lastTime = glfwGetTime(); - camera->setPitch(M_PI / 180 * -20); - camera->setYaw(M_PI / 180 * -20); + camera->setPitch(M_PI / 180 * -35); + camera->setYaw(M_PI / 180 * 45); glDepthMask(GL_TRUE); glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); glDepthMask(GL_TRUE); glEnable(GL_POLYGON_OFFSET_FILL); + glLineWidth(1); glPolygonOffset(1.0, 1.0); setUpdateBuffer(); @@ -181,7 +182,6 @@ void Window::updateFunc() { double tick = glfwGetTime(); double dt = tick - lastTime; lastTime = tick; - if (renderer->updateMouse(window, dt)) setUpdateBuffer(); if (camera->updateMouse(window, dt)) setUpdateBuffer(); if (controller->updatePuzzle(window, dt)) setUpdateBuffer(); @@ -203,9 +203,6 @@ void Window::draw() { modelShader->setMat4("projection", *camera->getProjection()); renderer->renderPuzzle(modelShader); - if (controller->checkOutline(window, modelShader, camera->inputFlipped())) { - setUpdateBuffer(); - } gui->renderGui(); glfwSwapBuffers(window); glfwPollEvents(); @@ -258,13 +255,9 @@ void Window::mouseButtonCallback(GLFWwindow* window, int button, int action) { } else { if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS) { camera->setMousePressed(true); - } else if (button == GLFW_MOUSE_BUTTON_MIDDLE && action == GLFW_PRESS) { - renderer->setMousePressed(true); } } if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_RELEASE) { camera->setMousePressed(false); - } else if (button == GLFW_MOUSE_BUTTON_MIDDLE && action == GLFW_RELEASE) { - renderer->setMousePressed(false); } }