├── .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 | ![pew_game](https://user-images.githubusercontent.com/322174/138608560-47de649e-7316-42f3-a4f5-c8ba59ef8b98.gif) 23 | 24 | # Cards 25 | An example of how to build up cards, decks, and hands and drag cards around. 26 | ![cards](https://user-images.githubusercontent.com/322174/138608557-5b1dfeb3-33a3-409c-8635-0dac7f7cdf36.gif) 27 | 28 | # Platform Example 29 | An example of platfomer style movement, sprite animation, and state management. 30 | ![platform_jump](https://user-images.githubusercontent.com/322174/147867102-ce62fbbd-2f2a-4ccd-8d44-9f49450b9df5.gif) 31 | 32 | # Box2d Raylib 33 | An example of using the Box2d physics library with raylib. 34 | ![Box2d_spin](https://user-images.githubusercontent.com/322174/155644898-4667f4e6-894c-4ae0-90bd-485c503fe2a6.gif) 35 | 36 | # Box2d Raylib Objects 37 | An more advanced example using box2d and objects 38 | ![box2d_objects](https://user-images.githubusercontent.com/322174/155657154-b13f5fa7-2f18-43ce-a647-deb2cebff826.gif) 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 | ![raycaster](https://user-images.githubusercontent.com/322174/203472549-2918ff06-0cb9-492d-bb8a-85fce61bc108.gif) 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 | ![Box2d_spin](https://user-images.githubusercontent.com/322174/155644898-4667f4e6-894c-4ae0-90bd-485c503fe2a6.gif) 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 | ![box2d_objects](https://user-images.githubusercontent.com/322174/155657154-b13f5fa7-2f18-43ce-a647-deb2cebff826.gif) 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](https://user-images.githubusercontent.com/322174/138608557-5b1dfeb3-33a3-409c-8635-0dac7f7cdf36.gif) -------------------------------------------------------------------------------- /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 37 | #include 38 | 39 | class GunPart 40 | { 41 | public: 42 | Texture2D Texture = { 0 }; 43 | Vector2 Orign = { 0 }; 44 | 45 | std::vector Hardpoints; 46 | 47 | std::string Name; 48 | 49 | virtual ~GunPart() 50 | { 51 | // really should be part of a sprite sheet, but whatever 52 | if (IsTextureValid(Texture)) 53 | UnloadTexture(Texture); 54 | } 55 | }; 56 | 57 | std::vector Guns; 58 | std::vector Scopes; 59 | std::vector BarrelMods; 60 | 61 | int GunIndex = 0; 62 | int ScopeIndex = 0; 63 | int BarrelIndex = 0; 64 | 65 | class GunAttachmentNode 66 | { 67 | public: 68 | bool Active = true; 69 | 70 | GunPart* Part = nullptr; 71 | 72 | Color Tint = WHITE; 73 | 74 | std::map Children; 75 | 76 | GunAttachmentNode() = default; 77 | GunAttachmentNode(GunPart* part) : Part(part) {} 78 | 79 | void Draw(bool flipY) const 80 | { 81 | if (!Active || !Part) 82 | return; 83 | 84 | rlPushMatrix(); 85 | // compute our local origin offset 86 | float yOrigin = Part->Orign.y; 87 | float yScale = 1; 88 | 89 | // if we are flipped all y data needs to be mirrored 90 | if (flipY) 91 | { 92 | yOrigin = Part->Texture.height - yOrigin; 93 | yScale *= -1; 94 | } 95 | 96 | // translate back so we are the right origin 97 | rlTranslatef(-Part->Orign.x, -yOrigin, 0); 98 | 99 | // draw the texture for this part 100 | DrawTextureRec(Part->Texture, Rectangle{ 0,0,float(Part->Texture.width), float(Part->Texture.height) * yScale }, Vector2Zero(), Tint); 101 | 102 | // walk all the children and offset them by the hardpoint location 103 | // these transforms are nested, so they will pick up any translation or rotation from the parent 104 | for (const auto& child : Children) 105 | { 106 | rlPushMatrix(); 107 | 108 | // if we are flipped all Y data is mirrored 109 | float yPos = Part->Hardpoints[child.first].y; 110 | if (flipY) 111 | { 112 | yPos = Part->Texture.height - yPos; 113 | } 114 | rlTranslatef(Part->Hardpoints[child.first].x, yPos, 0); 115 | child.second.Draw(flipY); 116 | rlPopMatrix(); 117 | } 118 | rlPopMatrix(); 119 | } 120 | }; 121 | 122 | GunAttachmentNode* Gun = nullptr; 123 | 124 | Texture2D Player = { 0 }; 125 | float GunAngle = 0; 126 | 127 | Vector2 PlayerPos = { 0,0 }; 128 | 129 | void GameInit() 130 | { 131 | // build up our gun parts 132 | 133 | GunPart* gun1 = new GunPart(); 134 | gun1->Texture = LoadTexture("resources/gun.png"); 135 | gun1->Orign = Vector2{ 28, 16 }; 136 | gun1->Name = "Rifle"; 137 | gun1->Hardpoints.push_back(Vector2{ 122, 14 }); // barrel mount hardpoint 138 | gun1->Hardpoints.push_back(Vector2{ 54, 2 }); // scope mount hardpoint 139 | Guns.push_back(gun1); 140 | 141 | // a smaller gun 142 | GunPart* gun2 = new GunPart(); 143 | gun2->Texture = LoadTexture("resources/gun2.png"); 144 | gun2->Orign = Vector2{ -10, 14 }; 145 | gun2->Name = "SMG"; 146 | gun2->Hardpoints.push_back(Vector2{ 61, 14 }); // barrel mount hardpoint 147 | gun2->Hardpoints.push_back(Vector2{ 18, 11 }); // scope mount hardpoint 148 | Guns.push_back(gun2); 149 | 150 | 151 | // barrel modes 152 | GunPart* silencer1 = new GunPart(); 153 | silencer1->Texture = LoadTexture("resources/Silencer.png"); 154 | silencer1->Orign = Vector2{ 0, 4 }; // where the silencer attaches to the hardpoint on the parent 155 | silencer1->Name = "Silencer"; 156 | BarrelMods.push_back(silencer1); 157 | 158 | GunPart* underBarelLight = new GunPart(); 159 | underBarelLight->Texture = LoadTexture("resources/Light.png"); 160 | underBarelLight->Orign = Vector2{ 6, 10 }; // where the light attaches to the hardpoint on the parent 161 | underBarelLight->Name = "Light"; 162 | BarrelMods.push_back(underBarelLight); 163 | 164 | // scopes 165 | GunPart* scope1 = new GunPart(); 166 | scope1->Texture = LoadTexture("resources/Scope.png"); 167 | scope1->Orign = Vector2{ 5, 9 }; // where the scope attaches to the hardpoint on the parent 168 | scope1->Name = "Scope"; 169 | Scopes.push_back(scope1); 170 | 171 | GunPart* scope2 = new GunPart(); 172 | scope2->Texture = LoadTexture("resources/RedDot.png"); 173 | scope2->Orign = Vector2{ 0, 9 }; 174 | scope2->Name = "Red Dot Sight"; 175 | Scopes.push_back(scope2); 176 | 177 | GunPart* scope3 = new GunPart(); 178 | scope3->Texture = LoadTexture("resources/Laser.png"); 179 | scope3->Orign = Vector2{ 3, 8 }; 180 | scope3->Name = "Laser"; 181 | Scopes.push_back(scope3); 182 | 183 | // player data 184 | Player = LoadTexture("resources/player.png"); 185 | PlayerPos.x = GetScreenWidth() * 0.5f; 186 | PlayerPos.y = GetScreenHeight() * 0.5f; 187 | 188 | // build an attachment of gun parts for rendering 189 | Gun = new GunAttachmentNode(gun1); 190 | Gun->Children.emplace(0, silencer1); // add a silencer to the barrel mount hardpoint 191 | Gun->Children.emplace(1, scope3); // add a scope to the scope mount hardpoint 192 | } 193 | 194 | void GameCleanup() 195 | { 196 | UnloadTexture(Player); 197 | Guns.clear(); 198 | BarrelMods.clear(); 199 | Scopes.clear(); 200 | delete(Gun); 201 | } 202 | 203 | bool GameUpdate() 204 | { 205 | if (Vector2DistanceSqr(PlayerPos, GetMousePosition()) > 10) 206 | GunAngle = Vector2LineAngle(PlayerPos, GetMousePosition()) * -RAD2DEG; 207 | 208 | Vector2 input = { 0 }; 209 | if (IsKeyDown(KEY_W)) 210 | input.y -= 1; 211 | if (IsKeyDown(KEY_S)) 212 | input.y += 1; 213 | 214 | if (IsKeyDown(KEY_A)) 215 | input.x -= 1; 216 | if (IsKeyDown(KEY_D)) 217 | input.x += 1; 218 | 219 | PlayerPos = Vector2Add(PlayerPos, Vector2Scale(input, 300 * GetFrameTime())); 220 | 221 | 222 | bool rebuildGun = false; 223 | // cycle guns 224 | if (IsKeyPressed(KEY_O)) 225 | { 226 | rebuildGun = true; 227 | GunIndex++; 228 | if (GunIndex >= Guns.size()) 229 | GunIndex = 0; 230 | } 231 | 232 | if (IsKeyPressed(KEY_P)) 233 | { 234 | rebuildGun = true; 235 | GunIndex--; 236 | if (GunIndex < 0) 237 | GunIndex = int(Guns.size()-1); 238 | } 239 | 240 | // cycle barrel modes 241 | if (IsKeyPressed(KEY_K)) 242 | { 243 | rebuildGun = true; 244 | BarrelIndex++; 245 | if (BarrelIndex >= BarrelMods.size()) 246 | BarrelIndex = -1; 247 | } 248 | 249 | if (IsKeyPressed(KEY_L)) 250 | { 251 | rebuildGun = true; 252 | BarrelIndex--; 253 | if (BarrelIndex < -1) 254 | BarrelIndex = int(BarrelMods.size() - 1); 255 | } 256 | 257 | // cycle scopes 258 | if (IsKeyPressed(KEY_Y)) 259 | { 260 | rebuildGun = true; 261 | ScopeIndex++; 262 | if (ScopeIndex >= Scopes.size()) 263 | ScopeIndex = -1; 264 | } 265 | 266 | if (IsKeyPressed(KEY_U)) 267 | { 268 | rebuildGun = true; 269 | ScopeIndex--; 270 | if (ScopeIndex < -1) 271 | ScopeIndex = int(Scopes.size() - 1); 272 | } 273 | 274 | if (rebuildGun) 275 | { 276 | // optimally this should cache the assembled gun to a render texture, but we'll just draw it every frame. 277 | 278 | // set the current parts 279 | Gun->Part = Guns[GunIndex]; 280 | 281 | auto barelSlot = Gun->Children.find(0); 282 | if (barelSlot != Gun->Children.end()) 283 | { 284 | if (BarrelIndex == -1) 285 | barelSlot->second.Part = nullptr; 286 | else 287 | barelSlot->second.Part = BarrelMods[BarrelIndex]; 288 | } 289 | 290 | auto scopeSlot = Gun->Children.find(1); 291 | if (scopeSlot != Gun->Children.end()) 292 | { 293 | if (ScopeIndex == -1) 294 | scopeSlot->second.Part = nullptr; 295 | else 296 | scopeSlot->second.Part = Scopes[ScopeIndex]; 297 | } 298 | } 299 | 300 | return true; 301 | } 302 | 303 | void GameDraw() 304 | { 305 | BeginDrawing(); 306 | ClearBackground(SKYBLUE); 307 | 308 | // draw the player 309 | DrawTexturePro(Player, 310 | Rectangle{ 0,0,float(Player.width), float(Player.height) }, 311 | Rectangle{ PlayerPos.x,PlayerPos.y,float(Player.width), float(Player.height) }, 312 | Vector2{ Player.width * 0.5f,Player.height * 0.5f }, 313 | 0, 314 | WHITE); 315 | 316 | // move to the origin of the gun on the player 317 | rlPushMatrix(); 318 | rlTranslatef(PlayerPos.x, PlayerPos.y + 20, 0); 319 | // rotate to the gun angle 320 | rlRotatef(GunAngle, 0, 0, 1); 321 | 322 | // draw the gun from it's origin 323 | Gun->Draw(fabsf(GunAngle) > 90); 324 | 325 | // put the transform back 326 | rlPopMatrix(); 327 | 328 | DrawFPS(0, 0); 329 | DrawText(TextFormat("Gun Angle %0.1f", GunAngle), 100, 0, 20, WHITE); 330 | 331 | // instructions for how to change parts 332 | DrawText(TextFormat("Gun : ", Gun->Part->Name.c_str()), 10, 20, 20, WHITE); 333 | 334 | auto& barrel = Gun->Children[0]; 335 | DrawText(TextFormat("Barrel : ", BarrelIndex == -1 ? "None" : barrel.Part->Name.c_str()), 10, 40, 20, WHITE); 336 | 337 | auto& scope = Gun->Children[1]; 338 | DrawText(TextFormat("Scope : ", ScopeIndex == -1 ? "None" : scope.Part->Name.c_str()), 10, 60, 20, WHITE); 339 | EndDrawing(); 340 | } 341 | 342 | int main() 343 | { 344 | SetConfigFlags(FLAG_VSYNC_HINT); 345 | InitWindow(1280, 800, "Example"); 346 | SetTargetFPS(144); 347 | 348 | GameInit(); 349 | 350 | while (!WindowShouldClose()) 351 | { 352 | if (!GameUpdate()) 353 | break; 354 | 355 | GameDraw(); 356 | } 357 | 358 | GameCleanup(); 359 | CloseWindow(); 360 | return 0; 361 | } -------------------------------------------------------------------------------- /hardpoints2d/premake5.lua: -------------------------------------------------------------------------------- 1 | 2 | baseName = path.getbasename(os.getcwd()) 3 | 4 | defineWorkspace(baseName) -------------------------------------------------------------------------------- /hardpoints2d/resources/Light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raylib-extras/examples-cpp/935b48d6f5fe597bd805c30355a193aef7d0e8fe/hardpoints2d/resources/Light.png -------------------------------------------------------------------------------- /hardpoints2d/resources/RedDot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raylib-extras/examples-cpp/935b48d6f5fe597bd805c30355a193aef7d0e8fe/hardpoints2d/resources/RedDot.png -------------------------------------------------------------------------------- /hardpoints2d/resources/Scope.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raylib-extras/examples-cpp/935b48d6f5fe597bd805c30355a193aef7d0e8fe/hardpoints2d/resources/Scope.png -------------------------------------------------------------------------------- /hardpoints2d/resources/Silencer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raylib-extras/examples-cpp/935b48d6f5fe597bd805c30355a193aef7d0e8fe/hardpoints2d/resources/Silencer.png -------------------------------------------------------------------------------- /hardpoints2d/resources/gun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raylib-extras/examples-cpp/935b48d6f5fe597bd805c30355a193aef7d0e8fe/hardpoints2d/resources/gun.png -------------------------------------------------------------------------------- /hardpoints2d/resources/gun2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raylib-extras/examples-cpp/935b48d6f5fe597bd805c30355a193aef7d0e8fe/hardpoints2d/resources/gun2.png -------------------------------------------------------------------------------- /hardpoints2d/resources/laser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raylib-extras/examples-cpp/935b48d6f5fe597bd805c30355a193aef7d0e8fe/hardpoints2d/resources/laser.png -------------------------------------------------------------------------------- /hardpoints2d/resources/player.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raylib-extras/examples-cpp/935b48d6f5fe597bd805c30355a193aef7d0e8fe/hardpoints2d/resources/player.png -------------------------------------------------------------------------------- /interpolated_animation_gpu/README.md: -------------------------------------------------------------------------------- 1 | # Interpolated GPU based animation 2 | An example of how to do animations on the GPU with hardware skinning and interpolation -------------------------------------------------------------------------------- /interpolated_animation_gpu/premake5.lua: -------------------------------------------------------------------------------- 1 | 2 | baseName = path.getbasename(os.getcwd()) 3 | 4 | defineWorkspace(baseName) -------------------------------------------------------------------------------- /interpolated_animation_gpu/resources/anim.fs: -------------------------------------------------------------------------------- 1 | #version 330 2 | 3 | // Input vertex attributes (from vertex shader) 4 | in vec2 fragTexCoord; 5 | in vec4 fragColor; 6 | in vec3 fragNormal; 7 | in vec3 fragPosition; 8 | 9 | uniform int useNormalForColor = 0; 10 | 11 | // Input uniform values 12 | uniform sampler2D texture0; 13 | uniform vec4 colDiffuse; 14 | 15 | 16 | // Output fragment color 17 | out vec4 finalColor; 18 | 19 | // NOTE: Add here your custom variables 20 | 21 | #define MAX_LIGHTS 4 22 | #define LIGHT_DIRECTIONAL 0 23 | #define LIGHT_POINT 1 24 | 25 | struct Light { 26 | int enabled; 27 | int type; 28 | vec3 position; 29 | vec3 target; 30 | vec4 color; 31 | float attenuation; 32 | float shine; 33 | }; 34 | 35 | // Input lighting values 36 | uniform Light lights[MAX_LIGHTS]; 37 | uniform vec4 ambient; 38 | uniform vec3 viewPos; 39 | 40 | // NOTE: Add here your custom variables 41 | 42 | void main() 43 | { 44 | // Texel color fetching from texture sampler 45 | vec4 texelColor = texture(texture0, fragTexCoord); 46 | 47 | vec3 lightDot = vec3(0.0); 48 | vec3 normal = normalize(fragNormal); 49 | vec3 viewD = normalize(viewPos - fragPosition); 50 | vec3 specular = vec3(0.0); 51 | 52 | for (int i = 0; i < MAX_LIGHTS; i++) 53 | { 54 | if (lights[i].enabled == 1) 55 | { 56 | vec3 light = vec3(0.0); 57 | 58 | if (lights[i].type == LIGHT_DIRECTIONAL) 59 | { 60 | light = -normalize(lights[i].target - lights[i].position); 61 | } 62 | 63 | float attenuation = 1; 64 | 65 | if (lights[i].type == LIGHT_POINT) 66 | { 67 | light = normalize(lights[i].position - fragPosition); 68 | 69 | if (lights[i].attenuation > 0) 70 | attenuation = clamp( lights[i].attenuation / distance(fragPosition, lights[i].position), 0.0, 1.0); 71 | } 72 | 73 | float NdotL = max(dot(normal, light), 0.0); 74 | lightDot += lights[i].color.rgb*NdotL * attenuation; 75 | 76 | float specCo = 0.0; 77 | if (NdotL > 0.0 && lights[i].shine > 0) 78 | specCo = pow(max(0.0, dot(viewD, reflect(-(light), normal))), lights[i].shine); 79 | specular += specCo; 80 | } 81 | } 82 | 83 | finalColor = (texelColor*((colDiffuse + vec4(specular, 1.0))*vec4(lightDot, 1.0))); 84 | finalColor += texelColor*(ambient/10.0)*colDiffuse; 85 | 86 | // Gamma correction 87 | finalColor = pow(finalColor, vec4(1.0/2.2)); 88 | 89 | if(useNormalForColor != 0) 90 | finalColor = texelColor * colDiffuse * vec4(fragNormal, 1); 91 | } 92 | 93 | -------------------------------------------------------------------------------- /interpolated_animation_gpu/resources/anim.vs: -------------------------------------------------------------------------------- 1 | #version 330 2 | 3 | // Input vertex attributes 4 | in vec3 vertexPosition; 5 | in vec2 vertexTexCoord; 6 | in vec2 vertexTexCoord2; // bone IDs 7 | in vec3 vertexNormal; 8 | in vec4 vertexColor; 9 | in vec4 vertexTangent; // bone weights 10 | 11 | #define MAX_BONES 64 12 | 13 | uniform mat4 bones[MAX_BONES]; 14 | 15 | // Input uniform values 16 | uniform mat4 mvp; 17 | uniform mat4 matModel; 18 | uniform mat4 matNormal; 19 | 20 | // Output vertex attributes (to fragment shader) 21 | out vec3 fragPosition; 22 | out vec2 fragTexCoord; 23 | out vec4 fragColor; 24 | out vec3 fragNormal; 25 | 26 | void main() 27 | { 28 | // non transformed data 29 | fragTexCoord = vertexTexCoord; 30 | fragColor = vertexColor; 31 | 32 | // bone ID stored in the UV2 chanel 33 | int bone0 = int(vertexTexCoord2.x / 1000); 34 | int bone1 = int(vertexTexCoord2.x - bone0*1000); 35 | int bone2 = int(vertexTexCoord2.y / 1000); 36 | int bone3 = int(vertexTexCoord2.y - bone2*1000); 37 | 38 | // vertex 39 | vec4 vertex = vec4(vertexPosition, 1.0f); 40 | 41 | vec4 blendedVert = bones[bone0] * vertex * vertexTangent.x; 42 | blendedVert += bones[bone1] * vertex * vertexTangent.y; 43 | blendedVert += bones[bone2] * vertex * vertexTangent.z; 44 | blendedVert += bones[bone3] * vertex * vertexTangent.w; 45 | blendedVert.w = 1.0f; 46 | 47 | gl_Position = mvp * blendedVert; 48 | 49 | // normals 50 | vec4 normal = vec4(vertexNormal, 0.0f); 51 | vec4 blendedNormal = bones[bone0] * normal * vertexTangent.x; 52 | blendedNormal += bones[bone1] * normal * vertexTangent.y; 53 | blendedNormal += bones[bone2] * normal * vertexTangent.z; 54 | blendedNormal += bones[bone3] * normal * vertexTangent.w; 55 | blendedNormal.w = 0.0f; 56 | 57 | fragNormal = normalize(vec3(matNormal*blendedNormal)); 58 | } -------------------------------------------------------------------------------- /interpolated_animation_gpu/resources/robot.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raylib-extras/examples-cpp/935b48d6f5fe597bd805c30355a193aef7d0e8fe/interpolated_animation_gpu/resources/robot.glb -------------------------------------------------------------------------------- /interpolated_animation_gpu/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-2024 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 | float shine; 54 | 55 | // Shader locations 56 | int enabledLoc; 57 | int typeLoc; 58 | int positionLoc; 59 | int targetLoc; 60 | int colorLoc; 61 | int attenuationLoc; 62 | int shineLoc; 63 | } Light; 64 | 65 | // Light type 66 | typedef enum { 67 | LIGHT_DIRECTIONAL = 0, 68 | LIGHT_POINT 69 | } LightType; 70 | 71 | #ifdef __cplusplus 72 | extern "C" { // Prevents name mangling of functions 73 | #endif 74 | 75 | //---------------------------------------------------------------------------------- 76 | // Module Functions Declaration 77 | //---------------------------------------------------------------------------------- 78 | Light CreateLight(int type, Vector3 position, Vector3 target, Color color, Shader shader); // Create a light and get shader locations 79 | void UpdateLightValues(Shader shader, Light light); // Send light properties to shader 80 | 81 | #ifdef __cplusplus 82 | } 83 | #endif 84 | 85 | #endif // RLIGHTS_H 86 | 87 | 88 | /*********************************************************************************** 89 | * 90 | * RLIGHTS IMPLEMENTATION 91 | * 92 | ************************************************************************************/ 93 | 94 | #if defined(RLIGHTS_IMPLEMENTATION) 95 | 96 | #include "raylib.h" 97 | 98 | //---------------------------------------------------------------------------------- 99 | // Defines and Macros 100 | //---------------------------------------------------------------------------------- 101 | // ... 102 | 103 | //---------------------------------------------------------------------------------- 104 | // Types and Structures Definition 105 | //---------------------------------------------------------------------------------- 106 | // ... 107 | 108 | //---------------------------------------------------------------------------------- 109 | // Global Variables Definition 110 | //---------------------------------------------------------------------------------- 111 | static int lightsCount = 0; // Current amount of created lights 112 | 113 | //---------------------------------------------------------------------------------- 114 | // Module specific Functions Declaration 115 | //---------------------------------------------------------------------------------- 116 | // ... 117 | 118 | //---------------------------------------------------------------------------------- 119 | // Module Functions Definition 120 | //---------------------------------------------------------------------------------- 121 | 122 | // Create a light and get shader locations 123 | Light CreateLight(int type, Vector3 position, Vector3 target, Color color, Shader shader) 124 | { 125 | Light light = { 0 }; 126 | 127 | if (lightsCount < MAX_LIGHTS) 128 | { 129 | light.enabled = true; 130 | light.type = type; 131 | light.position = position; 132 | light.target = target; 133 | light.color = color; 134 | light.attenuation = -1; 135 | light.shine = 16; 136 | 137 | // NOTE: Lighting shader naming must be the provided ones 138 | light.enabledLoc = GetShaderLocation(shader, TextFormat("lights[%i].enabled", lightsCount)); 139 | light.typeLoc = GetShaderLocation(shader, TextFormat("lights[%i].type", lightsCount)); 140 | light.positionLoc = GetShaderLocation(shader, TextFormat("lights[%i].position", lightsCount)); 141 | light.targetLoc = GetShaderLocation(shader, TextFormat("lights[%i].target", lightsCount)); 142 | light.colorLoc = GetShaderLocation(shader, TextFormat("lights[%i].color", lightsCount)); 143 | light.attenuationLoc = GetShaderLocation(shader, TextFormat("lights[%i].attenuation", lightsCount)); 144 | light.shineLoc = GetShaderLocation(shader, TextFormat("lights[%i].shine", lightsCount)); 145 | 146 | UpdateLightValues(shader, light); 147 | 148 | lightsCount++; 149 | } 150 | 151 | return light; 152 | } 153 | 154 | // Send light properties to shader 155 | // NOTE: Light shader locations should be available 156 | void UpdateLightValues(Shader shader, Light light) 157 | { 158 | // Send to shader light enabled state and type 159 | SetShaderValue(shader, light.enabledLoc, &light.enabled, SHADER_UNIFORM_INT); 160 | SetShaderValue(shader, light.typeLoc, &light.type, SHADER_UNIFORM_INT); 161 | 162 | // Send to shader light position values 163 | float position[3] = { light.position.x, light.position.y, light.position.z }; 164 | SetShaderValue(shader, light.positionLoc, position, SHADER_UNIFORM_VEC3); 165 | 166 | // Send to shader light target position values 167 | float target[3] = { light.target.x, light.target.y, light.target.z }; 168 | SetShaderValue(shader, light.targetLoc, target, SHADER_UNIFORM_VEC3); 169 | 170 | // Send to shader light color values 171 | float color[4] = { (float)light.color.r/(float)255, (float)light.color.g/(float)255, 172 | (float)light.color.b/(float)255, (float)light.color.a/(float)255 }; 173 | SetShaderValue(shader, light.colorLoc, color, SHADER_UNIFORM_VEC4); 174 | 175 | // Send to shader light attenuation value 176 | SetShaderValue(shader, light.attenuationLoc, &light.attenuation, SHADER_UNIFORM_FLOAT); 177 | 178 | // Send to shader light shine value 179 | SetShaderValue(shader, light.shineLoc, &light.shine, SHADER_UNIFORM_FLOAT); 180 | } 181 | 182 | #endif // RLIGHTS_IMPLEMENTATION -------------------------------------------------------------------------------- /inventory/README.md: -------------------------------------------------------------------------------- 1 | # inventory example 2 | A simple example of an inventory packing system. -------------------------------------------------------------------------------- /inventory/premake5.lua: -------------------------------------------------------------------------------- 1 | 2 | baseName = path.getbasename(os.getcwd()) 3 | 4 | defineWorkspace(baseName) -------------------------------------------------------------------------------- /inventory/resources/Items.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raylib-extras/examples-cpp/935b48d6f5fe597bd805c30355a193aef7d0e8fe/inventory/resources/Items.png -------------------------------------------------------------------------------- /pew/README.md: -------------------------------------------------------------------------------- 1 | # Pew-cpp 2 | A very simple game that shows time based movement, shooting and collision deection. 3 | 4 | Use A and D to turn the tank, use W and S to move it. 5 | Use the mouse to aim the turret and click to fire. 6 | Shoot the targets, don't run into them. 7 | Every 10 targets destoryed adds a new one. 8 | You have 3 lives 9 | 10 | Code shows how to use math to convert angles into vectors and apply those vectors to motion, using frame rate independent speeds. 11 | 12 | ![pew_game](https://user-images.githubusercontent.com/322174/138608560-47de649e-7316-42f3-a4f5-c8ba59ef8b98.gif) -------------------------------------------------------------------------------- /pew/pew.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 | #include 37 | #include 38 | 39 | constexpr int TargetSize = 20; 40 | constexpr float RefireTime = 0.25f; 41 | 42 | void SetRandomTarget(Vector2& pos) 43 | { 44 | pos.x = (float)GetRandomValue(TargetSize, GetScreenWidth() - TargetSize); 45 | pos.y = (float)GetRandomValue(TargetSize, GetScreenHeight() - TargetSize); 46 | } 47 | 48 | void KeepPosInBounds(Vector2& pos, float size, Vector2* velocity = nullptr) 49 | { 50 | if (pos.x < size) 51 | { 52 | if (velocity) 53 | velocity->x *= -1; 54 | pos.x = size; 55 | } 56 | 57 | if (pos.y < size) 58 | { 59 | if (velocity) 60 | velocity->y *= -1; 61 | pos.y = size; 62 | } 63 | 64 | if (pos.x > GetScreenWidth() - size) 65 | { 66 | if (velocity) 67 | velocity->x *= -1; 68 | pos.x = GetScreenWidth() - size; 69 | } 70 | 71 | if (pos.y > GetScreenHeight() - size) 72 | { 73 | if (velocity) 74 | velocity->y *= -1; 75 | pos.y = GetScreenHeight() - size; 76 | } 77 | } 78 | 79 | class Target 80 | { 81 | public: 82 | Vector2 Pos = { 0 }; 83 | Vector2 Velocity = { 0 }; 84 | float Speed = 50; 85 | float Lifetime = 0; 86 | float Size = 1; 87 | 88 | Target() 89 | { 90 | Reset(); 91 | } 92 | 93 | inline void Reset() 94 | { 95 | SetRandomTarget(Pos); 96 | Velocity.x = GetRandomValue(-1000, 1000) / 1000.0f; 97 | Velocity.y = GetRandomValue(-1000, 1000) / 1000.0f; 98 | Velocity = Vector2Normalize(Velocity); 99 | 100 | Lifetime = 0; 101 | Size = 1; 102 | Speed = (float)GetRandomValue(50, 150); 103 | } 104 | 105 | inline void Update() 106 | { 107 | Lifetime += GetFrameTime(); 108 | 109 | if (Lifetime < 1) 110 | Size = 1 + (Lifetime / 1.5f) * (TargetSize - 1); 111 | else 112 | Size = TargetSize; 113 | 114 | Pos = Vector2Add(Pos, Vector2Scale(Velocity, Speed * GetFrameTime())); 115 | 116 | KeepPosInBounds(Pos, Size, &Velocity); 117 | } 118 | 119 | bool Hit(Vector2& shot, float size) 120 | { 121 | if (CheckCollisionCircles(Pos, Size, shot, size)) 122 | { 123 | Reset(); 124 | return true; 125 | } 126 | 127 | return false; 128 | } 129 | 130 | inline void Draw() 131 | { 132 | DrawCircle((int)Pos.x, (int)Pos.y, Size, RED); 133 | DrawCircle((int)Pos.x, (int)Pos.y, Size * 0.75f, WHITE); 134 | DrawCircle((int)Pos.x, (int)Pos.y, Size * 0.5f, RED); 135 | DrawCircle((int)Pos.x, (int)Pos.y, Size * 0.25f, WHITE); 136 | } 137 | }; 138 | 139 | class Bullet 140 | { 141 | public: 142 | Vector2 Pos = { 0 }; 143 | Vector2 Velocity = { 0 }; 144 | float Speed = 750; 145 | float Lifetime = 0; 146 | const int Size = 2; 147 | 148 | public: 149 | Bullet(Vector2& playerPos, Vector2& velocityVector) 150 | { 151 | Velocity = velocityVector; 152 | 153 | // if the shot isn't moving, kill it 154 | if (Vector2LengthSqr(Velocity) == 0) 155 | { 156 | Lifetime = -1; 157 | return; 158 | } 159 | 160 | // put it a bit outside of our player pos 161 | Pos = Vector2Add(playerPos, Vector2Scale(Velocity, 10)); 162 | Lifetime = 2; 163 | 164 | // compute an angle for our shot drawing 165 | ShotAngle = atan2f(Velocity.y, Velocity.x) * RAD2DEG; 166 | } 167 | 168 | inline bool IsDead() 169 | { 170 | return Lifetime <= 0; 171 | } 172 | 173 | inline void Update() 174 | { 175 | // see if we die 176 | Lifetime -= GetFrameTime(); 177 | if (Lifetime <= 0) 178 | return; 179 | 180 | Pos = Vector2Add(Pos, Vector2Scale(Velocity, Speed * GetFrameTime())); 181 | 182 | // see if we went out of bounds, if so, we die 183 | if (Pos.x < -Size || Pos.y < -Size || Pos.x > GetScreenWidth() + Size || Pos.y > GetScreenHeight() + Size) 184 | { 185 | Lifetime = -1; 186 | return; 187 | } 188 | } 189 | 190 | inline void Draw() 191 | { 192 | Rectangle rect = { Pos.x, Pos.y, Size * 6.0f, Size * 2.0f }; 193 | Vector2 center = { Size * 3.0f, (float)Size }; 194 | DrawRectanglePro(rect, center, ShotAngle, RED); 195 | } 196 | 197 | protected: 198 | float ShotAngle = 0; 199 | }; 200 | 201 | int main() 202 | { 203 | SetConfigFlags(FLAG_VSYNC_HINT); 204 | InitWindow(1280, 800, "Shooter Sample"); 205 | SetTargetFPS(144); 206 | 207 | Vector2 PlayerPos = { 600, 400 }; 208 | float PlayerAngle = -90; 209 | float AimAngle = 0; 210 | 211 | Rectangle screenRect = Rectangle{ 0, 0 ,(float)GetScreenWidth(), (float)GetScreenHeight() }; 212 | 213 | bool wantFire = false; 214 | float reloadTime = -RefireTime; 215 | 216 | std::list bullets; 217 | 218 | std::vector targets; 219 | 220 | for (int i =0; i < 10; i++) 221 | { 222 | targets.emplace_back(Target()); 223 | } 224 | 225 | int score = 0; 226 | int lives = 3; 227 | 228 | bool gameOn = true; 229 | 230 | while (!WindowShouldClose()) 231 | { 232 | // save the vector to the mouse 233 | Vector2 aimVector = Vector2Normalize(Vector2Subtract(GetMousePosition(), PlayerPos)); 234 | Vector2 movementVector = Vector2{ cosf(PlayerAngle * DEG2RAD), sinf(PlayerAngle * DEG2RAD) }; 235 | 236 | if (gameOn) 237 | { 238 | // move player 239 | float moveSpeed = 200 * GetFrameTime(); 240 | float turnSpeed = 180 * GetFrameTime(); 241 | 242 | if (IsKeyDown(KEY_A)) 243 | PlayerAngle -= turnSpeed; 244 | if (IsKeyDown(KEY_D)) 245 | PlayerAngle += turnSpeed; 246 | 247 | movementVector = Vector2{ cosf(PlayerAngle * DEG2RAD), sinf(PlayerAngle * DEG2RAD) }; 248 | 249 | if (IsKeyDown(KEY_W)) 250 | PlayerPos = Vector2Add(PlayerPos, Vector2Scale(movementVector, moveSpeed)); 251 | if (IsKeyDown(KEY_S)) 252 | PlayerPos = Vector2Add(PlayerPos, Vector2Scale(movementVector, -moveSpeed)); 253 | 254 | // keep player in bounds 255 | KeepPosInBounds(PlayerPos, 30); 256 | 257 | // see where we are aiming 258 | aimVector = Vector2Normalize(Vector2Subtract(GetMousePosition(), PlayerPos)); 259 | if (Vector2LengthSqr(aimVector) > 0) // don't update the angle if the mouse is on the player 260 | AimAngle = atan2f(aimVector.y, aimVector.x) * RAD2DEG; 261 | 262 | // set the vector to match the angle (in case it was invalid) 263 | aimVector.x = cosf(AimAngle * DEG2RAD); 264 | aimVector.y = sinf(AimAngle * DEG2RAD); 265 | } 266 | else 267 | { 268 | if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) 269 | { 270 | // restart the game 271 | gameOn = true; 272 | score = 0; 273 | lives = 3; 274 | SetRandomTarget(PlayerPos); 275 | 276 | // get us back down to 10 targets 277 | while (targets.size() > 10) 278 | targets.erase(targets.begin()); 279 | } 280 | } 281 | 282 | // move targets 283 | for (auto& target : targets) 284 | { 285 | target.Update(); 286 | 287 | // see if we hit the target, if so, we die 288 | if (target.Hit(PlayerPos, 30)) 289 | { 290 | lives--; 291 | SetRandomTarget(PlayerPos); 292 | if (lives <= 0) 293 | { 294 | gameOn = false; 295 | } 296 | } 297 | } 298 | 299 | if (gameOn) 300 | { 301 | // make a shot 302 | reloadTime -= GetFrameTime(); 303 | if (IsMouseButtonDown(MOUSE_LEFT_BUTTON) && reloadTime <= 0) 304 | { 305 | wantFire = false; 306 | reloadTime = RefireTime; 307 | bullets.emplace_back(Bullet(PlayerPos, aimVector)); 308 | } 309 | } 310 | 311 | // update shots and cull any dead ones 312 | for (std::list::iterator itr = bullets.begin(); itr != bullets.end();) 313 | { 314 | itr->Update(); 315 | if (itr->IsDead() || !gameOn) 316 | { 317 | itr = bullets.erase(itr); 318 | } 319 | else 320 | { 321 | for (auto& target : targets) 322 | { 323 | if (target.Hit(itr->Pos, itr->Size*2.0f)) 324 | { 325 | itr->Lifetime = 0; 326 | score++; 327 | 328 | if (score % 10 == 0) 329 | targets.emplace_back(Target()); 330 | } 331 | } 332 | itr++; 333 | } 334 | } 335 | 336 | BeginDrawing(); 337 | ClearBackground(DARKGREEN); 338 | 339 | for (auto& target : targets) 340 | target.Draw(); 341 | 342 | for (auto& bullet : bullets) 343 | bullet.Draw(); 344 | 345 | // draw player 346 | if (gameOn) 347 | { 348 | DrawRectanglePro(Rectangle{ PlayerPos.x, PlayerPos.y,40,30 }, Vector2{ 20,15 }, PlayerAngle, DARKGRAY); 349 | 350 | DrawCircle((int)(PlayerPos.x + movementVector.x * 15), (int)(PlayerPos.y + movementVector.y * 15), 7, GRAY); 351 | 352 | DrawCircle((int)PlayerPos.x, (int)PlayerPos.y, 10, BLUE); 353 | 354 | Rectangle aimRectangle = { PlayerPos.x, PlayerPos.y, 26, 4 }; 355 | DrawRectanglePro(aimRectangle, Vector2{ -5, 2 }, AimAngle, DARKBLUE); 356 | 357 | DrawText(TextFormat("Score %d Lives %d", score, lives), 0, 0, 20, RAYWHITE); 358 | } 359 | else 360 | { 361 | std::string message = "Game Over, Click to Restart"; 362 | int textSize = MeasureText(message.c_str(), 20); 363 | DrawText(message.c_str(), GetScreenWidth()/2 - textSize/2, 400, 20, RAYWHITE); 364 | } 365 | 366 | EndDrawing(); 367 | } 368 | 369 | CloseWindow(); 370 | 371 | return 0; 372 | } -------------------------------------------------------------------------------- /pew/premake5.lua: -------------------------------------------------------------------------------- 1 | 2 | baseName = path.getbasename(os.getcwd()) 3 | 4 | defineWorkspace(baseName) -------------------------------------------------------------------------------- /platform_example/README.md: -------------------------------------------------------------------------------- 1 | # platform_example 2 | A very simple demo that shows platformer style motion, sprites, collision, and camera work 3 | 4 | Use A and D to run left and right 5 | Use Space to Jump, and S+Space to drop down. 6 | 7 | 8 | Code shows how to manage actor states and manage animation frames for sprite animation at different frame rates from a sprite sheet. 9 | 10 | ![platform_jump](https://user-images.githubusercontent.com/322174/147867102-ce62fbbd-2f2a-4ccd-8d44-9f49450b9df5.gif) 11 | 12 | Sprite from Itch.io: https://clembod.itch.io -------------------------------------------------------------------------------- /platform_example/premake5.lua: -------------------------------------------------------------------------------- 1 | 2 | baseName = path.getbasename(os.getcwd()) 3 | 4 | defineWorkspace(baseName) -------------------------------------------------------------------------------- /platform_example/resources/Warrior_Sheet-Effect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raylib-extras/examples-cpp/935b48d6f5fe597bd805c30355a193aef7d0e8fe/platform_example/resources/Warrior_Sheet-Effect.png -------------------------------------------------------------------------------- /platform_example/resources/panel_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raylib-extras/examples-cpp/935b48d6f5fe597bd805c30355a193aef7d0e8fe/platform_example/resources/panel_blue.png -------------------------------------------------------------------------------- /platform_example/sprites.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************************* 2 | * 3 | * Sprite animation and movement example 4 | * 5 | * Welcome to raylib! 6 | * 7 | * To test examples, just press F6 and execute raylib_compile_execute script 8 | * Note that compiled executable is placed in the same folder as .c file 9 | * 10 | * You can find all basic examples on C:\raylib\raylib\examples folder or 11 | * raylib official webpage: www.raylib.com 12 | * 13 | * Enjoy using raylib. :) 14 | * 15 | * This example has been created using raylib 4.0 (www.raylib.com) 16 | * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) 17 | * 18 | * Copyright (c) 2022 Jeffery Myers 19 | * 20 | ********************************************************************************************/ 21 | 22 | #include "sprites.h" 23 | 24 | #include 25 | 26 | SpriteSheet LoadSpriteSheet(const char* file, int cols, int rows) 27 | { 28 | SpriteSheet sheet = { 0 }; 29 | sheet.SheetTexture = LoadTexture(file); 30 | if (sheet.SheetTexture.id >= 0) 31 | { 32 | float w = (float)sheet.SheetTexture.width / cols; 33 | float h = (float)sheet.SheetTexture.height / rows; 34 | 35 | for (int y = 0; y < rows; y++) 36 | { 37 | for (int x = 0; x < cols; x++) 38 | { 39 | sheet.Frames.emplace_back(Rectangle{ x * w,y * h,w,h }); 40 | } 41 | } 42 | } 43 | 44 | return std::move(sheet); 45 | } 46 | 47 | int AddFippedFrames(SpriteSheet& sheet, int start, int end, bool flipX, int flipY) 48 | { 49 | int delta = end - start; 50 | int offset = delta / abs(delta); 51 | 52 | 53 | int newStart = (int)sheet.Frames.size(); 54 | for (int i = start; i != end + offset; i += offset) 55 | { 56 | if (i >= 0 || i < (int)sheet.Frames.size()) 57 | { 58 | Rectangle rect = sheet.Frames[i]; 59 | if (flipX) 60 | rect.width *= -1; 61 | if (flipY) 62 | rect.height *= -1; 63 | 64 | sheet.Frames.emplace_back(std::move(rect)); 65 | } 66 | } 67 | 68 | return newStart; 69 | } 70 | 71 | void DrawSprite(SpriteInstance& sprite) 72 | { 73 | if (sprite.Sheet == nullptr || sprite.Sheet->SheetTexture.id == 0 || sprite.Animation == nullptr) 74 | return; 75 | 76 | Rectangle frame = sprite.Sheet->Frames[sprite.CurrentFrame]; 77 | DrawTexturePro(sprite.Sheet->SheetTexture, frame, Rectangle{ sprite.Position.x,sprite.Position.y,fabsf(frame.width),fabsf(frame.height)}, sprite.Offset, 0, WHITE); 78 | } 79 | 80 | void UpdateSpriteAnimation(SpriteInstance& sprite) 81 | { 82 | if (sprite.Animation == nullptr) 83 | return; 84 | 85 | sprite.FrameLifetime += GetFrameTime(); 86 | if (sprite.FrameLifetime > 1.0f / sprite.Animation->FPS) 87 | { 88 | sprite.FrameLifetime = 0; 89 | sprite.CurrentFrame++; 90 | sprite.AnimationDone = false; 91 | if (sprite.CurrentFrame > sprite.Animation->EndFrame) 92 | { 93 | if (sprite.Animation->Loops) 94 | sprite.CurrentFrame = sprite.Animation->StartFrame; 95 | else 96 | { 97 | sprite.AnimationDone = true; 98 | sprite.CurrentFrame--; 99 | } 100 | } 101 | } 102 | } 103 | 104 | void SetSpriteAnimation(SpriteInstance& sprite, const SpriteAnimation& animation) 105 | { 106 | sprite.Animation = &animation; 107 | sprite.CurrentFrame = animation.StartFrame; 108 | sprite.FrameLifetime = 0; 109 | sprite.AnimationDone = false; 110 | } 111 | -------------------------------------------------------------------------------- /platform_example/sprites.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************************* 2 | * 3 | * Sprite animation and movement example 4 | * 5 | * Welcome to raylib! 6 | * 7 | * To test examples, just press F6 and execute raylib_compile_execute script 8 | * Note that compiled executable is placed in the same folder as .c file 9 | * 10 | * You can find all basic examples on C:\raylib\raylib\examples folder or 11 | * raylib official webpage: www.raylib.com 12 | * 13 | * Enjoy using raylib. :) 14 | * 15 | * This example has been created using raylib 4.0 (www.raylib.com) 16 | * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) 17 | * 18 | * Copyright (c) 2022 Jeffery Myers 19 | * 20 | ********************************************************************************************/ 21 | #pragma once 22 | 23 | #include "raylib.h" 24 | #include 25 | #include 26 | 27 | struct SpriteSheet 28 | { 29 | Texture2D SheetTexture = { 0 }; 30 | std::vector Frames; 31 | }; 32 | 33 | struct SpriteAnimation 34 | { 35 | std::string Name; 36 | int StartFrame = -1; 37 | int EndFrame = -1; 38 | float FPS = 15; 39 | bool Loops = true; 40 | }; 41 | 42 | struct SpriteInstance 43 | { 44 | Vector2 Position = { 0 }; 45 | 46 | Vector2 Offset = { 0,0 }; 47 | const SpriteSheet* Sheet = nullptr; 48 | const SpriteAnimation* Animation = nullptr; 49 | bool AnimationDone = false; 50 | int CurrentFrame = -1; 51 | float FrameLifetime = 0; 52 | }; 53 | 54 | SpriteSheet LoadSpriteSheet(const char* file, int cols, int rows); 55 | int AddFippedFrames(SpriteSheet& sheet, int start, int end, bool flipX, int flipY); 56 | 57 | void DrawSprite(SpriteInstance& sprite); 58 | void UpdateSpriteAnimation(SpriteInstance& sprite); 59 | void SetSpriteAnimation(SpriteInstance& sprite, const SpriteAnimation& animation); 60 | -------------------------------------------------------------------------------- /premake-VisualStudio.bat: -------------------------------------------------------------------------------- 1 | premake5.exe vs2022 2 | pause 3 | -------------------------------------------------------------------------------- /premake-mingw.bat: -------------------------------------------------------------------------------- 1 | premake5.exe gmake2 2 | pause 3 | -------------------------------------------------------------------------------- /premake5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raylib-extras/examples-cpp/935b48d6f5fe597bd805c30355a193aef7d0e8fe/premake5 -------------------------------------------------------------------------------- /premake5.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raylib-extras/examples-cpp/935b48d6f5fe597bd805c30355a193aef7d0e8fe/premake5.exe -------------------------------------------------------------------------------- /premake5.lua: -------------------------------------------------------------------------------- 1 | 2 | newoption 3 | { 4 | trigger = "graphics", 5 | value = "OPENGL_VERSION", 6 | description = "version of OpenGL to build raylib against", 7 | allowed = { 8 | { "opengl11", "OpenGL 1.1"}, 9 | { "opengl21", "OpenGL 2.1"}, 10 | { "opengl33", "OpenGL 3.3"}, 11 | { "opengl43", "OpenGL 4.3"} 12 | }, 13 | default = "opengl33" 14 | } 15 | 16 | function define_C() 17 | language "C" 18 | end 19 | 20 | function define_Cpp() 21 | language "C++" 22 | end 23 | 24 | function string.starts(String,Start) 25 | return string.sub(String,1,string.len(Start))==Start 26 | end 27 | 28 | function link_to(lib) 29 | links (lib) 30 | includedirs ("../"..lib,"../"..lib.."/include" ) 31 | end 32 | 33 | function download_progress(total, current) 34 | local ratio = current / total; 35 | ratio = math.min(math.max(ratio, 0), 1); 36 | local percent = math.floor(ratio * 100); 37 | print("Download progress (" .. percent .. "%/100%)") 38 | end 39 | 40 | function check_raylib() 41 | if(os.isdir("raylib") == false and os.isdir("raylib-master") == false) then 42 | if(not os.isfile("raylib-master.zip")) then 43 | print("Raylib not found, downloading from github") 44 | local result_str, response_code = http.download("https://github.com/raysan5/raylib/archive/refs/heads/master.zip", "raylib-master.zip", { 45 | progress = download_progress, 46 | headers = { "From: Premake", "Referer: Premake" } 47 | }) 48 | end 49 | print("Unzipping to " .. os.getcwd()) 50 | zip.extract("raylib-master.zip", os.getcwd()) 51 | os.remove("raylib-master.zip") 52 | end 53 | end 54 | 55 | function check_box2d() 56 | if(os.isdir(".box2d") == false and os.isdir("box2d-main") == false) then 57 | if(not os.isfile("box2d-main.zip")) then 58 | print("box2d not found, downloading from github") 59 | local result_str, response_code = http.download("https://github.com/erincatto/box2d/archive/refs/heads/main.zip", "box2d-main.zip", { 60 | progress = download_progress, 61 | headers = { "From: Premake", "Referer: Premake" } 62 | }) 63 | end 64 | print("Unzipping to " .. os.getcwd()) 65 | zip.extract("box2d-main.zip", os.getcwd()) 66 | os.remove("box2d-main.zip") 67 | end 68 | end 69 | 70 | function defineWorkspace(baseName) 71 | workspace (baseName) 72 | configurations { "Debug", "Release"} 73 | platforms { "x64", "x86"} 74 | 75 | filter "configurations:Debug" 76 | defines { "DEBUG" } 77 | symbols "On" 78 | 79 | filter "configurations:Release" 80 | defines { "NDEBUG" } 81 | optimize "On" 82 | 83 | filter { "platforms:x64" } 84 | architecture "x86_64" 85 | 86 | filter {} 87 | 88 | targetdir "_bin/%{cfg.buildcfg}/" 89 | 90 | startproject(baseName) 91 | 92 | defineRaylibProject() 93 | 94 | project (baseName) 95 | kind "ConsoleApp" 96 | location "_build" 97 | targetdir "_bin/%{cfg.buildcfg}" 98 | 99 | filter "action:vs*" 100 | debugdir "$(SolutionDir)" 101 | 102 | filter {"action:vs*", "configurations:Release"} 103 | kind "WindowedApp" 104 | entrypoint "mainCRTStartup" 105 | 106 | filter{} 107 | 108 | vpaths 109 | { 110 | ["Header Files/*"] = { "include/**.h", "include/**.hpp", "src/**.h", "src/**.hpp", "**.h", "**.hpp"}, 111 | ["Source Files/*"] = {"src/**.c", "src/**.cpp","**.c", "**.cpp"}, 112 | } 113 | files {"**.c", "**.cpp", "**.h", "**.hpp"} 114 | 115 | includedirs { "./"} 116 | includedirs { "./src"} 117 | includedirs { "./include"} 118 | link_raylib(); 119 | end 120 | 121 | include ("raylib_premake5.lua") 122 | cdialect "C99" 123 | cppdialect "C++17" 124 | check_raylib() 125 | check_box2d() 126 | 127 | folders = os.matchdirs("*") 128 | for _, folderName in ipairs(folders) do 129 | if (string.starts(folderName, "raylib") == false and string.starts(folderName, "_") == false and string.starts(folderName, ".") == false) then 130 | if (os.isfile(folderName .. "/premake5.lua")) then 131 | print(folderName) 132 | include (folderName) 133 | end 134 | end 135 | end 136 | -------------------------------------------------------------------------------- /premake5.osx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raylib-extras/examples-cpp/935b48d6f5fe597bd805c30355a193aef7d0e8fe/premake5.osx -------------------------------------------------------------------------------- /rayGui-cpp/premake5.lua: -------------------------------------------------------------------------------- 1 | 2 | baseName = path.getbasename(os.getcwd()) 3 | 4 | defineWorkspace(baseName) -------------------------------------------------------------------------------- /raycaster/README.md: -------------------------------------------------------------------------------- 1 | # raycaster 2 | Raylib software Raycaster similar to Wolfenstein 3D 3 | Based on algorithms from https://lodev.org/cgtutor/raycasting.html 4 | 5 | ![raycaster](https://user-images.githubusercontent.com/322174/203472549-2918ff06-0cb9-492d-bb8a-85fce61bc108.gif) -------------------------------------------------------------------------------- /raycaster/premake5.lua: -------------------------------------------------------------------------------- 1 | 2 | baseName = path.getbasename(os.getcwd()) 3 | 4 | defineWorkspace(baseName) -------------------------------------------------------------------------------- /raycaster/resources/textures.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raylib-extras/examples-cpp/935b48d6f5fe597bd805c30355a193aef7d0e8fe/raycaster/resources/textures.png -------------------------------------------------------------------------------- /raylib_premake5.lua: -------------------------------------------------------------------------------- 1 | 2 | function platform_defines() 3 | defines{"PLATFORM_DESKTOP"} 4 | 5 | filter {"options:graphics=opengl43"} 6 | defines{"GRAPHICS_API_OPENGL_43"} 7 | 8 | filter {"options:graphics=opengl33"} 9 | defines{"GRAPHICS_API_OPENGL_33"} 10 | 11 | filter {"options:graphics=opengl21"} 12 | defines{"GRAPHICS_API_OPENGL_21"} 13 | 14 | filter {"options:graphics=opengl11"} 15 | defines{"GRAPHICS_API_OPENGL_11"} 16 | 17 | filter {"system:macosx"} 18 | disablewarnings {"deprecated-declarations"} 19 | 20 | filter{} 21 | end 22 | 23 | function get_raylib_dir() 24 | if (os.isdir("raylib-master")) then 25 | return "raylib-master" 26 | end 27 | if (os.isdir("../raylib-master")) then 28 | return "../raylib-master" 29 | end 30 | if (os.isdir("../raylib")) then 31 | return "../raylib" 32 | end 33 | return "raylib" 34 | end 35 | 36 | function link_raylib() 37 | links {"raylib"} 38 | 39 | raylib_dir = get_raylib_dir(); 40 | includedirs {raylib_dir .. "/src" } 41 | includedirs {raylib_dir .."/src/external" } 42 | includedirs {raylib_dir .."/src/external/glfw/include" } 43 | platform_defines() 44 | 45 | libdirs {"_bin/%{cfg.buildcfg}"} 46 | 47 | filter "action:vs*" 48 | defines{"_WINSOCK_DEPRECATED_NO_WARNINGS", "_CRT_SECURE_NO_WARNINGS"} 49 | dependson {"raylib"} 50 | links {"raylib.lib"} 51 | characterset ("MBCS") 52 | 53 | filter "system:windows" 54 | defines{"_WIN32"} 55 | links {"winmm", "kernel32", "opengl32", "gdi32"} 56 | libdirs {"../_bin/%{cfg.buildcfg}"} 57 | 58 | filter "system:linux" 59 | links {"pthread", "GL", "m", "dl", "rt", "X11"} 60 | 61 | filter "system:macosx" 62 | links {"OpenGL.framework", "Cocoa.framework", "IOKit.framework", "CoreFoundation.framework", "CoreAudio.framework", "CoreVideo.framework"} 63 | 64 | filter{} 65 | end 66 | 67 | function include_raylib() 68 | raylib_dir = get_raylib_dir(); 69 | includedirs {raylib_dir .."/src" } 70 | includedirs {raylib_dir .."/src/external" } 71 | includedirs {raylib_dir .."/src/external/glfw/include" } 72 | platform_defines() 73 | 74 | filter "action:vs*" 75 | defines{"_WINSOCK_DEPRECATED_NO_WARNINGS", "_CRT_SECURE_NO_WARNINGS"} 76 | 77 | filter{} 78 | end 79 | 80 | function defineRaylibProject() 81 | project "raylib" 82 | kind "StaticLib" 83 | 84 | platform_defines() 85 | 86 | location "_build" 87 | language "C" 88 | targetdir "_bin/%{cfg.buildcfg}" 89 | 90 | filter "action:vs*" 91 | defines{"_WINSOCK_DEPRECATED_NO_WARNINGS", "_CRT_SECURE_NO_WARNINGS"} 92 | characterset ("MBCS") 93 | 94 | filter{} 95 | 96 | raylib_dir = get_raylib_dir(); 97 | print ("Using raylib dir " .. raylib_dir); 98 | includedirs {raylib_dir .. "/src", raylib_dir .. "/src/external/glfw/include" } 99 | vpaths 100 | { 101 | ["Header Files"] = { raylib_dir .. "/src/**.h"}, 102 | ["Source Files/*"] = { raylib_dir .. "/src/**.c"}, 103 | } 104 | files {raylib_dir .. "/src/*.h", raylib_dir .. "/src/*.c"} 105 | 106 | 107 | removefiles {raylib_dir .. "/src/rcore_*.c"} 108 | 109 | 110 | filter { "system:macosx", "files:" .. raylib_dir .. "/src/rglfw.c" } 111 | compileas "Objective-C" 112 | 113 | filter{} 114 | end 115 | -------------------------------------------------------------------------------- /skill_tree/README.md: -------------------------------------------------------------------------------- 1 | # skill tree 2 | A simple example of navigating skill tree type display using a camera 2d. 3 | right drag to pan, click on a skill to select it and center it, mouse wheel to zoom -------------------------------------------------------------------------------- /skill_tree/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Simple skill tree using a camera2d 3 | 4 | -- Copyright (c) 2020-2024 Jeffery Myers 5 | -- 6 | --This software is provided "as-is", without any express or implied warranty. In no event 7 | --will the authors be held liable for any damages arising from the use of this software. 8 | 9 | --Permission is granted to anyone to use this software for any purpose, including commercial 10 | --applications, and to alter it and redistribute it freely, subject to the following restrictions: 11 | 12 | -- 1. The origin of this software must not be misrepresented; you must not claim that you 13 | -- wrote the original software. If you use this software in a product, an acknowledgment 14 | -- in the product documentation would be appreciated but is not required. 15 | -- 16 | -- 2. Altered source versions must be plainly marked as such, and must not be misrepresented 17 | -- as being the original software. 18 | -- 19 | -- 3. This notice may not be removed or altered from any source distribution. 20 | 21 | */ 22 | 23 | #include "raylib.h" 24 | #include "raymath.h" 25 | 26 | #include 27 | #include 28 | 29 | Camera2D ViewCamera = { 0 }; 30 | 31 | struct SkillItem 32 | { 33 | Vector2 Postion = Vector2Zeros; 34 | 35 | std::string Icon; 36 | std::string Name; 37 | std::string Description; 38 | 39 | Color Tint = DARKGRAY; 40 | 41 | int ParentIndex = -1; 42 | std::vector ChildrenIndexes; 43 | }; 44 | 45 | std::vector Skills; 46 | 47 | int SelectedSkill = -1; 48 | 49 | Vector2 DesiredTarget = { -1,1 }; 50 | bool MovingToTarget = false; 51 | 52 | void Init() 53 | { 54 | ViewCamera.zoom = 1; 55 | ViewCamera.offset = Vector2{ GetScreenWidth() * 0.5f, GetScreenHeight() * 0.5f }; 56 | 57 | // inner ring 58 | float angleDelta = 360.0f/16.0f; 59 | 60 | float innerRadius = 200; 61 | for (int i = 0; i < 16; i++) 62 | { 63 | float angle = i * angleDelta; 64 | Vector2 pos = Vector2{ cosf(angle * DEG2RAD), sinf(angle * DEG2RAD) }; 65 | 66 | pos *= innerRadius; 67 | 68 | Skills.emplace_back(); 69 | Skills.back().Postion = pos; 70 | Skills.back().Icon = TextFormat("%d", i); 71 | Skills.back().Name = "Base Skill " + Skills.back().Icon; 72 | Skills.back().Description = "A simple inner ring skill"; 73 | Skills.back().Tint = DARKGREEN; 74 | } 75 | 76 | // outer ring 77 | float outerRadius = 500; 78 | 79 | angleDelta = 360.0f / 32; 80 | for (int i = 0; i < 32; i++) 81 | { 82 | float angle = (i * angleDelta) - (angleDelta/2); 83 | Vector2 pos = Vector2{ cosf(angle * DEG2RAD), sinf(angle * DEG2RAD) }; 84 | 85 | int parent = i / 2; 86 | 87 | pos *= outerRadius; 88 | 89 | Skills.emplace_back(); 90 | Skills.back().Postion = pos; 91 | Skills.back().Icon = TextFormat("%d", i + 16); 92 | Skills.back().Name = "Mid Skill " + Skills.back().Icon; 93 | Skills.back().Description = "A simple mid ring skill"; 94 | Skills.back().Tint = DARKBLUE; 95 | 96 | Skills.back().ParentIndex = parent; 97 | 98 | Skills[parent].ChildrenIndexes.push_back(i + 16); 99 | } 100 | } 101 | 102 | void RecenterOffset() 103 | { 104 | Vector2 offsetInWorldSpce = GetScreenToWorld2D(ViewCamera.offset, ViewCamera); 105 | Vector2 centerInWorldSpace = GetScreenToWorld2D(Vector2{ GetScreenWidth() * 0.5f, GetScreenHeight() * 0.5f }, ViewCamera); 106 | 107 | ViewCamera.target += centerInWorldSpace - offsetInWorldSpce; 108 | 109 | ViewCamera.offset = Vector2{ GetScreenWidth() * 0.5f, GetScreenHeight() * 0.5f }; 110 | } 111 | 112 | void DrawTree() 113 | { 114 | Vector2 mouseInWorld = GetScreenToWorld2D(GetMousePosition(), ViewCamera); 115 | for (int i = int(Skills.size())-1; i >= 0; i--) 116 | { 117 | auto& skill = Skills[i]; 118 | if (skill.ParentIndex >= 0) 119 | DrawLineV(skill.Postion, Skills[skill.ParentIndex].Postion, WHITE); 120 | else 121 | DrawLineV(skill.Postion, Vector2Zeros, GRAY); 122 | 123 | if (CheckCollisionPointCircle(mouseInWorld, skill.Postion, 20)) 124 | { 125 | DrawCircleV(skill.Postion, 28, YELLOW); 126 | 127 | if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) 128 | { 129 | RecenterOffset(); 130 | 131 | DesiredTarget = skill.Postion; 132 | MovingToTarget = true; 133 | SelectedSkill = i; 134 | } 135 | 136 | DrawText(skill.Description.c_str(), int(skill.Postion.x) - 50, int(skill.Postion.y) + 30, 10, SKYBLUE); 137 | } 138 | 139 | // if (SelectedSkill == i) 140 | // DrawCircleV(skill.Postion, 23, PURPLE); 141 | 142 | DrawCircleV(skill.Postion, 20, skill.Tint); 143 | DrawCircleLinesV(skill.Postion, 20, DARKGRAY); 144 | DrawTextEx(GetFontDefault(), skill.Icon.c_str(), skill.Postion - (Vector2Ones * 5), 20, 1, WHITE); 145 | DrawText(skill.Name.c_str(), int(skill.Postion.x) - 50, int(skill.Postion.y) - 45, 20, WHITE); 146 | } 147 | 148 | // if (!MovingToTarget && IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) 149 | // SelectedSkill = -1; 150 | } 151 | 152 | int main () 153 | { 154 | // Tell the window to use vsync and work on high DPI displays 155 | SetConfigFlags(FLAG_VSYNC_HINT); 156 | 157 | // Create the window and OpenGL context 158 | InitWindow(1280, 800, "Hello Skilltree"); 159 | 160 | Init(); 161 | 162 | // game loop 163 | while (!WindowShouldClose()) // run the loop until the user presses ESCAPE or presses the Close button on the window 164 | { 165 | // see if the user dragged with the right button 166 | if (IsMouseButtonDown(MOUSE_BUTTON_RIGHT)) 167 | { 168 | RecenterOffset(); 169 | 170 | Vector2 worldMouseDrag = GetMouseDelta() / ViewCamera.zoom; 171 | ViewCamera.target -= worldMouseDrag; 172 | MovingToTarget = false; 173 | } 174 | 175 | if (GetMouseWheelMove() != 0) 176 | { 177 | MovingToTarget = false; 178 | 179 | // get the world point that is under the mouse 180 | Vector2 mouseWorldPos = GetScreenToWorld2D(GetMousePosition(), ViewCamera); 181 | 182 | // set the offset to where the mouse is 183 | ViewCamera.offset = GetMousePosition(); 184 | 185 | // set the target to match, so that the camera maps the world space point under the cursor to the screen space point under the cursor at any zoom 186 | ViewCamera.target = mouseWorldPos; 187 | 188 | // zoom on the mouse point since that's where our origin is 189 | ViewCamera.zoom += (GetMouseWheelMove() / fabsf(GetMouseWheelMove())) * 0.1f; 190 | 191 | if (ViewCamera.zoom < 0.1f) 192 | ViewCamera.zoom = 0.1f; 193 | } 194 | 195 | // do we want to animate to some location? 196 | if (MovingToTarget) 197 | { 198 | float maxMove = 800 * GetFrameTime(); 199 | 200 | Vector2 vecToTarget = DesiredTarget - ViewCamera.target; 201 | float len = Vector2Length(vecToTarget); 202 | 203 | if (len < maxMove) 204 | { 205 | ViewCamera.target = DesiredTarget; 206 | MovingToTarget = false; 207 | } 208 | else 209 | { 210 | vecToTarget /= len; 211 | vecToTarget *= maxMove; 212 | ViewCamera.target += vecToTarget; 213 | } 214 | } 215 | 216 | // drawing 217 | BeginDrawing(); 218 | 219 | // Setup the back buffer for drawing (clear color and depth buffers) 220 | ClearBackground(BLACK); 221 | 222 | BeginMode2D(ViewCamera); 223 | DrawTree(); 224 | DrawCircle(0, 0, 10, RED); 225 | EndMode2D(); 226 | 227 | if (SelectedSkill >= 0) 228 | { 229 | DrawText(Skills[SelectedSkill].Name.c_str(), 5, 5, 20, YELLOW); 230 | DrawText(Skills[SelectedSkill].Description.c_str(), 5, 25, 20, YELLOW); 231 | } 232 | 233 | DrawFPS(0, GetScreenHeight() - 20); 234 | 235 | // end the frame and get ready for the next one (display frame, poll input, etc...) 236 | EndDrawing(); 237 | } 238 | 239 | // destroy the window and cleanup the OpenGL context 240 | CloseWindow(); 241 | return 0; 242 | } 243 | -------------------------------------------------------------------------------- /skill_tree/premake5.lua: -------------------------------------------------------------------------------- 1 | 2 | baseName = path.getbasename(os.getcwd()) 3 | 4 | defineWorkspace(baseName) -------------------------------------------------------------------------------- /stencil_reflection/main.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * raylib-extras, examples-cpp * examples for Raylib in C++ 4 | * 5 | * stencil_reflection * an example of using the stencil buffer for reflections 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 "rlgl.h" 33 | 34 | #include "external/glad.h" 35 | 36 | // stencil mask stuff 37 | 38 | 39 | int main() 40 | { 41 | SetConfigFlags(FLAG_VSYNC_HINT); 42 | InitWindow(1280, 800, "Reflections"); 43 | SetTargetFPS(144); 44 | 45 | float spinAngle = 0; 46 | Camera3D camera = { 0 }; 47 | 48 | camera.fovy = 60; 49 | camera.up.y = 1; 50 | camera.position.z = -5; 51 | camera.position.y = 2; 52 | 53 | while (!WindowShouldClose()) 54 | { 55 | spinAngle += GetFrameTime() * 45; 56 | 57 | BeginDrawing(); 58 | ClearBackground(GRAY); 59 | 60 | BeginMode3D(camera); 61 | 62 | rlPushMatrix(); 63 | rlRotatef(spinAngle, 0, 1, 0); 64 | DrawCube(Vector3{ 0,0.5f,0 }, 1, 1, 1, DARKBLUE); 65 | rlDrawRenderBatchActive(); 66 | 67 | glEnable(GL_STENCIL_TEST); 68 | 69 | glStencilFunc(GL_ALWAYS, 1, 0xFF); // Set any stencil to 1 70 | glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); 71 | glStencilMask(0xFF); // Write to stencil buffer 72 | rlDisableDepthMask(); 73 | glClear(GL_STENCIL_BUFFER_BIT); // Clear stencil buffer (0 by default) 74 | 75 | DrawPlane(Vector3{ 0, 0, 0 }, Vector2{ 3, 3 }, BLACK); 76 | rlDrawRenderBatchActive(); 77 | 78 | 79 | glStencilFunc(GL_EQUAL, 1, 0xFF); // Pass test if stencil value is 1 80 | glStencilMask(0x00); // Don't write anything to stencil buffer 81 | rlEnableDepthMask(); 82 | 83 | DrawCube(Vector3{ 0,-0.5f,0 }, 1, 1, 1, ColorAlpha(DARKBLUE,0.5f)); 84 | rlDrawRenderBatchActive(); 85 | 86 | glDisable(GL_STENCIL_TEST); 87 | 88 | rlPopMatrix(); 89 | EndMode3D(); 90 | 91 | EndDrawing(); 92 | } 93 | 94 | CloseWindow(); 95 | return 0; 96 | } -------------------------------------------------------------------------------- /stencil_reflection/premake5.lua: -------------------------------------------------------------------------------- 1 | 2 | baseName = path.getbasename(os.getcwd()) 3 | 4 | defineWorkspace(baseName) -------------------------------------------------------------------------------- /transform_hierarchy/README.md: -------------------------------------------------------------------------------- 1 | # Transform Hierarchy 2 | A very simple example of using a hierarchy of transforms to build up a simple first person controller 3 | with an attached gun that moves with the camera 4 | 5 | Use WADS to move and right click + the mouse to rotate. 6 | 7 | -------------------------------------------------------------------------------- /transform_hierarchy/main.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * raylib-extras, examples-cpp * examples for Raylib in C++ 4 | * 5 | * LICENSE: MIT 6 | * 7 | * Copyright (c) 2023 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 | #include "raymath.h" 31 | 32 | #include "object_transform.h" 33 | 34 | #include 35 | #include 36 | 37 | ObjectTransform PlayerBase; 38 | ObjectTransform CameraNode; 39 | ObjectTransform GunNode; 40 | 41 | RenderTexture OverlayTexture = { 0 }; 42 | 43 | Model GunModel = { 0 }; 44 | 45 | void GameInit() 46 | { 47 | // build up a Hierarchy of transform nodes in a parent child relationship 48 | // 49 | // Camera 50 | // |\ 51 | // | \Gun 52 | // | 53 | // + Base 54 | // 55 | // player base is where the players 'feet' are 56 | // its child is the camera node at an offset for the 'head' 57 | // the gun is a child of the camera so it moves with it 58 | 59 | PlayerBase.AddChild(CameraNode); 60 | CameraNode.MoveV(1); 61 | CameraNode.AddChild(GunNode); 62 | 63 | GunNode.MoveV(-0.5f); 64 | GunNode.MoveH(-0.5f); 65 | 66 | // load a gun model 67 | GunModel = LoadModel("resources/blasterD.glb"); 68 | 69 | OverlayTexture = LoadRenderTexture(GetScreenWidth(), GetScreenHeight()); 70 | } 71 | 72 | bool GameUpdate() 73 | { 74 | //rotate the player base left and right 75 | if (IsMouseButtonDown(MOUSE_BUTTON_RIGHT)) 76 | PlayerBase.RotateV(GetMouseDelta().x * -0.5f); 77 | 78 | // rotate the camera up and down 79 | if (IsMouseButtonDown(MOUSE_BUTTON_RIGHT)) 80 | CameraNode.RotateH(GetMouseDelta().y * -0.5f); 81 | 82 | // move the player based on it's local transform 83 | if (IsKeyDown(KEY_W)) 84 | PlayerBase.MoveD(GetFrameTime() * 10); 85 | 86 | if (IsKeyDown(KEY_S)) 87 | PlayerBase.MoveD(GetFrameTime() * -10); 88 | 89 | if (IsKeyDown(KEY_A)) 90 | PlayerBase.MoveH(GetFrameTime() * 10); 91 | 92 | if (IsKeyDown(KEY_D)) 93 | PlayerBase.MoveH(GetFrameTime() * -10); 94 | 95 | return true; 96 | } 97 | 98 | void GameDraw() 99 | { 100 | BeginDrawing(); 101 | ClearBackground(DARKGRAY); 102 | 103 | // the camera is not our controller, so we can always recreate it from the camera node 104 | Camera3D camera = { 0 }; 105 | camera.projection = CAMERA_PERSPECTIVE; 106 | camera.fovy = 45; 107 | camera.up.y = 1; 108 | 109 | // where the camera node is in the world 110 | camera.position = CameraNode.GetWorldPosition(); 111 | 112 | // where the depth vector of the camera node is in world space 113 | camera.target = Vector3Transform({ 0,0,1 }, CameraNode.GetWorldMatrix()); 114 | 115 | BeginMode3D(camera); 116 | 117 | DrawGrid(10, 10); 118 | DrawCube(Vector3{ 0,0.5f,10 }, 1, 1, 1, RED); 119 | 120 | EndMode3D(); 121 | 122 | // draw the gun to a render texture so that doesn't clip 123 | BeginTextureMode(OverlayTexture); 124 | ClearBackground(BLANK); 125 | BeginMode3D(camera); 126 | // push the OpenGL matrix for the gun node in world space 127 | // so we can draw the gun there 128 | GunNode.PushMatrix(); 129 | // we are now drawing local to the gun node, this model needs to stick out a little, so we shift it by 1.5 in z 130 | DrawModel(GunModel, Vector3{0,0,1.5f}, 1, WHITE); 131 | GunNode.PopMatrix(); 132 | EndMode3D(); 133 | 134 | // draw a target point 135 | DrawCircle(GetScreenWidth() / 2, GetScreenHeight() / 2, 5, ColorAlpha(SKYBLUE, 0.75f)); 136 | EndTextureMode(); 137 | 138 | DrawTextureRec(OverlayTexture.texture, Rectangle{ 0,0,float(GetScreenWidth()), -float(GetScreenHeight()) }, Vector2Zeros, WHITE); 139 | EndDrawing(); 140 | } 141 | 142 | int main() 143 | { 144 | SetConfigFlags(FLAG_VSYNC_HINT); 145 | InitWindow(1280, 800, "Transform Example"); 146 | SetTargetFPS(144); 147 | 148 | GameInit(); 149 | 150 | while (!WindowShouldClose()) 151 | { 152 | if (!GameUpdate()) 153 | break; 154 | 155 | GameDraw(); 156 | } 157 | 158 | UnloadModel(GunModel); 159 | 160 | CloseWindow(); 161 | return 0; 162 | } -------------------------------------------------------------------------------- /transform_hierarchy/object_transform.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * transforms.h * a sample object transfrom class 4 | * 5 | * LICENSE: ZLIB 6 | * 7 | * Copyright (c) 2022 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 | inline ObjectTransform* GetParent() const { return Parent; } 61 | 62 | inline const std::vector& GetChildren() const { return Children; } 63 | 64 | inline ObjectTransform* AddChild(ObjectTransform* child) 65 | { 66 | if (!child) 67 | return nullptr; 68 | 69 | child->Reparent(this); 70 | 71 | return child; 72 | } 73 | 74 | inline ObjectTransform& AddChild(ObjectTransform& child) 75 | { 76 | child.Reparent(this); 77 | 78 | return child; 79 | } 80 | 81 | inline void Reparent(ObjectTransform* newParent) 82 | { 83 | if (Parent == newParent) 84 | return; 85 | 86 | if (newParent) 87 | { 88 | auto child = std::find(newParent->Children.begin(), newParent->Children.end(), this); 89 | if (child != newParent->Children.end()) 90 | newParent->Children.erase(child); 91 | } 92 | 93 | Parent = newParent; 94 | if (Parent) 95 | Parent->Children.push_back(this); 96 | } 97 | 98 | inline void Detach() 99 | { 100 | if (!GetParent()) 101 | return; 102 | 103 | Matrix worldTransform = GetWorldMatrix(); 104 | Position = Vector3Transform(Vector3Zero(), WorldMatrix); 105 | 106 | Matrix translateMatrix = MatrixTranslate(Position.x, Position.y, Position.z); 107 | Matrix orientationMatrix = MatrixMultiply(worldTransform, translateMatrix); 108 | 109 | Orientation = QuaternionFromMatrix(WorldMatrix); 110 | 111 | Reparent(nullptr); 112 | } 113 | 114 | inline void SetDirty() 115 | { 116 | Dirty = true; 117 | for (ObjectTransform* childTransform : Children) 118 | { 119 | if (childTransform != nullptr) 120 | childTransform->SetDirty(); 121 | } 122 | } 123 | 124 | inline const Vector3& GetPosition() const { return Position; } 125 | 126 | inline Quaternion GetOrientation() 127 | { 128 | return Orientation; 129 | } 130 | 131 | inline Vector3 GetEulerAngles() 132 | { 133 | return QuaternionToEuler(Orientation); 134 | } 135 | 136 | inline Vector3 GetDVector() const 137 | { 138 | return Vector3Transform(Vector3{ 0, 0, 1 }, MatrixInvert(QuaternionToMatrix(Orientation))); 139 | } 140 | 141 | inline Vector3 GeVVector() const 142 | { 143 | return Vector3Transform(Vector3{ 0, 1, 0 }, MatrixInvert(QuaternionToMatrix(Orientation))); 144 | } 145 | 146 | inline Vector3 GetHNegVector() 147 | { 148 | return Vector3CrossProduct(GeVVector(), GetDVector()); 149 | } 150 | 151 | inline Vector3 GetHPostVector() 152 | { 153 | return Vector3CrossProduct(GetDVector(), GeVVector()); 154 | } 155 | 156 | inline Vector3 GetWorldPosition() 157 | { 158 | Matrix worldTransform = GetWorldMatrix(); 159 | return Vector3Transform(Vector3Zero(), WorldMatrix); 160 | } 161 | 162 | inline Vector3 GetWorldTarget() 163 | { 164 | Matrix worldTransform = GetWorldMatrix(); 165 | Vector3 pos = Vector3Transform(Vector3Zero(), WorldMatrix); 166 | 167 | Matrix translateMatrix = MatrixTranslate(Position.x, Position.y, Position.z); 168 | Matrix orientationMatrix = MatrixMultiply(worldTransform, translateMatrix); 169 | 170 | return Vector3Add(pos, Vector3Transform(Vector3{ 0 , 1 , 0 }, WorldMatrix)); 171 | } 172 | 173 | inline void SetPosition(float x, float y, float z) 174 | { 175 | Position.x = x; 176 | Position.y = y; 177 | Position.z = z; 178 | SetDirty(); 179 | } 180 | 181 | inline void SetPosition(const Vector3& pos) 182 | { 183 | Position = pos; 184 | SetDirty(); 185 | } 186 | 187 | inline 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 | inline bool IsDirty() 195 | { 196 | return Dirty; 197 | } 198 | 199 | inline 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 | inline Matrix GetLocalMatrix() 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 | inline 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 | inline const Matrix& GetWorldMatrix() 228 | { 229 | if (!IsDirty()) 230 | return WorldMatrix; 231 | 232 | UpdateWorldMatrix(); 233 | return WorldMatrix; 234 | } 235 | 236 | inline const Matrix& GetGLWorldMatrix() 237 | { 238 | if (!IsDirty()) 239 | return GlWorldMatrix; 240 | 241 | UpdateWorldMatrix(); 242 | return GlWorldMatrix; 243 | } 244 | 245 | inline Vector3 ToLocalPos(const Vector3& inPos) 246 | { 247 | return Vector3Transform(inPos, MatrixInvert(GetWorldMatrix())); 248 | } 249 | 250 | 251 | inline void MoveV(float distance) 252 | { 253 | SetDirty(); 254 | Position = Vector3Add(Position, Vector3Scale(GeVVector(), distance)); 255 | } 256 | 257 | inline void MoveD(float distance) 258 | { 259 | SetDirty(); 260 | Position = Vector3Add(Position, Vector3Scale(GetDVector(), distance)); 261 | } 262 | 263 | inline void MoveH(float distance) 264 | { 265 | SetDirty(); 266 | Position = Vector3Add(Position, Vector3Scale(GetHNegVector(), distance)); 267 | } 268 | 269 | inline void RotateV(float angle) 270 | { 271 | SetDirty(); 272 | auto rot = QuaternionFromEuler(0, -angle * DEG2RAD, 0); 273 | Orientation = QuaternionMultiply(Orientation, rot); 274 | } 275 | 276 | inline void RotateH(float angle) 277 | { 278 | SetDirty(); 279 | auto rot = QuaternionFromEuler(angle * DEG2RAD, 0, 0); 280 | Orientation = QuaternionMultiply(Orientation, rot); 281 | } 282 | 283 | inline void RotateD(float angle) 284 | { 285 | SetDirty(); 286 | auto rot = QuaternionFromEuler(0, 0, -angle * DEG2RAD); 287 | Orientation = QuaternionMultiply(Orientation, rot); 288 | } 289 | 290 | inline void RotateX(float angle) 291 | { 292 | SetDirty(); 293 | auto rot = QuaternionFromEuler(angle * DEG2RAD, 0, 0); 294 | Orientation = QuaternionMultiply(rot, Orientation); 295 | } 296 | 297 | inline void RotateY(float angle) 298 | { 299 | SetDirty(); 300 | auto rot = QuaternionFromEuler(0, -angle * DEG2RAD, 0); 301 | Orientation = QuaternionMultiply(rot, Orientation); 302 | } 303 | 304 | inline void RotateZ(float angle) 305 | { 306 | SetDirty(); 307 | auto rot = QuaternionFromEuler(0, 0, -angle * DEG2RAD); 308 | Orientation = QuaternionMultiply(rot, Orientation); 309 | } 310 | 311 | inline void PushMatrix() 312 | { 313 | const Matrix& glMatrix = GetGLWorldMatrix(); 314 | rlPushMatrix(); 315 | rlMultMatrixf((float*)(&glMatrix.m0)); 316 | } 317 | 318 | inline void PopMatrix() 319 | { 320 | rlPopMatrix(); 321 | } 322 | }; -------------------------------------------------------------------------------- /transform_hierarchy/premake5.lua: -------------------------------------------------------------------------------- 1 | 2 | baseName = path.getbasename(os.getcwd()) 3 | 4 | defineWorkspace(baseName) -------------------------------------------------------------------------------- /transform_hierarchy/resources/blasterD.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raylib-extras/examples-cpp/935b48d6f5fe597bd805c30355a193aef7d0e8fe/transform_hierarchy/resources/blasterD.glb -------------------------------------------------------------------------------- /voxel_mesher/README.md: -------------------------------------------------------------------------------- 1 | # Voxel-Mesher 2 | An example of how to create meshes for a voxel chunk similar to what may be used in block games (minecrafts) -------------------------------------------------------------------------------- /voxel_mesher/premake5.lua: -------------------------------------------------------------------------------- 1 | 2 | baseName = path.getbasename(os.getcwd()) 3 | 4 | defineWorkspace(baseName) -------------------------------------------------------------------------------- /voxel_mesher/resources/shaders/base_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 | -------------------------------------------------------------------------------- /voxel_mesher/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 MaterialProperty { 23 | vec3 color; 24 | int useSampler; 25 | sampler2D sampler; 26 | }; 27 | 28 | struct Light { 29 | int enabled; 30 | int type; 31 | vec3 position; 32 | vec3 target; 33 | vec4 color; 34 | }; 35 | 36 | // Input lighting values 37 | uniform Light lights[MAX_LIGHTS]; 38 | uniform vec4 ambient; 39 | uniform vec3 viewPos; 40 | 41 | void main() 42 | { 43 | // Texel color fetching from texture sampler 44 | vec4 texelColor = texture(texture0, fragTexCoord); 45 | vec3 lightDot = vec3(0.0); 46 | vec3 normal = normalize(fragNormal); 47 | vec3 viewD = normalize(viewPos - fragPosition); 48 | vec3 specular = vec3(0.0); 49 | 50 | // NOTE: Implement here your fragment shader code 51 | 52 | for (int i = 0; i < MAX_LIGHTS; i++) 53 | { 54 | if (lights[i].enabled == 1) 55 | { 56 | vec3 light = vec3(0.0); 57 | 58 | if (lights[i].type == LIGHT_DIRECTIONAL) 59 | { 60 | light = -normalize(lights[i].target - lights[i].position); 61 | } 62 | 63 | if (lights[i].type == LIGHT_POINT) 64 | { 65 | light = normalize(lights[i].position - fragPosition); 66 | } 67 | 68 | float NdotL = max(dot(normal, light), 0.0); 69 | lightDot += lights[i].color.rgb*NdotL; 70 | 71 | float specCo = 0.0; 72 | if (NdotL > 0.0) specCo = pow(max(0.0, dot(viewD, reflect(-(light), normal))), 16.0); // 16 refers to shine 73 | specular += specCo; 74 | } 75 | } 76 | 77 | vec4 tint = colDiffuse * fragColor; 78 | 79 | finalColor = (texelColor*((tint + vec4(specular, 1.0))*vec4(lightDot, 1.0))); 80 | finalColor += texelColor*(ambient/10.0)*tint; 81 | 82 | // Gamma correction 83 | finalColor = pow(finalColor, vec4(1.0/2.2)); 84 | } 85 | -------------------------------------------------------------------------------- /voxel_mesher/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-2020 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 | Vector3 position; 49 | Vector3 target; 50 | Color color; 51 | bool enabled; 52 | 53 | // Shader locations 54 | int enabledLoc; 55 | int typeLoc; 56 | int posLoc; 57 | int targetLoc; 58 | int colorLoc; 59 | } Light; 60 | 61 | // Light type 62 | typedef enum { 63 | LIGHT_DIRECTIONAL, 64 | LIGHT_POINT 65 | } LightType; 66 | 67 | #ifdef __cplusplus 68 | extern "C" { // Prevents name mangling of functions 69 | #endif 70 | 71 | //---------------------------------------------------------------------------------- 72 | // Module Functions Declaration 73 | //---------------------------------------------------------------------------------- 74 | Light CreateLight(int type, Vector3 position, Vector3 target, Color color, Shader shader); // Create a light and get shader locations 75 | void UpdateLightValues(Shader shader, Light light); // Send light properties to shader 76 | 77 | #ifdef __cplusplus 78 | } 79 | #endif 80 | 81 | #endif // RLIGHTS_H 82 | 83 | 84 | /*********************************************************************************** 85 | * 86 | * RLIGHTS IMPLEMENTATION 87 | * 88 | ************************************************************************************/ 89 | 90 | #if defined(RLIGHTS_IMPLEMENTATION) 91 | 92 | #include "raylib.h" 93 | 94 | //---------------------------------------------------------------------------------- 95 | // Defines and Macros 96 | //---------------------------------------------------------------------------------- 97 | // ... 98 | 99 | //---------------------------------------------------------------------------------- 100 | // Types and Structures Definition 101 | //---------------------------------------------------------------------------------- 102 | // ... 103 | 104 | //---------------------------------------------------------------------------------- 105 | // Global Variables Definition 106 | //---------------------------------------------------------------------------------- 107 | static int lightsCount = 0; // Current amount of created lights 108 | 109 | //---------------------------------------------------------------------------------- 110 | // Module specific Functions Declaration 111 | //---------------------------------------------------------------------------------- 112 | // ... 113 | 114 | //---------------------------------------------------------------------------------- 115 | // Module Functions Definition 116 | //---------------------------------------------------------------------------------- 117 | 118 | // Create a light and get shader locations 119 | Light CreateLight(int type, Vector3 position, Vector3 target, Color color, Shader shader) 120 | { 121 | Light light = { 0 }; 122 | 123 | if (lightsCount < MAX_LIGHTS) 124 | { 125 | light.enabled = true; 126 | light.type = type; 127 | light.position = position; 128 | light.target = target; 129 | light.color = color; 130 | 131 | // TODO: Below code doesn't look good to me, 132 | // it assumes a specific shader naming and structure 133 | // Probably this implementation could be improved 134 | char enabledName[32] = "lights[x].enabled\0"; 135 | char typeName[32] = "lights[x].type\0"; 136 | char posName[32] = "lights[x].position\0"; 137 | char targetName[32] = "lights[x].target\0"; 138 | char colorName[32] = "lights[x].color\0"; 139 | 140 | // Set location name [x] depending on lights count 141 | enabledName[7] = '0' + lightsCount; 142 | typeName[7] = '0' + lightsCount; 143 | posName[7] = '0' + lightsCount; 144 | targetName[7] = '0' + lightsCount; 145 | colorName[7] = '0' + lightsCount; 146 | 147 | light.enabledLoc = GetShaderLocation(shader, enabledName); 148 | light.typeLoc = GetShaderLocation(shader, typeName); 149 | light.posLoc = GetShaderLocation(shader, posName); 150 | light.targetLoc = GetShaderLocation(shader, targetName); 151 | light.colorLoc = GetShaderLocation(shader, colorName); 152 | 153 | UpdateLightValues(shader, light); 154 | 155 | lightsCount++; 156 | } 157 | 158 | return light; 159 | } 160 | 161 | // Send light properties to shader 162 | // NOTE: Light shader locations should be available 163 | void UpdateLightValues(Shader shader, Light light) 164 | { 165 | // Send to shader light enabled state and type 166 | SetShaderValue(shader, light.enabledLoc, &light.enabled, SHADER_UNIFORM_INT); 167 | SetShaderValue(shader, light.typeLoc, &light.type, SHADER_UNIFORM_INT); 168 | 169 | // Send to shader light position values 170 | float position[3] = { light.position.x, light.position.y, light.position.z }; 171 | SetShaderValue(shader, light.posLoc, position, SHADER_UNIFORM_VEC3); 172 | 173 | // Send to shader light target position values 174 | float target[3] = { light.target.x, light.target.y, light.target.z }; 175 | SetShaderValue(shader, light.targetLoc, target, SHADER_UNIFORM_VEC3); 176 | 177 | // Send to shader light color values 178 | float color[4] = { (float)light.color.r/(float)255, (float)light.color.g/(float)255, 179 | (float)light.color.b/(float)255, (float)light.color.a/(float)255 }; 180 | SetShaderValue(shader, light.colorLoc, color, SHADER_UNIFORM_VEC4); 181 | } 182 | 183 | #endif // RLIGHTS_IMPLEMENTATION --------------------------------------------------------------------------------