├── .gitignore ├── ACKNOWLEDGEMENTS ├── CMakeLists.txt ├── LICENSE ├── README.md ├── banner.png └── src ├── AxisAlignedBox.cpp ├── AxisAlignedBox.hpp ├── Circle.cpp ├── Circle.hpp ├── Collision.cpp ├── Collision.hpp ├── Line.cpp ├── Line.hpp ├── OrientedBox.cpp ├── OrientedBox.hpp ├── Point.cpp ├── Point.hpp ├── Render.cpp ├── Render.hpp ├── State.cpp ├── State.hpp ├── StateBoxes.cpp ├── StateBoxes.hpp ├── StateCircles.cpp ├── StateCircles.hpp ├── StateMachine.cpp ├── StateMachine.hpp ├── StateTest.cpp ├── StateTest.hpp ├── StateTriangulate.cpp ├── StateTriangulate.hpp ├── Triangle.cpp ├── Triangle.hpp └── main.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | 6 | # Compiled Dynamic libraries 7 | *.so 8 | *.dylib 9 | 10 | # Compiled Static libraries 11 | *.lai 12 | *.la 13 | *.a 14 | 15 | # Build directories 16 | *build/ 17 | 18 | # Vim swp files 19 | *.swp 20 | -------------------------------------------------------------------------------- /ACKNOWLEDGEMENTS: -------------------------------------------------------------------------------- 1 | This software utilizies the following libraries: 2 | 3 | CGUL https://github.com/Zethes/CGUL 4 | Copyright (C) 2012-2014, Joshua Brookover and Amber Thrall 5 | 6 | The OpenGL Extension Wrangler Library http://glew.sourceforge.net/ 7 | Copyright (C) 2002-2007, Milan Ikits 8 | Copyright (C) 2002-2007, Marcelo E. Magallon 9 | Copyright (C) 2002, Lev Povalahev 10 | All rights reserved. 11 | 12 | The libraries above are released under absolutely no warranty. 13 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.7) 2 | cmake_policy(VERSION 2.8.7) 3 | project(Physics CXX) 4 | 5 | find_package(CGUL 0.1.8 REQUIRED) 6 | 7 | include_directories(${CGUL_INCLUDE_DIRS}) 8 | add_executable(physics 9 | src/main.cpp 10 | src/State.cpp 11 | src/StateMachine.cpp 12 | src/StateBoxes.cpp 13 | src/StateCircles.cpp 14 | src/StateTest.cpp 15 | src/StateTriangulate.cpp 16 | src/Render.cpp 17 | src/Collision.cpp 18 | src/AxisAlignedBox.cpp 19 | src/OrientedBox.cpp 20 | src/Circle.cpp 21 | src/Line.cpp 22 | src/Triangle.cpp 23 | src/Point.cpp 24 | ) 25 | target_link_libraries(physics ${CGUL_LIBRARIES}) 26 | cgul_bake_rpath(physics "$ORIGIN") 27 | 28 | if(NOT CGUL_STATIC) 29 | get_target_property(__CGUL_PATH CGUL IMPORTED_LOCATION) 30 | get_filename_component(__CGUL_NAME ${__CGUL_PATH} NAME) 31 | add_custom_target(${__CGUL_NAME} ALL COMMAND cmake -E copy "${__CGUL_PATH}" "${CMAKE_CURRENT_BINARY_DIR}/" VERBATIM) 32 | endif() 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, Joshua Brookover 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, this 11 | list of conditions and the following disclaimer in the documentation and/or 12 | other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Physics2D 2 | ========= 3 | 4 | Some 2D collision detection and physics stuff written in C++. 5 | Utilizes and remains consistent with the [C++ General Utility Library (CGUL)](https://github.com/Zethes/CGUL). 6 | 7 | Goals 8 | ===== 9 | * [Collision detection](#collision-detection) between various trivial 2D primitives 10 | * [Closest point](#closest-point) algorithms 11 | * "Complex" objects built from trivial primitives 12 | * Triangulization from convex and concave primitives 13 | * Collision prediction algorithms 14 | * Collision response (impulse based?) 15 | * Force generators (gravity/springs/explosions) 16 | * Consistent results between identical iterations 17 | * Hierarchy collision detection optimizations 18 | * Binary space partitioning optimizations 19 | 20 | Collision Detection 21 | ===== 22 | Below is a matrix of supported collision algorithms between trivial 2D primitives. 23 | 24 | | | Circle | AABB | OBB | Line | Triangle | Point | 25 | |:--------------:|:-------------------:|:------------------:|:-----------------:|:------------------:|:------------------:|:------------------:| 26 | | __Circle__ | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | :heavy_check_mark: | | 27 | | __AABB__ | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | :heavy_check_mark: | | 28 | | __OBB__ | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | :heavy_check_mark: | | 29 | | __Line__ | | | | | | | 30 | | __Triangle__ | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | | :heavy_check_mark: | 31 | | __Point__ | | | | | :heavy_check_mark: | :heavy_check_mark: | 32 | 33 | __Planned types:__ 34 | * Ovals ? 35 | 36 | Closest Point 37 | ===== 38 | Closest point algorithms are implemented for the following types: 39 | * Circle 40 | * AABB 41 | * OBB 42 | * Line 43 | * Triangle (kind of buggy right now!) 44 | * Point 45 | 46 | Requirements 47 | ===== 48 | Requires [CGUL](https://github.com/Zethes/CGUL) built with [GLEW](http://glew.sourceforge.net/). 49 | Uses [CMake](http://www.cmake.org/) build system. 50 | Graphics via OpenGL 2.1(ish?) 51 | Tested with GCC 4.2 (Mac), Clang 3.2 (Mac), GCC 4.7 (Linux & MinGW), and Visual Studio 2010 (Windows). 52 | 53 | License 54 | ===== 55 | The code is under the [BSD 2-clause License](https://github.com/JoshuaBrookover/Physics2D/blob/master/LICENSE). You must include a copyright notice in your product's documentation if you use this code in full. Feel free to use snippets of the code, or re-implement the code, without this restriction. 56 | -------------------------------------------------------------------------------- /banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoshuaBrookover/Physics2D/d570bbc0a6e412d3968cb77c3a65a1b1c1d4677e/banner.png -------------------------------------------------------------------------------- /src/AxisAlignedBox.cpp: -------------------------------------------------------------------------------- 1 | #include "AxisAlignedBox.hpp" 2 | 3 | #include "Circle.hpp" 4 | #include "OrientedBox.hpp" 5 | #include "Line.hpp" 6 | #include "Point.hpp" 7 | 8 | AxisAlignedBox::AxisAlignedBox() : 9 | Collision(Collision::AXIS_ALIGNED_BOX) 10 | { 11 | } 12 | 13 | AxisAlignedBox::AxisAlignedBox(const CGUL::Vector2& position, const CGUL::Vector2& halfExtents) : 14 | Collision(Collision::AXIS_ALIGNED_BOX), 15 | position(position), 16 | halfExtents(halfExtents) 17 | { 18 | } 19 | 20 | void AxisAlignedBox::SetPosition(const CGUL::Vector2& position) 21 | { 22 | this->position = position; 23 | } 24 | 25 | void AxisAlignedBox::SetHalfExtents(const CGUL::Vector2& halfExtents) 26 | { 27 | this->halfExtents = halfExtents; 28 | } 29 | 30 | CGUL::Vector2 AxisAlignedBox::GetPosition() const 31 | { 32 | return this->position; 33 | } 34 | 35 | CGUL::Vector2 AxisAlignedBox::GetExtents() const 36 | { 37 | return this->halfExtents; 38 | } 39 | 40 | CGUL::Vector2 AxisAlignedBox::GetClosestPoint(const CGUL::Vector2& position) const 41 | { 42 | using namespace CGUL; 43 | 44 | Vector2 difference = position - this->position; 45 | difference.x = Math::Clamp(difference.x, -halfExtents.x, halfExtents.x); 46 | difference.y = Math::Clamp(difference.y, -halfExtents.y, halfExtents.y); 47 | return this->position + difference; 48 | } 49 | 50 | CGUL::Matrix AxisAlignedBox::GetWorldMatrix() const 51 | { 52 | return CGUL::Matrix::MakeTranslation(position); 53 | } 54 | 55 | void AxisAlignedBox::ProjectionOnAxis(const CGUL::Vector2& axis, CGUL::Float32* min, CGUL::Float32* max) const 56 | { 57 | CGUL::Matrix world; 58 | world = world * CGUL::Matrix::MakeTranslation(position); 59 | 60 | CGUL::Vector2 points[] = 61 | { 62 | CGUL::Vector2( halfExtents.x, halfExtents.y) * world, 63 | CGUL::Vector2(-halfExtents.x, halfExtents.y) * world, 64 | CGUL::Vector2( halfExtents.x, -halfExtents.y) * world, 65 | CGUL::Vector2(-halfExtents.x, -halfExtents.y) * world 66 | }; 67 | 68 | return Collision::ProjectionOnAxis(points, 4, axis, min, max); 69 | } 70 | 71 | bool AxisAlignedBox::CollidingCircle(const Circle& other) const 72 | { 73 | return CheckCircleAndAxisAlignedBox(other, *this); 74 | } 75 | 76 | bool AxisAlignedBox::CollidingAxisAlignedBox(const AxisAlignedBox& other) const 77 | { 78 | return CheckAxisAlignedBoxAndAxisAlignedBox(*this, other); 79 | } 80 | 81 | bool AxisAlignedBox::CollidingOrientedBox(const OrientedBox& other) const 82 | { 83 | return CheckAxisAlignedBoxAndOrientedBox(*this, other); 84 | } 85 | 86 | bool AxisAlignedBox::CollidingLine(const Line& other) const 87 | { 88 | return CheckAxisAlignedBoxAndLine(*this, other); 89 | } 90 | 91 | bool AxisAlignedBox::CollidingTriangle(const Triangle& other) const 92 | { 93 | return CheckAxisAlignedBoxAndTriangle(*this, other); 94 | } 95 | 96 | bool AxisAlignedBox::CollidingPoint(const Point& other) const 97 | { 98 | return CheckAxisAlignedBoxAndPoint(*this, other); 99 | } 100 | 101 | void AxisAlignedBox::Draw() const 102 | { 103 | render->Box(position, halfExtents * 2, color); 104 | } 105 | -------------------------------------------------------------------------------- /src/AxisAlignedBox.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "Collision.hpp" 4 | #include "Render.hpp" 5 | 6 | extern Render* render; 7 | 8 | struct AxisAlignedBox : public Collision 9 | { 10 | CGUL::Vector2 position; 11 | CGUL::Vector2 halfExtents; 12 | 13 | AxisAlignedBox(); 14 | AxisAlignedBox(const CGUL::Vector2& position, const CGUL::Vector2& halfExtents); 15 | 16 | void SetPosition(const CGUL::Vector2& position); 17 | void SetHalfExtents(const CGUL::Vector2& halfExtents); 18 | 19 | CGUL::Vector2 GetPosition() const; 20 | CGUL::Vector2 GetExtents() const; 21 | 22 | CGUL::Vector2 GetClosestPoint(const CGUL::Vector2& position) const; 23 | 24 | void ProjectionOnAxis(const CGUL::Vector2& axis, CGUL::Float32* min, CGUL::Float32* max) const; 25 | 26 | CGUL::Matrix GetWorldMatrix() const; 27 | 28 | bool CollidingCircle(const Circle& other) const; 29 | bool CollidingAxisAlignedBox(const AxisAlignedBox& other) const; 30 | bool CollidingOrientedBox(const OrientedBox& other) const; 31 | bool CollidingLine(const Line& other) const; 32 | bool CollidingTriangle(const Triangle& other) const; 33 | bool CollidingPoint(const Point& other) const; 34 | 35 | void Draw() const; 36 | }; 37 | -------------------------------------------------------------------------------- /src/Circle.cpp: -------------------------------------------------------------------------------- 1 | #include "Circle.hpp" 2 | 3 | #include "AxisAlignedBox.hpp" 4 | #include "OrientedBox.hpp" 5 | #include "Line.hpp" 6 | 7 | Circle::Circle() : 8 | Collision(Collision::CIRCLE), 9 | radius(0), 10 | orientation(0) 11 | { 12 | } 13 | 14 | Circle::Circle(const CGUL::Vector2& position, CGUL::Float32 radius, CGUL::Float32 orientation) : 15 | Collision(Collision::CIRCLE), 16 | position(position), 17 | radius(radius), 18 | orientation(orientation) 19 | { 20 | } 21 | 22 | void Circle::SetPosition(const CGUL::Vector2& position) 23 | { 24 | this->position = position; 25 | } 26 | 27 | void Circle::SetRadius(CGUL::Float32 radius) 28 | { 29 | this->radius = radius; 30 | } 31 | 32 | CGUL::Vector2 Circle::GetPosition() const 33 | { 34 | return position; 35 | } 36 | 37 | CGUL::Float32 Circle::GetRadius() const 38 | { 39 | return radius; 40 | } 41 | 42 | CGUL::Vector2 Circle::GetClosestPoint(const CGUL::Vector2& position) const 43 | { 44 | CGUL::Vector2 difference = position - this->position; 45 | CGUL::Float32 distance = difference.GetMagnitude(); 46 | if (distance > radius) 47 | { 48 | difference /= distance; 49 | difference *= radius; 50 | return this->position + difference; 51 | } 52 | return position; 53 | } 54 | 55 | CGUL::Matrix Circle::GetWorldMatrix() const 56 | { 57 | CGUL::Matrix matrix; 58 | matrix = matrix * CGUL::Matrix::MakeRotation(orientation); 59 | matrix = matrix * CGUL::Matrix::MakeTranslation(position); 60 | return matrix; 61 | } 62 | 63 | void Circle::ProjectionOnAxis(const CGUL::Vector2& axis, CGUL::Float32* min, CGUL::Float32* max) const 64 | { 65 | CGUL::Float32 projection = CGUL::Vector2::DotProduct(axis, position); 66 | *min = projection - radius; 67 | *max = projection + radius; 68 | } 69 | 70 | bool Circle::CollidingCircle(const Circle& other) const 71 | { 72 | return CheckCircleAndCircle(*this, other); 73 | } 74 | 75 | bool Circle::CollidingAxisAlignedBox(const AxisAlignedBox& other) const 76 | { 77 | return CheckCircleAndAxisAlignedBox(*this, other); 78 | } 79 | 80 | bool Circle::CollidingOrientedBox(const OrientedBox& other) const 81 | { 82 | return CheckCircleAndOrientedBox(*this, other); 83 | } 84 | 85 | bool Circle::CollidingLine(const Line& other) const 86 | { 87 | return CheckCircleAndLine(*this, other); 88 | } 89 | 90 | bool Circle::CollidingTriangle(const Triangle& other) const 91 | { 92 | return CheckCircleAndTriangle(*this, other); 93 | } 94 | 95 | bool Circle::CollidingPoint(const Point& other) const 96 | { 97 | return CheckCircleAndPoint(*this, other); 98 | } 99 | 100 | void Circle::Draw() const 101 | { 102 | render->Circle(position, radius, orientation, color); 103 | } 104 | -------------------------------------------------------------------------------- /src/Circle.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "Collision.hpp" 4 | #include "Render.hpp" 5 | 6 | extern Render* render; 7 | 8 | struct Circle : public Collision 9 | { 10 | CGUL::Vector2 position; 11 | CGUL::Float32 radius; 12 | CGUL::Float32 orientation; 13 | 14 | Circle(); 15 | Circle(const CGUL::Vector2& position, CGUL::Float32 radius, CGUL::Float32 orientation); 16 | 17 | void SetPosition(const CGUL::Vector2& position); 18 | void SetRadius(CGUL::Float32 radius); 19 | 20 | CGUL::Vector2 GetPosition() const; 21 | CGUL::Float32 GetRadius() const; 22 | 23 | CGUL::Vector2 GetClosestPoint(const CGUL::Vector2& position) const; 24 | 25 | void ProjectionOnAxis(const CGUL::Vector2& axis, CGUL::Float32* min, CGUL::Float32* max) const; 26 | 27 | CGUL::Matrix GetWorldMatrix() const; 28 | 29 | bool CollidingCircle(const Circle& other) const; 30 | bool CollidingAxisAlignedBox(const AxisAlignedBox& other) const; 31 | bool CollidingOrientedBox(const OrientedBox& other) const; 32 | bool CollidingLine(const Line& other) const; 33 | bool CollidingTriangle(const Triangle& other) const; 34 | bool CollidingPoint(const Point& other) const; 35 | 36 | void Draw() const; 37 | }; 38 | -------------------------------------------------------------------------------- /src/Collision.cpp: -------------------------------------------------------------------------------- 1 | #include "Collision.hpp" 2 | 3 | #include "Circle.hpp" 4 | #include "AxisAlignedBox.hpp" 5 | #include "OrientedBox.hpp" 6 | #include "Line.hpp" 7 | #include "Triangle.hpp" 8 | #include "Point.hpp" 9 | 10 | using namespace CGUL; 11 | 12 | void Collision::ProjectionOnAxis(const Vector2* points, const Size count, const Vector2& axis, Float32* min, Float32* max) 13 | { 14 | Vector2 point = points[0]; 15 | point = points[0]; 16 | Float32 dotProduct = Vector2::DotProduct(axis, point); 17 | *min = *max = dotProduct; 18 | for (Size i = 1; i < count; i++) 19 | { 20 | point = points[i]; 21 | 22 | dotProduct = Vector2::DotProduct(axis, point); 23 | 24 | if (dotProduct < *min) 25 | { 26 | *min = dotProduct; 27 | } 28 | if (dotProduct > *max) 29 | { 30 | *max = dotProduct; 31 | } 32 | } 33 | } 34 | 35 | bool Collision::CheckCircleAndCircle(const Circle& a, const Circle& b) 36 | { 37 | return (Math::Sqr(a.radius + b.radius) > Vector2::DistanceSquared(a.position, b.position)); 38 | } 39 | 40 | bool Collision::CheckCircleAndAxisAlignedBox(const Circle& circle, const AxisAlignedBox& box) 41 | { 42 | CGUL::Vector2 closestPoint = box.GetClosestPoint(circle.position); 43 | return (CGUL::Vector2::DistanceSquared(circle.position, closestPoint) < CGUL::Math::Sqr(circle.radius)); 44 | } 45 | 46 | bool Collision::CheckCircleAndOrientedBox(const Circle& circle, const OrientedBox& box) 47 | { 48 | CGUL::Vector2 closestPoint = box.GetClosestPoint(circle.position); 49 | return (CGUL::Vector2::DistanceSquared(circle.position, closestPoint) < CGUL::Math::Sqr(circle.radius)); 50 | } 51 | 52 | bool Collision::CheckCircleAndLine(const Circle& circle, const Line& line) 53 | { 54 | CGUL::Vector2 closestPoint = line.GetClosestPoint(circle.position); 55 | return (CGUL::Vector2::DistanceSquared(circle.position, closestPoint) < CGUL::Math::Sqr(circle.radius)); 56 | } 57 | 58 | bool Collision::CheckCircleAndTriangle(const Circle& circle, const Triangle& triangle) 59 | { 60 | CGUL::Vector2 closestPoint = triangle.GetClosestPoint(circle.position); 61 | return (CGUL::Vector2::DistanceSquared(circle.position, closestPoint) < CGUL::Math::Sqr(circle.radius)); 62 | } 63 | 64 | bool Collision::CheckCircleAndPoint(const Circle& circle, const Point& point) 65 | { 66 | // TODO 67 | return false; 68 | } 69 | 70 | bool Collision::CheckAxisAlignedBoxAndAxisAlignedBox(const AxisAlignedBox& a, const AxisAlignedBox& b) 71 | { 72 | CGUL::Vector2 difference = a.position - b.position; 73 | difference.x = CGUL::Math::Abs(difference.x); 74 | difference.y = CGUL::Math::Abs(difference.y); 75 | CGUL::Vector2 combinedExtents = (a.halfExtents + b.halfExtents); 76 | 77 | return (difference.x <= combinedExtents.x && difference.y <= combinedExtents.y); 78 | } 79 | 80 | bool Collision::CheckAxisAlignedBoxAndOrientedBox(const AxisAlignedBox& aabb, const OrientedBox& obb) 81 | { 82 | Vector2 axes[] = 83 | { 84 | Vector2::unitX, 85 | Vector2::unitY, 86 | Vector2(Math::Cos(obb.orientation), Math::Sin(obb.orientation)), 87 | Vector2(Math::Sin(obb.orientation), -Math::Cos(obb.orientation)) 88 | }; 89 | return aabb.CollidingOnAxes(obb, axes, 4); 90 | } 91 | 92 | bool Collision::CheckAxisAlignedBoxAndLine(const AxisAlignedBox& box, const Line& line) 93 | { 94 | // TODO 95 | return false; 96 | } 97 | 98 | bool Collision::CheckAxisAlignedBoxAndTriangle(const AxisAlignedBox& box, const Triangle& triangle) 99 | { 100 | Vector2 side1 = triangle.pointA - triangle.pointB; 101 | Vector2 side2 = triangle.pointB - triangle.pointC; 102 | Vector2 side3 = triangle.pointC - triangle.pointA; 103 | 104 | Vector2 axes[] = 105 | { 106 | Vector2::unitX, 107 | Vector2::unitY, 108 | Vector2::Normalized(side1.GetPerpendicular()), 109 | Vector2::Normalized(side2.GetPerpendicular()), 110 | Vector2::Normalized(side3.GetPerpendicular()) 111 | }; 112 | return box.CollidingOnAxes(triangle, axes, 5); 113 | } 114 | 115 | bool Collision::CheckAxisAlignedBoxAndPoint(const AxisAlignedBox& box, const Point& point) 116 | { 117 | // TODO 118 | return false; 119 | } 120 | 121 | bool Collision::CheckOrientedBoxAndOrientedBox(const OrientedBox& a, const OrientedBox& b) 122 | { 123 | Vector2 axes[] = 124 | { 125 | Vector2(Math::Cos(a.orientation), Math::Sin(a.orientation)), 126 | Vector2(Math::Sin(a.orientation), -Math::Cos(a.orientation)), 127 | Vector2(Math::Cos(b.orientation), Math::Sin(b.orientation)), 128 | Vector2(Math::Sin(b.orientation), -Math::Cos(b.orientation)) 129 | }; 130 | return a.CollidingOnAxes(b, axes, 4); 131 | } 132 | 133 | bool Collision::CheckOrientedBoxAndLine(const OrientedBox& box, const Line& line) 134 | { 135 | // TODO 136 | return false; 137 | } 138 | 139 | bool Collision::CheckOrientedBoxAndTriangle(const OrientedBox& box, const Triangle& triangle) 140 | { 141 | Vector2 side1 = triangle.pointA - triangle.pointB; 142 | Vector2 side2 = triangle.pointB - triangle.pointC; 143 | Vector2 side3 = triangle.pointC - triangle.pointA; 144 | 145 | Vector2 axes[] = 146 | { 147 | Vector2(Math::Cos(box.orientation), Math::Sin(box.orientation)), 148 | Vector2(Math::Sin(box.orientation), -Math::Cos(box.orientation)), 149 | Vector2::Normalized(side1.GetPerpendicular()), 150 | Vector2::Normalized(side2.GetPerpendicular()), 151 | Vector2::Normalized(side3.GetPerpendicular()) 152 | }; 153 | return box.CollidingOnAxes(triangle, axes, 5); 154 | } 155 | 156 | bool Collision::CheckOrientedBoxAndPoint(const OrientedBox& box, const Point& point) 157 | { 158 | // TODO 159 | return false; 160 | } 161 | 162 | bool Collision::CheckLineAndLine(const Line& a, const Line& b) 163 | { 164 | // TODO 165 | return false; 166 | } 167 | 168 | bool Collision::CheckLineAndTriangle(const Line& line, const Triangle& triangle) 169 | { 170 | // TODO 171 | return false; 172 | } 173 | 174 | bool Collision::CheckLineAndPoint(const Line& line, const Point& point) 175 | { 176 | // TODO 177 | return false; 178 | } 179 | 180 | bool Collision::CheckTriangleAndTriangle(const Triangle& a, const Triangle& b) 181 | { 182 | // TODO 183 | return false; 184 | } 185 | 186 | bool Collision::CheckTriangleAndPoint(const Triangle& triangle, const Point& point) 187 | { 188 | Vector2 p = point.position, a = triangle.pointA, b = triangle.pointB, c = triangle.pointC; 189 | float pab = Vector2::CrossProduct(p - a, b - a); 190 | float pbc = Vector2::CrossProduct(p - b, c - b); 191 | if (Math::Sign(pab) != Math::Sign(pbc)) 192 | { 193 | return false; 194 | } 195 | float pca = Vector2::CrossProduct(p - c, a - c); 196 | if (Math::Sign(pab) != Math::Sign(pca)) 197 | { 198 | return false; 199 | } 200 | return true; 201 | } 202 | 203 | bool Collision::CheckPointAndPoint(const Point& a, const Point& b) 204 | { 205 | return (a.position == b.position); 206 | } 207 | 208 | Collision::Collision(Enum type) : 209 | type(type) 210 | { 211 | } 212 | 213 | bool Collision::CollidingOnAxis(const Collision& other, const Vector2& axis) const 214 | { 215 | Float32 min, max, otherMin, otherMax; 216 | ProjectionOnAxis(axis, &min, &max); 217 | other.ProjectionOnAxis(axis, &otherMin, &otherMax); 218 | 219 | return (min <= otherMax && max >= otherMin); 220 | } 221 | 222 | bool Collision::CollidingOnAxes(const Collision& other, Vector2* axes, Size count) const 223 | { 224 | for (Size i = 0; i < count; i++) 225 | { 226 | if (!CollidingOnAxis(other, axes[i])) 227 | { 228 | return false; 229 | } 230 | } 231 | return true; 232 | } 233 | 234 | bool Collision::Colliding(const Collision* other) const 235 | { 236 | switch (type) 237 | { 238 | case CIRCLE: return other->CollidingCircle(*(Circle*)this); 239 | case AXIS_ALIGNED_BOX: return other->CollidingAxisAlignedBox(*(AxisAlignedBox*)this); 240 | case ORIENTED_BOX: return other->CollidingOrientedBox(*(OrientedBox*)this); 241 | case LINE: return other->CollidingLine(*(Line*)this); 242 | default: return false; 243 | } 244 | } 245 | -------------------------------------------------------------------------------- /src/Collision.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "Render.hpp" 4 | 5 | struct Circle; 6 | struct AxisAlignedBox; 7 | struct OrientedBox; 8 | struct Line; 9 | struct Triangle; 10 | struct Point; 11 | 12 | extern Render* render; 13 | 14 | struct Collision 15 | { 16 | enum 17 | { 18 | CIRCLE, 19 | AXIS_ALIGNED_BOX, 20 | ORIENTED_BOX, 21 | LINE, 22 | TRIANGLE, 23 | POINT 24 | }; 25 | 26 | static void ProjectionOnAxis(const CGUL::Vector2* points, const CGUL::Size count, const CGUL::Vector2& axis, CGUL::Float32* min, CGUL::Float32* max); 27 | 28 | static bool CheckCircleAndCircle(const Circle& a, const Circle& b); 29 | static bool CheckCircleAndAxisAlignedBox(const Circle& circle, const AxisAlignedBox& box); 30 | static bool CheckCircleAndOrientedBox(const Circle& circle, const OrientedBox& box); 31 | static bool CheckCircleAndLine(const Circle& circle, const Line& line); 32 | static bool CheckCircleAndTriangle(const Circle& circle, const Triangle& triangle); 33 | static bool CheckCircleAndPoint(const Circle& circle, const Point& point); 34 | static bool CheckAxisAlignedBoxAndAxisAlignedBox(const AxisAlignedBox& a, const AxisAlignedBox& b); 35 | static bool CheckAxisAlignedBoxAndOrientedBox(const AxisAlignedBox& aabb, const OrientedBox& obb); 36 | static bool CheckAxisAlignedBoxAndLine(const AxisAlignedBox& box, const Line& line); 37 | static bool CheckAxisAlignedBoxAndTriangle(const AxisAlignedBox& box, const Triangle& triangle); 38 | static bool CheckAxisAlignedBoxAndPoint(const AxisAlignedBox& box, const Point& point); 39 | static bool CheckOrientedBoxAndOrientedBox(const OrientedBox& a, const OrientedBox& b); 40 | static bool CheckOrientedBoxAndLine(const OrientedBox& box, const Line& line); 41 | static bool CheckOrientedBoxAndTriangle(const OrientedBox& box, const Triangle& triangle); 42 | static bool CheckOrientedBoxAndPoint(const OrientedBox& box, const Point& point); 43 | static bool CheckLineAndLine(const Line& a, const Line& b); 44 | static bool CheckLineAndTriangle(const Line& line, const Triangle& triangle); 45 | static bool CheckLineAndPoint(const Line& line, const Point& point); 46 | static bool CheckTriangleAndTriangle(const Triangle& a, const Triangle& b); 47 | static bool CheckTriangleAndPoint(const Triangle& triangle, const Point& point); 48 | static bool CheckPointAndPoint(const Point& a, const Point& b); 49 | 50 | CGUL::Enum type; 51 | CGUL::Color color; 52 | 53 | Collision(CGUL::Enum type); 54 | 55 | virtual void SetPosition(const CGUL::Vector2& position) = 0; 56 | virtual CGUL::Vector2 GetPosition() const = 0; 57 | 58 | virtual CGUL::Vector2 GetClosestPoint(const CGUL::Vector2& position) const = 0; 59 | 60 | virtual CGUL::Matrix GetWorldMatrix() const = 0; 61 | 62 | virtual void ProjectionOnAxis(const CGUL::Vector2& axis, CGUL::Float32* min, CGUL::Float32* max) const = 0; 63 | virtual bool CollidingOnAxis(const Collision& other, const CGUL::Vector2& axis) const; 64 | virtual bool CollidingOnAxes(const Collision& other, CGUL::Vector2* axes, CGUL::Size count) const; 65 | 66 | virtual bool CollidingCircle(const Circle& other) const = 0; 67 | virtual bool CollidingAxisAlignedBox(const AxisAlignedBox& other) const = 0; 68 | virtual bool CollidingOrientedBox(const OrientedBox& other) const = 0; 69 | virtual bool CollidingLine(const Line& other) const = 0; 70 | virtual bool CollidingTriangle(const Triangle& other) const = 0; 71 | virtual bool CollidingPoint(const Point& point) const = 0; 72 | 73 | bool Colliding(const Collision* other) const; 74 | 75 | virtual void Draw() const = 0; 76 | }; 77 | -------------------------------------------------------------------------------- /src/Line.cpp: -------------------------------------------------------------------------------- 1 | #include "Line.hpp" 2 | 3 | #include "Circle.hpp" 4 | #include "AxisAlignedBox.hpp" 5 | #include "OrientedBox.hpp" 6 | 7 | Line::Line() : 8 | Collision(Collision::LINE) 9 | { 10 | } 11 | 12 | Line::Line(const CGUL::Vector2& start, const CGUL::Vector2& end) : 13 | Collision(Collision::LINE), 14 | start(start), 15 | end(end) 16 | { 17 | } 18 | 19 | void Line::SetPosition(const CGUL::Vector2& position) 20 | { 21 | this->start = position; 22 | } 23 | 24 | void Line::SetStart(const CGUL::Vector2& start) 25 | { 26 | this->start = start; 27 | } 28 | 29 | void Line::SetEnd(const CGUL::Vector2& end) 30 | { 31 | this->end = end; 32 | } 33 | 34 | CGUL::Vector2 Line::GetPosition() const 35 | { 36 | return this->start; 37 | } 38 | 39 | CGUL::Vector2 Line::GetStart() const 40 | { 41 | return this->start; 42 | } 43 | 44 | CGUL::Vector2 Line::GetEnd() const 45 | { 46 | return this->end; 47 | } 48 | 49 | CGUL::Vector2 Line::GetClosestPoint(const CGUL::Vector2& position) const 50 | { 51 | using namespace CGUL; 52 | 53 | Vector2 axis = this->end - this->start; 54 | axis.Normalize(); 55 | Vector2 perp(axis.y, -axis.x); 56 | 57 | Float32 axisPosition = Vector2::DotProduct(position, axis); 58 | Float32 axisMin = Vector2::DotProduct(start, axis); 59 | Float32 axisMax = Vector2::DotProduct(end, axis); 60 | axisPosition = Math::Clamp(axisPosition, axisMin, axisMax); 61 | 62 | Float32 perpPosition = Vector2::DotProduct(start, perp); 63 | 64 | return axis * axisPosition + perp * perpPosition; 65 | } 66 | 67 | CGUL::Matrix Line::GetWorldMatrix() const 68 | { 69 | // TODO 70 | return CGUL::Matrix(); 71 | } 72 | 73 | void Line::ProjectionOnAxis(const CGUL::Vector2& axis, CGUL::Float32* min, CGUL::Float32* max) const 74 | { 75 | CGUL::Matrix world; 76 | 77 | CGUL::Vector2 points[] = 78 | { 79 | start, end 80 | }; 81 | 82 | return Collision::ProjectionOnAxis(points, 2, axis, min, max); 83 | } 84 | 85 | bool Line::CollidingCircle(const Circle& other) const 86 | { 87 | return CheckCircleAndLine(other, *this); 88 | } 89 | 90 | bool Line::CollidingAxisAlignedBox(const AxisAlignedBox& other) const 91 | { 92 | return CheckAxisAlignedBoxAndLine(other, *this); 93 | } 94 | 95 | bool Line::CollidingOrientedBox(const OrientedBox& other) const 96 | { 97 | return CheckOrientedBoxAndLine(other, *this); 98 | } 99 | 100 | bool Line::CollidingLine(const Line& other) const 101 | { 102 | return CheckLineAndLine(*this, other); 103 | } 104 | 105 | bool Line::CollidingTriangle(const Triangle& other) const 106 | { 107 | return CheckLineAndTriangle(*this, other); 108 | } 109 | 110 | bool Line::CollidingPoint(const Point& other) const 111 | { 112 | return CheckLineAndPoint(*this, other); 113 | } 114 | 115 | void Line::Draw() const 116 | { 117 | render->Line(start, end, color); 118 | } 119 | -------------------------------------------------------------------------------- /src/Line.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "Collision.hpp" 4 | #include "Render.hpp" 5 | 6 | extern Render* render; 7 | 8 | struct Line : public Collision 9 | { 10 | CGUL::Vector2 start; 11 | CGUL::Vector2 end; 12 | 13 | Line(); 14 | Line(const CGUL::Vector2& start, const CGUL::Vector2& end); 15 | 16 | void SetPosition(const CGUL::Vector2& position); 17 | void SetStart(const CGUL::Vector2& start); 18 | void SetEnd(const CGUL::Vector2& end); 19 | 20 | CGUL::Vector2 GetPosition() const; 21 | CGUL::Vector2 GetStart() const; 22 | CGUL::Vector2 GetEnd() const; 23 | 24 | CGUL::Vector2 GetClosestPoint(const CGUL::Vector2& position) const; 25 | 26 | void ProjectionOnAxis(const CGUL::Vector2& axis, CGUL::Float32* min, CGUL::Float32* max) const; 27 | 28 | CGUL::Matrix GetWorldMatrix() const; 29 | 30 | bool CollidingCircle(const Circle& other) const; 31 | bool CollidingAxisAlignedBox(const AxisAlignedBox& other) const; 32 | bool CollidingOrientedBox(const OrientedBox& other) const; 33 | bool CollidingLine(const Line& other) const; 34 | bool CollidingTriangle(const Triangle& other) const; 35 | bool CollidingPoint(const Point& other) const; 36 | 37 | void Draw() const; 38 | }; 39 | -------------------------------------------------------------------------------- /src/OrientedBox.cpp: -------------------------------------------------------------------------------- 1 | #include "OrientedBox.hpp" 2 | 3 | #include "Circle.hpp" 4 | #include "AxisAlignedBox.hpp" 5 | #include "Line.hpp" 6 | #include "Point.hpp" 7 | 8 | OrientedBox::OrientedBox() : 9 | Collision(Collision::ORIENTED_BOX) 10 | { 11 | } 12 | 13 | OrientedBox::OrientedBox(const CGUL::Vector2& position, const CGUL::Vector2& halfExtents, CGUL::Float32 orientation) : 14 | Collision(Collision::ORIENTED_BOX), 15 | position(position), 16 | halfExtents(halfExtents), 17 | orientation(orientation) 18 | { 19 | } 20 | 21 | void OrientedBox::SetPosition(const CGUL::Vector2& position) 22 | { 23 | this->position = position; 24 | } 25 | 26 | void OrientedBox::SetHalfExtents(const CGUL::Vector2& halfExtents) 27 | { 28 | this->halfExtents = halfExtents; 29 | } 30 | 31 | void OrientedBox::SetOrientation(CGUL::Float32 orientation) 32 | { 33 | this->orientation = orientation; 34 | } 35 | 36 | CGUL::Vector2 OrientedBox::GetPosition() const 37 | { 38 | return position; 39 | } 40 | 41 | CGUL::Vector2 OrientedBox::GetHalfExtents() const 42 | { 43 | return halfExtents; 44 | } 45 | 46 | CGUL::Float32 OrientedBox::GetOrientation() const 47 | { 48 | return orientation; 49 | } 50 | 51 | CGUL::Vector2 OrientedBox::GetClosestPoint(const CGUL::Vector2& position) const 52 | { 53 | using namespace CGUL; 54 | 55 | Vector2 axes[] = 56 | { 57 | Vector2(Math::Cos(orientation), Math::Sin(orientation)), 58 | Vector2(Math::Sin(orientation), -Math::Cos(orientation)) 59 | }; 60 | 61 | Vector2 difference = position - this->position; 62 | Vector2 converted(Vector2::DotProduct(difference, axes[0]), Vector2::DotProduct(difference, axes[1])); 63 | 64 | Vector2 before = converted; 65 | converted.x = Math::Clamp(converted.x, -halfExtents.x, halfExtents.x); 66 | converted.y = Math::Clamp(converted.y, -halfExtents.y, halfExtents.y); 67 | if (before == converted) 68 | { 69 | return position; 70 | } 71 | 72 | Vector2 result = this->position; 73 | result += axes[0] * converted.x; 74 | result += axes[1] * converted.y; 75 | 76 | return result; 77 | } 78 | 79 | CGUL::Matrix OrientedBox::GetWorldMatrix() const 80 | { 81 | CGUL::Matrix matrix; 82 | matrix = matrix * CGUL::Matrix::MakeRotation(orientation); 83 | //matrix = matrix * CGUL::Matrix::MakeScaling(halfExtents); 84 | matrix = matrix * CGUL::Matrix::MakeTranslation(position); 85 | return matrix; 86 | } 87 | 88 | void OrientedBox::ProjectionOnAxis(const CGUL::Vector2& axis, CGUL::Float32* min, CGUL::Float32* max) const 89 | { 90 | CGUL::Matrix world; 91 | world = world * CGUL::Matrix::MakeRotation(orientation); 92 | world = world * CGUL::Matrix::MakeTranslation(position); 93 | 94 | CGUL::Vector2 points[] = 95 | { 96 | CGUL::Vector2( halfExtents.x, halfExtents.y) * world, 97 | CGUL::Vector2(-halfExtents.x, halfExtents.y) * world, 98 | CGUL::Vector2( halfExtents.x, -halfExtents.y) * world, 99 | CGUL::Vector2(-halfExtents.x, -halfExtents.y) * world 100 | }; 101 | 102 | return Collision::ProjectionOnAxis(points, 4, axis, min, max); 103 | } 104 | 105 | bool OrientedBox::CollidingCircle(const Circle& other) const 106 | { 107 | return CheckCircleAndOrientedBox(other, *this); 108 | } 109 | 110 | bool OrientedBox::CollidingAxisAlignedBox(const AxisAlignedBox& other) const 111 | { 112 | return CheckAxisAlignedBoxAndOrientedBox(other, *this); 113 | } 114 | 115 | bool OrientedBox::CollidingOrientedBox(const OrientedBox& other) const 116 | { 117 | return CheckOrientedBoxAndOrientedBox(*this, other); 118 | } 119 | 120 | bool OrientedBox::CollidingLine(const Line& other) const 121 | { 122 | return CheckOrientedBoxAndLine(*this, other); 123 | } 124 | 125 | bool OrientedBox::CollidingTriangle(const Triangle& other) const 126 | { 127 | return CheckOrientedBoxAndTriangle(*this, other); 128 | } 129 | 130 | bool OrientedBox::CollidingPoint(const Point& other) const 131 | { 132 | return CheckOrientedBoxAndPoint(*this, other); 133 | } 134 | 135 | void OrientedBox::Draw() const 136 | { 137 | render->Box(position, halfExtents * 2, orientation, color); 138 | } 139 | -------------------------------------------------------------------------------- /src/OrientedBox.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "Collision.hpp" 4 | #include "Render.hpp" 5 | 6 | extern Render* render; 7 | 8 | struct OrientedBox : public Collision 9 | { 10 | CGUL::Vector2 position; 11 | CGUL::Vector2 halfExtents; 12 | CGUL::Float32 orientation; 13 | 14 | OrientedBox(); 15 | OrientedBox(const CGUL::Vector2& position, const CGUL::Vector2& halfExtents, CGUL::Float32 orientation); 16 | 17 | void SetPosition(const CGUL::Vector2& position); 18 | void SetHalfExtents(const CGUL::Vector2& halfExtents); 19 | void SetOrientation(CGUL::Float32 orientation); 20 | 21 | CGUL::Vector2 GetPosition() const; 22 | CGUL::Vector2 GetHalfExtents() const; 23 | CGUL::Float32 GetOrientation() const; 24 | 25 | CGUL::Vector2 GetClosestPoint(const CGUL::Vector2& position) const; 26 | 27 | CGUL::Matrix GetWorldMatrix() const; 28 | 29 | void ProjectionOnAxis(const CGUL::Vector2& axis, CGUL::Float32* min, CGUL::Float32* max) const; 30 | 31 | bool CollidingCircle(const Circle& other) const; 32 | bool CollidingAxisAlignedBox(const AxisAlignedBox& other) const; 33 | bool CollidingOrientedBox(const OrientedBox& other) const; 34 | bool CollidingLine(const Line& other) const; 35 | bool CollidingTriangle(const Triangle& other) const; 36 | bool CollidingPoint(const Point& other) const; 37 | 38 | void Draw() const; 39 | }; 40 | -------------------------------------------------------------------------------- /src/Point.cpp: -------------------------------------------------------------------------------- 1 | #include "Point.hpp" 2 | 3 | #include "Circle.hpp" 4 | #include "AxisAlignedBox.hpp" 5 | #include "OrientedBox.hpp" 6 | 7 | Point::Point() : 8 | Collision(Collision::POINT) 9 | { 10 | } 11 | 12 | Point::Point(const CGUL::Vector2& position) : 13 | Collision(Collision::POINT), 14 | position(position) 15 | { 16 | } 17 | 18 | void Point::SetPosition(const CGUL::Vector2& position) 19 | { 20 | this->position = position; 21 | } 22 | 23 | CGUL::Vector2 Point::GetPosition() const 24 | { 25 | return this->position; 26 | } 27 | 28 | CGUL::Vector2 Point::GetClosestPoint(const CGUL::Vector2& position) const 29 | { 30 | return position; 31 | } 32 | 33 | CGUL::Matrix Point::GetWorldMatrix() const 34 | { 35 | return CGUL::Matrix(); 36 | } 37 | 38 | void Point::ProjectionOnAxis(const CGUL::Vector2& axis, CGUL::Float32* min, CGUL::Float32* max) const 39 | { 40 | *min = *max = CGUL::Vector2::DotProduct(axis, this->position); 41 | } 42 | 43 | bool Point::CollidingCircle(const Circle& other) const 44 | { 45 | return CheckCircleAndPoint(other, *this); 46 | } 47 | 48 | bool Point::CollidingAxisAlignedBox(const AxisAlignedBox& other) const 49 | { 50 | return CheckAxisAlignedBoxAndPoint(other, *this); 51 | } 52 | 53 | bool Point::CollidingOrientedBox(const OrientedBox& other) const 54 | { 55 | return CheckOrientedBoxAndPoint(other, *this); 56 | } 57 | 58 | bool Point::CollidingLine(const Line& other) const 59 | { 60 | return CheckLineAndPoint(other, *this); 61 | } 62 | 63 | bool Point::CollidingTriangle(const Triangle& other) const 64 | { 65 | return CheckTriangleAndPoint(other, *this); 66 | } 67 | 68 | bool Point::CollidingPoint(const Point& other) const 69 | { 70 | return CheckPointAndPoint(*this, other); 71 | } 72 | 73 | void Point::Draw() const 74 | { 75 | } 76 | -------------------------------------------------------------------------------- /src/Point.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "Collision.hpp" 4 | #include "Render.hpp" 5 | 6 | extern Render* render; 7 | 8 | struct Point : public Collision 9 | { 10 | CGUL::Vector2 position; 11 | 12 | Point(); 13 | Point(const CGUL::Vector2& position); 14 | 15 | void SetPosition(const CGUL::Vector2& position); 16 | 17 | CGUL::Vector2 GetPosition() const; 18 | 19 | CGUL::Vector2 GetClosestPoint(const CGUL::Vector2& position) const; 20 | 21 | void ProjectionOnAxis(const CGUL::Vector2& axis, CGUL::Float32* min, CGUL::Float32* max) const; 22 | 23 | CGUL::Matrix GetWorldMatrix() const; 24 | 25 | bool CollidingCircle(const Circle& other) const; 26 | bool CollidingAxisAlignedBox(const AxisAlignedBox& other) const; 27 | bool CollidingOrientedBox(const OrientedBox& other) const; 28 | bool CollidingLine(const Line& other) const; 29 | bool CollidingTriangle(const Triangle& other) const; 30 | bool CollidingPoint(const Point& other) const; 31 | 32 | void Draw() const; 33 | }; 34 | -------------------------------------------------------------------------------- /src/Render.cpp: -------------------------------------------------------------------------------- 1 | #include "Render.hpp" 2 | #include "State.hpp" 3 | #include "StateMachine.hpp" 4 | #include 5 | 6 | void Render::MakeShader() 7 | { 8 | using namespace CGUL; 9 | 10 | // Create the shaders 11 | UInt vertexShader, fragmentShader; 12 | vertexShader = GL::CreateShader(GL_VERTEX_SHADER); 13 | fragmentShader = GL::CreateShader(GL_FRAGMENT_SHADER); 14 | 15 | // Set the shader sources 16 | GL::ShaderSource(vertexShader, 17 | "#version 120\n" 18 | "uniform mat4 orthoMatrix;\n" 19 | "uniform mat4 modelMatrix;\n" 20 | "uniform int shaderType;\n" // 0 = geometry, 1 = repositioned geometry, 2 = texture 21 | "uniform vec2 positions[20];\n" 22 | "attribute vec2 vertPosition;\n" 23 | "attribute vec2 vertTexCoord;\n" 24 | " varying vec2 fragTexCoord;\n" 25 | "void main(void)\n" 26 | "{\n" 27 | " if (shaderType == 2)\n" 28 | " {\n" 29 | " gl_Position = (orthoMatrix * modelMatrix) * vec4(vertPosition, 0.0, 1.0);\n" 30 | " fragTexCoord = vertTexCoord;\n" 31 | " }\n" 32 | " else if (shaderType == 1)\n" 33 | " {\n" 34 | " gl_Position = (orthoMatrix * modelMatrix) * vec4(positions[int(vertPosition.x)], 0.0, 1.0);\n" 35 | " }\n" 36 | " else\n" 37 | " {\n" 38 | " gl_Position = (orthoMatrix * modelMatrix) * vec4(vertPosition, 0.0, 1.0);\n" 39 | " }\n" 40 | "}\n"); 41 | GL::ShaderSource(fragmentShader, 42 | "#version 120\n" 43 | "uniform sampler2D texture;\n" 44 | "uniform vec4 color;\n" 45 | "uniform int shaderType;\n" 46 | "varying vec2 fragTexCoord;\n" 47 | "void main(void)\n" 48 | "{\n" 49 | " if (shaderType == 2)\n" 50 | " {\n" 51 | " gl_FragColor = texture2D(texture, fragTexCoord);\n" 52 | " }\n" 53 | " else\n" 54 | " {\n" 55 | " gl_FragColor = color;\n" 56 | " }\n" 57 | "}\n"); 58 | 59 | // Compile the shaders 60 | GL::CompileShader(vertexShader); 61 | GL::CompileShader(fragmentShader); 62 | 63 | // Check if shaders compiled 64 | SInt status; 65 | GL::GetShaderiv(vertexShader, GL_COMPILE_STATUS, &status); 66 | if (status != GL_TRUE) 67 | { 68 | String log; 69 | GL::GetShaderInfoLog(vertexShader, &log); 70 | throw FatalException(U8("Failed to compile shader:\n") + log); 71 | } 72 | GL::GetShaderiv(fragmentShader, GL_COMPILE_STATUS, &status); 73 | if (status != GL_TRUE) 74 | { 75 | String log; 76 | GL::GetShaderInfoLog(fragmentShader, &log); 77 | throw FatalException(U8("Failed to compile shader:\n") + log); 78 | } 79 | 80 | // Create the program 81 | shaderProgram = GL::CreateProgram(); 82 | 83 | // Setup the attributes 84 | GL::BindAttribLocation(shaderProgram, GL::POSITION1, "vertPosition"); 85 | GL::BindAttribLocation(shaderProgram, GL::TEXCOORD1, "vertTexCoord"); 86 | 87 | // Link the program 88 | GL::AttachShader(shaderProgram, vertexShader); 89 | GL::AttachShader(shaderProgram, fragmentShader); 90 | GL::LinkProgram(shaderProgram); 91 | GL::GetProgramiv(shaderProgram, GL_LINK_STATUS, &status); 92 | if (status != GL_TRUE) 93 | { 94 | String log; 95 | GL::GetProgramInfoLog(shaderProgram, &log); 96 | throw FatalException(U8("Failed to link program:\n") + log); 97 | } 98 | GL::ValidateProgram(shaderProgram); 99 | GL::GetProgramiv(shaderProgram, GL_VALIDATE_STATUS, &status); 100 | if (status != GL_TRUE) 101 | { 102 | String log; 103 | GL::GetProgramInfoLog(shaderProgram, &log); 104 | throw FatalException(U8("Failed to validate program:\n") + log); 105 | } 106 | 107 | } 108 | 109 | void Render::MakeSprite() 110 | { 111 | using namespace CGUL; 112 | 113 | // Setup the buffer data 114 | Vector2 spritePositions[] = { Vector2(0.0f, 0.0f), Vector2(0.0f, 1.0f), Vector2(1.0f, 1.0f), Vector2(1.0f, 0.0f) }; 115 | Vector2 spriteTexCoords[] = { Vector2(0.0f, 1.0f), Vector2(0.0f, 0.0f), Vector2(1.0f, 0.0f), Vector2(1.0f, 1.0f) }; 116 | 117 | // Create the vertex array object 118 | GL::GenVertexArrays(1, &vertexArraySprite); 119 | GL::BindVertexArray(vertexArraySprite); 120 | 121 | // Setup the position buffer and attach it to the vertex array 122 | UInt buffer1; 123 | GL::GenBuffers(1, &buffer1); 124 | GL::BindBuffer(GL_ARRAY_BUFFER, buffer1); 125 | GL::BufferData(GL_ARRAY_BUFFER, 4 * sizeof(Vector2), spritePositions, GL_STATIC_DRAW); 126 | GL::VertexAttribPointer(GL::POSITION1, 2, GL_FLOAT, false, 0, 0); 127 | GL::EnableVertexAttribArray(GL::POSITION1); 128 | 129 | // Setup the texcoord buffer and attach it to the vertex array 130 | UInt buffer2; 131 | GL::GenBuffers(1, &buffer2); 132 | GL::BindBuffer(GL_ARRAY_BUFFER, buffer2); 133 | GL::BufferData(GL_ARRAY_BUFFER, 4 * sizeof(Vector2), spriteTexCoords, GL_STATIC_DRAW); 134 | GL::VertexAttribPointer(GL::TEXCOORD1, 2, GL_FLOAT, false, 0, 0); 135 | GL::EnableVertexAttribArray(GL::TEXCOORD1); 136 | 137 | // All done 138 | GL::BindVertexArray(0); 139 | } 140 | 141 | void Render::MakeBox() 142 | { 143 | using namespace CGUL; 144 | 145 | // Setup the buffer data 146 | Vector2 boxPositions[] = { Vector2(-0.5f, -0.5f), Vector2(-0.5f, 0.5f), Vector2(0.5f, 0.5f), Vector2(0.5f, -0.5f) }; 147 | 148 | // Create the vertex array object 149 | GL::GenVertexArrays(1, &vertexArrayBox); 150 | GL::BindVertexArray(vertexArrayBox); 151 | 152 | // Setup the position buffer and attach it to the vertex array 153 | UInt buffer1; 154 | GL::GenBuffers(1, &buffer1); 155 | GL::BindBuffer(GL_ARRAY_BUFFER, buffer1); 156 | GL::BufferData(GL_ARRAY_BUFFER, 4 * sizeof(Vector2), boxPositions, GL_STATIC_DRAW); 157 | GL::VertexAttribPointer(GL::POSITION1, 2, GL_FLOAT, false, 0, 0); 158 | GL::EnableVertexAttribArray(GL::POSITION1); 159 | 160 | // All done 161 | GL::BindVertexArray(0); 162 | } 163 | 164 | void Render::MakeCircle() 165 | { 166 | using namespace CGUL; 167 | 168 | // Calculate circle coordinates 169 | Vector2 circlePositions[circlePrecision + 2]; 170 | circlePositions[0] = Vector2(0, 0); 171 | 172 | Float32 angle = 0; 173 | Float32 step = Math::Tau< Float32 >() / circlePrecision; 174 | for (UInt32 i = 1; i < circlePrecision + 2; i++) 175 | { 176 | circlePositions[i] = Vector2(Math::Cos(angle), Math::Sin(angle)); 177 | angle += step; 178 | } 179 | 180 | // Create the vertex array object 181 | GL::GenVertexArrays(1, &vertexArrayCircle); 182 | GL::BindVertexArray(vertexArrayCircle); 183 | 184 | // Setup the position buffer and attach it to the vertex array 185 | UInt buffer1; 186 | GL::GenBuffers(1, &buffer1); 187 | GL::BindBuffer(GL_ARRAY_BUFFER, buffer1); 188 | GL::BufferData(GL_ARRAY_BUFFER, (circlePrecision + 2) * sizeof(Vector2), circlePositions, GL_STATIC_DRAW); 189 | GL::VertexAttribPointer(GL::POSITION1, 2, GL_FLOAT, false, 0, 0); 190 | GL::EnableVertexAttribArray(GL::POSITION1); 191 | 192 | // All done 193 | GL::BindVertexArray(0); 194 | } 195 | 196 | void Render::MakeLine() 197 | { 198 | using namespace CGUL; 199 | 200 | // Setup the buffer data 201 | Vector2 linePositions[] = { Vector2(0, 0), Vector2(1, 1) }; 202 | 203 | // Create the vertex array object 204 | GL::GenVertexArrays(1, &vertexArrayLine); 205 | GL::BindVertexArray(vertexArrayLine); 206 | 207 | // Setup the position buffer and attach it to the vertex array 208 | UInt buffer1; 209 | GL::GenBuffers(1, &buffer1); 210 | GL::BindBuffer(GL_ARRAY_BUFFER, buffer1); 211 | GL::BufferData(GL_ARRAY_BUFFER, 2 * sizeof(Vector2), linePositions, GL_STATIC_DRAW); 212 | GL::VertexAttribPointer(GL::POSITION1, 2, GL_FLOAT, false, 0, 0); 213 | GL::EnableVertexAttribArray(GL::POSITION1); 214 | 215 | // All done 216 | GL::BindVertexArray(0); 217 | } 218 | 219 | void Render::MakeTriangle() 220 | { 221 | using namespace CGUL; 222 | 223 | // Setup the buffer data 224 | Vector2 trianglePositions[] = { Vector2(0, 0), Vector2(1, 1), Vector2(2, 2) }; 225 | //Vector2 trianglePositions[] = { Vector2(-20, 0), Vector2(0, 40), Vector2(20, 0) }; 226 | 227 | // Create the vertex array object 228 | GL::GenVertexArrays(1, &vertexArrayTriangle); 229 | GL::BindVertexArray(vertexArrayTriangle); 230 | 231 | // Setup the position buffer and attach it to the vertex array 232 | UInt buffer1; 233 | GL::GenBuffers(1, &buffer1); 234 | GL::BindBuffer(GL_ARRAY_BUFFER, buffer1); 235 | GL::BufferData(GL_ARRAY_BUFFER, 3 * sizeof(Vector2), trianglePositions, GL_STATIC_DRAW); 236 | GL::VertexAttribPointer(GL::POSITION1, 2, GL_FLOAT, false, 0, 0); 237 | GL::EnableVertexAttribArray(GL::POSITION1); 238 | 239 | // All done 240 | GL::BindVertexArray(0); 241 | } 242 | 243 | Render::Render(CGUL::Window* window) : 244 | window(window), 245 | screenSpace(0, 0, 800, 600) 246 | { 247 | context.Create(window); 248 | context.ClearColor(CGUL::Colors::black); 249 | 250 | CGUL::GL::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 251 | CGUL::GL::Enable(GL_BLEND); 252 | CGUL::GL::Enable(GL_ALPHA_TEST); 253 | CGUL::GL::Enable(GL_TEXTURE_2D); 254 | 255 | MakeShader(); 256 | MakeSprite(); 257 | MakeBox(); 258 | MakeCircle(); 259 | MakeLine(); 260 | MakeTriangle(); 261 | } 262 | 263 | void Render::Update(State* state, StateMachine* stateMachine, CGUL::Float32 deltaTime) 264 | { 265 | using namespace CGUL; 266 | 267 | context.Viewport(0, 0, window->GetWidth(), window->GetHeight()); 268 | context.Clear(GL_COLOR_BUFFER_BIT); 269 | 270 | GL::UseProgram(shaderProgram); 271 | GL::UniformMatrix4fv(GL::GetUniformLocation(shaderProgram, "orthoMatrix"), 1, false, Matrix::MakeOrtho2D(screenSpace.x, screenSpace.z, screenSpace.y, screenSpace.w).GetData()); 272 | 273 | if (state != NULL) 274 | { 275 | state->Update(deltaTime); 276 | } 277 | stateMachine->Draw(deltaTime); 278 | GL::UseProgram(0); 279 | context.SwapBuffers(); 280 | } 281 | 282 | void Render::Reset() 283 | { 284 | context.ClearColor(CGUL::Colors::black); 285 | } 286 | 287 | void Render::SetClearColor(const CGUL::Color& color) 288 | { 289 | context.ClearColor(color); 290 | } 291 | 292 | void Render::SetScreenSpace(const CGUL::Vector4& screenSpace) 293 | { 294 | this->screenSpace = screenSpace; 295 | } 296 | 297 | CGUL::UInt32 Render::LoadSprite(const CGUL::String& filename, CGUL::UCoord32* size) 298 | { 299 | using namespace CGUL; 300 | 301 | Image image; 302 | image.Load(filename); 303 | 304 | if (size != NULL) 305 | { 306 | *size = UCoord32(image.GetWidth(), image.GetHeight()); 307 | } 308 | 309 | UInt texture; 310 | GL::GenTextures(1, &texture); 311 | GL::BindTexture(GL_TEXTURE_2D, texture); 312 | GL::TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 313 | GL::TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 314 | GL::TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 315 | GL::TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 316 | GL::TexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); 317 | GL::PixelStorei(GL_UNPACK_ALIGNMENT, 1); 318 | GL::TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.GetWidth(), image.GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, image.GetData()); 319 | GL::BindTexture(GL_TEXTURE_2D, 0); 320 | 321 | return texture; 322 | } 323 | 324 | void Render::FreeSprite(CGUL::UInt32 texture) 325 | { 326 | // do stuff? 327 | } 328 | 329 | void Render::Sprite(CGUL::UInt32 texture, const CGUL::Vector2& position, const CGUL::Vector2& size) 330 | { 331 | using namespace CGUL; 332 | 333 | if (doNotDraw) 334 | { 335 | return; 336 | } 337 | 338 | Matrix model; 339 | model = model * Matrix::MakeScaling(size); 340 | model = model * Matrix::MakeTranslation(position); 341 | GL::UniformMatrix4fv(GL::GetUniformLocation(shaderProgram, "modelMatrix"), 1, false, model.GetData()); 342 | GL::Uniform1i(GL::GetUniformLocation(shaderProgram, "shaderType"), 2); 343 | GL::Uniform1i(GL::GetUniformLocation(shaderProgram, "texture"), 0); 344 | GL::ActiveTexture(GL_TEXTURE0); 345 | GL::BindTexture(GL_TEXTURE_2D, texture); 346 | GL::BindVertexArray(vertexArraySprite); 347 | GL::DrawArrays(GL_QUADS, 0, 4); 348 | GL::Uniform1i(GL::GetUniformLocation(shaderProgram, "shaderType"), 0); 349 | GL::BindVertexArray(0); 350 | } 351 | 352 | void Render::Box(const CGUL::Vector2& position, const CGUL::Vector2& size, const CGUL::Color& color) 353 | { 354 | using namespace CGUL; 355 | 356 | if (doNotDraw) 357 | { 358 | return; 359 | } 360 | 361 | Matrix model; 362 | model = model * Matrix::MakeScaling(size); 363 | model = model * Matrix::MakeTranslation(position); 364 | GL::UniformMatrix4fv(GL::GetUniformLocation(shaderProgram, "modelMatrix"), 1, false, model.GetData()); 365 | GL::Uniform4f(GL::GetUniformLocation(shaderProgram, "color"), color); 366 | GL::BindVertexArray(vertexArrayBox); 367 | GL::DrawArrays(GL_QUADS, 0, 4); 368 | GL::BindVertexArray(0); 369 | } 370 | 371 | void Render::Box(const CGUL::Vector2& position, const CGUL::Vector2& size, CGUL::Float32 orientation, const CGUL::Color& color) 372 | { 373 | using namespace CGUL; 374 | 375 | if (doNotDraw) 376 | { 377 | return; 378 | } 379 | 380 | Matrix model; 381 | model = model * Matrix::MakeScaling(size); 382 | model = model * Matrix::MakeRotation(orientation); 383 | model = model * Matrix::MakeTranslation(position); 384 | GL::UniformMatrix4fv(GL::GetUniformLocation(shaderProgram, "modelMatrix"), 1, false, model.GetData()); 385 | GL::Uniform4f(GL::GetUniformLocation(shaderProgram, "color"), color); 386 | GL::BindVertexArray(vertexArrayBox); 387 | GL::DrawArrays(GL_QUADS, 0, 4); 388 | GL::BindVertexArray(0); 389 | } 390 | 391 | void Render::Circle(const CGUL::Vector2& position, CGUL::Float32 radius, const CGUL::Color& color) 392 | { 393 | using namespace CGUL; 394 | 395 | if (doNotDraw) 396 | { 397 | return; 398 | } 399 | 400 | Matrix model; 401 | model = model * Matrix::MakeScaling(Vector2(radius, radius)); 402 | model = model * Matrix::MakeTranslation(position); 403 | GL::UniformMatrix4fv(GL::GetUniformLocation(shaderProgram, "modelMatrix"), 1, false, model.GetData()); 404 | GL::Uniform4f(GL::GetUniformLocation(shaderProgram, "color"), color); 405 | GL::BindVertexArray(vertexArrayCircle); 406 | GL::DrawArrays(GL_TRIANGLE_FAN, 0, circlePrecision + 2); 407 | GL::BindVertexArray(0); 408 | } 409 | 410 | void Render::Circle(const CGUL::Vector2& position, CGUL::Float32 radius, CGUL::Float32 orientation, const CGUL::Color& color) 411 | { 412 | using namespace CGUL; 413 | 414 | if (doNotDraw) 415 | { 416 | return; 417 | } 418 | 419 | Matrix model; 420 | model = model * Matrix::MakeScaling(Vector2(radius, radius)); 421 | model = model * Matrix::MakeRotation(orientation); 422 | model = model * Matrix::MakeTranslation(position); 423 | GL::UniformMatrix4fv(GL::GetUniformLocation(shaderProgram, "modelMatrix"), 1, false, model.GetData()); 424 | GL::Uniform4f(GL::GetUniformLocation(shaderProgram, "color"), color); 425 | GL::BindVertexArray(vertexArrayCircle); 426 | GL::DrawArrays(GL_TRIANGLE_FAN, 0, circlePrecision + 2); 427 | GL::BindVertexArray(0); 428 | } 429 | 430 | void Render::Line(const CGUL::Vector2& start, const CGUL::Vector2& end, const CGUL::Color& color) 431 | { 432 | using namespace CGUL; 433 | 434 | if (doNotDraw) 435 | { 436 | return; 437 | } 438 | 439 | Matrix model = Matrix::Identity(); 440 | GL::UniformMatrix4fv(GL::GetUniformLocation(shaderProgram, "modelMatrix"), 1, false, model.GetData()); 441 | GL::Uniform4f(GL::GetUniformLocation(shaderProgram, "color"), color); 442 | GL::Uniform1i(GL::GetUniformLocation(shaderProgram, "shaderType"), 1); 443 | CGUL::Vector2 positions[2] = { start, end }; 444 | GL::Uniform2fv(GL::GetUniformLocation(shaderProgram, "positions"), 2, positions); 445 | GL::BindVertexArray(vertexArrayLine); 446 | GL::DrawArrays(GL_LINES, 0, 2); 447 | GL::BindVertexArray(0); 448 | GL::Uniform1i(GL::GetUniformLocation(shaderProgram, "shaderType"), 0); 449 | } 450 | 451 | void Render::Triangle(const CGUL::Vector2& position, const CGUL::Vector2& pointA, const CGUL::Vector2& pointB, const CGUL::Vector2& pointC, const CGUL::Color& color) 452 | { 453 | using namespace CGUL; 454 | 455 | if (doNotDraw) 456 | { 457 | return; 458 | } 459 | 460 | Matrix model; 461 | model = model * Matrix::MakeTranslation(position); 462 | GL::UniformMatrix4fv(GL::GetUniformLocation(shaderProgram, "modelMatrix"), 1, false, model.GetData()); 463 | GL::Uniform4f(GL::GetUniformLocation(shaderProgram, "color"), color); 464 | GL::Uniform1i(GL::GetUniformLocation(shaderProgram, "shaderType"), 1); 465 | CGUL::Vector2 positions[3] = { pointA, pointB, pointC }; 466 | GL::Uniform2fv(GL::GetUniformLocation(shaderProgram, "positions"), 3, positions); 467 | GL::BindVertexArray(vertexArrayTriangle); 468 | GL::DrawArrays(GL_TRIANGLES, 0, 3); 469 | GL::BindVertexArray(0); 470 | GL::Uniform1i(GL::GetUniformLocation(shaderProgram, "shaderType"), 0); 471 | } 472 | 473 | void Render::SetDoNotDraw(CGUL::Boolean draw) 474 | { 475 | doNotDraw = draw; 476 | } 477 | -------------------------------------------------------------------------------- /src/Render.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | class State; 5 | class StateMachine; 6 | 7 | class Render 8 | { 9 | static const CGUL::UInt32 circlePrecision = 16; 10 | 11 | CGUL::UInt32 shaderProgram; 12 | CGUL::UInt32 vertexArraySprite; 13 | CGUL::UInt32 vertexArrayBox; 14 | CGUL::UInt32 vertexArrayCircle; 15 | CGUL::UInt32 vertexArrayLine; 16 | CGUL::UInt32 vertexArrayTriangle; 17 | 18 | CGUL::Window* window; 19 | CGUL::OpenGL::Context context; 20 | 21 | CGUL::Vector4 screenSpace; 22 | 23 | bool doNotDraw; 24 | 25 | void MakeShader(); 26 | void MakeSprite(); 27 | void MakeBox(); 28 | void MakeCircle(); 29 | void MakeLine(); 30 | void MakeTriangle(); 31 | public: 32 | Render(CGUL::Window* window); 33 | 34 | void Update(State* state, StateMachine* stateMachine, CGUL::Float32 deltaTime); 35 | void Reset(); 36 | 37 | void SetClearColor(const CGUL::Color& color); 38 | void SetScreenSpace(const CGUL::Vector4& screenSpace); 39 | 40 | CGUL::UInt32 LoadSprite(const CGUL::String& filename, CGUL::UCoord32* size); 41 | void FreeSprite(CGUL::UInt32 texture); 42 | 43 | void Sprite(CGUL::UInt32 texture, const CGUL::Vector2& position, const CGUL::Vector2& size); 44 | void Box(const CGUL::Vector2& position, const CGUL::Vector2& size, const CGUL::Color& color); 45 | void Box(const CGUL::Vector2& position, const CGUL::Vector2& size, CGUL::Float32 orientation, const CGUL::Color& color); 46 | void Circle(const CGUL::Vector2& position, CGUL::Float32 radius, const CGUL::Color& color); 47 | void Circle(const CGUL::Vector2& position, CGUL::Float32 radius, CGUL::Float32 orientation, const CGUL::Color& color); 48 | void Line(const CGUL::Vector2& start, const CGUL::Vector2& end, const CGUL::Color& color); 49 | void Triangle(const CGUL::Vector2& position, const CGUL::Vector2& pointA, const CGUL::Vector2& pointB, const CGUL::Vector2& pointC, const CGUL::Color& color); 50 | 51 | void SetDoNotDraw(CGUL::Boolean draw); 52 | }; 53 | -------------------------------------------------------------------------------- /src/State.cpp: -------------------------------------------------------------------------------- 1 | #include "State.hpp" 2 | 3 | State::State() 4 | { 5 | } 6 | 7 | State::~State() 8 | { 9 | } 10 | 11 | void State::Setup(StateMachine* stateMachine, Render* render, CGUL::Window* window) 12 | { 13 | this->stateMachine = stateMachine; 14 | this->render = render; 15 | this->window = window; 16 | } 17 | -------------------------------------------------------------------------------- /src/State.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "Render.hpp" 4 | #include "StateMachine.hpp" 5 | 6 | class State 7 | { 8 | protected: 9 | StateMachine* stateMachine; 10 | Render* render; 11 | 12 | CGUL::Window* window; 13 | public: 14 | State(); 15 | ~State(); 16 | 17 | void Setup(StateMachine* stateMachine, Render* render, CGUL::Window* window); 18 | 19 | virtual void Enter() = 0; 20 | virtual void Update(CGUL::Float32 deltaTime) = 0; 21 | virtual void Exit() = 0; 22 | }; 23 | -------------------------------------------------------------------------------- /src/StateBoxes.cpp: -------------------------------------------------------------------------------- 1 | #include "StateBoxes.hpp" 2 | 3 | StateBoxes::StateBoxes() : 4 | box1(CGUL::Vector2(0, 0), CGUL::Vector2(75, 75), 0), 5 | box2(CGUL::Vector2(400, 300), CGUL::Vector2(75, 100), 0), 6 | box3(CGUL::Vector2(600, 150), CGUL::Vector2(50, 40)) 7 | { 8 | box1.color = CGUL::Colors::cornflowerBlue; 9 | box2.color = CGUL::Colors::cornflowerBlue; 10 | line.color = CGUL::Colors::white; 11 | circle.color = CGUL::Colors::cornflowerBlue; 12 | } 13 | 14 | StateBoxes::~StateBoxes() 15 | { 16 | } 17 | 18 | void StateBoxes::Enter() 19 | { 20 | render->SetClearColor(CGUL::Colors::darkBlue); 21 | stateMachine->SetTitle(U8("Boxes")); 22 | } 23 | 24 | void StateBoxes::Update(CGUL::Float32 deltaTime) 25 | { 26 | //render->Box(CGUL::Vector2(100, 100), CGUL::Vector2(300, 300), CGUL::Colors::yellow); 27 | //render->Circle(CGUL::Vector2(450, 450), 50, CGUL::Colors::yellow); 28 | 29 | CGUL::SCoord32 mousePosition = stateMachine->GetMousePosition(); 30 | if (stateMachine->IsKeyDown('E')) 31 | { 32 | box1.position = mousePosition; 33 | } 34 | if (stateMachine->IsKeyDown('O')) 35 | { 36 | line.start = mousePosition; 37 | } 38 | if (stateMachine->IsKeyDown('P')) 39 | { 40 | line.end = mousePosition; 41 | } 42 | if (stateMachine->IsKeyDown('C')) 43 | { 44 | circle.position = mousePosition; 45 | } 46 | if (stateMachine->IsKeyDown('V')) 47 | { 48 | circle.radius = CGUL::Vector2::Distance(circle.position, mousePosition); 49 | } 50 | 51 | static CGUL::Float32 timer = 0; 52 | timer += deltaTime * 3; 53 | 54 | box1.halfExtents = CGUL::Vector2(50, 50) + (CGUL::Vector2(25, 25) * CGUL::Math::Sin(timer)); 55 | box1.orientation = CGUL::Math::Mod(box1.orientation + deltaTime, CGUL::Math::Tau< CGUL::Float32 >()); 56 | 57 | box2.orientation = CGUL::Math::Mod(box2.orientation + deltaTime * 0.34892f, CGUL::Math::Tau< CGUL::Float32 >()); 58 | /*if (stateMachine->IsKeyDown('A')) 59 | { 60 | box2.orientation = CGUL::Math::Pi< CGUL::Float32 >(); 61 | } 62 | else 63 | { 64 | box2.orientation = 0; 65 | }*/ 66 | 67 | render->SetDoNotDraw(true); 68 | box1.color = CGUL::Colors::cornflowerBlue; 69 | box2.color = CGUL::Colors::cornflowerBlue; 70 | box3.color = CGUL::Colors::cornflowerBlue; 71 | if (box1.CollidingOrientedBox(box2)) 72 | { 73 | box1.color = CGUL::Colors::red; 74 | box2.color = CGUL::Colors::red; 75 | } 76 | if (box1.CollidingAxisAlignedBox(box3)) 77 | { 78 | box1.color = CGUL::Colors::red; 79 | box3.color = CGUL::Colors::red; 80 | } 81 | render->SetDoNotDraw(false); 82 | 83 | box1.Draw(); 84 | box2.Draw(); 85 | box3.Draw(); 86 | line.Draw(); 87 | circle.Draw(); 88 | 89 | box1.CollidingOrientedBox(box2); 90 | 91 | CGUL::SCoord32 mousePos = stateMachine->GetMousePosition(); 92 | render->Circle(box1.GetClosestPoint(mousePos), 7, CGUL::Colors::green); 93 | render->Circle(box2.GetClosestPoint(mousePos), 7, CGUL::Colors::green); 94 | render->Circle(box3.GetClosestPoint(mousePos), 7, CGUL::Colors::green); 95 | render->Circle(line.GetClosestPoint(mousePos), 7, CGUL::Colors::green); 96 | render->Circle(circle.GetClosestPoint(mousePos), 7, CGUL::Colors::green); 97 | 98 | render->Circle(mousePos, 2, CGUL::Colors::red); 99 | } 100 | 101 | void StateBoxes::Exit() 102 | { 103 | } 104 | -------------------------------------------------------------------------------- /src/StateBoxes.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "State.hpp" 4 | #include "Circle.hpp" 5 | #include "AxisAlignedBox.hpp" 6 | #include "OrientedBox.hpp" 7 | #include "Line.hpp" 8 | 9 | class StateBoxes : public State 10 | { 11 | OrientedBox box1; 12 | OrientedBox box2; 13 | AxisAlignedBox box3; 14 | Line line; 15 | Circle circle; 16 | public: 17 | StateBoxes(); 18 | ~StateBoxes(); 19 | 20 | void Enter(); 21 | void Update(CGUL::Float32 deltaTime); 22 | void Exit(); 23 | }; 24 | -------------------------------------------------------------------------------- /src/StateCircles.cpp: -------------------------------------------------------------------------------- 1 | #include "StateCircles.hpp" 2 | 3 | struct MovingCircle : public Circle 4 | { 5 | CGUL::Vector2 velocity; 6 | 7 | MovingCircle() : 8 | Circle() 9 | { 10 | } 11 | 12 | MovingCircle(const CGUL::Vector2& position, CGUL::Float32 radius, const CGUL::Vector2& velocity) : 13 | Circle(position, radius, 0), 14 | velocity(velocity) 15 | { 16 | } 17 | }; 18 | 19 | StateCircles::StateCircles() 20 | { 21 | } 22 | 23 | StateCircles::~StateCircles() 24 | { 25 | } 26 | 27 | void StateCircles::Enter() 28 | { 29 | render->SetClearColor(CGUL::Colors::darkBlue); 30 | stateMachine->SetTitle(U8("Circles")); 31 | 32 | CGUL::Random random; 33 | for (int i = 0; i < 10; i++) 34 | { 35 | MovingCircle* circle = new MovingCircle; 36 | circle->position = CGUL::Vector2(random.GetInteger() % 800, random.GetInteger() % 600); 37 | circle->radius = 20 + random.GetInteger() % 40; 38 | circle->velocity = CGUL::Vector2::FromAngle(random.GetDecimal() * CGUL::Math::Tau< CGUL::Float32 >(), 2); 39 | circles.push_back(circle); 40 | } 41 | } 42 | 43 | void StateCircles::Update(CGUL::Float32 deltaTime) 44 | { 45 | static CGUL::Float32 timer = 0; 46 | timer += deltaTime * 3; 47 | 48 | box.halfExtents = CGUL::Vector2(50, 50) + (CGUL::Vector2(25, 25) * CGUL::Math::Sin(timer)); 49 | box.orientation = CGUL::Math::Mod(box.orientation + deltaTime, CGUL::Math::Tau< CGUL::Float32 >()); 50 | box.position = stateMachine->GetMousePosition(); 51 | 52 | render->SetDoNotDraw(true); 53 | for (CGUL::Vector< MovingCircle* >::iterator itr = circles.begin(); itr != circles.end(); itr++) 54 | { 55 | if ((*itr)->position.x < 0 || (*itr)->position.x > 800) 56 | { 57 | (*itr)->velocity.x *= -1; 58 | } 59 | if ((*itr)->position.y < 0 || (*itr)->position.y > 600) 60 | { 61 | (*itr)->velocity.y *= -1; 62 | } 63 | (*itr)->position += (*itr)->velocity; 64 | (*itr)->color = CGUL::Colors::cornflowerBlue; 65 | } 66 | 67 | for (CGUL::Vector< MovingCircle* >::iterator itr = circles.begin(); itr != circles.end(); itr++) 68 | { 69 | for (CGUL::Vector< MovingCircle* >::iterator other = itr + 1; other != circles.end(); other++) 70 | { 71 | if ((*itr)->CollidingCircle(*(*other))) 72 | { 73 | (*itr)->color = CGUL::Colors::red; 74 | (*other)->color = CGUL::Colors::red; 75 | } 76 | } 77 | } 78 | render->SetDoNotDraw(false); 79 | 80 | box.color = CGUL::Colors::cornflowerBlue; 81 | for (CGUL::Vector< MovingCircle* >::iterator itr = circles.begin(); itr != circles.end(); itr++) 82 | { 83 | if (box.CollidingCircle(*(*itr))) 84 | { 85 | box.color = CGUL::Colors::red; 86 | (*itr)->color = CGUL::Colors::red; 87 | } 88 | (*itr)->Draw(); 89 | } 90 | 91 | CGUL::SCoord32 mousePos = stateMachine->GetMousePosition(); 92 | for (CGUL::Vector< MovingCircle* >::iterator itr = circles.begin(); itr != circles.end(); itr++) 93 | { 94 | render->Circle((*itr)->GetClosestPoint(mousePos), 3, CGUL::Colors::white); 95 | } 96 | box.Draw(); 97 | } 98 | 99 | void StateCircles::Exit() 100 | { 101 | for (CGUL::Vector< MovingCircle* >::iterator itr = circles.begin(); itr != circles.end(); itr++) 102 | { 103 | delete *itr; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/StateCircles.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "State.hpp" 4 | #include "Circle.hpp" 5 | #include "AxisAlignedBox.hpp" 6 | #include "OrientedBox.hpp" 7 | 8 | struct MovingCircle; 9 | 10 | class StateCircles : public State 11 | { 12 | CGUL::Vector< MovingCircle* > circles; 13 | OrientedBox box; 14 | public: 15 | StateCircles(); 16 | ~StateCircles(); 17 | 18 | void Enter(); 19 | void Update(CGUL::Float32 deltaTime); 20 | void Exit(); 21 | }; 22 | -------------------------------------------------------------------------------- /src/StateMachine.cpp: -------------------------------------------------------------------------------- 1 | #include "StateMachine.hpp" 2 | #include "State.hpp" 3 | #include "Render.hpp" 4 | 5 | #include "StateBoxes.hpp" 6 | #include "StateCircles.hpp" 7 | #include "StateTest.hpp" 8 | #include "StateTriangulate.hpp" 9 | 10 | Render* render; 11 | 12 | void StateMachine::KeyButtonEvent(const CGUL::WindowKeyButtonEvent& event, void* userData) 13 | { 14 | StateMachine* stateMachine = (StateMachine*)userData; 15 | if (event.key < 256) 16 | { 17 | CGUL::Byte& key = stateMachine->keys[event.key]; 18 | key = (event.pressed ? key | INPUT_DOWN : key & ~INPUT_DOWN); 19 | } 20 | } 21 | 22 | void StateMachine::MouseButtonEvent(const CGUL::WindowMouseButtonEvent& event, void* userData) 23 | { 24 | StateMachine* stateMachine = (StateMachine*)userData; 25 | if (event.button < 3) 26 | { 27 | CGUL::Byte& button = stateMachine->buttons[event.button]; 28 | button = (event.pressed ? button | INPUT_DOWN : button & ~INPUT_DOWN); 29 | } 30 | } 31 | 32 | void StateMachine::MouseMoveEvent(const CGUL::WindowMouseMoveEvent& event, void* userData) 33 | { 34 | StateMachine* stateMachine = (StateMachine*)userData; 35 | CGUL::Vector2 relativeSize(800.0f / stateMachine->window.GetWidth(), 600.0f / stateMachine->window.GetHeight()); 36 | stateMachine->mousePosition = event.location; 37 | stateMachine->mousePosition = CGUL::SCoord32(stateMachine->mousePosition.x * relativeSize.x, stateMachine->mousePosition.y * relativeSize.y); 38 | } 39 | 40 | StateMachine::StateMachine() : 41 | currentState(NULL), 42 | queuedState(NULL), 43 | banner(0) 44 | { 45 | render = NULL; 46 | CGUL::Memory::ZeroData(keys, 256); 47 | } 48 | 49 | StateMachine::~StateMachine() 50 | { 51 | } 52 | 53 | void StateMachine::ChangeState(State* newState) 54 | { 55 | queuedState = newState; 56 | } 57 | 58 | void StateMachine::SetTitle(const CGUL::String& title) 59 | { 60 | window.SetTitle(title + " - Physics2D"); 61 | } 62 | 63 | void StateMachine::Initialize() 64 | { 65 | CGUL::WindowStyle style; 66 | style.title = U8(""); 67 | style.size = CGUL::UCoord32(800, 600); 68 | style.backgroundColor = CGUL::Colors::black; 69 | window.Create(style); 70 | window.SetCursorShow(false); 71 | 72 | window.onKeyButton.AddEvent(KeyButtonEvent, this); 73 | window.onMouseButton.AddEvent(MouseButtonEvent, this); 74 | window.onMouseMove.AddEvent(MouseMoveEvent, this); 75 | 76 | render = new Render(&window); 77 | 78 | try 79 | { 80 | banner = render->LoadSprite("banner.png", &bannerSize); 81 | } 82 | catch (...) 83 | { 84 | std::cout << "Could not load banner :(" << std::endl; 85 | banner = 0; 86 | } 87 | 88 | timer.Start(); 89 | } 90 | 91 | bool StateMachine::IsRunning() const 92 | { 93 | return window.IsOpen(); 94 | } 95 | 96 | void StateMachine::Update() 97 | { 98 | CGUL::Timer::Sleep(16); 99 | 100 | if (render == NULL) 101 | { 102 | return; 103 | } 104 | 105 | if (IsKeyPressed('1')) 106 | { 107 | ChangeState(new StateBoxes); 108 | } 109 | else if (IsKeyPressed('2')) 110 | { 111 | ChangeState(new StateCircles); 112 | } 113 | else if (IsKeyPressed('3')) 114 | { 115 | ChangeState(new StateTest); 116 | } 117 | else if (IsKeyPressed('4')) 118 | { 119 | ChangeState(new StateTriangulate); 120 | } 121 | 122 | for (CGUL::UInt32 i = 0; i < 256; i++) 123 | { 124 | if (keys[i] & INPUT_DOWN) 125 | { 126 | keys[i] |= INPUT_HELD; 127 | } 128 | else 129 | { 130 | keys[i] &= ~INPUT_HELD; 131 | } 132 | } 133 | 134 | for (CGUL::UInt32 i = 0; i < 3; i++) 135 | { 136 | if (buttons[i] & INPUT_DOWN) 137 | { 138 | buttons[i] |= INPUT_HELD; 139 | } 140 | else 141 | { 142 | buttons[i] &= ~INPUT_HELD; 143 | } 144 | } 145 | 146 | if (queuedState != NULL) 147 | { 148 | if (currentState != NULL) 149 | { 150 | currentState->Exit(); 151 | } 152 | delete currentState; 153 | currentState = queuedState; 154 | Reset(); 155 | if (currentState != NULL) 156 | { 157 | currentState->Setup(this, render, &window); 158 | currentState->Enter(); 159 | } 160 | queuedState = NULL; 161 | } 162 | CGUL::Float64 deltaTime = timer.GetDeltaTime(); 163 | CGUL::Window::Update(); 164 | render->Update(currentState, this, (CGUL::Float32)deltaTime); 165 | } 166 | 167 | void StateMachine::Draw(CGUL::Float32 deltaTime) 168 | { 169 | if (banner != 0) 170 | { 171 | CGUL::Vector2 pos = CGUL::Vector2(800, 0); 172 | pos.x -= bannerSize.x; 173 | 174 | render->Sprite(banner, pos, bannerSize); 175 | } 176 | } 177 | 178 | void StateMachine::Reset() 179 | { 180 | render->Reset(); 181 | window.SetTitle(U8("")); 182 | } 183 | 184 | void StateMachine::Exit() 185 | { 186 | if (currentState != NULL) 187 | { 188 | currentState->Exit(); 189 | } 190 | window.Close(); 191 | } 192 | 193 | CGUL::SCoord32 StateMachine::GetMousePosition() const 194 | { 195 | return mousePosition; 196 | } 197 | 198 | bool StateMachine::IsKeyDown(CGUL::Byte key) const 199 | { 200 | return (keys[key] & INPUT_DOWN) != 0; 201 | } 202 | 203 | bool StateMachine::IsKeyPressed(CGUL::Byte key) const 204 | { 205 | return (keys[key] & INPUT_DOWN) && !(keys[key] & INPUT_HELD); 206 | } 207 | 208 | bool StateMachine::IsKeyReleased(CGUL::Byte key) const 209 | { 210 | return (keys[key] & INPUT_HELD) && !(keys[key] & INPUT_DOWN); 211 | } 212 | 213 | bool StateMachine::IsButtonDown(CGUL::Byte button) const 214 | { 215 | return (buttons[button] & INPUT_DOWN) != 0; 216 | } 217 | 218 | bool StateMachine::IsButtonPressed(CGUL::Byte button) const 219 | { 220 | return (buttons[button] & INPUT_DOWN) && !(buttons[button] & INPUT_HELD); 221 | } 222 | 223 | bool StateMachine::IsButtonReleased(CGUL::Byte button) const 224 | { 225 | return (buttons[button] & INPUT_HELD) && !(buttons[button] & INPUT_DOWN); 226 | } 227 | -------------------------------------------------------------------------------- /src/StateMachine.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include 5 | 6 | class State; 7 | class Render; 8 | 9 | extern Render* render; 10 | 11 | class StateMachine 12 | { 13 | static void KeyButtonEvent(const CGUL::WindowKeyButtonEvent& event, void* userData); 14 | static void MouseButtonEvent(const CGUL::WindowMouseButtonEvent& event, void* userData); 15 | static void MouseMoveEvent(const CGUL::WindowMouseMoveEvent& event, void* userData); 16 | 17 | State* currentState; 18 | State* queuedState; 19 | 20 | CGUL::Window window; 21 | CGUL::Timer timer; 22 | 23 | enum InputState 24 | { 25 | INPUT_DOWN = 1, 26 | INPUT_HELD = 2 27 | }; 28 | CGUL::Byte keys[256]; 29 | CGUL::Byte buttons[3]; 30 | 31 | CGUL::SCoord32 mousePosition; 32 | 33 | CGUL::UInt32 banner; 34 | CGUL::UCoord32 bannerSize; 35 | public: 36 | StateMachine(); 37 | ~StateMachine(); 38 | 39 | void ChangeState(State* newState); 40 | 41 | void SetTitle(const CGUL::String& title); 42 | 43 | void Initialize(); 44 | bool IsRunning() const; 45 | void Update(); 46 | void Draw(CGUL::Float32 deltaTime); 47 | void Reset(); 48 | void Exit(); 49 | 50 | CGUL::SCoord32 GetMousePosition() const; 51 | 52 | bool IsKeyDown(CGUL::Byte key) const; 53 | bool IsKeyPressed(CGUL::Byte key) const; 54 | bool IsKeyReleased(CGUL::Byte key) const; 55 | 56 | bool IsButtonDown(CGUL::Byte button) const; 57 | bool IsButtonPressed(CGUL::Byte button) const; 58 | bool IsButtonReleased(CGUL::Byte button) const; 59 | }; 60 | -------------------------------------------------------------------------------- /src/StateTest.cpp: -------------------------------------------------------------------------------- 1 | #include "StateTest.hpp" 2 | #include "Circle.hpp" 3 | #include "AxisAlignedBox.hpp" 4 | #include "OrientedBox.hpp" 5 | #include "Line.hpp" 6 | #include "Triangle.hpp" 7 | 8 | StateTest::StateTest() : 9 | drag(NULL) 10 | { 11 | } 12 | 13 | StateTest::~StateTest() 14 | { 15 | } 16 | 17 | void StateTest::Enter() 18 | { 19 | using namespace CGUL; 20 | 21 | render->SetClearColor(CGUL::Colors::darkBlue); 22 | stateMachine->SetTitle(U8("Test")); 23 | 24 | objects.push_back(new AxisAlignedBox(Vector2(100, 100), Vector2(50, 50))); 25 | objects.push_back(new OrientedBox(Vector2(150, 150), Vector2(50, 50), 90)); 26 | objects.push_back(new Circle(Vector2(250, 350), 90, 0)); 27 | //objects.push_back(new Triangle(Vector2(400, 300), Vector2(-25, 0), Vector2(0, 50), Vector2(25, 0), 0)); 28 | objects.push_back(new Triangle(Vector2(400, 200), Vector2(-60, 0), Vector2(0, 120), Vector2(60, 0), 0)); 29 | } 30 | 31 | void StateTest::Update(CGUL::Float32 deltaTime) 32 | { 33 | using namespace CGUL; 34 | 35 | SCoord32 mousePos = stateMachine->GetMousePosition(); 36 | Color mouseColor = Colors::red; 37 | Float32 mouseSize = 2; 38 | 39 | static Float32 timer = 0; 40 | timer += deltaTime; 41 | 42 | OrientedBox* wee = (OrientedBox*)objects[1]; 43 | wee->orientation += deltaTime * 3; 44 | wee->halfExtents = Vector2(75, 75); 45 | 46 | Circle* circle = (Circle*)objects[2]; 47 | circle->orientation += deltaTime * 3; 48 | 49 | for (CGUL::Vector< Collision* >::iterator itr = objects.begin(); itr != objects.end(); itr++) 50 | { 51 | (*itr)->color = Colors::cornflowerBlue; 52 | 53 | if ((SCoord32)(*itr)->GetClosestPoint(mousePos) == mousePos) 54 | { 55 | mouseColor = Colors::green; 56 | mouseSize += 2; 57 | 58 | if (mouseSize == 4 && stateMachine->IsButtonPressed(0)) 59 | { 60 | drag = *itr; 61 | Matrix inverseWorld = (*itr)->GetWorldMatrix().GetInverse(); 62 | offset = mousePos; 63 | offset *= inverseWorld; 64 | offset *= -1; 65 | } 66 | } 67 | } 68 | if (!stateMachine->IsButtonDown(0)) 69 | { 70 | drag = NULL; 71 | } 72 | 73 | if (drag != NULL) 74 | { 75 | mouseColor = Colors::yellow; 76 | mouseSize = 1; 77 | 78 | drag->SetPosition(mousePos); 79 | Vector2 a = offset; 80 | a *= drag->GetWorldMatrix(); 81 | drag->SetPosition(a); 82 | } 83 | 84 | for (CGUL::Vector< Collision* >::iterator itr = objects.begin(); itr != objects.end(); itr++) 85 | { 86 | for (CGUL::Vector< Collision* >::iterator other = itr + 1; other != objects.end(); other++) 87 | { 88 | if ((*itr)->Colliding(*other)) 89 | { 90 | (*itr)->color = Colors::red; 91 | (*other)->color = Colors::red; 92 | } 93 | } 94 | } 95 | 96 | for (CGUL::Vector< Collision* >::iterator itr = objects.begin(); itr != objects.end(); itr++) 97 | { 98 | (*itr)->Draw(); 99 | } 100 | 101 | for (CGUL::Vector< Collision* >::iterator itr = objects.begin(); itr != objects.end(); itr++) 102 | { 103 | render->Circle((*itr)->GetClosestPoint(mousePos), 2, CGUL::Colors::white); 104 | } 105 | 106 | render->Circle(mousePos, mouseSize, mouseColor); 107 | } 108 | 109 | void StateTest::Exit() 110 | { 111 | for (CGUL::Vector< Collision* >::iterator itr = objects.begin(); itr != objects.end(); itr++) 112 | { 113 | delete *itr; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/StateTest.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "State.hpp" 4 | #include "Collision.hpp" 5 | 6 | struct MovingCircle; 7 | 8 | class StateTest : public State 9 | { 10 | CGUL::Vector< Collision* > objects; 11 | Collision* drag; 12 | CGUL::Vector2 offset; 13 | public: 14 | StateTest(); 15 | ~StateTest(); 16 | 17 | void Enter(); 18 | void Update(CGUL::Float32 deltaTime); 19 | void Exit(); 20 | }; 21 | -------------------------------------------------------------------------------- /src/StateTriangulate.cpp: -------------------------------------------------------------------------------- 1 | #include "StateTriangulate.hpp" 2 | #include "Triangle.hpp" 3 | #include "Point.hpp" 4 | 5 | bool IsCounterClockwise(CGUL::Vector< CGUL::Vector2 > inPoints) 6 | { 7 | using namespace CGUL; 8 | 9 | int count = 0, j = 0, k = 0; 10 | 11 | // Don't bother if there's less than 3 points, just assume its counter clockwise 12 | if (inPoints.size() < 3) 13 | { 14 | return true; 15 | } 16 | 17 | for (int i = 0; i < inPoints.size(); i++) 18 | { 19 | // Get the next two points 20 | j = (i + 1) % inPoints.size(); 21 | k = (i + 2) % inPoints.size(); 22 | 23 | // Get the direction of each points 24 | Vector2 valueA = inPoints[j] - inPoints[i]; 25 | Vector2 valueB = inPoints[k] - inPoints[j]; 26 | 27 | // Check if the cross product between the two directions is positive, 28 | // if so this point is clockwise 29 | count = (valueA.x * valueB.y - valueA.y * valueB.x < 0) ? (count + 1) : (count - 1); 30 | } 31 | 32 | // Determine clockwise-ness by which one was more common. 33 | // More CW points is CW, more CCW points is CCW. 34 | // A partial guess but it works for pracitcal means. 35 | return (count < 0); 36 | } 37 | 38 | bool Triangulate(CGUL::Vector< CGUL::Vector2 > inPoints, CGUL::Vector< Triangle >* triangles) 39 | { 40 | using namespace CGUL; 41 | 42 | if (inPoints.size() < 3) 43 | { 44 | return false; 45 | } 46 | 47 | Vector< Vector2 > points; 48 | for (Vector< Vector2 >::iterator itr = inPoints.begin(); itr < inPoints.end(); itr++) 49 | { 50 | points.push_back(*itr); 51 | } 52 | 53 | bool finished = false; 54 | Vector2 point; 55 | 56 | // The three points of our potential ear 57 | Vector2 point1; 58 | Vector2 point2; 59 | Vector2 point3; 60 | 61 | while (!finished) 62 | { 63 | int i = 0; 64 | bool found = false; 65 | 66 | while (!found && (i < points.size())) 67 | { 68 | // Set the point to our current point 69 | point1 = points[i]; 70 | 71 | // Begin checking if we found an ear 72 | bool isEar = true; 73 | 74 | // Find the previous point 75 | if (i == 0) 76 | { 77 | point2 = points[points.size() - 1]; 78 | } 79 | else 80 | { 81 | point2 = points[i - 1]; 82 | } 83 | 84 | // Find the next point 85 | if (i == points.size() - 1) 86 | { 87 | point3 = points[0]; 88 | } 89 | else 90 | { 91 | point3 = points[i + 1]; 92 | } 93 | 94 | // Find the area of the ear 95 | double area = 0; 96 | area += point2.x * point1.y; 97 | area -= (point2.y * point1.x); 98 | area += point1.x * point3.y; 99 | area -= (point1.y * point3.x); 100 | area += point3.x * point2.y; 101 | area -= (point3.y * point2.x); 102 | area = area / 2; 103 | 104 | // Is the ear convex? 105 | if (area < 0) 106 | { 107 | for (int j = 0; j < points.size() - 1; j++) 108 | { 109 | // check if good ear 110 | Vector2 pointCheck = points[j]; 111 | if (!(pointCheck == point1 || pointCheck == point2 || pointCheck == point3)) 112 | { 113 | if (Triangle(Vector2(0, 0), point2, point1, point3, 0).CollidingPoint(Point(pointCheck))) 114 | { 115 | isEar = false; 116 | } 117 | } 118 | } 119 | } 120 | else // not a good ear 121 | { 122 | isEar = false; 123 | } 124 | 125 | // ear 126 | if (isEar) 127 | { 128 | found = true; 129 | } 130 | else // not ear 131 | { 132 | i++; 133 | } 134 | } 135 | 136 | // triangulation failed 137 | if (found == false) 138 | { 139 | return false; 140 | } 141 | 142 | for (int j = 0; j < points.size(); j++) 143 | { 144 | if (i == j) 145 | { 146 | // found an ear 147 | triangles->push_back(Triangle(Vector2(0, 0), point2, point1, point3, 0)); 148 | 149 | // remove the point from the list 150 | points.erase(points.begin() + j); 151 | } 152 | } 153 | 154 | if (points.size() == 3) 155 | { 156 | triangles->push_back(Triangle(Vector2(0, 0), points[0], points[1], points[2], 0)); 157 | finished = true; 158 | } 159 | } 160 | 161 | return true; 162 | } 163 | 164 | StateTriangulate::StateTriangulate() 165 | { 166 | } 167 | 168 | StateTriangulate::~StateTriangulate() 169 | { 170 | } 171 | 172 | void StateTriangulate::Enter() 173 | { 174 | render->SetClearColor(CGUL::Colors::darkBlue); 175 | stateMachine->SetTitle(U8("Triangulate")); 176 | } 177 | 178 | void StateTriangulate::Update(CGUL::Float32 deltaTime) 179 | { 180 | using namespace CGUL; 181 | Vector2 mousePos = stateMachine->GetMousePosition(); 182 | 183 | if (stateMachine->IsButtonPressed(0)) 184 | { 185 | points.push_back(mousePos); 186 | 187 | if (IsCounterClockwise(points)) 188 | { 189 | std::cout << "CCW!!" << std::endl; 190 | } 191 | else 192 | { 193 | std::cout << "CW!!" << std::endl; 194 | } 195 | } 196 | 197 | if (stateMachine->IsKeyPressed('R')) 198 | { 199 | points.clear(); 200 | } 201 | 202 | for (Vector< Vector2 >::iterator itr = points.begin(); itr != points.end(); itr++) 203 | { 204 | render->Circle(*itr, 4, Colors::green); 205 | if (itr + 1 == points.end()) 206 | { 207 | render->Line(*itr, *(points.begin()), Colors::green); 208 | } 209 | else 210 | { 211 | render->Line(*itr, *(itr + 1), Colors::green); 212 | } 213 | } 214 | 215 | Vector< Triangle > triangles; 216 | Triangulate(points, &triangles); 217 | 218 | if (!stateMachine->IsKeyDown('H')) 219 | { 220 | for (Vector< Triangle >::iterator itr = triangles.begin(); itr != triangles.end(); itr++) 221 | { 222 | Triangle& triangle = *itr; 223 | render->Line(triangle.pointA, triangle.pointB, Colors::red); 224 | render->Line(triangle.pointB, triangle.pointC, Colors::red); 225 | render->Line(triangle.pointC, triangle.pointA, Colors::red); 226 | } 227 | } 228 | 229 | render->Circle(mousePos, 2, Colors::red); 230 | } 231 | 232 | void StateTriangulate::Exit() 233 | { 234 | } 235 | -------------------------------------------------------------------------------- /src/StateTriangulate.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "State.hpp" 4 | #include "Circle.hpp" 5 | #include "AxisAlignedBox.hpp" 6 | #include "OrientedBox.hpp" 7 | 8 | struct MovingCircle; 9 | 10 | class StateTriangulate : public State 11 | { 12 | CGUL::Vector< CGUL::Vector2 > points; 13 | public: 14 | StateTriangulate(); 15 | ~StateTriangulate(); 16 | 17 | void Enter(); 18 | void Update(CGUL::Float32 deltaTime); 19 | void Exit(); 20 | }; 21 | -------------------------------------------------------------------------------- /src/Triangle.cpp: -------------------------------------------------------------------------------- 1 | #include "Triangle.hpp" 2 | 3 | #include "AxisAlignedBox.hpp" 4 | #include "OrientedBox.hpp" 5 | 6 | Triangle::Triangle() : 7 | Collision(Collision::TRIANGLE), 8 | orientation(0) 9 | { 10 | } 11 | 12 | Triangle::Triangle(const CGUL::Vector2& position, const CGUL::Vector2& pointA, const CGUL::Vector2& pointB, const CGUL::Vector2& pointC, CGUL::Float32 orientation) : 13 | Collision(Collision::TRIANGLE), 14 | position(position), 15 | pointA(pointA), 16 | pointB(pointB), 17 | pointC(pointC), 18 | orientation(orientation) 19 | { 20 | } 21 | 22 | void Triangle::SetPosition(const CGUL::Vector2& position) 23 | { 24 | this->position = position; 25 | } 26 | 27 | CGUL::Vector2 Triangle::GetPosition() const 28 | { 29 | return position; 30 | } 31 | 32 | CGUL::Vector2 Triangle::GetClosestPoint(const CGUL::Vector2& position) const 33 | { 34 | using namespace CGUL; 35 | 36 | Vector2 axes[] = 37 | { 38 | Vector2::Normalized(pointA - pointB), 39 | Vector2::Normalized(pointB - pointC), 40 | Vector2::Normalized(pointC - pointA) 41 | }; 42 | 43 | Vector2 points[3][2] = 44 | { 45 | { pointA, pointB }, 46 | { pointB, pointC }, 47 | { pointC, pointA } 48 | }; 49 | 50 | Vector2 result = position - this->position; 51 | for (Byte i = 0; i < 3; i++) 52 | { 53 | Vector2 axis = axes[i]; 54 | Vector2 perp = axis.GetPerpendicular(); 55 | 56 | Float32 positionOnAxis = Vector2::DotProduct(result, axis); 57 | Float32 positionOnPerp = Vector2::DotProduct(result, perp); 58 | Float32 pointOnPerp = Vector2::DotProduct(points[i][0], perp); 59 | 60 | if (pointOnPerp > positionOnPerp) 61 | { 62 | positionOnPerp = pointOnPerp; 63 | } 64 | 65 | Float32 min, max, projection; 66 | min = max = Vector2::DotProduct(axis, pointA); 67 | projection = Vector2::DotProduct(axis, pointB); 68 | min = Math::Min(min, projection); 69 | max = Math::Max(max, projection); 70 | projection = Vector2::DotProduct(axis, pointC); 71 | min = Math::Min(min, projection); 72 | max = Math::Max(max, projection); 73 | positionOnAxis = Math::Clamp(positionOnAxis, min, max); 74 | 75 | result = axis * positionOnAxis + perp * positionOnPerp; 76 | } 77 | 78 | //return this->position + result; 79 | return this->position + result; 80 | } 81 | 82 | void Triangle::ProjectionOnAxis(const CGUL::Vector2& axis, CGUL::Float32* min, CGUL::Float32* max) const 83 | { 84 | CGUL::Matrix world; 85 | world = world * CGUL::Matrix::MakeTranslation(position); 86 | 87 | CGUL::Vector2 points[] = 88 | { 89 | pointA * world, 90 | pointB * world, 91 | pointC * world 92 | }; 93 | 94 | return Collision::ProjectionOnAxis(points, 3, axis, min, max); 95 | } 96 | 97 | CGUL::Matrix Triangle::GetWorldMatrix() const 98 | { 99 | CGUL::Matrix matrix; 100 | //matrix = matrix * CGUL::Matrix::MakeRotation(orientation); 101 | matrix = matrix * CGUL::Matrix::MakeTranslation(position); 102 | return matrix; 103 | } 104 | 105 | bool Triangle::CollidingCircle(const Circle& other) const 106 | { 107 | return CheckCircleAndTriangle(other, *this); 108 | } 109 | 110 | bool Triangle::CollidingAxisAlignedBox(const AxisAlignedBox& other) const 111 | { 112 | return CheckAxisAlignedBoxAndTriangle(other, *this); 113 | } 114 | 115 | bool Triangle::CollidingOrientedBox(const OrientedBox& other) const 116 | { 117 | return CheckOrientedBoxAndTriangle(other, *this); 118 | } 119 | 120 | bool Triangle::CollidingLine(const Line& other) const 121 | { 122 | return CheckLineAndTriangle(other, *this); 123 | } 124 | 125 | bool Triangle::CollidingTriangle(const Triangle& other) const 126 | { 127 | return CheckTriangleAndTriangle(*this, other); 128 | } 129 | 130 | bool Triangle::CollidingPoint(const Point& other) const 131 | { 132 | return CheckTriangleAndPoint(*this, other); 133 | } 134 | 135 | void Triangle::Draw() const 136 | { 137 | render->Triangle(position, pointA, pointB, pointC, color); 138 | } 139 | -------------------------------------------------------------------------------- /src/Triangle.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "Collision.hpp" 4 | #include "Render.hpp" 5 | 6 | extern Render* render; 7 | 8 | struct Triangle : public Collision 9 | { 10 | CGUL::Vector2 position; 11 | CGUL::Vector2 pointA; 12 | CGUL::Vector2 pointB; 13 | CGUL::Vector2 pointC; 14 | CGUL::Float32 orientation; 15 | 16 | Triangle(); 17 | Triangle(const CGUL::Vector2& position, const CGUL::Vector2& pointA, const CGUL::Vector2& pointB, const CGUL::Vector2& pointC, CGUL::Float32 orientation); 18 | 19 | void SetPosition(const CGUL::Vector2& position); 20 | void SetPointA(const CGUL::Vector2& point); 21 | void SetPointB(const CGUL::Vector2& point); 22 | void SetPointC(const CGUL::Vector2& point); 23 | void SetOrientation(CGUL::Float32 orientation); 24 | 25 | CGUL::Vector2 GetPosition() const; 26 | CGUL::Vector2 GetPointA() const; 27 | CGUL::Vector2 GetPointB() const; 28 | CGUL::Vector2 GetPointC() const; 29 | CGUL::Float32 GetOrientation() const; 30 | 31 | CGUL::Vector2 GetClosestPoint(const CGUL::Vector2& position) const; 32 | 33 | void ProjectionOnAxis(const CGUL::Vector2& axis, CGUL::Float32* min, CGUL::Float32* max) const; 34 | 35 | CGUL::Matrix GetWorldMatrix() const; 36 | 37 | bool CollidingCircle(const Circle& other) const; 38 | bool CollidingAxisAlignedBox(const AxisAlignedBox& other) const; 39 | bool CollidingOrientedBox(const OrientedBox& other) const; 40 | bool CollidingLine(const Line& other) const; 41 | bool CollidingTriangle(const Triangle& other) const; 42 | bool CollidingPoint(const Point& other) const; 43 | 44 | void Draw() const; 45 | }; 46 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "StateMachine.hpp" 2 | #include "StateBoxes.hpp" 3 | 4 | #include 5 | 6 | int main() 7 | { 8 | std::cout << "Powered by CGUL v" << CGUL::GetCGULVersion() << " (Compiled with: " << CGUL::GetCGULCompilerName() << ")" << std::endl; 9 | 10 | StateMachine stateMachine; 11 | stateMachine.Initialize(); 12 | stateMachine.ChangeState(new StateBoxes()); 13 | while (stateMachine.IsRunning()) 14 | { 15 | stateMachine.Update(); 16 | } 17 | stateMachine.Exit(); 18 | } 19 | --------------------------------------------------------------------------------