diff --git a/.gitignore b/.gitignore index cfd2159..d38b168 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .cache/ build/ compile_commands.json +build-vs/ \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index cd91ce8..d7dceb4 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,70 @@ { "files.associations": { - "xiosbase": "cpp" + "xiosbase": "cpp", + "iostream": "cpp", + "algorithm": "cpp", + "atomic": "cpp", + "bit": "cpp", + "cctype": "cpp", + "charconv": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "compare": "cpp", + "concepts": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "exception": "cpp", + "format": "cpp", + "functional": "cpp", + "initializer_list": "cpp", + "ios": "cpp", + "iosfwd": "cpp", + "istream": "cpp", + "iterator": "cpp", + "limits": "cpp", + "list": "cpp", + "locale": "cpp", + "map": "cpp", + "memory": "cpp", + "new": "cpp", + "optional": "cpp", + "ostream": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "string": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "typeinfo": "cpp", + "unordered_map": "cpp", + "utility": "cpp", + "vector": "cpp", + "xfacet": "cpp", + "xhash": "cpp", + "xlocale": "cpp", + "xlocbuf": "cpp", + "xlocinfo": "cpp", + "xlocmes": "cpp", + "xlocmon": "cpp", + "xlocnum": "cpp", + "xloctime": "cpp", + "xmemory": "cpp", + "xstring": "cpp", + "xtr1common": "cpp", + "xtree": "cpp", + "xutility": "cpp" + }, + "editor.formatOnSave": true, + "C_Cpp.clang_format_style": "{BasedOnStyle: LLVM, BraceWrapping: {AfterControlStatement: false, AfterFunction: false, AfterEnum: true, AfterStruct: true}, AllowShortEnumsOnASingleLine: false}", + "editor.tabSize": 4, + "editor.insertSpaces": true, + "[cpp]": { + "editor.tabSize": 4, + "editor.insertSpaces": true } } \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index de21af4..66ec228 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,7 +21,7 @@ FetchContent_Declare( ) FetchContent_MakeAvailable(imgui) -add_library(ImGui SHARED +add_library(ImGui STATIC ${imgui_SOURCE_DIR}/imgui.cpp ${imgui_SOURCE_DIR}/imgui_demo.cpp ${imgui_SOURCE_DIR}/imgui_draw.cpp diff --git a/RubixSimulation.hpp b/RubixSimulation.hpp new file mode 100644 index 0000000..42ada69 --- /dev/null +++ b/RubixSimulation.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include + +class RubixSimulation { +public: + virtual bool Init() = 0; + virtual void Run() = 0; +}; + +class RubixSimulationRunner { +public: + void SetSimulation(RubixSimulation *simulation) { sim = simulation; } + void StartSimulation() { + if (sim == nullptr) { + std::cout << "No simulation has been set\n"; + return; + } + if (!sim->Init()) { + std::cout << "There was an error creating simulation\n"; + } + sim->Run(); + } + +private: + RubixSimulation *sim = nullptr; +}; \ No newline at end of file diff --git a/Sims/OOPCube.hpp b/Sims/OOPCube.hpp new file mode 100644 index 0000000..b93c32c --- /dev/null +++ b/Sims/OOPCube.hpp @@ -0,0 +1,458 @@ +#pragma once + +#include "../RubixSimulation.hpp" +#include +#include +#include + +namespace OOPCube { + +struct VecTriangle { + Vector3 pointOne; + Vector3 pointTwo; + Vector3 pointThree; +}; + +struct Plane3D { + VecTriangle one; + VecTriangle two; + Color color; +}; + +struct CubeFace { + Plane3D tiles[9]; // 3x3 tiles +}; + +struct CubeRotation { + bool rotating; + float angle; + Vector3 axis; + CubeFace *face; +}; + +struct RubixCubeFaces { + CubeFace front; + CubeFace right; + CubeFace back; + CubeFace left; + CubeFace top; + CubeFace bottom; +}; + +class RubixCube { +public: + RubixCube() { + float cubeSize = 3.0f; + float faceOffset = cubeSize / 2.0f; + + faces.front = CreateCubeFace({0.0f, 0.0f, -faceOffset}, {0.0f, 0.0f, 1.0f}, + cubeSize, GREEN); + faces.back = CreateCubeFace({0.0f, 0.0f, faceOffset}, {0.0f, 0.0f, -1.0f}, + cubeSize, BLUE); + faces.left = CreateCubeFace({-faceOffset, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, + cubeSize, ORANGE); + faces.right = CreateCubeFace({faceOffset, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, + cubeSize, RED); + faces.top = CreateCubeFace({0.0f, faceOffset, 0.0f}, {0.0f, -1.0f, 0.0f}, + cubeSize, YELLOW); + faces.bottom = CreateCubeFace({0.0f, -faceOffset, 0.0f}, {0.0f, 1.0f, 0.0f}, + cubeSize, WHITE); + } + + void Draw(bool highlightFace = false, CubeFace *highlightedFace = nullptr) { + if (highlightFace && highlightedFace != nullptr) { + HighlightFace(highlightedFace); + } + DrawFace(&faces.front); + DrawFace(&faces.back); + DrawFace(&faces.left); + DrawFace(&faces.right); + DrawFace(&faces.top); + DrawFace(&faces.bottom); + } + + void RotateFace(CubeFace *face, float angle, Vector3 axis) { + CubeFace *neighbors[4]; // Holds adjacent faces + GetFaceNeighbors(face, neighbors); // Get adjacent faces + RotateLayer(face, angle, axis, neighbors); // Rotate both face and neighbors + UpdateCubeState(face, neighbors, + angle > 0); // Update the state after rotation + } + + CubeFace *GetFaceUnderMouse(Camera camera) { + Ray mouseRay = GetMouseRay(GetMousePosition(), camera); + CubeFace *face = nullptr; + + if (CheckRayIntersectionWithFace(mouseRay, faces.front)) { + face = &faces.front; + } else if (CheckRayIntersectionWithFace(mouseRay, faces.back)) { + face = &faces.back; + } else if (CheckRayIntersectionWithFace(mouseRay, faces.left)) { + face = &faces.left; + } else if (CheckRayIntersectionWithFace(mouseRay, faces.right)) { + face = &faces.right; + } else if (CheckRayIntersectionWithFace(mouseRay, faces.top)) { + face = &faces.top; + } else if (CheckRayIntersectionWithFace(mouseRay, faces.bottom)) { + face = &faces.bottom; + } + + return face; + } + +private: + RubixCubeFaces faces; + + void GetFaceNeighbors(CubeFace *face, CubeFace **neighbors) { + // Map the neighbors of each face (order: top, right, bottom, left) + if (face == &faces.front) { + neighbors[0] = &faces.top; + neighbors[1] = &faces.right; + neighbors[2] = &faces.bottom; + neighbors[3] = &faces.left; + } else if (face == &faces.back) { + neighbors[0] = &faces.top; + neighbors[1] = &faces.left; + neighbors[2] = &faces.bottom; + neighbors[3] = &faces.right; + } else if (face == &faces.left) { + neighbors[0] = &faces.top; + neighbors[1] = &faces.front; + neighbors[2] = &faces.bottom; + neighbors[3] = &faces.back; + } else if (face == &faces.right) { + neighbors[0] = &faces.top; + neighbors[1] = &faces.back; + neighbors[2] = &faces.bottom; + neighbors[3] = &faces.front; + } else if (face == &faces.top) { + neighbors[0] = &faces.back; + neighbors[1] = &faces.right; + neighbors[2] = &faces.front; + neighbors[3] = &faces.left; + } else if (face == &faces.bottom) { + neighbors[0] = &faces.front; + neighbors[1] = &faces.right; + neighbors[2] = &faces.back; + neighbors[3] = &faces.left; + } + } + + void RotateLayer(CubeFace *face, float angle, Vector3 axis, + CubeFace **neighbors) { + // Rotate the face itself + RotateCubeFace(face, MatrixRotate(axis, angle)); + // Apply rotation to the neighboring rows/columns + RotateNeighbors(face, angle, neighbors); + } + + void RotateNeighbors(CubeFace *rotatingFace, float angle, + CubeFace **neighbors) { + // Clockwise or counterclockwise based on angle + bool clockwise = angle > 0.0f; + + // Determine the layer based on the rotating face. + // If front/back, rotate the middle horizontal row; otherwise, rotate the + // vertical columns. + if (rotatingFace == &faces.front || rotatingFace == &faces.back) { + // Rotating the front or back face (affects top, right, bottom, and left + // face) + UpdateCubeState(rotatingFace, neighbors, clockwise); + } else if (rotatingFace == &faces.left || rotatingFace == &faces.right) { + // Rotating left or right face (affects top, front, bottom, and back face) + UpdateCubeState(rotatingFace, neighbors, clockwise); + } else if (rotatingFace == &faces.top || rotatingFace == &faces.bottom) { + // Rotating top or bottom face (affects front, right, back, and left face) + UpdateCubeState(rotatingFace, neighbors, clockwise); + } + } + + void UpdateCubeState(CubeFace *face, CubeFace **neighbors, bool clockwise) { + // Swapping tiles based on clockwise or counterclockwise rotation + + if (face == &faces.front || face == &faces.back) { + // Swap rows for front or back face rotation + if (clockwise) { + // Rotate clockwise: top->right, right->bottom, bottom->left, left->top + SwapRows(neighbors[0], neighbors[1], neighbors[2], neighbors[3], 2, + true); + } else { + // Rotate counter-clockwise: top->left, left->bottom, bottom->right, + // right->top + SwapRows(neighbors[0], neighbors[3], neighbors[2], neighbors[1], 2, + false); + } + } else if (face == &faces.left || face == &faces.right) { + // Swap columns for left or right face rotation + if (clockwise) { + // Rotate clockwise: top->front, front->bottom, bottom->back, back->top + SwapColumns(neighbors[0], neighbors[1], neighbors[2], neighbors[3], 0, + true); + } else { + // Rotate counter-clockwise: top->back, back->bottom, bottom->front, + // front->top + SwapColumns(neighbors[0], neighbors[3], neighbors[2], neighbors[1], 0, + false); + } + } else if (face == &faces.top || face == &faces.bottom) { + // Swap rows for top or bottom face rotation + if (clockwise) { + // Rotate clockwise: front->right, right->back, back->left, left->front + SwapRows(neighbors[0], neighbors[1], neighbors[2], neighbors[3], 0, + true); + } else { + // Rotate counter-clockwise: front->left, left->back, back->right, + // right->front + SwapRows(neighbors[0], neighbors[3], neighbors[2], neighbors[1], 0, + false); + } + } + } + + // Helper function to swap rows (used when rotating top/bottom or front/back) + void SwapRows(CubeFace *top, CubeFace *right, CubeFace *bottom, + CubeFace *left, int rowIndex, bool clockwise) { + Plane3D tempRow[3]; + + // Store top row temporarily + for (int i = 0; i < 3; i++) { + tempRow[i] = top->tiles[rowIndex * 3 + i]; + } + + // Swap rows based on direction + if (clockwise) { + // Top -> Right -> Bottom -> Left -> Top + for (int i = 0; i < 3; i++) { + top->tiles[rowIndex * 3 + i] = left->tiles[rowIndex * 3 + i]; + left->tiles[rowIndex * 3 + i] = bottom->tiles[rowIndex * 3 + i]; + bottom->tiles[rowIndex * 3 + i] = right->tiles[rowIndex * 3 + i]; + right->tiles[rowIndex * 3 + i] = tempRow[i]; + } + } else { + // Top -> Left -> Bottom -> Right -> Top + for (int i = 0; i < 3; i++) { + top->tiles[rowIndex * 3 + i] = right->tiles[rowIndex * 3 + i]; + right->tiles[rowIndex * 3 + i] = bottom->tiles[rowIndex * 3 + i]; + bottom->tiles[rowIndex * 3 + i] = left->tiles[rowIndex * 3 + i]; + left->tiles[rowIndex * 3 + i] = tempRow[i]; + } + } + } + + void SwapColumns(CubeFace *top, CubeFace *front, CubeFace *bottom, + CubeFace *back, int colIndex, bool clockwise) { + Plane3D tempCol[3]; + + // Store top column temporarily + for (int i = 0; i < 3; i++) { + tempCol[i] = top->tiles[i * 3 + colIndex]; + } + + // Swap columns based on direction + if (clockwise) { + // Top -> Front -> Bottom -> Back -> Top + for (int i = 0; i < 3; i++) { + top->tiles[i * 3 + colIndex] = back->tiles[i * 3 + colIndex]; + back->tiles[i * 3 + colIndex] = bottom->tiles[i * 3 + colIndex]; + bottom->tiles[i * 3 + colIndex] = front->tiles[i * 3 + colIndex]; + front->tiles[i * 3 + colIndex] = tempCol[i]; + } + } else { + // Top -> Back -> Bottom -> Front -> Top + for (int i = 0; i < 3; i++) { + top->tiles[i * 3 + colIndex] = front->tiles[i * 3 + colIndex]; + front->tiles[i * 3 + colIndex] = bottom->tiles[i * 3 + colIndex]; + bottom->tiles[i * 3 + colIndex] = back->tiles[i * 3 + colIndex]; + back->tiles[i * 3 + colIndex] = tempCol[i]; + } + } + } + + void RotateCubeFace(CubeFace *face, Matrix rotationMatrix) { + for (int i = 0; i < 9; i++) { + RotatePlane3D(&face->tiles[i], rotationMatrix); + } + } + + void RotatePlane3D(Plane3D *plane, Matrix rotationMatrix) { + plane->one.pointOne = Vector3Transform(plane->one.pointOne, rotationMatrix); + plane->one.pointTwo = Vector3Transform(plane->one.pointTwo, rotationMatrix); + plane->one.pointThree = + Vector3Transform(plane->one.pointThree, rotationMatrix); + plane->two.pointOne = Vector3Transform(plane->two.pointOne, rotationMatrix); + plane->two.pointTwo = Vector3Transform(plane->two.pointTwo, rotationMatrix); + plane->two.pointThree = + Vector3Transform(plane->two.pointThree, rotationMatrix); + } + + void HighlightFace(CubeFace *face) { DrawFace(face, true); } + + void DrawFace(CubeFace *face, bool highlight = false) { + Color faceColor = highlight ? LIGHTGRAY : face->tiles[0].color; + + for (int i = 0; i < 9; i++) { + DrawPlane3D(&face->tiles[i]); + } + } + + bool CheckRayIntersectionWithFace(Ray ray, CubeFace face) { + for (int i = 0; i < 9; i++) { + if (CheckRayCollision(ray, face.tiles[i])) { + return true; + } + } + return false; + } + + bool CheckRayCollision(Ray ray, Plane3D plane) { + RayCollision collisionOne = GetRayCollisionTriangle( + ray, plane.one.pointOne, plane.one.pointTwo, plane.one.pointThree); + RayCollision collisionTwo = GetRayCollisionTriangle( + ray, plane.two.pointOne, plane.two.pointTwo, plane.two.pointThree); + + return collisionOne.hit || collisionTwo.hit; + } + + Plane3D CreatePlane3D(float width, float height, Vector3 position, + Color color, Vector3 normal, float scale) { + Plane3D plane3D; + plane3D.color = color; + + Vector3 right, up; + + if (Vector3Equals(normal, {0.0f, 1.0f, 0.0f}) || + Vector3Equals(normal, {0.0f, -1.0f, 0.0f})) { + right = {1.0f, 0.0f, 0.0f}; + up = {0.0f, 0.0f, (normal.y > 0.0f) ? -1.0f : 1.0f}; + } else { + right = {normal.z, 0.0f, -normal.x}; + up = {0.0f, 1.0f, 0.0f}; + } + + float scaledWidth = width * scale; + float scaledHeight = height * scale; + + plane3D.one.pointOne = + Vector3Add(position, Vector3Add(Vector3Scale(right, -scaledWidth / 2), + Vector3Scale(up, -scaledHeight / 2))); + plane3D.one.pointTwo = + Vector3Add(position, Vector3Add(Vector3Scale(right, scaledWidth / 2), + Vector3Scale(up, -scaledHeight / 2))); + plane3D.one.pointThree = + Vector3Add(position, Vector3Add(Vector3Scale(right, -scaledWidth / 2), + Vector3Scale(up, scaledHeight / 2))); + + plane3D.two.pointOne = + Vector3Add(position, Vector3Add(Vector3Scale(right, scaledWidth / 2), + Vector3Scale(up, -scaledHeight / 2))); + plane3D.two.pointTwo = + Vector3Add(position, Vector3Add(Vector3Scale(right, scaledWidth / 2), + Vector3Scale(up, scaledHeight / 2))); + plane3D.two.pointThree = + Vector3Add(position, Vector3Add(Vector3Scale(right, -scaledWidth / 2), + Vector3Scale(up, scaledHeight / 2))); + + return plane3D; + } + + CubeFace CreateCubeFace(Vector3 center, Vector3 normal, float cubeSize, + Color faceColor) { + CubeFace face; + + float tileSize = cubeSize / 3.0f; + float halfSize = cubeSize / 2.0f; + + Vector3 right = Vector3CrossProduct(normal, {0.0f, 1.0f, 0.0f}); + if (Vector3Length(right) == 0) { + right = {1.0f, 0.0f, 0.0f}; + } + + Vector3 up = Vector3CrossProduct(right, normal); + Vector3 tileCenters[3][3]; + + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + tileCenters[i][j] = Vector3Add( + center, Vector3Add(Vector3Scale(right, (i - 1) * tileSize), + Vector3Scale(up, (j - 1) * tileSize))); + } + } + + for (int i = 0; i < 9; i++) { + face.tiles[i] = + CreatePlane3D(tileSize, tileSize, tileCenters[i / 3][i % 3], + faceColor, normal, 1.0f); + } + + return face; + } + + void DrawPlane3D(Plane3D *plane) { + DrawTriangle3D(plane->one.pointOne, plane->one.pointTwo, + plane->one.pointThree, plane->color); + DrawTriangle3D(plane->two.pointOne, plane->two.pointTwo, + plane->two.pointThree, plane->color); + } +}; + +class OOPCube : public RubixSimulation { +public: + bool Init() override { + camera = {0}; + camera.position = {4.0f, 4.0f, 4.0f}; + camera.target = {0.0f, 0.0f, 0.0f}; + camera.up = {0.0f, 1.0f, 0.0f}; + camera.fovy = 45.0f; + camera.projection = CAMERA_PERSPECTIVE; + + return true; + } + + void Run() override { + SetConfigFlags(FLAG_VSYNC_HINT); + InitWindow(1920, 1080, "OOP Cube Simulation"); + + DisableCursor(); + rlDisableBackfaceCulling(); + bool isControllingCamera = false; + + while (!WindowShouldClose()) { + if (IsKeyPressed(KEY_SPACE)) { + isControllingCamera = !isControllingCamera; + } + + if (isControllingCamera) { + HideCursor(); + UpdateCamera(&camera, CAMERA_FREE); + SetMousePosition(GetScreenWidth() / 2, GetScreenHeight() / 2); + } + BeginDrawing(); + ClearBackground(GRAY); + ShowCursor(); + + BeginMode3D(camera); + DrawGrid(10, 1.0f); + + CubeFace *faceUnderMouse = cube.GetFaceUnderMouse(camera); + if (faceUnderMouse != nullptr) { + if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) { + cube.RotateFace(faceUnderMouse, PI / 2.0f, {0.0f, 1.0f, 0.0f}); + } else if (IsMouseButtonPressed(MOUSE_RIGHT_BUTTON)) { + cube.RotateFace(faceUnderMouse, -PI / 2.0f, {0.0f, 1.0f, 0.0f}); + } + cube.Draw(true, faceUnderMouse); + } else { + cube.Draw(); + } + + EndMode3D(); + + EndDrawing(); + } + } + +private: + Camera camera; + RubixCube cube; +}; +} // namespace OOPCube diff --git a/Sims/RlImGuiSim.hpp b/Sims/RlImGuiSim.hpp new file mode 100644 index 0000000..6c2ef1e --- /dev/null +++ b/Sims/RlImGuiSim.hpp @@ -0,0 +1,221 @@ +#pragma once + +#include "../RubixSimulation.hpp" +#include "imgui.h" +#include "rlImGui.h" +#include +#include +#include + +namespace RlImGuiSim { +enum CubeFace { + FRONT = 0, + RIGHT, + BACK, + LEFT, + BOTTOM, + TOP +}; + +struct VecTriangle { + Vector3 pointOne; + Vector3 pointTwo; + Vector3 pointThree; +}; + +struct Plane3D { + VecTriangle one; + VecTriangle two; + Color color; +}; + +struct RubixCube { + Plane3D faces[6][9]; + Vector3 pos; +}; + +class RlImGuiSim : public RubixSimulation { +public: + bool Init() override { return true; } + void Run() override { + SetConfigFlags(FLAG_VSYNC_HINT); + InitWindow(1920, 1080, "Rubix Cube"); + + DisableCursor(); + + Camera3D cam = {0}; + cam.position = {10.0f, 10.0f, 10.0f}; + cam.target = {0.0f, 0.0f, 0.0f}; + cam.up = {0.0f, 1.0f, 0.0f}; + cam.fovy = 45.0f; + cam.projection = CAMERA_PERSPECTIVE; + + float cubeSize = 3.0f; + float previousCubeSize = cubeSize; + float planeScale = 1.0f; + + RubixCube cube = CreateRubixCube({0.0f, 0.0f, 0.0f}, cubeSize, planeScale); + + // Disable backface culling + rlDisableBackfaceCulling(); + + // Setup ImGui + rlImGuiSetup(true); + + bool isControllingCamera = true; + + while (!WindowShouldClose()) { + if (IsKeyPressed(KEY_SPACE)) + isControllingCamera = !isControllingCamera; + if (isControllingCamera) + UpdateCamera(&cam, CAMERA_FREE); + if (!isControllingCamera) + DrawText("Camera paused", 10, 10, 32, BLACK); + + BeginDrawing(); + ClearBackground(GRAY); + + rlImGuiBegin(); + ImGui::Begin("Controls"); + ImGui::SliderFloat("Cube Size", &cubeSize, 1.0f, 10.0f); + ImGui::SliderFloat("Plane Scale", &planeScale, 0.1f, 1.0f); + ImGui::End(); + rlImGuiEnd(); + + if (cubeSize != previousCubeSize || planeScale != 1.0f) { + cube = CreateRubixCube({0.0f, 0.0f, 0.0f}, cubeSize, planeScale); + previousCubeSize = cubeSize; + } + + BeginMode3D(cam); + + DrawRubixCube(&cube); + + DrawGrid(10, 1.0f); + + EndMode3D(); + EndDrawing(); + } + + rlImGuiShutdown(); + CloseWindow(); + } + + void DrawRubixCube(RubixCube *cube) { + rlDisableBackfaceCulling(); + for (int face = 0; face < 6; face++) { + for (int i = 0; i < 9; i++) { + DrawPlane3D(&cube->faces[face][i]); + } + } + } + + RubixCube CreateRubixCube(Vector3 position, float size, float planeScale) { + RubixCube cube; + cube.pos = position; + + float planeSize = size / 3.0f; + int faceIndex; + + for (int face = 0; face < 6; face++) { + faceIndex = 0; + for (int x = -1; x <= 1; x++) { + for (int y = -1; y <= 1; y++) { + Vector3 planePos = {position.x + x * planeSize, + position.y + y * planeSize, position.z}; + + switch (face) { + case FRONT: + planePos = {position.x + x * planeSize, position.y + y * planeSize, + position.z + size / 2}; + cube.faces[face][faceIndex++] = CreatePlane3D( + planeSize, planeSize, planePos, RED, {0, 0, 1}, planeScale); + break; + case BACK: + planePos = {position.x + x * planeSize, position.y + y * planeSize, + position.z - size / 2}; + cube.faces[face][faceIndex++] = CreatePlane3D( + planeSize, planeSize, planePos, ORANGE, {0, 0, -1}, planeScale); + break; + case LEFT: + planePos = {position.x - size / 2, position.y + y * planeSize, + position.z + x * planeSize}; + cube.faces[face][faceIndex++] = CreatePlane3D( + planeSize, planeSize, planePos, BLUE, {-1, 0, 0}, planeScale); + break; + case RIGHT: + planePos = {position.x + size / 2, position.y + y * planeSize, + position.z + x * planeSize}; + cube.faces[face][faceIndex++] = CreatePlane3D( + planeSize, planeSize, planePos, GREEN, {1, 0, 0}, planeScale); + break; + case TOP: + planePos = {position.x + x * planeSize, position.y + size / 2, + position.z + y * planeSize}; + cube.faces[face][faceIndex++] = CreatePlane3D( + planeSize, planeSize, planePos, YELLOW, {0, 1, 0}, planeScale); + break; + case BOTTOM: + planePos = {position.x + x * planeSize, position.y - size / 2, + position.z + y * planeSize}; + cube.faces[face][faceIndex++] = CreatePlane3D( + planeSize, planeSize, planePos, WHITE, {0, -1, 0}, planeScale); + break; + } + } + } + } + + return cube; + } + + void DrawPlane3D(Plane3D *plane) { + DrawTriangle3D(plane->one.pointOne, plane->one.pointTwo, + plane->one.pointThree, plane->color); + DrawTriangle3D(plane->two.pointOne, plane->two.pointTwo, + plane->two.pointThree, plane->color); + } + + Plane3D CreatePlane3D(float width, float height, Vector3 position, + Color color, Vector3 normal, float scale) { + Plane3D plane3D; + plane3D.color = color; + + Vector3 right, up; + + if (Vector3Equals(normal, {0.0f, 1.0f, 0.0f}) || + Vector3Equals(normal, {0.0f, -1.0f, 0.0f})) { + right = {1.0f, 0.0f, 0.0f}; + up = {0.0f, 0.0f, (normal.y > 0.0f) ? -1.0f : 1.0f}; + } else { + right = {normal.z, 0.0f, -normal.x}; + up = {0.0f, 1.0f, 0.0f}; + } + + float scaledWidth = width * scale; + float scaledHeight = height * scale; + + plane3D.one.pointOne = + Vector3Add(Vector3Add(position, Vector3Scale(right, -scaledWidth / 2)), + Vector3Scale(up, -scaledHeight / 2)); + plane3D.one.pointTwo = + Vector3Add(Vector3Add(position, Vector3Scale(right, scaledWidth / 2)), + Vector3Scale(up, -scaledHeight / 2)); + plane3D.one.pointThree = + Vector3Add(Vector3Add(position, Vector3Scale(right, -scaledWidth / 2)), + Vector3Scale(up, scaledHeight / 2)); + + plane3D.two.pointOne = + Vector3Add(Vector3Add(position, Vector3Scale(right, scaledWidth / 2)), + Vector3Scale(up, -scaledHeight / 2)); + plane3D.two.pointTwo = + Vector3Add(Vector3Add(position, Vector3Scale(right, scaledWidth / 2)), + Vector3Scale(up, scaledHeight / 2)); + plane3D.two.pointThree = + Vector3Add(Vector3Add(position, Vector3Scale(right, -scaledWidth / 2)), + Vector3Scale(up, scaledHeight / 2)); + + return plane3D; + } +}; +} // namespace RlImGuiSim diff --git a/main.cpp b/main.cpp index 429e661..ab47952 100644 --- a/main.cpp +++ b/main.cpp @@ -1,187 +1,12 @@ -#include -#include -#include -#include "rlImGui.h" -#include "imgui.h" - -enum CubeFace { - FRONT = 0, - RIGHT, - BACK, - LEFT, - BOTTOM, - TOP -}; - -struct VecTriangle { - Vector3 pointOne; - Vector3 pointTwo; - Vector3 pointThree; -}; - -struct Plane3D { - VecTriangle one; - VecTriangle two; - Color color; -}; - -struct RubixCube { - Plane3D faces[6][9]; - Vector3 pos; -}; - -void DrawRubixCube(RubixCube* cube); -void DrawPlane3D(Plane3D* plane); -Plane3D CreatePlane3D(float width, float height, Vector3 position, Color color, Vector3 normal, float scale); -RubixCube CreateRubixCube(Vector3 position, float size, float planeScale); +#include "Sims/OOPCube.hpp" +#include "Sims/RlImGuiSim.hpp" int main() { - SetConfigFlags(FLAG_VSYNC_HINT); - InitWindow(1920, 1080, "Rubix Cube"); + RubixSimulationRunner simRunner; + RlImGuiSim::RlImGuiSim rlImGuiSim; + OOPCube::OOPCube oopCube; + simRunner.SetSimulation(&oopCube); + simRunner.StartSimulation(); - DisableCursor(); - - Camera3D cam = { 0 }; - cam.position = { 10.0f, 10.0f, 10.0f }; - cam.target = { 0.0f, 0.0f, 0.0f }; - cam.up = { 0.0f, 1.0f, 0.0f }; - cam.fovy = 45.0f; - cam.projection = CAMERA_PERSPECTIVE; - - float cubeSize = 3.0f; - float previousCubeSize = cubeSize; - float planeScale = 1.0f; - - RubixCube cube = CreateRubixCube({0.0f, 0.0f, 0.0f}, cubeSize, planeScale); - - // Disable backface culling - rlDisableBackfaceCulling(); - - // Setup ImGui - rlImGuiSetup(true); - - bool isControllingCamera = true; - - while (!WindowShouldClose()) { - if (IsKeyPressed(KEY_SPACE)) isControllingCamera = !isControllingCamera; - if (isControllingCamera) UpdateCamera(&cam, CAMERA_FREE); - if (!isControllingCamera) DrawText("Camera paused", 10, 10, 32, BLACK); - - BeginDrawing(); - ClearBackground(GRAY); - - rlImGuiBegin(); - ImGui::Begin("Controls"); - ImGui::SliderFloat("Cube Size", &cubeSize, 1.0f, 10.0f); - ImGui::SliderFloat("Plane Scale", &planeScale, 0.1f, 1.0f); - ImGui::End(); - rlImGuiEnd(); - - if (cubeSize != previousCubeSize || planeScale != 1.0f) { - cube = CreateRubixCube({0.0f, 0.0f, 0.0f}, cubeSize, planeScale); - previousCubeSize = cubeSize; - } - - BeginMode3D(cam); - - DrawRubixCube(&cube); - - DrawGrid(10, 1.0f); - - EndMode3D(); - EndDrawing(); - } - - rlImGuiShutdown(); - CloseWindow(); - - return 0; -} - -void DrawRubixCube(RubixCube* cube) { - rlDisableBackfaceCulling(); - for (int face = 0; face < 6; face++) { - for (int i = 0; i < 9; i++) { - DrawPlane3D(&cube->faces[face][i]); - } - } -} - -RubixCube CreateRubixCube(Vector3 position, float size, float planeScale) { - RubixCube cube; - cube.pos = position; - - float planeSize = size / 3.0f; - int faceIndex; - - for (int face = 0; face < 6; face++) { - faceIndex = 0; - for (int x = -1; x <= 1; x++) { - for (int y = -1; y <= 1; y++) { - Vector3 planePos = { position.x + x * planeSize, position.y + y * planeSize, position.z }; - - switch (face) { - case FRONT: - planePos = { position.x + x * planeSize, position.y + y * planeSize, position.z + size / 2 }; - cube.faces[face][faceIndex++] = CreatePlane3D(planeSize, planeSize, planePos, RED, {0, 0, 1}, planeScale); - break; - case BACK: - planePos = { position.x + x * planeSize, position.y + y * planeSize, position.z - size / 2 }; - cube.faces[face][faceIndex++] = CreatePlane3D(planeSize, planeSize, planePos, ORANGE, {0, 0, -1}, planeScale); - break; - case LEFT: - planePos = { position.x - size / 2, position.y + y * planeSize, position.z + x * planeSize }; - cube.faces[face][faceIndex++] = CreatePlane3D(planeSize, planeSize, planePos, BLUE, {-1, 0, 0}, planeScale); - break; - case RIGHT: - planePos = { position.x + size / 2, position.y + y * planeSize, position.z + x * planeSize }; - cube.faces[face][faceIndex++] = CreatePlane3D(planeSize, planeSize, planePos, GREEN, {1, 0, 0}, planeScale); - break; - case TOP: - planePos = { position.x + x * planeSize, position.y + size / 2, position.z + y * planeSize }; - cube.faces[face][faceIndex++] = CreatePlane3D(planeSize, planeSize, planePos, YELLOW, {0, 1, 0}, planeScale); - break; - case BOTTOM: - planePos = { position.x + x * planeSize, position.y - size / 2, position.z + y * planeSize }; - cube.faces[face][faceIndex++] = CreatePlane3D(planeSize, planeSize, planePos, WHITE, {0, -1, 0}, planeScale); - break; - } - } - } - } - - return cube; -} - -void DrawPlane3D(Plane3D* plane) { - DrawTriangle3D(plane->one.pointOne, plane->one.pointTwo, plane->one.pointThree, plane->color); - DrawTriangle3D(plane->two.pointOne, plane->two.pointTwo, plane->two.pointThree, plane->color); -} - -Plane3D CreatePlane3D(float width, float height, Vector3 position, Color color, Vector3 normal, float scale) { - Plane3D plane3D; - plane3D.color = color; - - Vector3 right, up; - - if (Vector3Equals(normal, {0, 1, 0}) || Vector3Equals(normal, {0, -1, 0})) { - right = {1, 0, 0}; - up = {0, 0, (normal.y > 0) ? -1 : 1}; - } else { - right = {normal.z, 0, -normal.x}; - up = {0, 1, 0}; - } - - float scaledWidth = width * scale; - float scaledHeight = height * scale; - - plane3D.one.pointOne = Vector3Add(Vector3Add(position, Vector3Scale(right, -scaledWidth / 2)), Vector3Scale(up, -scaledHeight / 2)); - plane3D.one.pointTwo = Vector3Add(Vector3Add(position, Vector3Scale(right, scaledWidth / 2)), Vector3Scale(up, -scaledHeight / 2)); - plane3D.one.pointThree = Vector3Add(Vector3Add(position, Vector3Scale(right, -scaledWidth / 2)), Vector3Scale(up, scaledHeight / 2)); - - plane3D.two.pointOne = Vector3Add(Vector3Add(position, Vector3Scale(right, scaledWidth / 2)), Vector3Scale(up, -scaledHeight / 2)); - plane3D.two.pointTwo = Vector3Add(Vector3Add(position, Vector3Scale(right, scaledWidth / 2)), Vector3Scale(up, scaledHeight / 2)); - plane3D.two.pointThree = Vector3Add(Vector3Add(position, Vector3Scale(right, -scaledWidth / 2)), Vector3Scale(up, scaledHeight / 2)); - - return plane3D; -} + return 0; +} \ No newline at end of file