├── .gitignore
├── LICENSE
├── README.md
├── _app
├── main.cpp
└── premake5.lua
├── box2d_raylib
├── README.md
├── box2draylib.cpp
└── premake5.lua
├── box2d_raylib_objects
├── README.md
├── box2draylibobjects.cpp
└── premake5.lua
├── cards
├── README.md
├── cards.cpp
└── premake5.lua
├── chunked_procgen
├── Chunk.h
├── README.md
├── RenderArea.cpp
├── RenderArea.h
├── main.cpp
├── premake5.lua
├── resource_dir.h
└── resources
│ └── wabbit_alpha.png
├── fps_collisions
├── README.md
├── colisions.cpp
├── hud.cpp
├── include
│ ├── collisions.h
│ ├── hud.h
│ ├── map.h
│ ├── object_transform.h
│ ├── player.h
│ └── rlights.h
├── main.cpp
├── map.cpp
├── player.cpp
├── premake5.lua
└── resources
│ ├── blasterD.glb
│ ├── blasterH.glb
│ ├── laserLarge_004.ogg
│ ├── shaders
│ ├── lighting.fs
│ └── lighting.vs
│ ├── texture_07.png
│ └── texture_12.png
├── hardpoints2d
├── README.md
├── main.cpp
├── premake5.lua
└── resources
│ ├── Light.png
│ ├── RedDot.png
│ ├── Scope.png
│ ├── Silencer.png
│ ├── gun.png
│ ├── gun2.png
│ ├── laser.png
│ └── player.png
├── interpolated_animation_gpu
├── README.md
├── main.cpp
├── premake5.lua
├── resources
│ ├── anim.fs
│ ├── anim.vs
│ └── robot.glb
└── rlights.h
├── inventory
├── README.md
├── main.cpp
├── premake5.lua
└── resources
│ └── Items.png
├── pew
├── README.md
├── pew.cpp
└── premake5.lua
├── platform_example
├── README.md
├── main.cpp
├── premake5.lua
├── resources
│ ├── Warrior_Sheet-Effect.png
│ └── panel_blue.png
├── sprites.cpp
└── sprites.h
├── premake-VisualStudio.bat
├── premake-mingw.bat
├── premake5
├── premake5.exe
├── premake5.lua
├── premake5.osx
├── rayGui-cpp
├── main.cpp
└── premake5.lua
├── raycaster
├── README.md
├── premake5.lua
├── resources
│ └── textures.png
└── simple_raycaster_textures.cpp
├── raylib_premake5.lua
├── skill_tree
├── README.md
├── main.cpp
└── premake5.lua
├── stencil_reflection
├── main.cpp
└── premake5.lua
├── transform_hierarchy
├── README.md
├── main.cpp
├── object_transform.h
├── premake5.lua
└── resources
│ └── blasterD.glb
└── voxel_mesher
├── README.md
├── main.cpp
├── premake5.lua
├── resources
└── shaders
│ ├── base_lighting.vs
│ └── lighting.fs
└── rlights.h
/.gitignore:
--------------------------------------------------------------------------------
1 | /.vs/Examples-CPP/config/applicationhost.config
2 | /.vs/Examples-CPP/v16/.suo
3 | /.vs/Examples-CPP/v16/Browse.VC.db
4 | /.vs/Examples-CPP/v16/Browse.VC.db-shm
5 | /.vs/Examples-CPP/v16/Browse.VC.db-wal
6 | /.vs/Examples-CPP/v16/Browse.VC.opendb
7 | /.vs/Examples-CPP/v16/Solution.VC.db
8 | /.vs/Examples-CPP/v16/Solution.VC.db-shm
9 | /.vs/Examples-CPP/v16/Solution.VC.db-wal
10 | /.vs/Examples-CPP/v16/ipch/AutoPCH/15e6b6b1f4dca43f/RAUDIO.ipch
11 | /.vs/Examples-CPP/v16/ipch/AutoPCH/4bfe13d6a55d1387/RSHAPES.ipch
12 | /.vs/Examples-CPP/v16/ipch/AutoPCH/81137d3aa825123d/PEW.ipch
13 | /.vs/Examples-CPP/v16/ipch/AutoPCH/b2f66a8a7626455c/MAIN.ipch
14 | /.vs/Examples-CPP/v16/ipch/AutoPCH/c15e9969c728da86/RCORE.ipch
15 | /.vs/Examples-CPP/v16/ipch/AutoPCH/e2d68172fea7a4dd/CARDS.ipch
16 | /.vs/Examples-CPP/v16/ipch/AutoPCH/fab29d3eb75d7a95/RTEXTURES.ipch
17 | /Examples-CPP.sln
18 | /bin/Debug.DLL/Cards.exe
19 | /bin/Debug.DLL/Cards.pdb
20 | /bin/Debug.DLL/Pew.exe
21 | /bin/Debug.DLL/Pew.pdb
22 | /bin/Debug.DLL/raylib.dll
23 | /bin/Debug.DLL/raylib.exp
24 | /bin/Debug.DLL/raylib.lib
25 | /bin/Debug.DLL/raylib.pdb
26 | /build/obj/x64/Debug.DLL/raudio.obj
27 | /build/obj/x64/Debug.DLL/raylib.dll.recipe
28 | /build/obj/x64/Debug.DLL/raylib.ilk
29 | /build/obj/x64/Debug.DLL/raylib.log
30 | /build/obj/x64/Debug.DLL/raylib.tlog/CL.command.1.tlog
31 | /build/obj/x64/Debug.DLL/raylib.tlog/CL.read.1.tlog
32 | /build/obj/x64/Debug.DLL/raylib.tlog/CL.write.1.tlog
33 | /build/obj/x64/Debug.DLL/raylib.tlog/link.command.1.tlog
34 | /build/obj/x64/Debug.DLL/raylib.tlog/link.read.1.tlog
35 | /build/obj/x64/Debug.DLL/raylib.tlog/link.write.1.tlog
36 | /build/obj/x64/Debug.DLL/raylib.tlog/raylib.lastbuildstate
37 | /build/obj/x64/Debug.DLL/raylib.tlog/raylib.write.1u.tlog
38 | /build/obj/x64/Debug.DLL/rcore.obj
39 | /build/obj/x64/Debug.DLL/rglfw.obj
40 | /build/obj/x64/Debug.DLL/rmodels.obj
41 | /build/obj/x64/Debug.DLL/rshapes.obj
42 | /build/obj/x64/Debug.DLL/rtext.obj
43 | /build/obj/x64/Debug.DLL/rtextures.obj
44 | /build/obj/x64/Debug.DLL/utils.obj
45 | /build/obj/x64/Debug.DLL/vc142.idb
46 | /build/obj/x64/Debug.DLL/vc142.pdb
47 | /build/raylib.vcxproj
48 | /build/raylib.vcxproj.filters
49 | /cards/Cards.vcxproj
50 | /cards/Cards.vcxproj.filters
51 | /cards/Cards.vcxproj.user
52 | /pew/Pew.vcxproj
53 | /pew/Pew.vcxproj.filters
54 | /pew/Pew.vcxproj.user
55 | /pew/obj/x64/Debug.DLL/Pew.exe.recipe
56 | /pew/obj/x64/Debug.DLL/Pew.ilk
57 | /pew/obj/x64/Debug.DLL/Pew.log
58 | /pew/obj/x64/Debug.DLL/Pew.tlog/CL.command.1.tlog
59 | /pew/obj/x64/Debug.DLL/Pew.tlog/CL.read.1.tlog
60 | /pew/obj/x64/Debug.DLL/Pew.tlog/CL.write.1.tlog
61 | /pew/obj/x64/Debug.DLL/Pew.tlog/Pew.lastbuildstate
62 | /pew/obj/x64/Debug.DLL/Pew.tlog/link.command.1.tlog
63 | /pew/obj/x64/Debug.DLL/Pew.tlog/link.read.1.tlog
64 | /pew/obj/x64/Debug.DLL/Pew.tlog/link.write.1.tlog
65 | /pew/obj/x64/Debug.DLL/main.obj
66 | /pew/obj/x64/Debug.DLL/pew.obj
67 | /pew/obj/x64/Debug.DLL/vc142.idb
68 | /pew/obj/x64/Debug.DLL/vc142.pdb
69 | /premake5
70 | /premake5.exe
71 | /build/obj/x64/Debug.DLL/raylib.tlog/link.20680.delete.1.tlog
72 | /cards/obj/x64/Debug.DLL/Cards.exe.recipe
73 | /cards/obj/x64/Debug.DLL/Cards.ilk
74 | /cards/obj/x64/Debug.DLL/Cards.log
75 | /cards/obj/x64/Debug.DLL/Cards.tlog/CL.command.1.tlog
76 | /cards/obj/x64/Debug.DLL/Cards.tlog/CL.read.1.tlog
77 | /cards/obj/x64/Debug.DLL/Cards.tlog/CL.write.1.tlog
78 | /cards/obj/x64/Debug.DLL/Cards.tlog/Cards.lastbuildstate
79 | /cards/obj/x64/Debug.DLL/Cards.tlog/link.command.1.tlog
80 | /cards/obj/x64/Debug.DLL/Cards.tlog/link.read.1.tlog
81 | /cards/obj/x64/Debug.DLL/Cards.tlog/link.write.1.tlog
82 | /cards/obj/x64/Debug.DLL/cards.obj
83 | /cards/obj/x64/Debug.DLL/vc142.idb
84 | /cards/obj/x64/Debug.DLL/vc142.pdb
85 | /light_caster/obj/x64/Debug.DLL/LightCaster.exe.recipe
86 | /light_caster/obj/x64/Debug.DLL/LightCaster.ilk
87 | /light_caster/obj/x64/Debug.DLL/LightCaster.log
88 | /light_caster/obj/x64/Debug.DLL/LightCaster.tlog/CL.command.1.tlog
89 | /light_caster/obj/x64/Debug.DLL/LightCaster.tlog/CL.read.1.tlog
90 | /light_caster/obj/x64/Debug.DLL/LightCaster.tlog/CL.write.1.tlog
91 | /light_caster/obj/x64/Debug.DLL/LightCaster.tlog/LightCaster.lastbuildstate
92 | /light_caster/obj/x64/Debug.DLL/LightCaster.tlog/link.command.1.tlog
93 | /light_caster/obj/x64/Debug.DLL/LightCaster.tlog/link.read.1.tlog
94 | /light_caster/obj/x64/Debug.DLL/LightCaster.tlog/link.write.1.tlog
95 | /light_caster/obj/x64/Debug.DLL/main.obj
96 | /light_caster/obj/x64/Debug.DLL/vc142.idb
97 | /light_caster/obj/x64/Debug.DLL/vc142.pdb
98 | /.vs/Examples-CPP/v16/ipch/AutoPCH/fcf1419d1f80a874/MAIN.ipch
99 | /bin/Debug.DLL/LightCaster.exe
100 | /bin/Debug.DLL/LightCaster.pdb
101 | /light_caster/LightCaster.vcxproj
102 | /light_caster/LightCaster.vcxproj.filters
103 | /light_caster/LightCaster.vcxproj.user
104 | main.obj
105 | main.obj.enc
106 | platform_example.exe.recipe
107 | platform_example.ilk
108 | platform_example.log
109 | CL.command.1.tlog
110 | CL.read.1.tlog
111 | CL.write.1.tlog
112 | link.command.1.tlog
113 | link.read.1.tlog
114 | link.write.1.tlog
115 | platform_example.lastbuildstate
116 | sprites.obj
117 | vc142.idb
118 | vc142.pdb
119 | platform_example.vcxproj
120 | platform_example.vcxproj.filters
121 | platform_example.vcxproj.user
122 | MAIN.ipch
123 | platform_example.exe
124 | platform_example.pdb
125 | raylib.idb
126 | raylib.lib
127 | raylib.pdb
128 | raudio.obj
129 | raylib.lib.recipe
130 | raylib.log
131 | Lib-link.read.1.tlog
132 | Lib-link.write.1.tlog
133 | Lib.command.1.tlog
134 | raylib.lastbuildstate
135 | rcore.obj
136 | rglfw.obj
137 | rmodels.obj
138 | rshapes.obj
139 | rtext.obj
140 | rtextures.obj
141 | utils.obj
142 | StencilReflection.vcxproj
143 | StencilReflection.vcxproj.filters
144 | .vs
145 | Debug
146 | Release
147 | *.vcxproj
148 | *.filters
149 | *.user
150 | box2d-main
151 | raylib-master
152 | *.sln
153 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2020-2021 Jeffery Myers
2 |
3 | This software is provided "as-is", without any express or implied warranty. In no event
4 | will the authors be held liable for any damages arising from the use of this software.
5 |
6 | Permission is granted to anyone to use this software for any purpose, including commercial
7 | applications, and to alter it and redistribute it freely, subject to the following restrictions:
8 |
9 | 1. The origin of this software must not be misrepresented; you must not claim that you
10 | wrote the original software. If you use this software in a product, an acknowledgment
11 | in the product documentation would be appreciated but is not required.
12 |
13 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented
14 | as being the original software.
15 |
16 | 3. This notice may not be removed or altered from any source distribution.
17 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # examples-cpp
2 |
3 | Examples and samples made for raylib using C++
4 |
5 | ## Building
6 | The examples use premake. Each example is a project on it's own. Premake will setup the build systems for each project for you, and download any needed libraries (raylib and box2d)
7 |
8 | ### For Visual Studio
9 | Run premake-VisualStudio.bat. When it is done each example folder will have a .sln file in it that you can open and run.
10 |
11 | ### For MinGW
12 | Run premake-mingw.bat. When it is done each example folder will have a makefile that you can build, just cd into the example folder and type make.
13 |
14 | ### For GCC On Linux
15 | Run "premake5 gmake2". When it is done each example folder will have a makefile that you can build, just cd into the example folder and type make.
16 |
17 | ### For GCC On MacOs
18 | Run "premake5.osx gmake2". When it is done each example folder will have a makefile that you can build, just cd into the example folder and type make.
19 |
20 | # Pew
21 | A very simple game where you drive a tank around and shoot targets
22 | 
23 |
24 | # Cards
25 | An example of how to build up cards, decks, and hands and drag cards around.
26 | 
27 |
28 | # Platform Example
29 | An example of platfomer style movement, sprite animation, and state management.
30 | 
31 |
32 | # Box2d Raylib
33 | An example of using the Box2d physics library with raylib.
34 | 
35 |
36 | # Box2d Raylib Objects
37 | An more advanced example using box2d and objects
38 | 
39 |
40 | # Voxel Mesher
41 | An example of how to create blockgame (minecraft) style voxel chunk meshes.
42 |
43 | # Transform Hierarchy
44 | An example of how to use nested transforms in a parrent/child relationship to build up complex transformations. Example is a simple first person controller with an attached gun.
45 |
46 | # Hardpoints 2d
47 | An example of how to build up objects with attachment using compound transforms.
48 |
49 | # FPS collisions
50 | An example of one way to do FPS style motion and collisions.
51 |
52 | # raycaster
53 | Raylib software Raycaster similar to Wolfenstein 3D
54 | Based on algorithms from https://lodev.org/cgtutor/raycasting.html
55 |
56 | 
57 |
58 | # Inventory
59 | An example of a simple drag and drop inventory system
60 |
61 | # Skill Tree
62 | An example a skill tree type view with pan and zoom using Camera2D
63 |
64 |
--------------------------------------------------------------------------------
/_app/main.cpp:
--------------------------------------------------------------------------------
1 | #include "raylib.h"
2 |
3 | int main ()
4 | {
5 | InitWindow(1280,800,"Example");
6 |
7 | while (!WindowShouldClose())
8 | {
9 | BeginDrawing();
10 | ClearBackground(BLACK);
11 |
12 | EndDrawing();
13 | }
14 | CloseWindow();
15 | return 0;
16 | }
--------------------------------------------------------------------------------
/_app/premake5.lua:
--------------------------------------------------------------------------------
1 |
2 | baseName = path.getbasename(os.getcwd());
3 |
4 | project (baseName)
5 | kind "ConsoleApp"
6 | location "../build"
7 | targetdir "../bin/%{cfg.buildcfg}"
8 |
9 | vpaths
10 | {
11 | ["Header Files/*"] = { "**.h"},
12 | ["Source Files/*"] = {"**.c", "**.cpp"},
13 | }
14 | files {"**.c", "**.cpp", "**.h"}
15 |
16 | includedirs { "./"}
17 | setup_raylib();
--------------------------------------------------------------------------------
/box2d_raylib/README.md:
--------------------------------------------------------------------------------
1 | # Box2d Raylib
2 | An example of how to use box2d 2.x https://box2d.org/ with raylib
3 |
4 | # Box2d v3 examples
5 | https://github.com/erincatto/box2d-raylib
6 |
7 | 
8 |
--------------------------------------------------------------------------------
/box2d_raylib/box2draylib.cpp:
--------------------------------------------------------------------------------
1 | /**********************************************************************************************
2 | *
3 | * raylib-extras, examples-cpp * examples for Raylib in C++
4 | *
5 | * Box2d example
6 | *
7 | * LICENSE: MIT
8 | *
9 | * Copyright (c) 2022 Jeffery Myers
10 | *
11 | * Permission is hereby granted, free of charge, to any person obtaining a copy
12 | * of this software and associated documentation files (the "Software"), to deal
13 | * in the Software without restriction, including without limitation the rights
14 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 | * copies of the Software, and to permit persons to whom the Software is
16 | * furnished to do so, subject to the following conditions:
17 | *
18 | * The above copyright notice and this permission notice shall be included in all
19 | * copies or substantial portions of the Software.
20 | *
21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 | * SOFTWARE.
28 | *
29 | **********************************************************************************************/
30 |
31 | #include "raylib.h"
32 | #include "rlgl.h"
33 | #include "box2d/box2d.h"
34 |
35 | int main(void)
36 | {
37 | // Initialization
38 | //--------------------------------------------------------------------------------------
39 | const int screenWidth = 800;
40 | const int screenHeight = 450;
41 |
42 | // setup raylib
43 | InitWindow(screenWidth, screenHeight, "raylib example - Box2d");
44 | SetTargetFPS(60); // Set our game to run at 60 frames-per-second
45 |
46 | // setup a camera
47 | Camera2D cam = { 0 };
48 | cam.offset.y = GetScreenHeight() - 20.0f;
49 | cam.offset.x = GetScreenWidth() / 2.0f;
50 | cam.zoom = 4;
51 |
52 | // setup box2d
53 | b2Vec2 gravity(0.0f, 10.0f); // Y+ is down, so gravity is not negative
54 | b2World world(gravity);
55 |
56 | // ground box
57 | Vector2 groundSize = { 100, 2 }; // save a vector of our ground size, so we know what to draw
58 | b2BodyDef groundBodyDef;
59 | groundBodyDef.position.Set(0.0f, 0.0f);
60 | groundBodyDef.userData.pointer = uintptr_t(&groundSize);
61 | b2Body* groundBody = world.CreateBody(&groundBodyDef);
62 |
63 | b2PolygonShape groundBox;
64 | groundBox.SetAsBox(groundSize.x / 2, groundSize.y / 2);
65 | groundBody->CreateFixture(&groundBox, 0.0f);
66 |
67 | // dynamic shape
68 | Vector2 boxSize = { 10, 10 }; // save a vector of our box size, so we know what to draw
69 |
70 | b2BodyDef bodyDef;
71 | bodyDef.type = b2_dynamicBody;
72 | bodyDef.position.Set(0.0f, -50.0f);
73 | bodyDef.angle = 30 * DEG2RAD;
74 | bodyDef.userData.pointer = uintptr_t(&boxSize);
75 | b2Body* body = world.CreateBody(&bodyDef);
76 |
77 | b2PolygonShape dynamicBox;
78 | dynamicBox.SetAsBox(boxSize.x/2, boxSize.y/2);
79 |
80 | b2FixtureDef fixtureDef;
81 | fixtureDef.shape = &dynamicBox;
82 | fixtureDef.density = 1.0f;
83 | fixtureDef.friction = 0.3f;
84 |
85 | body->CreateFixture(&fixtureDef);
86 |
87 | int32 velocityIterations = 6;
88 | int32 positionIterations = 2;
89 |
90 | // Main game loop
91 | while (!WindowShouldClose()) // Detect window close button or ESC key
92 | {
93 | // apply some forces on space pressed
94 | if (IsKeyPressed(KEY_SPACE))
95 | {
96 | body->ApplyLinearImpulseToCenter(b2Vec2(0, -2000), true);
97 | body->ApplyAngularImpulse(5000, true);
98 | }
99 |
100 | // update the world for the new frame
101 | world.Step(GetFrameTime(), velocityIterations, positionIterations);
102 |
103 | BeginDrawing();
104 | ClearBackground(RAYWHITE);
105 |
106 | // set our camera
107 | BeginMode2D(cam);
108 |
109 | // draw a grid
110 | rlPushMatrix();
111 | rlRotatef(90, 1, 0, 0);
112 | DrawGrid(50, 10);
113 | rlPopMatrix();
114 |
115 | // and some axes
116 | DrawLine(0, 0, 100, 0, RED);
117 | DrawLine(0, 0, 0, -100, BLUE);
118 |
119 | // ground box
120 | // get the position and size from box2d
121 | Vector2* size = (Vector2*)groundBody->GetUserData().pointer;
122 | b2Vec2 pos = groundBody->GetPosition();
123 | Rectangle rect = { pos.x - size->x/2, pos.y - size->y/2,size->x,size->y };
124 | DrawRectangleRec(rect, BROWN);
125 |
126 | // dynamic box
127 | // get the position, rotation, and size data we saved from box2d
128 | size = (Vector2*)body->GetUserData().pointer;
129 | pos = body->GetPosition();
130 | rect = { pos.x, pos.y,size->x,size->y };
131 | DrawRectanglePro(rect, Vector2{ size->x/2, size->y/2 },body->GetAngle()* RAD2DEG, RED);
132 |
133 | EndMode2D();
134 |
135 | EndDrawing();
136 | }
137 |
138 | CloseWindow();
139 |
140 | return 0;
141 | }
--------------------------------------------------------------------------------
/box2d_raylib/premake5.lua:
--------------------------------------------------------------------------------
1 | baseName = path.getbasename(os.getcwd())
2 |
3 | defineWorkspace(baseName)
4 |
5 | project (baseName)
6 | files {"../box2d-main/include/**h", "../box2d-main/src/**.cpp", "../box2d-main/src/**.h"}
7 | includedirs {"../box2d-main/include/"}
8 | files {"../box2d/include/**h", "../box2dn/src/**.cpp", "../box2d/src/**.h"}
9 | includedirs {"../box2d/include/"}
--------------------------------------------------------------------------------
/box2d_raylib_objects/README.md:
--------------------------------------------------------------------------------
1 | # Box2d Raylib Objects
2 | A more advanced example of how to use box2d v2.x https://box2d.org/ with raylib using objects
3 |
4 | # Box2d v3 examples
5 | https://github.com/erincatto/box2d-raylib
6 |
7 | 
8 |
9 |
--------------------------------------------------------------------------------
/box2d_raylib_objects/box2draylibobjects.cpp:
--------------------------------------------------------------------------------
1 | /**********************************************************************************************
2 | *
3 | * raylib-extras, examples-cpp * examples for Raylib in C++
4 | *
5 | * Box2d advanced object example
6 | *
7 | * LICENSE: MIT
8 | *
9 | * Copyright (c) 2022 Jeffery Myers
10 | *
11 | * Permission is hereby granted, free of charge, to any person obtaining a copy
12 | * of this software and associated documentation files (the "Software"), to deal
13 | * in the Software without restriction, including without limitation the rights
14 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 | * copies of the Software, and to permit persons to whom the Software is
16 | * furnished to do so, subject to the following conditions:
17 | *
18 | * The above copyright notice and this permission notice shall be included in all
19 | * copies or substantial portions of the Software.
20 | *
21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 | * SOFTWARE.
28 | *
29 | **********************************************************************************************/
30 |
31 | #include "raylib.h"
32 | #include "rlgl.h"
33 | #include "box2d/box2d.h"
34 |
35 | #include
36 |
37 | // setup box2d
38 | b2Vec2 Gravity(0.0f, 20.0f); // Y+ is down, so gravity is not negative
39 | b2World World(Gravity);
40 |
41 | class PhysicsObject
42 | {
43 | public:
44 |
45 | b2Body* RigidBody = nullptr;
46 | Color ShapeColor = RED;
47 |
48 | virtual void Draw() = 0;
49 | };
50 |
51 | class BoxObject : public PhysicsObject
52 | {
53 | public:
54 |
55 | Vector2 Size = { 0,0 };
56 | Vector2 HalfSize = { 0,0 };
57 |
58 | b2PolygonShape Box;
59 |
60 | BoxObject(Vector2 pos, Vector2 size, Color c, float angle = 0, bool isDynamic = true)
61 | {
62 | ShapeColor = c;
63 | Size = size;
64 | HalfSize.x = size.x / 2;
65 | HalfSize.y = size.y / 2;
66 |
67 | b2BodyDef bodyDef;
68 | bodyDef.type = isDynamic ? b2_dynamicBody : b2_staticBody;
69 | bodyDef.position.Set(pos.x,pos.y);
70 | bodyDef.angle = angle * DEG2RAD;
71 | bodyDef.userData.pointer = uintptr_t(this);
72 | RigidBody = World.CreateBody(&bodyDef);
73 |
74 | Box.SetAsBox(Size.x / 2, Size.y / 2);
75 |
76 | b2FixtureDef fixtureDef;
77 | fixtureDef.shape = &Box;
78 | fixtureDef.density = 1.0f;
79 | fixtureDef.friction = 0.3f;
80 |
81 | RigidBody->CreateFixture(&fixtureDef);
82 | }
83 |
84 | void Draw() override
85 | {
86 | DrawRectanglePro(Rectangle{ RigidBody->GetPosition().x,RigidBody->GetPosition().y, Size.x, Size.y }, HalfSize, RigidBody->GetAngle() * RAD2DEG, ShapeColor);
87 | }
88 | };
89 |
90 | class BallObject : public PhysicsObject
91 | {
92 | public:
93 | float Radius = 0;
94 |
95 | b2CircleShape CircleShape;
96 |
97 | BallObject(Vector2 pos, float radius, Color c)
98 | {
99 | Radius = radius;
100 | ShapeColor = c;
101 |
102 | b2BodyDef bodyDef;
103 | bodyDef.type = b2_dynamicBody;
104 | bodyDef.position.Set(pos.x, pos.y);
105 | bodyDef.userData.pointer = uintptr_t(this);
106 | RigidBody = World.CreateBody(&bodyDef);
107 |
108 | CircleShape.m_radius = radius;
109 |
110 | b2FixtureDef fixtureDef;
111 | fixtureDef.shape = &CircleShape;
112 | fixtureDef.density = 1.0f;
113 | fixtureDef.friction = 0.3f;
114 |
115 | RigidBody->CreateFixture(&fixtureDef);
116 | }
117 |
118 | void Draw() override
119 | {
120 | DrawCircleV(Vector2{ RigidBody->GetPosition().x,RigidBody->GetPosition().y }, Radius, ShapeColor);
121 | }
122 | };
123 |
124 |
125 | std::vector Objects;
126 |
127 | int main(void)
128 | {
129 | // Initialization
130 | //--------------------------------------------------------------------------------------
131 | const int screenWidth = 800;
132 | const int screenHeight = 450;
133 |
134 | // setup raylib
135 | InitWindow(screenWidth, screenHeight, "raylib example - Box2d Objects");
136 | SetTargetFPS(60); // Set our game to run at 60 frames-per-second
137 |
138 | // setup a camera
139 | Camera2D cam = { 0 };
140 | cam.offset.y = GetScreenHeight() - 20.0f;
141 | cam.offset.x = GetScreenWidth() / 2.0f;
142 | cam.zoom = 4;
143 |
144 | BoxObject ground(Vector2{ 0,0 }, Vector2{ 200, 2 }, BROWN, 0, false);
145 |
146 | // ground box
147 | Vector2 groundSize = { 100, 2 }; // save a vector of our ground size, so we know what to draw
148 |
149 | Objects.push_back(new BoxObject(Vector2{ 0,-50 }, Vector2{ 10,10 }, RED, 45));
150 | Objects.push_back(new BoxObject(Vector2{ 20,-60 }, Vector2{ 12,8 }, GREEN, 30));
151 | Objects.push_back(new BoxObject(Vector2{ -20,-60 }, Vector2{ 8,12 }, BLUE , -30));
152 |
153 | Objects.push_back(new BallObject(Vector2{ 0, -80 },3, PURPLE));
154 |
155 | int32 velocityIterations = 6;
156 | int32 positionIterations = 2;
157 |
158 | float accumulator = 0;
159 | float physTime = 1 / 60.0f;
160 |
161 | // Main game loop
162 | while (!WindowShouldClose()) // Detect window close button or ESC key
163 | {
164 | Vector2 pos = GetScreenToWorld2D(GetMousePosition(), cam);
165 | if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT))
166 | {
167 | Objects.push_back(new BallObject(pos, 3, ORANGE));
168 | }
169 | if (IsMouseButtonPressed(MOUSE_BUTTON_RIGHT))
170 | {
171 | Objects.push_back(new BoxObject(pos, Vector2{ float(GetRandomValue(10,20)),float(GetRandomValue(10,20)) }, MAROON, float(GetRandomValue(0, 180))));
172 | }
173 |
174 | // update the world for the new frame
175 | accumulator += GetFrameTime();
176 | while (accumulator >= physTime)
177 | {
178 | accumulator -= physTime;
179 | World.Step(physTime, velocityIterations, positionIterations);
180 | }
181 |
182 | BeginDrawing();
183 | ClearBackground(RAYWHITE);
184 |
185 | // set our camera
186 | BeginMode2D(cam);
187 |
188 | // draw a grid
189 | rlPushMatrix();
190 | rlRotatef(90, 1, 0, 0);
191 | DrawGrid(50, 10);
192 | rlPopMatrix();
193 |
194 | // and some axes
195 | DrawLine(0, 0, 100, 0, RED);
196 | DrawLine(0, 0, 0, -100, BLUE);
197 |
198 | ground.Draw();
199 |
200 | for (auto object : Objects)
201 | object->Draw();
202 |
203 | EndMode2D();
204 |
205 | DrawFPS(0, 0);
206 | DrawText("Left Click to add a ball - Right Click to add a box", 100, 0, 20, BLACK);
207 | EndDrawing();
208 | }
209 |
210 | for (auto object : Objects)
211 | delete(object);
212 |
213 | CloseWindow();
214 |
215 | return 0;
216 | }
--------------------------------------------------------------------------------
/box2d_raylib_objects/premake5.lua:
--------------------------------------------------------------------------------
1 | baseName = path.getbasename(os.getcwd())
2 |
3 | defineWorkspace(baseName)
4 |
5 | project (baseName)
6 | files {"../box2d-main/include/**h", "../box2d-main/src/**.cpp", "../box2d-main/src/**.h"}
7 | includedirs {"../box2d-main/include/"}
8 | files {"../box2d/include/**h", "../box2dn/src/**.cpp", "../box2d/src/**.h"}
9 | includedirs {"../box2d/include/"}
--------------------------------------------------------------------------------
/cards/README.md:
--------------------------------------------------------------------------------
1 | # Cards-cpp
2 | A simple example of how to build up data for cards and keep them stacks and hands.
3 | Includes code to select and drag the cards around.
4 |
5 | A deck is a unquie set of cards, and owns the card data. Represents the cards in the box.
6 | A stack is a set of card pointers, used for things like draw decks. Represents a stack of some subset of the cards from a deck.
7 | A hand is a set of card pointers that are manipulatable and dragable. These represent the cards a player has drawn or are in play.
8 |
9 | 
--------------------------------------------------------------------------------
/cards/cards.cpp:
--------------------------------------------------------------------------------
1 | /**********************************************************************************************
2 | *
3 | * raylib-extras, examples-cpp * examples for Raylib in C++
4 | *
5 | * pew * an example of movement and shots
6 | *
7 | * LICENSE: MIT
8 | *
9 | * Copyright (c) 2021 Jeffery Myers
10 | *
11 | * Permission is hereby granted, free of charge, to any person obtaining a copy
12 | * of this software and associated documentation files (the "Software"), to deal
13 | * in the Software without restriction, including without limitation the rights
14 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 | * copies of the Software, and to permit persons to whom the Software is
16 | * furnished to do so, subject to the following conditions:
17 | *
18 | * The above copyright notice and this permission notice shall be included in all
19 | * copies or substantial portions of the Software.
20 | *
21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 | * SOFTWARE.
28 | *
29 | **********************************************************************************************/
30 |
31 | #include "raylib.h"
32 | #include "raymath.h"
33 |
34 | #include
35 | #include
36 |
37 | Texture CardBack;
38 |
39 | enum class CardSuit
40 | {
41 | Circle,
42 | Square,
43 | };
44 |
45 | // represents a single unique card
46 | class Card
47 | {
48 | public:
49 | Vector2 Position;
50 | CardSuit Suit = CardSuit::Circle;
51 | int Value = 0;
52 |
53 | bool FaceUp = false;
54 |
55 | Color GetCardColor()
56 | {
57 | switch (Suit)
58 | {
59 | case CardSuit::Circle:
60 | return RED;
61 | case CardSuit::Square:
62 | return BLUE;
63 | default:
64 | return BLACK;
65 | }
66 | }
67 |
68 | Rectangle GetScreenRect()
69 | {
70 | return Rectangle{ Position.x , Position.y, (float)CardBack.width, (float)CardBack.height };
71 | }
72 |
73 | void Draw()
74 | {
75 | if (FaceUp)
76 | {
77 | // draw the card face with an outline
78 | Rectangle baseRect = Rectangle{ Position.x-1 , Position.y-1, (float)CardBack.width+2, (float)CardBack.height+2 };
79 | DrawRectangleRec(baseRect, BLACK);
80 | DrawRectangleRec(GetScreenRect(), RAYWHITE);
81 |
82 | Vector2 center = { Position.x + CardBack.width / 2, Position.y + CardBack.height / 2 };
83 |
84 | DrawText(TextFormat("%d", Value), (int)center.x, (int)center.y + 55, 40, GetCardColor());
85 |
86 | switch (Suit)
87 | {
88 | case CardSuit::Circle:
89 | DrawCircle((int)center.x, (int)center.y - 40, 40, GetCardColor());
90 | break;
91 | case CardSuit::Square:
92 | DrawRectangle((int)center.x-20, (int)center.y - 60, 40, 40, GetCardColor());
93 | break;
94 | }
95 | }
96 | else
97 | {
98 | // draw the card back
99 | DrawTexture(CardBack, (int)Position.x, (int)Position.y, WHITE);
100 | }
101 | }
102 |
103 | bool PointIn(const Vector2& pos)
104 | {
105 | return CheckCollisionPointRec(pos, GetScreenRect());
106 | }
107 | };
108 |
109 | // owns a set of unique cards
110 | class Deck
111 | {
112 | public:
113 | std::vector Cards;
114 |
115 | Deck()
116 | {
117 | // build up 20 cards of each suit
118 | for (int i = 0; i < 20; i++)
119 | {
120 | Cards.emplace_back(Card{ Vector2Zero(),CardSuit::Circle,i + 1, false });
121 | Cards.emplace_back(Card{ Vector2Zero(),CardSuit::Square,i + 1, false });
122 | }
123 | }
124 | };
125 |
126 | // a stack of card pointers, used for things like draw decks and things that draw as card stack.
127 | class Stack
128 | {
129 | public:
130 | // where the stack origin is on screen
131 | Vector2 Pos = { 0 };
132 |
133 | std::vector Cards;
134 |
135 | void FromDeck(Deck& deck)
136 | {
137 | Cards.clear();
138 | for (auto& card : deck.Cards)
139 | Cards.push_back(&card);
140 | }
141 |
142 | // swaps the location of two cards
143 | void Swap(size_t a, size_t b)
144 | {
145 | Card* t = Cards[a];
146 | Cards[a] = Cards[b];
147 | Cards[b] = t;
148 | }
149 |
150 | // swaps random cards for factor * card count to try and shuffle the stack.
151 | void Shuffle( size_t factor = 4)
152 | {
153 | size_t count = Cards.size() * factor;
154 |
155 | for (size_t i = 0; i < count; i++)
156 | {
157 | size_t a = (size_t)GetRandomValue(0, (int)Cards.size() - 1);
158 | size_t b = (size_t)GetRandomValue(0, (int)Cards.size() - 1);
159 |
160 | Swap(a, b);
161 | }
162 | }
163 |
164 | Card* Top()
165 | {
166 | Card* topCard = nullptr;
167 | if (!Cards.empty())
168 | topCard = Cards[Cards.size() - 1];
169 |
170 | return topCard;
171 | }
172 |
173 | Card* PopTop()
174 | {
175 | if (Cards.empty())
176 | return nullptr;
177 |
178 | Card* topCard = Cards[Cards.size() - 1];
179 | Cards.erase(Cards.begin() + (Cards.size()-1));
180 |
181 | return topCard;
182 | }
183 |
184 | void Draw()
185 | {
186 | Rectangle baseRect = Rectangle{ Pos.x,Pos.y, (float)CardBack.width, (float)CardBack.height };
187 |
188 | // draw a gray rectangle where this stack is
189 | DrawRectangleRec(baseRect, DARKGRAY);
190 |
191 |
192 | // draw a fake 'card' for every 10 cards in the stack
193 | int stackHeight = (int)Cards.size() / 10;
194 | stackHeight *= 3;
195 |
196 | for (int i = 3; i < stackHeight; i += 3)
197 | {
198 | baseRect.x -= 3;
199 | baseRect.y -= 3;
200 | DrawRectangleRec(baseRect, (i % 6) == 0 ? DARKGRAY : GRAY );
201 | }
202 |
203 | // draw the top card
204 | Card* topCard = Top();
205 |
206 | if (topCard != nullptr)
207 | {
208 | topCard->Position.x = baseRect.x - 3;
209 | topCard->Position.y = baseRect.y - 3;
210 | topCard->Draw();
211 | }
212 | }
213 | };
214 |
215 | class Hand : public Stack
216 | {
217 | public:
218 | std::list Cards;
219 |
220 | Card* SelectedCard = nullptr;
221 |
222 | void AddCard(Card* card, bool selected = true)
223 | {
224 | Cards.emplace_back(card);
225 | if (selected)
226 | Select(card);
227 | }
228 |
229 | void Select(Card* card)
230 | {
231 | Deselect();
232 | if (card == nullptr)
233 | return;
234 |
235 | SelectedCard = card;
236 |
237 | auto itr = std::find(Cards.begin(), Cards.end(), SelectedCard);
238 | if (itr != Cards.end())
239 | Cards.erase(itr);
240 |
241 | Cards.push_back(SelectedCard);
242 |
243 | // make it look like we picked up the card
244 | SelectedCard->Position.x -= 5;
245 | SelectedCard->Position.y -= 5;
246 | }
247 |
248 | void Deselect()
249 | {
250 | if (SelectedCard != nullptr)
251 | {
252 | // make it look like we dropped the card
253 | SelectedCard->Position.x += 10;
254 | SelectedCard->Position.y += 10;
255 | }
256 | SelectedCard = nullptr;
257 | }
258 |
259 | void Draw()
260 | {
261 | for (Card* card : Cards)
262 | {
263 | if (card == SelectedCard)
264 | {
265 | // draw a shadow below the card
266 | Rectangle shadow = SelectedCard->GetScreenRect();
267 | shadow.x += 10;
268 | shadow.y += 10;
269 |
270 | DrawRectangleRec(shadow, ColorAlpha(BLACK, 0.5f));
271 |
272 | }
273 |
274 | card->Draw();
275 |
276 | }
277 | }
278 | };
279 |
280 | int main()
281 | {
282 | SetConfigFlags(FLAG_VSYNC_HINT);
283 | InitWindow(1280, 800, "Card Sample");
284 | SetTargetFPS(144);
285 |
286 | Image img = GenImageChecked(100, 200, 25, 25, RED, MAROON);
287 | CardBack = LoadTextureFromImage(img);
288 | UnloadImage(img);
289 |
290 | // all the cards in the game
291 | Deck cards;
292 |
293 | // the deck of cards we can pull from
294 | Stack DrawDeck{ 50, 50 };
295 | DrawDeck.FromDeck(cards);
296 | DrawDeck.Shuffle();
297 |
298 | // the cards we have pulled
299 | Hand PlayerHand;
300 |
301 | while (!WindowShouldClose())
302 | {
303 | bool handled = false;
304 |
305 | // check to see if we are dragging a card
306 | if (PlayerHand.SelectedCard != nullptr)
307 | {
308 | if (PlayerHand.SelectedCard->PointIn(GetMousePosition()))
309 | {
310 | if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
311 | PlayerHand.SelectedCard->Position = Vector2Add(PlayerHand.SelectedCard->Position, GetMouseDelta());
312 | else
313 | PlayerHand.Deselect();
314 | handled = true;
315 | }
316 | }
317 | else if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) // check to see if we are selecting a card from the hand
318 | {
319 | for (auto itr = PlayerHand.Cards.rbegin(); itr != PlayerHand.Cards.rend(); itr++ )
320 | {
321 | auto* card = *itr;
322 | if (card->PointIn(GetMousePosition()))
323 | {
324 | // activate this card so we can start dragging it.
325 | PlayerHand.Select(card);
326 | break;
327 | }
328 | }
329 | }
330 |
331 | // check to see if we are interacting with the draw deck
332 | if (!handled)
333 | {
334 | Card* deckTop = DrawDeck.Top();
335 | if (deckTop != nullptr)
336 | {
337 | if (deckTop->PointIn(GetMousePosition()))
338 | {
339 | if (IsMouseButtonPressed(MOUSE_RIGHT_BUTTON))
340 | {
341 | // show the top card
342 | deckTop->FaceUp = true;
343 | }
344 | else if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON) && PlayerHand.SelectedCard == nullptr)
345 | {
346 | // take the card into a hand and start dragging it.
347 | PlayerHand.AddCard(DrawDeck.PopTop());
348 |
349 | // always show the face of drawn cards
350 | PlayerHand.SelectedCard->FaceUp = true;
351 | }
352 | }
353 | }
354 | }
355 |
356 | BeginDrawing();
357 | ClearBackground(DARKGREEN);
358 |
359 | DrawText("DECK", int(DrawDeck.Pos.x), int(DrawDeck.Pos.y - 40), 20, PINK);
360 | DrawDeck.Draw();
361 | PlayerHand.Draw();
362 |
363 | EndDrawing();
364 | }
365 |
366 | CloseWindow();
367 | return 0;
368 | }
--------------------------------------------------------------------------------
/cards/premake5.lua:
--------------------------------------------------------------------------------
1 |
2 | baseName = path.getbasename(os.getcwd())
3 |
4 | defineWorkspace(baseName)
--------------------------------------------------------------------------------
/chunked_procgen/Chunk.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "raylib.h"
4 |
5 | #include
6 | #include
7 |
8 | struct ChunkOrigin
9 | {
10 | int32_t X;
11 | int32_t Y;
12 |
13 | uint64_t GetId() const
14 | {
15 | return (uint64_t(X) << 32) | uint64_t(Y);
16 | }
17 |
18 | bool operator<(const ChunkOrigin& o) const
19 | {
20 | return GetId() < o.GetId();
21 | }
22 |
23 | ChunkOrigin() = default;
24 |
25 | ChunkOrigin(int32_t x, int32_t y)
26 | {
27 | X = x;
28 | Y = y;
29 | }
30 |
31 | // Arithmetic operators for ChunkOrigin
32 | ChunkOrigin operator+(const ChunkOrigin& other) const
33 | {
34 | return ChunkOrigin(X + other.X, Y + other.Y);
35 | }
36 |
37 | ChunkOrigin operator-(const ChunkOrigin& other) const
38 | {
39 | return ChunkOrigin(X - other.X, Y - other.Y);
40 | }
41 |
42 | ChunkOrigin operator*(int32_t scalar) const
43 | {
44 | return ChunkOrigin(X * scalar, Y * scalar);
45 | }
46 |
47 | ChunkOrigin operator/(int32_t scalar) const
48 | {
49 | return ChunkOrigin(X / scalar, Y / scalar);
50 | }
51 |
52 | ChunkOrigin& operator+=(const ChunkOrigin& other)
53 | {
54 | X += other.X;
55 | Y += other.Y;
56 | return *this;
57 | }
58 |
59 | ChunkOrigin& operator-=(const ChunkOrigin& other)
60 | {
61 | X -= other.X;
62 | Y -= other.Y;
63 | return *this;
64 | }
65 |
66 | ChunkOrigin& operator*=(int32_t scalar)
67 | {
68 | X *= scalar;
69 | Y *= scalar;
70 | return *this;
71 | }
72 |
73 | ChunkOrigin& operator/=(int32_t scalar)
74 | {
75 | X /= scalar;
76 | Y /= scalar;
77 | return *this;
78 | }
79 |
80 | bool operator==(const ChunkOrigin& other) const
81 | {
82 | if (X == other.X && Y == other.Y)
83 | return true;
84 | else
85 | return false;
86 | }
87 |
88 | struct Hasher
89 | {
90 | size_t operator()(const ChunkOrigin& k) const
91 | {
92 | return size_t(k.GetId());
93 | }
94 | };
95 | };
96 |
97 | template <>
98 | struct std::hash
99 | {
100 | std::size_t operator()(const ChunkOrigin& k) const
101 | {
102 | return size_t(k.GetId());
103 | }
104 | };
105 |
106 | enum class ChunkState
107 | {
108 | Ungenerated,
109 | Generated,
110 | Cached,
111 | };
112 |
113 | struct ChunkRenderInfo
114 | {
115 | RenderTexture2D BaseLayer;
116 | RenderTexture2D OverlayLayer;
117 | };
118 |
119 |
120 | struct Chunk
121 | {
122 | ChunkOrigin Origin;
123 |
124 | ChunkRenderInfo* RenderInfo = nullptr;
125 | std::vector Tiles;
126 |
127 | std::mutex Mutex;
128 |
129 | ChunkState State = ChunkState::Ungenerated;
130 |
131 | Chunk(int32_t x, int32_t y)
132 | {
133 | Origin.X = x;
134 | Origin.Y = y;
135 | Tiles.resize(16 * 16);
136 | }
137 |
138 | Chunk(ChunkOrigin origin)
139 | {
140 | Origin = origin;
141 | Tiles.resize(16 * 16);
142 | }
143 |
144 | ChunkState GetState()
145 | {
146 | std::lock_guard lock(Mutex);
147 | return State;
148 | }
149 | };
--------------------------------------------------------------------------------
/chunked_procgen/README.md:
--------------------------------------------------------------------------------
1 | # Chunked Procedural Generation
2 | Shows how to generate a procedural world that is very large, larger than would be possible with regular floating point values.
3 |
4 | Only the chunks around the player are generated and stored in render textures.
5 | The system uses a floating origin, keeping the player relative to the nearest chunk so that it does not get floating point resolution errors.
--------------------------------------------------------------------------------
/chunked_procgen/RenderArea.cpp:
--------------------------------------------------------------------------------
1 | #include "RenderArea.h"
2 |
3 | #include
4 |
5 | RenderLoop::RenderLoop(uint32_t size) : Size(size)
6 | {
7 | if (size == 0)
8 | {
9 | Chunks.insert_or_assign(ChunkOrigin(0,0), nullptr);
10 | }
11 |
12 | int bounds = int(size);
13 | for (int x = -bounds; x <= bounds; x++)
14 | {
15 | Chunks.insert_or_assign(ChunkOrigin(x, bounds), nullptr);
16 | Chunks.insert_or_assign(ChunkOrigin(x, -bounds), nullptr);
17 | }
18 |
19 | for (int y = -bounds +1; y < bounds; y++)
20 | {
21 | Chunks.insert_or_assign(ChunkOrigin(bounds, y), nullptr);
22 | Chunks.insert_or_assign(ChunkOrigin(-bounds, y), nullptr);
23 | }
24 | }
25 |
26 | Chunk* RenderLoop::GetChunk(int32_t x, int32_t y)
27 | {
28 | int32_t max = std::max(std::abs(x), std::abs(y));
29 |
30 | if (max != Size)
31 | return nullptr;
32 |
33 | return Chunks[ChunkOrigin(x, y)];
34 | }
35 |
36 | void RenderLoop::SetChunk(int32_t x, int32_t y, Chunk* chunk)
37 | {
38 | int32_t max = std::max(std::abs(x), std::abs(y));
39 |
40 | if (max != Size)
41 | return;
42 |
43 | Chunks[ChunkOrigin(x, y)] = chunk;
44 | }
45 |
46 | RenderArea::RenderArea(uint32_t size)
47 | {
48 | for (uint32_t i = 0; i <= size; i++)
49 | Loops.emplace_back(i);
50 | }
51 |
52 | Chunk* RenderArea::GetChunk(int32_t x, int32_t y)
53 | {
54 | int32_t max = std::max(std::abs(x), std::abs(y));
55 |
56 | if (max > Loops.size())
57 | return nullptr;
58 |
59 | return Loops[max].GetChunk(x, y);
60 | }
61 |
62 | void RenderArea::SetChunk(int32_t x, int32_t y, Chunk* chunk)
63 | {
64 | int32_t max = std::max(std::abs(x), std::abs(y));
65 |
66 | if (max > Loops.size())
67 | return;
68 |
69 | return Loops[max].SetChunk(x, y, chunk);
70 | }
71 |
72 | RenderAreaManager::RenderAreaManager(uint32_t size, int32_t orignX, int32_t originY) : Area(size)
73 | {
74 | Origin = ChunkOrigin(orignX, originY);
75 |
76 | int RenderTextureSize = 256;
77 |
78 | for (auto& loop : Area.Loops)
79 | {
80 | for (auto& [chunkOrigin, chunkInfo] : loop.Chunks)
81 | {
82 | UndefinedChunks[chunkOrigin] = Origin + chunkOrigin;
83 | }
84 | }
85 | }
86 |
87 | void RenderAreaManager::MoveOrigin(int32_t x, int32_t y)
88 | {
89 | int32_t size = int32_t(Area.Loops.size()) - 1;
90 |
91 | // origin sifts right (X+), so shift everything left (x-)
92 | while (x > 0)
93 | {
94 | for (int currentY = -size; currentY <= size; currentY++)
95 | {
96 | for (int currentX = -size; currentX <= size; currentX++)
97 | {
98 | Chunk* chunk = Area.GetChunk(currentX, currentY);
99 |
100 | ChunkOrigin currentOrigin(currentX, currentY);
101 |
102 | // first chunk on the left side is destroyed
103 | if (currentX == -size)
104 | {
105 | if (chunk != nullptr)
106 | DeadChunks.push_back(chunk);
107 |
108 | Area.SetChunk(currentX, currentY, nullptr);
109 | continue;
110 | }
111 |
112 | // move this chunk to the left one slot, and clear it
113 | Area.SetChunk(currentX - 1, currentY, chunk);
114 | Area.SetChunk(currentX, currentY, nullptr);
115 |
116 | if (currentX == size)
117 | {
118 | // the last chunk on the right needs to be generated
119 | UndefinedChunks[currentOrigin] = Origin + currentOrigin + ChunkOrigin(1,0);
120 | }
121 | }
122 | }
123 | Origin.X += 1;
124 | x -= 1;
125 | }
126 |
127 | // origin sifts left (X-), so shift everything right (x+)
128 | while (x < 0)
129 | {
130 | for (int currentY = -size; currentY <= size; currentY++)
131 | {
132 | for (int currentX = size; currentX >= -size; currentX--)
133 | {
134 | Chunk* chunk = Area.GetChunk(currentX, currentY);
135 |
136 | ChunkOrigin currentOrigin(currentX, currentY);
137 |
138 | // first chunk on the right side is destroyed
139 | if (currentX == size)
140 | {
141 | if (chunk != nullptr)
142 | DeadChunks.push_back(chunk);
143 |
144 | Area.SetChunk(currentX, currentY, nullptr);
145 | continue;
146 | }
147 |
148 | // move this chunk to the right one slot, and clear it
149 | Area.SetChunk(currentX + 1, currentY, chunk);
150 | Area.SetChunk(currentX, currentY, nullptr);
151 |
152 | if (currentX == -size)
153 | {
154 | // the last chunk on the left needs to be generated
155 | UndefinedChunks[currentOrigin] = Origin + currentOrigin + ChunkOrigin(-1, 0);
156 | }
157 | }
158 | }
159 | Origin.X -= 1;
160 | x += 1;
161 | }
162 |
163 | // origin sifts down (Y+), so shift everything up (y-)
164 | while (y > 0)
165 | {
166 | for (int currentX = -size; currentX <= size; currentX++)
167 | {
168 | for (int currentY = -size; currentY <= size; currentY++)
169 | {
170 | Chunk* chunk = Area.GetChunk(currentX, currentY);
171 |
172 | ChunkOrigin currentOrigin(currentX, currentY);
173 |
174 | // first chunk on the top side is destroyed
175 | if (currentY == -size)
176 | {
177 | if (chunk != nullptr)
178 | DeadChunks.push_back(chunk);
179 |
180 | Area.SetChunk(currentX, currentY, nullptr);
181 | continue;
182 | }
183 |
184 | // move this chunk to the up one slot, and clear it
185 | Area.SetChunk(currentX, currentY-1, chunk);
186 | Area.SetChunk(currentX, currentY, nullptr);
187 |
188 | if (currentY == size)
189 | {
190 | // the last chunk on the bottom needs to be generated
191 | UndefinedChunks[currentOrigin] = Origin + currentOrigin + ChunkOrigin(0, 1);
192 | }
193 | }
194 | }
195 | Origin.Y += 1;
196 | y -= 1;
197 | }
198 |
199 | // origin sifts up (Y-), so shift everything down (y+)
200 | while (y < 0)
201 | {
202 | for (int currentX = -size; currentX <= size; currentX++)
203 | {
204 | for (int currentY = size; currentY >= -size; currentY--)
205 | {
206 | Chunk* chunk = Area.GetChunk(currentX, currentY);
207 |
208 | ChunkOrigin currentOrigin(currentX, currentY);
209 |
210 | // first chunk on the bottom side is destroyed
211 | if (currentY == size)
212 | {
213 | if (chunk != nullptr)
214 | DeadChunks.push_back(chunk);
215 |
216 | Area.SetChunk(currentX, currentY, nullptr);
217 | continue;
218 | }
219 |
220 | // move this chunk to the right one slot, and clear it
221 | Area.SetChunk(currentX, currentY+1, chunk);
222 | Area.SetChunk(currentX, currentY, nullptr);
223 |
224 | if (currentY == -size)
225 | {
226 | // the last chunk on the left needs to be generated
227 | UndefinedChunks[currentOrigin] = Origin + currentOrigin + ChunkOrigin(0, -1);
228 | }
229 | }
230 | }
231 | Origin.Y -= 1;
232 | y += 1;
233 | }
234 | }
235 |
--------------------------------------------------------------------------------
/chunked_procgen/RenderArea.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "Chunk.h"
4 |
5 | #include
6 |
7 | struct RenderLoop
8 | {
9 | uint32_t Size = 0;
10 | std::unordered_map Chunks;
11 |
12 | RenderLoop(uint32_t size);
13 |
14 | Chunk* GetChunk(int32_t x, int32_t y);
15 |
16 | void SetChunk(int32_t x, int32_t y, Chunk* chunk);
17 | };
18 |
19 | struct RenderArea
20 | {
21 | std::vector Loops;
22 |
23 | Chunk* GetChunk(int32_t x, int32_t y);
24 |
25 | void SetChunk(int32_t x, int32_t y, Chunk* chunk);
26 |
27 | RenderArea(uint32_t size);
28 | };
29 |
30 | class RenderAreaManager
31 | {
32 | public:
33 | RenderAreaManager(uint32_t size, int32_t originX = 0, int32_t originY = 0);
34 |
35 | std::unordered_map UndefinedChunks;
36 | std::vector DeadChunks;
37 |
38 | RenderArea Area;
39 | ChunkOrigin Origin;
40 |
41 | void MoveOrigin(int32_t x, int32_t y);
42 | };
--------------------------------------------------------------------------------
/chunked_procgen/main.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | Raylib example file.
3 | This is an example main file for a simple raylib project.
4 | Use this as a starting point or replace it with your code.
5 |
6 | by Jeffery Myers is marked with CC0 1.0. To view a copy of this license, visit https://creativecommons.org/publicdomain/zero/1.0/
7 |
8 | */
9 |
10 | #include "raylib.h"
11 | #include "raymath.h"
12 |
13 | #include "resource_dir.h" // utility header for SearchAndSetResourceDir
14 |
15 | #include "RenderArea.h"
16 |
17 | #include "external/stb_perlin.h"
18 |
19 | int ScaleToDPI(int x)
20 | {
21 | return int(x * GetWindowScaleDPI().x);
22 | }
23 |
24 | float ScaleToDPI(float x)
25 | {
26 | return float(x * GetWindowScaleDPI().x);
27 | }
28 |
29 | Vector2 ScaleToDPI(const Vector2& x)
30 | {
31 | return x * GetWindowScaleDPI();
32 | }
33 |
34 | std::vector ChunkTextureCache;
35 | std::vector AvailableChunkTextures;
36 |
37 | Vector2 PlayerPos = { 0,0 };
38 |
39 | ChunkOrigin CurrentChunk(0, 0);
40 |
41 | int main()
42 | {
43 | // Tell the window to use vsync and work on high DPI displays
44 | SetConfigFlags(FLAG_VSYNC_HINT);
45 |
46 | // Create the window and OpenGL context
47 | InitWindow(1280, 800, "Hello Chunks");
48 |
49 | // Utility function from resource_dir.h to find the resources folder and set it as the current working directory so we can load from it
50 | SearchAndSetResourceDir("resources");
51 |
52 | // Load a texture from the resources directory
53 | Texture wabbit = LoadTexture("wabbit_alpha.png");
54 |
55 | constexpr int renderDistance = 3;
56 |
57 | RenderAreaManager renderArea(renderDistance);
58 |
59 | for (auto& loop : renderArea.Area.Loops)
60 | {
61 | for (auto& [chunkOrigin, chunkInfo] : loop.Chunks)
62 | {
63 | auto& chunkInfo = ChunkTextureCache.emplace_back();
64 | chunkInfo.BaseLayer = LoadRenderTexture(256, 256);
65 | SetTextureWrap(chunkInfo.BaseLayer.texture, TEXTURE_WRAP_CLAMP);
66 | }
67 | }
68 |
69 | for (auto& chunkInfo : ChunkTextureCache)
70 | {
71 | AvailableChunkTextures.push_back(&chunkInfo);
72 | }
73 |
74 | bool forceGenerate = true;
75 | constexpr float chunkSize = 256.0f;
76 |
77 | constexpr float chunkTileCount = 16;
78 |
79 | Camera2D camera = { 0 };
80 | camera.zoom = 1.0f;
81 | camera.offset = { float(GetScreenWidth() / 2), float(GetScreenHeight() / 2) };
82 |
83 | Color ringColors[6] = { RED, DARKGRAY, DARKBLUE, ORANGE, DARKPURPLE, DARKBROWN };
84 |
85 | // game loop
86 | while (!WindowShouldClose()) // run the loop until the user presses ESCAPE or presses the Close button on the window
87 | {
88 | float speed = 200.0f * GetFrameTime();
89 | if (IsKeyDown(KEY_LEFT_SHIFT) || IsKeyDown(KEY_RIGHT_SHIFT))
90 | speed *= 10;
91 |
92 | if (IsKeyDown(KEY_D))
93 | PlayerPos.x += speed;
94 | if (IsKeyDown(KEY_A))
95 | PlayerPos.x -= speed;
96 |
97 | if (IsKeyDown(KEY_S))
98 | PlayerPos.y += speed;
99 | if (IsKeyDown(KEY_W))
100 | PlayerPos.y -= speed;
101 |
102 | camera.zoom += (GetMouseWheelMove() * 0.1f);
103 | if (camera.zoom < 0.1f)
104 | camera.zoom = 0.1f;
105 |
106 | float halfChunkSize = chunkSize * 0.5f;
107 |
108 | if (PlayerPos.x > halfChunkSize)
109 | {
110 | renderArea.MoveOrigin(1, 0);
111 | PlayerPos.x -= chunkSize;
112 | CurrentChunk.X += 1;
113 | }
114 | else if (PlayerPos.x < -halfChunkSize)
115 | {
116 | renderArea.MoveOrigin(-1, 0);
117 | PlayerPos.x += chunkSize;
118 | CurrentChunk.X += -1;
119 | }
120 |
121 | if (PlayerPos.y > halfChunkSize)
122 | {
123 | renderArea.MoveOrigin(0, 1);
124 | PlayerPos.y -= chunkSize;
125 | CurrentChunk.Y += 1;
126 | }
127 | else if (PlayerPos.y < -halfChunkSize)
128 | {
129 | renderArea.MoveOrigin(0, -1);
130 | PlayerPos.y += chunkSize;
131 | CurrentChunk.Y += -1;
132 | }
133 |
134 | if (!renderArea.UndefinedChunks.empty())
135 | {
136 | forceGenerate = false;
137 |
138 | for (auto dead : renderArea.DeadChunks)
139 | {
140 | AvailableChunkTextures.push_back(dead->RenderInfo);
141 | delete dead;
142 | }
143 | renderArea.DeadChunks.clear();
144 |
145 | for (const auto& [relative, global] : renderArea.UndefinedChunks)
146 | {
147 | auto* chunk = new Chunk(global);
148 | renderArea.Area.SetChunk(relative.X,relative.Y, chunk);
149 |
150 | for (int y = 0; y < 16; y++)
151 | {
152 | for (int x = 0; x < 16; x++)
153 | {
154 | float noiseX = global.X + (1.0f/16 * x);
155 | float noiseY = global.Y + (1.0f / 16 * y);
156 |
157 | float value = (stb_perlin_fbm_noise3(noiseX, noiseY, 1.0f, 2.0f, 0.5f, 6) + 1) * 0.49f;
158 |
159 | int index = int(std::floor(value * 3));
160 |
161 | chunk->Tiles[y * 16 + x] = index;
162 | }
163 | }
164 |
165 | chunk->RenderInfo = AvailableChunkTextures.back();
166 | AvailableChunkTextures.pop_back();
167 |
168 | BeginTextureMode(chunk->RenderInfo->BaseLayer);
169 | ClearBackground(MAGENTA);
170 | for (int y = 0; y < 16; y++)
171 | {
172 | for (int x = 0; x < 16; x++)
173 | {
174 | int index = chunk->Tiles[y * 16 + x];
175 |
176 | Color color = BLANK;
177 | switch (index)
178 | {
179 | default:
180 | color = PURPLE;
181 | break;
182 | case 0:
183 | color = BLUE;
184 | break;
185 |
186 | case 1:
187 | color = DARKBROWN;
188 | break;
189 |
190 | case 2:
191 | color = DARKGREEN;
192 | break;
193 | }
194 | DrawRectangle(x * 16, y * 16, 16, 16, color);
195 | }
196 | }
197 | EndTextureMode();
198 | }
199 | renderArea.UndefinedChunks.clear();
200 | }
201 | // drawing
202 | BeginDrawing();
203 |
204 | // Setup the back buffer for drawing (clear color and depth buffers)
205 | ClearBackground(BLACK);
206 |
207 | camera.target = PlayerPos;
208 |
209 | BeginMode2D(camera);
210 | int loopIndex = 0;
211 | for (auto& loop : renderArea.Area.Loops)
212 | {
213 | for (const auto& [relativeOrigin, chunk] : loop.Chunks)
214 | {
215 | Vector2 pos = { 0,0 };
216 | pos.x = relativeOrigin.X * chunkSize;
217 | pos.y = relativeOrigin.Y * chunkSize;
218 |
219 | Rectangle rec = { pos.x-chunkSize*0.5f, pos.y - chunkSize * 0.5f, chunkSize, chunkSize };
220 |
221 | if (chunk != nullptr)
222 | {
223 | DrawTexturePro(chunk->RenderInfo->BaseLayer.texture, Rectangle{ 0,0,256,-256 }, rec, Vector2Zeros, 0, WHITE);
224 | }
225 | else
226 | {
227 | DrawRectangleRec(rec, ringColors[loopIndex]);
228 | }
229 |
230 | DrawRectangleLinesEx(rec, 3.0f, ringColors[loopIndex]);
231 |
232 | DrawText(TextFormat("R(%i,%i)", relativeOrigin.X, relativeOrigin.Y), int(pos.x) - 20, int(pos.y) - 10, 10, WHITE);
233 |
234 | if (chunk != nullptr)
235 | {
236 | DrawText(TextFormat("O[%i,%i]", chunk->Origin.X, chunk->Origin.Y), int(pos.x) - 20, int(pos.y + 20) - 10, 10, SKYBLUE);
237 | }
238 |
239 | DrawTexturePro(wabbit,
240 | Rectangle{ 0,0,float(wabbit.width),float(wabbit.height) },
241 | Rectangle{ PlayerPos.x, PlayerPos.y, float(wabbit.width), float(wabbit.height) },
242 | Vector2{ wabbit.width *0.5f, wabbit.height *0.5f},
243 | 0,
244 | WHITE);
245 |
246 | }
247 | loopIndex++;
248 | }
249 | EndMode2D();
250 |
251 | DrawFPS(10, 10);
252 |
253 | DrawRectangle(10, 30, 300, 80, ColorAlpha(WHITE, 0.5f));
254 | DrawText(TextFormat("Current Chunk[%i,%i]", CurrentChunk.X, CurrentChunk.Y), 20, 40, 20, BLACK);
255 |
256 | double realX = double(CurrentChunk.X) * chunkSize + PlayerPos.x;
257 | double realY = double(CurrentChunk.Y) * chunkSize + PlayerPos.y;
258 | DrawText(TextFormat("Real Pos[%0.2lf,%0.2lf]", realX, realY), 20, 60, 20, BLACK);
259 |
260 | DrawText(TextFormat("Local Pos[%0.2f,%0.2f]", PlayerPos.x, PlayerPos.x), 20, 80, 20, BLACK);
261 | EndDrawing();
262 | }
263 |
264 | // cleanup
265 | // unload our texture so it can be cleaned up
266 | UnloadTexture(wabbit);
267 |
268 | // destroy the window and cleanup the OpenGL context
269 | CloseWindow();
270 | return 0;
271 | }
272 |
--------------------------------------------------------------------------------
/chunked_procgen/premake5.lua:
--------------------------------------------------------------------------------
1 |
2 | baseName = path.getbasename(os.getcwd())
3 |
4 | defineWorkspace(baseName)
--------------------------------------------------------------------------------
/chunked_procgen/resource_dir.h:
--------------------------------------------------------------------------------
1 | /**********************************************************************************************
2 | *
3 | * raylibExtras * Utilities and Shared Components for Raylib
4 | *
5 | * Resource Dir * function to help find resource dir in common locations
6 | *
7 | * LICENSE: MIT
8 | *
9 | * Copyright (c) 2022 Jeffery Myers
10 | *
11 | * Permission is hereby granted, free of charge, to any person obtaining a copy
12 | * of this software and associated documentation files (the "Software"), to deal
13 | * in the Software without restriction, including without limitation the rights
14 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 | * copies of the Software, and to permit persons to whom the Software is
16 | * furnished to do so, subject to the following conditions:
17 | *
18 | * The above copyright notice and this permission notice shall be included in all
19 | * copies or substantial portions of the Software.
20 | *
21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 | * SOFTWARE.
28 | *
29 | **********************************************************************************************/
30 |
31 | #pragma once
32 |
33 | #include "raylib.h"
34 |
35 | #if defined(__cplusplus)
36 | extern "C" { // Prevents name mangling of functions
37 | #endif
38 | ///
39 | /// Looks for the specified resource dir in several common locations
40 | /// The working dir
41 | /// The app dir
42 | /// Up to 3 levels above the app dir
43 | /// When found the dir will be set as the working dir so that assets can be loaded relative to that.
44 | ///
45 | /// The name of the resources dir to look for
46 | /// True if a dir with the name was found, false if no change was made to the working dir
47 | inline static bool SearchAndSetResourceDir(const char* folderName)
48 | {
49 | // check the working dir
50 | if (DirectoryExists(folderName))
51 | {
52 | ChangeDirectory(TextFormat("%s/%s", GetWorkingDirectory(), folderName));
53 | return true;
54 | }
55 |
56 | const char* appDir = GetApplicationDirectory();
57 |
58 | // check the applicationDir
59 | const char* dir = TextFormat("%s%s", appDir, folderName);
60 | if (DirectoryExists(dir))
61 | {
62 | ChangeDirectory(dir);
63 | return true;
64 | }
65 |
66 | // check one up from the app dir
67 | dir = TextFormat("%s../%s", appDir, folderName);
68 | if (DirectoryExists(dir))
69 | {
70 | ChangeDirectory(dir);
71 | return true;
72 | }
73 |
74 | // check two up from the app dir
75 | dir = TextFormat("%s../../%s", appDir, folderName);
76 | if (DirectoryExists(dir))
77 | {
78 | ChangeDirectory(dir);
79 | return true;
80 | }
81 |
82 | // check three up from the app dir
83 | dir = TextFormat("%s../../../%s", appDir, folderName);
84 | if (DirectoryExists(dir))
85 | {
86 | ChangeDirectory(dir);
87 | return true;
88 | }
89 |
90 | return false;
91 | }
92 |
93 | #if defined(__cplusplus)
94 | }
95 | #endif
--------------------------------------------------------------------------------
/chunked_procgen/resources/wabbit_alpha.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/raylib-extras/examples-cpp/935b48d6f5fe597bd805c30355a193aef7d0e8fe/chunked_procgen/resources/wabbit_alpha.png
--------------------------------------------------------------------------------
/fps_collisions/README.md:
--------------------------------------------------------------------------------
1 | # fps collsion example
2 | A very simple demo that shows a simple version of FPS style collisions.
3 |
4 | The world is made of obstacles that are transformed in 3d space. Collisions are done on the axis alligned bounding box (AABB) for each object.
5 | Colliding things are transformed into the rotated object's space and then tested, that way simple AABB tests can be used for rotated objects.
6 | Both cylinder and ray collisions are shown in the example
--------------------------------------------------------------------------------
/fps_collisions/colisions.cpp:
--------------------------------------------------------------------------------
1 | /*********************************************************************************************
2 | *
3 | * raylib-extras, FPS collision example
4 | *
5 | * LICENSE: MIT
6 | *
7 | * Copyright (c) 2024 Jeffery Myers
8 | *
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy
10 | * of this software and associated documentation files (the "Software"), to deal
11 | * in the Software without restriction, including without limitation the rights
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | * copies of the Software, and to permit persons to whom the Software is
14 | * furnished to do so, subject to the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be included in all
17 | * copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 | * SOFTWARE.
26 | *
27 | **********************************************************************************************/
28 |
29 | #include
30 |
31 | #include "collisions.h"
32 | #include "raylib.h"
33 | #include "raymath.h"
34 |
35 | // check if a cylinder hits a bounding box
36 | bool IntersectBBoxCylinder(BoundingBox bounds, Vector3& center, Vector3 initalPosition, float radius, float height, Vector3& intersectionPoint, Vector3& hitNormal)
37 | {
38 | Rectangle rect = { bounds.min.x, bounds.min.z, bounds.max.x - bounds.min.x, bounds.max.z - bounds.min.z };
39 | Vector2 center2d = { center.x, center.z };
40 |
41 | if (!CheckCollisionCircleRec(center2d, radius, rect))
42 | return false;
43 |
44 | // we are above or below
45 | if (center.y > bounds.max.y)
46 | return false;
47 |
48 | if (center.y + height < bounds.min.y)
49 | return false;
50 |
51 |
52 | // see if we landed on top
53 | if (center.y <= bounds.max.y && initalPosition.y > bounds.max.y && initalPosition.y > center.y)
54 | {
55 | // we have hit the top of the obstacle, so clamp our position to where we hit that Y
56 | Vector3 movementVec = Vector3Subtract(center, initalPosition);
57 |
58 | float yParam = (initalPosition.y - bounds.max.y) / movementVec.y;
59 | movementVec = Vector3Scale(movementVec, yParam);
60 | center = Vector3Add(initalPosition, movementVec);
61 | intersectionPoint = center;
62 | hitNormal = Vector3{ 0,1,0 };
63 | return true;
64 | }
65 |
66 | // see if we hit the bottom
67 | float centerTop = center.y + height;
68 | float oldTop = initalPosition.y + height;
69 |
70 | if (centerTop >= bounds.min.y && oldTop < bounds.min.y && initalPosition.y < center.y)
71 | {
72 | // simple situation of
73 | center = initalPosition;
74 | intersectionPoint = center;
75 | hitNormal = Vector3{ 0,-1,0 };
76 | return true;
77 | }
78 |
79 | Vector2 newPosOrigin = { center.x, center.z };
80 | Vector2 hitPoint = { std::numeric_limits::min(), std::numeric_limits::min() };
81 | Vector2 hitNormal2d = { 0 };
82 |
83 | PointNearestRectanglePoint(rect, newPosOrigin, hitPoint, hitNormal2d);
84 |
85 | Vector2 vectorToHit = Vector2Subtract(hitPoint, newPosOrigin);
86 |
87 | if (Vector2LengthSqr(vectorToHit) >= radius * radius)
88 | return false;
89 |
90 | intersectionPoint = Vector3{ hitPoint.x, center.y, hitPoint.y };
91 | hitNormal = Vector3{ hitNormal2d.x, 0, hitNormal2d.y };
92 |
93 | // normalize the vector along the point to where we are nearest
94 | vectorToHit = Vector2Normalize(vectorToHit);
95 |
96 | // project that out to the radius to find the point that should be 'deepest' into the rectangle.
97 | Vector2 projectedPoint = Vector2Add(newPosOrigin, Vector2Scale(vectorToHit, radius));
98 |
99 | // compute the shift to take the deepest point out to the edge of our nearest hit, based on the vector direction
100 | Vector2 delta = { 0,0 };
101 |
102 | if (hitNormal.x != 0)
103 | delta.x = hitPoint.x - projectedPoint.x;
104 | else
105 | delta.y = hitPoint.y - projectedPoint.y;
106 |
107 | // shift the new point by the delta to push us outside of the rectangle
108 | newPosOrigin = Vector2Add(newPosOrigin, delta);
109 |
110 | center = Vector3{ newPosOrigin.x, center.y, newPosOrigin.y };
111 | return true;
112 | }
113 |
114 | ///
115 | /// Returns the point on a rectangle that is nearest to a provided point
116 | ///
117 | /// The rectangle to test against
118 | /// The point you want to start from
119 | /// A pointer that will be filed out with the point on the rectangle that is nearest to your passed in point
120 | /// A pointer that will be filed out with the the normal of the edge the nearest point is on
121 | void PointNearestRectanglePoint(Rectangle rect, Vector2 point, Vector2& nearest, Vector2& normal)
122 | {
123 | // get the closest point on the vertical sides
124 | float hValue = rect.x;
125 | float hNormal = -1;
126 | if (point.x > rect.x + rect.width)
127 | {
128 | hValue = rect.x + rect.width;
129 | hNormal = 1;
130 | }
131 |
132 | Vector2 vecToPoint = Vector2Subtract(Vector2{ hValue, rect.y }, point);
133 | // get the dot product between the ray and the vector to the point
134 | float dotForPoint = Vector2DotProduct(Vector2{ 0, -1 }, vecToPoint);
135 | Vector2 nearestPoint = { hValue, 0 };
136 |
137 | if (dotForPoint < 0)
138 | nearestPoint.y = rect.y;
139 | else if (dotForPoint >= rect.height)
140 | nearestPoint.y = rect.y + rect.height;
141 | else
142 | nearestPoint.y = rect.y + dotForPoint;
143 |
144 | // get the closest point on the horizontal sides
145 | float vValue = rect.y;
146 | float vNormal = -1;
147 | if (point.y > rect.y + rect.height)
148 | {
149 | vValue = rect.y + rect.height;
150 | vNormal = 1;
151 | }
152 |
153 | vecToPoint = Vector2Subtract(Vector2{ rect.x, vValue }, point);
154 | // get the dot product between the ray and the vector to the point
155 | dotForPoint = Vector2DotProduct(Vector2{ -1, 0 }, vecToPoint);
156 | nearest = Vector2{ 0,vValue };
157 |
158 | if (dotForPoint < 0)
159 | nearest.x = rect.x;
160 | else if (dotForPoint >= rect.width)
161 | nearest.x = rect.x + rect.width;
162 | else
163 | nearest.x = rect.x + dotForPoint;
164 |
165 | if (Vector2LengthSqr(Vector2Subtract(point, nearestPoint)) <= Vector2LengthSqr(Vector2Subtract(point, nearest)))
166 | {
167 | nearest = nearestPoint;
168 | normal.x = hNormal;
169 | normal.y = 0;
170 | }
171 | else
172 | {
173 | normal.y = vNormal;
174 | normal.x = 0;
175 | }
176 | }
--------------------------------------------------------------------------------
/fps_collisions/hud.cpp:
--------------------------------------------------------------------------------
1 | /*********************************************************************************************
2 | *
3 | * raylib-extras, FPS collision example
4 | *
5 | * LICENSE: MIT
6 | *
7 | * Copyright (c) 2024 Jeffery Myers
8 | *
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy
10 | * of this software and associated documentation files (the "Software"), to deal
11 | * in the Software without restriction, including without limitation the rights
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | * copies of the Software, and to permit persons to whom the Software is
14 | * furnished to do so, subject to the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be included in all
17 | * copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 | * SOFTWARE.
26 | *
27 | **********************************************************************************************/
28 |
29 | #include "hud.h"
30 | #include "raylib.h"
31 |
32 | namespace HUD
33 | {
34 | static RenderTexture MiniMapRenderTexture = { 0 };
35 |
36 | constexpr int MiniMapSize = 250;
37 |
38 | void SetupGraphics()
39 | {
40 | if (!IsRenderTextureValid(MiniMapRenderTexture))
41 | MiniMapRenderTexture = LoadRenderTexture(MiniMapSize, MiniMapSize);
42 | }
43 |
44 | void CleanupGraphics()
45 | {
46 | if (IsRenderTextureValid(MiniMapRenderTexture))
47 | UnloadRenderTexture(MiniMapRenderTexture);
48 |
49 | MiniMapRenderTexture.id = 0;
50 | }
51 |
52 | void UpdateMiniMapTexture(Map& map, PlayerInfo& player)
53 | {
54 | Camera3D camera = { 0 };
55 | camera.up.z = 1;
56 | camera.position = player.ViewCamera.position;
57 | camera.position.y = 100;
58 | camera.target = player.ViewCamera.position;
59 | camera.target.y = 0;
60 | camera.fovy = 30;
61 | camera.projection = CAMERA_ORTHOGRAPHIC;
62 |
63 | BeginTextureMode(MiniMapRenderTexture);
64 | ClearBackground(ColorAlpha(BLACK, 0.25f));
65 | BeginMode3D(camera);
66 |
67 | map.DrawWalls(camera);
68 |
69 | DrawCube(Vector3Zero(), 1, 1, 1, RED);
70 |
71 | EndMode3D();
72 |
73 | Vector2 center = Vector2{ MiniMapRenderTexture.texture.width * 0.5f, MiniMapRenderTexture.texture.height * 0.5f };
74 |
75 | DrawCircleV(center, 3, DARKBLUE);
76 | Vector2 viewVec = Vector2Normalize(Vector2{ player.ViewCamera.target.x - player.ViewCamera.position.x,player.ViewCamera.target.z - player.ViewCamera.position.z });
77 | viewVec = Vector2Scale(viewVec, -30);
78 | DrawLineV(center, Vector2Add(center, viewVec), SKYBLUE);
79 |
80 | EndTextureMode();
81 | }
82 |
83 | void Draw(Map& map, PlayerInfo& player)
84 | {
85 | UpdateMiniMapTexture(map, player);
86 |
87 | DrawTextureRec(MiniMapRenderTexture.texture, Rectangle{ 0,0, float(MiniMapRenderTexture.texture.width), -float(MiniMapRenderTexture.texture.height) }, Vector2{ float(GetScreenWidth() - MiniMapRenderTexture.texture.width), 0 }, WHITE);
88 |
89 | DrawCircle(GetScreenWidth() / 2, GetScreenHeight() / 2, 2, ColorAlpha(WHITE, 0.75f));
90 | DrawFPS(10, 10);
91 |
92 | DrawText("WADS to move, left click to shoot", 100, 10, 10, BLACK);
93 | #ifdef _DEBUG
94 | DrawText("Hold Right Mouse to Rotate View", 100, 20, 10, BLACK);
95 | #endif // _DEBUG
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/fps_collisions/include/collisions.h:
--------------------------------------------------------------------------------
1 | /*********************************************************************************************
2 | *
3 | * raylib-extras, FPS collision example
4 | *
5 | * LICENSE: MIT
6 | *
7 | * Copyright (c) 2024 Jeffery Myers
8 | *
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy
10 | * of this software and associated documentation files (the "Software"), to deal
11 | * in the Software without restriction, including without limitation the rights
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | * copies of the Software, and to permit persons to whom the Software is
14 | * furnished to do so, subject to the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be included in all
17 | * copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 | * SOFTWARE.
26 | *
27 | **********************************************************************************************/
28 |
29 | #pragma once
30 |
31 | #include "raylib.h"
32 |
33 | void PointNearestRectanglePoint(Rectangle rect, Vector2 point, Vector2& nearest, Vector2& normal);
34 | bool IntersectBBoxCylinder(BoundingBox bounds, Vector3& center, Vector3 initalPosition, float radius, float height, Vector3& intersectionPoint, Vector3& hitNormal);
--------------------------------------------------------------------------------
/fps_collisions/include/hud.h:
--------------------------------------------------------------------------------
1 | /*********************************************************************************************
2 | *
3 | * raylib-extras, FPS collision example
4 | *
5 | * LICENSE: MIT
6 | *
7 | * Copyright (c) 2024 Jeffery Myers
8 | *
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy
10 | * of this software and associated documentation files (the "Software"), to deal
11 | * in the Software without restriction, including without limitation the rights
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | * copies of the Software, and to permit persons to whom the Software is
14 | * furnished to do so, subject to the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be included in all
17 | * copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 | * SOFTWARE.
26 | *
27 | **********************************************************************************************/
28 |
29 | #pragma once
30 |
31 | #include "map.h"
32 | #include "player.h"
33 |
34 | namespace HUD
35 | {
36 | void SetupGraphics();
37 | void CleanupGraphics();
38 | void Draw(Map& map, PlayerInfo& player);
39 | }
40 |
--------------------------------------------------------------------------------
/fps_collisions/include/map.h:
--------------------------------------------------------------------------------
1 |
2 | /*********************************************************************************************
3 | *
4 | * raylib-extras, FPS collision example
5 | *
6 | * LICENSE: MIT
7 | *
8 | * Copyright (c) 2024 Jeffery Myers
9 | *
10 | * Permission is hereby granted, free of charge, to any person obtaining a copy
11 | * of this software and associated documentation files (the "Software"), to deal
12 | * in the Software without restriction, including without limitation the rights
13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | * copies of the Software, and to permit persons to whom the Software is
15 | * furnished to do so, subject to the following conditions:
16 | *
17 | * The above copyright notice and this permission notice shall be included in all
18 | * copies or substantial portions of the Software.
19 | *
20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 | * SOFTWARE.
27 | *
28 | **********************************************************************************************/
29 |
30 | #pragma once
31 |
32 | #include "object_transform.h"
33 | #include
34 | #include
35 |
36 | class Obstacle
37 | {
38 | public:
39 | ObjectTransform Transform;
40 | Vector3 Scale = { 1, 1, 1 };
41 | Color Tint = DARKGREEN;
42 |
43 | Vector3 thing{ 1,2,2 };
44 |
45 | Vector3 LastNearestPoint = { 0,0 };
46 |
47 | BoundingBox Bounds = { 0 };
48 |
49 | Obstacle() = default;
50 | Obstacle(float x, float z, float width, float height, float depth, float angle);
51 | bool CollideWithPlayer(Vector3& newPosition, Vector3 oldPosition, float radius, float height);
52 |
53 | bool CheckRaycast(Ray worldRay, RayCollision& collision);
54 | };
55 |
56 | struct Explosion
57 | {
58 | Vector3 Postion = { 0 };
59 | Vector3 Normal = { 0 };
60 | float Lifetime = 0;
61 |
62 | static constexpr float MaxLife = 0.25f;
63 | };
64 |
65 | class Map
66 | {
67 | public:
68 | std::vector Walls;
69 | std::deque Explosions;
70 |
71 | static void SetupGraphics();
72 | static void CleanupGraphics();
73 | static Shader GetLightShader();
74 |
75 | void Setup();
76 | void Cleanup();
77 |
78 | bool CollidePlayer(Vector3& newPosition, Vector3 oldPosition, float radius, float height);
79 | bool CollideRay(Ray worldspaceRay, RayCollision& outputCollision, Obstacle* hitObstacle = nullptr);
80 |
81 | void Draw(Camera3D& view);
82 | void DrawWalls(Camera3D& view);
83 |
84 | void AddExplosition(RayCollision& collision);
85 |
86 | void AddShotSound();
87 |
88 | private:
89 | static constexpr int MaxSounds = 32;
90 |
91 | Sound ShotSound = { 0 };
92 | Sound ShotLoop[MaxSounds] = { 0 };
93 | int CurrentShotSound = 0;
94 | };
95 |
96 |
97 | void BuildDemoMap(Map& map);
--------------------------------------------------------------------------------
/fps_collisions/include/object_transform.h:
--------------------------------------------------------------------------------
1 | /**********************************************************************************************
2 | *
3 | * object_transform.h * a sample 3d object transfrom class
4 | *
5 | * LICENSE: ZLIB
6 | *
7 | * Copyright (c) 2024 Jeffery Myers
8 | *
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy
10 | * of this software and associated documentation files (the "Software"), to deal
11 | * in the Software without restriction, including without limitation the rights
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | * copies of the Software, and to permit persons to whom the Software is
14 | * furnished to do so, subject to the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be included in all
17 | * copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 | * SOFTWARE.
26 | *
27 | **********************************************************************************************/
28 |
29 | #pragma once
30 |
31 | #include "raylib.h"
32 | #include "raymath.h"
33 | #include "rlgl.h"
34 |
35 | #include
36 | #include
37 |
38 | class ObjectTransform
39 | {
40 | private:
41 | Vector3 Position = { 0 };
42 | Quaternion Orientation = QuaternionIdentity();
43 |
44 | bool Dirty = true;
45 |
46 | Matrix WorldMatrix = { 0 };
47 | Matrix GlWorldMatrix = { 0 };
48 |
49 | ObjectTransform* Parent = nullptr;
50 | std::vector Children;
51 |
52 | public:
53 |
54 | ObjectTransform(bool faceY = true)
55 | {
56 | if (faceY)
57 | Orientation = QuaternionFromAxisAngle(Vector3{ 0,1,0 }, 0);
58 | }
59 |
60 | virtual ~ObjectTransform() = default;
61 |
62 | ObjectTransform* GetParent() const { return Parent; }
63 |
64 | const std::vector& GetChildren() const { return Children; }
65 |
66 | Quaternion GetOrientation() const { return Orientation; }
67 |
68 | ObjectTransform* AddChild(ObjectTransform* child)
69 | {
70 | if (!child)
71 | return nullptr;
72 |
73 | child->Reparent(this);
74 |
75 | return child;
76 | }
77 |
78 | ObjectTransform& AddChild(ObjectTransform& child)
79 | {
80 | child.Reparent(this);
81 |
82 | return child;
83 | }
84 |
85 | void Reparent(ObjectTransform* newParent)
86 | {
87 | if (Parent == newParent)
88 | return;
89 |
90 | if (newParent)
91 | {
92 | auto child = std::find(newParent->Children.begin(), newParent->Children.end(), this);
93 | if (child != newParent->Children.end())
94 | newParent->Children.erase(child);
95 | }
96 |
97 | Parent = newParent;
98 | if (Parent)
99 | Parent->Children.push_back(this);
100 | }
101 |
102 | void Detach()
103 | {
104 | if (!GetParent())
105 | return;
106 |
107 | Matrix worldTransform = GetWorldMatrix();
108 | Position = Vector3Transform(Vector3Zero(), WorldMatrix);
109 |
110 | Matrix translateMatrix = MatrixTranslate(Position.x, Position.y, Position.z);
111 | Matrix orientationMatrix = MatrixMultiply(worldTransform, translateMatrix);
112 |
113 | Orientation = QuaternionFromMatrix(WorldMatrix);
114 |
115 | Reparent(nullptr);
116 | }
117 |
118 | void SetDirty()
119 | {
120 | Dirty = true;
121 | for (ObjectTransform* childTransform : Children)
122 | {
123 | if (childTransform != nullptr)
124 | childTransform->SetDirty();
125 | }
126 | }
127 |
128 | const Vector3& GetPosition() const { return Position; }
129 |
130 | Vector3 GetEulerAngles() const
131 | {
132 | return QuaternionToEuler(Orientation);
133 | }
134 |
135 | Vector3 GetDVector() const
136 | {
137 | return Vector3Transform(Vector3{ 0, 0, 1 }, MatrixInvert(QuaternionToMatrix(Orientation)));
138 | }
139 |
140 | Vector3 GeVVector() const
141 | {
142 | return Vector3Transform(Vector3{ 0, 1, 0 }, MatrixInvert(QuaternionToMatrix(Orientation)));
143 | }
144 |
145 | Vector3 GetHNegVector() const
146 | {
147 | return Vector3CrossProduct(GeVVector(), GetDVector());
148 | }
149 |
150 | Vector3 GetHPosVector() const
151 | {
152 | return Vector3CrossProduct(GetDVector(), GeVVector());
153 | }
154 |
155 | Vector3 GetWorldPosition()
156 | {
157 | return Vector3Transform(Vector3Zero(), GetWorldMatrix());
158 | }
159 |
160 | Vector3 GetWorldTargetPoint()
161 | {
162 | return Vector3Transform(Vector3{ 0,1,0 }, GetWorldMatrix());
163 | }
164 |
165 | void SetPosition(float x, float y, float z)
166 | {
167 | Position.x = x;
168 | Position.y = y;
169 | Position.z = z;
170 | SetDirty();
171 | }
172 |
173 | void MovePosition(float x, float y, float z)
174 | {
175 | Position.x += x;
176 | Position.y += y;
177 | Position.z += z;
178 | SetDirty();
179 | }
180 |
181 | void SetPosition(const Vector3& pos)
182 | {
183 | Position = pos;
184 | SetDirty();
185 | }
186 |
187 | void SetOrientation(const Vector3& eulerAngles)
188 | {
189 | Vector3 angles = Vector3Scale(eulerAngles, DEG2RAD);
190 | Orientation = QuaternionFromEuler(angles.x, angles.y, angles.z);
191 | SetDirty();
192 | }
193 |
194 | bool IsDirty() const
195 | {
196 | return Dirty;
197 | }
198 |
199 | void LookAt(const Vector3& target, const Vector3& up)
200 | {
201 | SetDirty();
202 | Matrix mat = MatrixLookAt(Position, target, up);
203 | Orientation = QuaternionFromMatrix(mat);
204 | }
205 |
206 | Matrix GetLocalMatrix() const
207 | {
208 | Matrix orient = QuaternionToMatrix(Orientation);
209 | Matrix translation = MatrixTranslate(Position.x, Position.y, Position.z);
210 |
211 | return MatrixMultiply(MatrixInvert(orient), translation);
212 | }
213 |
214 | void UpdateWorldMatrix()
215 | {
216 | Matrix parentMatrix = MatrixIdentity();
217 |
218 | if (Parent)
219 | parentMatrix = Parent->GetWorldMatrix();
220 |
221 | WorldMatrix = MatrixMultiply(GetLocalMatrix(), parentMatrix);
222 | GlWorldMatrix = MatrixTranspose(WorldMatrix);
223 |
224 | Dirty = false;
225 | }
226 |
227 | const Matrix& GetWorldMatrix()
228 | {
229 | if (!IsDirty())
230 | return WorldMatrix;
231 |
232 | UpdateWorldMatrix();
233 | return WorldMatrix;
234 | }
235 |
236 | const Matrix& GetGLWorldMatrix()
237 | {
238 | if (!IsDirty())
239 | return GlWorldMatrix;
240 |
241 | UpdateWorldMatrix();
242 | return GlWorldMatrix;
243 | }
244 |
245 | Vector3 ToLocalPos(const Vector3& inPos)
246 | {
247 | return Vector3Transform(inPos, MatrixInvert(GetWorldMatrix()));
248 | }
249 |
250 | void MoveV(float distance)
251 | {
252 | SetDirty();
253 | Position = Vector3Add(Position, Vector3Scale(GeVVector(), distance));
254 | }
255 |
256 | void MoveD(float distance)
257 | {
258 | SetDirty();
259 | Position = Vector3Add(Position, Vector3Scale(GetDVector(), distance));
260 | }
261 |
262 | void MoveH(float distance)
263 | {
264 | SetDirty();
265 | Position = Vector3Add(Position, Vector3Scale(GetHNegVector(), distance));
266 | }
267 |
268 | void SetV(float value)
269 | {
270 | SetDirty();
271 | Position.y = value;
272 | }
273 |
274 | void SetD(float value)
275 | {
276 | SetDirty();
277 | Position.z = value;
278 | }
279 |
280 | void SeteH(float value)
281 | {
282 | SetDirty();
283 | Position.x = value;
284 | }
285 |
286 | void RotateY(float angle)
287 | {
288 | SetDirty();
289 | auto rot = QuaternionFromEuler(0, -angle * DEG2RAD, 0);
290 | Orientation = QuaternionMultiply(Orientation, rot);
291 | }
292 |
293 | void RotateX(float angle)
294 | {
295 | SetDirty();
296 | auto rot = QuaternionFromEuler(angle * DEG2RAD, 0, 0);
297 | Orientation = QuaternionMultiply(Orientation, rot);
298 | }
299 |
300 | void RotateZ(float angle)
301 | {
302 | SetDirty();
303 | auto rot = QuaternionFromEuler(0, 0, -angle * DEG2RAD);
304 | Orientation = QuaternionMultiply(Orientation, rot);
305 | }
306 |
307 | void RotateH(float angle)
308 | {
309 | SetDirty();
310 | auto rot = QuaternionFromEuler(angle * DEG2RAD, 0, 0);
311 | Orientation = QuaternionMultiply(rot, Orientation);
312 | }
313 |
314 | void RotateV(float angle)
315 | {
316 | SetDirty();
317 | auto rot = QuaternionFromEuler(0, -angle * DEG2RAD, 0);
318 | Orientation = QuaternionMultiply(rot, Orientation);
319 | }
320 |
321 | void RotateD(float angle)
322 | {
323 | SetDirty();
324 | auto rot = QuaternionFromEuler(0, 0, -angle * DEG2RAD);
325 | Orientation = QuaternionMultiply(rot, Orientation);
326 | }
327 |
328 | void SetCamera(Camera3D& camera)
329 | {
330 | camera.position = Vector3Transform(Vector3Zero(), GetWorldMatrix());
331 | camera.target = Vector3Transform(Vector3{ 0,0,1 }, WorldMatrix);
332 | camera.up = Vector3Subtract(Vector3Transform(Vector3{ 0,1,0 }, WorldMatrix), camera.target);
333 | }
334 |
335 | void PushMatrix()
336 | {
337 | const Matrix& glMatrix = GetGLWorldMatrix();
338 | rlPushMatrix();
339 | rlMultMatrixf((float*)(&glMatrix.m0));
340 | }
341 |
342 | void PopMatrix()
343 | {
344 | rlPopMatrix();
345 | }
346 | };
--------------------------------------------------------------------------------
/fps_collisions/include/player.h:
--------------------------------------------------------------------------------
1 | /*********************************************************************************************
2 | *
3 | * raylib-extras, FPS collision example
4 | *
5 | * LICENSE: MIT
6 | *
7 | * Copyright (c) 2024 Jeffery Myers
8 | *
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy
10 | * of this software and associated documentation files (the "Software"), to deal
11 | * in the Software without restriction, including without limitation the rights
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | * copies of the Software, and to permit persons to whom the Software is
14 | * furnished to do so, subject to the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be included in all
17 | * copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 | * SOFTWARE.
26 | *
27 | **********************************************************************************************/
28 |
29 | #pragma once
30 |
31 | #include "object_transform.h"
32 | #include "map.h"
33 |
34 | struct PlayerInfo
35 | {
36 | static constexpr float GunDefaultH = -0.25f;
37 | static constexpr float GunDefaultV = -0.5f;
38 | static constexpr float GunDefaultD = 1.5f;
39 |
40 | static constexpr float CollisionRadius = 1.5f;
41 |
42 | static constexpr float ReloadTime = 0.1f;
43 | static constexpr float RecoilDistance = -0.125f;
44 |
45 | ObjectTransform PlayerNode;
46 | ObjectTransform CameraNode;
47 | ObjectTransform ShoulderNode;
48 | ObjectTransform GunNode;
49 |
50 | Camera3D ViewCamera = { 0 };
51 |
52 | float TitltAngle = 0;
53 |
54 | Vector3 DesiredMovement = { 0 };
55 |
56 | float Speed = 30.0f;
57 |
58 | bool HitLastFrame = false;
59 |
60 | float BobbleTime = 0;
61 |
62 | RayCollision LastGunCollision = { 0 };
63 |
64 | float Reload = 0;
65 |
66 | static void SetupGraphics();
67 | static void CleanupGraphics();
68 |
69 | void Setup();
70 |
71 | void Update(Map& map);
72 |
73 | void Draw();
74 | };
--------------------------------------------------------------------------------
/fps_collisions/include/rlights.h:
--------------------------------------------------------------------------------
1 | /**********************************************************************************************
2 | *
3 | * raylib.lights - Some useful functions to deal with lights data
4 | *
5 | * CONFIGURATION:
6 | *
7 | * #define RLIGHTS_IMPLEMENTATION
8 | * Generates the implementation of the library into the included file.
9 | * If not defined, the library is in header only mode and can be included in other headers
10 | * or source files without problems. But only ONE file should hold the implementation.
11 | *
12 | * LICENSE: zlib/libpng
13 | *
14 | * Copyright (c) 2017-2023 Victor Fisac (@victorfisac) and Ramon Santamaria (@raysan5)
15 | *
16 | * This software is provided "as-is", without any express or implied warranty. In no event
17 | * will the authors be held liable for any damages arising from the use of this software.
18 | *
19 | * Permission is granted to anyone to use this software for any purpose, including commercial
20 | * applications, and to alter it and redistribute it freely, subject to the following restrictions:
21 | *
22 | * 1. The origin of this software must not be misrepresented; you must not claim that you
23 | * wrote the original software. If you use this software in a product, an acknowledgment
24 | * in the product documentation would be appreciated but is not required.
25 | *
26 | * 2. Altered source versions must be plainly marked as such, and must not be misrepresented
27 | * as being the original software.
28 | *
29 | * 3. This notice may not be removed or altered from any source distribution.
30 | *
31 | **********************************************************************************************/
32 |
33 | #ifndef RLIGHTS_H
34 | #define RLIGHTS_H
35 |
36 | //----------------------------------------------------------------------------------
37 | // Defines and Macros
38 | //----------------------------------------------------------------------------------
39 | #define MAX_LIGHTS 4 // Max dynamic lights supported by shader
40 |
41 | //----------------------------------------------------------------------------------
42 | // Types and Structures Definition
43 | //----------------------------------------------------------------------------------
44 |
45 | // Light data
46 | typedef struct {
47 | int type;
48 | bool enabled;
49 | Vector3 position;
50 | Vector3 target;
51 | Color color;
52 | float attenuation;
53 |
54 | // Shader locations
55 | int enabledLoc;
56 | int typeLoc;
57 | int positionLoc;
58 | int targetLoc;
59 | int colorLoc;
60 | int attenuationLoc;
61 | } Light;
62 |
63 | // Light type
64 | typedef enum {
65 | LIGHT_DIRECTIONAL = 0,
66 | LIGHT_POINT
67 | } LightType;
68 |
69 | #ifdef __cplusplus
70 | extern "C" { // Prevents name mangling of functions
71 | #endif
72 |
73 | //----------------------------------------------------------------------------------
74 | // Module Functions Declaration
75 | //----------------------------------------------------------------------------------
76 | Light CreateLight(int type, Vector3 position, Vector3 target, Color color, Shader shader); // Create a light and get shader locations
77 | void UpdateLightValues(Shader shader, Light light); // Send light properties to shader
78 |
79 | #ifdef __cplusplus
80 | }
81 | #endif
82 |
83 | #endif // RLIGHTS_H
84 |
85 |
86 | /***********************************************************************************
87 | *
88 | * RLIGHTS IMPLEMENTATION
89 | *
90 | ************************************************************************************/
91 |
92 | #if defined(RLIGHTS_IMPLEMENTATION)
93 |
94 | #include "raylib.h"
95 |
96 | //----------------------------------------------------------------------------------
97 | // Defines and Macros
98 | //----------------------------------------------------------------------------------
99 | // ...
100 |
101 | //----------------------------------------------------------------------------------
102 | // Types and Structures Definition
103 | //----------------------------------------------------------------------------------
104 | // ...
105 |
106 | //----------------------------------------------------------------------------------
107 | // Global Variables Definition
108 | //----------------------------------------------------------------------------------
109 | static int lightsCount = 0; // Current amount of created lights
110 |
111 | //----------------------------------------------------------------------------------
112 | // Module specific Functions Declaration
113 | //----------------------------------------------------------------------------------
114 | // ...
115 |
116 | //----------------------------------------------------------------------------------
117 | // Module Functions Definition
118 | //----------------------------------------------------------------------------------
119 |
120 | // Create a light and get shader locations
121 | Light CreateLight(int type, Vector3 position, Vector3 target, Color color, Shader shader)
122 | {
123 | Light light = { 0 };
124 |
125 | if (lightsCount < MAX_LIGHTS)
126 | {
127 | light.enabled = true;
128 | light.type = type;
129 | light.position = position;
130 | light.target = target;
131 | light.color = color;
132 |
133 | // NOTE: Lighting shader naming must be the provided ones
134 | light.enabledLoc = GetShaderLocation(shader, TextFormat("lights[%i].enabled", lightsCount));
135 | light.typeLoc = GetShaderLocation(shader, TextFormat("lights[%i].type", lightsCount));
136 | light.positionLoc = GetShaderLocation(shader, TextFormat("lights[%i].position", lightsCount));
137 | light.targetLoc = GetShaderLocation(shader, TextFormat("lights[%i].target", lightsCount));
138 | light.colorLoc = GetShaderLocation(shader, TextFormat("lights[%i].color", lightsCount));
139 |
140 | UpdateLightValues(shader, light);
141 |
142 | lightsCount++;
143 | }
144 |
145 | return light;
146 | }
147 |
148 | // Send light properties to shader
149 | // NOTE: Light shader locations should be available
150 | void UpdateLightValues(Shader shader, Light light)
151 | {
152 | // Send to shader light enabled state and type
153 | SetShaderValue(shader, light.enabledLoc, &light.enabled, SHADER_UNIFORM_INT);
154 | SetShaderValue(shader, light.typeLoc, &light.type, SHADER_UNIFORM_INT);
155 |
156 | // Send to shader light position values
157 | float position[3] = { light.position.x, light.position.y, light.position.z };
158 | SetShaderValue(shader, light.positionLoc, position, SHADER_UNIFORM_VEC3);
159 |
160 | // Send to shader light target position values
161 | float target[3] = { light.target.x, light.target.y, light.target.z };
162 | SetShaderValue(shader, light.targetLoc, target, SHADER_UNIFORM_VEC3);
163 |
164 | // Send to shader light color values
165 | float color[4] = { (float)light.color.r/(float)255, (float)light.color.g/(float)255,
166 | (float)light.color.b/(float)255, (float)light.color.a/(float)255 };
167 | SetShaderValue(shader, light.colorLoc, color, SHADER_UNIFORM_VEC4);
168 | }
169 |
170 | #endif // RLIGHTS_IMPLEMENTATION
--------------------------------------------------------------------------------
/fps_collisions/main.cpp:
--------------------------------------------------------------------------------
1 | /**********************************************************************************************
2 | *
3 | * raylib-extras, FPS collision example
4 | *
5 | * LICENSE: MIT
6 | *
7 | * Copyright (c) 2024 Jeffery Myers
8 | *
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy
10 | * of this software and associated documentation files (the "Software"), to deal
11 | * in the Software without restriction, including without limitation the rights
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | * copies of the Software, and to permit persons to whom the Software is
14 | * furnished to do so, subject to the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be included in all
17 | * copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 | * SOFTWARE.
26 | *
27 | **********************************************************************************************/
28 |
29 | #include "raylib.h"
30 |
31 | #include "collisions.h"
32 | #include "hud.h"
33 | #include "map.h"
34 | #include "object_transform.h"
35 | #include "player.h"
36 |
37 | // global player
38 | PlayerInfo Player;
39 |
40 | RenderTexture OverlayTexture = { 0 };
41 |
42 | void GameInit(Map &map)
43 | {
44 | InitAudioDevice();
45 |
46 | Map::SetupGraphics();
47 | PlayerInfo::SetupGraphics();
48 | HUD::SetupGraphics();
49 |
50 | OverlayTexture = LoadRenderTexture(GetScreenWidth(), GetScreenHeight());
51 |
52 | BuildDemoMap(map);
53 |
54 | map.Setup();
55 | Player.Setup();
56 | }
57 |
58 | void GameCleanup(Map& map)
59 | {
60 | map.Cleanup();
61 | Map::CleanupGraphics();
62 | PlayerInfo::CleanupGraphics();
63 | HUD::CleanupGraphics();
64 | }
65 |
66 | bool GameUpdate(Map& map)
67 | {
68 | Player.Update(map);
69 |
70 | return true;
71 | }
72 |
73 | void Draw3D(Map& map)
74 | {
75 | BeginMode3D(Player.ViewCamera);
76 | map.Draw(Player.ViewCamera);
77 | EndMode3D();
78 |
79 | BeginTextureMode(OverlayTexture);
80 | ClearBackground(BLANK);
81 | BeginMode3D(Player.ViewCamera);
82 | Player.Draw();
83 |
84 | EndMode3D();
85 | EndTextureMode();
86 | DrawTextureRec(OverlayTexture.texture, Rectangle{ 0,0, float(GetScreenWidth()), -float(GetScreenHeight()) }, Vector2Zeros, WHITE);
87 | }
88 |
89 | void GameDraw(Map& map)
90 | {
91 | if (IsWindowResized())
92 | {
93 | UnloadRenderTexture(OverlayTexture);
94 | OverlayTexture = LoadRenderTexture(GetScreenWidth(), GetScreenHeight());
95 | }
96 |
97 | BeginDrawing();
98 | ClearBackground(SKYBLUE);
99 |
100 | Draw3D(map);
101 |
102 | HUD::Draw(map, Player);
103 |
104 | EndDrawing();
105 | }
106 |
107 | int main()
108 | {
109 | SetConfigFlags(FLAG_VSYNC_HINT | FLAG_WINDOW_RESIZABLE);
110 | InitWindow(1280, 800, "FPS Collisions");
111 | SetTargetFPS(144);
112 |
113 | Map map;
114 |
115 | GameInit(map);
116 |
117 | while (!WindowShouldClose())
118 | {
119 | if (!GameUpdate(map))
120 | break;
121 |
122 | GameDraw(map);
123 | }
124 |
125 | GameCleanup(map);
126 | CloseWindow();
127 | return 0;
128 | }
129 |
--------------------------------------------------------------------------------
/fps_collisions/map.cpp:
--------------------------------------------------------------------------------
1 |
2 | /*********************************************************************************************
3 | *
4 | * raylib-extras, FPS collision example
5 | *
6 | * LICENSE: MIT
7 | *
8 | * Copyright (c) 2024 Jeffery Myers
9 | *
10 | * Permission is hereby granted, free of charge, to any person obtaining a copy
11 | * of this software and associated documentation files (the "Software"), to deal
12 | * in the Software without restriction, including without limitation the rights
13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | * copies of the Software, and to permit persons to whom the Software is
15 | * furnished to do so, subject to the following conditions:
16 | *
17 | * The above copyright notice and this permission notice shall be included in all
18 | * copies or substantial portions of the Software.
19 | *
20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 | * SOFTWARE.
27 | *
28 | **********************************************************************************************/
29 |
30 | #include "map.h"
31 | #include "collisions.h"
32 |
33 | #define RLIGHTS_IMPLEMENTATION
34 | #include "rlights.h"
35 |
36 | // obstacle
37 | Obstacle::Obstacle(float x, float z, float width, float height, float depth, float angle)
38 | {
39 | Transform.SetPosition(x, height * 0.5f, z);
40 | Transform.RotateV(angle);
41 | Scale.x = width;
42 | Scale.y = height;
43 | Scale.z = depth;
44 |
45 | Bounds.min = Vector3{ width * -0.5f, height * -0.5f, depth * -0.5f };
46 | Bounds.max = Vector3{ width * 0.5f, height * 0.5f, depth * 0.5f };
47 | }
48 |
49 | bool Obstacle::CollideWithPlayer(Vector3& newPosition, Vector3 oldPosition, float radius, float height)
50 | {
51 | // transform the input into the rotated space of the obstacle
52 | Matrix objectMatrix = Transform.GetWorldMatrix();
53 | Vector3 localPos = Vector3Transform(newPosition, MatrixInvert(objectMatrix));
54 | Vector3 locaOldPos = Vector3Transform(oldPosition, MatrixInvert(objectMatrix));
55 |
56 | Vector3 hitNormal = { 0 };
57 |
58 | // see if the player cylinder (in local space) hits our bounding box, and clamp the position to be outside of it
59 | bool hit = IntersectBBoxCylinder(Bounds, localPos, locaOldPos, radius, height, LastNearestPoint, hitNormal);
60 |
61 | // transform the local position back into worldspace
62 | newPosition = Vector3Transform(localPos, objectMatrix);
63 |
64 | return hit;
65 | }
66 |
67 | bool Obstacle::CheckRaycast(Ray worldRay, RayCollision & collision)
68 | {
69 | // transform the ray into local space
70 | Matrix objectMatrix = Transform.GetWorldMatrix();
71 | Ray localRay = { 0 };
72 | localRay.position = Vector3Transform(worldRay.position, MatrixInvert(objectMatrix));
73 | localRay.direction = Vector3Transform(Vector3Add(worldRay.position, worldRay.direction), MatrixInvert(objectMatrix));
74 | localRay.direction = Vector3Subtract(localRay.direction, localRay.position);
75 |
76 | // see if the local space ray hits our bounding box
77 | collision = GetRayCollisionBox(localRay, Bounds);
78 |
79 |
80 | // transform the hit point and normal back into world space
81 | if (collision.hit)
82 | {
83 | collision.point = Vector3Transform(collision.point, objectMatrix);
84 | collision.normal = Vector3RotateByQuaternion(collision.normal, Transform.GetOrientation());
85 | }
86 |
87 | return collision.hit;
88 | }
89 |
90 | // map graphics
91 | static Mesh WallMesh = { 0 };
92 | static Mesh PlaneMesh = { 0 };
93 |
94 | static Material WallMaterial = { 0 };
95 | static Material PlaneMaterial = { 0 };
96 |
97 | void BuildDemoMap(Map& map)
98 | {
99 | map.Walls.emplace_back(10.0f, 10.0f, 3.5f, 3.0f, 14.0f, 0.0f);
100 | map.Walls.emplace_back(20.0f, 10.0f, 0.5f, 3.0f, 15.0f, 90.0f);
101 | map.Walls.emplace_back(-20.0f, 10.0f, 0.5f, 3.0f, 15.0f, 45.0f);
102 | map.Walls.emplace_back(-20.0f, 10.0f, 0.5f, 3.0f, 15.0f, -45.0f);
103 |
104 | map.Walls.emplace_back(20.0f, -10.0f, 2.5f, 3.0f, 25.0f, 30.0f);
105 |
106 | map.Walls.emplace_back(0.0f, -20.0f, 1.5f, 3.0f, 35.0f, 90.0f);
107 | }
108 |
109 |
110 | // map
111 | void Map::SetupGraphics()
112 | {
113 | CleanupGraphics();
114 |
115 | WallMesh = GenMeshCube(1, 1, 1);
116 | WallMaterial = LoadMaterialDefault();
117 | WallMaterial.shader = LoadShader("resources/shaders/lighting.vs", "resources/shaders/lighting.fs");
118 | WallMaterial.shader.locs[SHADER_LOC_VECTOR_VIEW] = GetShaderLocation(WallMaterial.shader, "viewPos");
119 |
120 | CreateLight(LIGHT_POINT, Vector3{ -200, 100, -200 }, Vector3Zero(), WHITE, WallMaterial.shader);
121 |
122 | // Ambient light level (some basic lighting)
123 | int ambientLoc = GetShaderLocation(WallMaterial.shader, "ambient");
124 | float ambient[4] = { 0.1f, 0.1f, 0.1f, 1.0f };
125 | SetShaderValue(WallMaterial.shader, ambientLoc, ambient, SHADER_UNIFORM_VEC4);
126 |
127 | WallMaterial.maps[MATERIAL_MAP_ALBEDO].texture = LoadTexture("resources/texture_12.png");
128 |
129 | PlaneMesh = GenMeshPlane(100, 100, 50, 50);
130 | PlaneMaterial = LoadMaterialDefault();
131 | PlaneMaterial.shader = WallMaterial.shader;
132 | PlaneMaterial.maps[MATERIAL_MAP_ALBEDO].texture = LoadTexture("resources/texture_07.png");
133 | }
134 |
135 | void Map::CleanupGraphics()
136 | {
137 | if (!IsShaderValid(WallMaterial.shader))
138 | return;
139 |
140 | UnloadShader(WallMaterial.shader);
141 | WallMaterial.shader.id = 0;
142 |
143 | UnloadTexture(WallMaterial.maps[MATERIAL_MAP_ALBEDO].texture);
144 | WallMaterial.maps[MATERIAL_MAP_ALBEDO].texture.id = 0;
145 |
146 | UnloadTexture(PlaneMaterial.maps[MATERIAL_MAP_ALBEDO].texture);
147 | PlaneMaterial.maps[MATERIAL_MAP_ALBEDO].texture.id = 0;
148 |
149 | UnloadMesh(WallMesh);
150 | WallMesh.vertexCount = 0;
151 | }
152 |
153 | Shader Map::GetLightShader()
154 | {
155 | return WallMaterial.shader;
156 | }
157 |
158 | void Map::Setup()
159 | {
160 | ShotSound = LoadSound("resources/laserLarge_004.ogg");
161 | for (int i = 0; i < MaxSounds; i++)
162 | ShotLoop[i] = LoadSoundAlias(ShotSound);
163 | }
164 |
165 | void Map::Cleanup()
166 | {
167 | for (int i = 0; i < MaxSounds; i++)
168 | UnloadSoundAlias(ShotLoop[i]);
169 |
170 | UnloadSound(ShotSound);
171 | }
172 |
173 | bool Map::CollidePlayer(Vector3& newPosition, Vector3 oldPosition, float radius, float height)
174 | {
175 | bool hitSomething = false;
176 | for (auto& wall : Walls)
177 | {
178 | if (wall.CollideWithPlayer(newPosition, oldPosition, radius, height))
179 | hitSomething = true;
180 | }
181 |
182 | return hitSomething;
183 | }
184 |
185 | bool Map::CollideRay(Ray worldspaceRay, RayCollision& outputCollision, Obstacle* hitObstacle)
186 | {
187 | RayCollision collision = { 0 };
188 |
189 | outputCollision.hit = false;
190 | outputCollision.distance = std::numeric_limits::max();
191 |
192 | for (auto& wall : Walls)
193 | {
194 | if (wall.CheckRaycast(worldspaceRay, collision))
195 | {
196 | if (collision.distance < outputCollision.distance)
197 | {
198 | outputCollision = collision;
199 | if (hitObstacle != nullptr)
200 | hitObstacle = &wall;
201 | }
202 | }
203 | }
204 |
205 | return outputCollision.hit;
206 | }
207 |
208 | void Map::Draw(Camera3D &view)
209 | {
210 | if (!IsTextureValid(PlaneMaterial.maps[MATERIAL_MAP_ALBEDO].texture))
211 | return;
212 |
213 | float cameraPos[3] = { view.position.x, view.position.y, view.position.z };
214 | SetShaderValue(WallMaterial.shader, WallMaterial.shader.locs[SHADER_LOC_VECTOR_VIEW], cameraPos, SHADER_UNIFORM_VEC3);
215 |
216 | DrawMesh(PlaneMesh, PlaneMaterial, MatrixIdentity());
217 |
218 | DrawWalls(view);
219 |
220 | // axis markers
221 | DrawCube(Vector3{ 1,0,0 }, 1.25f, 0.25f, 0.25f, RED);
222 | DrawCube(Vector3{ 0,0,1 }, 0.25f, 0.25f, 1.25f, BLUE);
223 |
224 | // explosions
225 | rlDisableDepthMask();
226 | for (auto& explosion : Explosions)
227 | {
228 | explosion.Lifetime -= GetFrameTime();
229 | if (explosion.Lifetime > 0)
230 | {
231 | float param = explosion.Lifetime / Explosion::MaxLife;
232 | DrawSphere(explosion.Postion, 0.125f + ((1.0f - param) * 0.5f), ColorAlpha(ORANGE, explosion.Lifetime / Explosion::MaxLife));
233 | }
234 | }
235 | rlDrawRenderBatchActive();
236 | rlEnableDepthMask();
237 |
238 | while (!Explosions.empty() && Explosions.front().Lifetime < 0)
239 | Explosions.pop_front();
240 | }
241 |
242 | void Map::DrawWalls(Camera3D& view)
243 | {
244 | if (!IsTextureValid(WallMaterial.maps[MATERIAL_MAP_ALBEDO].texture))
245 | return;
246 |
247 | float cameraPos[3] = { view.position.x, view.position.y, view.position.z };
248 | SetShaderValue(WallMaterial.shader, WallMaterial.shader.locs[SHADER_LOC_VECTOR_VIEW], cameraPos, SHADER_UNIFORM_VEC3);
249 |
250 | for (auto& wall : Walls)
251 | {
252 | wall.Transform.PushMatrix();
253 | DrawMesh(WallMesh, WallMaterial, MatrixScale(wall.Scale.x, wall.Scale.y, wall.Scale.z));
254 |
255 | wall.Transform.PopMatrix();
256 | }
257 | }
258 |
259 | void Map::AddExplosition(RayCollision& collision)
260 | {
261 | Explosions.emplace_back();
262 | Explosions.back().Lifetime = Explosion::MaxLife;
263 | Explosions.back().Postion = collision.point;
264 | Explosions.back().Normal = collision.normal;
265 | }
266 |
267 | void Map::AddShotSound()
268 | {
269 | CurrentShotSound++;
270 | if (CurrentShotSound >= MaxSounds)
271 | CurrentShotSound = 0;
272 | PlaySound(ShotLoop[CurrentShotSound]);
273 | }
274 |
--------------------------------------------------------------------------------
/fps_collisions/player.cpp:
--------------------------------------------------------------------------------
1 | /*********************************************************************************************
2 | *
3 | * raylib-extras, FPS collision example
4 | *
5 | * LICENSE: MIT
6 | *
7 | * Copyright (c) 2024 Jeffery Myers
8 | *
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy
10 | * of this software and associated documentation files (the "Software"), to deal
11 | * in the Software without restriction, including without limitation the rights
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | * copies of the Software, and to permit persons to whom the Software is
14 | * furnished to do so, subject to the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be included in all
17 | * copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 | * SOFTWARE.
26 | *
27 | **********************************************************************************************/
28 |
29 | #include "player.h"
30 | #include "map.h"
31 | #include "raymath.h"
32 |
33 | Model GunMesh = { 0 };
34 |
35 | void PlayerInfo::SetupGraphics()
36 | {
37 | GunMesh = LoadModel("resources/blasterD.glb");
38 | for (int i = 0; i < GunMesh.materialCount; i++)
39 | GunMesh.materials[i].shader = Map::GetLightShader();
40 | }
41 |
42 | void PlayerInfo::CleanupGraphics()
43 | {
44 | if (IsModelValid(GunMesh))
45 | UnloadModel(GunMesh);
46 | }
47 |
48 | void PlayerInfo::Setup()
49 | {
50 | PlayerNode.SetPosition(0, 0, -5);
51 | PlayerNode.AddChild(CameraNode);
52 | CameraNode.MoveV(2);
53 |
54 | PlayerNode.AddChild(ShoulderNode);
55 |
56 | // move the pivot of the gun down a little so it's not attached to the center of our head
57 | ShoulderNode.MoveV(1.85f);
58 |
59 | ShoulderNode.AddChild(GunNode);
60 |
61 | GunNode.SetPosition(PlayerInfo::GunDefaultH, PlayerInfo::GunDefaultV, PlayerInfo::GunDefaultD);
62 |
63 | ViewCamera.fovy = 45;
64 | ViewCamera.up.y = 1;
65 | ViewCamera.target.y = 2;
66 | ViewCamera.position.y = 2;
67 | ViewCamera.position.z = -5;
68 |
69 | #ifndef _DEBUG
70 | DisableCursor();
71 | #endif // _DEBUG
72 | }
73 |
74 | void PlayerInfo::Update(Map& map)
75 | {
76 | DesiredMovement.x = DesiredMovement.y = DesiredMovement.z = 0;
77 |
78 | #ifdef _DEBUG
79 | if (IsMouseButtonDown(MOUSE_BUTTON_RIGHT))
80 | #endif
81 | {
82 | constexpr float mouseSpeedScale = 0.5f;
83 | constexpr float maxViewAngle = 89.95f;
84 | constexpr float forwardSpeed = 30;
85 | constexpr float sideSpeed = 10;
86 |
87 | // rotate the player by the horizontal delta
88 | PlayerNode.RotateV(-GetMouseDelta().x * mouseSpeedScale);
89 |
90 | // rotate the camera node (head) by the tilt angle (clamped)
91 | TitltAngle += -GetMouseDelta().y * mouseSpeedScale;
92 | if (TitltAngle > maxViewAngle)
93 | TitltAngle = maxViewAngle;
94 | else if (TitltAngle < -maxViewAngle)
95 | TitltAngle = -maxViewAngle;
96 |
97 | CameraNode.SetOrientation(Vector3{ TitltAngle,0,0 });
98 | ShoulderNode.SetOrientation(Vector3{ TitltAngle,0,0 });
99 |
100 | // get the input movement
101 | Vector2 wadsVector = { 0 };
102 |
103 | if (IsKeyDown(KEY_W))
104 | wadsVector.y += 1;
105 | if (IsKeyDown(KEY_S))
106 | wadsVector.y -= 1;
107 |
108 | if (IsKeyDown(KEY_A))
109 | wadsVector.x += 1;
110 | if (IsKeyDown(KEY_D))
111 | wadsVector.x -= 1;
112 |
113 | // handle forward and sidestep motion
114 | DesiredMovement = Vector3Add(DesiredMovement, Vector3Scale(PlayerNode.GetDVector(), forwardSpeed * wadsVector.y * GetFrameTime()));
115 | DesiredMovement = Vector3Add(DesiredMovement, Vector3Scale(PlayerNode.GetHNegVector(), sideSpeed * wadsVector.x * GetFrameTime()));
116 | }
117 |
118 | // if we are moving, bobble the gun a little
119 | if (Vector3LengthSqr(DesiredMovement) > 0)
120 | {
121 | BobbleTime += GetFrameTime();
122 | GunNode.SeteH(GunDefaultH + sinf(BobbleTime * 4.0f) * 0.05f);
123 | GunNode.SetV(GunDefaultV + cosf(BobbleTime * 6.0f) * 0.02f);
124 | }
125 |
126 | // try and move the player in the world and see where we end up after we hit all the things.
127 | Vector3 oldPos = PlayerNode.GetPosition();
128 | Vector3 newWorldPos = Vector3Add(oldPos, DesiredMovement);
129 |
130 | HitLastFrame = map.CollidePlayer(newWorldPos, oldPos, CollisionRadius, 2);
131 |
132 | // set the player to where they can be
133 | PlayerNode.SetPosition(newWorldPos);
134 |
135 | // update the camera with the new view.
136 | CameraNode.SetCamera(ViewCamera);
137 |
138 | // raycast from the view into the world to see what it would hit
139 | Ray gunRay = { 0 };
140 | gunRay.position = Vector3Transform(Vector3Zero(), CameraNode.GetWorldMatrix());
141 | gunRay.direction = Vector3Subtract(Vector3Transform(Vector3{ 0,0,1 }, CameraNode.GetWorldMatrix()), gunRay.position);
142 |
143 | map.CollideRay(gunRay, LastGunCollision); // optional, if you need to know what you hit, you can pass a pointer in here that will be set with the wall that is hit
144 |
145 | // handle shooting
146 | Reload -= GetFrameTime(); // decrement reload wait time
147 |
148 | // if we can shoot, and they want to shoot
149 | if (IsMouseButtonDown(MOUSE_LEFT_BUTTON) && Reload <= 0)
150 | {
151 | // make them wait for another shot
152 | Reload = ReloadTime;
153 |
154 | // make the gun sound
155 | map.AddShotSound();
156 |
157 | // if they hit something, then add an explosion there
158 | if (LastGunCollision.hit)
159 | map.AddExplosition(LastGunCollision);
160 | }
161 |
162 | // gun recoil 'animation'
163 | float param = 0;
164 | if (Reload > 0)
165 | param = Reload / ReloadTime;
166 |
167 | GunNode.SetD(param * RecoilDistance + GunDefaultD);
168 | }
169 |
170 | void PlayerInfo::Draw()
171 | {
172 | GunNode.PushMatrix();
173 |
174 | DrawModel(GunMesh, Vector3Zero(), 1, WHITE);
175 |
176 | rlBegin(RL_LINES);
177 | rlColor4f(1,0,0,1);
178 | rlVertex3f(Vector3Zeros.x, Vector3Zeros.y, Vector3Zeros.z);
179 | rlColor4f(1, 0, 0, 0);
180 | rlVertex3f(0,0, 3);
181 | rlEnd();
182 |
183 | GunNode.PopMatrix();
184 | }
185 |
--------------------------------------------------------------------------------
/fps_collisions/premake5.lua:
--------------------------------------------------------------------------------
1 |
2 | baseName = path.getbasename(os.getcwd())
3 |
4 | defineWorkspace(baseName)
--------------------------------------------------------------------------------
/fps_collisions/resources/blasterD.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/raylib-extras/examples-cpp/935b48d6f5fe597bd805c30355a193aef7d0e8fe/fps_collisions/resources/blasterD.glb
--------------------------------------------------------------------------------
/fps_collisions/resources/blasterH.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/raylib-extras/examples-cpp/935b48d6f5fe597bd805c30355a193aef7d0e8fe/fps_collisions/resources/blasterH.glb
--------------------------------------------------------------------------------
/fps_collisions/resources/laserLarge_004.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/raylib-extras/examples-cpp/935b48d6f5fe597bd805c30355a193aef7d0e8fe/fps_collisions/resources/laserLarge_004.ogg
--------------------------------------------------------------------------------
/fps_collisions/resources/shaders/lighting.fs:
--------------------------------------------------------------------------------
1 | #version 330
2 |
3 | // Input vertex attributes (from vertex shader)
4 | in vec3 fragPosition;
5 | in vec2 fragTexCoord;
6 | //in vec4 fragColor;
7 | in vec3 fragNormal;
8 |
9 | // Input uniform values
10 | uniform sampler2D texture0;
11 | uniform vec4 colDiffuse;
12 |
13 | // Output fragment color
14 | out vec4 finalColor;
15 |
16 | // NOTE: Add here your custom variables
17 |
18 | #define MAX_LIGHTS 4
19 | #define LIGHT_DIRECTIONAL 0
20 | #define LIGHT_POINT 1
21 |
22 | struct Light {
23 | int enabled;
24 | int type;
25 | vec3 position;
26 | vec3 target;
27 | vec4 color;
28 | };
29 |
30 | // Input lighting values
31 | uniform Light lights[MAX_LIGHTS];
32 | uniform vec4 ambient;
33 | uniform vec3 viewPos;
34 |
35 | void main()
36 | {
37 | // Texel color fetching from texture sampler
38 | vec4 texelColor = texture(texture0, fragTexCoord);
39 | vec3 lightDot = vec3(0.0);
40 | vec3 normal = normalize(fragNormal);
41 | vec3 viewD = normalize(viewPos - fragPosition);
42 | vec3 specular = vec3(0.0);
43 |
44 | // NOTE: Implement here your fragment shader code
45 |
46 | for (int i = 0; i < MAX_LIGHTS; i++)
47 | {
48 | if (lights[i].enabled == 1)
49 | {
50 | vec3 light = vec3(0.0);
51 |
52 | if (lights[i].type == LIGHT_DIRECTIONAL)
53 | {
54 | light = -normalize(lights[i].target - lights[i].position);
55 | }
56 |
57 | if (lights[i].type == LIGHT_POINT)
58 | {
59 | light = normalize(lights[i].position - fragPosition);
60 | }
61 |
62 | float NdotL = max(dot(normal, light), 0.0);
63 | lightDot += lights[i].color.rgb*NdotL;
64 |
65 | float specCo = 0.0;
66 | if (NdotL > 0.0) specCo = pow(max(0.0, dot(viewD, reflect(-(light), normal))), 16.0); // 16 refers to shine
67 | specular += specCo;
68 | }
69 | }
70 |
71 | finalColor = (texelColor*((colDiffuse + vec4(specular, 1.0))*vec4(lightDot, 1.0)));
72 | finalColor += texelColor*(ambient)*colDiffuse;
73 |
74 | // Gamma correction
75 | finalColor = pow(finalColor, vec4(1.0/2.2));
76 | }
77 |
--------------------------------------------------------------------------------
/fps_collisions/resources/shaders/lighting.vs:
--------------------------------------------------------------------------------
1 | #version 330
2 |
3 | // Input vertex attributes
4 | in vec3 vertexPosition;
5 | in vec2 vertexTexCoord;
6 | in vec3 vertexNormal;
7 | in vec4 vertexColor;
8 |
9 | // Input uniform values
10 | uniform mat4 mvp;
11 | uniform mat4 matModel;
12 | uniform mat4 matNormal;
13 |
14 | // Output vertex attributes (to fragment shader)
15 | out vec3 fragPosition;
16 | out vec2 fragTexCoord;
17 | out vec4 fragColor;
18 | out vec3 fragNormal;
19 |
20 | // NOTE: Add here your custom variables
21 |
22 | void main()
23 | {
24 | // Send vertex attributes to fragment shader
25 | fragPosition = vec3(matModel*vec4(vertexPosition, 1.0));
26 | fragTexCoord = vertexTexCoord;
27 | fragColor = vertexColor;
28 | fragNormal = normalize(vec3(matNormal*vec4(vertexNormal, 1.0)));
29 |
30 | // Calculate final vertex position
31 | gl_Position = mvp*vec4(vertexPosition, 1.0);
32 | }
33 |
--------------------------------------------------------------------------------
/fps_collisions/resources/texture_07.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/raylib-extras/examples-cpp/935b48d6f5fe597bd805c30355a193aef7d0e8fe/fps_collisions/resources/texture_07.png
--------------------------------------------------------------------------------
/fps_collisions/resources/texture_12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/raylib-extras/examples-cpp/935b48d6f5fe597bd805c30355a193aef7d0e8fe/fps_collisions/resources/texture_12.png
--------------------------------------------------------------------------------
/hardpoints2d/README.md:
--------------------------------------------------------------------------------
1 | # hardpoints 2d
2 | A simple example of how to build up objects with attachment to hardpoints using compound transforms.
--------------------------------------------------------------------------------
/hardpoints2d/main.cpp:
--------------------------------------------------------------------------------
1 | /**********************************************************************************************
2 | *
3 | * raylib-extras, examples-cpp * examples for Raylib in C++
4 | *
5 | * Hardpoint and compound transforms
6 | *
7 | * LICENSE: MIT
8 | *
9 | * Copyright (c) 2023 Jeffery Myers
10 | *
11 | * Permission is hereby granted, free of charge, to any person obtaining a copy
12 | * of this software and associated documentation files (the "Software"), to deal
13 | * in the Software without restriction, including without limitation the rights
14 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 | * copies of the Software, and to permit persons to whom the Software is
16 | * furnished to do so, subject to the following conditions:
17 | *
18 | * The above copyright notice and this permission notice shall be included in all
19 | * copies or substantial portions of the Software.
20 | *
21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 | * SOFTWARE.
28 | *
29 | **********************************************************************************************/
30 |
31 | #include "raylib.h"
32 | #include "raymath.h"
33 | #include "rlgl.h"
34 |
35 | #include
36 | #include